7 #include "headeritem.h"
10 #include "kcursorsaver.h"
11 #include "kmcommands.h"
12 #include "kmmainwidget.h"
13 #include "kmfiltermgr.h"
14 #include "undostack.h"
15 #include "kmmsgdict.h"
17 #include "kmfoldertree.h"
18 #include "folderjob.h"
19 using KMail::FolderJob;
20 #include "actionscheduler.h"
21 using KMail::ActionScheduler;
22 #include "messagecopyhelper.h"
24 #include "broadcaststatus.h"
25 using KPIM::BroadcastStatus;
26 #include "progressmanager.h"
27 using KPIM::ProgressManager;
28 using KPIM::ProgressItem;
29 #include <maillistdrag.h>
30 #include "globalsettings.h"
32 #include "messageactions.h"
34 #include <tdeapplication.h>
35 #include <tdeaccelmanager.h>
36 #include <tdeglobalsettings.h>
37 #include <tdemessagebox.h>
38 #include <kiconloader.h>
39 #include <tdepopupmenu.h>
41 #include <tdeconfig.h>
42 #include <tdelocale.h>
46 #include <tqeventloop.h>
49 #include <tqptrstack.h>
50 #include <tqptrqueue.h>
51 #include <tqpainter.h>
52 #include <tqtextcodec.h>
54 #include <tqlistview.h>
56 #include <mimelib/enum.h>
57 #include <mimelib/field.h>
58 #include <mimelib/mimepp.h>
63 #include "textsource.h"
65 TQPixmap* KMHeaders::pixNew = 0;
66 TQPixmap* KMHeaders::pixUns = 0;
67 TQPixmap* KMHeaders::pixDel = 0;
68 TQPixmap* KMHeaders::pixRead = 0;
69 TQPixmap* KMHeaders::pixRep = 0;
70 TQPixmap* KMHeaders::pixQueued = 0;
71 TQPixmap* KMHeaders::pixTodo = 0;
72 TQPixmap* KMHeaders::pixSent = 0;
73 TQPixmap* KMHeaders::pixFwd = 0;
74 TQPixmap* KMHeaders::pixFlag = 0;
75 TQPixmap* KMHeaders::pixWatched = 0;
76 TQPixmap* KMHeaders::pixIgnored = 0;
77 TQPixmap* KMHeaders::pixSpam = 0;
78 TQPixmap* KMHeaders::pixHam = 0;
79 TQPixmap* KMHeaders::pixFullySigned = 0;
80 TQPixmap* KMHeaders::pixPartiallySigned = 0;
81 TQPixmap* KMHeaders::pixUndefinedSigned = 0;
82 TQPixmap* KMHeaders::pixFullyEncrypted = 0;
83 TQPixmap* KMHeaders::pixPartiallyEncrypted = 0;
84 TQPixmap* KMHeaders::pixUndefinedEncrypted = 0;
85 TQPixmap* KMHeaders::pixEncryptionProblematic = 0;
86 TQPixmap* KMHeaders::pixSignatureProblematic = 0;
87 TQPixmap* KMHeaders::pixAttachment = 0;
88 TQPixmap* KMHeaders::pixInvitation = 0;
89 TQPixmap* KMHeaders::pixReadFwd = 0;
90 TQPixmap* KMHeaders::pixReadReplied = 0;
91 TQPixmap* KMHeaders::pixReadFwdReplied = 0;
95 KMHeaders::KMHeaders(KMMainWidget *aOwner, TQWidget *parent,
97 TDEListView( parent, name ),
98 mIgnoreSortOrderChanges( false )
100 static bool pixmapsLoaded =
false;
102 KImageIO::registerFormats();
108 setSelectionMode( TQListView::Extended );
109 setAllColumnsShowFocus(
true );
111 nestingPolicy = OpenUnread;
112 mNestedOverride =
false;
113 mSubjThreading =
true;
114 mMousePressed =
false;
115 mSortInfo.dirty =
true;
116 mSortInfo.fakeSort = 0;
117 mSortInfo.removed = 0;
118 mSortInfo.column = 0;
120 mSortDescending =
false;
121 mSortInfo.ascending =
false;
122 mReaderWindowActive =
false;
125 setStyleDependantFrameWidth();
127 header()->setClickEnabled(
true);
128 header()->installEventFilter(
this);
129 mPopup =
new TDEPopupMenu(
this);
130 mPopup->insertTitle(i18n(
"View Columns"));
131 mPopup->setCheckable(
true);
132 mPopup->insertItem(i18n(
"Status"), KPaintInfo::COL_STATUS);
133 mPopup->insertItem(i18n(
"Important"), KPaintInfo::COL_IMPORTANT);
134 mPopup->insertItem(i18n(
"Action Item"), KPaintInfo::COL_TODO);
135 mPopup->insertItem(i18n(
"Attachment"), KPaintInfo::COL_ATTACHMENT);
136 mPopup->insertItem(i18n(
"Invitation"), KPaintInfo::COL_INVITATION);
137 mPopup->insertItem(i18n(
"Spam/Ham"), KPaintInfo::COL_SPAM_HAM);
138 mPopup->insertItem(i18n(
"Watched/Ignored"), KPaintInfo::COL_WATCHED_IGNORED);
139 mPopup->insertItem(i18n(
"Signature"), KPaintInfo::COL_SIGNED);
140 mPopup->insertItem(i18n(
"Encryption"), KPaintInfo::COL_CRYPTO);
141 mPopup->insertItem(i18n(
"Size"), KPaintInfo::COL_SIZE);
142 mPopup->insertItem(i18n(
"Receiver"), KPaintInfo::COL_RECEIVER);
144 connect(mPopup, TQT_SIGNAL(activated(
int)),
this, TQT_SLOT(slotToggleColumn(
int)));
146 setShowSortIndicator(
true);
147 setFocusPolicy( TQ_WheelFocus );
151 pixmapsLoaded =
true;
152 pixNew =
new TQPixmap( UserIcon(
"kmmsgnew" ) );
153 pixUns =
new TQPixmap( UserIcon(
"kmmsgunseen" ) );
154 pixDel =
new TQPixmap( UserIcon(
"kmmsgdel" ) );
155 pixRead =
new TQPixmap( UserIcon(
"kmmsgread" ) );
156 pixRep =
new TQPixmap( UserIcon(
"kmmsgreplied" ) );
157 pixQueued =
new TQPixmap( UserIcon(
"kmmsgqueued" ) );
158 pixTodo =
new TQPixmap( UserIcon(
"kmmsgtodo" ) );
159 pixSent =
new TQPixmap( UserIcon(
"kmmsgsent" ) );
160 pixFwd =
new TQPixmap( UserIcon(
"kmmsgforwarded" ) );
161 pixFlag =
new TQPixmap( UserIcon(
"kmmsgflag" ) );
162 pixWatched =
new TQPixmap( UserIcon(
"kmmsgwatched" ) );
163 pixIgnored =
new TQPixmap( UserIcon(
"kmmsgignored" ) );
164 pixSpam =
new TQPixmap( UserIcon(
"kmmsgspam" ) );
165 pixHam =
new TQPixmap( UserIcon(
"kmmsgham" ) );
166 pixFullySigned =
new TQPixmap( UserIcon(
"kmmsgfullysigned" ) );
167 pixPartiallySigned =
new TQPixmap( UserIcon(
"kmmsgpartiallysigned" ) );
168 pixUndefinedSigned =
new TQPixmap( UserIcon(
"kmmsgundefinedsigned" ) );
169 pixFullyEncrypted =
new TQPixmap( UserIcon(
"kmmsgfullyencrypted" ) );
170 pixPartiallyEncrypted =
new TQPixmap( UserIcon(
"kmmsgpartiallyencrypted" ) );
171 pixUndefinedEncrypted =
new TQPixmap( UserIcon(
"kmmsgundefinedencrypted" ) );
172 pixEncryptionProblematic =
new TQPixmap( UserIcon(
"kmmsgencryptionproblematic" ) );
173 pixSignatureProblematic =
new TQPixmap( UserIcon(
"kmmsgsignatureproblematic" ) );
174 pixAttachment =
new TQPixmap( UserIcon(
"kmmsgattachment" ) );
175 pixInvitation =
new TQPixmap( UserIcon(
"kmmsginvitation" ) );
176 pixReadFwd =
new TQPixmap( UserIcon(
"kmmsgread_fwd" ) );
177 pixReadReplied =
new TQPixmap( UserIcon(
"kmmsgread_replied" ) );
178 pixReadFwdReplied =
new TQPixmap( UserIcon(
"kmmsgread_fwd_replied" ) );
181 header()->setStretchEnabled(
false );
182 header()->setResizeEnabled(
false );
184 mPaintInfo.subCol = addColumn( i18n(
"Subject"), 310 );
185 mPaintInfo.senderCol = addColumn( i18n(
"Sender"), 170 );
186 mPaintInfo.dateCol = addColumn( i18n(
"Date"), 170 );
187 mPaintInfo.sizeCol = addColumn( i18n(
"Size"), 0 );
188 mPaintInfo.receiverCol = addColumn( i18n(
"Receiver"), 0 );
190 mPaintInfo.statusCol = addColumn( *pixNew ,
"", 0 );
191 mPaintInfo.importantCol = addColumn( *pixFlag ,
"", 0 );
192 mPaintInfo.todoCol = addColumn( *pixTodo ,
"", 0 );
193 mPaintInfo.attachmentCol = addColumn( *pixAttachment ,
"", 0 );
194 mPaintInfo.invitationCol = addColumn( *pixInvitation ,
"", 0 );
195 mPaintInfo.spamHamCol = addColumn( *pixSpam ,
"", 0 );
196 mPaintInfo.watchedIgnoredCol = addColumn( *pixWatched ,
"", 0 );
197 mPaintInfo.signedCol = addColumn( *pixFullySigned ,
"", 0 );
198 mPaintInfo.cryptoCol = addColumn( *pixFullyEncrypted,
"", 0 );
200 setResizeMode( TQListView::NoColumn );
203 header()->setResizeEnabled(
true, mPaintInfo.subCol );
204 header()->setResizeEnabled(
true, mPaintInfo.senderCol );
205 header()->setResizeEnabled(
true, mPaintInfo.dateCol );
207 connect(
this, TQT_SIGNAL( contextMenuRequested( TQListViewItem*,
const TQPoint &,
int )),
208 this, TQT_SLOT( rightButtonPressed( TQListViewItem*,
const TQPoint &,
int )));
209 connect(
this, TQT_SIGNAL(doubleClicked(TQListViewItem*)),
210 this,TQT_SLOT(selectMessage(TQListViewItem*)));
211 connect(
this,TQT_SIGNAL(currentChanged(TQListViewItem*)),
212 this,TQT_SLOT(highlightMessage(TQListViewItem*)));
215 mSubjectLists.setAutoDelete(
true );
217 mMoveMessages =
false;
218 connect(
this, TQT_SIGNAL(selectionChanged()), TQT_SLOT(updateActions()) );
223 KMHeaders::~KMHeaders ()
229 mFolder->close(
"kmheaders");
236 bool KMHeaders::eventFilter ( TQObject *o, TQEvent *e )
238 if ( e->type() == TQEvent::MouseButtonPress &&
239 TQT_TQMOUSEEVENT(e)->button() == Qt::RightButton &&
240 o->isA(TQHEADER_OBJECT_NAME_STRING) )
244 if ( mPaintInfo.showReceiver )
245 mPopup->changeItem(KPaintInfo::COL_RECEIVER, i18n(
"Receiver"));
247 if ( mFolder && (mFolder->whoField().lower() ==
"to") )
248 mPopup->changeItem(KPaintInfo::COL_RECEIVER, i18n(
"Sender"));
250 mPopup->changeItem(KPaintInfo::COL_RECEIVER, i18n(
"Receiver"));
252 mPopup->popup( TQT_TQMOUSEEVENT(e)->globalPos() );
255 return TDEListView::eventFilter(o, e);
267 switch ( static_cast<KPaintInfo::ColumnIds>(
id) )
269 case KPaintInfo::COL_SIZE:
271 show = &mPaintInfo.showSize;
272 col = &mPaintInfo.sizeCol;
276 case KPaintInfo::COL_ATTACHMENT:
278 show = &mPaintInfo.showAttachment;
279 col = &mPaintInfo.attachmentCol;
280 width = pixAttachment->width() + 8;
281 if ( *col == header()->mapToIndex( *col ) )
285 case KPaintInfo::COL_INVITATION:
287 show = &mPaintInfo.showInvitation;
288 col = &mPaintInfo.invitationCol;
289 width = pixAttachment->width() + 8;
290 if ( *col == header()->mapToIndex( *col ) )
294 case KPaintInfo::COL_IMPORTANT:
296 show = &mPaintInfo.showImportant;
297 col = &mPaintInfo.importantCol;
298 width = pixFlag->width() + 8;
299 if ( *col == header()->mapToIndex( *col ) )
303 case KPaintInfo::COL_TODO:
305 show = &mPaintInfo.showTodo;
306 col = &mPaintInfo.todoCol;
307 width = pixTodo->width() + 8;
308 if ( *col == header()->mapToIndex( *col ) )
312 case KPaintInfo::COL_SPAM_HAM:
314 show = &mPaintInfo.showSpamHam;
315 col = &mPaintInfo.spamHamCol;
316 width = pixSpam->width() + 8;
317 if ( *col == header()->mapToIndex( *col ) )
321 case KPaintInfo::COL_WATCHED_IGNORED:
323 show = &mPaintInfo.showWatchedIgnored;
324 col = &mPaintInfo.watchedIgnoredCol;
325 width = pixWatched->width() + 8;
326 if ( *col == header()->mapToIndex( *col ) )
330 case KPaintInfo::COL_STATUS:
332 show = &mPaintInfo.showStatus;
333 col = &mPaintInfo.statusCol;
334 width = pixNew->width() + 8;
335 if ( *col == header()->mapToIndex( *col ) )
339 case KPaintInfo::COL_SIGNED:
341 show = &mPaintInfo.showSigned;
342 col = &mPaintInfo.signedCol;
343 width = pixFullySigned->width() + 8;
344 if ( *col == header()->mapToIndex( *col ) )
348 case KPaintInfo::COL_CRYPTO:
350 show = &mPaintInfo.showCrypto;
351 col = &mPaintInfo.cryptoCol;
352 width = pixFullyEncrypted->width() + 8;
353 if ( *col == header()->mapToIndex( *col ) )
357 case KPaintInfo::COL_RECEIVER:
359 show = &mPaintInfo.showReceiver;
360 col = &mPaintInfo.receiverCol;
364 case KPaintInfo::COL_SCORE: ;
375 mPopup->setItemChecked(
id, *show);
378 header()->setResizeEnabled(
true, *col);
379 setColumnWidth(*col, width);
380 if ( moveToCol >= 0 )
381 header()->moveSection( *col, moveToCol );
384 header()->setResizeEnabled(
false, *col);
385 header()->setStretchEnabled(
false, *col);
391 if ( static_cast<KPaintInfo::ColumnIds>(
id) == KPaintInfo::COL_RECEIVER ) {
392 TQString colText = i18n(
"Sender" );
393 if ( mFolder && (mFolder->whoField().lower() ==
"to") && !mPaintInfo.showReceiver)
394 colText = i18n(
"Receiver" );
395 setColumnText( mPaintInfo.senderCol, colText );
406 if (mPaintInfo.pixmapOn)
407 p->drawTiledPixmap( rect.left(), rect.top(), rect.width(), rect.height(),
409 rect.left() + contentsX(),
410 rect.top() + contentsY() );
412 p->fillRect( rect, colorGroup().base() );
418 if (e->type() == TQEvent::ApplicationPaletteChange)
429 TDEConfig* config = KMKernel::config();
431 TDEConfigGroupSaver saver(config,
"Reader");
432 TQColor c1=TQColor(kapp->palette().active().text());
433 TQColor c2=TQColor(
"red");
434 TQColor c3=TQColor(
"blue");
435 TQColor c4=TQColor(kapp->palette().active().base());
436 TQColor c5=TQColor(0,0x7F,0);
437 TQColor c6=TQColor(0,0x98,0);
438 TQColor c7=TDEGlobalSettings::alternateBackgroundColor();
440 if (!config->readBoolEntry(
"defaultColors",
true)) {
441 mPaintInfo.colFore = config->readColorEntry(
"ForegroundColor",&c1);
442 mPaintInfo.colBack = config->readColorEntry(
"BackgroundColor",&c4);
443 TQPalette newPal = kapp->palette();
444 newPal.setColor( TQColorGroup::Base, mPaintInfo.colBack );
445 newPal.setColor( TQColorGroup::Text, mPaintInfo.colFore );
446 setPalette( newPal );
447 mPaintInfo.colNew = config->readColorEntry(
"NewMessage",&c2);
448 mPaintInfo.colUnread = config->readColorEntry(
"UnreadMessage",&c3);
449 mPaintInfo.colFlag = config->readColorEntry(
"FlagMessage",&c5);
450 mPaintInfo.colTodo = config->readColorEntry(
"TodoMessage",&c6);
451 c7 = config->readColorEntry(
"AltBackgroundColor",&c7);
454 mPaintInfo.colFore = c1;
455 mPaintInfo.colBack = c4;
456 TQPalette newPal = kapp->palette();
457 newPal.setColor( TQColorGroup::Base, c4 );
458 newPal.setColor( TQColorGroup::Text, c1 );
459 setPalette( newPal );
460 mPaintInfo.colNew = c2;
461 mPaintInfo.colUnread = c3;
462 mPaintInfo.colFlag = c5;
463 mPaintInfo.colTodo = c6;
465 setAlternateBackground(c7);
471 TDEConfig* config = KMKernel::config();
475 TDEConfigGroupSaver saver(config,
"Pixmaps");
476 TQString pixmapFile = config->readEntry(
"Headers");
477 mPaintInfo.pixmapOn =
false;
478 if (!pixmapFile.isEmpty()) {
479 mPaintInfo.pixmapOn =
true;
480 mPaintInfo.pixmap = TQPixmap( pixmapFile );
485 TDEConfigGroupSaver saver(config,
"General");
486 bool show = config->readBoolEntry(
"showMessageSize");
489 show = config->readBoolEntry(
"showAttachmentColumn");
492 show = config->readBoolEntry(
"showInvitationColumn");
495 show = config->readBoolEntry(
"showImportantColumn");
498 show = config->readBoolEntry(
"showTodoColumn");
501 show = config->readBoolEntry(
"showSpamHamColumn");
504 show = config->readBoolEntry(
"showWatchedIgnoredColumn");
507 show = config->readBoolEntry(
"showStatusColumn");
510 show = config->readBoolEntry(
"showSignedColumn");
513 show = config->readBoolEntry(
"showCryptoColumn");
516 show = config->readBoolEntry(
"showReceiverColumn");
519 mPaintInfo.showCryptoIcons = config->readBoolEntry(
"showCryptoIcons",
false );
520 mPaintInfo.showAttachmentIcon = config->readBoolEntry(
"showAttachmentIcon",
true );
521 mPaintInfo.showInvitationIcon = config->readBoolEntry(
"showInvitationIcon",
false );
523 KMime::DateFormatter::FormatType t =
524 (KMime::DateFormatter::FormatType) config->readNumEntry(
"dateFormat", KMime::DateFormatter::Fancy ) ;
525 mDate.setCustomFormat( config->readEntry(
"customDateFormat") );
526 mDate.setFormat( t );
533 TDEConfigGroupSaver saver(config,
"Fonts");
534 if (!(config->readBoolEntry(
"defaultFonts",
true)))
536 TQFont listFont( TDEGlobalSettings::generalFont() );
537 listFont = config->readFontEntry(
"list-font", &listFont );
539 mNewFont = config->readFontEntry(
"list-new-font", &listFont );
540 mUnreadFont = config->readFontEntry(
"list-unread-font", &listFont );
541 mImportantFont = config->readFontEntry(
"list-important-font", &listFont );
542 mTodoFont = config->readFontEntry(
"list-todo-font", &listFont );
543 mDateFont = TDEGlobalSettings::fixedFont();
544 mDateFont = config->readFontEntry(
"list-date-font", &mDateFont );
546 mNewFont= mUnreadFont = mImportantFont = mDateFont = mTodoFont =
547 TDEGlobalSettings::generalFont();
548 setFont( mDateFont );
554 TDEConfigGroupSaver saver(config,
"Geometry");
555 mReaderWindowActive = config->readEntry(
"readerWindowMode",
"below" ) !=
"hide";
565 mIgnoreSortOrderChanges =
true;
566 restoreLayout( config, group );
567 mIgnoreSortOrderChanges =
false;
577 TQString colText = i18n(
"Sender" );
578 if ( mFolder && (mFolder->whoField().lower() ==
"to") && !mPaintInfo.showReceiver)
579 colText = i18n(
"Receiver" );
580 setColumnText( mPaintInfo.senderCol, colText );
586 ensureCurrentItemVisible();
593 NestingPolicy oldNestPolicy = nestingPolicy;
594 TDEConfig* config = KMKernel::config();
595 TDEConfigGroupSaver saver(config,
"Geometry");
596 mNested = config->readBoolEntry(
"nestedMessages",
false );
598 nestingPolicy = (NestingPolicy)config->readNumEntry(
"nestingPolicy", OpenUnread );
599 if ((nestingPolicy != oldNestPolicy) ||
602 setRootIsDecorated( nestingPolicy != AlwaysOpen &&
isThreaded() );
611 if (!mFolder)
return;
612 TDEConfig* config = KMKernel::config();
614 TDEConfigGroupSaver saver(config,
"Folder-" + mFolder->idString());
615 mNestedOverride = config->readBoolEntry(
"threadMessagesOverride",
false );
616 mSortCol = config->readNumEntry(
"SortColumn", mSortCol+1 );
617 mSortDescending = (mSortCol < 0);
618 mSortCol = abs(mSortCol) - 1;
620 mTopItem = config->readNumEntry(
"Top", 0);
621 mCurrentItem = config->readNumEntry(
"Current", 0);
622 mCurrentItemSerNum = config->readNumEntry(
"CurrentSerialNum", 0);
624 mPaintInfo.orderOfArrival = config->readBoolEntry(
"OrderOfArrival",
false );
625 mPaintInfo.status = config->readBoolEntry(
"Status",
false );
628 TDEConfigGroupSaver saver(config,
"Geometry");
629 mNested = config->readBoolEntry(
"nestedMessages",
false );
630 nestingPolicy = (NestingPolicy)config->readNumEntry(
"nestingPolicy", OpenUnread );
633 setRootIsDecorated( nestingPolicy != AlwaysOpen &&
isThreaded() );
634 mSubjThreading = config->readBoolEntry(
"threadMessagesBySubject",
true );
641 if (!mFolder)
return;
642 TDEConfig* config = KMKernel::config();
643 int mSortColAdj = mSortCol + 1;
645 TDEConfigGroupSaver saver(config,
"Folder-" + mFolder->idString());
646 config->writeEntry(
"SortColumn", (mSortDescending ? -mSortColAdj : mSortColAdj));
651 if ( current && mFolder->getMsgBase( current->
msgId() ) )
652 sernum = mFolder->getMsgBase( current->
msgId() )->getMsgSerNum();
653 config->writeEntry(
"CurrentSerialNum", sernum);
655 config->writeEntry(
"OrderOfArrival", mPaintInfo.orderOfArrival);
656 config->writeEntry(
"Status", mPaintInfo.status);
662 TDEConfig* config = KMKernel::config();
663 saveLayout(config,
"Header-Geometry");
664 TDEConfigGroupSaver saver(config,
"General");
665 config->writeEntry(
"showMessageSize" , mPaintInfo.showSize);
666 config->writeEntry(
"showAttachmentColumn" , mPaintInfo.showAttachment);
667 config->writeEntry(
"showInvitationColumn" , mPaintInfo.showInvitation);
668 config->writeEntry(
"showImportantColumn" , mPaintInfo.showImportant);
669 config->writeEntry(
"showTodoColumn" , mPaintInfo.showTodo);
670 config->writeEntry(
"showSpamHamColumn" , mPaintInfo.showSpamHam);
671 config->writeEntry(
"showWatchedIgnoredColumn", mPaintInfo.showWatchedIgnored);
672 config->writeEntry(
"showStatusColumn" , mPaintInfo.showStatus);
673 config->writeEntry(
"showSignedColumn" , mPaintInfo.showSigned);
674 config->writeEntry(
"showCryptoColumn" , mPaintInfo.showCrypto);
675 config->writeEntry(
"showReceiverColumn" , mPaintInfo.showReceiver);
681 CREATE_TIMER(set_folder);
682 START_TIMER(set_folder);
687 mSortInfo.fakeSort = 0;
688 if ( mFolder && static_cast<KMFolder*>(mFolder) == aFolder ) {
700 highlightMessage(0,
false);
702 disconnect(mFolder, TQT_SIGNAL(numUnreadMsgsChanged(
KMFolder*)),
705 mFolder->markNewAsUnread();
709 disconnect(mFolder, TQT_SIGNAL(
msgAdded(
int)),
711 disconnect(mFolder, TQT_SIGNAL(
msgRemoved(
int, TQString ) ),
712 this, TQT_SLOT(
msgRemoved(
int, TQString ) ) );
713 disconnect(mFolder, TQT_SIGNAL(changed()),
715 disconnect(mFolder, TQT_SIGNAL(cleared()),
717 disconnect(mFolder, TQT_SIGNAL(expunged(
KMFolder* )),
719 disconnect(mFolder, TQT_SIGNAL(closed()),
721 disconnect( mFolder, TQT_SIGNAL( statusMsg(
const TQString& ) ),
722 BroadcastStatus::instance(), TQT_SLOT( setStatusMsg(
const TQString& ) ) );
723 disconnect(mFolder, TQT_SIGNAL(viewConfigChanged()),
this, TQT_SLOT(
reset()));
725 mFolder->close(
"kmheaders");
728 if (mFolder->dirty()) mFolder->writeIndex();
731 mSortInfo.removed = 0;
733 mSortInfo.dirty =
true;
735 mOwner->useAction()->setEnabled( mFolder ?
736 ( kmkernel->folderIsTemplates( mFolder ) ) :
false );
737 mOwner->messageActions()->replyListAction()->setEnabled( mFolder ?
738 mFolder->isMailingListEnabled() : false );
742 connect(mFolder, TQT_SIGNAL(
msgAdded(
int)),
744 connect(mFolder, TQT_SIGNAL(
msgRemoved(
int,TQString)),
746 connect(mFolder, TQT_SIGNAL(changed()),
748 connect(mFolder, TQT_SIGNAL(cleared()),
750 connect(mFolder, TQT_SIGNAL(expunged(
KMFolder* )),
752 connect(mFolder, TQT_SIGNAL(closed()),
754 connect(mFolder, TQT_SIGNAL(statusMsg(
const TQString&)),
755 BroadcastStatus::instance(), TQT_SLOT( setStatusMsg(
const TQString& ) ) );
756 connect(mFolder, TQT_SIGNAL(numUnreadMsgsChanged(
KMFolder*)),
758 connect(mFolder, TQT_SIGNAL(viewConfigChanged()),
this, TQT_SLOT(
reset()));
772 CREATE_TIMER(kmfolder_open);
773 START_TIMER(kmfolder_open);
774 mFolder->open(
"kmheaders");
775 END_TIMER(kmfolder_open);
776 SHOW_TIMER(kmfolder_open);
786 CREATE_TIMER(updateMsg);
787 START_TIMER(updateMsg);
788 updateMessageList(
true, forceJumpToUnread);
789 END_TIMER(updateMsg);
790 SHOW_TIMER(updateMsg);
794 TQString colText = i18n(
"Sender" );
795 if (mFolder && (mFolder->whoField().lower() ==
"to") && !mPaintInfo.showReceiver)
796 colText = i18n(
"Receiver");
797 setColumnText( mPaintInfo.senderCol, colText);
799 colText = i18n(
"Date" );
800 if (mPaintInfo.orderOfArrival)
801 colText = i18n(
"Order of Arrival" );
802 setColumnText( mPaintInfo.dateCol, colText);
804 colText = i18n(
"Subject" );
805 if (mPaintInfo.status)
806 colText = colText + i18n(
" (Status)" );
807 setColumnText( mPaintInfo.subCol, colText);
812 END_TIMER(set_folder);
813 SHOW_TIMER(set_folder);
819 if (mFolder->count() == 0) {
824 if (!isUpdatesEnabled())
return;
829 const bool scrollbarAtTop = verticalScrollBar() &&
830 verticalScrollBar()->value() == verticalScrollBar()->minValue();
831 const bool scrollbarAtBottom = verticalScrollBar() &&
832 verticalScrollBar()->value() == verticalScrollBar()->maxValue();
833 const HeaderItem *
const oldFirstVisibleItem =
dynamic_cast<HeaderItem*
>( itemAt( TQPoint( 0, 0 ) ) );
834 const int oldOffsetOfFirstVisibleItem = itemRect( oldFirstVisibleItem ).y();
835 const uint oldSerNumOfFirstVisibleItem = oldFirstVisibleItem ? oldFirstVisibleItem->msgSerNum() : 0;
838 TQListViewItem *item = currentItem();
842 KMMsgBase *mb = mFolder->getMsgBase(hi->
msgId());
844 msgIdMD5 = mb->msgIdMD5();
848 disconnect(
this,TQT_SIGNAL(currentChanged(TQListViewItem*)),
849 this,TQT_SLOT(highlightMessage(TQListViewItem*)));
856 if ( scrollbarAtTop ) {
857 setContentsPos( 0, 0 );
858 }
else if ( scrollbarAtBottom ) {
859 setContentsPos( 0, contentsHeight() );
860 }
else if ( oldSerNumOfFirstVisibleItem > 0 ) {
861 for ( uint i = 0; i < mItems.size(); ++i ) {
862 const KMMsgBase *
const mMsgBase = mFolder->getMsgBase( i );
863 if ( mMsgBase->getMsgSerNum() == oldSerNumOfFirstVisibleItem ) {
864 setContentsPos( 0, itemPos( mItems[i] ) - oldOffsetOfFirstVisibleItem );
870 connect(
this,TQT_SIGNAL(currentChanged(TQListViewItem*)),
871 this,TQT_SLOT(highlightMessage(TQListViewItem*)));
880 item = currentItem();
883 KMMsgBase *mb = mFolder->getMsgBase(hi->
msgId());
885 if (msgIdMD5.isEmpty() || (msgIdMD5 != mb->msgIdMD5()))
899 if (!isUpdatesEnabled())
return;
904 assert( mFolder->getMsgBase(
id ) );
911 if (mSortCacheItems.count() == (uint)mFolder->count()
912 || mSortCacheItems.count() == 0) {
913 kdDebug (5006) <<
"KMHeaders::msgAdded - Resizing id and subject trees of " << mFolder->label()
914 <<
": before=" << mSortCacheItems.count() <<
" ,after=" << (mFolder->count()*2) << endl;
915 mSortCacheItems.resize(mFolder->count()*2);
916 mSubjectLists.resize(mFolder->count()*2);
918 TQString
msgId = mFolder->getMsgBase(
id)->msgIdMD5();
921 TQString
replyToId = mFolder->getMsgBase(
id)->replyToIdMD5();
924 if (!parent && mSubjThreading) {
925 parent = findParentBySubject( sci );
931 if (msgId == mFolder->getMsgBase(parent->
item()->
msgId())->replyToIdMD5()
937 if (parent && mFolder->getMsgBase(parent->id())->isWatched())
938 mFolder->getMsgBase(
id)->setStatus( KMMsgStatusWatched );
939 else if (parent && mFolder->getMsgBase(parent->id())->isIgnored())
940 mFolder->getMsgBase(
id)->setStatus( KMMsgStatusIgnored );
951 mItems.resize( mFolder->count() );
954 if ( !msgId.isEmpty() )
955 mSortCacheItems.replace(msgId, sci);
958 if (mSubjThreading && parent) {
959 TQString subjMD5 = mFolder->getMsgBase(
id)->strippedSubjectMD5();
960 if (subjMD5.isEmpty()) {
961 mFolder->getMsgBase(
id)->initStrippedSubjectMD5();
962 subjMD5 = mFolder->getMsgBase(
id)->strippedSubjectMD5();
964 if( !subjMD5.isEmpty()) {
965 if ( !mSubjectLists.find(subjMD5) )
966 mSubjectLists.insert(subjMD5,
new TQPtrList<SortCacheItem>());
969 for (TQPtrListIterator<SortCacheItem> it(*mSubjectLists[subjMD5]);
970 it.current(); ++it) {
971 KMMsgBase *mb = mFolder->getMsgBase((*it)->id());
972 if ( mb->date() < mFolder->getMsgBase(
id)->date())
976 mSubjectLists[subjMD5]->insert( p, sci);
977 sci->setSubjectThreadingList( mSubjectLists[subjMD5] );
986 disconnect(
this, TQT_SIGNAL(currentChanged(TQListViewItem*)),
987 this, TQT_SLOT(highlightMessage(TQListViewItem*)));
989 if ( !msgId.isEmpty() ) {
990 TQPtrListIterator<HeaderItem> it(mImperfectlyThreadedList);
992 while ( (cur = it.current()) ) {
994 int tryMe = cur->
msgId();
998 bool perfectParent =
true;
999 KMMsgBase *otherMsg = mFolder->getMsgBase(tryMe);
1001 kdDebug(5006) <<
"otherMsg is NULL !!! tryMe: " << tryMe << endl;
1004 TQString otherId = otherMsg->replyToIdMD5();
1005 if (msgId != otherId) {
1006 if (msgId != otherMsg->replyToAuxIdMD5())
1009 if (!otherId.isEmpty() && mSortCacheItems.find(otherId))
1014 perfectParent =
false;
1017 TQListViewItem *newParent = mItems[
id];
1018 TQListViewItem *msg = mItems[tryMe];
1021 msg->parent()->takeItem(msg);
1024 newParent->insertItem(msg);
1030 if (perfectParent) {
1031 mImperfectlyThreadedList.removeRef (mItems[tryMe]);
1034 TQString sortFile = KMAIL_SORT_FILE(mFolder);
1035 FILE *sortStream = fopen(TQFile::encodeName(sortFile),
"r+");
1037 mItems[tryMe]->sortCacheItem()->updateSortFile( sortStream, mFolder );
1038 fclose (sortStream);
1045 mImperfectlyThreadedList.append(hi);
1049 mItems.resize( mFolder->count() );
1055 if (mSortInfo.fakeSort) {
1056 TQObject::disconnect(header(), TQT_SIGNAL(clicked(
int)),
this, TQT_SLOT(
dirtySortOrder(
int)));
1058 mSortInfo.fakeSort = 0;
1060 appendItemToSortFile(hi);
1064 if ((childCount() == 1) && hi) {
1066 setCurrentItem( firstChild() );
1067 setSelectionAnchor( currentItem() );
1068 highlightMessage( currentItem() );
1072 connect(
this, TQT_SIGNAL(currentChanged(TQListViewItem*)),
1073 this, TQT_SLOT(highlightMessage(TQListViewItem*)));
1084 if (!isUpdatesEnabled())
return;
1086 if ((
id < 0) || (
id >= (
int)mItems.size()))
1093 disconnect(
this, TQT_SIGNAL(currentChanged(TQListViewItem*)),
1094 this, TQT_SLOT(highlightMessage(TQListViewItem*)));
1097 if (!removedItem)
return;
1100 for (
int i =
id; i < (int)mItems.size() - 1; ++i) {
1101 mItems[i] = mItems[i+1];
1102 mItems[i]->setMsgId( i );
1103 mItems[i]->sortCacheItem()->setId( i );
1106 mItems.resize( mItems.size() - 1 );
1109 if ( !msgId.isEmpty() && mSortCacheItems[
msgId] ) {
1111 mSortCacheItems.remove(msgId);
1119 TQListViewItem *myParent = removedItem;
1120 TQListViewItem *myChild = myParent->firstChild();
1121 TQListViewItem *threadRoot = myParent;
1122 while (threadRoot->parent())
1123 threadRoot = threadRoot->parent();
1124 TQString key =
static_cast<HeaderItem*
>(threadRoot)->key(mSortCol, !mSortDescending);
1126 TQPtrList<TQListViewItem> childList;
1131 childList.append(myChild);
1133 myChild = myChild->nextSibling();
1135 myParent->takeItem( item );
1139 item->setTempKey( key + item->key( mSortCol, !mSortDescending ));
1140 if (mSortInfo.fakeSort) {
1141 TQObject::disconnect(header(), TQT_SIGNAL(clicked(
int)),
this, TQT_SLOT(
dirtySortOrder(
int)));
1143 mSortInfo.fakeSort = 0;
1147 for (TQPtrListIterator<TQListViewItem> it(childList); it.current() ; ++it ) {
1148 TQListViewItem *lvi = *it;
1152 if ( !parent && mSubjThreading )
1153 parent = findParentBySubject( sci );
1155 Q_ASSERT( !parent || parent->
item() != removedItem );
1156 myParent->takeItem(lvi);
1157 if ( parent && parent->
item() != item && parent->
item() != removedItem ) {
1158 parent->
item()->insertItem(lvi);
1166 && !mImperfectlyThreadedList.containsRef(item))
1167 mImperfectlyThreadedList.append(item);
1170 && mImperfectlyThreadedList.containsRef(item))
1171 mImperfectlyThreadedList.removeRef(item);
1175 if (!mFolder->count())
1178 mImperfectlyThreadedList.removeRef( removedItem );
1181 while ( mImperfectlyThreadedList.findRef( removedItem ) != -1 ) {
1182 mImperfectlyThreadedList.remove();
1183 kdDebug(5006) <<
"Remove doubled item from mImperfectlyThreadedList: " << removedItem << endl;
1189 if ( curItem != removedItem ) {
1190 setCurrentItem( curItem );
1191 setSelectionAnchor( currentItem() );
1199 int contentX, contentY;
1200 HeaderItem *nextItem = prepareMove( &contentX, &contentY );
1201 finalizeMove( nextItem, contentX, contentY );
1205 connect(
this, TQT_SIGNAL(currentChanged(TQListViewItem*)),
1206 this, TQT_SLOT(highlightMessage(TQListViewItem*)));
1213 if (msgId<0 || msgId >= (
int)mItems.size() || !isUpdatesEnabled())
return;
1227 if (serNums.empty())
1230 KMCommand *command =
new KMSeStatusCommand( status, serNums, toggle );
1237 if (!mFolder)
return TQPtrList<TQListViewItem>();
1240 TQListViewItem *curItem = currentItem();
1241 if (!curItem)
return TQPtrList<TQListViewItem>();
1244 TQListViewItem *topOfThread = curItem;
1245 while ( topOfThread->parent() )
1246 topOfThread = topOfThread->parent();
1249 TQPtrList<TQListViewItem> list;
1250 TQListViewItem *topOfNextThread = topOfThread->nextSibling();
1251 for ( TQListViewItemIterator it( topOfThread ) ;
1252 it.current() && it.current() != topOfNextThread ; ++it )
1253 list.append( it.current() );
1259 TQPtrList<TQListViewItem> curThread;
1262 TQPtrList<TQListViewItem> topOfThreads;
1265 for (TQListViewItem *item = firstChild(); item; item = item->itemBelow())
1266 if (item->isSelected() ) {
1268 TQListViewItem *top = item;
1269 while ( top->parent() )
1270 top = top->parent();
1271 if (!topOfThreads.contains(top)) {
1272 topOfThreads.append(top);
1277 for ( TQPtrListIterator<TQListViewItem> it( topOfThreads ) ;
1278 it.current() ; ++ it ) {
1279 TQListViewItem *top = *it;
1282 TQListViewItem *topOfNextThread = top->nextSibling();
1283 for ( TQListViewItemIterator it( top ) ;
1284 it.current() && it.current() != topOfNextThread ; ++it )
1285 curThread.append( it.current() );
1289 TQPtrListIterator<TQListViewItem> it( curThread );
1292 for ( it.toFirst() ; it.current() ; ++it ) {
1294 KMMsgBase *msgBase = mFolder->getMsgBase(
id );
1295 serNums.append( msgBase->getMsgSerNum() );
1298 if (serNums.empty())
1301 KMCommand *command =
new KMSeStatusCommand( status, serNums, toggle );
1308 if ( !msg )
return 2;
1310 int filterResult = kmkernel->filterMgr()->process(msg,KMFilterMgr::Explicit);
1311 if (filterResult == 2) {
1313 kmkernel->emergencyExit( i18n(
"Unable to process messages: " ) + TQString::fromLocal8Bit(strerror(errno)));
1316 if (msg->parent()) {
1320 assert( p == msg->parent() ); assert( idx >= 0 );
1324 return filterResult;
1332 TQListViewItem *item = currentItem();
1333 if ( !item )
return;
1335 item->setSelected(
true );
1336 while ( item->parent() )
1337 item = item->parent();
1342 ensureItemVisible( currentItem() );
1349 TQListViewItem * item = currentItem();
1352 item->setSelected(
true );
1355 for ( TQListViewItem *item = firstChild() ;
1356 item ; item = item->nextSibling() )
1357 static_cast<HeaderItem*>(item)->setOpenRecursive( expand );
1359 TQListViewItem * item = currentItem();
1361 while ( item->parent() )
1362 item = item->parent();
1366 ensureItemVisible( currentItem() );
1374 if( style().isA(
"KeramikStyle") )
1375 frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth ) - 1;
1377 frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth );
1378 if ( frameWidth < 0 )
1380 if ( frameWidth != lineWidth() )
1381 setLineWidth( frameWidth );
1394 if ( !mFolder )
return;
1396 const int unread = mFolder->countUnread();
1397 if ( static_cast<KMFolder*>(mFolder) == kmkernel->outboxFolder() )
1398 str = unread ? i18n(
"1 unsent",
"%n unsent", unread ) : i18n(
"0 unsent" );
1400 str = unread ? i18n(
"1 unread",
"%n unread", unread ) : i18n(
"0 unread" );
1401 const int count = mFolder->count();
1402 str = count ? i18n(
"1 message, %1.",
"%n messages, %1.", count ).arg( str )
1403 : i18n(
"0 messages" );
1404 if ( mFolder->isReadOnly() )
1405 str = i18n(
"%1 = n messages, m unread.",
"%1 Folder is read-only.").arg( str );
1406 BroadcastStatus::instance()->setStatusMsg(str);
1410 void KMHeaders::applyFiltersOnMsg()
1412 if (ActionScheduler::isEnabled() ||
1413 kmkernel->filterMgr()->atLeastOneOnlineImapFolderTarget()) {
1415 KMFilterMgr::FilterSet
set = KMFilterMgr::Explicit;
1416 TQValueList<KMFilter*> filters = kmkernel->filterMgr()->filters();
1417 ActionScheduler *scheduler =
new ActionScheduler(
set, filters,
this );
1418 scheduler->setAutoDestruct(
true );
1420 int contentX, contentY;
1421 HeaderItem *nextItem = prepareMove( &contentX, &contentY );
1423 finalizeMove( nextItem, contentX, contentY );
1425 for (KMMsgBase *msg = msgList.first(); msg; msg = msgList.next())
1426 scheduler->execFilters( msg );
1428 int contentX, contentY;
1429 HeaderItem *nextItem = prepareMove( &contentX, &contentY );
1433 if ( serNums.isEmpty() )
1436 finalizeMove( nextItem, contentX, contentY );
1437 CREATE_TIMER(filter);
1438 START_TIMER(filter);
1442 int msgCountToFilter = serNums.count();
1443 ProgressItem* progressItem =
1444 ProgressManager::createProgressItem(
"filter"+ProgressManager::getUniqueID(),
1445 i18n(
"Filtering messages" ) );
1446 progressItem->setTotalItems( msgCountToFilter );
1448 for ( TQValueList<unsigned long>::ConstIterator it = serNums.constBegin();
1449 it != serNums.constEnd(); ++it ) {
1451 if ( msgCountToFilter - msgCount < 10 || !( msgCount % 20 ) || msgCount <= 10 ) {
1452 progressItem->updateProgress();
1453 TQString statusMsg = i18n(
"Filtering message %1 of %2");
1454 statusMsg = statusMsg.arg( msgCount ).arg( msgCountToFilter );
1455 KPIM::BroadcastStatus::instance()->setStatusMsg( statusMsg );
1456 TDEApplication::kApplication()->eventLoop()->processEvents( TQEventLoop::ExcludeUserInput, 50 );
1464 msg = folder->
getMsg(idx);
1470 FolderJob *job = mFolder->createJob(msg);
1471 connect(job, TQT_SIGNAL(messageRetrieved(
KMMessage*)),
1479 kdDebug (5006) <<
"####### KMHeaders::applyFiltersOnMsg -"
1480 " A message went missing during filtering " << endl;
1482 progressItem->incCompletedItems();
1484 progressItem->setComplete();
1493 void KMHeaders::setMsgRead (
int msgId)
1495 KMMsgBase *msgBase = mFolder->getMsgBase( msgId );
1500 if (msgBase->isNew() || msgBase->isUnread()) {
1501 serNums.append( msgBase->getMsgSerNum() );
1504 KMCommand *command =
new KMSeStatusCommand( KMMsgStatusRead, serNums );
1510 void KMHeaders::deleteMsg ()
1516 int contentX, contentY;
1517 HeaderItem *nextItem = prepareMove( &contentX, &contentY );
1519 finalizeMove( nextItem, contentX, contentY );
1521 KMCommand *command =
new KMDeleteMsgCommand( mFolder, msgList );
1522 connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
1523 this, TQT_SLOT( slotMoveCompleted( KMCommand * ) ) );
1526 BroadcastStatus::instance()->setStatusMsg(
"");
1534 if (mMenuToFolder[menuId])
1539 HeaderItem* KMHeaders::prepareMove(
int *contentX,
int *contentY )
1544 disconnect(
this, TQT_SIGNAL(currentChanged(TQListViewItem*)),
1545 this, TQT_SLOT(highlightMessage(TQListViewItem*)));
1547 TQListViewItem *curItem;
1549 curItem = currentItem();
1550 while (curItem && curItem->isSelected() && curItem->itemBelow())
1551 curItem = curItem->itemBelow();
1552 while (curItem && curItem->isSelected() && curItem->itemAbove())
1553 curItem = curItem->itemAbove();
1556 *contentX = contentsX();
1557 *contentY = contentsY();
1559 if (item && !item->isSelected())
1566 void KMHeaders::finalizeMove(
HeaderItem *item,
int contentX,
int contentY )
1572 setCurrentItem( item );
1574 setSelectionAnchor( currentItem() );
1576 highlightMessage( item,
false);
1579 setContentsPos( contentX, contentY );
1581 connect(
this, TQT_SIGNAL(currentChanged(TQListViewItem*)),
1582 this, TQT_SLOT(highlightMessage(TQListViewItem*)));
1589 if ( destFolder == mFolder )
return;
1590 if ( mFolder->isReadOnly() )
return;
1593 if ( msgList.isEmpty() )
return;
1594 if ( !destFolder && askForConfirmation &&
1595 KMessageBox::warningContinueCancel(
this,
1596 i18n(
"<qt>Do you really want to delete the selected message?<br>"
1597 "Once deleted, it cannot be restored.</qt>",
1598 "<qt>Do you really want to delete the %n selected messages?<br>"
1599 "Once deleted, they cannot be restored.</qt>", msgList.count() ),
1600 msgList.count()>1 ? i18n(
"Delete Messages") : i18n(
"Delete Message"),
KStdGuiItem::del(),
1601 "NoConfirmDelete") == KMessageBox::Cancel )
1605 int contentX, contentY;
1606 HeaderItem *nextItem = prepareMove( &contentX, &contentY );
1608 finalizeMove( nextItem, contentX, contentY );
1610 KMCommand *command =
new KMMoveCommand( destFolder, msgList );
1611 connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
1612 this, TQT_SLOT( slotMoveCompleted( KMCommand * ) ) );
1616 void KMHeaders::slotMoveCompleted( KMCommand *command )
1618 kdDebug(5006) << k_funcinfo << command->result() << endl;
1619 bool deleted =
static_cast<KMMoveCommand *
>( command )->destFolder() == 0;
1620 if ( command->result() == KMCommand::OK ) {
1623 BroadcastStatus::instance()->setStatusMsg(
1624 deleted ? i18n(
"Messages deleted successfully.") : i18n(
"Messages moved successfully") );
1632 for (TQListViewItemIterator it(
this); it.current(); it++) {
1636 item->setSelectable (
true );
1637 KMMsgBase *msgBase = mFolder->getMsgBase(item->
msgId());
1638 if ( msgBase->isMessage() ) {
1645 if ( command->result() == KMCommand::Failed )
1646 BroadcastStatus::instance()->setStatusMsg(
1647 deleted ? i18n(
"Deleting messages failed.") : i18n(
"Moving messages failed.") );
1649 BroadcastStatus::instance()->setStatusMsg(
1650 deleted ? i18n(
"Deleting messages canceled.") : i18n(
"Moving messages canceled.") );
1652 mOwner->updateMessageActions();
1655 bool KMHeaders::canUndo()
const
1657 return ( kmkernel->undoStack()->size() > 0 );
1661 void KMHeaders::undo()
1663 kmkernel->undoStack()->undo();
1669 if (mMenuToFolder[menuId])
1680 KMCommand * command = 0;
1682 command =
new KMCopyCommand( destFolder, aMsg );
1685 command =
new KMCopyCommand( destFolder, msgList );
1695 if (!mFolder)
return;
1696 if (cur >= mFolder->count()) cur = mFolder->count() - 1;
1697 if ((cur >= 0) && (cur < (
int)mItems.size())) {
1699 setCurrentItem( mItems[cur] );
1701 setSelectionAnchor( currentItem() );
1713 if ( item->isVisible() )
1714 TDEListView::setSelected( item, selected );
1718 if (
isThreaded() && !item->isOpen() && item->firstChild() ) {
1719 TQListViewItem *nextRoot = item->itemBelow();
1720 TQListViewItemIterator it( item->firstChild() );
1721 for( ; (*it) != nextRoot; ++it ) {
1722 if ( (*it)->isVisible() )
1723 (*it)->setSelected( selected );
1730 for ( TQValueList<int>::Iterator it = items.begin(); it != items.end(); ++it )
1732 if ( ((*it) >= 0) && ((*it) < (int)mItems.size()) )
1742 for (TQListViewItemIterator it(
this); it.current(); it++) {
1745 KMMsgBase *msgBase = mFolder->getMsgBase( item->
msgId() );
1746 if ( serNum == msgBase->getMsgSerNum() ) {
1748 item->setSelectable (
true );
1758 mSelMsgBaseList.clear();
1759 for (TQListViewItemIterator it(
this); it.current(); it++) {
1760 if ( it.current()->isSelected() && it.current()->isVisible() ) {
1766 item->setSelectable (
false );
1768 KMMsgBase *msgBase = mFolder->getMsgBase(item->
msgId());
1769 mSelMsgBaseList.append(msgBase);
1773 return &mSelMsgBaseList;
1779 TQValueList<int> items;
1780 for ( TQListViewItemIterator it(
this); it.current(); it++ )
1782 if ( it.current()->isSelected() && it.current()->isVisible() )
1785 items.append( item->
msgId() );
1794 int selectedMsg = -1;
1795 TQListViewItem *item;
1796 for (item = firstChild(); item; item = item->itemBelow())
1797 if (item->isSelected()) {
1807 TQListViewItem *lvi = currentItem();
1808 if (lvi && lvi->itemBelow()) {
1812 setSelectionAnchor( currentItem() );
1813 ensureCurrentItemVisible();
1820 if ( cm && cm->isBeingParsed() )
1822 TQListViewItem *lvi = currentItem();
1824 TQListViewItem *below = lvi->itemBelow();
1825 TQListViewItem *temp = lvi;
1826 if (lvi && below ) {
1829 temp = temp->parent();
1834 setCurrentItem(below);
1844 TQListViewItem *lvi = currentItem();
1845 if (lvi && lvi->itemAbove()) {
1849 setSelectionAnchor( currentItem() );
1850 ensureCurrentItemVisible();
1857 if ( cm && cm->isBeingParsed() )
1859 TQListViewItem *lvi = currentItem();
1861 TQListViewItem *above = lvi->itemAbove();
1862 TQListViewItem *temp = lvi;
1867 temp = temp->parent();
1872 setCurrentItem(above);
1883 if ( cm && cm->isBeingParsed() )
1885 TQListViewItem *lvi = currentItem();
1886 if ( lvi && lvi->itemBelow() ) {
1888 disconnect(
this,TQT_SIGNAL(currentChanged(TQListViewItem*)),
1889 this,TQT_SLOT(highlightMessage(TQListViewItem*)));
1890 setCurrentItem( lvi->itemBelow() );
1891 ensureCurrentItemVisible();
1893 connect(
this,TQT_SIGNAL(currentChanged(TQListViewItem*)),
1894 this,TQT_SLOT(highlightMessage(TQListViewItem*)));
1901 if ( cm && cm->isBeingParsed() )
1903 TQListViewItem *lvi = currentItem();
1904 if ( lvi && lvi->itemAbove() ) {
1905 disconnect(
this,TQT_SIGNAL(currentChanged(TQListViewItem*)),
1906 this,TQT_SLOT(highlightMessage(TQListViewItem*)));
1907 setCurrentItem( lvi->itemAbove() );
1908 ensureCurrentItemVisible();
1910 connect(
this,TQT_SIGNAL(currentChanged(TQListViewItem*)),
1911 this,TQT_SLOT(highlightMessage(TQListViewItem*)));
1918 highlightMessage( currentItem() );
1923 bool & foundUnreadMessage,
1927 KMMsgBase* msgBase = 0;
1933 msgBase = mFolder->getMsgBase(item->
msgId());
1934 if (!msgBase)
continue;
1935 if (msgBase->isUnread() || msgBase->isNew())
1936 foundUnreadMessage =
true;
1938 if (!onlyNew && (msgBase->isUnread() || msgBase->isNew()))
break;
1939 if (onlyNew && msgBase->isNew())
break;
1940 item =
static_cast<HeaderItem*
>(item->itemBelow());
1946 msgBase = mFolder->getMsgBase(newItem->
msgId());
1947 if (!msgBase)
continue;
1948 if (msgBase->isUnread() || msgBase->isNew())
1949 foundUnreadMessage =
true;
1950 if ( ( !onlyNew && (msgBase->isUnread() || msgBase->isNew()) )
1951 || ( onlyNew && msgBase->isNew() ) )
1952 lastUnread = newItem;
1953 if (newItem == item)
break;
1954 newItem =
static_cast<HeaderItem*
>(newItem->itemBelow());
1964 bool foundUnreadMessage =
false;
1966 if (!mFolder)
return -1;
1967 if (mFolder->count() <= 0)
return -1;
1969 if ((aStartAt >= 0) && (aStartAt < (int)mItems.size()))
1970 item = mItems[aStartAt];
1975 item =
static_cast<HeaderItem*
>(firstChild());
1977 item =
static_cast<HeaderItem*
>(lastChild());
1982 if ( !acceptCurrent ) {
1984 item =
static_cast<HeaderItem*
>(item->itemBelow());
1987 item =
static_cast<HeaderItem*
>(item->itemAbove());
1994 findUnreadAux( item, foundUnreadMessage, onlyNew, aDirNext );
2002 TQListViewItem *next = item;
2003 while (next->parent())
2004 next = next->parent();
2005 next =
static_cast<HeaderItem*
>(next)->firstChildNonConst();
2006 while (next && (next != item))
2007 if (static_cast<HeaderItem*>(next)->firstChildNonConst())
2008 next = next->firstChild();
2009 else if (next->nextSibling())
2010 next = next->nextSibling();
2012 while (next && (next != item)) {
2013 next = next->parent();
2016 if (next && next->nextSibling()) {
2017 next = next->nextSibling();
2026 findUnreadAux( item, foundUnreadMessage, onlyNew, aDirNext );
2028 return item->
msgId();
2032 int unread = mFolder->countUnread();
2033 if (((unread == 0) && foundUnreadMessage) ||
2034 ((unread > 0) && !foundUnreadMessage)) {
2035 mFolder->correctUnreadMsgsCount();
2043 if ( !mFolder || !mFolder->countUnread() )
return false;
2044 int i =
findUnread(
true, -1,
false, acceptCurrent);
2045 if ( i < 0 && GlobalSettings::self()->loopOnGotoUnread() !=
2046 GlobalSettings::EnumLoopOnGotoUnread::DontLoop )
2055 ensureCurrentItemVisible();
2059 void KMHeaders::ensureCurrentItemVisible()
2062 if ((i >= 0) && (i < (
int)mItems.size()))
2063 center( contentsX(), itemPos(mItems[i]), 0, 9.0 );
2069 if ( !mFolder || !mFolder->countUnread() )
return false;
2071 if ( i < 0 && GlobalSettings::self()->loopOnGotoUnread() !=
2072 GlobalSettings::EnumLoopOnGotoUnread::DontLoop )
2081 ensureCurrentItemVisible();
2102 ensureItemVisible( currentItem() );
2106 void KMHeaders::highlightMessage(TQListViewItem* lvi,
bool markitread)
2109 if (lvi && !lvi->isSelectable())
return;
2112 if (lvi != mPrevCurrent) {
2113 if (mPrevCurrent && mFolder)
2116 if (prevMsg && mReaderWindowActive)
2118 mFolder->ignoreJobsForMessage(prevMsg);
2120 mFolder->unGetMsg(mPrevCurrent->
msgId());
2123 mPrevCurrent = item;
2130 int idx = item->
msgId();
2132 if (mReaderWindowActive && !msg) {
2138 BroadcastStatus::instance()->setStatusMsg(
"");
2139 if (markitread && idx >= 0) setMsgRead(idx);
2140 mItems[idx]->irefresh();
2141 mItems[idx]->repaint();
2146 void KMHeaders::highlightCurrentThread()
2149 TQPtrListIterator<TQListViewItem> it( curThread );
2151 for ( it.toFirst() ; it.current() ; ++it ) {
2152 TQListViewItem *lvi = *it;
2153 lvi->setSelected(
true );
2162 TQTimer::singleShot( ( 60-TQTime::currentTime().second() ) * 1000,
2173 int idx = item->
msgId();
2186 void KMHeaders::updateMessageList(
bool set_selection,
bool forceJumpToUnread )
2198 readSortOrder( set_selection, forceJumpToUnread );
2219 void KMHeaders::keyPressEvent( TQKeyEvent * e )
2221 bool cntrl = (e->state() & ControlButton );
2222 bool shft = (e->state() & ShiftButton );
2223 TQListViewItem *cur = currentItem();
2225 if (!e || !firstChild())
2230 setCurrentItem( firstChild() );
2231 setSelectionAnchor( currentItem() );
2236 if (cur->isSelectable() && e->ascii() ==
' ' ) {
2238 highlightMessage( cur,
false);
2244 disconnect(
this,TQT_SIGNAL(currentChanged(TQListViewItem*)),
2245 this,TQT_SLOT(highlightMessage(TQListViewItem*)));
2254 TDEListView::keyPressEvent( e );
2257 connect(
this,TQT_SIGNAL(currentChanged(TQListViewItem*)),
2258 this,TQT_SLOT(highlightMessage(TQListViewItem*)));
2269 if (!(lvi->isSelected())) {
2279 mPressPos = e->pos();
2280 TQListViewItem *lvi = itemAt( contentsToViewport( e->pos() ));
2281 bool wasSelected =
false;
2282 bool rootDecoClicked =
false;
2284 wasSelected = lvi->isSelected();
2286 ( mPressPos.x() <= header()->cellPos( header()->mapToActual( 0 ) ) +
2287 treeStepSize() * ( lvi->depth() + ( rootIsDecorated() ? 1 : 0 ) ) + itemMargin() )
2288 && ( mPressPos.x() >= header()->cellPos( header()->mapToActual( 0 ) ) );
2290 if ( rootDecoClicked ) {
2295 if ( !lvi->isOpen() && lvi->firstChild() ) {
2296 TQListViewItem *nextRoot = lvi->itemBelow();
2297 TQListViewItemIterator it( lvi->firstChild() );
2298 for( ; (*it) != nextRoot; ++it )
2299 (*it)->setSelected(
false );
2309 if ( e->state() & ShiftButton ) {
2310 TQListViewItemIterator it(
this, TQListViewItemIterator::Invisible );
2311 while ( it.current() ) {
2312 it.current()->setSelected(
false );
2317 if ( rootDecoClicked ) {
2319 if ( lvi && !lvi->isOpen() && lvi->isSelected() )
2323 if ( lvi && !rootDecoClicked ) {
2324 if ( lvi != currentItem() )
2325 highlightMessage( lvi );
2330 if ( !( e->state() & ControlButton ) && !wasSelected )
2333 if ( e->state() & ControlButton )
2336 if ((e->button() == Qt::LeftButton) )
2337 mMousePressed =
true;
2341 if ( lvi && e->button() == Qt::LeftButton && !( e->state() & (ShiftButton | ControlButton | AltButton | MetaButton) ) ) {
2342 bool flagsToggleable = GlobalSettings::self()->allowLocalFlags() || !(mFolder ? mFolder->isReadOnly() :
true);
2343 int section = header()->sectionAt( e->pos().x() );
2345 KMMsgBase *msg = mFolder->getMsgBase(item->
msgId());
2346 if ( section == mPaintInfo.flagCol && flagsToggleable ) {
2348 }
else if ( section == mPaintInfo.importantCol && flagsToggleable ) {
2350 }
else if ( section == mPaintInfo.todoCol && flagsToggleable ) {
2352 }
else if ( section == mPaintInfo.watchedIgnoredCol && flagsToggleable ) {
2353 if ( msg->isWatched() || msg->isIgnored() )
2357 }
else if ( section == mPaintInfo.statusCol ) {
2358 if ( msg->isUnread() || msg->isNew() )
2367 void KMHeaders::contentsMouseReleaseEvent(TQMouseEvent* e)
2369 if (e->button() != Qt::RightButton)
2370 TDEListView::contentsMouseReleaseEvent(e);
2372 mMousePressed =
false;
2378 if (mMousePressed &&
2379 (e->pos() - mPressPos).manhattanLength() > TDEGlobalSettings::dndEventDelay()) {
2380 mMousePressed =
false;
2381 TQListViewItem *item = itemAt( contentsToViewport(mPressPos) );
2384 unsigned int count = 0;
2385 for( TQListViewItemIterator it(
this); it.current(); it++ )
2386 if( it.current()->isSelected() ) {
2388 KMMsgBase *msg = mFolder->getMsgBase(item->
msgId());
2391 MailSummary mailSummary( msg->getMsgSerNum(), msg->msgIdMD5(),
2392 msg->subject(), msg->fromStrip(),
2393 msg->toStrip(), msg->date() );
2394 mailList.append( mailSummary );
2397 MailListDrag *d =
new MailListDrag( mailList, viewport(),
new KMTextSource );
2402 pixmap = TQPixmap( DesktopIcon(
"message", TDEIcon::SizeSmall) );
2404 pixmap = TQPixmap( DesktopIcon(
"application-vnd.tde.tdemultiple", TDEIcon::SizeSmall) );
2407 if( !pixmap.isNull() ) {
2408 TQPoint hotspot( pixmap.width() / 2, pixmap.height() / 2 );
2409 d->setPixmap( pixmap, hotspot );
2411 if ( mFolder->isReadOnly() )
2419 void KMHeaders::highlightMessage(TQListViewItem* i)
2421 highlightMessage( i,
false );
2427 if (!topLevelWidget())
return;
2428 mOwner->updateMessageActions();
2431 TQListViewItem *item = itemAt( viewport()->mapFromGlobal( TQCursor::pos() ) );
2433 int section = header()->sectionAt( viewportToContents( viewport()->mapFromGlobal( TQCursor::pos() ) ).x() );
2434 if ( section == mPaintInfo.flagCol || section == mPaintInfo.importantCol
2435 || section == mPaintInfo.todoCol || section == mPaintInfo.statusCol ) {
2436 mOwner->statusMenu()->popup( TQCursor::pos() );
2439 if ( section == mPaintInfo.watchedIgnoredCol ) {
2440 mOwner->threadStatusMenu()->popup( TQCursor::pos() );
2445 TQPopupMenu *menu =
new TQPopupMenu(
this);
2447 mMenuToFolder.clear();
2449 mOwner->updateMessageMenu();
2451 bool out_folder = kmkernel->folderIsDraftOrOutbox( mFolder );
2452 bool tem_folder = kmkernel->folderIsTemplates( mFolder );
2454 mOwner->useAction()->plug( menu );
2457 mOwner->messageActions()->replyMenu()->plug( menu );
2458 mOwner->forwardMenu()->plug( menu );
2459 if( mOwner->sendAgainAction()->isEnabled() ) {
2460 mOwner->sendAgainAction()->plug( menu );
2462 mOwner->editAction()->plug( menu );
2465 menu->insertSeparator();
2467 TQPopupMenu *msgCopyMenu =
new TQPopupMenu(menu);
2468 mOwner->folderTree()->folderToPopupMenu( KMFolderTree::CopyMessage, TQT_TQOBJECT(
this),
2469 &mMenuToFolder, msgCopyMenu );
2470 menu->insertItem(i18n(
"&Copy To"), msgCopyMenu);
2472 if ( !mFolder->canDeleteMessages() ) {
2473 int id = menu->insertItem( i18n(
"&Move To") );
2474 menu->setItemEnabled(
id,
false );
2476 TQPopupMenu *msgMoveMenu =
new TQPopupMenu(menu);
2477 mOwner->folderTree()->folderToPopupMenu( KMFolderTree::MoveMessage, TQT_TQOBJECT(
this),
2478 &mMenuToFolder, msgMoveMenu );
2479 menu->insertItem(i18n(
"&Move To"), msgMoveMenu);
2481 menu->insertSeparator();
2482 mOwner->statusMenu()->plug( menu );
2483 if ( mOwner->threadStatusMenu()->isEnabled() ) {
2484 mOwner->threadStatusMenu()->plug( menu );
2487 if ( !out_folder && !tem_folder ) {
2488 menu->insertSeparator();
2489 mOwner->filterMenu()->plug( menu );
2490 mOwner->action(
"apply_filter_actions" )->plug( menu );
2493 menu->insertSeparator();
2494 mOwner->printAction()->plug(menu);
2495 mOwner->saveAsAction()->plug(menu);
2496 mOwner->saveAttachmentsAction()->plug(menu);
2497 menu->insertSeparator();
2498 if ( mFolder->isTrash() ) {
2499 mOwner->deleteAction()->plug(menu);
2500 if ( mOwner->trashThreadAction()->isEnabled() )
2501 mOwner->deleteThreadAction()->plug(menu);
2503 mOwner->trashAction()->plug(menu);
2504 if ( mOwner->trashThreadAction()->isEnabled() )
2505 mOwner->trashThreadAction()->plug(menu);
2507 menu->insertSeparator();
2508 mOwner->messageActions()->createTodoAction()->plug( menu );
2510 TDEAcceleratorManager::manage(menu);
2511 kmkernel->setContextMenuShown(
true );
2512 menu->exec(TQCursor::pos(), 0);
2513 kmkernel->setContextMenuShown(
false );
2524 return mFolder->getMsg(hi->
msgId());
2530 return static_cast<HeaderItem*
>(currentItem());
2538 return item->
msgId();
2546 if (!mFolder->isOpened())
setFolder(mFolder);
2548 if ((msgIdx >= 0) && (msgIdx < (int)mItems.size())) {
2550 bool unchanged = (currentItem() == mItems[msgIdx]);
2551 setCurrentItem( mItems[msgIdx] );
2553 setSelectionAnchor( currentItem() );
2555 highlightMessage( mItems[msgIdx],
false);
2565 return item->
msgId();
2573 if ( aMsgIdx < 0 || static_cast<unsigned int>( aMsgIdx ) >= mItems.size() )
2575 const TQListViewItem *
const item = mItems[aMsgIdx];
2577 setContentsPos( 0, itemPos( item ) );
2581 void KMHeaders::setNestedOverride(
bool override )
2583 mSortInfo.dirty =
true;
2584 mNestedOverride =
override;
2585 setRootIsDecorated( nestingPolicy != AlwaysOpen
2587 TQString sortFile = mFolder->indexLocation() +
".sorted";
2588 unlink(TQFile::encodeName(sortFile));
2593 void KMHeaders::setSubjectThreading(
bool aSubjThreading )
2595 mSortInfo.dirty =
true;
2596 mSubjThreading = aSubjThreading;
2597 TQString sortFile = mFolder->indexLocation() +
".sorted";
2598 unlink(TQFile::encodeName(sortFile));
2605 if ((nestingPolicy != AlwaysOpen)|| open)
2606 ((
HeaderItem*)item)->setOpenRecursive( open );
2613 return mFolder->getMsgBase( hi->
msgId() );
2619 if ( mIgnoreSortOrderChanges )
2626 if(mSortInfo.dirty || column != mSortInfo.column || ascending != mSortInfo.ascending) {
2627 TQObject::disconnect(header(), TQT_SIGNAL(clicked(
int)),
this, TQT_SLOT(
dirtySortOrder(
int)));
2628 mSortInfo.dirty =
true;
2631 assert(column >= 0);
2633 mSortDescending = !ascending;
2635 if (!ascending && (column == mPaintInfo.dateCol))
2636 mPaintInfo.orderOfArrival = !mPaintInfo.orderOfArrival;
2638 if (!ascending && (column == mPaintInfo.subCol))
2639 mPaintInfo.status = !mPaintInfo.status;
2641 TQString colText = i18n(
"Date" );
2642 if (mPaintInfo.orderOfArrival)
2643 colText = i18n(
"Order of Arrival" );
2644 setColumnText( mPaintInfo.dateCol, colText);
2646 colText = i18n(
"Subject" );
2647 if (mPaintInfo.status)
2648 colText = colText + i18n(
" (Status)" );
2649 setColumnText( mPaintInfo.subCol, colText);
2652 ensureCurrentItemVisible();
2662 static void internalWriteItem(FILE *sortStream,
KMFolder *folder,
int msgid,
2663 int parent_id, TQString key,
2664 bool update_discover=
true)
2666 unsigned long msgSerNum;
2667 unsigned long parentSerNum;
2672 parentSerNum = (
unsigned long)(parent_id + KMAIL_RESERVED);
2674 fwrite(&msgSerNum,
sizeof(msgSerNum), 1, sortStream);
2675 fwrite(&parentSerNum,
sizeof(parentSerNum), 1, sortStream);
2676 TQ_INT32 len = key.length() *
sizeof(TQChar);
2677 fwrite(&len,
sizeof(len), 1, sortStream);
2679 fwrite(key.unicode(), TQMIN(len, KMAIL_MAX_KEY_LEN), 1, sortStream);
2681 if (update_discover) {
2683 TQ_INT32 discovered_count = 0;
2684 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 20, SEEK_SET);
2685 fread(&discovered_count,
sizeof(discovered_count), 1, sortStream);
2687 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 20, SEEK_SET);
2688 fwrite(&discovered_count,
sizeof(discovered_count), 1, sortStream);
2694 mSortCacheItems.clear();
2695 mSubjectLists.clear();
2696 mImperfectlyThreadedList.clear();
2704 if ( mFolder->open(
"kmheaders" ) == 0 )
2705 updateMessageList();
2710 bool KMHeaders::writeSortOrder()
2712 TQString sortFile = KMAIL_SORT_FILE(mFolder);
2714 if (!mSortInfo.dirty) {
2715 struct stat stat_tmp;
2716 if(stat(TQFile::encodeName(sortFile), &stat_tmp) == -1) {
2717 mSortInfo.dirty =
true;
2720 if (mSortInfo.dirty) {
2721 if (!mFolder->count()) {
2723 unlink(TQFile::encodeName(sortFile));
2726 TQString tempName = sortFile +
".temp";
2727 unlink(TQFile::encodeName(tempName));
2728 FILE *sortStream = fopen(TQFile::encodeName(tempName),
"w");
2732 mSortInfo.ascending = !mSortDescending;
2733 mSortInfo.dirty =
false;
2734 mSortInfo.column = mSortCol;
2735 fprintf(sortStream, KMAIL_SORT_HEADER, KMAIL_SORT_VERSION);
2737 TQ_INT32 byteOrder = 0x12345678;
2738 TQ_INT32 column = mSortCol;
2739 TQ_INT32 ascending= !mSortDescending;
2741 TQ_INT32 appended=0;
2742 TQ_INT32 discovered_count = 0;
2743 TQ_INT32 sorted_count=0;
2744 fwrite(&byteOrder,
sizeof(byteOrder), 1, sortStream);
2745 fwrite(&column,
sizeof(column), 1, sortStream);
2746 fwrite(&ascending,
sizeof(ascending), 1, sortStream);
2747 fwrite(&threaded,
sizeof(threaded), 1, sortStream);
2748 fwrite(&appended,
sizeof(appended), 1, sortStream);
2749 fwrite(&discovered_count,
sizeof(discovered_count), 1, sortStream);
2750 fwrite(&sorted_count,
sizeof(sorted_count), 1, sortStream);
2752 TQPtrStack<HeaderItem> items;
2754 TQPtrStack<TQListViewItem> s;
2755 for (TQListViewItem * i = firstChild(); i; ) {
2757 if ( i->firstChild() ) {
2759 i = i->firstChild();
2760 }
else if( i->nextSibling()) {
2761 i = i->nextSibling();
2763 for(i=0; !i && s.count(); i = s.pop()->nextSibling())
2773 kmb = mFolder->getMsgBase( i->msgId() );
2777 TQString replymd5 = kmb->replyToIdMD5();
2778 TQString replyToAuxId = kmb->replyToAuxIdMD5();
2780 if(!replymd5.isEmpty())
2781 p = mSortCacheItems[replymd5];
2784 parent_id = p->id();
2790 if (replymd5.isEmpty()
2791 && replyToAuxId.isEmpty()
2792 && !kmb->subjectIsPrefixed() )
2798 internalWriteItem(sortStream, mFolder, i->msgId(), parent_id,
2799 i->key(mSortCol, !mSortDescending),
false);
2805 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET, SEEK_SET);
2806 fwrite(&byteOrder,
sizeof(byteOrder), 1, sortStream);
2807 fwrite(&column,
sizeof(column), 1, sortStream);
2808 fwrite(&ascending,
sizeof(ascending), 1, sortStream);
2809 fwrite(&threaded,
sizeof(threaded), 1, sortStream);
2810 fwrite(&appended,
sizeof(appended), 1, sortStream);
2811 fwrite(&discovered_count,
sizeof(discovered_count), 1, sortStream);
2812 fwrite(&sorted_count,
sizeof(sorted_count), 1, sortStream);
2813 if (sortStream && ferror(sortStream)) {
2815 unlink(TQFile::encodeName(sortFile));
2816 kdWarning(5006) <<
"Error: Failure modifying " << sortFile <<
" (No space left on device?)" << endl;
2817 kdWarning(5006) << __FILE__ <<
":" << __LINE__ << endl;
2818 kmkernel->emergencyExit( i18n(
"Failure modifying %1\n(No space left on device?)").arg( sortFile ));
2821 ::rename(TQFile::encodeName(tempName), TQFile::encodeName(sortFile));
2827 void KMHeaders::appendItemToSortFile(
HeaderItem *khi)
2829 TQString sortFile = KMAIL_SORT_FILE(mFolder);
2830 if(FILE *sortStream = fopen(TQFile::encodeName(sortFile),
"r+")) {
2835 KMMsgBase *kmb = mFolder->getMsgBase( khi->
msgId() );
2837 parent_id = sci->
parent()->id();
2838 else if(kmb->replyToIdMD5().isEmpty()
2839 && kmb->replyToAuxIdMD5().isEmpty()
2840 && !kmb->subjectIsPrefixed())
2844 internalWriteItem(sortStream, mFolder, khi->
msgId(), parent_id,
2845 khi->key(mSortCol, !mSortDescending),
false);
2848 TQ_INT32 appended = 1;
2849 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 16, SEEK_SET);
2850 fwrite(&appended,
sizeof(appended), 1, sortStream);
2851 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 16, SEEK_SET);
2853 if (sortStream && ferror(sortStream)) {
2855 unlink(TQFile::encodeName(sortFile));
2856 kdWarning(5006) <<
"Error: Failure modifying " << sortFile <<
" (No space left on device?)" << endl;
2857 kdWarning(5006) << __FILE__ <<
":" << __LINE__ << endl;
2858 kmkernel->emergencyExit( i18n(
"Failure modifying %1\n(No space left on device?)").arg( sortFile ));
2862 mSortInfo.dirty =
true;
2868 mSortInfo.dirty =
true;
2869 TQObject::disconnect(header(), TQT_SIGNAL(clicked(
int)),
this, TQT_SLOT(
dirtySortOrder(
int)));
2870 setSorting(column, mSortInfo.column == column ? !mSortInfo.ascending :
true);
2874 void SortCacheItem::updateSortFile( FILE *sortStream,
KMFolder *folder,
2875 bool waiting_for_parent,
bool update_discover)
2877 if(mSortOffset == -1) {
2878 fseek(sortStream, 0, SEEK_END);
2879 mSortOffset = ftell(sortStream);
2881 fseek(sortStream, mSortOffset, SEEK_SET);
2885 if(!waiting_for_parent) {
2887 parent_id = mParent->id();
2889 internalWriteItem(sortStream, folder, mId, parent_id, mKey, update_discover);
2892 static bool compare_ascending =
false;
2893 static bool compare_toplevel =
true;
2894 static int compare_SortCacheItem(
const void *s1,
const void *s2)
2900 int ret = (*b1)->key().compare((*b2)->key());
2901 if(compare_ascending || !compare_toplevel)
2907 void KMHeaders::printSubjectThreadingTree()
2909 TQDictIterator< TQPtrList< SortCacheItem > > it ( mSubjectLists );
2910 kdDebug(5006) <<
"SubjectThreading tree: " << endl;
2911 for( ; it.current(); ++it ) {
2912 TQPtrList<SortCacheItem> list = *( it.current() );
2913 TQPtrListIterator<SortCacheItem> it2( list ) ;
2914 kdDebug(5006) <<
"Subject MD5: " << it.currentKey() <<
" list: " << endl;
2915 for( ; it2.current(); ++it2 ) {
2917 kdDebug(5006) <<
" item:" << sci <<
" sci id: " << sci->id() << endl;
2920 kdDebug(5006) << endl;
2923 void KMHeaders::printThreadingTree()
2925 kdDebug(5006) <<
"Threading tree: " << endl;
2926 TQDictIterator<SortCacheItem> it( mSortCacheItems );
2927 kdDebug(5006) << endl;
2928 for( ; it.current(); ++it ) {
2930 kdDebug(5006) <<
"MsgId MD5: " << it.currentKey() <<
" message id: " << sci->id() << endl;
2932 for (
int i = 0; i < (int)mItems.size(); ++i) {
2935 kdDebug( 5006 ) <<
"SortCacheItem: " << item->
sortCacheItem()->id() <<
" parent: " << parentCacheId << endl;
2938 kdDebug(5006) << endl;
2943 void KMHeaders::buildThreadingTree( TQMemArray<SortCacheItem *> sortCache )
2945 mSortCacheItems.clear();
2946 mSortCacheItems.resize( mFolder->count() * 2 );
2949 for(
int x = 0; x < mFolder->count(); x++) {
2950 KMMsgBase *mi = mFolder->getMsgBase(x);
2951 TQString md5 = mi->msgIdMD5();
2953 mSortCacheItems.replace(md5, sortCache[x]);
2958 void KMHeaders::buildSubjectThreadingTree( TQMemArray<SortCacheItem *> sortCache )
2960 mSubjectLists.clear();
2961 mSubjectLists.resize( mFolder->count() * 2 );
2963 for(
int x = 0; x < mFolder->count(); x++) {
2965 if ( sortCache[x]->parent()
2966 && sortCache[x]->parent()->id() != -666 )
continue;
2967 KMMsgBase *mi = mFolder->getMsgBase(x);
2968 TQString subjMD5 = mi->strippedSubjectMD5();
2969 if (subjMD5.isEmpty()) {
2970 mFolder->getMsgBase(x)->initStrippedSubjectMD5();
2971 subjMD5 = mFolder->getMsgBase(x)->strippedSubjectMD5();
2973 if( subjMD5.isEmpty() )
continue;
2977 if (!mSubjectLists.find(subjMD5))
2978 mSubjectLists.insert(subjMD5,
new TQPtrList<SortCacheItem>());
2984 for (TQPtrListIterator<SortCacheItem> it(*mSubjectLists[subjMD5]);
2985 it.current(); ++it) {
2986 KMMsgBase *mb = mFolder->getMsgBase((*it)->id());
2987 if ( mb->date() < mi->date())
2991 mSubjectLists[subjMD5]->insert( p, sortCache[x]);
3000 if (!item)
return parent;
3001 KMMsgBase *msg = mFolder->getMsgBase(item->id());
3002 TQString replyToIdMD5 = msg->replyToIdMD5();
3006 if(!replyToIdMD5.isEmpty()) {
3007 parent = mSortCacheItems[replyToIdMD5];
3018 TQString ref = msg->replyToAuxIdMD5();
3020 parent = mSortCacheItems[ref];
3028 if (!item)
return parent;
3030 KMMsgBase *msg = mFolder->getMsgBase(item->id());
3035 if (!msg->subjectIsPrefixed())
3038 TQString replyToIdMD5 = msg->replyToIdMD5();
3039 TQString subjMD5 = msg->strippedSubjectMD5();
3040 if (!subjMD5.isEmpty() && mSubjectLists[subjMD5]) {
3043 for (TQPtrListIterator<SortCacheItem> it2(*mSubjectLists[subjMD5]);
3044 it2.current(); ++it2) {
3045 KMMsgBase *mb = mFolder->getMsgBase((*it2)->id());
3046 if ( !mb )
return parent;
3048 if ( item == (*it2) )
continue;
3049 int delta = msg->date() - mb->date();
3054 if (delta < 3628899)
3063 bool KMHeaders::readSortOrder(
bool set_selection,
bool forceJumpToUnread )
3065 if (!mFolder->isOpened()) mFolder->open(
"kmheaders");
3068 TQ_INT32 column, ascending, threaded, discovered_count, sorted_count, appended;
3069 TQ_INT32 deleted_count = 0;
3070 bool unread_exists =
false;
3071 bool jumpToUnread = (GlobalSettings::self()->actionEnterFolder() ==
3072 GlobalSettings::EnumActionEnterFolder::SelectFirstUnreadNew) ||
3076 TQMemArray<SortCacheItem *> sortCache(mFolder->count());
3080 TQPtrList<SortCacheItem> unparented;
3081 mImperfectlyThreadedList.clear();
3084 mItems.fill( 0, mFolder->count() );
3085 sortCache.fill( 0 );
3087 mRoot->clearChildren();
3089 TQString sortFile = KMAIL_SORT_FILE(mFolder);
3090 FILE *sortStream = fopen(TQFile::encodeName(sortFile),
"r+");
3091 mSortInfo.fakeSort = 0;
3094 mSortInfo.fakeSort = 1;
3096 if (fscanf(sortStream, KMAIL_SORT_HEADER, &version) != 1)
3098 if(version == KMAIL_SORT_VERSION) {
3099 TQ_INT32 byteOrder = 0;
3100 fread(&byteOrder,
sizeof(byteOrder), 1, sortStream);
3101 if (byteOrder == 0x12345678)
3103 fread(&column,
sizeof(column), 1, sortStream);
3104 fread(&ascending,
sizeof(ascending), 1, sortStream);
3105 fread(&threaded,
sizeof(threaded), 1, sortStream);
3106 fread(&appended,
sizeof(appended), 1, sortStream);
3107 fread(&discovered_count,
sizeof(discovered_count), 1, sortStream);
3108 fread(&sorted_count,
sizeof(sorted_count), 1, sortStream);
3111 TDEListView::setSorting(-1);
3112 header()->setSortIndicator(column, ascending);
3113 TQObject::connect(header(), TQT_SIGNAL(clicked(
int)),
this, TQT_SLOT(dirtySortOrder(
int)));
3115 mSortInfo.dirty =
false;
3116 mSortInfo.column = (short)column;
3117 mSortInfo.ascending = (compare_ascending = ascending);
3120 unsigned long serNum, parentSerNum;
3121 int id, len, parent, x;
3122 TQChar *tmp_qchar = 0;
3123 int tmp_qchar_len = 0;
3124 const int mFolderCount = mFolder->count();
3127 CREATE_TIMER(parse);
3129 for(x = 0; !feof(sortStream) && !error; x++) {
3130 off_t offset = ftell(sortStream);
3133 if(!fread(&serNum,
sizeof(serNum), 1, sortStream) ||
3134 !fread(&parentSerNum,
sizeof(parentSerNum), 1, sortStream) ||
3135 !fread(&len,
sizeof(len), 1, sortStream)) {
3138 if ((len < 0) || (len > KMAIL_MAX_KEY_LEN)) {
3139 kdDebug(5006) <<
"Whoa.2! len " << len <<
" " << __FILE__ <<
":" << __LINE__ << endl;
3144 if(len > tmp_qchar_len) {
3145 tmp_qchar = (TQChar *)realloc(tmp_qchar, len);
3146 tmp_qchar_len = len;
3148 if(!fread(tmp_qchar, len, 1, sortStream))
3150 key = TQString(tmp_qchar, len / 2);
3156 if (folder != mFolder) {
3160 if (parentSerNum < KMAIL_RESERVED) {
3161 parent = (int)parentSerNum - KMAIL_RESERVED;
3164 if (folder != mFolder)
3167 if ((
id < 0) || (
id >= mFolderCount) ||
3168 (parent < -2) || (parent >= mFolderCount)) {
3169 kdDebug(5006) <<
"Whoa.1! " << __FILE__ <<
":" << __LINE__ << endl;
3174 if ((item=sortCache[
id])) {
3175 if (item->id() != -1) {
3176 kdDebug(5006) <<
"Whoa.3! " << __FILE__ <<
":" << __LINE__ << endl;
3182 item->setOffset(offset);
3186 if (threaded && parent != -2) {
3188 unparented.append(item);
3189 mRoot->addUnsortedChild(item);
3191 if( ! sortCache[parent] ) {
3197 if(x < sorted_count )
3198 mRoot->addSortedChild(item);
3200 mRoot->addUnsortedChild(item);
3204 if (error || (x != sorted_count + discovered_count)) {
3205 kdDebug(5006) << endl <<
"Whoa: x " << x <<
", sorted_count " << sorted_count <<
", discovered_count " << discovered_count <<
", count " << mFolder->count() << endl << endl;
3226 mSortInfo.dirty =
true;
3227 mSortInfo.column = column = mSortCol;
3228 mSortInfo.ascending = ascending = !mSortDescending;
3229 threaded = (isThreaded());
3230 sorted_count = discovered_count = appended = 0;
3231 TDEListView::setSorting( mSortCol, !mSortDescending );
3234 if((sorted_count + discovered_count - deleted_count) < mFolder->count()) {
3235 CREATE_TIMER(holes);
3238 for(
int x = 0; x < mFolder->count(); x++) {
3239 if((!sortCache[x] || (sortCache[x]->
id() < 0)) && (msg=mFolder->getMsgBase(x))) {
3240 int sortOrder = column;
3241 if (mPaintInfo.orderOfArrival)
3242 sortOrder |= (1 << 6);
3243 if (mPaintInfo.status)
3244 sortOrder |= (1 << 5);
3246 x, HeaderItem::generate_key(
this, msg, &mPaintInfo, sortOrder ));
3248 unparented.append(sortCache[x]);
3250 mRoot->addUnsortedChild(sortCache[x]);
3252 sortCache[x]->updateSortFile(sortStream, mFolder,
true,
true);
3263 if (threaded) buildThreadingTree( sortCache );
3264 TQPtrList<SortCacheItem> toBeSubjThreaded;
3266 if (threaded && !unparented.isEmpty()) {
3267 CREATE_TIMER(reparent);
3268 START_TIMER(reparent);
3270 for(TQPtrListIterator<SortCacheItem> it(unparented); it.current(); ++it) {
3274 if ( parent && (parent != (*it)) ) {
3277 (*it)->updateSortFile(sortStream, mFolder);
3282 toBeSubjThreaded.append((*it));
3284 mRoot->addUnsortedChild((*it));
3288 if (mSubjThreading) {
3289 buildSubjectThreadingTree( sortCache );
3290 for(TQPtrListIterator<SortCacheItem> it(toBeSubjThreaded); it.current(); ++it) {
3297 (*it)->updateSortFile(sortStream, mFolder);
3300 mRoot->addUnsortedChild((*it));
3304 END_TIMER(reparent);
3305 SHOW_TIMER(reparent);
3308 CREATE_TIMER(header_creation);
3309 START_TIMER(header_creation);
3312 TQPtrQueue<SortCacheItem> s;
3314 compare_toplevel =
true;
3318 int unsorted_count, unsorted_off=0;
3322 compare_SortCacheItem);
3328 for(TQPtrListIterator<SortCacheItem> it(*sorted);
3329 (unsorted && unsorted_off < unsorted_count) || it.current(); ) {
3336 ( !unsorted || unsorted_off >= unsorted_count
3338 ( ( !ascending || (ascending && !compare_toplevel) )
3339 && (*it)->key() < unsorted[unsorted_off]->
key() )
3341 ( ascending && (*it)->key() >= unsorted[unsorted_off]->
key() )
3349 new_kci = unsorted[unsorted_off++];
3351 if(new_kci->
item() || new_kci->
parent() != i)
3354 if(threaded && i->
item()) {
3357 if (mFolder->getMsgBase(i->id())->isWatched())
3358 mFolder->getMsgBase(new_kci->id())->setStatus(KMMsgStatusWatched);
3359 if (mFolder->getMsgBase(i->id())->isIgnored())
3360 mFolder->getMsgBase(new_kci->id())->setStatus(KMMsgStatusIgnored);
3365 new_kci->
setItem(mItems[new_kci->id()] = khi);
3370 if ( ( mFolder->getMsgBase(new_kci->id())->isNew() &&
3371 GlobalSettings::self()->actionEnterFolder() ==
3372 GlobalSettings::EnumActionEnterFolder::SelectFirstNew ) ||
3373 ( ( mFolder->getMsgBase(new_kci->id())->isNew() ||
3374 mFolder->getMsgBase(new_kci->id())->isUnread() ) &&
3377 unread_exists =
true;
3380 if ( !oldestItem || mFolder->getMsgBase( oldestItem->
msgId() )->date() >
3381 mFolder->getMsgBase( new_kci->id() )->date() ) {
3385 if ( !newestItem || mFolder->getMsgBase( newestItem->
msgId() )->date() <
3386 mFolder->getMsgBase( new_kci->id() )->date() ) {
3393 if (mSortCol == paintInfo()->dateCol)
3394 compare_toplevel =
false;
3395 }
while(!s.isEmpty());
3397 for(
int x = 0; x < mFolder->count(); x++) {
3398 if (!sortCache[x]) {
3402 if (!sortCache[x]->item()) {
3403 kdDebug(5006) <<
"KMHeaders::readSortOrder - msg could not be threaded. "
3404 << endl <<
"Please talk to your threading counselor asap. " << endl;
3405 khi =
new HeaderItem(
this, sortCache[x]->
id(), sortCache[x]->key());
3406 sortCache[x]->setItem(mItems[sortCache[x]->
id()] = khi);
3411 if (threaded && sortCache[x]->isImperfectlyThreaded()) {
3412 mImperfectlyThreadedList.append(sortCache[x]->item());
3416 sortCache[x]->item()->setSortCacheItem(sortCache[x]);
3419 if (getNestingPolicy()<2)
3420 for (
HeaderItem *khi=static_cast<HeaderItem*>(firstChild()); khi!=0;khi=
static_cast<HeaderItem*
>(khi->nextSibling()))
3423 END_TIMER(header_creation);
3424 SHOW_TIMER(header_creation);
3428 if( discovered_count * discovered_count > sorted_count - deleted_count ) {
3429 mSortInfo.dirty =
true;
3433 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 16, SEEK_SET);
3434 fwrite(&appended,
sizeof(appended), 1, sortStream);
3439 CREATE_TIMER(selection);
3440 START_TIMER(selection);
3444 int first_unread = -1;
3445 if (unread_exists) {
3448 if ( ( mFolder->getMsgBase(item->
msgId())->isNew() &&
3449 GlobalSettings::self()->actionEnterFolder() ==
3450 GlobalSettings::EnumActionEnterFolder::SelectFirstNew ) ||
3451 ( ( mFolder->getMsgBase(item->
msgId())->isNew() ||
3452 mFolder->getMsgBase(item->
msgId())->isUnread() ) &&
3455 first_unread = item->
msgId();
3458 item =
static_cast<HeaderItem*
>(item->itemBelow());
3463 if(first_unread == -1 ) {
3464 setTopItemByIndex( mTopItem );
3466 if ( GlobalSettings::self()->actionEnterFolder() ==
3467 GlobalSettings::EnumActionEnterFolder::SelectNewest && newestItem != 0 ) {
3468 setCurrentItemByIndex( newestItem->
msgId() );
3470 else if ( GlobalSettings::self()->actionEnterFolder() ==
3471 GlobalSettings::EnumActionEnterFolder::SelectOldest && oldestItem != 0 ) {
3472 setCurrentItemByIndex( oldestItem->
msgId() );
3474 else if ( mCurrentItem >= 0 )
3475 setCurrentItemByIndex( mCurrentItem );
3476 else if ( mCurrentItemSerNum > 0 )
3477 setCurrentItemBySerialNum( mCurrentItemSerNum );
3479 setCurrentItemByIndex( 0 );
3483 setCurrentItemByIndex(first_unread);
3484 makeHeaderVisible();
3485 center( contentsX(), itemPos(mItems[first_unread]), 0, 9.0 );
3491 if (mCurrentItem <= 0) {
3492 setTopItemByIndex(mTopItem);
3493 setCurrentItemByIndex(0);
3496 END_TIMER(selection);
3497 SHOW_TIMER(selection);
3498 if (error || (sortStream && ferror(sortStream))) {
3501 unlink(TQFile::encodeName(sortFile));
3502 kdWarning(5006) <<
"Error: Failure modifying " << sortFile <<
" (No space left on device?)" << endl;
3503 kdWarning(5006) << __FILE__ <<
":" << __LINE__ << endl;
3519 for (
int i = 0; i < (int)mItems.size() - 1; ++i) {
3520 KMMsgBase *mMsgBase = mFolder->getMsgBase( i );
3521 if ( mMsgBase->getMsgSerNum() == serialNum ) {
3522 bool unchanged = (currentItem() == mItems[i]);
3523 setCurrentItem( mItems[i] );
3524 setSelected( mItems[i],
true );
3525 setSelectionAnchor( currentItem() );
3527 highlightMessage( currentItem(),
false );
3528 ensureCurrentItemVisible();
3533 kdDebug(5006) <<
"KMHeaders::setCurrentItem item with serial number " << serialNum <<
" NOT FOUND" << endl;
3536 void KMHeaders::copyMessages()
3538 mCopiedMessages.clear();
3539 KMMessageList* list = selectedMsgs();
3540 for ( uint i = 0; i < list->count(); ++ i )
3541 mCopiedMessages << list->at( i )->getMsgSerNum();
3542 mMoveMessages =
false;
3547 void KMHeaders::cutMessages()
3549 mCopiedMessages.clear();
3550 KMMessageList* list = selectedMsgs();
3551 for ( uint i = 0; i < list->count(); ++ i )
3552 mCopiedMessages << list->at( i )->getMsgSerNum();
3553 mMoveMessages =
true;
3558 void KMHeaders::pasteMessages()
3560 new MessageCopyHelper( mCopiedMessages, folder(), mMoveMessages, TQT_TQOBJECT(
this) );
3561 if ( mMoveMessages ) {
3562 mCopiedMessages.clear();
3567 void KMHeaders::updateActions()
3569 TDEAction *copy = owner()->action(
"copy_messages" );
3570 TDEAction *cut = owner()->action(
"cut_messages" );
3571 TDEAction *paste = owner()->action(
"paste_messages" );
3573 if ( selectedItems().isEmpty() ) {
3574 copy->setEnabled(
false );
3575 cut->setEnabled(
false );
3577 copy->setEnabled(
true );
3578 if ( folder() && !folder()->canDeleteMessages() )
3579 cut->setEnabled(
false );
3581 cut->setEnabled(
true );
3584 if ( mCopiedMessages.isEmpty() || !folder() || folder()->
isReadOnly() )
3585 paste->setEnabled(
false );
3587 paste->setEnabled(
true );
3592 mCopiedMessages = msgs;
3593 mMoveMessages = move;
3599 return mMoveMessages && mCopiedMessages.contains( serNum );
3604 TQValueList<TQ_UINT32> list;
3605 for ( TQListViewItemIterator it(
this); it.current(); it++ ) {
3606 if ( it.current()->isSelected() && it.current()->isVisible() ) {
3608 KMMsgBase *msgBase = mFolder->getMsgBase( item->
msgId() );
3610 list.append( msgBase->getMsgSerNum() );
3619 TQValueList<TQ_UINT32> list;
3620 TQListViewItemIterator it(
this, TQListViewItemIterator::Selected|TQListViewItemIterator::Visible);
3621 while( it.current() ) {
3622 if ( it.current()->isSelected() && it.current()->isVisible() ) {
3623 if ( it.current()->parent() && ( !it.current()->parent()->isOpen() ) ) {
3625 TQListViewItem * lastAncestorWithSiblings = it.current()->parent();
3627 while ( ( lastAncestorWithSiblings->depth() > 0 ) && !lastAncestorWithSiblings->nextSibling() )
3628 lastAncestorWithSiblings = lastAncestorWithSiblings->parent();
3630 it = TQListViewItemIterator( lastAncestorWithSiblings->nextSibling() );
3634 KMMsgBase *msgBase = mFolder->getMsgBase( item->
msgId() );
3636 list.append( msgBase->getMsgSerNum() );
3645 #include "kmheaders.moc"