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