00001
00002
00003
00004
#include <config.h>
00005
00006
#include "kmheaders.h"
00007
00008
#include "kcursorsaver.h"
00009
#include "kmcommands.h"
00010
#include "kmfolderimap.h"
00011
#include "kmmainwidget.h"
00012
#include "kmcomposewin.h"
00013
#include "kmfiltermgr.h"
00014
#include "undostack.h"
00015
#include "kmmsgdict.h"
00016
#include "kmkernel.h"
00017
#include "kmdebug.h"
00018
using KMail::FolderJob;
00019
#include "broadcaststatus.h"
00020
using KPIM::BroadcastStatus;
00021
#include "actionscheduler.h"
00022
using KMail::ActionScheduler;
00023
#include <maillistdrag.h>
00024
#include "globalsettings.h"
00025
using namespace KPIM;
00026
00027
#include <kapplication.h>
00028
#include <kaccelmanager.h>
00029
#include <kglobalsettings.h>
00030
#include <kmessagebox.h>
00031
#include <kiconloader.h>
00032
#include <kimageio.h>
00033
#include <kconfig.h>
00034
#include <klocale.h>
00035
#include <kdebug.h>
00036
00037
#include <qbuffer.h>
00038
#include <qfile.h>
00039
#include <qheader.h>
00040
#include <qptrstack.h>
00041
#include <qptrqueue.h>
00042
#include <qpainter.h>
00043
#include <qtextcodec.h>
00044
#include <qbitmap.h>
00045
#include <qstyle.h>
00046
#include <qlistview.h>
00047
#include <qregexp.h>
00048
00049
#include <mimelib/enum.h>
00050
#include <mimelib/field.h>
00051
#include <mimelib/mimepp.h>
00052
00053
#include <stdlib.h>
00054
#include <errno.h>
00055
00056
QPixmap* KMHeaders::pixNew = 0;
00057
QPixmap* KMHeaders::pixUns = 0;
00058
QPixmap* KMHeaders::pixDel = 0;
00059
QPixmap* KMHeaders::pixRead = 0;
00060
QPixmap* KMHeaders::pixRep = 0;
00061
QPixmap* KMHeaders::pixQueued = 0;
00062
QPixmap* KMHeaders::pixSent = 0;
00063
QPixmap* KMHeaders::pixFwd = 0;
00064
QPixmap* KMHeaders::pixFlag = 0;
00065
QPixmap* KMHeaders::pixWatched = 0;
00066
QPixmap* KMHeaders::pixIgnored = 0;
00067
QPixmap* KMHeaders::pixSpam = 0;
00068
QPixmap* KMHeaders::pixHam = 0;
00069
QPixmap* KMHeaders::pixFullySigned = 0;
00070
QPixmap* KMHeaders::pixPartiallySigned = 0;
00071
QPixmap* KMHeaders::pixUndefinedSigned = 0;
00072
QPixmap* KMHeaders::pixFullyEncrypted = 0;
00073
QPixmap* KMHeaders::pixPartiallyEncrypted = 0;
00074
QPixmap* KMHeaders::pixUndefinedEncrypted = 0;
00075
QPixmap* KMHeaders::pixEncryptionProblematic = 0;
00076
QPixmap* KMHeaders::pixSignatureProblematic = 0;
00077
QPixmap* KMHeaders::pixAttachment = 0;
00078
00079
#define KMAIL_SORT_VERSION 1012
00080
#define KMAIL_SORT_FILE(x) x->indexLocation() + ".sorted"
00081
#define KMAIL_SORT_HEADER "## KMail Sort V%04d\n\t"
00082
#define KMAIL_MAGIC_HEADER_OFFSET 21 //strlen(KMAIL_SORT_HEADER)
00083
#define KMAIL_MAX_KEY_LEN 16384
00084
#define KMAIL_RESERVED 3
00085
00086
00087
class KMSortCacheItem {
00088 KMHeaderItem *mItem;
00089 KMSortCacheItem *mParent;
00090
int mId, mSortOffset;
00091
QString mKey;
00092
00093
QPtrList<KMSortCacheItem> mSortedChildren;
00094
int mUnsortedCount, mUnsortedSize;
00095 KMSortCacheItem **mUnsortedChildren;
00096
bool mImperfectlyThreaded;
00097
00098
public:
00099 KMSortCacheItem() : mItem(0), mParent(0), mId(-1), mSortOffset(-1),
00100 mUnsortedCount(0), mUnsortedSize(0), mUnsortedChildren(0),
00101 mImperfectlyThreaded (true) { }
00102 KMSortCacheItem(
int i,
QString k,
int o=-1)
00103 : mItem(0), mParent(0), mId(i), mSortOffset(o), mKey(k),
00104 mUnsortedCount(0), mUnsortedSize(0), mUnsortedChildren(0),
00105 mImperfectlyThreaded (true) { }
00106 ~KMSortCacheItem() {
if(mUnsortedChildren) free(mUnsortedChildren); }
00107
00108 KMSortCacheItem *parent()
const {
return mParent; }
00109
bool isImperfectlyThreaded()
const
00110
{
return mImperfectlyThreaded; }
00111
void setImperfectlyThreaded (
bool val)
00112 { mImperfectlyThreaded = val; }
00113
bool hasChildren()
const
00114
{
return mSortedChildren.count() || mUnsortedCount; }
00115
const QPtrList<KMSortCacheItem> *sortedChildren()
const
00116
{
return &mSortedChildren; }
00117 KMSortCacheItem **unsortedChildren(
int &count)
const
00118
{ count = mUnsortedCount;
return mUnsortedChildren; }
00119
void addSortedChild(KMSortCacheItem *i) {
00120 i->mParent =
this;
00121 mSortedChildren.append(i);
00122 }
00123
void addUnsortedChild(KMSortCacheItem *i) {
00124 i->mParent =
this;
00125
if(!mUnsortedChildren)
00126 mUnsortedChildren = (KMSortCacheItem **)malloc((mUnsortedSize = 25) *
sizeof(KMSortCacheItem *));
00127
else if(mUnsortedCount >= mUnsortedSize)
00128 mUnsortedChildren = (KMSortCacheItem **)realloc(mUnsortedChildren,
00129 (mUnsortedSize *= 2) *
sizeof(KMSortCacheItem *));
00130 mUnsortedChildren[mUnsortedCount++] = i;
00131 }
00132
00133 KMHeaderItem *item()
const {
return mItem; }
00134
void setItem(KMHeaderItem *i) { Q_ASSERT(!mItem); mItem = i; }
00135
00136
const QString &key()
const {
return mKey; }
00137
void setKey(
const QString &key) { mKey = key; }
00138
00139
int id()
const {
return mId; }
00140
void setId(
int id) { mId =
id; }
00141
00142
int offset()
const {
return mSortOffset; }
00143
void setOffset(
int x) { mSortOffset = x; }
00144
00145
void updateSortFile( FILE *sortStream,
KMFolder *folder,
00146
bool waiting_for_parent =
false,
00147
bool update_discovered_count =
false);
00148 };
00149
00150
00151
00152
00153
00154
class KMHeaderItem :
public KListViewItem
00155 {
00156
00157
public:
00158
int mMsgId;
00159
QString mKey;
00160
00161
00162
00163 KMHeaderItem(
QListView* parent,
int msgId,
const QString& key = QString::null )
00164 : KListViewItem( parent ),
00165 mMsgId( msgId ),
00166 mKey( key ),
00167 mAboutToBeDeleted( false ),
00168 mSortCacheItem( 0 )
00169 {
00170 irefresh();
00171 }
00172
00173
00174 KMHeaderItem(
QListViewItem* parent,
int msgId,
const QString& key = QString::null )
00175 : KListViewItem( parent ),
00176 mMsgId( msgId ),
00177 mKey( key ),
00178 mAboutToBeDeleted( false ),
00179 mSortCacheItem( 0 )
00180 {
00181 irefresh();
00182 }
00183
00184 ~KMHeaderItem ()
00185 {
00186
delete mSortCacheItem;
00187 }
00188
00189
00190
void setMsgId(
int aMsgId )
00191 {
00192 mMsgId = aMsgId;
00193 }
00194
00195
00196
00197
00198
void irefresh()
00199 {
00200
KMHeaders *headers = static_cast<KMHeaders*>(listView());
00201 NestingPolicy threadingPolicy = headers->
getNestingPolicy();
00202
if ((threadingPolicy == AlwaysOpen) ||
00203 (threadingPolicy == DefaultOpen)) {
00204
00205 setOpen(
true);
00206
return;
00207
00208 }
00209
if (threadingPolicy == DefaultClosed)
00210
return;
00211
00212
00213
if (parent() && parent()->isOpen()) {
00214 setOpen(
true);
00215
return;
00216 }
00217
00218 KMMsgBase *mMsgBase = headers->
folder()->
getMsgBase( mMsgId );
00219
if (mMsgBase->isNew() || mMsgBase->isUnread()
00220 || mMsgBase->isImportant() || mMsgBase->isWatched() ) {
00221 setOpen(
true);
00222 KMHeaderItem * topOfThread =
this;
00223
while(topOfThread->parent())
00224 topOfThread = (KMHeaderItem*)topOfThread->parent();
00225 topOfThread->setOpenRecursive(
true);
00226 }
00227 }
00228
00229
00230
int msgId()
const
00231
{
00232
return mMsgId;
00233 }
00234
00235
00236
void reset(
int aMsgId )
00237 {
00238 mMsgId = aMsgId;
00239 irefresh();
00240 }
00241
00242
00243
void setOpenRecursive(
bool open )
00244 {
00245
if (open){
00246
QListViewItem * lvchild;
00247 lvchild = firstChild();
00248
while (lvchild){
00249 ((KMHeaderItem*)lvchild)->setOpenRecursive(
true );
00250 lvchild = lvchild->nextSibling();
00251 }
00252 setOpen(
true );
00253 }
else {
00254 setOpen(
false );
00255 }
00256 }
00257
00258
QString text(
int col)
const
00259
{
00260
KMHeaders *headers = static_cast<KMHeaders*>(listView());
00261 KMMsgBase *mMsgBase = headers->
folder()->
getMsgBase( mMsgId );
00262
QString tmp;
00263
00264 assert(mMsgBase);
00265
00266
if(col == headers->
paintInfo()->flagCol) {
00267
if (headers->
paintInfo()->flagCol >= 0)
00268 tmp =
QString(
QChar( (
char)mMsgBase->status() ));
00269
00270 }
else if(col == headers->
paintInfo()->senderCol) {
00271
if (headers->
folder()->
whoField().lower() ==
"to")
00272 tmp = mMsgBase->toStrip();
00273
else
00274 tmp = mMsgBase->fromStrip();
00275
if (tmp.isEmpty())
00276 tmp = i18n(
"Unknown");
00277
else
00278 tmp = tmp.simplifyWhiteSpace();
00279
00280 }
else if(col == headers->
paintInfo()->subCol) {
00281 tmp = mMsgBase->subject();
00282
if (tmp.isEmpty())
00283 tmp = i18n(
"No Subject");
00284
else
00285 tmp.remove(
QRegExp(
"[\r\n]"));
00286
00287 }
else if(col == headers->
paintInfo()->dateCol) {
00288 tmp = headers->
mDate.dateString( mMsgBase->date() );
00289 }
else if(col == headers->
paintInfo()->sizeCol
00290 && headers->
paintInfo()->showSize) {
00291
if ( mMsgBase->parent()->folderType() == KMFolderTypeImap ) {
00292 tmp = KIO::convertSize( mMsgBase->msgSizeServer() );
00293 }
else {
00294 tmp = KIO::convertSize( mMsgBase->msgSize() );
00295 }
00296 }
00297
return tmp;
00298 }
00299
00300
void setup()
00301 {
00302 widthChanged();
00303
const int ph = KMHeaders::pixNew->height();
00304
QListView *v = listView();
00305
int h = QMAX( v->fontMetrics().height(), ph ) + 2*v->itemMargin();
00306 h = QMAX( h, QApplication::globalStrut().height());
00307
if ( h % 2 > 0 )
00308 h++;
00309 setHeight( h );
00310 }
00311
00312
typedef QValueList<QPixmap> PixmapList;
00313
00314
QPixmap pixmapMerge( PixmapList pixmaps )
const {
00315
int width = 0;
00316
int height = 0;
00317
for ( PixmapList::ConstIterator it = pixmaps.begin();
00318 it != pixmaps.end(); ++it ) {
00319 width += (*it).width();
00320 height = QMAX( height, (*it).height() );
00321 }
00322
00323
QPixmap res( width, height );
00324
QBitmap mask( width, height );
00325
00326
int x = 0;
00327
for ( PixmapList::ConstIterator it = pixmaps.begin();
00328 it != pixmaps.end(); ++it ) {
00329 bitBlt( &res, x, 0, &(*it) );
00330 bitBlt( &mask, x, 0, (*it).mask() );
00331 x += (*it).width();
00332 }
00333
00334 res.setMask( mask );
00335
return res;
00336 }
00337
00338
00339
const QPixmap * pixmap(
int col)
const
00340
{
00341
if(!col) {
00342
KMHeaders *headers = static_cast<KMHeaders*>(listView());
00343 KMMsgBase *mMsgBase = headers->
folder()->
getMsgBase( mMsgId );
00344
00345 PixmapList pixmaps;
00346
00347
00348
if(mMsgBase->isSpam()) pixmaps << *KMHeaders::pixSpam;
00349
if(mMsgBase->isHam()) pixmaps << *KMHeaders::pixHam;
00350
if(mMsgBase->isIgnored()) pixmaps << *KMHeaders::pixIgnored;
00351
if(mMsgBase->isWatched()) pixmaps << *KMHeaders::pixWatched;
00352
00353
if(mMsgBase->isQueued()) pixmaps << *KMHeaders::pixQueued;
00354
if(mMsgBase->isSent()) pixmaps << *KMHeaders::pixSent;
00355
00356
if(mMsgBase->isNew()) pixmaps << *KMHeaders::pixNew;
00357
if(mMsgBase->isRead() || mMsgBase->isOld()) pixmaps << *KMHeaders::pixRead;
00358
if(mMsgBase->isUnread()) pixmaps << *KMHeaders::pixUns;
00359
if(mMsgBase->isDeleted()) pixmaps << *KMHeaders::pixDel;
00360
00361
00362
if( headers->
paintInfo()->showAttachmentIcon &&
00363 mMsgBase->attachmentState() == KMMsgHasAttachment )
00364 pixmaps << *KMHeaders::pixAttachment;
00365
00366
00367
if( headers->
paintInfo()->showCryptoIcons ) {
00368
if( mMsgBase->encryptionState() == KMMsgFullyEncrypted )
00369 pixmaps << *KMHeaders::pixFullyEncrypted;
00370
else if( mMsgBase->encryptionState() == KMMsgPartiallyEncrypted )
00371 pixmaps << *KMHeaders::pixPartiallyEncrypted;
00372
else if( mMsgBase->encryptionState() == KMMsgEncryptionStateUnknown )
00373 pixmaps << *KMHeaders::pixUndefinedEncrypted;
00374
else if( mMsgBase->encryptionState() == KMMsgEncryptionProblematic )
00375 pixmaps << *KMHeaders::pixEncryptionProblematic;
00376
00377
if( mMsgBase->signatureState() == KMMsgFullySigned )
00378 pixmaps << *KMHeaders::pixFullySigned;
00379
else if( mMsgBase->signatureState() == KMMsgPartiallySigned )
00380 pixmaps << *KMHeaders::pixPartiallySigned;
00381
else if( mMsgBase->signatureState() == KMMsgSignatureStateUnknown )
00382 pixmaps << *KMHeaders::pixUndefinedSigned;
00383
else if( mMsgBase->signatureState() == KMMsgSignatureProblematic )
00384 pixmaps << *KMHeaders::pixSignatureProblematic;
00385 }
00386
00387
if(mMsgBase->isImportant()) pixmaps << *KMHeaders::pixFlag;
00388
if(mMsgBase->isReplied()) pixmaps << *KMHeaders::pixRep;
00389
if(mMsgBase->isForwarded()) pixmaps << *KMHeaders::pixFwd;
00390
00391
static QPixmap mergedpix;
00392 mergedpix = pixmapMerge( pixmaps );
00393
return &mergedpix;
00394 }
00395
return 0;
00396 }
00397
00398
void paintCell(
QPainter * p,
const QColorGroup & cg,
00399
int column,
int width,
int align )
00400 {
00401
KMHeaders *headers = static_cast<KMHeaders*>(listView());
00402
if (headers->
noRepaint)
return;
00403
if (!headers->
folder())
return;
00404
QColorGroup _cg( cg );
00405
QColor c = _cg.text();
00406
QColor *color;
00407
00408 KMMsgBase *mMsgBase = headers->
folder()->
getMsgBase( mMsgId );
00409
if (!mMsgBase)
return;
00410
00411 color = (
QColor *)(&headers->
paintInfo()->colFore);
00412
00413
if (mMsgBase->isUnread()) color = (
QColor*)(&headers->
paintInfo()->colUnread);
00414
if (mMsgBase->isNew()) color = (
QColor*)(&headers->
paintInfo()->colNew);
00415
if (mMsgBase->isImportant()) color = (
QColor*)(&headers->
paintInfo()->colFlag);
00416
00417 _cg.setColor( QColorGroup::Text, *color );
00418
00419
if( column == headers->
paintInfo()->dateCol )
00420 p->setFont(headers->
dateFont);
00421
00422 KListViewItem::paintCell( p, _cg, column, width, align );
00423
00424
if (aboutToBeDeleted()) {
00425
00426 p->drawLine( 0, height()/2, width, height()/2);
00427 }
00428 _cg.setColor( QColorGroup::Text, c );
00429 }
00430
00431
static QString generate_key(
KMHeaders *headers, KMMsgBase *msg,
const KPaintInfo *paintInfo,
int sortOrder )
00432 {
00433
00434
00435
00436
if (!msg)
return QString::null;
00437
00438
int column = sortOrder & ((1 << 5) - 1);
00439
QString ret =
QChar( (
char)sortOrder );
00440
QString sortArrival =
QString(
"%1" ).arg( msg->getMsgSerNum(), 0, 36 );
00441
while (sortArrival.length() < 7) sortArrival =
'0' + sortArrival;
00442
00443
if (column == paintInfo->dateCol) {
00444
if (paintInfo->orderOfArrival)
00445
return ret + sortArrival;
00446
else {
00447
QString d = QString::number(msg->date());
00448
while (d.length() <= 10) d =
'0' + d;
00449
return ret + d + sortArrival;
00450 }
00451 }
else if (column == paintInfo->senderCol) {
00452
QString tmp;
00453
if (headers->
folder()->
whoField().lower() ==
"to")
00454 tmp = msg->toStrip();
00455
else
00456 tmp = msg->fromStrip();
00457
return ret + tmp.lower() +
' ' + sortArrival;
00458 }
else if (column == paintInfo->subCol) {
00459
QString tmp;
00460 tmp = ret;
00461
if (paintInfo->status) {
00462 tmp += msg->statusToSortRank() +
' ';
00463 }
00464 tmp += KMMessage::stripOffPrefixes( msg->subject().lower() ) +
' ' + sortArrival;
00465
return tmp;
00466 }
00467
else if (column == paintInfo->sizeCol) {
00468
QString len;
00469
if ( msg->parent()->folderType() == KMFolderTypeImap )
00470 {
00471 len = QString::number( msg->msgSizeServer() );
00472 }
else {
00473 len = QString::number( msg->msgSize() );
00474 }
00475
while (len.length() < 9) len =
'0' + len;
00476
return ret + len + sortArrival;
00477 }
00478
return ret +
"missing key";
00479 }
00480
00481
virtual QString key(
int column,
bool )
const
00482
{
00483
KMHeaders *headers = static_cast<KMHeaders*>(listView());
00484
int sortOrder = column;
00485
if (headers->
mPaintInfo.orderOfArrival)
00486 sortOrder |= (1 << 6);
00487
if (headers->
mPaintInfo.status)
00488 sortOrder |= (1 << 5);
00489
00490
00491
if(mKey.isEmpty() || mKey[0] != (
char)sortOrder) {
00492
KMHeaders *headers = static_cast<KMHeaders*>(listView());
00493 KMMsgBase *msgBase = headers->
folder()->
getMsgBase( mMsgId );
00494
return ((KMHeaderItem *)
this)->mKey =
00495 generate_key( headers, msgBase, headers->
paintInfo(), sortOrder );
00496 }
00497
return mKey;
00498 }
00499
00500
void setTempKey(
QString key ) {
00501 mKey = key;
00502 }
00503
00504
int compare(
QListViewItem *i,
int col,
bool ascending )
const
00505
{
00506
int res = 0;
00507
KMHeaders *headers = static_cast<KMHeaders*>(listView());
00508
if ( col == headers->
paintInfo()->sizeCol ) {
00509 res = key( col, ascending ).compare( i->key( col, ascending ) );
00510 }
else if ( col == headers->
paintInfo()->dateCol ) {
00511 res = key( col, ascending ).compare( i->key( col, ascending ) );
00512
if (i->parent() && !ascending)
00513 res = -res;
00514 }
else if ( col == headers->
paintInfo()->subCol
00515 || col ==headers->
paintInfo()->senderCol) {
00516 res = key( col, ascending ).localeAwareCompare( i->key( col, ascending ) );
00517 }
00518
return res;
00519 }
00520
00521
QListViewItem* firstChildNonConst() {
00522 enforceSortOrder();
00523
return firstChild();
00524 }
00525
00526
bool mAboutToBeDeleted;
00527
bool aboutToBeDeleted()
const {
return mAboutToBeDeleted; }
00528
void setAboutToBeDeleted(
bool val ) { mAboutToBeDeleted = val; }
00529
00530 KMSortCacheItem *mSortCacheItem;
00531
void setSortCacheItem( KMSortCacheItem *item ) { mSortCacheItem = item; }
00532 KMSortCacheItem* sortCacheItem()
const {
return mSortCacheItem; }
00533 };
00534
00535
00536 KMHeaders::KMHeaders(KMMainWidget *aOwner,
QWidget *parent,
00537
const char *name) :
00538 KListView(parent, name)
00539 {
00540
static bool pixmapsLoaded =
false;
00541
00542 KImageIO::registerFormats();
00543 mOwner = aOwner;
00544 mFolder = 0;
00545 noRepaint =
false;
00546 getMsgIndex = -1;
00547 mTopItem = 0;
00548 setSelectionMode( QListView::Extended );
00549 setAllColumnsShowFocus(
true );
00550 mNested =
false;
00551 nestingPolicy = OpenUnread;
00552 mNestedOverride =
false;
00553 mSubjThreading =
true;
00554 mMousePressed =
false;
00555 mSortInfo.dirty =
true;
00556 mSortInfo.fakeSort = 0;
00557 mSortInfo.removed = 0;
00558 mSortInfo.column = 0;
00559 mSortInfo.ascending =
false;
00560 mReaderWindowActive =
false;
00561 setStyleDependantFrameWidth();
00562
00563 header()->setClickEnabled(
true);
00564 header()->installEventFilter(
this);
00565 mPopup =
new KPopupMenu(
this);
00566 mPopup->insertTitle(i18n(
"View Columns"));
00567 mPopup->setCheckable(
true);
00568 mSizeColumn = mPopup->insertItem(i18n(
"Size"),
this, SLOT(slotToggleSizeColumn()));
00569 mPaintInfo.showSize =
false;
00570
00571 mPaintInfo.flagCol = -1;
00572 mPaintInfo.subCol = mPaintInfo.flagCol + 1;
00573 mPaintInfo.senderCol = mPaintInfo.subCol + 1;
00574 mPaintInfo.dateCol = mPaintInfo.senderCol + 1;
00575 mPaintInfo.orderOfArrival =
false;
00576 mPaintInfo.status =
false;
00577 mSortCol = KMMsgList::sfDate;
00578 mSortDescending =
false;
00579
00580 setShowSortIndicator(
true);
00581 setFocusPolicy( WheelFocus );
00582
00583
if (!pixmapsLoaded)
00584 {
00585 pixmapsLoaded =
true;
00586 pixNew =
new QPixmap( UserIcon(
"kmmsgnew") );
00587 pixUns =
new QPixmap( UserIcon(
"kmmsgunseen") );
00588 pixDel =
new QPixmap( UserIcon(
"kmmsgdel") );
00589 pixRead =
new QPixmap( UserIcon(
"kmmsgread") );
00590 pixRep =
new QPixmap( UserIcon(
"kmmsgreplied") );
00591 pixQueued=
new QPixmap( UserIcon(
"kmmsgqueued") );
00592 pixSent =
new QPixmap( UserIcon(
"kmmsgsent") );
00593 pixFwd =
new QPixmap( UserIcon(
"kmmsgforwarded") );
00594 pixFlag =
new QPixmap( UserIcon(
"kmmsgflag") );
00595 pixWatched =
new QPixmap( UserIcon(
"kmmsgwatched") );
00596 pixIgnored =
new QPixmap( UserIcon(
"kmmsgignored") );
00597 pixSpam =
new QPixmap( UserIcon(
"kmmsgspam") );
00598 pixHam =
new QPixmap( UserIcon(
"kmmsgham") );
00599 pixFullySigned =
new QPixmap( UserIcon(
"kmmsgfullysigned" ) );
00600 pixPartiallySigned =
new QPixmap( UserIcon(
"kmmsgpartiallysigned" ) );
00601 pixUndefinedSigned =
new QPixmap( UserIcon(
"kmmsgundefinedsigned" ) );
00602 pixFullyEncrypted =
new QPixmap( UserIcon(
"kmmsgfullyencrypted" ) );
00603 pixPartiallyEncrypted =
new QPixmap( UserIcon(
"kmmsgpartiallyencrypted" ) );
00604 pixUndefinedEncrypted =
new QPixmap( UserIcon(
"kmmsgundefinedencrypted" ) );
00605 pixEncryptionProblematic =
new QPixmap( UserIcon(
"kmmsgencryptionproblematic" ) );
00606 pixSignatureProblematic =
new QPixmap( UserIcon(
"kmmsgsignatureproblematic" ) );
00607 pixAttachment =
new QPixmap( UserIcon(
"kmmsgattachment" ) );
00608 }
00609
00610 addColumn( i18n(
"Subject"), 310 );
00611 addColumn( i18n(
"Sender"), 170 );
00612 addColumn( i18n(
"Date"), 170 );
00613
00614 readConfig();
00615 restoreLayout(KMKernel::config(),
"Header-Geometry");
00616
00617 connect(
this, SIGNAL( contextMenuRequested(
QListViewItem*,
const QPoint &,
int )),
00618
this, SLOT( rightButtonPressed(
QListViewItem*,
const QPoint &,
int )));
00619 connect(
this, SIGNAL(doubleClicked(
QListViewItem*)),
00620
this,SLOT(selectMessage(
QListViewItem*)));
00621 connect(
this,SIGNAL(currentChanged(
QListViewItem*)),
00622
this,SLOT(highlightMessage(
QListViewItem*)));
00623 resetCurrentTime();
00624
00625 mSubjectLists.setAutoDelete(
true );
00626 }
00627
00628
00629
00630 KMHeaders::~KMHeaders ()
00631 {
00632
if (mFolder)
00633 {
00634
writeFolderConfig();
00635 writeSortOrder();
00636 mFolder->close();
00637 }
00638
writeConfig();
00639 }
00640
00641
00642
bool KMHeaders::eventFilter (
QObject *o,
QEvent *e )
00643 {
00644
if ( e->type() == QEvent::MouseButtonPress &&
00645 static_cast<QMouseEvent*>(e)->button() == RightButton &&
00646 o->isA(
"QHeader") )
00647 {
00648 mPopup->popup( static_cast<QMouseEvent*>(e)->globalPos() );
00649
return true;
00650 }
00651
return KListView::eventFilter(o, e);
00652 }
00653
00654
00655
void KMHeaders::slotToggleSizeColumn(
int mode)
00656 {
00657
bool old = mPaintInfo.showSize;
00658
if (mode == -1)
00659 mPaintInfo.showSize = !mPaintInfo.showSize;
00660
else
00661 mPaintInfo.showSize = mode;
00662
00663 mPopup->setItemChecked(mSizeColumn, mPaintInfo.showSize);
00664
if (mPaintInfo.showSize && !old)
00665 mPaintInfo.sizeCol = addColumn(i18n(
"Size"), 80);
00666
else if (!mPaintInfo.showSize && old) {
00667 removeColumn(mPaintInfo.sizeCol);
00668 mPaintInfo.sizeCol = -1;
00669 }
00670
00671
if (mode == -1)
00672
writeConfig();
00673 }
00674
00675
00676
00677
00678
void KMHeaders::paintEmptyArea(
QPainter * p,
const QRect & rect )
00679 {
00680
if (mPaintInfo.pixmapOn)
00681 p->drawTiledPixmap( rect.left(), rect.top(), rect.width(), rect.height(),
00682 mPaintInfo.pixmap,
00683 rect.left() + contentsX(),
00684 rect.top() + contentsY() );
00685
else
00686 p->fillRect( rect, colorGroup().base() );
00687 }
00688
00689
bool KMHeaders::event(
QEvent *e)
00690 {
00691
bool result = KListView::event(e);
00692
if (e->type() == QEvent::ApplicationPaletteChange)
00693 {
00694
readColorConfig();
00695 }
00696
return result;
00697 }
00698
00699
00700
00701
void KMHeaders::readColorConfig (
void)
00702 {
00703 KConfig* config = KMKernel::config();
00704
00705 KConfigGroupSaver saver(config,
"Reader");
00706
QColor c1=
QColor(kapp->palette().active().text());
00707
QColor c2=
QColor(
"red");
00708 QColor c3=QColor(
"blue");
00709 QColor c4=QColor(kapp->palette().active().base());
00710 QColor c5=QColor(0,0x7F,0);
00711 QColor c6=KGlobalSettings::alternateBackgroundColor();
00712
00713
if (!config->readBoolEntry(
"defaultColors",
true)) {
00714 mPaintInfo.colFore = config->readColorEntry(
"ForegroundColor",&c1);
00715 mPaintInfo.colBack = config->readColorEntry(
"BackgroundColor",&c4);
00716
QPalette newPal = kapp->palette();
00717 newPal.setColor( QColorGroup::Base, mPaintInfo.colBack );
00718 newPal.setColor( QColorGroup::Text, mPaintInfo.colFore );
00719 setPalette( newPal );
00720 mPaintInfo.colNew = config->readColorEntry(
"NewMessage",&c2);
00721 mPaintInfo.colUnread = config->readColorEntry(
"UnreadMessage",&c3);
00722 mPaintInfo.colFlag = config->readColorEntry(
"FlagMessage",&c5);
00723 c6 = config->readColorEntry(
"AltBackgroundColor",&c6);
00724 }
00725
else {
00726 mPaintInfo.colFore = c1;
00727 mPaintInfo.colBack = c4;
00728
QPalette newPal = kapp->palette();
00729 newPal.setColor( QColorGroup::Base, c4 );
00730 newPal.setColor( QColorGroup::Text, c1 );
00731 setPalette( newPal );
00732 mPaintInfo.colNew = c2;
00733 mPaintInfo.colUnread = c3;
00734 mPaintInfo.colFlag = c5;
00735 }
00736 setAlternateBackground(c6);
00737 }
00738
00739
00740
void KMHeaders::readConfig (
void)
00741 {
00742 KConfig* config = KMKernel::config();
00743
00744
00745 {
00746 KConfigGroupSaver saver(config,
"Pixmaps");
00747
QString pixmapFile = config->readEntry(
"Headers");
00748 mPaintInfo.pixmapOn =
false;
00749
if (!pixmapFile.isEmpty()) {
00750 mPaintInfo.pixmapOn =
true;
00751 mPaintInfo.pixmap =
QPixmap( pixmapFile );
00752 }
00753 }
00754
00755 {
00756 KConfigGroupSaver saver(config,
"General");
00757
bool show = config->readBoolEntry(
"showMessageSize");
00758 mPopup->setItemChecked(mSizeColumn, show);
00759
slotToggleSizeColumn(show);
00760
00761 mPaintInfo.showCryptoIcons = config->readBoolEntry(
"showCryptoIcons",
false );
00762 mPaintInfo.showAttachmentIcon = config->readBoolEntry(
"showAttachmentIcon",
true );
00763
00764 KMime::DateFormatter::FormatType t =
00765 (KMime::DateFormatter::FormatType) config->readNumEntry(
"dateFormat", KMime::DateFormatter::Fancy ) ;
00766 mDate.setCustomFormat( config->readEntry(
"customDateFormat") );
00767 mDate.setFormat( t );
00768 }
00769
00770
readColorConfig();
00771
00772
00773 {
00774 KConfigGroupSaver saver(config,
"Fonts");
00775
if (!(config->readBoolEntry(
"defaultFonts",
true)))
00776 {
00777
QFont listFont( KGlobalSettings::generalFont() );
00778 setFont(config->readFontEntry(
"list-font", &listFont));
00779 dateFont = KGlobalSettings::fixedFont();
00780 dateFont = config->readFontEntry(
"list-date-font", &dateFont);
00781 }
else {
00782 dateFont = KGlobalSettings::generalFont();
00783 setFont(dateFont);
00784 }
00785 }
00786
00787
00788 {
00789 KConfigGroupSaver saver(config,
"Geometry");
00790 mReaderWindowActive = config->readEntry(
"readerWindowMode",
"below" ) !=
"hide";
00791 }
00792 }
00793
00794
00795
00796
void KMHeaders::reset(
void)
00797 {
00798
int top =
topItemIndex();
00799
int id =
currentItemIndex();
00800 noRepaint =
true;
00801 clear();
00802 noRepaint =
false;
00803 mItems.resize(0);
00804 updateMessageList();
00805
setCurrentMsg(
id);
00806
setTopItemByIndex(top);
00807 ensureCurrentItemVisible();
00808 }
00809
00810
00811
void KMHeaders::refreshNestedState(
void)
00812 {
00813
bool oldState =
isThreaded();
00814 NestingPolicy oldNestPolicy = nestingPolicy;
00815 KConfig* config = KMKernel::config();
00816 KConfigGroupSaver saver(config,
"Geometry");
00817 mNested = config->readBoolEntry(
"nestedMessages",
false );
00818
00819 nestingPolicy = (NestingPolicy)config->readNumEntry(
"nestingPolicy", OpenUnread );
00820
if ((nestingPolicy != oldNestPolicy) ||
00821 (oldState !=
isThreaded()))
00822 {
00823 setRootIsDecorated( nestingPolicy != AlwaysOpen &&
isThreaded() );
00824
reset();
00825 }
00826
00827 }
00828
00829
00830
void KMHeaders::readFolderConfig (
void)
00831 {
00832
if (!mFolder)
return;
00833 KConfig* config = KMKernel::config();
00834
00835 KConfigGroupSaver saver(config,
"Folder-" + mFolder->idString());
00836 mNestedOverride = config->readBoolEntry(
"threadMessagesOverride",
false );
00837 mSortCol = config->readNumEntry(
"SortColumn", (
int)KMMsgList::sfDate);
00838 mSortDescending = (mSortCol < 0);
00839 mSortCol = abs(mSortCol) - 1;
00840
00841 mTopItem = config->readNumEntry(
"Top", 0);
00842 mCurrentItem = config->readNumEntry(
"Current", 0);
00843 mCurrentItemSerNum = config->readNumEntry(
"CurrentSerialNum", 0);
00844
00845 mPaintInfo.orderOfArrival = config->readBoolEntry(
"OrderOfArrival",
true );
00846 mPaintInfo.status = config->readBoolEntry(
"Status",
false );
00847
00848 {
00849 KConfigGroupSaver saver(config,
"Geometry");
00850 mNested = config->readBoolEntry(
"nestedMessages",
false );
00851 nestingPolicy = (NestingPolicy)config->readNumEntry(
"nestingPolicy", OpenUnread );
00852 }
00853
00854 setRootIsDecorated( nestingPolicy != AlwaysOpen &&
isThreaded() );
00855 mSubjThreading = config->readBoolEntry(
"threadMessagesBySubject",
true );
00856 }
00857
00858
00859
00860
void KMHeaders::writeFolderConfig (
void)
00861 {
00862
if (!mFolder)
return;
00863 KConfig* config = KMKernel::config();
00864
int mSortColAdj = mSortCol + 1;
00865
00866 KConfigGroupSaver saver(config,
"Folder-" + mFolder->idString());
00867 config->writeEntry(
"SortColumn", (mSortDescending ? -mSortColAdj : mSortColAdj));
00868 config->writeEntry(
"Top",
topItemIndex());
00869 config->writeEntry(
"Current",
currentItemIndex());
00870 KMHeaderItem* current =
currentHeaderItem();
00871 ulong sernum = 0;
00872
if ( current && mFolder->getMsgBase( current->msgId() ) )
00873 sernum = mFolder->getMsgBase( current->msgId() )->getMsgSerNum();
00874 config->writeEntry(
"CurrentSerialNum", sernum);
00875
00876 config->writeEntry(
"OrderOfArrival", mPaintInfo.orderOfArrival);
00877 config->writeEntry(
"Status", mPaintInfo.status);
00878 }
00879
00880
00881
void KMHeaders::writeConfig (
void)
00882 {
00883 KConfig* config = KMKernel::config();
00884 saveLayout(config,
"Header-Geometry");
00885 KConfigGroupSaver saver(config,
"General");
00886 config->writeEntry(
"showMessageSize", mPaintInfo.showSize);
00887 }
00888
00889
00890
void KMHeaders::setFolder(
KMFolder *aFolder,
bool forceJumpToUnread )
00891 {
00892 CREATE_TIMER(set_folder);
00893 START_TIMER(set_folder);
00894
00895
int id;
00896
QString str;
00897
00898 mSortInfo.fakeSort = 0;
00899
if ( mFolder && static_cast<KMFolder*>(mFolder) == aFolder ) {
00900
int top =
topItemIndex();
00901
id =
currentItemIndex();
00902
writeFolderConfig();
00903
readFolderConfig();
00904 updateMessageList();
00905
setCurrentMsg(
id);
00906
setTopItemByIndex(top);
00907 }
else {
00908
if (mFolder) {
00909
00910
00911
highlightMessage(0,
false);
00912
00913 disconnect(mFolder, SIGNAL(numUnreadMsgsChanged(
KMFolder*)),
00914
this, SLOT(
setFolderInfoStatus()));
00915
00916 mFolder->markNewAsUnread();
00917
writeFolderConfig();
00918 disconnect(mFolder, SIGNAL(
msgHeaderChanged(
KMFolder*,
int)),
00919
this, SLOT(
msgHeaderChanged(
KMFolder*,
int)));
00920 disconnect(mFolder, SIGNAL(
msgAdded(
int)),
00921
this, SLOT(
msgAdded(
int)));
00922 disconnect(mFolder, SIGNAL(
msgRemoved(
int,
QString,
QString)),
00923
this, SLOT(
msgRemoved(
int,
QString,
QString)));
00924 disconnect(mFolder, SIGNAL(changed()),
00925
this, SLOT(
msgChanged()));
00926 disconnect(mFolder, SIGNAL(cleared()),
00927
this, SLOT(
folderCleared()));
00928 disconnect(mFolder, SIGNAL(expunged()),
00929
this, SLOT(
folderCleared()));
00930 disconnect( mFolder, SIGNAL( statusMsg(
const QString& ) ),
00931 BroadcastStatus::instance(), SLOT( setStatusMsg(
const QString& ) ) );
00932 writeSortOrder();
00933 mFolder->close();
00934
00935
00936
if (mFolder->dirty()) mFolder->writeIndex();
00937 }
00938
00939 mSortInfo.removed = 0;
00940 mFolder = aFolder;
00941 mSortInfo.dirty =
true;
00942 mOwner->editAction()->setEnabled(mFolder ?
00943 (kmkernel->folderIsDraftOrOutbox(mFolder)):
false );
00944 mOwner->replyListAction()->setEnabled(mFolder ?
00945 mFolder->isMailingListEnabled() :
false);
00946
if (mFolder)
00947 {
00948 connect(mFolder, SIGNAL(
msgHeaderChanged(
KMFolder*,
int)),
00949
this, SLOT(
msgHeaderChanged(
KMFolder*,
int)));
00950 connect(mFolder, SIGNAL(
msgAdded(
int)),
00951
this, SLOT(
msgAdded(
int)));
00952 connect(mFolder, SIGNAL(
msgRemoved(
int,
QString,
QString)),
00953
this, SLOT(
msgRemoved(
int,
QString,
QString)));
00954 connect(mFolder, SIGNAL(changed()),
00955
this, SLOT(
msgChanged()));
00956 connect(mFolder, SIGNAL(cleared()),
00957
this, SLOT(
folderCleared()));
00958 connect(mFolder, SIGNAL(expunged()),
00959
this, SLOT(
folderCleared()));
00960 connect(mFolder, SIGNAL(statusMsg(
const QString&)),
00961 BroadcastStatus::instance(), SLOT( setStatusMsg(
const QString& ) ) );
00962 connect(mFolder, SIGNAL(numUnreadMsgsChanged(
KMFolder*)),
00963
this, SLOT(
setFolderInfoStatus()));
00964
00965
00966
00967
00968
if (
isThreaded()) {
00969 noRepaint =
true;
00970 clear();
00971 noRepaint =
false;
00972 mItems.resize( 0 );
00973 }
00974
00975
readFolderConfig();
00976
00977 CREATE_TIMER(kmfolder_open);
00978 START_TIMER(kmfolder_open);
00979 mFolder->open();
00980 END_TIMER(kmfolder_open);
00981 SHOW_TIMER(kmfolder_open);
00982
00983
if (
isThreaded()) {
00984 noRepaint =
true;
00985 clear();
00986 noRepaint =
false;
00987 mItems.resize( 0 );
00988 }
00989 }
00990 }
00991
00992 CREATE_TIMER(updateMsg);
00993 START_TIMER(updateMsg);
00994 updateMessageList(
true, forceJumpToUnread);
00995 END_TIMER(updateMsg);
00996 SHOW_TIMER(updateMsg);
00997
makeHeaderVisible();
00998
00999
if (mFolder)
01000
setFolderInfoStatus();
01001
01002
QString colText = i18n(
"Sender" );
01003
if (mFolder && (mFolder->whoField().lower() ==
"to"))
01004 colText = i18n(
"Receiver");
01005 setColumnText( mPaintInfo.senderCol, colText);
01006
01007 colText = i18n(
"Date" );
01008
if (mPaintInfo.orderOfArrival)
01009 colText = i18n(
"Date (Order of Arrival)" );
01010 setColumnText( mPaintInfo.dateCol, colText);
01011
01012 colText = i18n(
"Subject" );
01013
if (mPaintInfo.status)
01014 colText = colText + i18n(
" (Status)" );
01015 setColumnText( mPaintInfo.subCol, colText);
01016
01017 END_TIMER(set_folder);
01018 SHOW_TIMER(set_folder);
01019 }
01020
01021
01022
void KMHeaders::msgChanged()
01023 {
01024 emit
maybeDeleting();
01025
if (mFolder->count() == 0) {
01026 clear();
01027
return;
01028 }
01029
int i =
topItemIndex();
01030
int cur =
currentItemIndex();
01031
if (!isUpdatesEnabled())
return;
01032
QString msgIdMD5;
01033
QListViewItem *item = currentItem();
01034 KMHeaderItem *hi = dynamic_cast<KMHeaderItem*>(item);
01035
if (item && hi) {
01036 KMMsgBase *mb = mFolder->getMsgBase(hi->msgId());
01037
if (mb)
01038 msgIdMD5 = mb->msgIdMD5();
01039 }
01040
if (!isUpdatesEnabled())
return;
01041
01042 disconnect(
this,SIGNAL(currentChanged(
QListViewItem*)),
01043
this,SLOT(
highlightMessage(
QListViewItem*)));
01044
01045
QValueList<int> curItems =
selectedItems();
01046 updateMessageList();
01047
01048
setTopItemByIndex( i );
01049
setCurrentMsg( cur );
01050
setSelectedByIndex( curItems,
true );
01051 connect(
this,SIGNAL(currentChanged(
QListViewItem*)),
01052
this,SLOT(
highlightMessage(
QListViewItem*)));
01053
01054
01055
01056
01057
01058
01059
01060
01061 item = currentItem();
01062 hi = dynamic_cast<KMHeaderItem*>(item);
01063
if (item && hi) {
01064 KMMsgBase *mb = mFolder->getMsgBase(hi->msgId());
01065
if (mb) {
01066
if (msgIdMD5.isEmpty() || (msgIdMD5 != mb->msgIdMD5()))
01067 emit
selected(mFolder->getMsg(hi->msgId()));
01068 }
else {
01069 emit
selected(0);
01070 }
01071 }
else
01072 emit
selected(0);
01073 }
01074
01075
01076
01077
void KMHeaders::msgAdded(
int id)
01078 {
01079 KMHeaderItem* hi = 0;
01080
if (!isUpdatesEnabled())
return;
01081
01082 CREATE_TIMER(
msgAdded);
01083 START_TIMER(
msgAdded);
01084
01085 assert( mFolder->getMsgBase(
id ) );
01086
01087
01088 KMSortCacheItem *sci =
new KMSortCacheItem;
01089 sci->setId(
id);
01090
if (
isThreaded()) {
01091
01092
if (mSortCacheItems.count() == (uint)mFolder->count()
01093 || mSortCacheItems.count() == 0) {
01094 kdDebug (5006) <<
"KMHeaders::msgAdded - Resizing id and subject trees of " << mFolder->label()
01095 <<
": before=" << mSortCacheItems.count() <<
" ,after=" << (mFolder->count()*2) << endl;
01096 mSortCacheItems.resize(mFolder->count()*2);
01097 mSubjectLists.resize(mFolder->count()*2);
01098 }
01099
QString msgId = mFolder->getMsgBase(
id)->msgIdMD5();
01100
if (msgId.isNull())
01101 msgId =
"";
01102
QString replyToId = mFolder->getMsgBase(
id)->replyToIdMD5();
01103
01104 KMSortCacheItem *parent = findParent( sci );
01105
if (!parent && mSubjThreading) {
01106 parent = findParentBySubject( sci );
01107
if (parent && sci->isImperfectlyThreaded()) {
01108
01109
01110
01111
01112
if (msgId == mFolder->getMsgBase(parent->item()->msgId())->replyToIdMD5()
01113 || msgId == mFolder->getMsgBase(parent->item()->msgId())->replyToAuxIdMD5())
01114 parent = NULL;
01115 }
01116 }
01117
01118
if (parent && mFolder->getMsgBase(parent->id())->isWatched())
01119 mFolder->getMsgBase(
id)->setStatus( KMMsgStatusWatched );
01120
else if (parent && mFolder->getMsgBase(parent->id())->isIgnored()) {
01121 mFolder->getMsgBase(
id)->setStatus( KMMsgStatusIgnored );
01122 mFolder->setStatus(
id, KMMsgStatusRead );
01123 }
01124
if (parent)
01125 hi =
new KMHeaderItem( parent->item(),
id );
01126
else
01127 hi =
new KMHeaderItem(
this,
id );
01128
01129
01130 hi->setSortCacheItem(sci);
01131 sci->setItem(hi);
01132
01133
01134 mItems.resize( mFolder->count() );
01135 mItems[
id] = hi;
01136
01137
if ( !msgId.isEmpty() )
01138 mSortCacheItems.replace(msgId, sci);
01139
01140
01141
if (mSubjThreading && parent) {
01142
QString subjMD5 = mFolder->getMsgBase(
id)->strippedSubjectMD5();
01143
if (subjMD5.isEmpty()) {
01144 mFolder->getMsgBase(
id)->initStrippedSubjectMD5();
01145 subjMD5 = mFolder->getMsgBase(
id)->strippedSubjectMD5();
01146 }
01147
if( !subjMD5.isEmpty()) {
01148
if ( !mSubjectLists.find(subjMD5) )
01149 mSubjectLists.insert(subjMD5,
new QPtrList<KMSortCacheItem>());
01150
01151
int p=0;
01152
for (
QPtrListIterator<KMSortCacheItem> it(*mSubjectLists[subjMD5]);
01153 it.current(); ++it) {
01154 KMMsgBase *mb = mFolder->getMsgBase((*it)->id());
01155
if ( mb->date() < mFolder->getMsgBase(
id)->date())
01156
break;
01157 p++;
01158 }
01159 mSubjectLists[subjMD5]->insert( p, sci);
01160 }
01161 }
01162
01163
01164
01165
01166
01167
01168 disconnect(
this, SIGNAL(currentChanged(
QListViewItem*)),
01169
this, SLOT(
highlightMessage(
QListViewItem*)));
01170
01171
if ( !msgId.isEmpty() ) {
01172
QPtrListIterator<KMHeaderItem> it(mImperfectlyThreadedList);
01173 KMHeaderItem *cur;
01174
while ( (cur = it.current()) ) {
01175 ++it;
01176
int tryMe = cur->msgId();
01177
01178
01179
01180
bool perfectParent =
true;
01181 KMMsgBase *otherMsg = mFolder->getMsgBase(tryMe);
01182
if ( !otherMsg ) {
01183 kdDebug(5006) <<
"otherMsg is NULL !!! tryMe: " << tryMe << endl;
01184
continue;
01185 }
01186
QString otherId = otherMsg->replyToIdMD5();
01187
if (msgId != otherId) {
01188
if (msgId != otherMsg->replyToAuxIdMD5())
01189
continue;
01190
else {
01191
if (!otherId.isEmpty() && mSortCacheItems.find(otherId))
01192
continue;
01193
else
01194
01195
01196 perfectParent =
false;
01197 }
01198 }
01199
QListViewItem *newParent = mItems[
id];
01200
QListViewItem *msg = mItems[tryMe];
01201
01202
if (msg->parent())
01203 msg->parent()->takeItem(msg);
01204
else
01205 takeItem(msg);
01206 newParent->insertItem(msg);
01207
01208
makeHeaderVisible();
01209
01210
if (perfectParent) {
01211 mImperfectlyThreadedList.removeRef (mItems[tryMe]);
01212
01213
01214
QString sortFile = KMAIL_SORT_FILE(mFolder);
01215 FILE *sortStream = fopen(QFile::encodeName(sortFile),
"r+");
01216
if (sortStream) {
01217 mItems[tryMe]->sortCacheItem()->updateSortFile( sortStream, mFolder );
01218 fclose (sortStream);
01219 }
01220 }
01221 }
01222 }
01223
01224
if (hi && hi->sortCacheItem()->isImperfectlyThreaded())
01225 mImperfectlyThreadedList.append(hi);
01226 }
else {
01227
01228 hi =
new KMHeaderItem(
this,
id );
01229 mItems.resize( mFolder->count() );
01230 mItems[
id] = hi;
01231
01232 hi->setSortCacheItem(sci);
01233 sci->setItem(hi);
01234 }
01235
if (mSortInfo.fakeSort) {
01236 QObject::disconnect(header(), SIGNAL(clicked(
int)),
this, SLOT(
dirtySortOrder(
int)));
01237 KListView::setSorting(mSortCol, !mSortDescending );
01238 mSortInfo.fakeSort = 0;
01239 }
01240 appendItemToSortFile(hi);
01241
01242
msgHeaderChanged(mFolder,
id);
01243
01244
if ((childCount() == 1) && hi) {
01245
setSelected( hi,
true );
01246 setCurrentItem( firstChild() );
01247 setSelectionAnchor( currentItem() );
01248
highlightMessage( currentItem() );
01249 }
01250
01251
01252 connect(
this, SIGNAL(currentChanged(
QListViewItem*)),
01253
this, SLOT(
highlightMessage(
QListViewItem*)));
01254
01255 emit
messageListUpdated();
01256 END_TIMER(
msgAdded);
01257 SHOW_TIMER(
msgAdded);
01258 }
01259
01260
01261
01262
void KMHeaders::msgRemoved(
int id,
QString msgId,
QString strippedSubjMD5)
01263 {
01264
if (!isUpdatesEnabled())
return;
01265
01266
if ((id < 0) || (id >= (
int)mItems.size()))
01267
return;
01268
01269
01270
01271
01272
01273 disconnect(
this, SIGNAL(currentChanged(
QListViewItem*)),
01274
this, SLOT(
highlightMessage(
QListViewItem*)));
01275
01276 KMHeaderItem *removedItem = mItems[
id];
01277
if (!removedItem)
return;
01278 KMHeaderItem *curItem =
currentHeaderItem();
01279
01280
for (
int i =
id; i < (
int)mItems.size() - 1; ++i) {
01281 mItems[i] = mItems[i+1];
01282 mItems[i]->setMsgId( i );
01283 mItems[i]->sortCacheItem()->setId( i );
01284 }
01285
01286 mItems.resize( mItems.size() - 1 );
01287
01288
if (
isThreaded() && mFolder->count()) {
01289
if ( !msgId.isEmpty() && mSortCacheItems[msgId] ) {
01290
if (mSortCacheItems[msgId] == removedItem->sortCacheItem())
01291 mSortCacheItems.remove(msgId);
01292 }
01293
01294
01295
if (!strippedSubjMD5.isEmpty() &&
01296 mSubjThreading && mSubjectLists[strippedSubjMD5])
01297 mSubjectLists[strippedSubjMD5]->remove(removedItem->sortCacheItem());
01298
01299
01300
QListViewItem *myParent = removedItem;
01301
QListViewItem *myChild = myParent->firstChild();
01302
QListViewItem *threadRoot = myParent;
01303
while (threadRoot->parent())
01304 threadRoot = threadRoot->parent();
01305
QString key = static_cast<KMHeaderItem*>(threadRoot)->key(mSortCol, !mSortDescending);
01306
01307
QPtrList<QListViewItem> childList;
01308
while (myChild) {
01309 KMHeaderItem *item = static_cast<KMHeaderItem*>(myChild);
01310
01311
if ( !item->aboutToBeDeleted() ) {
01312 childList.append(myChild);
01313 }
01314 myChild = myChild->nextSibling();
01315
if ( item->aboutToBeDeleted() ) {
01316 myParent->takeItem( item );
01317 insertItem( item );
01318 }
01319 item->setTempKey( key + item->key( mSortCol, !mSortDescending ));
01320
if (mSortInfo.fakeSort) {
01321 QObject::disconnect(header(), SIGNAL(clicked(
int)),
this, SLOT(
dirtySortOrder(
int)));
01322 KListView::setSorting(mSortCol, !mSortDescending );
01323 mSortInfo.fakeSort = 0;
01324 }
01325 }
01326
01327
for (
QPtrListIterator<QListViewItem> it(childList); it.current() ; ++it ) {
01328
QListViewItem *lvi = *it;
01329 KMHeaderItem *item = static_cast<KMHeaderItem*>(lvi);
01330 KMSortCacheItem *sci = item->sortCacheItem();
01331 KMSortCacheItem *parent = findParent( sci );
01332
if (!parent) parent = findParentBySubject( sci );
01333 myParent->takeItem(lvi);
01334
if (parent && parent->item() != item)
01335 parent->item()->insertItem(lvi);
01336
else
01337 insertItem(lvi);
01338
01339
if (!parent || (sci->isImperfectlyThreaded()
01340 && !mImperfectlyThreadedList.containsRef(item)))
01341 mImperfectlyThreadedList.append(item);
01342
if (parent && !sci->isImperfectlyThreaded()
01343 && mImperfectlyThreadedList.containsRef(item))
01344 mImperfectlyThreadedList.removeRef(item);
01345 }
01346 }
01347
01348
if (!mFolder->count())
01349
folderCleared();
01350
01351 mImperfectlyThreadedList.removeRef(removedItem);
01352
delete removedItem;
01353
01354
if ( curItem && curItem != removedItem ) {
01355 setCurrentItem( curItem );
01356 setSelectionAnchor( currentItem() );
01357 }
01358
01359
01360 connect(
this, SIGNAL(currentChanged(
QListViewItem*)),
01361
this, SLOT(
highlightMessage(
QListViewItem*)));
01362
01363 }
01364
01365
01366
01367
void KMHeaders::msgHeaderChanged(
KMFolder*,
int msgId)
01368 {
01369
if (msgId<0 || msgId >= (
int)mItems.size() || !isUpdatesEnabled())
return;
01370 KMHeaderItem *item = mItems[msgId];
01371
if (item) {
01372 item->irefresh();
01373 item->repaint();
01374 }
01375 }
01376
01377
01378
01379
void KMHeaders::setMsgStatus (KMMsgStatus status,
bool toggle)
01380 {
01381
SerNumList serNums;
01382
for (
QListViewItemIterator it(
this); it.current(); ++it)
01383
if ( it.current()->isSelected() && it.current()->isVisible() ) {
01384 KMHeaderItem *item = static_cast<KMHeaderItem*>(it.current());
01385 KMMsgBase *msgBase = mFolder->getMsgBase(item->msgId());
01386 serNums.append( msgBase->getMsgSerNum() );
01387 }
01388
if (serNums.empty())
01389
return;
01390
01391 KMCommand *command =
new KMSetStatusCommand( status, serNums, toggle );
01392 command->start();
01393 }
01394
01395
01396
QPtrList<QListViewItem> KMHeaders::currentThread()
const
01397
{
01398
if (!mFolder)
return QPtrList<QListViewItem>();
01399
01400
01401
QListViewItem *curItem = currentItem();
01402
if (!curItem)
return QPtrList<QListViewItem>();
01403
01404
01405
QListViewItem *topOfThread = curItem;
01406
while ( topOfThread->parent() )
01407 topOfThread = topOfThread->parent();
01408
01409
01410
QPtrList<QListViewItem> list;
01411
QListViewItem *topOfNextThread = topOfThread->nextSibling();
01412
for (
QListViewItemIterator it( topOfThread ) ;
01413 it.current() && it.current() != topOfNextThread ; ++it )
01414 list.append( it.current() );
01415
return list;
01416 }
01417
01418
void KMHeaders::setThreadStatus(KMMsgStatus status,
bool toggle)
01419 {
01420
QPtrList<QListViewItem> curThread =
currentThread();
01421
QPtrListIterator<QListViewItem> it( curThread );
01422
SerNumList serNums;
01423
01424
for ( it.toFirst() ; it.current() ; ++it ) {
01425
int id = static_cast<KMHeaderItem*>(*it)->msgId();
01426 KMMsgBase *msgBase = mFolder->getMsgBase(
id );
01427 serNums.append( msgBase->getMsgSerNum() );
01428 }
01429
01430
if (serNums.empty())
01431
return;
01432
01433 KMCommand *command =
new KMSetStatusCommand( status, serNums, toggle );
01434 command->start();
01435 }
01436
01437
01438
int KMHeaders::slotFilterMsg(KMMessage *msg)
01439 {
01440 msg->setTransferInProgress(
false);
01441
int filterResult = kmkernel->filterMgr()->process(msg,KMFilterMgr::Explicit);
01442
if (filterResult == 2) {
01443
01444 kmkernel->emergencyExit( i18n(
"Unable to process messages: " ) + QString::fromLocal8Bit(strerror(errno)));
01445
return 2;
01446 }
01447
if (msg->parent()) {
01448
int idx = -1;
01449
KMFolder * p = 0;
01450 kmkernel->msgDict()->getLocation( msg, &p, &idx );
01451 assert( p == msg->parent() ); assert( idx >= 0 );
01452 p->
unGetMsg( idx );
01453 }
01454
01455
return filterResult;
01456 }
01457
01458
01459
void KMHeaders::slotExpandOrCollapseThread(
bool expand )
01460 {
01461
if ( !
isThreaded() )
return;
01462
01463
QListViewItem *item = currentItem();
01464
if ( !item )
return;
01465 clearSelection();
01466 item->setSelected(
true );
01467
while ( item->parent() )
01468 item = item->parent();
01469 KMHeaderItem * hdrItem = static_cast<KMHeaderItem*>(item);
01470 hdrItem->setOpenRecursive( expand );
01471
if ( !expand )
01472
setCurrentMsg( hdrItem->msgId() );
01473 ensureItemVisible( currentItem() );
01474 }
01475
01476
void KMHeaders::slotExpandOrCollapseAllThreads(
bool expand )
01477 {
01478
if ( !
isThreaded() )
return;
01479
01480
QListViewItem * item = currentItem();
01481
if( item ) {
01482 clearSelection();
01483 item->setSelected(
true );
01484 }
01485
01486
for (
QListViewItem *item = firstChild() ;
01487 item ; item = item->nextSibling() )
01488 static_cast<KMHeaderItem*>(item)->setOpenRecursive( expand );
01489
if ( !expand ) {
01490
QListViewItem * item = currentItem();
01491
if( item ) {
01492
while ( item->parent() )
01493 item = item->parent();
01494
setCurrentMsg( static_cast<KMHeaderItem*>(item)->msgId() );
01495 }
01496 }
01497 ensureItemVisible( currentItem() );
01498 }
01499
01500
01501
void KMHeaders::setStyleDependantFrameWidth()
01502 {
01503
01504
int frameWidth;
01505
if( style().isA(
"KeramikStyle") )
01506 frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth ) - 1;
01507
else
01508 frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth );
01509
if ( frameWidth < 0 )
01510 frameWidth = 0;
01511
if ( frameWidth != lineWidth() )
01512 setLineWidth( frameWidth );
01513 }
01514
01515
01516
void KMHeaders::styleChange(
QStyle& oldStyle )
01517 {
01518
setStyleDependantFrameWidth();
01519 KListView::styleChange( oldStyle );
01520 }
01521
01522
01523
void KMHeaders::setFolderInfoStatus ()
01524 {
01525
if ( !mFolder )
return;
01526
QString str = ( static_cast<KMFolder*>(mFolder) == kmkernel->outboxFolder() )
01527 ? i18n(
"1 unsent",
"%n unsent", mFolder->countUnread() )
01528 : i18n(
"1 unread",
"%n unread", mFolder->countUnread() );
01529 str = i18n(
"1 message, %1.",
"%n messages, %1.", mFolder->count() )
01530 .arg( str );
01531
if ( mFolder->isReadOnly() )
01532 str = i18n(
"%1 = n messages, m unread.",
"%1 Folder is read-only.").arg( str );
01533 BroadcastStatus::instance()->setStatusMsg(str);
01534 }
01535
01536
01537
void KMHeaders::applyFiltersOnMsg()
01538 {
01539
#if 0 // uses action scheduler
01540
KMFilterMgr::FilterSet set = KMFilterMgr::All;
01541
QPtrList<KMFilter> filters;
01542 filters = *( kmkernel->filterMgr() );
01543 ActionScheduler *scheduler =
new ActionScheduler( set, filters,
this );
01544 scheduler->setAutoDestruct(
true );
01545
01546
int contentX, contentY;
01547 KMHeaderItem *nextItem = prepareMove( &contentX, &contentY );
01548
QPtrList<KMMsgBase> msgList = *
selectedMsgs(
true);
01549 finalizeMove( nextItem, contentX, contentY );
01550
01551
for (KMMsgBase *msg = msgList.first(); msg; msg = msgList.next())
01552 scheduler->execFilters( msg );
01553
#else
01554
emit
maybeDeleting();
01555
01556 disconnect(
this,SIGNAL(currentChanged(
QListViewItem*)),
01557
this,SLOT(
highlightMessage(
QListViewItem*)));
01558
KMMessageList* msgList =
selectedMsgs();
01559
int topX = contentsX();
01560
int topY = contentsY();
01561
01562
if (msgList->isEmpty())
01563
return;
01564
QListViewItem *qlvi = currentItem();
01565
QListViewItem *next = qlvi;
01566
while (next && next->isSelected())
01567 next = next->itemBelow();
01568
if (!next || (next && next->isSelected())) {
01569 next = qlvi;
01570
while (next && next->isSelected())
01571 next = next->itemAbove();
01572 }
01573
01574 clearSelection();
01575
for (KMMsgBase* msgBase=msgList->first(); msgBase; msgBase=msgList->next()) {
01576
int idx = msgBase->parent()->find(msgBase);
01577 assert(idx != -1);
01578 KMMessage * msg = msgBase->parent()->getMsg(idx);
01579
if (msg->transferInProgress())
continue;
01580 msg->setTransferInProgress(
true);
01581
if ( !msg->isComplete() )
01582 {
01583 FolderJob *job = mFolder->createJob(msg);
01584 connect(job, SIGNAL(messageRetrieved(KMMessage*)),
01585 SLOT(
slotFilterMsg(KMMessage*)));
01586 job->start();
01587 }
else {
01588
if (
slotFilterMsg(msg) == 2)
break;
01589 }
01590 }
01591
01592 setContentsPos( topX, topY );
01593 emit
selected( 0 );
01594
if (next) {
01595 setCurrentItem( next );
01596
setSelected( next,
true );
01597 setSelectionAnchor( currentItem() );
01598
highlightMessage( next );
01599 }
01600
else if (currentItem()) {
01601
setSelected( currentItem(),
true );
01602 setSelectionAnchor( currentItem() );
01603
highlightMessage( currentItem() );
01604 }
01605
else
01606 emit
selected( 0 );
01607
01608
makeHeaderVisible();
01609 connect(
this,SIGNAL(currentChanged(
QListViewItem*)),
01610
this,SLOT(
highlightMessage(
QListViewItem*)));
01611
#endif
01612
}
01613
01614
01615
01616
void KMHeaders::setMsgRead (
int msgId)
01617 {
01618 KMMsgBase *msgBase = mFolder->getMsgBase( msgId );
01619
if (!msgBase)
01620
return;
01621
01622
SerNumList serNums;
01623
if (msgBase->isNew() || msgBase->isUnread()) {
01624 serNums.append( msgBase->getMsgSerNum() );
01625 }
01626
01627 KMCommand *command =
new KMSetStatusCommand( KMMsgStatusRead, serNums );
01628 command->start();
01629 }
01630
01631
01632
01633
void KMHeaders::deleteMsg ()
01634 {
01635
01636
if (!mFolder)
01637
return;
01638
01639
int contentX, contentY;
01640 KMHeaderItem *nextItem = prepareMove( &contentX, &contentY );
01641
KMMessageList msgList = *
selectedMsgs(
true);
01642 finalizeMove( nextItem, contentX, contentY );
01643
01644 KMCommand *command =
new KMDeleteMsgCommand( mFolder, msgList );
01645 connect( command, SIGNAL( completed( KMCommand * ) ),
01646
this, SLOT( slotMoveCompleted( KMCommand * ) ) );
01647 command->start();
01648
01649 BroadcastStatus::instance()->setStatusMsg(
"");
01650
01651 }
01652
01653
01654
01655
void KMHeaders::moveSelectedToFolder(
int menuId )
01656 {
01657
if (mMenuToFolder[menuId])
01658
moveMsgToFolder( mMenuToFolder[menuId] );
01659 }
01660
01661
01662 KMHeaderItem* KMHeaders::prepareMove(
int *contentX,
int *contentY )
01663 {
01664 KMHeaderItem *ret = 0;
01665 emit
maybeDeleting();
01666
01667 disconnect(
this, SIGNAL(currentChanged(
QListViewItem*)),
01668
this, SLOT(
highlightMessage(
QListViewItem*)));
01669
01670
QListViewItem *curItem;
01671 KMHeaderItem *item;
01672 curItem = currentItem();
01673
while (curItem && curItem->isSelected() && curItem->itemBelow())
01674 curItem = curItem->itemBelow();
01675
while (curItem && curItem->isSelected() && curItem->itemAbove())
01676 curItem = curItem->itemAbove();
01677 item = static_cast<KMHeaderItem*>(curItem);
01678
01679 *contentX = contentsX();
01680 *contentY = contentsY();
01681
01682
if (item && !item->isSelected())
01683 ret = item;
01684
01685
return ret;
01686 }
01687
01688
01689
void KMHeaders::finalizeMove( KMHeaderItem *item,
int contentX,
int contentY )
01690 {
01691 emit
selected( 0 );
01692
01693
if ( item ) {
01694 clearSelection();
01695 setCurrentItem( item );
01696
setSelected( item,
true );
01697 setSelectionAnchor( currentItem() );
01698 mPrevCurrent = 0;
01699
highlightMessage( item,
false);
01700 }
01701
01702 setContentsPos( contentX, contentY );
01703
makeHeaderVisible();
01704 connect(
this, SIGNAL(currentChanged(
QListViewItem*)),
01705
this, SLOT(
highlightMessage(
QListViewItem*)));
01706 }
01707
01708
01709
01710
void KMHeaders::moveMsgToFolder (
KMFolder* destFolder,
bool askForConfirmation )
01711 {
01712
KMMessageList msgList = *
selectedMsgs();
01713
if ( !destFolder && askForConfirmation &&
01714 KMessageBox::warningContinueCancel(
this,
01715 i18n(
"<qt>Do you really want to delete the selected message?<br>"
01716
"Once deleted, it cannot be restored.</qt>",
01717
"<qt>Do you really want to delete the %n selected messages?<br>"
01718
"Once deleted, they cannot be restored.</qt>", msgList.count() ),
01719 i18n(
"Delete Messages"), KGuiItem(i18n(
"De&lete"),
"editdelete"),
"NoConfirmDelete") == KMessageBox::Cancel )
01720
return;
01721
01722
01723
int contentX, contentY;
01724 KMHeaderItem *nextItem = prepareMove( &contentX, &contentY );
01725 msgList = *
selectedMsgs(
true);
01726 finalizeMove( nextItem, contentX, contentY );
01727
01728 KMCommand *command =
new KMMoveCommand( destFolder, msgList );
01729 connect( command, SIGNAL( completed( KMCommand * ) ),
01730
this, SLOT( slotMoveCompleted( KMCommand * ) ) );
01731 command->start();
01732
01733 }
01734
01735
void KMHeaders::slotMoveCompleted( KMCommand *command )
01736 {
01737 kdDebug(5006) << k_funcinfo << command->result() << endl;
01738
bool deleted = static_cast<KMMoveCommand *>( command )->destFolder() == 0;
01739
if ( command->result() == KMCommand::OK ) {
01740
01741
makeHeaderVisible();
01742
#if 0 // enable after the message-freeze
01743
BroadcastStatus::instance()->setStatusMsg(
01744 deleted ? i18nTODO(
"Messages deleted successfully.") : i18nTODO(
"Messages moved successfully") );
01745
#else
01746
if ( !deleted ) BroadcastStatus::instance()->setStatusMsg( i18n(
"Messages moved successfully" ) );
01747
#endif
01748
}
else {
01749
01750
01751
01752
01753
01754
01755
for (
QListViewItemIterator it(
this); it.current(); it++) {
01756 KMHeaderItem *item = static_cast<KMHeaderItem*>(it.current());
01757
if ( item->aboutToBeDeleted() ) {
01758 item->setAboutToBeDeleted (
false );
01759 item->setSelectable (
true );
01760 KMMsgBase *msgBase = mFolder->getMsgBase(item->msgId());
01761
if ( msgBase->isMessage() ) {
01762 KMMessage *msg = static_cast<KMMessage *>(msgBase);
01763
if ( msg ) msg->setTransferInProgress(
false,
true );
01764 }
01765 }
01766 }
01767 triggerUpdate();
01768
#if 0 // enable after the message-freeze
01769
if ( command->result() == KMCommand::Failed )
01770 BroadcastStatus::instance()->setStatusMsg(
01771 deleted ? i18nTODO(
"Deleting messages failed.") : i18nTODO(
"Moving messages failed.") );
01772
else
01773 BroadcastStatus::instance()->setStatusMsg(
01774 deleted ? i18nTODO(
"Deleting messages canceled.") : i18nTODO(
"Moving messages canceled.") );
01775
#else
01776
if ( !deleted ) {
01777
if ( command->result() == KMCommand::Failed )
01778 BroadcastStatus::instance()->setStatusMsg( i18n(
"Moving messages failed.") );
01779
else
01780 BroadcastStatus::instance()->setStatusMsg( i18n(
"Moving messages canceled.") );
01781 }
01782
#endif
01783
}
01784 }
01785
01786
bool KMHeaders::canUndo()
const
01787
{
01788
return ( kmkernel->undoStack()->size() > 0 );
01789 }
01790
01791
01792
void KMHeaders::undo()
01793 {
01794 kmkernel->undoStack()->undo();
01795 }
01796
01797
01798
void KMHeaders::copySelectedToFolder(
int menuId )
01799 {
01800
if (mMenuToFolder[menuId])
01801
copyMsgToFolder( mMenuToFolder[menuId] );
01802 }
01803
01804
01805
01806
void KMHeaders::copyMsgToFolder(
KMFolder* destFolder, KMMessage* aMsg)
01807 {
01808
if ( !destFolder )
01809
return;
01810
01811 KMCommand * command = 0;
01812
if (aMsg)
01813 command =
new KMCopyCommand( destFolder, aMsg );
01814
else {
01815
KMMessageList msgList = *
selectedMsgs();
01816 command =
new KMCopyCommand( destFolder, msgList );
01817 }
01818
01819 command->start();
01820 }
01821
01822
01823
01824
void KMHeaders::setCurrentMsg(
int cur)
01825 {
01826
if (!mFolder)
return;
01827
if (cur >= mFolder->count()) cur = mFolder->count() - 1;
01828
if ((cur >= 0) && (cur < (
int)mItems.size())) {
01829 clearSelection();
01830 setCurrentItem( mItems[cur] );
01831
setSelected( mItems[cur],
true );
01832 setSelectionAnchor( currentItem() );
01833 }
01834
makeHeaderVisible();
01835
setFolderInfoStatus();
01836 }
01837
01838
01839
void KMHeaders::setSelected(
QListViewItem *item,
bool selected )
01840 {
01841
if ( !item )
01842
return;
01843
01844
if ( item->isVisible() )
01845 KListView::setSelected( item, selected );
01846
01847
01848
01849
if (
isThreaded() && !item->isOpen() && item->firstChild() ) {
01850
QListViewItem *nextRoot = item->itemBelow();
01851
QListViewItemIterator it( item->firstChild() );
01852
for( ; (*it) != nextRoot; ++it ) {
01853
if ( (*it)->isVisible() )
01854 (*it)->setSelected( selected );
01855 }
01856 }
01857 }
01858
01859
void KMHeaders::setSelectedByIndex(
QValueList<int> items,
bool selected )
01860 {
01861
for (
QValueList<int>::Iterator it = items.begin(); it != items.end(); ++it )
01862 {
01863
if ( ((*it) >= 0) && ((*it) < (
int)mItems.size()) )
01864 {
01865
setSelected( mItems[(*it)], selected );
01866 }
01867 }
01868 }
01869
01870
void KMHeaders::clearSelectableAndAboutToBeDeleted( Q_UINT32 serNum )
01871 {
01872
01873
for (
QListViewItemIterator it(
this); it.current(); it++) {
01874 KMHeaderItem *item = static_cast<KMHeaderItem*>(it.current());
01875
if ( item->aboutToBeDeleted() ) {
01876 KMMsgBase *msgBase = mFolder->getMsgBase( item->msgId() );
01877
if ( serNum == msgBase->getMsgSerNum() ) {
01878 item->setAboutToBeDeleted (
false );
01879 item->setSelectable (
true );
01880 }
01881 }
01882 }
01883 triggerUpdate();
01884 }
01885
01886
01887
KMMessageList*
KMHeaders::selectedMsgs(
bool toBeDeleted)
01888 {
01889 mSelMsgBaseList.clear();
01890
for (
QListViewItemIterator it(
this); it.current(); it++) {
01891
if ( it.current()->isSelected() && it.current()->isVisible() ) {
01892 KMHeaderItem *item = static_cast<KMHeaderItem*>(it.current());
01893
if (toBeDeleted) {
01894
01895 item->setAboutToBeDeleted (
true );
01896 item->setSelectable (
false );
01897 }
01898 KMMsgBase *msgBase = mFolder->getMsgBase(item->msgId());
01899 mSelMsgBaseList.append(msgBase);
01900 }
01901 }
01902
return &mSelMsgBaseList;
01903 }
01904
01905
01906
QValueList<int> KMHeaders::selectedItems()
01907 {
01908
QValueList<int> items;
01909
for (
QListViewItemIterator it(
this); it.current(); it++ )
01910 {
01911
if ( it.current()->isSelected() && it.current()->isVisible() )
01912 {
01913 KMHeaderItem* item = static_cast<KMHeaderItem*>( it.current() );
01914 items.append( item->msgId() );
01915 }
01916 }
01917
return items;
01918 }
01919
01920
01921
int KMHeaders::firstSelectedMsg()
const
01922
{
01923
int selectedMsg = -1;
01924
QListViewItem *item;
01925
for (item = firstChild(); item; item = item->itemBelow())
01926
if (item->isSelected()) {
01927 selectedMsg = (static_cast<KMHeaderItem*>(item))->msgId();
01928
break;
01929 }
01930
return selectedMsg;
01931 }
01932
01933
01934
void KMHeaders::nextMessage()
01935 {
01936
QListViewItem *lvi = currentItem();
01937
if (lvi && lvi->itemBelow()) {
01938 clearSelection();
01939
setSelected( lvi,
false );
01940
selectNextMessage();
01941 setSelectionAnchor( currentItem() );
01942 ensureCurrentItemVisible();
01943 }
01944 }
01945
01946
void KMHeaders::selectNextMessage()
01947 {
01948
QListViewItem *lvi = currentItem();
01949
if( lvi ) {
01950
QListViewItem *below = lvi->itemBelow();
01951
QListViewItem *temp = lvi;
01952
if (lvi && below ) {
01953
while (temp) {
01954 temp->firstChild();
01955 temp = temp->parent();
01956 }
01957 lvi->repaint();
01958
01959 (below->isSelected() ?
setSelected(lvi,
false) :
setSelected(below,
true));
01960 setCurrentItem(below);
01961
makeHeaderVisible();
01962
setFolderInfoStatus();
01963 }
01964 }
01965 }
01966
01967
01968
void KMHeaders::prevMessage()
01969 {
01970
QListViewItem *lvi = currentItem();
01971
if (lvi && lvi->itemAbove()) {
01972 clearSelection();
01973
setSelected( lvi,
false );
01974
selectPrevMessage();
01975 setSelectionAnchor( currentItem() );
01976 ensureCurrentItemVisible();
01977 }
01978 }
01979
01980
void KMHeaders::selectPrevMessage()
01981 {
01982
QListViewItem *lvi = currentItem();
01983
if( lvi ) {
01984
QListViewItem *above = lvi->itemAbove();
01985
QListViewItem *temp = lvi;
01986
01987
if (lvi && above) {
01988
while (temp) {
01989 temp->firstChild();
01990 temp = temp->parent();
01991 }
01992 lvi->repaint();
01993
01994 (above->isSelected() ?
setSelected(lvi,
false) :
setSelected(above,
true));
01995 setCurrentItem(above);
01996
makeHeaderVisible();
01997
setFolderInfoStatus();
01998 }
01999 }
02000 }
02001
02002
02003
void KMHeaders::findUnreadAux( KMHeaderItem*& item,
02004
bool & foundUnreadMessage,
02005
bool onlyNew,
02006
bool aDirNext )
02007 {
02008 KMMsgBase* msgBase = 0;
02009 KMHeaderItem *lastUnread = 0;
02010
02011
if (aDirNext)
02012 {
02013
while (item) {
02014 msgBase = mFolder->getMsgBase(item->msgId());
02015
if (!msgBase)
continue;
02016
if (msgBase->isUnread() || msgBase->isNew())
02017 foundUnreadMessage =
true;
02018
02019
if (!onlyNew && (msgBase->isUnread() || msgBase->isNew()))
break;
02020
if (onlyNew && msgBase->isNew())
break;
02021 item = static_cast<KMHeaderItem*>(item->itemBelow());
02022 }
02023 }
else {
02024 KMHeaderItem *newItem = static_cast<KMHeaderItem*>(firstChild());
02025
while (newItem)
02026 {
02027 msgBase = mFolder->getMsgBase(newItem->msgId());
02028
if (!msgBase)
continue;
02029
if (msgBase->isUnread() || msgBase->isNew())
02030 foundUnreadMessage =
true;
02031
if (!onlyNew && (msgBase->isUnread() || msgBase->isNew())
02032 || onlyNew && msgBase->isNew())
02033 lastUnread = newItem;
02034
if (newItem == item)
break;
02035 newItem = static_cast<KMHeaderItem*>(newItem->itemBelow());
02036 }
02037 item = lastUnread;
02038 }
02039 }
02040
02041
02042
int KMHeaders::findUnread(
bool aDirNext,
int aStartAt,
bool onlyNew,
bool acceptCurrent)
02043 {
02044 KMHeaderItem *item, *pitem;
02045
bool foundUnreadMessage =
false;
02046
02047
if (!mFolder)
return -1;
02048
if (!(mFolder->count()) > 0)
return -1;
02049
02050
if ((aStartAt >= 0) && (aStartAt < (
int)mItems.size()))
02051 item = mItems[aStartAt];
02052
else {
02053 item =
currentHeaderItem();
02054
if (!item) {
02055
if (aDirNext)
02056 item = static_cast<KMHeaderItem*>(firstChild());
02057
else
02058 item = static_cast<KMHeaderItem*>(lastChild());
02059 }
02060
if (!item)
02061
return -1;
02062
02063
if ( !acceptCurrent )
02064
if (aDirNext)
02065 item = static_cast<KMHeaderItem*>(item->itemBelow());
02066
else
02067 item = static_cast<KMHeaderItem*>(item->itemAbove());
02068 }
02069
02070 pitem = item;
02071
02072
findUnreadAux( item, foundUnreadMessage, onlyNew, aDirNext );
02073
02074
02075
02076
02077
02078
02079
if (item) {
02080
QListViewItem *next = item;
02081
while (next->parent())
02082 next = next->parent();
02083 next = static_cast<KMHeaderItem*>(next)->firstChildNonConst();
02084
while (next && (next != item))
02085
if (static_cast<KMHeaderItem*>(next)->firstChildNonConst())
02086 next = next->firstChild();
02087
else if (next->nextSibling())
02088 next = next->nextSibling();
02089
else {
02090
while (next && (next != item)) {
02091 next = next->parent();
02092
if (next == item)
02093
break;
02094
if (next && next->nextSibling()) {
02095 next = next->nextSibling();
02096
break;
02097 }
02098 }
02099 }
02100 }
02101
02102 item = pitem;
02103
02104
findUnreadAux( item, foundUnreadMessage, onlyNew, aDirNext );
02105
if (item)
02106
return item->msgId();
02107
02108
02109
02110
int unread = mFolder->countUnread();
02111
if (((unread == 0) && foundUnreadMessage) ||
02112 ((unread > 0) && !foundUnreadMessage)) {
02113 mFolder->correctUnreadMsgsCount();
02114 }
02115
return -1;
02116 }
02117
02118
02119
bool KMHeaders::nextUnreadMessage(
bool acceptCurrent)
02120 {
02121
if ( !mFolder || !mFolder->countUnread() )
return false;
02122
int i =
findUnread(
true, -1,
false, acceptCurrent);
02123
if ( i < 0 && GlobalSettings::loopOnGotoUnread() !=
02124 GlobalSettings::EnumLoopOnGotoUnread::DontLoop )
02125 {
02126 KMHeaderItem * first = static_cast<KMHeaderItem*>(firstChild());
02127
if ( first )
02128 i =
findUnread(
true, first->msgId(),
false, acceptCurrent);
02129 }
02130
if ( i < 0 )
02131
return false;
02132
setCurrentMsg(i);
02133 ensureCurrentItemVisible();
02134
return true;
02135 }
02136
02137
void KMHeaders::ensureCurrentItemVisible()
02138 {
02139
int i =
currentItemIndex();
02140
if ((i >= 0) && (i < (
int)mItems.size()))
02141 center( contentsX(), itemPos(mItems[i]), 0, 9.0 );
02142 }
02143
02144
02145
bool KMHeaders::prevUnreadMessage()
02146 {
02147
if ( !mFolder || !mFolder->countUnread() )
return false;
02148
int i =
findUnread(
false);
02149
if ( i < 0 && GlobalSettings::loopOnGotoUnread() !=
02150 GlobalSettings::EnumLoopOnGotoUnread::DontLoop )
02151 {
02152 KMHeaderItem * last = static_cast<KMHeaderItem*>(lastItem());
02153
if ( last )
02154 i =
findUnread(
false, last->msgId() );
02155 }
02156
if ( i < 0 )
02157
return false;
02158
setCurrentMsg(i);
02159 ensureCurrentItemVisible();
02160
return true;
02161 }
02162
02163
02164
02165
void KMHeaders::slotNoDrag()
02166 {
02167 mMousePressed =
false;
02168 }
02169
02170
02171
02172
void KMHeaders::makeHeaderVisible()
02173 {
02174
if (currentItem())
02175 ensureItemVisible( currentItem() );
02176 }
02177
02178
02179
void KMHeaders::highlightMessage(
QListViewItem* lvi,
bool markitread)
02180 {
02181
02182
if (lvi && !lvi->isSelectable())
return;
02183
02184 KMHeaderItem *item = static_cast<KMHeaderItem*>(lvi);
02185
if (lvi != mPrevCurrent) {
02186
if (mPrevCurrent && mFolder)
02187 {
02188 KMMessage *prevMsg = mFolder->getMsg(mPrevCurrent->msgId());
02189
if (prevMsg && mReaderWindowActive)
02190 {
02191 mFolder->ignoreJobsForMessage(prevMsg);
02192
if (!prevMsg->transferInProgress())
02193 mFolder->unGetMsg(mPrevCurrent->msgId());
02194 }
02195 }
02196 mPrevCurrent = item;
02197 }
02198
02199
if (!item)
02200 {
02201 emit
selected( 0 );
return;
02202 }
02203
02204
int idx = item->msgId();
02205
if (mReaderWindowActive)
02206 {
02207 KMMessage *msg = mFolder->getMsg(idx);
02208
if (!msg || msg->transferInProgress())
02209 {
02210 emit
selected( 0 );
02211 mPrevCurrent = 0;
02212
return;
02213 }
02214 }
02215
02216 BroadcastStatus::instance()->setStatusMsg(
"");
02217
if (markitread && idx >= 0) setMsgRead(idx);
02218 mItems[idx]->irefresh();
02219 mItems[idx]->repaint();
02220 emit
selected(mFolder->getMsg(idx));
02221
setFolderInfoStatus();
02222 }
02223
02224
void KMHeaders::resetCurrentTime()
02225 {
02226 mDate.reset();
02227 QTimer::singleShot( 1000,
this, SLOT(
resetCurrentTime() ) );
02228 }
02229
02230
02231
void KMHeaders::selectMessage(
QListViewItem* lvi)
02232 {
02233 KMHeaderItem *item = static_cast<KMHeaderItem*>(lvi);
02234
if (!item)
02235
return;
02236
02237
int idx = item->msgId();
02238 KMMessage *msg = mFolder->getMsg(idx);
02239
if (!msg->transferInProgress())
02240 {
02241 emit
activated(mFolder->getMsg(idx));
02242 }
02243
02244
02245
02246 }
02247
02248
02249
02250
void KMHeaders::updateMessageList(
bool set_selection,
bool forceJumpToUnread )
02251 {
02252 mPrevCurrent = 0;
02253 noRepaint =
true;
02254 clear();
02255 noRepaint =
false;
02256 KListView::setSorting( mSortCol, !mSortDescending );
02257
if (!mFolder) {
02258 mItems.resize(0);
02259 repaint();
02260
return;
02261 }
02262 readSortOrder( set_selection, forceJumpToUnread );
02263 emit
messageListUpdated();
02264 }
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278
02279
02280
02281
02282
02283
void KMHeaders::keyPressEvent(
QKeyEvent * e )
02284 {
02285
bool cntrl = (e->state() & ControlButton );
02286
bool shft = (e->state() & ShiftButton );
02287
QListViewItem *cur = currentItem();
02288
02289
if (!e || !firstChild())
02290
return;
02291
02292
02293
if (!cur) {
02294 setCurrentItem( firstChild() );
02295 setSelectionAnchor( currentItem() );
02296
return;
02297 }
02298
02299
02300
if (cur->isSelectable() && e->ascii() ==
' ' ) {
02301
setSelected( cur, !cur->isSelected() );
02302
highlightMessage( cur,
false);
02303
return;
02304 }
02305
02306
if (cntrl) {
02307
if (!shft)
02308 disconnect(
this,SIGNAL(currentChanged(
QListViewItem*)),
02309
this,SLOT(
highlightMessage(
QListViewItem*)));
02310
switch (e->key()) {
02311
case Key_Down:
02312
case Key_Up:
02313
case Key_Home:
02314
case Key_End:
02315
case Key_Next:
02316
case Key_Prior:
02317
case Key_Escape:
02318 KListView::keyPressEvent( e );
02319 }
02320
if (!shft)
02321 connect(
this,SIGNAL(currentChanged(
QListViewItem*)),
02322
this,SLOT(
highlightMessage(
QListViewItem*)));
02323 }
02324 }
02325
02326
02327
02328
void KMHeaders::rightButtonPressed(
QListViewItem *lvi,
const QPoint &,
int )
02329 {
02330
if (!lvi)
02331
return;
02332
02333
if (!(lvi->isSelected())) {
02334 clearSelection();
02335 }
02336
setSelected( lvi,
true );
02337
slotRMB();
02338 }
02339
02340
02341
void KMHeaders::contentsMousePressEvent(
QMouseEvent* e)
02342 {
02343 mPressPos = e->pos();
02344
QListViewItem *lvi = itemAt( contentsToViewport( e->pos() ));
02345
bool wasSelected =
false;
02346
bool rootDecoClicked =
false;
02347
if (lvi) {
02348 wasSelected = lvi->isSelected();
02349 rootDecoClicked =
02350 ( mPressPos.x() <= header()->cellPos( header()->mapToActual( 0 ) ) +
02351 treeStepSize() * ( lvi->depth() + ( rootIsDecorated() ? 1 : 0 ) ) + itemMargin() )
02352 && ( mPressPos.x() >= header()->cellPos( header()->mapToActual( 0 ) ) );
02353
02354
if ( rootDecoClicked ) {
02355
02356
02357
02358
02359
if ( !lvi->isOpen() && lvi->firstChild() ) {
02360
QListViewItem *nextRoot = lvi->itemBelow();
02361
QListViewItemIterator it( lvi->firstChild() );
02362
for( ; (*it) != nextRoot; ++it )
02363 (*it)->setSelected(
false );
02364 }
02365 }
02366 }
02367
02368
02369 KListView::contentsMousePressEvent(e);
02370
02371
02372
02373
if ( e->state() & ShiftButton ) {
02374
QListViewItemIterator it(
this, QListViewItemIterator::Invisible );
02375
while ( it.current() ) {
02376 it.current()->setSelected(
false );
02377 ++it;
02378 }
02379 }
02380
02381
if ( rootDecoClicked ) {
02382
02383
if ( lvi && !lvi->isOpen() && lvi->isSelected() )
02384
setSelected( lvi,
true );
02385 }
02386
02387
if ( lvi && !rootDecoClicked ) {
02388
if ( lvi != currentItem() )
02389
highlightMessage( lvi );
02390
02391
02392
02393
02394
if ( !( e->state() & ControlButton ) && !wasSelected )
02395
setSelected( lvi,
true );
02396
02397
if ( e->state() & ControlButton )
02398
setSelected( lvi, !wasSelected );
02399
02400
if ((e->button() == LeftButton) )
02401 mMousePressed =
true;
02402 }
02403 }
02404
02405
02406
void KMHeaders::contentsMouseReleaseEvent(
QMouseEvent* e)
02407 {
02408
if (e->button() != RightButton)
02409 KListView::contentsMouseReleaseEvent(e);
02410
02411 mMousePressed =
false;
02412 }
02413
02414
02415
void KMHeaders::contentsMouseMoveEvent(
QMouseEvent* e )
02416 {
02417
if (mMousePressed &&
02418 (e->pos() - mPressPos).manhattanLength() > KGlobalSettings::dndEventDelay()) {
02419 mMousePressed =
false;
02420
QListViewItem *item = itemAt( contentsToViewport(mPressPos) );
02421
if ( item ) {
02422 MailList mailList;
02423
unsigned int count = 0;
02424
for(
QListViewItemIterator it(
this); it.current(); it++ )
02425
if( it.current()->isSelected() ) {
02426 KMHeaderItem *item = static_cast<KMHeaderItem*>(it.current());
02427 KMMsgBase *msg = mFolder->getMsgBase(item->msgId());
02428 MailSummary mailSummary( msg->getMsgSerNum(), msg->msgIdMD5(),
02429 msg->subject(), msg->fromStrip(),
02430 msg->toStrip(), msg->date() );
02431 mailList.append( mailSummary );
02432 ++count;
02433 }
02434 MailListDrag *d =
new MailListDrag( mailList, viewport() );
02435
02436
02437
QPixmap pixmap;
02438
if( count == 1 )
02439 pixmap =
QPixmap( DesktopIcon(
"message", KIcon::SizeSmall) );
02440
else
02441 pixmap = QPixmap( DesktopIcon(
"kmultiple", KIcon::SizeSmall) );
02442
02443
02444
if( !pixmap.isNull() ) {
02445
QPoint hotspot( pixmap.width() / 2, pixmap.height() / 2 );
02446 d->setPixmap( pixmap, hotspot );
02447 }
02448 d->drag();
02449 }
02450 }
02451 }
02452
02453
void KMHeaders::highlightMessage(
QListViewItem* i)
02454 {
02455
highlightMessage( i,
false );
02456 }
02457
02458
02459
void KMHeaders::slotRMB()
02460 {
02461
if (!topLevelWidget())
return;
02462
02463
QPopupMenu *menu =
new QPopupMenu(
this);
02464
02465 mMenuToFolder.clear();
02466
02467 mOwner->updateMessageMenu();
02468
02469
bool out_folder = kmkernel->folderIsDraftOrOutbox(mFolder);
02470
if ( out_folder )
02471 mOwner->editAction()->plug(menu);
02472
else {
02473
02474 mOwner->replyAction()->plug(menu);
02475 mOwner->replyAllAction()->plug(menu);
02476 mOwner->replyAuthorAction()->plug( menu );
02477 mOwner->replyListAction()->plug(menu);
02478 mOwner->forwardMenu()->plug(menu);
02479 mOwner->bounceAction()->plug(menu);
02480 mOwner->sendAgainAction()->plug(menu);
02481 }
02482 menu->insertSeparator();
02483
02484 QPopupMenu *msgCopyMenu =
new QPopupMenu(menu);
02485 KMCopyCommand::folderToPopupMenu(
false,
this, &mMenuToFolder, msgCopyMenu );
02486 menu->insertItem(i18n(
"&Copy To"), msgCopyMenu);
02487
02488
if ( mFolder->isReadOnly() ) {
02489
int id = menu->insertItem( i18n(
"&Move To") );
02490 menu->setItemEnabled(
id,
false );
02491 }
else {
02492 QPopupMenu *msgMoveMenu =
new QPopupMenu(menu);
02493 KMMoveCommand::folderToPopupMenu(
true,
this, &mMenuToFolder, msgMoveMenu );
02494 menu->insertItem(i18n(
"&Move To"), msgMoveMenu);
02495 }
02496
02497
if ( !out_folder ) {
02498 mOwner->statusMenu()->plug( menu );
02499
if ( mOwner->threadStatusMenu()->isEnabled() ) {
02500 mOwner->threadStatusMenu()->plug( menu );
02501 }
02502 }
02503
02504
if (mOwner->watchThreadAction()->isEnabled() ) {
02505 menu->insertSeparator();
02506 mOwner->watchThreadAction()->plug(menu);
02507 mOwner->ignoreThreadAction()->plug(menu);
02508 }
02509 menu->insertSeparator();
02510 mOwner->trashAction()->plug(menu);
02511 mOwner->deleteAction()->plug(menu);
02512
02513 menu->insertSeparator();
02514 mOwner->saveAsAction()->plug(menu);
02515 mOwner->saveAttachmentsAction()->plug(menu);
02516 mOwner->printAction()->plug(menu);
02517
02518
if ( !out_folder ) {
02519 menu->insertSeparator();
02520 mOwner->action(
"apply_filters")->plug(menu);
02521 mOwner->filterMenu()->plug( menu );
02522 }
02523
02524 mOwner->action(
"apply_filter_actions")->plug(menu);
02525
02526 KAcceleratorManager::manage(menu);
02527 kmkernel->setContextMenuShown(
true );
02528 menu->exec(QCursor::pos(), 0);
02529 kmkernel->setContextMenuShown(
false );
02530
delete menu;
02531 }
02532
02533
02534 KMMessage*
KMHeaders::currentMsg()
02535 {
02536 KMHeaderItem *hi =
currentHeaderItem();
02537
if (!hi)
02538
return 0;
02539
else
02540
return mFolder->getMsg(hi->msgId());
02541 }
02542
02543
02544 KMHeaderItem*
KMHeaders::currentHeaderItem()
02545 {
02546
return static_cast<KMHeaderItem*>(currentItem());
02547 }
02548
02549
02550
int KMHeaders::currentItemIndex()
02551 {
02552 KMHeaderItem* item =
currentHeaderItem();
02553
if (item)
02554
return item->msgId();
02555
else
02556
return -1;
02557 }
02558
02559
02560
void KMHeaders::setCurrentItemByIndex(
int msgIdx)
02561 {
02562
if ((msgIdx >= 0) && (msgIdx < (
int)mItems.size())) {
02563 clearSelection();
02564
bool unchanged = (currentItem() == mItems[msgIdx]);
02565 setCurrentItem( mItems[msgIdx] );
02566
setSelected( mItems[msgIdx],
true );
02567 setSelectionAnchor( currentItem() );
02568
if (unchanged)
02569
highlightMessage( mItems[msgIdx],
false);
02570 }
02571 }
02572
02573
02574
int KMHeaders::topItemIndex()
02575 {
02576 KMHeaderItem *item = static_cast<KMHeaderItem*>(itemAt(
QPoint(1,1)));
02577
if (item)
02578
return item->msgId();
02579
else
02580
return -1;
02581 }
02582
02583
02584
02585
void KMHeaders::showNewMail()
02586 {
02587
if (mSortCol != mPaintInfo.dateCol)
02588
return;
02589
for(
int i = 0; i < (
int)mItems.size(); ++i)
02590
if (mFolder->getMsgBase(i)->isNew()) {
02591
if (!mSortDescending)
02592
setTopItemByIndex(
currentItemIndex() );
02593
break;
02594 }
02595 }
02596
02597
02598
void KMHeaders::setTopItemByIndex(
int aMsgIdx)
02599 {
02600
int msgIdx = aMsgIdx;
02601
if (msgIdx < 0)
02602 msgIdx = 0;
02603
else if (msgIdx >= (
int)mItems.size())
02604 msgIdx = mItems.size() - 1;
02605
if ((msgIdx >= 0) && (msgIdx < (
int)mItems.size()))
02606 setContentsPos( 0, itemPos( mItems[msgIdx] ));
02607 }
02608
02609
02610
void KMHeaders::setNestedOverride(
bool override )
02611 {
02612 mSortInfo.dirty =
true;
02613 mNestedOverride = override;
02614 setRootIsDecorated( nestingPolicy != AlwaysOpen
02615 &&
isThreaded() );
02616
QString sortFile = mFolder->indexLocation() +
".sorted";
02617 unlink(QFile::encodeName(sortFile));
02618
reset();
02619 }
02620
02621
02622
void KMHeaders::setSubjectThreading(
bool aSubjThreading )
02623 {
02624 mSortInfo.dirty =
true;
02625 mSubjThreading = aSubjThreading;
02626
QString sortFile = mFolder->indexLocation() +
".sorted";
02627 unlink(QFile::encodeName(sortFile));
02628
reset();
02629 }
02630
02631
02632
void KMHeaders::setOpen(
QListViewItem *item,
bool open )
02633 {
02634
if ((nestingPolicy != AlwaysOpen)|| open)
02635 ((KMHeaderItem*)item)->setOpenRecursive( open );
02636 }
02637
02638
02639
const KMMsgBase*
KMHeaders::getMsgBaseForItem(
const QListViewItem *item )
const
02640
{
02641
const KMHeaderItem *hi = static_cast<const KMHeaderItem *> ( item );
02642
return mFolder->getMsgBase( hi->msgId() );
02643 }
02644
02645
02646
void KMHeaders::setSorting(
int column,
bool ascending )
02647 {
02648
if (column != -1) {
02649
02650
02651
02652
if(mSortInfo.dirty || column != mSortInfo.column || ascending != mSortInfo.ascending) {
02653 QObject::disconnect(header(), SIGNAL(clicked(
int)),
this, SLOT(
dirtySortOrder(
int)));
02654 mSortInfo.dirty =
true;
02655 }
02656
02657 mSortCol = column;
02658 mSortDescending = !ascending;
02659
02660
if (!ascending && (column == mPaintInfo.dateCol))
02661 mPaintInfo.orderOfArrival = !mPaintInfo.orderOfArrival;
02662
02663
if (!ascending && (column == mPaintInfo.subCol))
02664 mPaintInfo.status = !mPaintInfo.status;
02665
02666
QString colText = i18n(
"Date" );
02667
if (mPaintInfo.orderOfArrival)
02668 colText = i18n(
"Date (Order of Arrival)" );
02669 setColumnText( mPaintInfo.dateCol, colText);
02670
02671 colText = i18n(
"Subject" );
02672
if (mPaintInfo.status)
02673 colText = colText + i18n(
" (Status)" );
02674 setColumnText( mPaintInfo.subCol, colText);
02675 }
02676 KListView::setSorting( column, ascending );
02677 ensureCurrentItemVisible();
02678
02679
02680
if ( mFolder ) {
02681
writeFolderConfig();
02682 writeSortOrder();
02683 }
02684 }
02685
02686
02687
static void internalWriteItem(FILE *sortStream,
KMFolder *folder,
int msgid,
02688
int parent_id,
QString key,
02689
bool update_discover=
true)
02690 {
02691
unsigned long msgSerNum;
02692
unsigned long parentSerNum;
02693 msgSerNum = kmkernel->msgDict()->getMsgSerNum( folder, msgid );
02694
if (parent_id >= 0)
02695 parentSerNum = kmkernel->msgDict()->getMsgSerNum( folder, parent_id ) + KMAIL_RESERVED;
02696
else
02697 parentSerNum = (
unsigned long)(parent_id + KMAIL_RESERVED);
02698
02699 fwrite(&msgSerNum,
sizeof(msgSerNum), 1, sortStream);
02700 fwrite(&parentSerNum,
sizeof(parentSerNum), 1, sortStream);
02701 Q_INT32 len = key.length() *
sizeof(
QChar);
02702 fwrite(&len,
sizeof(len), 1, sortStream);
02703
if (len)
02704 fwrite(key.unicode(), QMIN(len, KMAIL_MAX_KEY_LEN), 1, sortStream);
02705
02706
if (update_discover) {
02707
02708 Q_INT32 discovered_count = 0;
02709 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 20, SEEK_SET);
02710 fread(&discovered_count,
sizeof(discovered_count), 1, sortStream);
02711 discovered_count++;
02712 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 20, SEEK_SET);
02713 fwrite(&discovered_count,
sizeof(discovered_count), 1, sortStream);
02714 }
02715 }
02716
02717
void KMHeaders::folderCleared()
02718 {
02719 mSortCacheItems.clear();
02720 mSubjectLists.clear();
02721 mImperfectlyThreadedList.clear();
02722 mPrevCurrent = 0;
02723 emit
selected(0);
02724 }
02725
02726
bool KMHeaders::writeSortOrder()
02727 {
02728
QString sortFile = KMAIL_SORT_FILE(mFolder);
02729
02730
if (!mSortInfo.dirty) {
02731
struct stat stat_tmp;
02732
if(stat(QFile::encodeName(sortFile), &stat_tmp) == -1) {
02733 mSortInfo.dirty =
true;
02734 }
02735 }
02736
if (mSortInfo.dirty) {
02737
if (!mFolder->count()) {
02738
02739 unlink(QFile::encodeName(sortFile));
02740
return true;
02741 }
02742
QString tempName = sortFile +
".temp";
02743 unlink(QFile::encodeName(tempName));
02744 FILE *sortStream = fopen(QFile::encodeName(tempName),
"w");
02745
if (!sortStream)
02746
return false;
02747
02748 mSortInfo.ascending = !mSortDescending;
02749 mSortInfo.dirty =
false;
02750 mSortInfo.column = mSortCol;
02751 fprintf(sortStream, KMAIL_SORT_HEADER, KMAIL_SORT_VERSION);
02752
02753 Q_INT32 byteOrder = 0x12345678;
02754 Q_INT32 column = mSortCol;
02755 Q_INT32 ascending= !mSortDescending;
02756 Q_INT32 threaded =
isThreaded();
02757 Q_INT32 appended=0;
02758 Q_INT32 discovered_count = 0;
02759 Q_INT32 sorted_count=0;
02760 fwrite(&byteOrder,
sizeof(byteOrder), 1, sortStream);
02761 fwrite(&column,
sizeof(column), 1, sortStream);
02762 fwrite(&ascending,
sizeof(ascending), 1, sortStream);
02763 fwrite(&threaded,
sizeof(threaded), 1, sortStream);
02764 fwrite(&appended,
sizeof(appended), 1, sortStream);
02765 fwrite(&discovered_count,
sizeof(discovered_count), 1, sortStream);
02766 fwrite(&sorted_count,
sizeof(sorted_count), 1, sortStream);
02767
02768
QPtrStack<KMHeaderItem> items;
02769 {
02770
QPtrStack<QListViewItem> s;
02771
for (
QListViewItem * i = firstChild(); i; ) {
02772 items.push((KMHeaderItem *)i);
02773
if ( i->firstChild() ) {
02774 s.push( i );
02775 i = i->firstChild();
02776 }
else if( i->nextSibling()) {
02777 i = i->nextSibling();
02778 }
else {
02779
for(i=0; !i && s.count(); i = s.pop()->nextSibling());
02780 }
02781 }
02782 }
02783
02784 KMMsgBase *kmb;
02785
while(KMHeaderItem *i = items.pop()) {
02786
int parent_id = -1;
02787
if (threaded) {
02788 kmb = mFolder->getMsgBase( i->mMsgId );
02789 assert(kmb);
02790
02791
QString replymd5 = kmb->replyToIdMD5();
02792
QString replyToAuxId = kmb->replyToAuxIdMD5();
02793 KMSortCacheItem *p = NULL;
02794
if(!replymd5.isEmpty())
02795 p = mSortCacheItems[replymd5];
02796
02797
if (p)
02798 parent_id = p->id();
02799
02800
02801
02802
02803
02804
if (replymd5.isEmpty()
02805 && replyToAuxId.isEmpty()
02806 && !kmb->subjectIsPrefixed() )
02807 parent_id = -2;
02808
02809
02810
02811 }
02812 internalWriteItem(sortStream, mFolder, i->mMsgId, parent_id,
02813 i->key(mSortCol, !mSortDescending),
false);
02814
02815 sorted_count++;
02816 }
02817
02818
02819 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET, SEEK_SET);
02820 fwrite(&byteOrder,
sizeof(byteOrder), 1, sortStream);
02821 fwrite(&column,
sizeof(column), 1, sortStream);
02822 fwrite(&ascending,
sizeof(ascending), 1, sortStream);
02823 fwrite(&threaded,
sizeof(threaded), 1, sortStream);
02824 fwrite(&appended,
sizeof(appended), 1, sortStream);
02825 fwrite(&discovered_count,
sizeof(discovered_count), 1, sortStream);
02826 fwrite(&sorted_count,
sizeof(sorted_count), 1, sortStream);
02827
if (sortStream && ferror(sortStream)) {
02828 fclose(sortStream);
02829 unlink(QFile::encodeName(sortFile));
02830 kdWarning(5006) <<
"Error: Failure modifying " << sortFile <<
" (No space left on device?)" << endl;
02831 kdWarning(5006) << __FILE__ <<
":" << __LINE__ << endl;
02832 kmkernel->emergencyExit( i18n(
"Failure modifying %1\n(No space left on device?)").arg( sortFile ));
02833 }
02834 fclose(sortStream);
02835 ::rename(QFile::encodeName(tempName), QFile::encodeName(sortFile));
02836 }
02837
02838
return true;
02839 }
02840
02841
void KMHeaders::appendItemToSortFile(KMHeaderItem *khi)
02842 {
02843
QString sortFile = KMAIL_SORT_FILE(mFolder);
02844
if(FILE *sortStream = fopen(QFile::encodeName(sortFile),
"r+")) {
02845
int parent_id = -1;
02846
02847
if (
isThreaded()) {
02848 KMSortCacheItem *sci = khi->sortCacheItem();
02849 KMMsgBase *kmb = mFolder->getMsgBase( khi->mMsgId );
02850
if(sci->parent() && !sci->isImperfectlyThreaded())
02851 parent_id = sci->parent()->id();
02852
else if(kmb->replyToIdMD5().isEmpty()
02853 && kmb->replyToAuxIdMD5().isEmpty()
02854 && !kmb->subjectIsPrefixed())
02855 parent_id = -2;
02856 }
02857
02858 internalWriteItem(sortStream, mFolder, khi->mMsgId, parent_id,
02859 khi->key(mSortCol, !mSortDescending),
false);
02860
02861
02862 Q_INT32 appended = 1;
02863 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 16, SEEK_SET);
02864 fwrite(&appended,
sizeof(appended), 1, sortStream);
02865 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 16, SEEK_SET);
02866
02867
if (sortStream && ferror(sortStream)) {
02868 fclose(sortStream);
02869 unlink(QFile::encodeName(sortFile));
02870 kdWarning(5006) <<
"Error: Failure modifying " << sortFile <<
" (No space left on device?)" << endl;
02871 kdWarning(5006) << __FILE__ <<
":" << __LINE__ << endl;
02872 kmkernel->emergencyExit( i18n(
"Failure modifying %1\n(No space left on device?)").arg( sortFile ));
02873 }
02874 fclose(sortStream);
02875 }
else {
02876 mSortInfo.dirty =
true;
02877 }
02878 }
02879
02880
void KMHeaders::dirtySortOrder(
int column)
02881 {
02882 mSortInfo.dirty =
true;
02883 QObject::disconnect(header(), SIGNAL(clicked(
int)),
this, SLOT(
dirtySortOrder(
int)));
02884
setSorting(column, mSortInfo.column == column ? !mSortInfo.ascending :
true);
02885 }
02886
void KMSortCacheItem::updateSortFile( FILE *sortStream,
KMFolder *folder,
02887
bool waiting_for_parent,
bool update_discover)
02888 {
02889
if(mSortOffset == -1) {
02890 fseek(sortStream, 0, SEEK_END);
02891 mSortOffset = ftell(sortStream);
02892 }
else {
02893 fseek(sortStream, mSortOffset, SEEK_SET);
02894 }
02895
02896
int parent_id = -1;
02897
if(!waiting_for_parent) {
02898
if(mParent && !isImperfectlyThreaded())
02899 parent_id = mParent->id();
02900 }
02901 internalWriteItem(sortStream, folder, mId, parent_id, mKey, update_discover);
02902 }
02903
02904
static bool compare_ascending =
false;
02905
static bool compare_toplevel =
true;
02906
static int compare_KMSortCacheItem(
const void *s1,
const void *s2)
02907 {
02908
if ( !s1 || !s2 )
02909
return 0;
02910 KMSortCacheItem **b1 = (KMSortCacheItem **)s1;
02911 KMSortCacheItem **b2 = (KMSortCacheItem **)s2;
02912
int ret = (*b1)->key().compare((*b2)->key());
02913
if(compare_ascending || !compare_toplevel)
02914 ret = -ret;
02915
return ret;
02916 }
02917
02918
02919
void KMHeaders::buildThreadingTree(
QMemArray<KMSortCacheItem *> sortCache )
02920 {
02921 mSortCacheItems.clear();
02922 mSortCacheItems.resize( mFolder->count() * 2 );
02923
02924
02925
for(
int x = 0; x < mFolder->count(); x++) {
02926 KMMsgBase *mi = mFolder->getMsgBase(x);
02927
QString md5 = mi->msgIdMD5();
02928
if(!md5.isEmpty())
02929 mSortCacheItems.replace(md5, sortCache[x]);
02930 }
02931 }
02932
02933
02934
void KMHeaders::buildSubjectThreadingTree(
QMemArray<KMSortCacheItem *> sortCache )
02935 {
02936 mSubjectLists.clear();
02937 mSubjectLists.resize( mFolder->count() * 2 );
02938
02939
for(
int x = 0; x < mFolder->count(); x++) {
02940
02941
if ( sortCache[x]->parent()
02942 && sortCache[x]->parent()->id() != -666 )
continue;
02943 KMMsgBase *mi = mFolder->getMsgBase(x);
02944
QString subjMD5 = mi->strippedSubjectMD5();
02945
if (subjMD5.isEmpty()) {
02946 mFolder->getMsgBase(x)->initStrippedSubjectMD5();
02947 subjMD5 = mFolder->getMsgBase(x)->strippedSubjectMD5();
02948 }
02949
if( subjMD5.isEmpty() )
continue;
02950
02951
02952
02953
if (!mSubjectLists.find(subjMD5))
02954 mSubjectLists.insert(subjMD5,
new QPtrList<KMSortCacheItem>());
02955
02956
02957
02958
02959
int p=0;
02960
for (
QPtrListIterator<KMSortCacheItem> it(*mSubjectLists[subjMD5]);
02961 it.current(); ++it) {
02962 KMMsgBase *mb = mFolder->getMsgBase((*it)->id());
02963
if ( mb->date() < mi->date())
02964
break;
02965 p++;
02966 }
02967 mSubjectLists[subjMD5]->insert( p, sortCache[x]);
02968 }
02969 }
02970
02971
02972 KMSortCacheItem* KMHeaders::findParent(KMSortCacheItem *item)
02973 {
02974 KMSortCacheItem *parent = NULL;
02975
if (!item)
return parent;
02976 KMMsgBase *msg = mFolder->getMsgBase(item->id());
02977
QString replyToIdMD5 = msg->replyToIdMD5();
02978 item->setImperfectlyThreaded(
true);
02979
02980
02981
if(!replyToIdMD5.isEmpty()) {
02982 parent = mSortCacheItems[replyToIdMD5];
02983
if (parent)
02984 item->setImperfectlyThreaded(
false);
02985 }
02986
if (!parent) {
02987
02988
02989
02990
02991
02992
02993
QString ref = msg->replyToAuxIdMD5();
02994
if (!ref.isEmpty())
02995 parent = mSortCacheItems[ref];
02996 }
02997
return parent;
02998 }
02999
03000 KMSortCacheItem* KMHeaders::findParentBySubject(KMSortCacheItem *item)
03001 {
03002 KMSortCacheItem *parent = NULL;
03003
if (!item)
return parent;
03004
03005 KMMsgBase *msg = mFolder->getMsgBase(item->id());
03006
03007
03008
03009
03010
if (!msg->subjectIsPrefixed())
03011
return parent;
03012
03013
QString replyToIdMD5 = msg->replyToIdMD5();
03014
QString subjMD5 = msg->strippedSubjectMD5();
03015
if (!subjMD5.isEmpty() && mSubjectLists[subjMD5]) {
03016
03017
03018
for (
QPtrListIterator<KMSortCacheItem> it2(*mSubjectLists[subjMD5]);
03019 it2.current(); ++it2) {
03020 KMMsgBase *mb = mFolder->getMsgBase((*it2)->id());
03021
if ( !mb )
return parent;
03022
03023
if ( item == (*it2) )
continue;
03024
int delta = msg->date() - mb->date();
03025
03026
03027
if (delta > 0 ) {
03028
03029
if (delta < 3628899)
03030 parent = (*it2);
03031
break;
03032 }
03033 }
03034 }
03035
return parent;
03036 }
03037
03038
bool KMHeaders::readSortOrder(
bool set_selection,
bool forceJumpToUnread )
03039 {
03040
03041 Q_INT32 column, ascending, threaded, discovered_count, sorted_count, appended;
03042 Q_INT32 deleted_count = 0;
03043
bool unread_exists =
false;
03044
bool jumpToUnread = GlobalSettings::jumpToUnread() ||
03045 forceJumpToUnread;
03046
QMemArray<KMSortCacheItem *> sortCache(mFolder->count());
03047 KMSortCacheItem root;
03048 root.setId(-666);
03049
bool error =
false;
03050
03051
03052
QPtrList<KMSortCacheItem> unparented;
03053 mImperfectlyThreadedList.clear();
03054
03055
03056 mItems.fill( 0, mFolder->count() );
03057 sortCache.fill( 0 );
03058
03059
QString sortFile = KMAIL_SORT_FILE(mFolder);
03060 FILE *sortStream = fopen(QFile::encodeName(sortFile),
"r+");
03061 mSortInfo.fakeSort = 0;
03062
03063
if(sortStream) {
03064 mSortInfo.fakeSort = 1;
03065
int version = 0;
03066
if (fscanf(sortStream, KMAIL_SORT_HEADER, &version) != 1)
03067 version = -1;
03068
if(version == KMAIL_SORT_VERSION) {
03069 Q_INT32 byteOrder = 0;
03070 fread(&byteOrder,
sizeof(byteOrder), 1, sortStream);
03071
if (byteOrder == 0x12345678)
03072 {
03073 fread(&column,
sizeof(column), 1, sortStream);
03074 fread(&ascending,
sizeof(ascending), 1, sortStream);
03075 fread(&threaded,
sizeof(threaded), 1, sortStream);
03076 fread(&appended,
sizeof(appended), 1, sortStream);
03077 fread(&discovered_count,
sizeof(discovered_count), 1, sortStream);
03078 fread(&sorted_count,
sizeof(sorted_count), 1, sortStream);
03079
03080
03081 KListView::setSorting(-1);
03082 header()->setSortIndicator(column, ascending);
03083 QObject::connect(header(), SIGNAL(clicked(
int)),
this, SLOT(
dirtySortOrder(
int)));
03084
03085 mSortInfo.dirty =
false;
03086 mSortInfo.column = (
short)column;
03087 mSortInfo.ascending = (compare_ascending = ascending);
03088
03089 KMSortCacheItem *item;
03090
unsigned long serNum, parentSerNum;
03091
int id, len, parent, x;
03092
QChar *tmp_qchar = 0;
03093
int tmp_qchar_len = 0;
03094
const int mFolderCount = mFolder->count();
03095
QString key;
03096
03097 CREATE_TIMER(parse);
03098 START_TIMER(parse);
03099
for(x = 0; !feof(sortStream) && !error; x++) {
03100 off_t offset = ftell(sortStream);
03101
KMFolder *folder;
03102
03103
if(!fread(&serNum,
sizeof(serNum), 1, sortStream) ||
03104 !fread(&parentSerNum,
sizeof(parentSerNum), 1, sortStream) ||
03105 !fread(&len,
sizeof(len), 1, sortStream)) {
03106
break;
03107 }
03108
if ((len < 0) || (len > KMAIL_MAX_KEY_LEN)) {
03109 kdDebug(5006) <<
"Whoa.2! len " << len <<
" " << __FILE__ <<
":" << __LINE__ << endl;
03110 error =
true;
03111
continue;
03112 }
03113
if(len) {
03114
if(len > tmp_qchar_len) {
03115 tmp_qchar = (
QChar *)realloc(tmp_qchar, len);
03116 tmp_qchar_len = len;
03117 }
03118
if(!fread(tmp_qchar, len, 1, sortStream))
03119
break;
03120 key =
QString(tmp_qchar, len / 2);
03121 }
else {
03122 key =
QString(
"");
03123 }
03124
03125 kmkernel->msgDict()->getLocation(serNum, &folder, &
id);
03126
if (folder != mFolder) {
03127 ++deleted_count;
03128
continue;
03129 }
03130
if (parentSerNum < KMAIL_RESERVED) {
03131 parent = (
int)parentSerNum - KMAIL_RESERVED;
03132 }
else {
03133 kmkernel->msgDict()->getLocation(parentSerNum - KMAIL_RESERVED, &folder, &parent);
03134
if (folder != mFolder)
03135 parent = -1;
03136 }
03137
if ((id < 0) || (id >= mFolderCount) ||
03138 (parent < -2) || (parent >= mFolderCount)) {
03139 kdDebug(5006) <<
"Whoa.1! " << __FILE__ <<
":" << __LINE__ << endl;
03140 error =
true;
03141
continue;
03142 }
03143
03144
if ((item=sortCache[
id])) {
03145
if (item->id() != -1) {
03146 kdDebug(5006) <<
"Whoa.3! " << __FILE__ <<
":" << __LINE__ << endl;
03147 error =
true;
03148
continue;
03149 }
03150 item->setKey(key);
03151 item->setId(
id);
03152 item->setOffset(offset);
03153 }
else {
03154 item = sortCache[
id] =
new KMSortCacheItem(
id, key, offset);
03155 }
03156
if (threaded && parent != -2) {
03157
if(parent == -1) {
03158 unparented.append(item);
03159 root.addUnsortedChild(item);
03160 }
else {
03161
if( ! sortCache[parent] )
03162 sortCache[parent] =
new KMSortCacheItem;
03163 sortCache[parent]->addUnsortedChild(item);
03164 }
03165 }
else {
03166
if(x < sorted_count )
03167 root.addSortedChild(item);
03168
else {
03169 root.addUnsortedChild(item);
03170 }
03171 }
03172 }
03173
if (error || (x != sorted_count + discovered_count)) {
03174 kdDebug(5006) << endl <<
"Whoa: x " << x <<
", sorted_count " << sorted_count <<
", discovered_count " << discovered_count <<
", count " << mFolder->count() << endl << endl;
03175 fclose(sortStream);
03176 sortStream = 0;
03177 }
03178
03179
if(tmp_qchar)
03180 free(tmp_qchar);
03181 END_TIMER(parse);
03182 SHOW_TIMER(parse);
03183 }
03184
else {
03185 fclose(sortStream);
03186 sortStream = 0;
03187 }
03188 }
else {
03189 fclose(sortStream);
03190 sortStream = 0;
03191 }
03192 }
03193
03194
if (!sortStream) {
03195 mSortInfo.dirty =
true;
03196 mSortInfo.column = column = mSortCol;
03197 mSortInfo.ascending = ascending = !mSortDescending;
03198 threaded = (
isThreaded());
03199 sorted_count = discovered_count = appended = 0;
03200 KListView::setSorting( mSortCol, !mSortDescending );
03201 }
03202
03203
if((sorted_count + discovered_count - deleted_count) < mFolder->count()) {
03204 CREATE_TIMER(holes);
03205 START_TIMER(holes);
03206 KMMsgBase *msg = 0;
03207
for(
int x = 0; x < mFolder->count(); x++) {
03208
if((!sortCache[x] || (sortCache[x]->id() < 0)) && (msg=mFolder->getMsgBase(x))) {
03209
int sortOrder = column;
03210
if (mPaintInfo.orderOfArrival)
03211 sortOrder |= (1 << 6);
03212
if (mPaintInfo.status)
03213 sortOrder |= (1 << 5);
03214 sortCache[x] =
new KMSortCacheItem(
03215 x, KMHeaderItem::generate_key(
this, msg, &mPaintInfo, sortOrder ));
03216
if(threaded)
03217 unparented.append(sortCache[x]);
03218
else
03219 root.addUnsortedChild(sortCache[x]);
03220
if(sortStream)
03221 sortCache[x]->updateSortFile(sortStream, mFolder,
true,
true);
03222 discovered_count++;
03223 appended = 1;
03224 }
03225 }
03226 END_TIMER(holes);
03227 SHOW_TIMER(holes);
03228 }
03229
03230
03231
03232
if (threaded) buildThreadingTree( sortCache );
03233
QPtrList<KMSortCacheItem> toBeSubjThreaded;
03234
03235
if (threaded && !unparented.isEmpty()) {
03236 CREATE_TIMER(reparent);
03237 START_TIMER(reparent);
03238
03239
for(
QPtrListIterator<KMSortCacheItem> it(unparented); it.current(); ++it) {
03240 KMSortCacheItem *item = (*it);
03241 KMSortCacheItem *parent = findParent( item );
03242
03243
if ( parent && (parent != (*it)) ) {
03244 parent->addUnsortedChild((*it));
03245
if(sortStream)
03246 (*it)->updateSortFile(sortStream, mFolder);
03247 }
else {
03248
03249
03250
if (mSubjThreading)
03251 toBeSubjThreaded.append((*it));
03252
else
03253 root.addUnsortedChild((*it));
03254 }
03255 }
03256
03257
if (mSubjThreading) {
03258 buildSubjectThreadingTree( sortCache );
03259
for(
QPtrListIterator<KMSortCacheItem> it(toBeSubjThreaded); it.current(); ++it) {
03260 KMSortCacheItem *item = (*it);
03261 KMSortCacheItem *parent = findParentBySubject( item );
03262
03263
if ( parent ) {
03264 parent->addUnsortedChild((*it));
03265
if(sortStream)
03266 (*it)->updateSortFile(sortStream, mFolder);
03267 }
else {
03268
03269 root.addUnsortedChild((*it));
03270 }
03271 }
03272 }
03273 END_TIMER(reparent);
03274 SHOW_TIMER(reparent);
03275 }
03276
03277 CREATE_TIMER(header_creation);
03278 START_TIMER(header_creation);
03279 KMHeaderItem *khi;
03280 KMSortCacheItem *i, *new_kci;
03281
QPtrQueue<KMSortCacheItem> s;
03282 s.enqueue(&root);
03283 compare_toplevel =
true;
03284
do {
03285 i = s.dequeue();
03286
const QPtrList<KMSortCacheItem> *sorted = i->sortedChildren();
03287
int unsorted_count, unsorted_off=0;
03288 KMSortCacheItem **unsorted = i->unsortedChildren(unsorted_count);
03289
if(unsorted)
03290 qsort(unsorted, unsorted_count,
sizeof(KMSortCacheItem *),
03291 compare_KMSortCacheItem);
03292
03293
03294
03295
03296
03297
for(
QPtrListIterator<KMSortCacheItem> it(*sorted);
03298 (unsorted && unsorted_off < unsorted_count) || it.current(); ) {
03299
03300
03301
03302
03303
03304
if( it.current() &&
03305 ( !unsorted || unsorted_off >= unsorted_count
03306 ||
03307 ( ( !ascending || (ascending && !compare_toplevel) )
03308 && (*it)->key() < unsorted[unsorted_off]->key() )
03309 ||
03310 ( ascending && (*it)->key() >= unsorted[unsorted_off]->key() )
03311 )
03312 )
03313 {
03314 new_kci = (*it);
03315 ++it;
03316 }
else {
03317
03318 new_kci = unsorted[unsorted_off++];
03319 }
03320
if(new_kci->item() || new_kci->parent() != i)
03321
continue;
03322
03323
if(threaded && i->item()) {
03324
03325
03326
if (mFolder->getMsgBase(i->id())->isWatched())
03327 mFolder->getMsgBase(new_kci->id())->setStatus(KMMsgStatusWatched);
03328
if (mFolder->getMsgBase(i->id())->isIgnored()) {
03329 mFolder->getMsgBase(new_kci->id())->setStatus(KMMsgStatusIgnored);
03330 mFolder->setStatus(new_kci->id(), KMMsgStatusRead);
03331 }
03332 khi =
new KMHeaderItem(i->item(), new_kci->id(), new_kci->key());
03333 }
else {
03334 khi =
new KMHeaderItem(
this, new_kci->id(), new_kci->key());
03335 }
03336 new_kci->setItem(mItems[new_kci->id()] = khi);
03337
if(new_kci->hasChildren())
03338 s.enqueue(new_kci);
03339
03340
03341
if ( mFolder->getMsgBase(new_kci->id())->isNew() ||
03342 ( jumpToUnread &&
03343 mFolder->getMsgBase(new_kci->id())->isUnread() ) ) {
03344 unread_exists =
true;
03345 }
03346 }
03347
03348
03349
03350
if (mSortCol ==
paintInfo()->dateCol)
03351 compare_toplevel =
false;
03352 }
while(!s.isEmpty());
03353
03354
for(
int x = 0; x < mFolder->count(); x++) {
03355
if (!sortCache[x]) {
03356
continue;
03357 }
03358
03359
if (!sortCache[x]->item()) {
03360 kdDebug(5006) <<
"KMHeaders::readSortOrder - msg could not be threaded. "
03361 << endl <<
"Please talk to your threading counselor asap. " << endl;
03362 khi =
new KMHeaderItem(
this, sortCache[x]->
id(), sortCache[x]->key());
03363 sortCache[x]->setItem(mItems[sortCache[x]->
id()] = khi);
03364 }
03365
03366
03367
03368
if (threaded && sortCache[x]->isImperfectlyThreaded()) {
03369 mImperfectlyThreadedList.append(sortCache[x]->item());
03370 }
03371
03372
03373 sortCache[x]->item()->setSortCacheItem(sortCache[x]);
03374 }
03375
03376
if (getNestingPolicy()<2)
03377
for (KMHeaderItem *khi=static_cast<KMHeaderItem*>(firstChild()); khi!=0;khi=static_cast<KMHeaderItem*>(khi->nextSibling()))
03378 khi->setOpen(
true);
03379
03380 END_TIMER(header_creation);
03381 SHOW_TIMER(header_creation);
03382
03383
if(sortStream) {
03384
03385
if( discovered_count * discovered_count > sorted_count - deleted_count ) {
03386 mSortInfo.dirty =
true;
03387 }
else {
03388
03389 appended = 0;
03390 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 16, SEEK_SET);
03391 fwrite(&appended,
sizeof(appended), 1, sortStream);
03392 }
03393 }
03394
03395
03396 CREATE_TIMER(selection);
03397 START_TIMER(selection);
03398
if(set_selection) {
03399
int first_unread = -1;
03400
if (unread_exists) {
03401 KMHeaderItem *item = static_cast<KMHeaderItem*>(firstChild());
03402
while (item) {
03403
if ( mFolder->getMsgBase( item->msgId() )->isNew() ||
03404 ( jumpToUnread &&
03405 mFolder->getMsgBase( item->msgId() )->isUnread() ) ) {
03406 first_unread = item->msgId();
03407
break;
03408 }
03409 item = static_cast<KMHeaderItem*>(item->itemBelow());
03410 }
03411 }
03412
03413
if(first_unread == -1 ) {
03414
setTopItemByIndex(mTopItem);
03415
if ( mCurrentItem >= 0 )
03416
setCurrentItemByIndex( mCurrentItem );
03417
else if ( mCurrentItemSerNum > 0 )
03418
setCurrentItemBySerialNum( mCurrentItemSerNum );
03419
else
03420
setCurrentItemByIndex( 0 );
03421 }
else {
03422
setCurrentItemByIndex(first_unread);
03423
makeHeaderVisible();
03424 center( contentsX(), itemPos(mItems[first_unread]), 0, 9.0 );
03425 }
03426 }
else {
03427
03428
if (mCurrentItem <= 0) {
03429
setTopItemByIndex(mTopItem);
03430
setCurrentItemByIndex(0);
03431 }
03432 }
03433 END_TIMER(selection);
03434 SHOW_TIMER(selection);
03435
if (error || (sortStream && ferror(sortStream))) {
03436
if ( sortStream )
03437 fclose(sortStream);
03438 unlink(QFile::encodeName(sortFile));
03439 kdWarning(5006) <<
"Error: Failure modifying " << sortFile <<
" (No space left on device?)" << endl;
03440 kdWarning(5006) << __FILE__ <<
":" << __LINE__ << endl;
03441
03442 }
03443
if(sortStream)
03444 fclose(sortStream);
03445
03446
return true;
03447 }
03448
03449
03450
void KMHeaders::setCurrentItemBySerialNum(
unsigned long serialNum )
03451 {
03452
03453
03454
03455
for (
int i = 0; i < (
int)mItems.size() - 1; ++i) {
03456 KMMsgBase *mMsgBase = mFolder->getMsgBase( i );
03457
if ( mMsgBase->getMsgSerNum() == serialNum ) {
03458
bool unchanged = (currentItem() == mItems[i]);
03459 setCurrentItem( mItems[i] );
03460
setSelected( mItems[i],
true );
03461 setSelectionAnchor( currentItem() );
03462
if ( unchanged )
03463
highlightMessage( currentItem(),
false );
03464 ensureCurrentItemVisible();
03465
return;
03466 }
03467 }
03468
03469 kdDebug(5006) <<
"KMHeaders::setCurrentItem item with serial number " << serialNum <<
" NOT FOUND" << endl;
03470 }
03471
03472
#include "kmheaders.moc"