6 #include "headeritem.h"
9 #include "kcursorsaver.h"
10 #include "kmcommands.h"
11 #include "kmmainwidget.h"
12 #include "kmfiltermgr.h"
13 #include "undostack.h"
14 #include "kmmsgdict.h"
16 #include "kmfoldertree.h"
17 #include "folderjob.h"
18 using KMail::FolderJob;
19 #include "actionscheduler.h"
20 using KMail::ActionScheduler;
21 #include "messagecopyhelper.h"
23 #include "broadcaststatus.h"
24 using KPIM::BroadcastStatus;
25 #include "progressmanager.h"
26 using KPIM::ProgressManager;
27 using KPIM::ProgressItem;
28 #include <maillistdrag.h>
29 #include "globalsettings.h"
31 #include "messageactions.h"
33 #include <tdeapplication.h>
34 #include <tdeaccelmanager.h>
35 #include <tdeglobalsettings.h>
36 #include <tdemessagebox.h>
37 #include <kiconloader.h>
38 #include <tdepopupmenu.h>
40 #include <tdeconfig.h>
41 #include <tdelocale.h>
45 #include <tqeventloop.h>
48 #include <tqptrstack.h>
49 #include <tqptrqueue.h>
50 #include <tqpainter.h>
51 #include <tqtextcodec.h>
53 #include <tqlistview.h>
55 #include <mimelib/enum.h>
56 #include <mimelib/field.h>
57 #include <mimelib/mimepp.h>
62 #include "textsource.h"
64 TQPixmap* KMHeaders::pixNew = 0;
65 TQPixmap* KMHeaders::pixUns = 0;
66 TQPixmap* KMHeaders::pixDel = 0;
67 TQPixmap* KMHeaders::pixRead = 0;
68 TQPixmap* KMHeaders::pixRep = 0;
69 TQPixmap* KMHeaders::pixQueued = 0;
70 TQPixmap* KMHeaders::pixTodo = 0;
71 TQPixmap* KMHeaders::pixSent = 0;
72 TQPixmap* KMHeaders::pixFwd = 0;
73 TQPixmap* KMHeaders::pixFlag = 0;
74 TQPixmap* KMHeaders::pixWatched = 0;
75 TQPixmap* KMHeaders::pixIgnored = 0;
76 TQPixmap* KMHeaders::pixSpam = 0;
77 TQPixmap* KMHeaders::pixHam = 0;
78 TQPixmap* KMHeaders::pixFullySigned = 0;
79 TQPixmap* KMHeaders::pixPartiallySigned = 0;
80 TQPixmap* KMHeaders::pixUndefinedSigned = 0;
81 TQPixmap* KMHeaders::pixFullyEncrypted = 0;
82 TQPixmap* KMHeaders::pixPartiallyEncrypted = 0;
83 TQPixmap* KMHeaders::pixUndefinedEncrypted = 0;
84 TQPixmap* KMHeaders::pixEncryptionProblematic = 0;
85 TQPixmap* KMHeaders::pixSignatureProblematic = 0;
86 TQPixmap* KMHeaders::pixAttachment = 0;
87 TQPixmap* KMHeaders::pixInvitation = 0;
88 TQPixmap* KMHeaders::pixReadFwd = 0;
89 TQPixmap* KMHeaders::pixReadReplied = 0;
90 TQPixmap* KMHeaders::pixReadFwdReplied = 0;
94 KMHeaders::KMHeaders(KMMainWidget *aOwner, TQWidget *parent,
96 TDEListView( parent, name ),
97 mIgnoreSortOrderChanges( false )
99 static bool pixmapsLoaded =
false;
101 KImageIO::registerFormats();
107 setSelectionMode( TQListView::Extended );
108 setAllColumnsShowFocus(
true );
110 nestingPolicy = OpenUnread;
111 mNestedOverride =
false;
112 mSubjThreading =
true;
113 mMousePressed =
false;
114 mSortInfo.dirty =
true;
115 mSortInfo.fakeSort = 0;
116 mSortInfo.removed = 0;
117 mSortInfo.column = 0;
119 mSortDescending =
false;
120 mSortInfo.ascending =
false;
121 mReaderWindowActive =
false;
124 setStyleDependantFrameWidth();
126 header()->setClickEnabled(
true);
127 header()->installEventFilter(
this);
128 mPopup =
new TDEPopupMenu(
this);
129 mPopup->insertTitle(i18n(
"View Columns"));
130 mPopup->setCheckable(
true);
131 mPopup->insertItem(i18n(
"Status"), KPaintInfo::COL_STATUS);
132 mPopup->insertItem(i18n(
"Important"), KPaintInfo::COL_IMPORTANT);
133 mPopup->insertItem(i18n(
"Action Item"), KPaintInfo::COL_TODO);
134 mPopup->insertItem(i18n(
"Attachment"), KPaintInfo::COL_ATTACHMENT);
135 mPopup->insertItem(i18n(
"Invitation"), KPaintInfo::COL_INVITATION);
136 mPopup->insertItem(i18n(
"Spam/Ham"), KPaintInfo::COL_SPAM_HAM);
137 mPopup->insertItem(i18n(
"Watched/Ignored"), KPaintInfo::COL_WATCHED_IGNORED);
138 mPopup->insertItem(i18n(
"Signature"), KPaintInfo::COL_SIGNED);
139 mPopup->insertItem(i18n(
"Encryption"), KPaintInfo::COL_CRYPTO);
140 mPopup->insertItem(i18n(
"Size"), KPaintInfo::COL_SIZE);
141 mPopup->insertItem(i18n(
"Receiver"), KPaintInfo::COL_RECEIVER);
143 connect(mPopup, TQ_SIGNAL(activated(
int)),
this, TQ_SLOT(slotToggleColumn(
int)));
145 setShowSortIndicator(
true);
146 setFocusPolicy( TQWidget::WheelFocus );
150 pixmapsLoaded =
true;
151 pixNew =
new TQPixmap( UserIcon(
"kmmsgnew" ) );
152 pixUns =
new TQPixmap( UserIcon(
"kmmsgunseen" ) );
153 pixDel =
new TQPixmap( UserIcon(
"kmmsgdel" ) );
154 pixRead =
new TQPixmap( UserIcon(
"kmmsgread" ) );
155 pixRep =
new TQPixmap( UserIcon(
"kmmsgreplied" ) );
156 pixQueued =
new TQPixmap( UserIcon(
"kmmsgqueued" ) );
157 pixTodo =
new TQPixmap( UserIcon(
"kmmsgtodo" ) );
158 pixSent =
new TQPixmap( UserIcon(
"kmmsgsent" ) );
159 pixFwd =
new TQPixmap( UserIcon(
"kmmsgforwarded" ) );
160 pixFlag =
new TQPixmap( UserIcon(
"kmmsgflag" ) );
161 pixWatched =
new TQPixmap( UserIcon(
"kmmsgwatched" ) );
162 pixIgnored =
new TQPixmap( UserIcon(
"kmmsgignored" ) );
163 pixSpam =
new TQPixmap( UserIcon(
"kmmsgspam" ) );
164 pixHam =
new TQPixmap( UserIcon(
"kmmsgham" ) );
165 pixFullySigned =
new TQPixmap( UserIcon(
"kmmsgfullysigned" ) );
166 pixPartiallySigned =
new TQPixmap( UserIcon(
"kmmsgpartiallysigned" ) );
167 pixUndefinedSigned =
new TQPixmap( UserIcon(
"kmmsgundefinedsigned" ) );
168 pixFullyEncrypted =
new TQPixmap( UserIcon(
"kmmsgfullyencrypted" ) );
169 pixPartiallyEncrypted =
new TQPixmap( UserIcon(
"kmmsgpartiallyencrypted" ) );
170 pixUndefinedEncrypted =
new TQPixmap( UserIcon(
"kmmsgundefinedencrypted" ) );
171 pixEncryptionProblematic =
new TQPixmap( UserIcon(
"kmmsgencryptionproblematic" ) );
172 pixSignatureProblematic =
new TQPixmap( UserIcon(
"kmmsgsignatureproblematic" ) );
173 pixAttachment =
new TQPixmap( UserIcon(
"kmmsgattachment" ) );
174 pixInvitation =
new TQPixmap( UserIcon(
"kmmsginvitation" ) );
175 pixReadFwd =
new TQPixmap( UserIcon(
"kmmsgread_fwd" ) );
176 pixReadReplied =
new TQPixmap( UserIcon(
"kmmsgread_replied" ) );
177 pixReadFwdReplied =
new TQPixmap( UserIcon(
"kmmsgread_fwd_replied" ) );
180 header()->setStretchEnabled(
false );
181 header()->setResizeEnabled(
false );
183 mPaintInfo.subCol = addColumn( i18n(
"Subject"), 310 );
184 mPaintInfo.senderCol = addColumn( i18n(
"Sender"), 170 );
185 mPaintInfo.dateCol = addColumn( i18n(
"Date"), 170 );
186 mPaintInfo.sizeCol = addColumn( i18n(
"Size"), 0 );
187 mPaintInfo.receiverCol = addColumn( i18n(
"Receiver"), 0 );
189 mPaintInfo.statusCol = addColumn( *pixNew ,
"", 0 );
190 mPaintInfo.importantCol = addColumn( *pixFlag ,
"", 0 );
191 mPaintInfo.todoCol = addColumn( *pixTodo ,
"", 0 );
192 mPaintInfo.attachmentCol = addColumn( *pixAttachment ,
"", 0 );
193 mPaintInfo.invitationCol = addColumn( *pixInvitation ,
"", 0 );
194 mPaintInfo.spamHamCol = addColumn( *pixSpam ,
"", 0 );
195 mPaintInfo.watchedIgnoredCol = addColumn( *pixWatched ,
"", 0 );
196 mPaintInfo.signedCol = addColumn( *pixFullySigned ,
"", 0 );
197 mPaintInfo.cryptoCol = addColumn( *pixFullyEncrypted,
"", 0 );
199 setResizeMode( TQListView::NoColumn );
202 header()->setResizeEnabled(
true, mPaintInfo.subCol );
203 header()->setResizeEnabled(
true, mPaintInfo.senderCol );
204 header()->setResizeEnabled(
true, mPaintInfo.dateCol );
206 connect(
this, TQ_SIGNAL( contextMenuRequested( TQListViewItem*,
const TQPoint &,
int )),
207 this, TQ_SLOT( rightButtonPressed( TQListViewItem*,
const TQPoint &,
int )));
208 connect(
this, TQ_SIGNAL(doubleClicked(TQListViewItem*)),
209 this,TQ_SLOT(selectMessage(TQListViewItem*)));
210 connect(
this,TQ_SIGNAL(currentChanged(TQListViewItem*)),
211 this,TQ_SLOT(highlightMessage(TQListViewItem*)));
214 mSubjectLists.setAutoDelete(
true );
216 mMoveMessages =
false;
217 connect(
this, TQ_SIGNAL(selectionChanged()), TQ_SLOT(updateActions()) );
222 KMHeaders::~KMHeaders ()
228 mFolder->close(
"kmheaders");
235 bool KMHeaders::eventFilter ( TQObject *o, TQEvent *e )
237 if ( e->type() == TQEvent::MouseButtonPress &&
238 static_cast<TQMouseEvent*
>(e)->button() == TQt::RightButton &&
243 if ( mPaintInfo.showReceiver )
244 mPopup->changeItem(KPaintInfo::COL_RECEIVER, i18n(
"Receiver"));
246 if ( mFolder && (mFolder->whoField().lower() ==
"to") )
247 mPopup->changeItem(KPaintInfo::COL_RECEIVER, i18n(
"Sender"));
249 mPopup->changeItem(KPaintInfo::COL_RECEIVER, i18n(
"Receiver"));
251 mPopup->popup(
static_cast<TQMouseEvent*
>(e)->globalPos() );
254 return TDEListView::eventFilter(o, e);
266 switch (
static_cast<KPaintInfo::ColumnIds
>(
id) )
268 case KPaintInfo::COL_SIZE:
270 show = &mPaintInfo.showSize;
271 col = &mPaintInfo.sizeCol;
275 case KPaintInfo::COL_ATTACHMENT:
277 show = &mPaintInfo.showAttachment;
278 col = &mPaintInfo.attachmentCol;
279 width = pixAttachment->width() + 8;
280 if ( *col == header()->mapToIndex( *col ) )
284 case KPaintInfo::COL_INVITATION:
286 show = &mPaintInfo.showInvitation;
287 col = &mPaintInfo.invitationCol;
288 width = pixAttachment->width() + 8;
289 if ( *col == header()->mapToIndex( *col ) )
293 case KPaintInfo::COL_IMPORTANT:
295 show = &mPaintInfo.showImportant;
296 col = &mPaintInfo.importantCol;
297 width = pixFlag->width() + 8;
298 if ( *col == header()->mapToIndex( *col ) )
302 case KPaintInfo::COL_TODO:
304 show = &mPaintInfo.showTodo;
305 col = &mPaintInfo.todoCol;
306 width = pixTodo->width() + 8;
307 if ( *col == header()->mapToIndex( *col ) )
311 case KPaintInfo::COL_SPAM_HAM:
313 show = &mPaintInfo.showSpamHam;
314 col = &mPaintInfo.spamHamCol;
315 width = pixSpam->width() + 8;
316 if ( *col == header()->mapToIndex( *col ) )
320 case KPaintInfo::COL_WATCHED_IGNORED:
322 show = &mPaintInfo.showWatchedIgnored;
323 col = &mPaintInfo.watchedIgnoredCol;
324 width = pixWatched->width() + 8;
325 if ( *col == header()->mapToIndex( *col ) )
329 case KPaintInfo::COL_STATUS:
331 show = &mPaintInfo.showStatus;
332 col = &mPaintInfo.statusCol;
333 width = pixNew->width() + 8;
334 if ( *col == header()->mapToIndex( *col ) )
338 case KPaintInfo::COL_SIGNED:
340 show = &mPaintInfo.showSigned;
341 col = &mPaintInfo.signedCol;
342 width = pixFullySigned->width() + 8;
343 if ( *col == header()->mapToIndex( *col ) )
347 case KPaintInfo::COL_CRYPTO:
349 show = &mPaintInfo.showCrypto;
350 col = &mPaintInfo.cryptoCol;
351 width = pixFullyEncrypted->width() + 8;
352 if ( *col == header()->mapToIndex( *col ) )
356 case KPaintInfo::COL_RECEIVER:
358 show = &mPaintInfo.showReceiver;
359 col = &mPaintInfo.receiverCol;
363 case KPaintInfo::COL_SCORE: ;
374 mPopup->setItemChecked(
id, *show);
377 header()->setResizeEnabled(
true, *col);
378 setColumnWidth(*col, width);
379 if ( moveToCol >= 0 )
380 header()->moveSection( *col, moveToCol );
383 header()->setResizeEnabled(
false, *col);
384 header()->setStretchEnabled(
false, *col);
390 if (
static_cast<KPaintInfo::ColumnIds
>(
id) == KPaintInfo::COL_RECEIVER ) {
391 TQString colText = i18n(
"Sender" );
392 if ( mFolder && (mFolder->whoField().lower() ==
"to") && !mPaintInfo.showReceiver)
393 colText = i18n(
"Receiver" );
394 setColumnText( mPaintInfo.senderCol, colText );
405 if (mPaintInfo.pixmapOn)
406 p->drawTiledPixmap( rect.left(), rect.top(), rect.width(), rect.height(),
408 rect.left() + contentsX(),
409 rect.top() + contentsY() );
411 p->fillRect( rect, colorGroup().base() );
416 bool result = TDEListView::event(e);
417 if (e->type() == TQEvent::ApplicationPaletteChange)
428 TDEConfig* config = KMKernel::config();
430 TDEConfigGroupSaver saver(config,
"Reader");
431 TQColor c1=TQColor(kapp->palette().active().text());
432 TQColor c2=TQColor(
"red");
433 TQColor c3=TQColor(
"blue");
434 TQColor c4=TQColor(kapp->palette().active().base());
435 TQColor c5=TQColor(0,0x7F,0);
436 TQColor c6=TQColor(0,0x98,0);
437 TQColor c7=TDEGlobalSettings::alternateBackgroundColor();
439 if (!config->readBoolEntry(
"defaultColors",
true)) {
440 mPaintInfo.colFore = config->readColorEntry(
"ForegroundColor",&c1);
441 mPaintInfo.colBack = config->readColorEntry(
"BackgroundColor",&c4);
442 TQPalette newPal = kapp->palette();
443 newPal.setColor( TQColorGroup::Base, mPaintInfo.colBack );
444 newPal.setColor( TQColorGroup::Text, mPaintInfo.colFore );
445 setPalette( newPal );
446 mPaintInfo.colNew = config->readColorEntry(
"NewMessage",&c2);
447 mPaintInfo.colUnread = config->readColorEntry(
"UnreadMessage",&c3);
448 mPaintInfo.colFlag = config->readColorEntry(
"FlagMessage",&c5);
449 mPaintInfo.colTodo = config->readColorEntry(
"TodoMessage",&c6);
450 c7 = config->readColorEntry(
"AltBackgroundColor",&c7);
453 mPaintInfo.colFore = c1;
454 mPaintInfo.colBack = c4;
455 TQPalette newPal = kapp->palette();
456 newPal.setColor( TQColorGroup::Base, c4 );
457 newPal.setColor( TQColorGroup::Text, c1 );
458 setPalette( newPal );
459 mPaintInfo.colNew = c2;
460 mPaintInfo.colUnread = c3;
461 mPaintInfo.colFlag = c5;
462 mPaintInfo.colTodo = c6;
464 setAlternateBackground(c7);
470 TDEConfig* config = KMKernel::config();
474 TDEConfigGroupSaver saver(config,
"Pixmaps");
475 TQString pixmapFile = config->readEntry(
"Headers");
476 mPaintInfo.pixmapOn =
false;
477 if (!pixmapFile.isEmpty()) {
478 mPaintInfo.pixmapOn =
true;
479 mPaintInfo.pixmap = TQPixmap( pixmapFile );
484 TDEConfigGroupSaver saver(config,
"General");
485 bool show = config->readBoolEntry(
"showMessageSize");
488 show = config->readBoolEntry(
"showAttachmentColumn");
491 show = config->readBoolEntry(
"showInvitationColumn");
494 show = config->readBoolEntry(
"showImportantColumn");
497 show = config->readBoolEntry(
"showTodoColumn");
500 show = config->readBoolEntry(
"showSpamHamColumn");
503 show = config->readBoolEntry(
"showWatchedIgnoredColumn");
506 show = config->readBoolEntry(
"showStatusColumn");
509 show = config->readBoolEntry(
"showSignedColumn");
512 show = config->readBoolEntry(
"showCryptoColumn");
515 show = config->readBoolEntry(
"showReceiverColumn");
518 mPaintInfo.showCryptoIcons = config->readBoolEntry(
"showCryptoIcons",
false );
519 mPaintInfo.showAttachmentIcon = config->readBoolEntry(
"showAttachmentIcon",
true );
520 mPaintInfo.showInvitationIcon = config->readBoolEntry(
"showInvitationIcon",
false );
522 KMime::DateFormatter::FormatType t =
523 (KMime::DateFormatter::FormatType) config->readNumEntry(
"dateFormat", KMime::DateFormatter::Fancy ) ;
524 mDate.setCustomFormat( config->readEntry(
"customDateFormat") );
525 mDate.setFormat( t );
532 TDEConfigGroupSaver saver(config,
"Fonts");
533 if (!(config->readBoolEntry(
"defaultFonts",
true)))
535 TQFont listFont( TDEGlobalSettings::generalFont() );
536 listFont = config->readFontEntry(
"list-font", &listFont );
538 mNewFont = config->readFontEntry(
"list-new-font", &listFont );
539 mUnreadFont = config->readFontEntry(
"list-unread-font", &listFont );
540 mImportantFont = config->readFontEntry(
"list-important-font", &listFont );
541 mTodoFont = config->readFontEntry(
"list-todo-font", &listFont );
542 mDateFont = TDEGlobalSettings::fixedFont();
543 mDateFont = config->readFontEntry(
"list-date-font", &mDateFont );
545 mNewFont= mUnreadFont = mImportantFont = mDateFont = mTodoFont =
546 TDEGlobalSettings::generalFont();
547 setFont( mDateFont );
553 TDEConfigGroupSaver saver(config,
"Geometry");
554 mReaderWindowActive = config->readEntry(
"readerWindowMode",
"below" ) !=
"hide";
564 mIgnoreSortOrderChanges =
true;
565 restoreLayout( config, group );
566 mIgnoreSortOrderChanges =
false;
576 TQString colText = i18n(
"Sender" );
577 if ( mFolder && (mFolder->whoField().lower() ==
"to") && !mPaintInfo.showReceiver)
578 colText = i18n(
"Receiver" );
579 setColumnText( mPaintInfo.senderCol, colText );
585 ensureCurrentItemVisible();
592 NestingPolicy oldNestPolicy = nestingPolicy;
593 TDEConfig* config = KMKernel::config();
594 TDEConfigGroupSaver saver(config,
"Geometry");
595 mNested = config->readBoolEntry(
"nestedMessages",
false );
597 nestingPolicy = (NestingPolicy)config->readNumEntry(
"nestingPolicy", OpenUnread );
598 if ((nestingPolicy != oldNestPolicy) ||
601 setRootIsDecorated( nestingPolicy != AlwaysOpen &&
isThreaded() );
610 if (!mFolder)
return;
611 TDEConfig* config = KMKernel::config();
613 TDEConfigGroupSaver saver(config,
"Folder-" + mFolder->idString());
614 mNestedOverride = config->readBoolEntry(
"threadMessagesOverride",
false );
615 mSortCol = config->readNumEntry(
"SortColumn", mSortCol+1 );
616 mSortDescending = (mSortCol < 0);
617 mSortCol = abs(mSortCol) - 1;
619 mTopItem = config->readNumEntry(
"Top", 0);
620 mCurrentItem = config->readNumEntry(
"Current", 0);
621 mCurrentItemSerNum = config->readNumEntry(
"CurrentSerialNum", 0);
623 mPaintInfo.orderOfArrival = config->readBoolEntry(
"OrderOfArrival",
false );
624 mPaintInfo.status = config->readBoolEntry(
"Status",
false );
627 TDEConfigGroupSaver saver(config,
"Geometry");
628 mNested = config->readBoolEntry(
"nestedMessages",
false );
629 nestingPolicy = (NestingPolicy)config->readNumEntry(
"nestingPolicy", OpenUnread );
632 setRootIsDecorated( nestingPolicy != AlwaysOpen &&
isThreaded() );
633 mSubjThreading = config->readBoolEntry(
"threadMessagesBySubject",
true );
640 if (!mFolder)
return;
641 TDEConfig* config = KMKernel::config();
642 int mSortColAdj = mSortCol + 1;
644 TDEConfigGroupSaver saver(config,
"Folder-" + mFolder->idString());
645 config->writeEntry(
"SortColumn", (mSortDescending ? -mSortColAdj : mSortColAdj));
650 if ( current && mFolder->getMsgBase( current->
msgId() ) )
651 sernum = mFolder->getMsgBase( current->
msgId() )->getMsgSerNum();
652 config->writeEntry(
"CurrentSerialNum", sernum);
654 config->writeEntry(
"OrderOfArrival", mPaintInfo.orderOfArrival);
655 config->writeEntry(
"Status", mPaintInfo.status);
661 TDEConfig* config = KMKernel::config();
662 saveLayout(config,
"Header-Geometry");
663 TDEConfigGroupSaver saver(config,
"General");
664 config->writeEntry(
"showMessageSize" , mPaintInfo.showSize);
665 config->writeEntry(
"showAttachmentColumn" , mPaintInfo.showAttachment);
666 config->writeEntry(
"showInvitationColumn" , mPaintInfo.showInvitation);
667 config->writeEntry(
"showImportantColumn" , mPaintInfo.showImportant);
668 config->writeEntry(
"showTodoColumn" , mPaintInfo.showTodo);
669 config->writeEntry(
"showSpamHamColumn" , mPaintInfo.showSpamHam);
670 config->writeEntry(
"showWatchedIgnoredColumn", mPaintInfo.showWatchedIgnored);
671 config->writeEntry(
"showStatusColumn" , mPaintInfo.showStatus);
672 config->writeEntry(
"showSignedColumn" , mPaintInfo.showSigned);
673 config->writeEntry(
"showCryptoColumn" , mPaintInfo.showCrypto);
674 config->writeEntry(
"showReceiverColumn" , mPaintInfo.showReceiver);
680 CREATE_TIMER(set_folder);
681 START_TIMER(set_folder);
686 mSortInfo.fakeSort = 0;
687 if ( mFolder &&
static_cast<KMFolder*
>(mFolder) == aFolder ) {
699 highlightMessage(0,
false);
701 disconnect(mFolder, TQ_SIGNAL(numUnreadMsgsChanged(
KMFolder*)),
704 mFolder->markNewAsUnread();
708 disconnect(mFolder, TQ_SIGNAL(
msgAdded(
int)),
710 disconnect(mFolder, TQ_SIGNAL(
msgRemoved(
int, TQString ) ),
711 this, TQ_SLOT(
msgRemoved(
int, TQString ) ) );
712 disconnect(mFolder, TQ_SIGNAL(changed()),
714 disconnect(mFolder, TQ_SIGNAL(cleared()),
716 disconnect(mFolder, TQ_SIGNAL(expunged(
KMFolder* )),
718 disconnect(mFolder, TQ_SIGNAL(closed()),
720 disconnect( mFolder, TQ_SIGNAL( statusMsg(
const TQString& ) ),
721 BroadcastStatus::instance(), TQ_SLOT( setStatusMsg(
const TQString& ) ) );
722 disconnect(mFolder, TQ_SIGNAL(viewConfigChanged()),
this, TQ_SLOT(
reset()));
724 mFolder->close(
"kmheaders");
727 if (mFolder->dirty()) mFolder->writeIndex();
730 mSortInfo.removed = 0;
732 mSortInfo.dirty =
true;
734 mOwner->useAction()->setEnabled( mFolder ?
735 ( kmkernel->folderIsTemplates( mFolder ) ) :
false );
736 mOwner->messageActions()->replyListAction()->setEnabled( mFolder ?
737 mFolder->isMailingListEnabled() :
false );
741 connect(mFolder, TQ_SIGNAL(
msgAdded(
int)),
743 connect(mFolder, TQ_SIGNAL(
msgRemoved(
int,TQString)),
745 connect(mFolder, TQ_SIGNAL(changed()),
747 connect(mFolder, TQ_SIGNAL(cleared()),
749 connect(mFolder, TQ_SIGNAL(expunged(
KMFolder* )),
751 connect(mFolder, TQ_SIGNAL(closed()),
753 connect(mFolder, TQ_SIGNAL(statusMsg(
const TQString&)),
754 BroadcastStatus::instance(), TQ_SLOT( setStatusMsg(
const TQString& ) ) );
755 connect(mFolder, TQ_SIGNAL(numUnreadMsgsChanged(
KMFolder*)),
757 connect(mFolder, TQ_SIGNAL(viewConfigChanged()),
this, TQ_SLOT(
reset()));
771 CREATE_TIMER(kmfolder_open);
772 START_TIMER(kmfolder_open);
773 mFolder->open(
"kmheaders");
774 END_TIMER(kmfolder_open);
775 SHOW_TIMER(kmfolder_open);
785 CREATE_TIMER(updateMsg);
786 START_TIMER(updateMsg);
787 updateMessageList(
true, forceJumpToUnread);
788 END_TIMER(updateMsg);
789 SHOW_TIMER(updateMsg);
793 TQString colText = i18n(
"Sender" );
794 if (mFolder && (mFolder->whoField().lower() ==
"to") && !mPaintInfo.showReceiver)
795 colText = i18n(
"Receiver");
796 setColumnText( mPaintInfo.senderCol, colText);
798 colText = i18n(
"Date" );
799 if (mPaintInfo.orderOfArrival)
800 colText = i18n(
"Order of Arrival" );
801 setColumnText( mPaintInfo.dateCol, colText);
803 colText = i18n(
"Subject" );
804 if (mPaintInfo.status)
805 colText = colText + i18n(
" (Status)" );
806 setColumnText( mPaintInfo.subCol, colText);
811 END_TIMER(set_folder);
812 SHOW_TIMER(set_folder);
818 if (mFolder->count() == 0) {
823 if (!isUpdatesEnabled())
return;
828 const bool scrollbarAtTop = verticalScrollBar() &&
829 verticalScrollBar()->value() == verticalScrollBar()->minValue();
830 const bool scrollbarAtBottom = verticalScrollBar() &&
831 verticalScrollBar()->value() == verticalScrollBar()->maxValue();
832 const HeaderItem *
const oldFirstVisibleItem =
dynamic_cast<HeaderItem*
>( itemAt( TQPoint( 0, 0 ) ) );
833 const int oldOffsetOfFirstVisibleItem = itemRect( oldFirstVisibleItem ).y();
834 const uint oldSerNumOfFirstVisibleItem = oldFirstVisibleItem ? oldFirstVisibleItem->msgSerNum() : 0;
837 TQListViewItem *item = currentItem();
841 KMMsgBase *mb = mFolder->getMsgBase(hi->
msgId());
843 msgIdMD5 = mb->msgIdMD5();
847 disconnect(
this,TQ_SIGNAL(currentChanged(TQListViewItem*)),
848 this,TQ_SLOT(highlightMessage(TQListViewItem*)));
855 if ( scrollbarAtTop ) {
856 setContentsPos( 0, 0 );
857 }
else if ( scrollbarAtBottom ) {
858 setContentsPos( 0, contentsHeight() );
859 }
else if ( oldSerNumOfFirstVisibleItem > 0 ) {
860 for ( uint i = 0; i < mItems.size(); ++i ) {
861 const KMMsgBase *
const mMsgBase = mFolder->getMsgBase( i );
862 if ( mMsgBase->getMsgSerNum() == oldSerNumOfFirstVisibleItem ) {
863 setContentsPos( 0, itemPos( mItems[i] ) - oldOffsetOfFirstVisibleItem );
869 connect(
this,TQ_SIGNAL(currentChanged(TQListViewItem*)),
870 this,TQ_SLOT(highlightMessage(TQListViewItem*)));
879 item = currentItem();
882 KMMsgBase *mb = mFolder->getMsgBase(hi->
msgId());
884 if (msgIdMD5.isEmpty() || (msgIdMD5 != mb->msgIdMD5()))
898 if (!isUpdatesEnabled())
return;
903 assert( mFolder->getMsgBase(
id ) );
910 if (mSortCacheItems.count() == (uint)mFolder->count()
911 || mSortCacheItems.count() == 0) {
912 kdDebug (5006) <<
"KMHeaders::msgAdded - Resizing id and subject trees of " << mFolder->label()
913 <<
": before=" << mSortCacheItems.count() <<
" ,after=" << (mFolder->count()*2) << endl;
914 mSortCacheItems.resize(mFolder->count()*2);
915 mSubjectLists.resize(mFolder->count()*2);
917 TQString
msgId = mFolder->getMsgBase(
id)->msgIdMD5();
920 TQString
replyToId = mFolder->getMsgBase(
id)->replyToIdMD5();
923 if (!parent && mSubjThreading) {
924 parent = findParentBySubject( sci );
930 if (
msgId == mFolder->getMsgBase(parent->
item()->
msgId())->replyToIdMD5()
931 ||
msgId == mFolder->getMsgBase(parent->
item()->
msgId())->replyToAuxIdMD5())
936 if (parent && mFolder->getMsgBase(parent->id())->isWatched())
937 mFolder->getMsgBase(
id)->setStatus( KMMsgStatusWatched );
938 else if (parent && mFolder->getMsgBase(parent->id())->isIgnored())
939 mFolder->getMsgBase(
id)->setStatus( KMMsgStatusIgnored );
950 mItems.resize( mFolder->count() );
953 if ( !
msgId.isEmpty() )
954 mSortCacheItems.replace(
msgId, sci);
957 if (mSubjThreading && parent) {
958 TQString subjMD5 = mFolder->getMsgBase(
id)->strippedSubjectMD5();
959 if (subjMD5.isEmpty()) {
960 mFolder->getMsgBase(
id)->initStrippedSubjectMD5();
961 subjMD5 = mFolder->getMsgBase(
id)->strippedSubjectMD5();
963 if( !subjMD5.isEmpty()) {
964 if ( !mSubjectLists.find(subjMD5) )
965 mSubjectLists.insert(subjMD5,
new TQPtrList<SortCacheItem>());
968 for (TQPtrListIterator<SortCacheItem> it(*mSubjectLists[subjMD5]);
969 it.current(); ++it) {
970 KMMsgBase *mb = mFolder->getMsgBase((*it)->id());
971 if ( mb->date() < mFolder->getMsgBase(
id)->date())
975 mSubjectLists[subjMD5]->insert( p, sci);
985 disconnect(
this, TQ_SIGNAL(currentChanged(TQListViewItem*)),
986 this, TQ_SLOT(highlightMessage(TQListViewItem*)));
988 if ( !
msgId.isEmpty() ) {
989 TQPtrListIterator<HeaderItem> it(mImperfectlyThreadedList);
991 while ( (cur = it.current()) ) {
993 int tryMe = cur->
msgId();
997 bool perfectParent =
true;
998 KMMsgBase *otherMsg = mFolder->getMsgBase(tryMe);
1000 kdDebug(5006) <<
"otherMsg is NULL !!! tryMe: " << tryMe << endl;
1003 TQString otherId = otherMsg->replyToIdMD5();
1004 if (
msgId != otherId) {
1005 if (
msgId != otherMsg->replyToAuxIdMD5())
1008 if (!otherId.isEmpty() && mSortCacheItems.find(otherId))
1013 perfectParent =
false;
1016 TQListViewItem *newParent = mItems[
id];
1017 TQListViewItem *msg = mItems[tryMe];
1020 msg->parent()->takeItem(msg);
1023 newParent->insertItem(msg);
1029 if (perfectParent) {
1030 mImperfectlyThreadedList.removeRef (mItems[tryMe]);
1033 TQString sortFile = KMAIL_SORT_FILE(mFolder);
1034 FILE *sortStream = fopen(TQFile::encodeName(sortFile),
"r+");
1036 mItems[tryMe]->sortCacheItem()->updateSortFile( sortStream, mFolder );
1037 fclose (sortStream);
1044 mImperfectlyThreadedList.append(hi);
1048 mItems.resize( mFolder->count() );
1054 if (mSortInfo.fakeSort) {
1055 TQObject::disconnect(header(), TQ_SIGNAL(clicked(
int)),
this, TQ_SLOT(
dirtySortOrder(
int)));
1056 TDEListView::setSorting(mSortCol, !mSortDescending );
1057 mSortInfo.fakeSort = 0;
1059 appendItemToSortFile(hi);
1063 if ((childCount() == 1) && hi) {
1065 setCurrentItem( firstChild() );
1066 setSelectionAnchor( currentItem() );
1067 highlightMessage( currentItem() );
1071 connect(
this, TQ_SIGNAL(currentChanged(TQListViewItem*)),
1072 this, TQ_SLOT(highlightMessage(TQListViewItem*)));
1083 if (!isUpdatesEnabled())
return;
1085 if ((
id < 0) || (
id >= (
int)mItems.size()))
1092 disconnect(
this, TQ_SIGNAL(currentChanged(TQListViewItem*)),
1093 this, TQ_SLOT(highlightMessage(TQListViewItem*)));
1096 if (!removedItem)
return;
1099 for (
int i =
id; i < (int)mItems.size() - 1; ++i) {
1100 mItems[i] = mItems[i+1];
1101 mItems[i]->setMsgId( i );
1102 mItems[i]->sortCacheItem()->setId( i );
1105 mItems.resize( mItems.size() - 1 );
1108 if ( !
msgId.isEmpty() && mSortCacheItems[
msgId] ) {
1110 mSortCacheItems.remove(
msgId);
1118 TQListViewItem *myParent = removedItem;
1119 TQListViewItem *myChild = myParent->firstChild();
1120 TQListViewItem *threadRoot = myParent;
1121 while (threadRoot->parent())
1122 threadRoot = threadRoot->parent();
1123 TQString key =
static_cast<HeaderItem*
>(threadRoot)->key(mSortCol, !mSortDescending);
1125 TQPtrList<TQListViewItem> childList;
1130 childList.append(myChild);
1132 myChild = myChild->nextSibling();
1134 myParent->takeItem( item );
1138 item->setTempKey( key + item->key( mSortCol, !mSortDescending ));
1139 if (mSortInfo.fakeSort) {
1140 TQObject::disconnect(header(), TQ_SIGNAL(clicked(
int)),
this, TQ_SLOT(
dirtySortOrder(
int)));
1141 TDEListView::setSorting(mSortCol, !mSortDescending );
1142 mSortInfo.fakeSort = 0;
1146 for (TQPtrListIterator<TQListViewItem> it(childList); it.current() ; ++it ) {
1147 TQListViewItem *lvi = *it;
1151 if ( !parent && mSubjThreading )
1152 parent = findParentBySubject( sci );
1154 Q_ASSERT( !parent || parent->
item() != removedItem );
1155 myParent->takeItem(lvi);
1156 if ( parent && parent->
item() != item && parent->
item() != removedItem ) {
1157 parent->
item()->insertItem(lvi);
1165 && !mImperfectlyThreadedList.containsRef(item))
1166 mImperfectlyThreadedList.append(item);
1169 && mImperfectlyThreadedList.containsRef(item))
1170 mImperfectlyThreadedList.removeRef(item);
1174 if (!mFolder->count())
1177 mImperfectlyThreadedList.removeRef( removedItem );
1180 while ( mImperfectlyThreadedList.findRef( removedItem ) != -1 ) {
1181 mImperfectlyThreadedList.remove();
1182 kdDebug(5006) <<
"Remove doubled item from mImperfectlyThreadedList: " << removedItem << endl;
1188 if ( curItem != removedItem ) {
1189 setCurrentItem( curItem );
1190 setSelectionAnchor( currentItem() );
1198 int contentX, contentY;
1199 HeaderItem *nextItem = prepareMove( &contentX, &contentY );
1200 finalizeMove( nextItem, contentX, contentY );
1204 connect(
this, TQ_SIGNAL(currentChanged(TQListViewItem*)),
1205 this, TQ_SLOT(highlightMessage(TQListViewItem*)));
1212 if (msgId<0 || msgId >= (
int)mItems.size() || !isUpdatesEnabled())
return;
1226 if (serNums.empty())
1229 KMCommand *command =
new KMSeStatusCommand(
status, serNums, toggle );
1236 if (!mFolder)
return TQPtrList<TQListViewItem>();
1239 TQListViewItem *curItem = currentItem();
1240 if (!curItem)
return TQPtrList<TQListViewItem>();
1243 TQListViewItem *topOfThread = curItem;
1244 while ( topOfThread->parent() )
1245 topOfThread = topOfThread->parent();
1248 TQPtrList<TQListViewItem> list;
1249 TQListViewItem *topOfNextThread = topOfThread->nextSibling();
1250 for ( TQListViewItemIterator it( topOfThread ) ;
1251 it.current() && it.current() != topOfNextThread ; ++it )
1252 list.append( it.current() );
1258 TQPtrList<TQListViewItem> curThread;
1261 TQPtrList<TQListViewItem> topOfThreads;
1264 for (TQListViewItem *item = firstChild(); item; item = item->itemBelow())
1265 if (item->isSelected() ) {
1267 TQListViewItem *top = item;
1268 while ( top->parent() )
1269 top = top->parent();
1270 if (!topOfThreads.contains(top)) {
1271 topOfThreads.append(top);
1276 for ( TQPtrListIterator<TQListViewItem> it( topOfThreads ) ;
1277 it.current() ; ++ it ) {
1278 TQListViewItem *top = *it;
1281 TQListViewItem *topOfNextThread = top->nextSibling();
1282 for ( TQListViewItemIterator it( top ) ;
1283 it.current() && it.current() != topOfNextThread ; ++it )
1284 curThread.append( it.current() );
1288 TQPtrListIterator<TQListViewItem> it( curThread );
1291 for ( it.toFirst() ; it.current() ; ++it ) {
1293 KMMsgBase *msgBase = mFolder->getMsgBase(
id );
1294 serNums.append( msgBase->getMsgSerNum() );
1297 if (serNums.empty())
1300 KMCommand *command =
new KMSeStatusCommand(
status, serNums, toggle );
1307 if ( !msg )
return 2;
1309 int filterResult = kmkernel->filterMgr()->process(msg,KMFilterMgr::Explicit);
1310 if (filterResult == 2) {
1312 kmkernel->emergencyExit( i18n(
"Unable to process messages: " ) + TQString::fromLocal8Bit(strerror(errno)));
1315 if (msg->parent()) {
1319 assert( p == msg->parent() ); assert( idx >= 0 );
1323 return filterResult;
1331 TQListViewItem *item = currentItem();
1332 if ( !item )
return;
1334 item->setSelected(
true );
1335 while ( item->parent() )
1336 item = item->parent();
1341 ensureItemVisible( currentItem() );
1348 TQListViewItem * item = currentItem();
1351 item->setSelected(
true );
1354 for ( TQListViewItem *item = firstChild() ;
1355 item ; item = item->nextSibling() )
1356 static_cast<HeaderItem*
>(item)->setOpenRecursive( expand );
1358 TQListViewItem * item = currentItem();
1360 while ( item->parent() )
1361 item = item->parent();
1365 ensureItemVisible( currentItem() );
1373 if( style().isA(
"KeramikStyle") )
1374 frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth ) - 1;
1376 frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth );
1377 if ( frameWidth < 0 )
1379 if ( frameWidth != lineWidth() )
1380 setLineWidth( frameWidth );
1387 TDEListView::styleChange( oldStyle );
1393 if ( !mFolder )
return;
1395 const int unread = mFolder->countUnread();
1396 if (
static_cast<KMFolder*
>(mFolder) == kmkernel->outboxFolder() )
1397 str = unread ? i18n(
"1 unsent",
"%n unsent", unread ) : i18n(
"0 unsent" );
1399 str = unread ? i18n(
"1 unread",
"%n unread", unread ) : i18n(
"0 unread" );
1400 const int count = mFolder->count();
1401 str = count ? i18n(
"1 message, %1.",
"%n messages, %1.", count ).arg( str )
1402 : i18n(
"0 messages" );
1403 if ( mFolder->isReadOnly() )
1404 str = i18n(
"%1 = n messages, m unread.",
"%1 Folder is read-only.").arg( str );
1405 BroadcastStatus::instance()->setStatusMsg(str);
1409 void KMHeaders::applyFiltersOnMsg()
1411 if (ActionScheduler::isEnabled() ||
1412 kmkernel->filterMgr()->atLeastOneOnlineImapFolderTarget()) {
1414 KMFilterMgr::FilterSet set = KMFilterMgr::Explicit;
1415 TQValueList<KMFilter*> filters = kmkernel->filterMgr()->filters();
1416 ActionScheduler *scheduler =
new ActionScheduler( set, filters,
this );
1417 scheduler->setAutoDestruct(
true );
1419 int contentX, contentY;
1420 HeaderItem *nextItem = prepareMove( &contentX, &contentY );
1422 finalizeMove( nextItem, contentX, contentY );
1424 for (KMMsgBase *msg = msgList.first(); msg; msg = msgList.next())
1425 scheduler->execFilters( msg );
1427 int contentX, contentY;
1428 HeaderItem *nextItem = prepareMove( &contentX, &contentY );
1432 if ( serNums.isEmpty() )
1435 finalizeMove( nextItem, contentX, contentY );
1436 CREATE_TIMER(filter);
1437 START_TIMER(filter);
1441 int msgCountToFilter = serNums.count();
1442 ProgressItem* progressItem =
1443 ProgressManager::createProgressItem(
"filter"+ProgressManager::getUniqueID(),
1444 i18n(
"Filtering messages" ) );
1445 progressItem->setTotalItems( msgCountToFilter );
1447 for ( TQValueList<unsigned long>::ConstIterator it = serNums.constBegin();
1448 it != serNums.constEnd(); ++it ) {
1450 if ( msgCountToFilter - msgCount < 10 || !( msgCount % 20 ) || msgCount <= 10 ) {
1451 progressItem->updateProgress();
1452 TQString statusMsg = i18n(
"Filtering message %1 of %2");
1453 statusMsg = statusMsg.arg( msgCount ).arg( msgCountToFilter );
1454 KPIM::BroadcastStatus::instance()->setStatusMsg( statusMsg );
1455 TDEApplication::kApplication()->eventLoop()->processEvents( TQEventLoop::ExcludeUserInput, 50 );
1469 FolderJob *job = mFolder->createJob(msg);
1470 connect(job, TQ_SIGNAL(messageRetrieved(
KMMessage*)),
1478 kdDebug (5006) <<
"####### KMHeaders::applyFiltersOnMsg -"
1479 " A message went missing during filtering " << endl;
1481 progressItem->incCompletedItems();
1483 progressItem->setComplete();
1492 void KMHeaders::setMsgRead (
int msgId)
1494 KMMsgBase *msgBase = mFolder->getMsgBase(
msgId );
1499 if (msgBase->isNew() || msgBase->isUnread()) {
1500 serNums.append( msgBase->getMsgSerNum() );
1503 KMCommand *command =
new KMSeStatusCommand( KMMsgStatusRead, serNums );
1509 void KMHeaders::deleteMsg ()
1515 int contentX, contentY;
1516 HeaderItem *nextItem = prepareMove( &contentX, &contentY );
1518 finalizeMove( nextItem, contentX, contentY );
1520 KMCommand *command =
new KMDeleteMsgCommand( mFolder, msgList );
1521 connect( command, TQ_SIGNAL( completed( KMCommand * ) ),
1522 this, TQ_SLOT( slotMoveCompleted( KMCommand * ) ) );
1525 BroadcastStatus::instance()->setStatusMsg(
"");
1533 if (mMenuToFolder[menuId])
1538 HeaderItem* KMHeaders::prepareMove(
int *contentX,
int *contentY )
1543 disconnect(
this, TQ_SIGNAL(currentChanged(TQListViewItem*)),
1544 this, TQ_SLOT(highlightMessage(TQListViewItem*)));
1546 TQListViewItem *curItem;
1548 curItem = currentItem();
1549 while (curItem && curItem->isSelected() && curItem->itemBelow())
1550 curItem = curItem->itemBelow();
1551 while (curItem && curItem->isSelected() && curItem->itemAbove())
1552 curItem = curItem->itemAbove();
1555 *contentX = contentsX();
1556 *contentY = contentsY();
1558 if (item && !item->isSelected())
1565 void KMHeaders::finalizeMove(
HeaderItem *item,
int contentX,
int contentY )
1571 setCurrentItem( item );
1573 setSelectionAnchor( currentItem() );
1575 highlightMessage( item,
false);
1578 setContentsPos( contentX, contentY );
1580 connect(
this, TQ_SIGNAL(currentChanged(TQListViewItem*)),
1581 this, TQ_SLOT(highlightMessage(TQListViewItem*)));
1588 if ( destFolder == mFolder )
return;
1589 if ( mFolder->isReadOnly() )
return;
1592 if ( msgList.isEmpty() )
return;
1593 if ( !destFolder && askForConfirmation &&
1594 KMessageBox::warningContinueCancel(
this,
1595 i18n(
"<qt>Do you really want to delete the selected message?<br>"
1596 "Once deleted, it cannot be restored.</qt>",
1597 "<qt>Do you really want to delete the %n selected messages?<br>"
1598 "Once deleted, they cannot be restored.</qt>", msgList.count() ),
1599 msgList.count()>1 ? i18n(
"Delete Messages") : i18n(
"Delete Message"), KStdGuiItem::del(),
1600 "NoConfirmDelete") == KMessageBox::Cancel )
1604 int contentX, contentY;
1605 HeaderItem *nextItem = prepareMove( &contentX, &contentY );
1607 finalizeMove( nextItem, contentX, contentY );
1609 KMCommand *command =
new KMMoveCommand( destFolder, msgList );
1610 connect( command, TQ_SIGNAL( completed( KMCommand * ) ),
1611 this, TQ_SLOT( slotMoveCompleted( KMCommand * ) ) );
1615 void KMHeaders::slotMoveCompleted( KMCommand *command )
1617 kdDebug(5006) << k_funcinfo << command->result() << endl;
1618 bool deleted =
static_cast<KMMoveCommand *
>( command )->destFolder() == 0;
1619 if ( command->result() == KMCommand::OK ) {
1622 BroadcastStatus::instance()->setStatusMsg(
1623 deleted ? i18n(
"Messages deleted successfully.") : i18n(
"Messages moved successfully") );
1631 for (TQListViewItemIterator it(
this); it.current(); it++) {
1635 item->setSelectable (
true );
1636 KMMsgBase *msgBase = mFolder->getMsgBase(item->
msgId());
1637 if ( msgBase->isMessage() ) {
1644 if ( command->result() == KMCommand::Failed )
1645 BroadcastStatus::instance()->setStatusMsg(
1646 deleted ? i18n(
"Deleting messages failed.") : i18n(
"Moving messages failed.") );
1648 BroadcastStatus::instance()->setStatusMsg(
1649 deleted ? i18n(
"Deleting messages canceled.") : i18n(
"Moving messages canceled.") );
1651 mOwner->updateMessageActions();
1654 bool KMHeaders::canUndo()
const
1656 return ( kmkernel->undoStack()->size() > 0 );
1660 void KMHeaders::undo()
1662 kmkernel->undoStack()->undo();
1668 if (mMenuToFolder[menuId])
1679 KMCommand * command = 0;
1681 command =
new KMCopyCommand( destFolder, aMsg );
1684 command =
new KMCopyCommand( destFolder, msgList );
1694 if (!mFolder)
return;
1695 if (cur >= mFolder->count()) cur = mFolder->count() - 1;
1696 if ((cur >= 0) && (cur < (
int)mItems.size())) {
1698 setCurrentItem( mItems[cur] );
1700 setSelectionAnchor( currentItem() );
1712 if ( item->isVisible() )
1713 TDEListView::setSelected( item,
selected );
1717 if (
isThreaded() && !item->isOpen() && item->firstChild() ) {
1718 TQListViewItem *nextRoot = item->itemBelow();
1719 TQListViewItemIterator it( item->firstChild() );
1720 for( ; (*it) != nextRoot; ++it ) {
1721 if ( (*it)->isVisible() )
1729 for ( TQValueList<int>::Iterator it = items.begin(); it != items.end(); ++it )
1731 if ( ((*it) >= 0) && ((*it) < (
int)mItems.size()) )
1741 for (TQListViewItemIterator it(
this); it.current(); it++) {
1744 KMMsgBase *msgBase = mFolder->getMsgBase( item->
msgId() );
1745 if ( serNum == msgBase->getMsgSerNum() ) {
1747 item->setSelectable (
true );
1757 mSelMsgBaseList.clear();
1758 for (TQListViewItemIterator it(
this); it.current(); it++) {
1759 if ( it.current()->isSelected() && it.current()->isVisible() ) {
1765 item->setSelectable (
false );
1767 KMMsgBase *msgBase = mFolder->getMsgBase(item->
msgId());
1768 mSelMsgBaseList.append(msgBase);
1772 return &mSelMsgBaseList;
1778 TQValueList<int> items;
1779 for ( TQListViewItemIterator it(
this); it.current(); it++ )
1781 if ( it.current()->isSelected() && it.current()->isVisible() )
1784 items.append( item->
msgId() );
1793 int selectedMsg = -1;
1794 TQListViewItem *item;
1795 for (item = firstChild(); item; item = item->itemBelow())
1796 if (item->isSelected()) {
1806 TQListViewItem *lvi = currentItem();
1807 if (lvi && lvi->itemBelow()) {
1811 setSelectionAnchor( currentItem() );
1812 ensureCurrentItemVisible();
1819 if ( cm && cm->isBeingParsed() )
1821 TQListViewItem *lvi = currentItem();
1823 TQListViewItem *below = lvi->itemBelow();
1824 TQListViewItem *temp = lvi;
1825 if (lvi && below ) {
1828 temp = temp->parent();
1833 setCurrentItem(below);
1843 TQListViewItem *lvi = currentItem();
1844 if (lvi && lvi->itemAbove()) {
1848 setSelectionAnchor( currentItem() );
1849 ensureCurrentItemVisible();
1856 if ( cm && cm->isBeingParsed() )
1858 TQListViewItem *lvi = currentItem();
1860 TQListViewItem *above = lvi->itemAbove();
1861 TQListViewItem *temp = lvi;
1866 temp = temp->parent();
1871 setCurrentItem(above);
1882 if ( cm && cm->isBeingParsed() )
1884 TQListViewItem *lvi = currentItem();
1885 if ( lvi && lvi->itemBelow() ) {
1887 disconnect(
this,TQ_SIGNAL(currentChanged(TQListViewItem*)),
1888 this,TQ_SLOT(highlightMessage(TQListViewItem*)));
1889 setCurrentItem( lvi->itemBelow() );
1890 ensureCurrentItemVisible();
1892 connect(
this,TQ_SIGNAL(currentChanged(TQListViewItem*)),
1893 this,TQ_SLOT(highlightMessage(TQListViewItem*)));
1900 if ( cm && cm->isBeingParsed() )
1902 TQListViewItem *lvi = currentItem();
1903 if ( lvi && lvi->itemAbove() ) {
1904 disconnect(
this,TQ_SIGNAL(currentChanged(TQListViewItem*)),
1905 this,TQ_SLOT(highlightMessage(TQListViewItem*)));
1906 setCurrentItem( lvi->itemAbove() );
1907 ensureCurrentItemVisible();
1909 connect(
this,TQ_SIGNAL(currentChanged(TQListViewItem*)),
1910 this,TQ_SLOT(highlightMessage(TQListViewItem*)));
1917 highlightMessage( currentItem() );
1922 bool & foundUnreadMessage,
1926 KMMsgBase* msgBase = 0;
1932 msgBase = mFolder->getMsgBase(item->
msgId());
1933 if (!msgBase)
continue;
1934 if (msgBase->isUnread() || msgBase->isNew())
1935 foundUnreadMessage =
true;
1937 if (!onlyNew && (msgBase->isUnread() || msgBase->isNew()))
break;
1938 if (onlyNew && msgBase->isNew())
break;
1939 item =
static_cast<HeaderItem*
>(item->itemBelow());
1945 msgBase = mFolder->getMsgBase(newItem->
msgId());
1946 if (!msgBase)
continue;
1947 if (msgBase->isUnread() || msgBase->isNew())
1948 foundUnreadMessage =
true;
1949 if ( ( !onlyNew && (msgBase->isUnread() || msgBase->isNew()) )
1950 || ( onlyNew && msgBase->isNew() ) )
1951 lastUnread = newItem;
1952 if (newItem == item)
break;
1953 newItem =
static_cast<HeaderItem*
>(newItem->itemBelow());
1963 bool foundUnreadMessage =
false;
1965 if (!mFolder)
return -1;
1966 if (mFolder->count() <= 0)
return -1;
1968 if ((aStartAt >= 0) && (aStartAt < (
int)mItems.size()))
1969 item = mItems[aStartAt];
1974 item =
static_cast<HeaderItem*
>(firstChild());
1976 item =
static_cast<HeaderItem*
>(lastChild());
1981 if ( !acceptCurrent ) {
1983 item =
static_cast<HeaderItem*
>(item->itemBelow());
1986 item =
static_cast<HeaderItem*
>(item->itemAbove());
1993 findUnreadAux( item, foundUnreadMessage, onlyNew, aDirNext );
2001 TQListViewItem *next = item;
2002 while (next->parent())
2003 next = next->parent();
2004 next =
static_cast<HeaderItem*
>(next)->firstChildNonConst();
2005 while (next && (next != item))
2006 if (
static_cast<HeaderItem*
>(next)->firstChildNonConst())
2007 next = next->firstChild();
2008 else if (next->nextSibling())
2009 next = next->nextSibling();
2011 while (next && (next != item)) {
2012 next = next->parent();
2015 if (next && next->nextSibling()) {
2016 next = next->nextSibling();
2025 findUnreadAux( item, foundUnreadMessage, onlyNew, aDirNext );
2027 return item->
msgId();
2031 int unread = mFolder->countUnread();
2032 if (((unread == 0) && foundUnreadMessage) ||
2033 ((unread > 0) && !foundUnreadMessage)) {
2034 mFolder->correctUnreadMsgsCount();
2042 if ( !mFolder || !mFolder->countUnread() )
return false;
2043 int i =
findUnread(
true, -1,
false, acceptCurrent);
2044 if ( i < 0 && GlobalSettings::self()->loopOnGotoUnread() !=
2045 GlobalSettings::EnumLoopOnGotoUnread::DontLoop )
2054 ensureCurrentItemVisible();
2058 void KMHeaders::ensureCurrentItemVisible()
2061 if ((i >= 0) && (i < (
int)mItems.size()))
2062 center( contentsX(), itemPos(mItems[i]), 0, 9.0 );
2068 if ( !mFolder || !mFolder->countUnread() )
return false;
2070 if ( i < 0 && GlobalSettings::self()->loopOnGotoUnread() !=
2071 GlobalSettings::EnumLoopOnGotoUnread::DontLoop )
2080 ensureCurrentItemVisible();
2101 ensureItemVisible( currentItem() );
2105 void KMHeaders::highlightMessage(TQListViewItem* lvi,
bool markitread)
2108 if (lvi && !lvi->isSelectable())
return;
2111 if (lvi != mPrevCurrent) {
2112 if (mPrevCurrent && mFolder)
2115 if (prevMsg && mReaderWindowActive)
2117 mFolder->ignoreJobsForMessage(prevMsg);
2119 mFolder->unGetMsg(mPrevCurrent->
msgId());
2122 mPrevCurrent = item;
2129 int idx = item->
msgId();
2131 if (mReaderWindowActive && !msg) {
2137 BroadcastStatus::instance()->setStatusMsg(
"");
2138 if (markitread && idx >= 0) setMsgRead(idx);
2139 mItems[idx]->irefresh();
2140 mItems[idx]->repaint();
2145 void KMHeaders::highlightCurrentThread()
2148 TQPtrListIterator<TQListViewItem> it( curThread );
2150 for ( it.toFirst() ; it.current() ; ++it ) {
2151 TQListViewItem *lvi = *it;
2152 lvi->setSelected(
true );
2161 TQTimer::singleShot( ( 60-TQTime::currentTime().second() ) * 1000,
2172 int idx = item->
msgId();
2185 void KMHeaders::updateMessageList(
bool set_selection,
bool forceJumpToUnread )
2192 TDEListView::setSorting( mSortCol, !mSortDescending );
2197 readSortOrder( set_selection, forceJumpToUnread );
2218 void KMHeaders::keyPressEvent( TQKeyEvent * e )
2220 bool cntrl = (e->state() & ControlButton );
2221 bool shft = (e->state() & ShiftButton );
2222 TQListViewItem *cur = currentItem();
2224 if (!e || !firstChild())
2229 setCurrentItem( firstChild() );
2230 setSelectionAnchor( currentItem() );
2235 if (cur->isSelectable() && e->ascii() ==
' ' ) {
2237 highlightMessage( cur,
false);
2243 disconnect(
this,TQ_SIGNAL(currentChanged(TQListViewItem*)),
2244 this,TQ_SLOT(highlightMessage(TQListViewItem*)));
2253 TDEListView::keyPressEvent( e );
2256 connect(
this,TQ_SIGNAL(currentChanged(TQListViewItem*)),
2257 this,TQ_SLOT(highlightMessage(TQListViewItem*)));
2268 if (!(lvi->isSelected())) {
2278 mPressPos = e->pos();
2279 TQListViewItem *lvi = itemAt( contentsToViewport( e->pos() ));
2280 bool wasSelected =
false;
2281 bool rootDecoClicked =
false;
2283 wasSelected = lvi->isSelected();
2285 ( mPressPos.x() <= header()->cellPos( header()->mapToActual( 0 ) ) +
2286 treeStepSize() * ( lvi->depth() + ( rootIsDecorated() ? 1 : 0 ) ) + itemMargin() )
2287 && ( mPressPos.x() >= header()->cellPos( header()->mapToActual( 0 ) ) );
2289 if ( rootDecoClicked ) {
2294 if ( !lvi->isOpen() && lvi->firstChild() ) {
2295 TQListViewItem *nextRoot = lvi->itemBelow();
2296 TQListViewItemIterator it( lvi->firstChild() );
2297 for( ; (*it) != nextRoot; ++it )
2298 (*it)->setSelected(
false );
2304 TDEListView::contentsMousePressEvent(e);
2308 if ( e->state() & ShiftButton ) {
2309 TQListViewItemIterator it(
this, TQListViewItemIterator::Invisible );
2310 while ( it.current() ) {
2311 it.current()->setSelected(
false );
2316 if ( rootDecoClicked ) {
2318 if ( lvi && !lvi->isOpen() && lvi->isSelected() )
2322 if ( lvi && !rootDecoClicked ) {
2323 if ( lvi != currentItem() )
2324 highlightMessage( lvi );
2329 if ( !( e->state() & ControlButton ) && !wasSelected )
2332 if ( e->state() & ControlButton )
2335 if ((e->button() == TQt::LeftButton) )
2336 mMousePressed =
true;
2340 if ( lvi && e->button() == TQt::LeftButton && !( e->state() & (ShiftButton | ControlButton | AltButton | MetaButton) ) ) {
2341 bool flagsToggleable = GlobalSettings::self()->allowLocalFlags() || !(mFolder ? mFolder->isReadOnly() :
true);
2342 int section = header()->sectionAt( e->pos().x() );
2344 KMMsgBase *msg = mFolder->getMsgBase(item->
msgId());
2345 if ( section == mPaintInfo.flagCol && flagsToggleable ) {
2347 }
else if ( section == mPaintInfo.importantCol && flagsToggleable ) {
2349 }
else if ( section == mPaintInfo.todoCol && flagsToggleable ) {
2351 }
else if ( section == mPaintInfo.watchedIgnoredCol && flagsToggleable ) {
2352 if ( msg->isWatched() || msg->isIgnored() )
2356 }
else if ( section == mPaintInfo.statusCol ) {
2357 if ( msg->isUnread() || msg->isNew() )
2366 void KMHeaders::contentsMouseReleaseEvent(TQMouseEvent* e)
2368 if (e->button() != TQt::RightButton)
2369 TDEListView::contentsMouseReleaseEvent(e);
2371 mMousePressed =
false;
2377 if (mMousePressed &&
2378 (e->pos() - mPressPos).manhattanLength() > TDEGlobalSettings::dndEventDelay()) {
2379 mMousePressed =
false;
2380 TQListViewItem *item = itemAt( contentsToViewport(mPressPos) );
2383 unsigned int count = 0;
2384 for( TQListViewItemIterator it(
this); it.current(); it++ )
2385 if( it.current()->isSelected() ) {
2387 KMMsgBase *msg = mFolder->getMsgBase(item->
msgId());
2390 MailSummary mailSummary( msg->getMsgSerNum(), msg->msgIdMD5(),
2391 msg->subject(), msg->fromStrip(),
2392 msg->toStrip(), msg->date() );
2393 mailList.append( mailSummary );
2396 MailListDrag *d =
new MailListDrag( mailList, viewport(),
new KMTextSource );
2401 pixmap = TQPixmap( DesktopIcon(
"message", TDEIcon::SizeSmall) );
2403 pixmap = TQPixmap( DesktopIcon(
"application-vnd.tde.tdemultiple", TDEIcon::SizeSmall) );
2406 if( !pixmap.isNull() ) {
2407 TQPoint hotspot( pixmap.width() / 2, pixmap.height() / 2 );
2408 d->setPixmap( pixmap, hotspot );
2410 if ( mFolder->isReadOnly() )
2418 void KMHeaders::highlightMessage(TQListViewItem* i)
2420 highlightMessage( i,
false );
2426 if (!topLevelWidget())
return;
2427 mOwner->updateMessageActions();
2430 TQListViewItem *item = itemAt( viewport()->mapFromGlobal( TQCursor::pos() ) );
2432 int section = header()->sectionAt( viewportToContents( viewport()->mapFromGlobal( TQCursor::pos() ) ).x() );
2433 if ( section == mPaintInfo.flagCol || section == mPaintInfo.importantCol
2434 || section == mPaintInfo.todoCol || section == mPaintInfo.statusCol ) {
2435 mOwner->statusMenu()->popup( TQCursor::pos() );
2438 if ( section == mPaintInfo.watchedIgnoredCol ) {
2439 mOwner->threadStatusMenu()->popup( TQCursor::pos() );
2444 TQPopupMenu *menu =
new TQPopupMenu(
this);
2446 mMenuToFolder.clear();
2448 mOwner->updateMessageMenu();
2450 bool out_folder = kmkernel->folderIsDraftOrOutbox( mFolder );
2451 bool tem_folder = kmkernel->folderIsTemplates( mFolder );
2453 mOwner->useAction()->plug( menu );
2456 mOwner->messageActions()->replyMenu()->plug( menu );
2457 mOwner->forwardMenu()->plug( menu );
2458 if( mOwner->sendAgainAction()->isEnabled() ) {
2459 mOwner->sendAgainAction()->plug( menu );
2461 mOwner->editAction()->plug( menu );
2464 menu->insertSeparator();
2466 TQPopupMenu *msgCopyMenu =
new TQPopupMenu(menu);
2467 mOwner->folderTree()->folderToPopupMenu( KMFolderTree::CopyMessage,
this,
2468 &mMenuToFolder, msgCopyMenu );
2469 menu->insertItem(i18n(
"&Copy To"), msgCopyMenu);
2471 if ( !mFolder->canDeleteMessages() ) {
2472 int id = menu->insertItem( i18n(
"&Move To") );
2473 menu->setItemEnabled(
id,
false );
2475 TQPopupMenu *msgMoveMenu =
new TQPopupMenu(menu);
2476 mOwner->folderTree()->folderToPopupMenu( KMFolderTree::MoveMessage,
this,
2477 &mMenuToFolder, msgMoveMenu );
2478 menu->insertItem(i18n(
"&Move To"), msgMoveMenu);
2480 menu->insertSeparator();
2481 mOwner->statusMenu()->plug( menu );
2482 if ( mOwner->threadStatusMenu()->isEnabled() ) {
2483 mOwner->threadStatusMenu()->plug( menu );
2486 if ( !out_folder && !tem_folder ) {
2487 menu->insertSeparator();
2488 mOwner->filterMenu()->plug( menu );
2489 mOwner->action(
"apply_filter_actions" )->plug( menu );
2492 menu->insertSeparator();
2493 mOwner->printAction()->plug(menu);
2494 mOwner->saveAsAction()->plug(menu);
2495 mOwner->saveAttachmentsAction()->plug(menu);
2496 menu->insertSeparator();
2497 if ( mFolder->isTrash() ) {
2498 mOwner->deleteAction()->plug(menu);
2499 if ( mOwner->trashThreadAction()->isEnabled() )
2500 mOwner->deleteThreadAction()->plug(menu);
2502 mOwner->trashAction()->plug(menu);
2503 if ( mOwner->trashThreadAction()->isEnabled() )
2504 mOwner->trashThreadAction()->plug(menu);
2506 menu->insertSeparator();
2507 mOwner->messageActions()->createTodoAction()->plug( menu );
2509 TDEAcceleratorManager::manage(menu);
2510 kmkernel->setContextMenuShown(
true );
2511 menu->exec(TQCursor::pos(), 0);
2512 kmkernel->setContextMenuShown(
false );
2523 return mFolder->getMsg(hi->
msgId());
2529 return static_cast<HeaderItem*
>(currentItem());
2537 return item->
msgId();
2545 if (!mFolder->isOpened())
setFolder(mFolder);
2547 if ((msgIdx >= 0) && (msgIdx < (
int)mItems.size())) {
2549 bool unchanged = (currentItem() == mItems[msgIdx]);
2550 setCurrentItem( mItems[msgIdx] );
2552 setSelectionAnchor( currentItem() );
2554 highlightMessage( mItems[msgIdx],
false);
2564 return item->
msgId();
2572 if ( aMsgIdx < 0 ||
static_cast<unsigned int>( aMsgIdx ) >= mItems.size() )
2574 const TQListViewItem *
const item = mItems[aMsgIdx];
2576 setContentsPos( 0, itemPos( item ) );
2580 void KMHeaders::setNestedOverride(
bool override )
2582 mSortInfo.dirty =
true;
2583 mNestedOverride =
override;
2584 setRootIsDecorated( nestingPolicy != AlwaysOpen
2586 TQString sortFile = mFolder->indexLocation() +
".sorted";
2587 unlink(TQFile::encodeName(sortFile));
2592 void KMHeaders::setSubjectThreading(
bool aSubjThreading )
2594 mSortInfo.dirty =
true;
2595 mSubjThreading = aSubjThreading;
2596 TQString sortFile = mFolder->indexLocation() +
".sorted";
2597 unlink(TQFile::encodeName(sortFile));
2604 if ((nestingPolicy != AlwaysOpen)|| open)
2605 ((
HeaderItem*)item)->setOpenRecursive( open );
2612 return mFolder->getMsgBase( hi->
msgId() );
2618 if ( mIgnoreSortOrderChanges )
2625 if(mSortInfo.dirty || column != mSortInfo.column || ascending != mSortInfo.ascending) {
2626 TQObject::disconnect(header(), TQ_SIGNAL(clicked(
int)),
this, TQ_SLOT(
dirtySortOrder(
int)));
2627 mSortInfo.dirty =
true;
2630 assert(column >= 0);
2632 mSortDescending = !ascending;
2634 if (!ascending && (column == mPaintInfo.dateCol))
2635 mPaintInfo.orderOfArrival = !mPaintInfo.orderOfArrival;
2637 if (!ascending && (column == mPaintInfo.subCol))
2638 mPaintInfo.status = !mPaintInfo.status;
2640 TQString colText = i18n(
"Date" );
2641 if (mPaintInfo.orderOfArrival)
2642 colText = i18n(
"Order of Arrival" );
2643 setColumnText( mPaintInfo.dateCol, colText);
2645 colText = i18n(
"Subject" );
2646 if (mPaintInfo.status)
2647 colText = colText + i18n(
" (Status)" );
2648 setColumnText( mPaintInfo.subCol, colText);
2650 TDEListView::setSorting( column, ascending );
2651 ensureCurrentItemVisible();
2661 static void internalWriteItem(FILE *sortStream,
KMFolder *folder,
int msgid,
2662 int parent_id, TQString key,
2663 bool update_discover=
true)
2665 unsigned long msgSerNum;
2666 unsigned long parentSerNum;
2671 parentSerNum = (
unsigned long)(parent_id + KMAIL_RESERVED);
2673 fwrite(&msgSerNum,
sizeof(msgSerNum), 1, sortStream);
2674 fwrite(&parentSerNum,
sizeof(parentSerNum), 1, sortStream);
2675 TQ_INT32 len = key.length() *
sizeof(TQChar);
2676 fwrite(&len,
sizeof(len), 1, sortStream);
2678 fwrite(key.unicode(), TQMIN(len, KMAIL_MAX_KEY_LEN), 1, sortStream);
2680 if (update_discover) {
2682 TQ_INT32 discovered_count = 0;
2683 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 20, SEEK_SET);
2684 fread(&discovered_count,
sizeof(discovered_count), 1, sortStream);
2686 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 20, SEEK_SET);
2687 fwrite(&discovered_count,
sizeof(discovered_count), 1, sortStream);
2693 mSortCacheItems.clear();
2694 mSubjectLists.clear();
2695 mImperfectlyThreadedList.clear();
2703 if ( mFolder->open(
"kmheaders" ) == 0 )
2704 updateMessageList();
2709 bool KMHeaders::writeSortOrder()
2711 TQString sortFile = KMAIL_SORT_FILE(mFolder);
2713 if (!mSortInfo.dirty) {
2714 struct stat stat_tmp;
2715 if(stat(TQFile::encodeName(sortFile), &stat_tmp) == -1) {
2716 mSortInfo.dirty =
true;
2719 if (mSortInfo.dirty) {
2720 if (!mFolder->count()) {
2722 unlink(TQFile::encodeName(sortFile));
2725 TQString tempName = sortFile +
".temp";
2726 unlink(TQFile::encodeName(tempName));
2727 FILE *sortStream = fopen(TQFile::encodeName(tempName),
"w");
2731 mSortInfo.ascending = !mSortDescending;
2732 mSortInfo.dirty =
false;
2733 mSortInfo.column = mSortCol;
2734 fprintf(sortStream, KMAIL_SORT_HEADER, KMAIL_SORT_VERSION);
2736 TQ_INT32 byteOrder = 0x12345678;
2737 TQ_INT32 column = mSortCol;
2738 TQ_INT32 ascending= !mSortDescending;
2740 TQ_INT32 appended=0;
2741 TQ_INT32 discovered_count = 0;
2742 TQ_INT32 sorted_count=0;
2743 fwrite(&byteOrder,
sizeof(byteOrder), 1, sortStream);
2744 fwrite(&column,
sizeof(column), 1, sortStream);
2745 fwrite(&ascending,
sizeof(ascending), 1, sortStream);
2746 fwrite(&threaded,
sizeof(threaded), 1, sortStream);
2747 fwrite(&appended,
sizeof(appended), 1, sortStream);
2748 fwrite(&discovered_count,
sizeof(discovered_count), 1, sortStream);
2749 fwrite(&sorted_count,
sizeof(sorted_count), 1, sortStream);
2751 TQPtrStack<HeaderItem> items;
2753 TQPtrStack<TQListViewItem> s;
2754 for (TQListViewItem * i = firstChild(); i; ) {
2756 if ( i->firstChild() ) {
2758 i = i->firstChild();
2759 }
else if( i->nextSibling()) {
2760 i = i->nextSibling();
2762 for(i=0; !i && s.count(); i = s.pop()->nextSibling())
2772 kmb = mFolder->getMsgBase( i->
msgId() );
2776 TQString replymd5 = kmb->replyToIdMD5();
2777 TQString replyToAuxId = kmb->replyToAuxIdMD5();
2779 if(!replymd5.isEmpty())
2780 p = mSortCacheItems[replymd5];
2783 parent_id = p->id();
2789 if (replymd5.isEmpty()
2790 && replyToAuxId.isEmpty()
2791 && !kmb->subjectIsPrefixed() )
2797 internalWriteItem(sortStream, mFolder, i->
msgId(), parent_id,
2798 i->key(mSortCol, !mSortDescending),
false);
2804 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET, SEEK_SET);
2805 fwrite(&byteOrder,
sizeof(byteOrder), 1, sortStream);
2806 fwrite(&column,
sizeof(column), 1, sortStream);
2807 fwrite(&ascending,
sizeof(ascending), 1, sortStream);
2808 fwrite(&threaded,
sizeof(threaded), 1, sortStream);
2809 fwrite(&appended,
sizeof(appended), 1, sortStream);
2810 fwrite(&discovered_count,
sizeof(discovered_count), 1, sortStream);
2811 fwrite(&sorted_count,
sizeof(sorted_count), 1, sortStream);
2812 if (sortStream && ferror(sortStream)) {
2814 unlink(TQFile::encodeName(sortFile));
2815 kdWarning(5006) <<
"Error: Failure modifying " << sortFile <<
" (No space left on device?)" << endl;
2816 kdWarning(5006) << __FILE__ <<
":" << __LINE__ << endl;
2817 kmkernel->emergencyExit( i18n(
"Failure modifying %1\n(No space left on device?)").arg( sortFile ));
2820 ::rename(TQFile::encodeName(tempName), TQFile::encodeName(sortFile));
2826 void KMHeaders::appendItemToSortFile(
HeaderItem *khi)
2828 TQString sortFile = KMAIL_SORT_FILE(mFolder);
2829 if(FILE *sortStream = fopen(TQFile::encodeName(sortFile),
"r+")) {
2834 KMMsgBase *kmb = mFolder->getMsgBase( khi->
msgId() );
2836 parent_id = sci->
parent()->id();
2837 else if(kmb->replyToIdMD5().isEmpty()
2838 && kmb->replyToAuxIdMD5().isEmpty()
2839 && !kmb->subjectIsPrefixed())
2843 internalWriteItem(sortStream, mFolder, khi->
msgId(), parent_id,
2844 khi->key(mSortCol, !mSortDescending),
false);
2847 TQ_INT32 appended = 1;
2848 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 16, SEEK_SET);
2849 fwrite(&appended,
sizeof(appended), 1, sortStream);
2850 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 16, SEEK_SET);
2852 if (sortStream && ferror(sortStream)) {
2854 unlink(TQFile::encodeName(sortFile));
2855 kdWarning(5006) <<
"Error: Failure modifying " << sortFile <<
" (No space left on device?)" << endl;
2856 kdWarning(5006) << __FILE__ <<
":" << __LINE__ << endl;
2857 kmkernel->emergencyExit( i18n(
"Failure modifying %1\n(No space left on device?)").arg( sortFile ));
2861 mSortInfo.dirty =
true;
2867 mSortInfo.dirty =
true;
2868 TQObject::disconnect(header(), TQ_SIGNAL(clicked(
int)),
this, TQ_SLOT(
dirtySortOrder(
int)));
2869 setSorting(column, mSortInfo.column == column ? !mSortInfo.ascending :
true);
2873 void SortCacheItem::updateSortFile( FILE *sortStream,
KMFolder *folder,
2874 bool waiting_for_parent,
bool update_discover)
2876 if(mSortOffset == -1) {
2877 fseek(sortStream, 0, SEEK_END);
2878 mSortOffset = ftell(sortStream);
2880 fseek(sortStream, mSortOffset, SEEK_SET);
2884 if(!waiting_for_parent) {
2886 parent_id = mParent->id();
2888 internalWriteItem(sortStream, folder, mId, parent_id, mKey, update_discover);
2891 static bool compare_ascending =
false;
2892 static bool compare_toplevel =
true;
2893 static int compare_SortCacheItem(
const void *s1,
const void *s2)
2899 int ret = (*b1)->key().compare((*b2)->key());
2900 if(compare_ascending || !compare_toplevel)
2906 void KMHeaders::printSubjectThreadingTree()
2908 TQDictIterator< TQPtrList< SortCacheItem > > it ( mSubjectLists );
2909 kdDebug(5006) <<
"SubjectThreading tree: " << endl;
2910 for( ; it.current(); ++it ) {
2911 TQPtrList<SortCacheItem> list = *( it.current() );
2912 TQPtrListIterator<SortCacheItem> it2( list ) ;
2913 kdDebug(5006) <<
"Subject MD5: " << it.currentKey() <<
" list: " << endl;
2914 for( ; it2.current(); ++it2 ) {
2916 kdDebug(5006) <<
" item:" << sci <<
" sci id: " << sci->id() << endl;
2919 kdDebug(5006) << endl;
2922 void KMHeaders::printThreadingTree()
2924 kdDebug(5006) <<
"Threading tree: " << endl;
2925 TQDictIterator<SortCacheItem> it( mSortCacheItems );
2926 kdDebug(5006) << endl;
2927 for( ; it.current(); ++it ) {
2929 kdDebug(5006) <<
"MsgId MD5: " << it.currentKey() <<
" message id: " << sci->id() << endl;
2931 for (
int i = 0; i < (int)mItems.size(); ++i) {
2934 kdDebug( 5006 ) <<
"SortCacheItem: " << item->
sortCacheItem()->id() <<
" parent: " << parentCacheId << endl;
2937 kdDebug(5006) << endl;
2942 void KMHeaders::buildThreadingTree( TQMemArray<SortCacheItem *> sortCache )
2944 mSortCacheItems.clear();
2945 mSortCacheItems.resize( mFolder->count() * 2 );
2948 for(
int x = 0; x < mFolder->count(); x++) {
2949 KMMsgBase *mi = mFolder->getMsgBase(x);
2950 TQString md5 = mi->msgIdMD5();
2952 mSortCacheItems.replace(md5, sortCache[x]);
2957 void KMHeaders::buildSubjectThreadingTree( TQMemArray<SortCacheItem *> sortCache )
2959 mSubjectLists.clear();
2960 mSubjectLists.resize( mFolder->count() * 2 );
2962 for(
int x = 0; x < mFolder->count(); x++) {
2964 if ( sortCache[x]->parent()
2965 && sortCache[x]->parent()->
id() != -666 )
continue;
2966 KMMsgBase *mi = mFolder->getMsgBase(x);
2967 TQString subjMD5 = mi->strippedSubjectMD5();
2968 if (subjMD5.isEmpty()) {
2969 mFolder->getMsgBase(x)->initStrippedSubjectMD5();
2970 subjMD5 = mFolder->getMsgBase(x)->strippedSubjectMD5();
2972 if( subjMD5.isEmpty() )
continue;
2976 if (!mSubjectLists.find(subjMD5))
2977 mSubjectLists.insert(subjMD5,
new TQPtrList<SortCacheItem>());
2983 for (TQPtrListIterator<SortCacheItem> it(*mSubjectLists[subjMD5]);
2984 it.current(); ++it) {
2985 KMMsgBase *mb = mFolder->getMsgBase((*it)->id());
2986 if ( mb->date() < mi->date())
2990 mSubjectLists[subjMD5]->insert( p, sortCache[x]);
2991 sortCache[x]->setSubjectThreadingList( mSubjectLists[subjMD5] );
2999 if (!item)
return parent;
3000 KMMsgBase *msg = mFolder->getMsgBase(item->id());
3001 TQString replyToIdMD5 = msg->replyToIdMD5();
3005 if(!replyToIdMD5.isEmpty()) {
3006 parent = mSortCacheItems[replyToIdMD5];
3017 TQString ref = msg->replyToAuxIdMD5();
3019 parent = mSortCacheItems[ref];
3027 if (!item)
return parent;
3029 KMMsgBase *msg = mFolder->getMsgBase(item->id());
3034 if (!msg->subjectIsPrefixed())
3037 TQString replyToIdMD5 = msg->replyToIdMD5();
3038 TQString subjMD5 = msg->strippedSubjectMD5();
3039 if (!subjMD5.isEmpty() && mSubjectLists[subjMD5]) {
3042 for (TQPtrListIterator<SortCacheItem> it2(*mSubjectLists[subjMD5]);
3043 it2.current(); ++it2) {
3044 KMMsgBase *mb = mFolder->getMsgBase((*it2)->id());
3045 if ( !mb )
return parent;
3047 if ( item == (*it2) )
continue;
3048 int delta = msg->date() - mb->date();
3053 if (delta < 3628899)
3062 bool KMHeaders::readSortOrder(
bool set_selection,
bool forceJumpToUnread )
3064 if (!mFolder->isOpened()) mFolder->open(
"kmheaders");
3067 TQ_INT32 column, ascending, threaded, discovered_count, sorted_count, appended;
3068 TQ_INT32 deleted_count = 0;
3069 bool unread_exists =
false;
3070 bool jumpToUnread = (GlobalSettings::self()->actionEnterFolder() ==
3071 GlobalSettings::EnumActionEnterFolder::SelectFirstUnreadNew) ||
3075 TQMemArray<SortCacheItem *> sortCache(mFolder->count());
3079 TQPtrList<SortCacheItem> unparented;
3080 mImperfectlyThreadedList.clear();
3083 mItems.fill( 0, mFolder->count() );
3084 sortCache.fill( 0 );
3086 mRoot->clearChildren();
3088 TQString sortFile = KMAIL_SORT_FILE(mFolder);
3089 FILE *sortStream = fopen(TQFile::encodeName(sortFile),
"r+");
3090 mSortInfo.fakeSort = 0;
3093 mSortInfo.fakeSort = 1;
3095 if (fscanf(sortStream, KMAIL_SORT_HEADER, &version) != 1)
3097 if(version == KMAIL_SORT_VERSION) {
3098 TQ_INT32 byteOrder = 0;
3099 fread(&byteOrder,
sizeof(byteOrder), 1, sortStream);
3100 if (byteOrder == 0x12345678)
3102 fread(&column,
sizeof(column), 1, sortStream);
3103 fread(&ascending,
sizeof(ascending), 1, sortStream);
3104 fread(&threaded,
sizeof(threaded), 1, sortStream);
3105 fread(&appended,
sizeof(appended), 1, sortStream);
3106 fread(&discovered_count,
sizeof(discovered_count), 1, sortStream);
3107 fread(&sorted_count,
sizeof(sorted_count), 1, sortStream);
3110 TDEListView::setSorting(-1);
3111 header()->setSortIndicator(column, ascending);
3112 TQObject::connect(header(), TQ_SIGNAL(clicked(
int)),
this, TQ_SLOT(dirtySortOrder(
int)));
3114 mSortInfo.dirty =
false;
3115 mSortInfo.column = (short)column;
3116 mSortInfo.ascending = (compare_ascending = ascending);
3119 unsigned long serNum, parentSerNum;
3120 int id, len, parent, x;
3121 TQChar *tmp_qchar = 0;
3122 int tmp_qchar_len = 0;
3123 const int mFolderCount = mFolder->count();
3126 CREATE_TIMER(parse);
3128 for(x = 0; !feof(sortStream) && !error; x++) {
3129 off_t offset = ftell(sortStream);
3132 if(!fread(&serNum,
sizeof(serNum), 1, sortStream) ||
3133 !fread(&parentSerNum,
sizeof(parentSerNum), 1, sortStream) ||
3134 !fread(&len,
sizeof(len), 1, sortStream)) {
3137 if ((len < 0) || (len > KMAIL_MAX_KEY_LEN)) {
3138 kdDebug(5006) <<
"Whoa.2! len " << len <<
" " << __FILE__ <<
":" << __LINE__ << endl;
3143 if(len > tmp_qchar_len) {
3144 tmp_qchar = (TQChar *)realloc(tmp_qchar, len);
3145 tmp_qchar_len = len;
3147 if(!fread(tmp_qchar, len, 1, sortStream))
3149 key = TQString(tmp_qchar, len / 2);
3155 if (folder != mFolder) {
3159 if (parentSerNum < KMAIL_RESERVED) {
3160 parent = (int)parentSerNum - KMAIL_RESERVED;
3163 if (folder != mFolder)
3166 if ((
id < 0) || (
id >= mFolderCount) ||
3167 (parent < -2) || (parent >= mFolderCount)) {
3168 kdDebug(5006) <<
"Whoa.1! " << __FILE__ <<
":" << __LINE__ << endl;
3173 if ((item=sortCache[
id])) {
3174 if (item->id() != -1) {
3175 kdDebug(5006) <<
"Whoa.3! " << __FILE__ <<
":" << __LINE__ << endl;
3181 item->setOffset(offset);
3185 if (threaded && parent != -2) {
3187 unparented.append(item);
3188 mRoot->addUnsortedChild(item);
3190 if( ! sortCache[parent] ) {
3193 sortCache[parent]->addUnsortedChild(item);
3196 if(x < sorted_count )
3197 mRoot->addSortedChild(item);
3199 mRoot->addUnsortedChild(item);
3203 if (error || (x != sorted_count + discovered_count)) {
3204 kdDebug(5006) << endl <<
"Whoa: x " << x <<
", sorted_count " << sorted_count <<
", discovered_count " << discovered_count <<
", count " << mFolder->count() << endl << endl;
3225 mSortInfo.dirty =
true;
3226 mSortInfo.column = column = mSortCol;
3227 mSortInfo.ascending = ascending = !mSortDescending;
3228 threaded = (isThreaded());
3229 sorted_count = discovered_count = appended = 0;
3230 TDEListView::setSorting( mSortCol, !mSortDescending );
3233 if((sorted_count + discovered_count - deleted_count) < mFolder->count()) {
3234 CREATE_TIMER(holes);
3237 for(
int x = 0; x < mFolder->count(); x++) {
3238 if((!sortCache[x] || (sortCache[x]->
id() < 0)) && (msg=mFolder->getMsgBase(x))) {
3239 int sortOrder = column;
3240 if (mPaintInfo.orderOfArrival)
3241 sortOrder |= (1 << 6);
3242 if (mPaintInfo.status)
3243 sortOrder |= (1 << 5);
3245 x, HeaderItem::generate_key(
this, msg, &mPaintInfo, sortOrder ));
3247 unparented.append(sortCache[x]);
3249 mRoot->addUnsortedChild(sortCache[x]);
3251 sortCache[x]->updateSortFile(sortStream, mFolder,
true,
true);
3262 if (threaded) buildThreadingTree( sortCache );
3263 TQPtrList<SortCacheItem> toBeSubjThreaded;
3265 if (threaded && !unparented.isEmpty()) {
3266 CREATE_TIMER(reparent);
3267 START_TIMER(reparent);
3269 for(TQPtrListIterator<SortCacheItem> it(unparented); it.current(); ++it) {
3273 if ( parent && (parent != (*it)) ) {
3276 (*it)->updateSortFile(sortStream, mFolder);
3281 toBeSubjThreaded.append((*it));
3283 mRoot->addUnsortedChild((*it));
3287 if (mSubjThreading) {
3288 buildSubjectThreadingTree( sortCache );
3289 for(TQPtrListIterator<SortCacheItem> it(toBeSubjThreaded); it.current(); ++it) {
3296 (*it)->updateSortFile(sortStream, mFolder);
3299 mRoot->addUnsortedChild((*it));
3303 END_TIMER(reparent);
3304 SHOW_TIMER(reparent);
3307 CREATE_TIMER(header_creation);
3308 START_TIMER(header_creation);
3311 TQPtrQueue<SortCacheItem> s;
3313 compare_toplevel =
true;
3317 int unsorted_count, unsorted_off=0;
3321 compare_SortCacheItem);
3327 for(TQPtrListIterator<SortCacheItem> it(*sorted);
3328 (unsorted && unsorted_off < unsorted_count) || it.current(); ) {
3335 ( !unsorted || unsorted_off >= unsorted_count
3337 ( ( !ascending || (ascending && !compare_toplevel) )
3338 && (*it)->key() < unsorted[unsorted_off]->
key() )
3340 ( ascending && (*it)->key() >= unsorted[unsorted_off]->
key() )
3348 new_kci = unsorted[unsorted_off++];
3350 if(new_kci->
item() || new_kci->
parent() != i)
3353 if(threaded && i->
item()) {
3356 if (mFolder->getMsgBase(i->id())->isWatched())
3357 mFolder->getMsgBase(new_kci->id())->setStatus(KMMsgStatusWatched);
3358 if (mFolder->getMsgBase(i->id())->isIgnored())
3359 mFolder->getMsgBase(new_kci->id())->setStatus(KMMsgStatusIgnored);
3364 new_kci->
setItem(mItems[new_kci->id()] = khi);
3369 if ( ( mFolder->getMsgBase(new_kci->id())->isNew() &&
3370 GlobalSettings::self()->actionEnterFolder() ==
3371 GlobalSettings::EnumActionEnterFolder::SelectFirstNew ) ||
3372 ( ( mFolder->getMsgBase(new_kci->id())->isNew() ||
3373 mFolder->getMsgBase(new_kci->id())->isUnread() ) &&
3376 unread_exists =
true;
3379 if ( !oldestItem || mFolder->getMsgBase( oldestItem->
msgId() )->date() >
3380 mFolder->getMsgBase( new_kci->id() )->date() ) {
3384 if ( !newestItem || mFolder->getMsgBase( newestItem->
msgId() )->date() <
3385 mFolder->getMsgBase( new_kci->id() )->date() ) {
3392 if (mSortCol == paintInfo()->dateCol)
3393 compare_toplevel =
false;
3394 }
while(!s.isEmpty());
3396 for(
int x = 0; x < mFolder->count(); x++) {
3397 if (!sortCache[x]) {
3401 if (!sortCache[x]->item()) {
3402 kdDebug(5006) <<
"KMHeaders::readSortOrder - msg could not be threaded. "
3403 << endl <<
"Please talk to your threading counselor asap. " << endl;
3404 khi =
new HeaderItem(
this, sortCache[x]->
id(), sortCache[x]->key());
3405 sortCache[x]->setItem(mItems[sortCache[x]->
id()] = khi);
3410 if (threaded && sortCache[x]->isImperfectlyThreaded()) {
3411 mImperfectlyThreadedList.append(sortCache[x]->item());
3415 sortCache[x]->item()->setSortCacheItem(sortCache[x]);
3418 if (getNestingPolicy()<2)
3422 END_TIMER(header_creation);
3423 SHOW_TIMER(header_creation);
3427 if( discovered_count * discovered_count > sorted_count - deleted_count ) {
3428 mSortInfo.dirty =
true;
3432 fseek(sortStream, KMAIL_MAGIC_HEADER_OFFSET + 16, SEEK_SET);
3433 fwrite(&appended,
sizeof(appended), 1, sortStream);
3438 CREATE_TIMER(selection);
3439 START_TIMER(selection);
3443 int first_unread = -1;
3444 if (unread_exists) {
3447 if ( ( mFolder->getMsgBase(item->
msgId())->isNew() &&
3448 GlobalSettings::self()->actionEnterFolder() ==
3449 GlobalSettings::EnumActionEnterFolder::SelectFirstNew ) ||
3450 ( ( mFolder->getMsgBase(item->
msgId())->isNew() ||
3451 mFolder->getMsgBase(item->
msgId())->isUnread() ) &&
3454 first_unread = item->
msgId();
3457 item =
static_cast<HeaderItem*
>(item->itemBelow());
3462 if(first_unread == -1 ) {
3463 setTopItemByIndex( mTopItem );
3465 if ( GlobalSettings::self()->actionEnterFolder() ==
3466 GlobalSettings::EnumActionEnterFolder::SelectNewest && newestItem != 0 ) {
3467 setCurrentItemByIndex( newestItem->
msgId() );
3469 else if ( GlobalSettings::self()->actionEnterFolder() ==
3470 GlobalSettings::EnumActionEnterFolder::SelectOldest && oldestItem != 0 ) {
3471 setCurrentItemByIndex( oldestItem->
msgId() );
3473 else if ( mCurrentItem >= 0 )
3474 setCurrentItemByIndex( mCurrentItem );
3475 else if ( mCurrentItemSerNum > 0 )
3476 setCurrentItemBySerialNum( mCurrentItemSerNum );
3478 setCurrentItemByIndex( 0 );
3482 setCurrentItemByIndex(first_unread);
3483 makeHeaderVisible();
3484 center( contentsX(), itemPos(mItems[first_unread]), 0, 9.0 );
3490 if (mCurrentItem <= 0) {
3491 setTopItemByIndex(mTopItem);
3492 setCurrentItemByIndex(0);
3495 END_TIMER(selection);
3496 SHOW_TIMER(selection);
3497 if (error || (sortStream && ferror(sortStream))) {
3500 unlink(TQFile::encodeName(sortFile));
3501 kdWarning(5006) <<
"Error: Failure modifying " << sortFile <<
" (No space left on device?)" << endl;
3502 kdWarning(5006) << __FILE__ <<
":" << __LINE__ << endl;
3518 for (
int i = 0; i < (int)mItems.size() - 1; ++i) {
3519 KMMsgBase *mMsgBase = mFolder->getMsgBase( i );
3520 if ( mMsgBase->getMsgSerNum() == serialNum ) {
3521 bool unchanged = (currentItem() == mItems[i]);
3522 setCurrentItem( mItems[i] );
3523 setSelected( mItems[i],
true );
3524 setSelectionAnchor( currentItem() );
3526 highlightMessage( currentItem(),
false );
3527 ensureCurrentItemVisible();
3532 kdDebug(5006) <<
"KMHeaders::setCurrentItem item with serial number " << serialNum <<
" NOT FOUND" << endl;
3535 void KMHeaders::copyMessages()
3537 mCopiedMessages.clear();
3538 KMMessageList* list = selectedMsgs();
3539 for ( uint i = 0; i < list->count(); ++ i )
3540 mCopiedMessages << list->at( i )->getMsgSerNum();
3541 mMoveMessages =
false;
3546 void KMHeaders::cutMessages()
3548 mCopiedMessages.clear();
3549 KMMessageList* list = selectedMsgs();
3550 for ( uint i = 0; i < list->count(); ++ i )
3551 mCopiedMessages << list->at( i )->getMsgSerNum();
3552 mMoveMessages =
true;
3557 void KMHeaders::pasteMessages()
3560 if ( mMoveMessages ) {
3561 mCopiedMessages.clear();
3566 void KMHeaders::updateActions()
3568 TDEAction *copy = owner()->action(
"copy_messages" );
3569 TDEAction *cut = owner()->action(
"cut_messages" );
3570 TDEAction *paste = owner()->action(
"paste_messages" );
3572 if ( selectedItems().isEmpty() ) {
3573 copy->setEnabled(
false );
3574 cut->setEnabled(
false );
3576 copy->setEnabled(
true );
3577 if ( folder() && !folder()->canDeleteMessages() )
3578 cut->setEnabled(
false );
3580 cut->setEnabled(
true );
3583 if ( mCopiedMessages.isEmpty() || !folder() || folder()->isReadOnly() )
3584 paste->setEnabled(
false );
3586 paste->setEnabled(
true );
3591 mCopiedMessages = msgs;
3592 mMoveMessages = move;
3598 return mMoveMessages && mCopiedMessages.contains( serNum );
3603 TQValueList<TQ_UINT32> list;
3604 for ( TQListViewItemIterator it(
this); it.current(); it++ ) {
3605 if ( it.current()->isSelected() && it.current()->isVisible() ) {
3607 KMMsgBase *msgBase = mFolder->getMsgBase( item->
msgId() );
3609 list.append( msgBase->getMsgSerNum() );
3618 TQValueList<TQ_UINT32> list;
3619 TQListViewItemIterator it(
this, TQListViewItemIterator::Selected|TQListViewItemIterator::Visible);
3620 while( it.current() ) {
3621 if ( it.current()->isSelected() && it.current()->isVisible() ) {
3622 if ( it.current()->parent() && ( !it.current()->parent()->isOpen() ) ) {
3624 TQListViewItem * lastAncestorWithSiblings = it.current()->parent();
3626 while ( ( lastAncestorWithSiblings->depth() > 0 ) && !lastAncestorWithSiblings->nextSibling() )
3627 lastAncestorWithSiblings = lastAncestorWithSiblings->parent();
3629 it = TQListViewItemIterator( lastAncestorWithSiblings->nextSibling() );
3633 KMMsgBase *msgBase = mFolder->getMsgBase( item->
msgId() );
3635 list.append( msgBase->getMsgSerNum() );
3644 #include "kmheaders.moc"