kmail

searchwindow.cpp
1/*
2 * kmail: KDE mail client
3 * Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
4 * Copyright (c) 2001 Aaron J. Seigo <aseigo@kde.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 */
21#include <config.h>
22#include "kmcommands.h"
23#include "searchwindow.h"
24#include "kmmainwidget.h"
25#include "kmmsgdict.h"
26#include "kmmsgpart.h"
27#include "kmfolderimap.h"
28#include "kmfoldermgr.h"
29#include "kmfoldersearch.h"
30#include "kmfoldertree.h"
31#include "kmheaders.h"
32#include "kmsearchpatternedit.h"
33#include "kmsearchpattern.h"
34#include "folderrequester.h"
35#include "messagecopyhelper.h"
36#include "textsource.h"
37
38#include <tdeapplication.h>
39#include <kdebug.h>
40#include <kstatusbar.h>
41#include <twin.h>
42#include <tdeconfig.h>
43#include <kstdaction.h>
44#include <kiconloader.h>
45
46#include <tqcheckbox.h>
47#include <tqlayout.h>
48#include <klineedit.h>
49#include <tqpushbutton.h>
50#include <tqradiobutton.h>
51#include <tqbuttongroup.h>
52#include <tqcombobox.h>
53#include <tqobjectlist.h> //for mPatternEdit->queryList( 0, "mRuleField" )->first();
54#include <tqcursor.h>
55#include <tqpopupmenu.h>
56
57#include <maillistdrag.h>
58using namespace KPIM;
59
60#include <mimelib/enum.h>
61#include <mimelib/boyermor.h>
62
63#include <assert.h>
64#include <stdlib.h>
65
66namespace KMail {
67
68const int SearchWindow::MSGID_COLUMN = 4;
69
70// TDEListView sub-class for dnd support
71class MatchListView : public TDEListView
72{
73 public:
74 MatchListView( TQWidget *parent, SearchWindow* sw, const char* name = 0 ) :
75 TDEListView( parent, name ),
76 mSearchWindow( sw )
77 {}
78
79 protected:
80 virtual TQDragObject* dragObject()
81 {
82 KMMessageList list = mSearchWindow->selectedMessages();
83 MailList mailList;
84 for ( KMMsgBase* msg = list.first(); msg; msg = list.next() ) {
85 if ( !msg )
86 continue;
87 MailSummary mailSummary( msg->getMsgSerNum(), msg->msgIdMD5(),
88 msg->subject(), msg->fromStrip(),
89 msg->toStrip(), msg->date() );
90 mailList.append( mailSummary );
91 }
92 MailListDrag *d = new MailListDrag( mailList, viewport(), new KMTextSource );
93
94 TQPixmap pixmap;
95 if( mailList.count() == 1 )
96 pixmap = TQPixmap( DesktopIcon("message", TDEIcon::SizeSmall) );
97 else
98 pixmap = TQPixmap( DesktopIcon("application-vnd.tde.tdemultiple", TDEIcon::SizeSmall) );
99
100 d->setPixmap( pixmap );
101 return d;
102 }
103
104 private:
105 SearchWindow* mSearchWindow;
106};
107
108//-----------------------------------------------------------------------------
109SearchWindow::SearchWindow(KMMainWidget* w, const char* name,
110 KMFolder *curFolder, bool modal):
111 KDialogBase(0, name, modal, i18n("Find Messages"),
112 User1 | User2 | Close, User1, false,
113 KGuiItem( i18n("&Search"), "edit-find" ),
114 KStdGuiItem::stop()),
115 mStopped(false),
116 mCloseRequested(false),
117 mSortColumn(0),
118 mSortOrder(Ascending),
119 mFolder(0),
120 mTimer(new TQTimer(this, "mTimer")),
121 mLastFocus(0),
122 mKMMainWidget(w)
123{
124 KWin::setIcons(winId(), tdeApp->icon(), tdeApp->miniIcon());
125
126 TDEConfig* config = KMKernel::config();
127 config->setGroup("SearchDialog");
128
129 TQWidget* searchWidget = new TQWidget(this);
130 TQVBoxLayout *vbl = new TQVBoxLayout( searchWidget, 0, spacingHint(), "kmfs_vbl" );
131
132 TQButtonGroup * radioGroup = new TQButtonGroup( searchWidget );
133 radioGroup->hide();
134
135 mChkbxAllFolders = new TQRadioButton(i18n("Search in &all local folders"), searchWidget);
136 vbl->addWidget( mChkbxAllFolders );
137 radioGroup->insert( mChkbxAllFolders );
138
139 TQHBoxLayout *hbl = new TQHBoxLayout( vbl, spacingHint(), "kmfs_hbl" );
140 mChkbxSpecificFolders = new TQRadioButton(i18n("Search &only in:"), searchWidget);
141 hbl->addWidget(mChkbxSpecificFolders);
142 mChkbxSpecificFolders->setChecked(true);
143 radioGroup->insert( mChkbxSpecificFolders );
144
145 mCbxFolders = new FolderRequester( searchWidget,
146 kmkernel->getKMMainWidget()->folderTree() );
147 mCbxFolders->setMustBeReadWrite( false );
148 mCbxFolders->setFolder(curFolder);
149 hbl->addWidget(mCbxFolders);
150
151 mChkSubFolders = new TQCheckBox(i18n("I&nclude sub-folders"), searchWidget);
152 mChkSubFolders->setChecked(true);
153 hbl->addWidget(mChkSubFolders);
154
155 TQWidget *spacer = new TQWidget( searchWidget, "spacer" );
156 spacer->setMinimumHeight( 2 );
157 vbl->addWidget( spacer );
158
159 mPatternEdit = new KMSearchPatternEdit( "", searchWidget , "spe", false, true );
160 mPatternEdit->setFrameStyle( TQFrame::NoFrame | TQFrame::Plain );
161 mPatternEdit->setInsideMargin( 0 );
162 mSearchPattern = new KMSearchPattern();
163 KMFolderSearch *searchFolder = 0;
164 if (curFolder)
165 searchFolder = dynamic_cast<KMFolderSearch*>(curFolder->storage());
166 if (searchFolder) {
167 TDEConfig config(curFolder->location());
168 KMFolder *root = searchFolder->search()->root();
169 config.setGroup("Search Folder");
170 mSearchPattern->readConfig(&config);
171 if (root) {
172 mChkbxSpecificFolders->setChecked(true);
173 mCbxFolders->setFolder(root);
174 mChkSubFolders->setChecked(searchFolder->search()->recursive());
175 } else {
176 mChkbxAllFolders->setChecked(true);
177 }
178 }
179 mPatternEdit->setSearchPattern( mSearchPattern );
180 TQObjectList *list = mPatternEdit->queryList( 0, "mRuleField" );
181 TQObject *object = 0;
182 if ( list )
183 object = list->first();
184 delete list;
185 if (!searchFolder && object && ::tqt_cast<TQComboBox*>(object))
186 static_cast<TQComboBox*>(object)->setCurrentText(i18n("Subject"));
187
188 vbl->addWidget( mPatternEdit );
189
190 // enable/disable widgets depending on radio buttons:
191 connect( mChkbxSpecificFolders, TQ_SIGNAL(toggled(bool)),
192 mCbxFolders, TQ_SLOT(setEnabled(bool)) );
193 connect( mChkbxSpecificFolders, TQ_SIGNAL(toggled(bool)),
194 mChkSubFolders, TQ_SLOT(setEnabled(bool)) );
195 connect( mChkbxAllFolders, TQ_SIGNAL(toggled(bool)),
196 this, TQ_SLOT(setEnabledSearchButton(bool)) );
197
198 mLbxMatches = new MatchListView(searchWidget, this, "Find Messages");
199
200 /*
201 Default is to sort by date. TODO: Unfortunately this sorts *while*
202 inserting, which looks rather strange - the user cannot read
203 the results so far as they are constantly re-sorted --dnaber
204
205 Sorting is now disabled when a search is started and reenabled
206 when it stops. Items are appended to the list. This not only
207 solves the above problem, but speeds searches with many hits
208 up considerably. - till
209
210 TODO: subclass TDEListViewItem and do proper (and performant)
211 comapare functions
212 */
213 mLbxMatches->setSorting(2, false);
214 mLbxMatches->setShowSortIndicator(true);
215 mLbxMatches->setAllColumnsShowFocus(true);
216 mLbxMatches->setSelectionModeExt(TDEListView::Extended);
217 mLbxMatches->addColumn(i18n("Subject"),
218 config->readNumEntry("SubjectWidth", 150));
219 mLbxMatches->addColumn(i18n("Sender/Receiver"),
220 config->readNumEntry("SenderWidth", 120));
221 mLbxMatches->addColumn(i18n("Date"),
222 config->readNumEntry("DateWidth", 120));
223 mLbxMatches->addColumn(i18n("Folder"),
224 config->readNumEntry("FolderWidth", 100));
225
226 mLbxMatches->addColumn(""); // should be hidden
227 mLbxMatches->setColumnWidthMode( MSGID_COLUMN, TQListView::Manual );
228 mLbxMatches->setColumnWidth(MSGID_COLUMN, 0);
229 mLbxMatches->header()->setResizeEnabled(false, MSGID_COLUMN);
230
231 mLbxMatches->setDragEnabled( true );
232
233 connect( mLbxMatches, TQ_SIGNAL(clicked(TQListViewItem *)),
234 this, TQ_SLOT(slotShowMsg(TQListViewItem *)) );
235 connect( mLbxMatches, TQ_SIGNAL(doubleClicked(TQListViewItem *)),
236 this, TQ_SLOT(slotViewMsg(TQListViewItem *)) );
237 connect( mLbxMatches, TQ_SIGNAL(currentChanged(TQListViewItem *)),
238 this, TQ_SLOT(slotCurrentChanged(TQListViewItem *)) );
239 connect( mLbxMatches, TQ_SIGNAL(contextMenuRequested(TQListViewItem *,const TQPoint &,int)),
240 this, TQ_SLOT(slotContextMenuRequested(TQListViewItem *,const TQPoint &,int)) );
241 vbl->addWidget( mLbxMatches );
242
243 TQHBoxLayout *hbl2 = new TQHBoxLayout( vbl, spacingHint(), "kmfs_hbl2" );
244 mSearchFolderLbl = new TQLabel(i18n("Search folder &name:"), searchWidget);
245 hbl2->addWidget(mSearchFolderLbl);
246 mSearchFolderEdt = new KLineEdit(searchWidget);
247 if (searchFolder)
248 mSearchFolderEdt->setText(searchFolder->folder()->name());
249 else
250 mSearchFolderEdt->setText(i18n("Last Search"));
251
252 mSearchFolderLbl->setBuddy(mSearchFolderEdt);
253 hbl2->addWidget(mSearchFolderEdt);
254 mSearchFolderOpenBtn = new TQPushButton(i18n("Op&en Search Folder"), searchWidget);
255 mSearchFolderOpenBtn->setEnabled(false);
256 hbl2->addWidget(mSearchFolderOpenBtn);
257 connect( mSearchFolderEdt, TQ_SIGNAL( textChanged( const TQString &)),
258 this, TQ_SLOT( scheduleRename( const TQString & )));
259 connect( &mRenameTimer, TQ_SIGNAL( timeout() ),
260 this, TQ_SLOT( renameSearchFolder() ));
261 connect( mSearchFolderOpenBtn, TQ_SIGNAL( clicked() ),
262 this, TQ_SLOT( openSearchFolder() ));
263 mSearchResultOpenBtn = new TQPushButton(i18n("Open &Message"), searchWidget);
264 mSearchResultOpenBtn->setEnabled(false);
265 hbl2->addWidget(mSearchResultOpenBtn);
266 connect( mSearchResultOpenBtn, TQ_SIGNAL( clicked() ),
267 this, TQ_SLOT( slotViewSelectedMsg() ));
268 mStatusBar = new KStatusBar(searchWidget);
269 mStatusBar->insertFixedItem(i18n("AMiddleLengthText..."), 0, true);
270 mStatusBar->changeItem(i18n("Ready."), 0);
271 mStatusBar->setItemAlignment(0, AlignLeft | AlignVCenter);
272 mStatusBar->insertItem(TQString(), 1, 1, true);
273 mStatusBar->setItemAlignment(1, AlignLeft | AlignVCenter);
274 vbl->addWidget(mStatusBar);
275
276 int mainWidth = config->readNumEntry("SearchWidgetWidth", 0);
277 int mainHeight = config->readNumEntry("SearchWidgetHeight", 0);
278
279 if (mainWidth || mainHeight)
280 resize(mainWidth, mainHeight);
281
282 setMainWidget(searchWidget);
283 setButtonBoxOrientation(TQt::Vertical);
284
285 mBtnSearch = actionButton(KDialogBase::User1);
286 mBtnStop = actionButton(KDialogBase::User2);
287 mBtnStop->setEnabled(false);
288
289 connect(this, TQ_SIGNAL(user1Clicked()), TQ_SLOT(slotSearch()));
290 connect(this, TQ_SIGNAL(user2Clicked()), TQ_SLOT(slotStop()));
291 connect(this, TQ_SIGNAL(finished()), this, TQ_SLOT(deleteLater()));
292
293 // give focus to the value field of the first search rule
294 object = mPatternEdit->child( "regExpLineEdit" );
295 if ( object && object->isWidgetType() ) {
296 static_cast<TQWidget*>(object)->setFocus();
297 //kdDebug(5006) << "SearchWindow: focus has been given to widget "
298 // << object->name() << endl;
299 }
300 else
301 kdDebug(5006) << "SearchWindow: regExpLineEdit not found" << endl;
302
303 //set up actions
304 TDEActionCollection *ac = actionCollection();
305 ac->setWidget( this );
306 mReplyAction = new TDEAction( i18n("&Reply..."), "mail-reply-sender", 0, this,
307 TQ_SLOT(slotReplyToMsg()), ac, "search_reply" );
308 mReplyAllAction = new TDEAction( i18n("Reply to &All..."), "mail-reply-all",
309 0, this, TQ_SLOT(slotReplyAllToMsg()),
310 ac, "search_reply_all" );
311 mReplyListAction = new TDEAction( i18n("Reply to Mailing-&List..."),
312 "mail_replylist", 0, this,
313 TQ_SLOT(slotReplyListToMsg()), ac,
314 "search_reply_list" );
315 mForwardActionMenu = new TDEActionMenu( i18n("Message->","&Forward"),
316 "mail-forward", ac,
317 "search_message_forward" );
318 connect( mForwardActionMenu, TQ_SIGNAL(activated()), this,
319 TQ_SLOT(slotForwardInlineMsg()) );
320 mForwardAttachedAction = new TDEAction( i18n("Message->Forward->","As &Attachment..."),
321 "mail-forward", 0, this,
322 TQ_SLOT(slotForwardAttachedMsg()), ac,
323 "search_message_forward_as_attachment" );
324 mForwardInlineAction = new TDEAction( i18n("&Inline..."),
325 "mail-forward", 0, this,
326 TQ_SLOT(slotForwardInlineMsg()), ac,
327 "search_message_forward_inline" );
328 if ( GlobalSettings::self()->forwardingInlineByDefault() ) {
329 mForwardActionMenu->insert( mForwardInlineAction );
330 mForwardActionMenu->insert( mForwardAttachedAction );
331 } else {
332 mForwardActionMenu->insert( mForwardAttachedAction );
333 mForwardActionMenu->insert( mForwardInlineAction );
334 }
335
336 mForwardDigestAction = new TDEAction( i18n("Message->Forward->","As Di&gest..."),
337 "mail-forward", 0, this,
338 TQ_SLOT(slotForwardDigestMsg()), ac,
339 "search_message_forward_as_digest" );
340 mForwardActionMenu->insert( mForwardDigestAction );
341 mRedirectAction = new TDEAction( i18n("Message->Forward->","&Redirect..."),
342 "mail-forward", 0, this,
343 TQ_SLOT(slotRedirectMsg()), ac,
344 "search_message_forward_redirect" );
345 mForwardActionMenu->insert( mRedirectAction );
346 mSaveAsAction = KStdAction::saveAs( this, TQ_SLOT(slotSaveMsg()), ac, "search_file_save_as" );
347 mSaveAtchAction = new TDEAction( i18n("Save Attachments..."), "attach", 0,
348 this, TQ_SLOT(slotSaveAttachments()), ac, "search_save_attachments" );
349
350 mPrintAction = KStdAction::print( this, TQ_SLOT(slotPrintMsg()), ac, "search_print" );
351 mClearAction = new TDEAction( i18n("Clear Selection"), 0, 0, this,
352 TQ_SLOT(slotClearSelection()), ac, "search_clear_selection" );
353
354 mCopyAction = KStdAction::copy( this, TQ_SLOT(slotCopyMsgs()), ac, "search_copy_messages" );
355 mCutAction = KStdAction::cut( this, TQ_SLOT(slotCutMsgs()), ac, "search_cut_messages" );
356
357 connect(mTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(updStatus()));
358 connect(kmkernel->searchFolderMgr(), TQ_SIGNAL(folderInvalidated(KMFolder*)),
359 this, TQ_SLOT(folderInvalidated(KMFolder*)));
360
361 connect(mCbxFolders, TQ_SIGNAL(folderChanged(KMFolder*)),
362 this, TQ_SLOT(slotFolderActivated()));
363
364}
365
366//-----------------------------------------------------------------------------
367SearchWindow::~SearchWindow()
368{
369 TQValueListIterator<TQGuardedPtr<KMFolder> > fit;
370 for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
371 if (!(*fit))
372 continue;
373 (*fit)->close("searchwindow");
374 }
375
376 TDEConfig* config = KMKernel::config();
377 config->setGroup("SearchDialog");
378 config->writeEntry("SubjectWidth", mLbxMatches->columnWidth(0));
379 config->writeEntry("SenderWidth", mLbxMatches->columnWidth(1));
380 config->writeEntry("DateWidth", mLbxMatches->columnWidth(2));
381 config->writeEntry("FolderWidth", mLbxMatches->columnWidth(3));
382 config->writeEntry("SearchWidgetWidth", width());
383 config->writeEntry("SearchWidgetHeight", height());
384 config->sync();
385}
386
387void SearchWindow::setEnabledSearchButton(bool)
388{
389 //Make sure that button is enable
390 //Before when we selected a folder == "Local Folder" as that it was not a folder
391 //search button was disable, and when we select "Search in all local folder"
392 //Search button was never enabled :(
393 mBtnSearch->setEnabled( true );
394}
395
396//-----------------------------------------------------------------------------
398{
399 TQString genMsg, detailMsg, procMsg;
400 int numMatches = 0, numProcessed = 0;
401 KMSearch const *search = (mFolder) ? (mFolder->search()) : 0;
402 TQString folderName;
403 if (search) {
404 numMatches = search->foundCount();
405 numProcessed = search->searchCount();
406 folderName = search->currentFolder();
407 }
408
409 if (search && !search->running()) {
410 procMsg = i18n("%n message searched", "%n messages searched",
411 numProcessed);
412 if(!mStopped) {
413 genMsg = i18n("Done.");
414 detailMsg = i18n("%n match in %1", "%n matches in %1",
415 numMatches).arg(procMsg);
416 } else {
417 genMsg = i18n("Search canceled.");
418 detailMsg = i18n("%n match so far in %1", "%n matches so far in %1",
419 numMatches).arg(procMsg);
420 }
421 } else {
422 procMsg = i18n("%n message", "%n messages", numProcessed);
423 genMsg = i18n("%n match", "%n matches", numMatches);
424 detailMsg = i18n("Searching in %1. %2 searched so far")
425 .arg(folderName).arg(procMsg);
426 }
427
428 mStatusBar->changeItem(genMsg, 0);
429 mStatusBar->changeItem(detailMsg, 1);
430}
431
432
433//-----------------------------------------------------------------------------
434void SearchWindow::keyPressEvent(TQKeyEvent *evt)
435{
436 KMSearch const *search = (mFolder) ? mFolder->search() : 0;
437 bool searching = (search) ? search->running() : false;
438 if (evt->key() == Key_Escape && searching) {
439 mFolder->stopSearch();
440 return;
441 }
442
443 KDialogBase::keyPressEvent(evt);
444}
445
446
447//-----------------------------------------------------------------------------
448void SearchWindow::slotFolderActivated()
449{
450 mChkbxSpecificFolders->setChecked(true);
451}
452
453//-----------------------------------------------------------------------------
455{
456 mChkbxSpecificFolders->setChecked(true);
457 mCbxFolders->setFolder(curFolder);
458}
459
460//-----------------------------------------------------------------------------
461void SearchWindow::slotSearch()
462{
463 mLastFocus = focusWidget();
464 mBtnSearch->setFocus(); // set focus so we don't miss key event
465
466 mStopped = false;
467 mFetchingInProgress = 0;
468
469 mSearchFolderOpenBtn->setEnabled(true);
470 if ( mSearchFolderEdt->text().isEmpty() ) {
471 mSearchFolderEdt->setText( i18n("Last Search") );
472 }
473 mBtnSearch->setEnabled(false);
474 mBtnStop->setEnabled(true);
475
476 mLbxMatches->clear();
477
478 mSortColumn = mLbxMatches->sortColumn();
479 mSortOrder = mLbxMatches->sortOrder();
480 mLbxMatches->setSorting(-1);
481 mLbxMatches->setShowSortIndicator(false);
482
483 // If we haven't openend an existing search folder, find or
484 // create one.
485 if (!mFolder) {
486 KMFolderMgr *mgr = kmkernel->searchFolderMgr();
487 TQString baseName = mSearchFolderEdt->text();
488 TQString fullName = baseName;
489 int count = 0;
490 KMFolder *folder;
491 while ((folder = mgr->find(fullName))) {
492 if (folder->storage()->inherits("KMFolderSearch"))
493 break;
494 fullName = TQString("%1 %2").arg(baseName).arg(++count);
495 }
496
497 if (!folder)
498 folder = mgr->createFolder(fullName, false, KMFolderTypeSearch,
499 &mgr->dir());
500
501 mFolder = dynamic_cast<KMFolderSearch*>( folder->storage() );
502 }
503 mFolder->stopSearch();
504 disconnect(mFolder, TQ_SIGNAL(msgAdded(int)),
505 this, TQ_SLOT(slotAddMsg(int)));
506 disconnect(mFolder, TQ_SIGNAL(msgRemoved(KMFolder*, TQ_UINT32)),
507 this, TQ_SLOT(slotRemoveMsg(KMFolder*, TQ_UINT32)));
508 connect(mFolder, TQ_SIGNAL(msgAdded(int)),
509 this, TQ_SLOT(slotAddMsg(int)));
510 connect(mFolder, TQ_SIGNAL(msgRemoved(KMFolder*, TQ_UINT32)),
511 this, TQ_SLOT(slotRemoveMsg(KMFolder*, TQ_UINT32)));
512 mSearchFolderEdt->setEnabled(false);
513 KMSearch *search = new KMSearch();
514 connect(search, TQ_SIGNAL(finished(bool)),
515 this, TQ_SLOT(searchDone()));
516 if (mChkbxAllFolders->isChecked()) {
517 search->setRecursive(true);
518 } else {
519 search->setRoot(mCbxFolders->folder());
520 search->setRecursive(mChkSubFolders->isChecked());
521 }
522
523 mPatternEdit->updateSearchPattern();
524 KMSearchPattern *searchPattern = new KMSearchPattern();
525 *searchPattern = *mSearchPattern; //deep copy
526 searchPattern->purify();
527 search->setSearchPattern(searchPattern);
528 mFolder->setSearch(search);
529 enableGUI();
530
531 mTimer->start(200);
532}
533
534//-----------------------------------------------------------------------------
536{
537 mTimer->stop();
538 updStatus();
539
540 TQTimer::singleShot(0, this, TQ_SLOT(enableGUI()));
541 if(mLastFocus)
542 mLastFocus->setFocus();
543 if (mCloseRequested)
544 close();
545
546 mLbxMatches->setSorting(mSortColumn, mSortOrder == Ascending);
547 mLbxMatches->setShowSortIndicator(true);
548
549 mSearchFolderEdt->setEnabled(true);
550}
551
552void SearchWindow::slotAddMsg(int idx)
553{
554 if (!mFolder)
555 return;
556 bool unget = !mFolder->isMessage(idx);
557 KMMessage *msg = mFolder->getMsg(idx);
558 TQString from, fName;
559 KMFolder *pFolder = msg->parent();
560 if (!mFolders.contains(pFolder)) {
561 mFolders.append(pFolder);
562 pFolder->open("searchwindow");
563 }
564 if(pFolder->whoField() == "To")
565 from = msg->to();
566 else
567 from = msg->from();
568 if (pFolder->isSystemFolder())
569 fName = i18n(pFolder->name().utf8());
570 else
571 fName = pFolder->name();
572
573 (void)new TDEListViewItem(mLbxMatches, mLbxMatches->lastItem(),
574 msg->subject(), from, msg->dateIsoStr(),
575 fName,
576 TQString::number(mFolder->serNum(idx)));
577 if (unget)
578 mFolder->unGetMsg(idx);
579}
580
581void SearchWindow::slotRemoveMsg(KMFolder *, TQ_UINT32 serNum)
582{
583 if (!mFolder)
584 return;
585 TQListViewItemIterator it(mLbxMatches);
586 while (it.current()) {
587 TQListViewItem *item = *it;
588 if (serNum == (*it)->text(MSGID_COLUMN).toUInt()) {
589 delete item;
590 return;
591 }
592 ++it;
593 }
594}
595
596//-----------------------------------------------------------------------------
597void SearchWindow::slotStop()
598{
599 if (mFolder)
600 mFolder->stopSearch();
601 mStopped = true;
602 mBtnStop->setEnabled(false);
603}
604
605//-----------------------------------------------------------------------------
606void SearchWindow::slotClose()
607{
608 accept();
609}
610
611
612//-----------------------------------------------------------------------------
613void SearchWindow::closeEvent(TQCloseEvent *e)
614{
615 if (mFolder && mFolder->search() && mFolder->search()->running()) {
616 mCloseRequested = true;
617 //Cancel search in progress by setting the search folder search to
618 //the null search
619 mFolder->setSearch(new KMSearch());
620 TQTimer::singleShot(0, this, TQ_SLOT(slotClose()));
621 } else {
622 KDialogBase::closeEvent(e);
623 }
624}
625
626//-----------------------------------------------------------------------------
627void SearchWindow::scheduleRename( const TQString &s)
628{
629 if (!s.isEmpty() ) {
630 mRenameTimer.start(250, true);
631 mSearchFolderOpenBtn->setEnabled(false);
632 } else {
633 mRenameTimer.stop();
634 mSearchFolderOpenBtn->setEnabled(!s.isEmpty());
635 }
636}
637
638//-----------------------------------------------------------------------------
639void SearchWindow::renameSearchFolder()
640{
641 if (mFolder && (mFolder->folder()->name() != mSearchFolderEdt->text())) {
642 int i = 1;
643 TQString name = mSearchFolderEdt->text();
644 while (i < 100) {
645 if (!kmkernel->searchFolderMgr()->find( name )) {
646 mFolder->rename( name );
647 kmkernel->searchFolderMgr()->contentsChanged();
648 break;
649 }
650 name.setNum( i );
651 name = mSearchFolderEdt->text() + " " + name;
652 ++i;
653 }
654 }
655 if ( mFolder )
656 mSearchFolderOpenBtn->setEnabled(true);
657}
658
659void SearchWindow::openSearchFolder()
660{
661 Q_ASSERT( mFolder );
662 renameSearchFolder();
663 mKMMainWidget->slotSelectFolder( mFolder->folder() );
664 slotClose();
665}
666
667//-----------------------------------------------------------------------------
668void SearchWindow::folderInvalidated(KMFolder *folder)
669{
670 if (folder->storage() == mFolder) {
671 mLbxMatches->clear();
672 if (mFolder->search())
673 connect(mFolder->search(), TQ_SIGNAL(finished(bool)),
674 this, TQ_SLOT(searchDone()));
675 mTimer->start(200);
676 enableGUI();
677 }
678}
679
680//-----------------------------------------------------------------------------
681KMMessage *SearchWindow::indexToMessage( TQListViewItem *item )
682{
683 if( !item ) {
684 return 0;
685 }
686
687 KMFolder *folder;
688 int msgIndex;
689 KMMsgDict::instance()->getLocation( item->text( MSGID_COLUMN ).toUInt(),
690 &folder, &msgIndex );
691
692 if ( !folder || msgIndex < 0 ) {
693 return 0;
694 }
695
696 mKMMainWidget->slotSelectFolder( folder );
697 return folder->getMsg( msgIndex );
698}
699
700//-----------------------------------------------------------------------------
701bool SearchWindow::slotShowMsg( TQListViewItem *item )
702{
703 KMMessage *message = indexToMessage( item );
704 if ( message ) {
705 mKMMainWidget->slotSelectMessage( message );
706 return true;
707 }
708 return false;
709}
710
711//-----------------------------------------------------------------------------
712void SearchWindow::slotViewSelectedMsg()
713{
714 slotViewMsg( mLbxMatches->currentItem() );
715}
716
717//-----------------------------------------------------------------------------
718bool SearchWindow::slotViewMsg( TQListViewItem *item )
719{
720 KMMessage *message = indexToMessage( item );
721 if ( message ) {
722 mKMMainWidget->slotMsgActivated( message );
723 return true;
724 }
725 return false;
726}
727
728//-----------------------------------------------------------------------------
729void SearchWindow::slotCurrentChanged(TQListViewItem *item)
730{
731 mSearchResultOpenBtn->setEnabled(item!=0);
732}
733
734//-----------------------------------------------------------------------------
735void SearchWindow::enableGUI()
736{
737 KMSearch const *search = (mFolder) ? (mFolder->search()) : 0;
738 bool searching = (search) ? (search->running()) : false;
739 actionButton(KDialogBase::Close)->setEnabled(!searching);
740 mCbxFolders->setEnabled(!searching && !mChkbxAllFolders->isChecked());
741 mChkSubFolders->setEnabled(!searching && !mChkbxAllFolders->isChecked());
742 mChkbxAllFolders->setEnabled(!searching);
743 mChkbxSpecificFolders->setEnabled(!searching);
744 mPatternEdit->setEnabled(!searching);
745 mBtnSearch->setEnabled(!searching);
746 mBtnStop->setEnabled(searching);
747}
748
749
750//-----------------------------------------------------------------------------
752{
753 KMMessageList msgList;
754 KMFolder* folder = 0;
755 int msgIndex = -1;
756 for (TQListViewItemIterator it(mLbxMatches); it.current(); it++)
757 if (it.current()->isSelected()) {
758 KMMsgDict::instance()->getLocation((*it)->text(MSGID_COLUMN).toUInt(),
759 &folder, &msgIndex);
760 if (folder && msgIndex >= 0)
761 msgList.append(folder->getMsgBase(msgIndex));
762 }
763 return msgList;
764}
765
766//-----------------------------------------------------------------------------
768{
769 TQListViewItem *item = mLbxMatches->currentItem();
770 KMFolder* folder = 0;
771 int msgIndex = -1;
772 if (!item)
773 return 0;
774 KMMsgDict::instance()->getLocation(item->text(MSGID_COLUMN).toUInt(),
775 &folder, &msgIndex);
776 if (!folder || msgIndex < 0)
777 return 0;
778
779 return folder->getMsg(msgIndex);
780}
781
782//-----------------------------------------------------------------------------
783void SearchWindow::moveSelectedToFolder( int menuId )
784{
785 KMFolder *dest = mMenuToFolder[menuId];
786 if (!dest)
787 return;
788
789 KMMessageList msgList = selectedMessages();
790 KMCommand *command = new KMMoveCommand( dest, msgList );
791 command->start();
792}
793
794//-----------------------------------------------------------------------------
795void SearchWindow::copySelectedToFolder( int menuId )
796{
797 KMFolder *dest = mMenuToFolder[menuId];
798 if (!dest)
799 return;
800
801 KMMessageList msgList = selectedMessages();
802 KMCommand *command = new KMCopyCommand( dest, msgList );
803 command->start();
804}
805
806//-----------------------------------------------------------------------------
807void SearchWindow::updateContextMenuActions()
808{
809 int count = selectedMessages().count();
810 bool single_actions = count == 1;
811 mReplyAction->setEnabled( single_actions );
812 mReplyAllAction->setEnabled( single_actions );
813 mReplyListAction->setEnabled( single_actions );
814 mPrintAction->setEnabled( single_actions );
815 mForwardDigestAction->setEnabled( !single_actions );
816 mRedirectAction->setEnabled( single_actions );
817 mCopyAction->setEnabled( count > 0 );
818 mCutAction->setEnabled( count > 0 );
819}
820
821//-----------------------------------------------------------------------------
822void SearchWindow::slotContextMenuRequested( TQListViewItem *lvi, const TQPoint &, int )
823{
824 if (!lvi)
825 return;
826 mLbxMatches->setSelected( lvi, true );
827 mLbxMatches->setCurrentItem( lvi );
828 // FIXME is this ever unGetMsg()'d?
829 if (!message())
830 return;
831 TQPopupMenu *menu = new TQPopupMenu(this);
832 updateContextMenuActions();
833
834 mMenuToFolder.clear();
835 TQPopupMenu *msgMoveMenu = new TQPopupMenu(menu);
836 mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::MoveMessage,
837 this, &mMenuToFolder, msgMoveMenu );
838 TQPopupMenu *msgCopyMenu = new TQPopupMenu(menu);
839 mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::CopyMessage,
840 this, &mMenuToFolder, msgCopyMenu );
841
842 // show most used actions
843 mReplyAction->plug(menu);
844 mReplyAllAction->plug(menu);
845 mReplyListAction->plug(menu);
846 mForwardActionMenu->plug(menu);
847 menu->insertSeparator();
848 mCopyAction->plug(menu);
849 mCutAction->plug(menu);
850 menu->insertItem(i18n("&Copy To"), msgCopyMenu);
851 menu->insertItem(i18n("&Move To"), msgMoveMenu);
852 menu->insertSeparator();
853 mSaveAsAction->plug(menu);
854 mSaveAtchAction->plug(menu);
855 mPrintAction->plug(menu);
856 menu->insertSeparator();
857 mClearAction->plug(menu);
858 menu->exec (TQCursor::pos(), 0);
859 delete menu;
860}
861
862//-----------------------------------------------------------------------------
863void SearchWindow::slotClearSelection()
864{
865 mLbxMatches->clearSelection();
866}
867
868//-----------------------------------------------------------------------------
869void SearchWindow::slotReplyToMsg()
870{
871 KMCommand *command = new KMReplyToCommand(this, message());
872 command->start();
873}
874
875//-----------------------------------------------------------------------------
876void SearchWindow::slotReplyAllToMsg()
877{
878 KMCommand *command = new KMReplyToAllCommand(this, message());
879 command->start();
880}
881
882//-----------------------------------------------------------------------------
883void SearchWindow::slotReplyListToMsg()
884{
885 KMCommand *command = new KMReplyListCommand(this, message());
886 command->start();
887}
888
889//-----------------------------------------------------------------------------
890void SearchWindow::slotForwardInlineMsg()
891{
892 KMCommand *command = new KMForwardInlineCommand(this, selectedMessages());
893 command->start();
894}
895
896//-----------------------------------------------------------------------------
897void SearchWindow::slotForwardAttachedMsg()
898{
899 KMCommand *command = new KMForwardAttachedCommand(this, selectedMessages());
900 command->start();
901}
902
903//-----------------------------------------------------------------------------
904void SearchWindow::slotForwardDigestMsg()
905{
906 KMCommand *command = new KMForwardDigestCommand(this, selectedMessages());
907 command->start();
908}
909
910//-----------------------------------------------------------------------------
911void SearchWindow::slotRedirectMsg()
912{
913 KMCommand *command = new KMRedirectCommand(this, message());
914 command->start();
915}
916
917//-----------------------------------------------------------------------------
918void SearchWindow::slotSaveMsg()
919{
920 KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand(this,
922 if (saveCommand->url().isEmpty())
923 delete saveCommand;
924 else
925 saveCommand->start();
926}
927//-----------------------------------------------------------------------------
928void SearchWindow::slotSaveAttachments()
929{
930 KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand(this,
932 saveCommand->start();
933}
934
935
936//-----------------------------------------------------------------------------
937void SearchWindow::slotPrintMsg()
938{
939 KMCommand *command = new KMPrintCommand(this, message());
940 command->start();
941}
942
943void SearchWindow::slotCopyMsgs()
944{
945 TQValueList<TQ_UINT32> list = MessageCopyHelper::serNumListFromMsgList( selectedMessages() );
946 mKMMainWidget->headers()->setCopiedMessages( list, false );
947}
948
949void SearchWindow::slotCutMsgs()
950{
951 TQValueList<TQ_UINT32> list = MessageCopyHelper::serNumListFromMsgList( selectedMessages() );
952 mKMMainWidget->headers()->setCopiedMessages( list, true );
953}
954
955
956void SearchWindow::setSearchPattern( const KMSearchPattern& pattern )
957{
958 *mSearchPattern = pattern;
959 mPatternEdit->setSearchPattern( mSearchPattern );
960}
961
962} // namespace KMail
963#include "searchwindow.moc"
Mail folder.
Definition: kmfolder.h:69
TQString whoField() const
Get / set the name of the field that is used for the Sender/Receiver column in the headers (From/To)
Definition: kmfolder.h:396
bool isSystemFolder() const
Returns true if the folder is a kmail system folder.
Definition: kmfolder.h:369
KMMessage * getMsg(int idx)
Read message at given index.
Definition: kmfolder.cpp:321
const KMMsgBase * getMsgBase(int idx) const
Provides access to the basic message fields that are also stored in the index.
Definition: kmfolder.cpp:360
int open(const char *owner)
Open folder for access.
Definition: kmfolder.cpp:479
TQString location() const
Returns full path to folder file.
Definition: kmfolder.cpp:243
This is a Mime Message.
Definition: kmmessage.h:68
TQString from() const
Get or set the 'From' header field.
Definition: kmmessage.cpp:2015
TQString to() const
Get or set the 'To' header field.
Definition: kmmessage.cpp:1894
TQString subject() const
Get or set the 'Subject' header field.
Definition: kmmessage.cpp:2049
void getLocation(unsigned long key, KMFolder **retFolder, int *retIndex) const
Returns the folder the message represented by the serial number key is in and the index in that folde...
Definition: kmmsgdict.cpp:319
static const KMMsgDict * instance()
Access the globally unique MessageDict.
Definition: kmmsgdict.cpp:167
This widget is intended to be used in the filter configuration as well as in the message search dialo...
void updateSearchPattern()
Updates the search pattern according to the current widget values.
void setSearchPattern(KMSearchPattern *aPattern)
Set the search pattern.
This class is an abstraction of a search over messages.
void readConfig(const TDEConfig *config)
Reads a search pattern from a TDEConfig.
void purify()
Removes all empty rules from the list.
A widget that contains a KLineEdit which shows the current folder and a button that fires a KMFolderS...
KMFolder * folder(void) const
Returns selected folder.
void setFolder(KMFolder *)
Preset the folder.
void setMustBeReadWrite(bool readwrite)
Set if readonly folders should be disabled Be aware that if you disable this the user can also select...
static TQValueList< TQ_UINT32 > serNumListFromMsgList(TQPtrList< KMMsgBase > list)
Converts a KMMsgsBase* list into a serial number list.
virtual void searchDone()
GUI cleanup after search.
KMMessage * message()
Provides access to the currently selected message.
virtual void updStatus(void)
Update status line widget.
virtual void keyPressEvent(TQKeyEvent *)
Reimplemented to react to Escape.
SearchWindow(KMMainWidget *parent, const char *name=0, KMFolder *curFolder=0, bool modal=false)
Creates a new search window.
virtual void closeEvent(TQCloseEvent *)
Reimplemented to stop searching when the window is closed.
KMMessageList selectedMessages()
Provides access to the list of currently selected message in the listview.
void activateFolder(KMFolder *curFolder)
Changes the base folder for search operations to a different folder.
folderdiaquotatab.h
Definition: aboutdata.cpp:40