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