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