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>
58 using namespace KPIM;
59 
60 #include <mimelib/enum.h>
61 #include <mimelib/boyermor.h>
62 
63 #include <assert.h>
64 #include <stdlib.h>
65 
66 namespace KMail {
67 
68 const int SearchWindow::MSGID_COLUMN = 4;
69 
70 // TDEListView sub-class for dnd support
71 class 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 //-----------------------------------------------------------------------------
109 SearchWindow::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 #if !KDE_IS_VERSION( 3, 2, 91 )
125  // HACK - KWin keeps all dialogs on top of their mainwindows, but that's probably
126  // wrong (#76026), and should be done only for modals. CVS HEAD should get
127  // proper fix in KWin (l.lunak@kde.org)
128  XDeleteProperty( tqt_xdisplay(), winId(), XA_WM_TRANSIENT_FOR );
129 #endif
130  KWin::setIcons(winId(), kapp->icon(), kapp->miniIcon());
131 
132  TDEConfig* config = KMKernel::config();
133  config->setGroup("SearchDialog");
134 
135  TQWidget* searchWidget = new TQWidget(this);
136  TQVBoxLayout *vbl = new TQVBoxLayout( searchWidget, 0, spacingHint(), "kmfs_vbl" );
137 
138  TQButtonGroup * radioGroup = new TQButtonGroup( searchWidget );
139  radioGroup->hide();
140 
141  mChkbxAllFolders = new TQRadioButton(i18n("Search in &all local folders"), searchWidget);
142  vbl->addWidget( mChkbxAllFolders );
143  radioGroup->insert( mChkbxAllFolders );
144 
145  TQHBoxLayout *hbl = new TQHBoxLayout( vbl, spacingHint(), "kmfs_hbl" );
146  mChkbxSpecificFolders = new TQRadioButton(i18n("Search &only in:"), searchWidget);
147  hbl->addWidget(mChkbxSpecificFolders);
148  mChkbxSpecificFolders->setChecked(true);
149  radioGroup->insert( mChkbxSpecificFolders );
150 
151  mCbxFolders = new FolderRequester( searchWidget,
152  kmkernel->getKMMainWidget()->folderTree() );
153  mCbxFolders->setMustBeReadWrite( false );
154  mCbxFolders->setFolder(curFolder);
155  hbl->addWidget(mCbxFolders);
156 
157  mChkSubFolders = new TQCheckBox(i18n("I&nclude sub-folders"), searchWidget);
158  mChkSubFolders->setChecked(true);
159  hbl->addWidget(mChkSubFolders);
160 
161  TQWidget *spacer = new TQWidget( searchWidget, "spacer" );
162  spacer->setMinimumHeight( 2 );
163  vbl->addWidget( spacer );
164 
165  mPatternEdit = new KMSearchPatternEdit( "", searchWidget , "spe", false, true );
166  mPatternEdit->setFrameStyle( TQFrame::NoFrame | TQFrame::Plain );
167  mPatternEdit->setInsideMargin( 0 );
168  mSearchPattern = new KMSearchPattern();
169  KMFolderSearch *searchFolder = 0;
170  if (curFolder)
171  searchFolder = dynamic_cast<KMFolderSearch*>(curFolder->storage());
172  if (searchFolder) {
173  TDEConfig config(curFolder->location());
174  KMFolder *root = searchFolder->search()->root();
175  config.setGroup("Search Folder");
176  mSearchPattern->readConfig(&config);
177  if (root) {
178  mChkbxSpecificFolders->setChecked(true);
179  mCbxFolders->setFolder(root);
180  mChkSubFolders->setChecked(searchFolder->search()->recursive());
181  } else {
182  mChkbxAllFolders->setChecked(true);
183  }
184  }
185  mPatternEdit->setSearchPattern( mSearchPattern );
186  TQObjectList *list = mPatternEdit->queryList( 0, "mRuleField" );
187  TQObject *object = 0;
188  if ( list )
189  object = list->first();
190  delete list;
191  if (!searchFolder && object && ::tqt_cast<TQComboBox*>(object))
192  static_cast<TQComboBox*>(object)->setCurrentText(i18n("Subject"));
193 
194  vbl->addWidget( mPatternEdit );
195 
196  // enable/disable widgets depending on radio buttons:
197  connect( mChkbxSpecificFolders, TQ_SIGNAL(toggled(bool)),
198  mCbxFolders, TQ_SLOT(setEnabled(bool)) );
199  connect( mChkbxSpecificFolders, TQ_SIGNAL(toggled(bool)),
200  mChkSubFolders, TQ_SLOT(setEnabled(bool)) );
201  connect( mChkbxAllFolders, TQ_SIGNAL(toggled(bool)),
202  this, TQ_SLOT(setEnabledSearchButton(bool)) );
203 
204  mLbxMatches = new MatchListView(searchWidget, this, "Find Messages");
205 
206  /*
207  Default is to sort by date. TODO: Unfortunately this sorts *while*
208  inserting, which looks rather strange - the user cannot read
209  the results so far as they are constantly re-sorted --dnaber
210 
211  Sorting is now disabled when a search is started and reenabled
212  when it stops. Items are appended to the list. This not only
213  solves the above problem, but speeds searches with many hits
214  up considerably. - till
215 
216  TODO: subclass TDEListViewItem and do proper (and performant)
217  comapare functions
218  */
219  mLbxMatches->setSorting(2, false);
220  mLbxMatches->setShowSortIndicator(true);
221  mLbxMatches->setAllColumnsShowFocus(true);
222  mLbxMatches->setSelectionModeExt(TDEListView::Extended);
223  mLbxMatches->addColumn(i18n("Subject"),
224  config->readNumEntry("SubjectWidth", 150));
225  mLbxMatches->addColumn(i18n("Sender/Receiver"),
226  config->readNumEntry("SenderWidth", 120));
227  mLbxMatches->addColumn(i18n("Date"),
228  config->readNumEntry("DateWidth", 120));
229  mLbxMatches->addColumn(i18n("Folder"),
230  config->readNumEntry("FolderWidth", 100));
231 
232  mLbxMatches->addColumn(""); // should be hidden
233  mLbxMatches->setColumnWidthMode( MSGID_COLUMN, TQListView::Manual );
234  mLbxMatches->setColumnWidth(MSGID_COLUMN, 0);
235  mLbxMatches->header()->setResizeEnabled(false, MSGID_COLUMN);
236 
237  mLbxMatches->setDragEnabled( true );
238 
239  connect( mLbxMatches, TQ_SIGNAL(clicked(TQListViewItem *)),
240  this, TQ_SLOT(slotShowMsg(TQListViewItem *)) );
241  connect( mLbxMatches, TQ_SIGNAL(doubleClicked(TQListViewItem *)),
242  this, TQ_SLOT(slotViewMsg(TQListViewItem *)) );
243  connect( mLbxMatches, TQ_SIGNAL(currentChanged(TQListViewItem *)),
244  this, TQ_SLOT(slotCurrentChanged(TQListViewItem *)) );
245  connect( mLbxMatches, TQ_SIGNAL(contextMenuRequested(TQListViewItem *,const TQPoint &,int)),
246  this, TQ_SLOT(slotContextMenuRequested(TQListViewItem *,const TQPoint &,int)) );
247  vbl->addWidget( mLbxMatches );
248 
249  TQHBoxLayout *hbl2 = new TQHBoxLayout( vbl, spacingHint(), "kmfs_hbl2" );
250  mSearchFolderLbl = new TQLabel(i18n("Search folder &name:"), searchWidget);
251  hbl2->addWidget(mSearchFolderLbl);
252  mSearchFolderEdt = new KLineEdit(searchWidget);
253  if (searchFolder)
254  mSearchFolderEdt->setText(searchFolder->folder()->name());
255  else
256  mSearchFolderEdt->setText(i18n("Last Search"));
257 
258  mSearchFolderLbl->setBuddy(mSearchFolderEdt);
259  hbl2->addWidget(mSearchFolderEdt);
260  mSearchFolderOpenBtn = new TQPushButton(i18n("Op&en Search Folder"), searchWidget);
261  mSearchFolderOpenBtn->setEnabled(false);
262  hbl2->addWidget(mSearchFolderOpenBtn);
263  connect( mSearchFolderEdt, TQ_SIGNAL( textChanged( const TQString &)),
264  this, TQ_SLOT( scheduleRename( const TQString & )));
265  connect( &mRenameTimer, TQ_SIGNAL( timeout() ),
266  this, TQ_SLOT( renameSearchFolder() ));
267  connect( mSearchFolderOpenBtn, TQ_SIGNAL( clicked() ),
268  this, TQ_SLOT( openSearchFolder() ));
269  mSearchResultOpenBtn = new TQPushButton(i18n("Open &Message"), searchWidget);
270  mSearchResultOpenBtn->setEnabled(false);
271  hbl2->addWidget(mSearchResultOpenBtn);
272  connect( mSearchResultOpenBtn, TQ_SIGNAL( clicked() ),
273  this, TQ_SLOT( slotViewSelectedMsg() ));
274  mStatusBar = new KStatusBar(searchWidget);
275  mStatusBar->insertFixedItem(i18n("AMiddleLengthText..."), 0, true);
276  mStatusBar->changeItem(i18n("Ready."), 0);
277  mStatusBar->setItemAlignment(0, AlignLeft | AlignVCenter);
278  mStatusBar->insertItem(TQString(), 1, 1, true);
279  mStatusBar->setItemAlignment(1, AlignLeft | AlignVCenter);
280  vbl->addWidget(mStatusBar);
281 
282  int mainWidth = config->readNumEntry("SearchWidgetWidth", 0);
283  int mainHeight = config->readNumEntry("SearchWidgetHeight", 0);
284 
285  if (mainWidth || mainHeight)
286  resize(mainWidth, mainHeight);
287 
288  setMainWidget(searchWidget);
289  setButtonBoxOrientation(TQt::Vertical);
290 
291  mBtnSearch = actionButton(KDialogBase::User1);
292  mBtnStop = actionButton(KDialogBase::User2);
293  mBtnStop->setEnabled(false);
294 
295  connect(this, TQ_SIGNAL(user1Clicked()), TQ_SLOT(slotSearch()));
296  connect(this, TQ_SIGNAL(user2Clicked()), TQ_SLOT(slotStop()));
297  connect(this, TQ_SIGNAL(finished()), this, TQ_SLOT(deleteLater()));
298 
299  // give focus to the value field of the first search rule
300  object = mPatternEdit->child( "regExpLineEdit" );
301  if ( object && object->isWidgetType() ) {
302  static_cast<TQWidget*>(object)->setFocus();
303  //kdDebug(5006) << "SearchWindow: focus has been given to widget "
304  // << object->name() << endl;
305  }
306  else
307  kdDebug(5006) << "SearchWindow: regExpLineEdit not found" << endl;
308 
309  //set up actions
310  TDEActionCollection *ac = actionCollection();
311  ac->setWidget( this );
312  mReplyAction = new TDEAction( i18n("&Reply..."), "mail-reply-sender", 0, this,
313  TQ_SLOT(slotReplyToMsg()), ac, "search_reply" );
314  mReplyAllAction = new TDEAction( i18n("Reply to &All..."), "mail-reply-all",
315  0, this, TQ_SLOT(slotReplyAllToMsg()),
316  ac, "search_reply_all" );
317  mReplyListAction = new TDEAction( i18n("Reply to Mailing-&List..."),
318  "mail_replylist", 0, this,
319  TQ_SLOT(slotReplyListToMsg()), ac,
320  "search_reply_list" );
321  mForwardActionMenu = new TDEActionMenu( i18n("Message->","&Forward"),
322  "mail-forward", ac,
323  "search_message_forward" );
324  connect( mForwardActionMenu, TQ_SIGNAL(activated()), this,
325  TQ_SLOT(slotForwardInlineMsg()) );
326  mForwardAttachedAction = new TDEAction( i18n("Message->Forward->","As &Attachment..."),
327  "mail-forward", 0, this,
328  TQ_SLOT(slotForwardAttachedMsg()), ac,
329  "search_message_forward_as_attachment" );
330  mForwardInlineAction = new TDEAction( i18n("&Inline..."),
331  "mail-forward", 0, this,
332  TQ_SLOT(slotForwardInlineMsg()), ac,
333  "search_message_forward_inline" );
334  if ( GlobalSettings::self()->forwardingInlineByDefault() ) {
335  mForwardActionMenu->insert( mForwardInlineAction );
336  mForwardActionMenu->insert( mForwardAttachedAction );
337  } else {
338  mForwardActionMenu->insert( mForwardAttachedAction );
339  mForwardActionMenu->insert( mForwardInlineAction );
340  }
341 
342  mForwardDigestAction = new TDEAction( i18n("Message->Forward->","As Di&gest..."),
343  "mail-forward", 0, this,
344  TQ_SLOT(slotForwardDigestMsg()), ac,
345  "search_message_forward_as_digest" );
346  mForwardActionMenu->insert( mForwardDigestAction );
347  mRedirectAction = new TDEAction( i18n("Message->Forward->","&Redirect..."),
348  "mail-forward", 0, this,
349  TQ_SLOT(slotRedirectMsg()), ac,
350  "search_message_forward_redirect" );
351  mForwardActionMenu->insert( mRedirectAction );
352  mSaveAsAction = KStdAction::saveAs( this, TQ_SLOT(slotSaveMsg()), ac, "search_file_save_as" );
353  mSaveAtchAction = new TDEAction( i18n("Save Attachments..."), "attach", 0,
354  this, TQ_SLOT(slotSaveAttachments()), ac, "search_save_attachments" );
355 
356  mPrintAction = KStdAction::print( this, TQ_SLOT(slotPrintMsg()), ac, "search_print" );
357  mClearAction = new TDEAction( i18n("Clear Selection"), 0, 0, this,
358  TQ_SLOT(slotClearSelection()), ac, "search_clear_selection" );
359 
360  mCopyAction = KStdAction::copy( this, TQ_SLOT(slotCopyMsgs()), ac, "search_copy_messages" );
361  mCutAction = KStdAction::cut( this, TQ_SLOT(slotCutMsgs()), ac, "search_cut_messages" );
362 
363  connect(mTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(updStatus()));
364  connect(kmkernel->searchFolderMgr(), TQ_SIGNAL(folderInvalidated(KMFolder*)),
365  this, TQ_SLOT(folderInvalidated(KMFolder*)));
366 
367  connect(mCbxFolders, TQ_SIGNAL(folderChanged(KMFolder*)),
368  this, TQ_SLOT(slotFolderActivated()));
369 
370 }
371 
372 //-----------------------------------------------------------------------------
373 SearchWindow::~SearchWindow()
374 {
375  TQValueListIterator<TQGuardedPtr<KMFolder> > fit;
376  for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
377  if (!(*fit))
378  continue;
379  (*fit)->close("searchwindow");
380  }
381 
382  TDEConfig* config = KMKernel::config();
383  config->setGroup("SearchDialog");
384  config->writeEntry("SubjectWidth", mLbxMatches->columnWidth(0));
385  config->writeEntry("SenderWidth", mLbxMatches->columnWidth(1));
386  config->writeEntry("DateWidth", mLbxMatches->columnWidth(2));
387  config->writeEntry("FolderWidth", mLbxMatches->columnWidth(3));
388  config->writeEntry("SearchWidgetWidth", width());
389  config->writeEntry("SearchWidgetHeight", height());
390  config->sync();
391 }
392 
393 void SearchWindow::setEnabledSearchButton(bool)
394 {
395  //Make sure that button is enable
396  //Before when we selected a folder == "Local Folder" as that it was not a folder
397  //search button was disable, and when we select "Search in all local folder"
398  //Search button was never enabled :(
399  mBtnSearch->setEnabled( true );
400 }
401 
402 //-----------------------------------------------------------------------------
404 {
405  TQString genMsg, detailMsg, procMsg;
406  int numMatches = 0, numProcessed = 0;
407  KMSearch const *search = (mFolder) ? (mFolder->search()) : 0;
408  TQString folderName;
409  if (search) {
410  numMatches = search->foundCount();
411  numProcessed = search->searchCount();
412  folderName = search->currentFolder();
413  }
414 
415  if (search && !search->running()) {
416  procMsg = i18n("%n message searched", "%n messages searched",
417  numProcessed);
418  if(!mStopped) {
419  genMsg = i18n("Done.");
420  detailMsg = i18n("%n match in %1", "%n matches in %1",
421  numMatches).arg(procMsg);
422  } else {
423  genMsg = i18n("Search canceled.");
424  detailMsg = i18n("%n match so far in %1", "%n matches so far in %1",
425  numMatches).arg(procMsg);
426  }
427  } else {
428  procMsg = i18n("%n message", "%n messages", numProcessed);
429  genMsg = i18n("%n match", "%n matches", numMatches);
430  detailMsg = i18n("Searching in %1. %2 searched so far")
431  .arg(folderName).arg(procMsg);
432  }
433 
434  mStatusBar->changeItem(genMsg, 0);
435  mStatusBar->changeItem(detailMsg, 1);
436 }
437 
438 
439 //-----------------------------------------------------------------------------
440 void SearchWindow::keyPressEvent(TQKeyEvent *evt)
441 {
442  KMSearch const *search = (mFolder) ? mFolder->search() : 0;
443  bool searching = (search) ? search->running() : false;
444  if (evt->key() == Key_Escape && searching) {
445  mFolder->stopSearch();
446  return;
447  }
448 
449  KDialogBase::keyPressEvent(evt);
450 }
451 
452 
453 //-----------------------------------------------------------------------------
454 void SearchWindow::slotFolderActivated()
455 {
456  mChkbxSpecificFolders->setChecked(true);
457 }
458 
459 //-----------------------------------------------------------------------------
461 {
462  mChkbxSpecificFolders->setChecked(true);
463  mCbxFolders->setFolder(curFolder);
464 }
465 
466 //-----------------------------------------------------------------------------
467 void SearchWindow::slotSearch()
468 {
469  mLastFocus = focusWidget();
470  mBtnSearch->setFocus(); // set focus so we don't miss key event
471 
472  mStopped = false;
473  mFetchingInProgress = 0;
474 
475  mSearchFolderOpenBtn->setEnabled(true);
476  if ( mSearchFolderEdt->text().isEmpty() ) {
477  mSearchFolderEdt->setText( i18n("Last Search") );
478  }
479  mBtnSearch->setEnabled(false);
480  mBtnStop->setEnabled(true);
481 
482  mLbxMatches->clear();
483 
484  mSortColumn = mLbxMatches->sortColumn();
485  mSortOrder = mLbxMatches->sortOrder();
486  mLbxMatches->setSorting(-1);
487  mLbxMatches->setShowSortIndicator(false);
488 
489  // If we haven't openend an existing search folder, find or
490  // create one.
491  if (!mFolder) {
492  KMFolderMgr *mgr = kmkernel->searchFolderMgr();
493  TQString baseName = mSearchFolderEdt->text();
494  TQString fullName = baseName;
495  int count = 0;
496  KMFolder *folder;
497  while ((folder = mgr->find(fullName))) {
498  if (folder->storage()->inherits("KMFolderSearch"))
499  break;
500  fullName = TQString("%1 %2").arg(baseName).arg(++count);
501  }
502 
503  if (!folder)
504  folder = mgr->createFolder(fullName, false, KMFolderTypeSearch,
505  &mgr->dir());
506 
507  mFolder = dynamic_cast<KMFolderSearch*>( folder->storage() );
508  }
509  mFolder->stopSearch();
510  disconnect(mFolder, TQ_SIGNAL(msgAdded(int)),
511  this, TQ_SLOT(slotAddMsg(int)));
512  disconnect(mFolder, TQ_SIGNAL(msgRemoved(KMFolder*, TQ_UINT32)),
513  this, TQ_SLOT(slotRemoveMsg(KMFolder*, TQ_UINT32)));
514  connect(mFolder, TQ_SIGNAL(msgAdded(int)),
515  this, TQ_SLOT(slotAddMsg(int)));
516  connect(mFolder, TQ_SIGNAL(msgRemoved(KMFolder*, TQ_UINT32)),
517  this, TQ_SLOT(slotRemoveMsg(KMFolder*, TQ_UINT32)));
518  mSearchFolderEdt->setEnabled(false);
519  KMSearch *search = new KMSearch();
520  connect(search, TQ_SIGNAL(finished(bool)),
521  this, TQ_SLOT(searchDone()));
522  if (mChkbxAllFolders->isChecked()) {
523  search->setRecursive(true);
524  } else {
525  search->setRoot(mCbxFolders->folder());
526  search->setRecursive(mChkSubFolders->isChecked());
527  }
528 
529  mPatternEdit->updateSearchPattern();
530  KMSearchPattern *searchPattern = new KMSearchPattern();
531  *searchPattern = *mSearchPattern; //deep copy
532  searchPattern->purify();
533  search->setSearchPattern(searchPattern);
534  mFolder->setSearch(search);
535  enableGUI();
536 
537  mTimer->start(200);
538 }
539 
540 //-----------------------------------------------------------------------------
542 {
543  mTimer->stop();
544  updStatus();
545 
546  TQTimer::singleShot(0, this, TQ_SLOT(enableGUI()));
547  if(mLastFocus)
548  mLastFocus->setFocus();
549  if (mCloseRequested)
550  close();
551 
552  mLbxMatches->setSorting(mSortColumn, mSortOrder == Ascending);
553  mLbxMatches->setShowSortIndicator(true);
554 
555  mSearchFolderEdt->setEnabled(true);
556 }
557 
558 void SearchWindow::slotAddMsg(int idx)
559 {
560  if (!mFolder)
561  return;
562  bool unget = !mFolder->isMessage(idx);
563  KMMessage *msg = mFolder->getMsg(idx);
564  TQString from, fName;
565  KMFolder *pFolder = msg->parent();
566  if (!mFolders.contains(pFolder)) {
567  mFolders.append(pFolder);
568  pFolder->open("searchwindow");
569  }
570  if(pFolder->whoField() == "To")
571  from = msg->to();
572  else
573  from = msg->from();
574  if (pFolder->isSystemFolder())
575  fName = i18n(pFolder->name().utf8());
576  else
577  fName = pFolder->name();
578 
579  (void)new TDEListViewItem(mLbxMatches, mLbxMatches->lastItem(),
580  msg->subject(), from, msg->dateIsoStr(),
581  fName,
582  TQString::number(mFolder->serNum(idx)));
583  if (unget)
584  mFolder->unGetMsg(idx);
585 }
586 
587 void SearchWindow::slotRemoveMsg(KMFolder *, TQ_UINT32 serNum)
588 {
589  if (!mFolder)
590  return;
591  TQListViewItemIterator it(mLbxMatches);
592  while (it.current()) {
593  TQListViewItem *item = *it;
594  if (serNum == (*it)->text(MSGID_COLUMN).toUInt()) {
595  delete item;
596  return;
597  }
598  ++it;
599  }
600 }
601 
602 //-----------------------------------------------------------------------------
603 void SearchWindow::slotStop()
604 {
605  if (mFolder)
606  mFolder->stopSearch();
607  mStopped = true;
608  mBtnStop->setEnabled(false);
609 }
610 
611 //-----------------------------------------------------------------------------
612 void SearchWindow::slotClose()
613 {
614  accept();
615 }
616 
617 
618 //-----------------------------------------------------------------------------
619 void SearchWindow::closeEvent(TQCloseEvent *e)
620 {
621  if (mFolder && mFolder->search() && mFolder->search()->running()) {
622  mCloseRequested = true;
623  //Cancel search in progress by setting the search folder search to
624  //the null search
625  mFolder->setSearch(new KMSearch());
626  TQTimer::singleShot(0, this, TQ_SLOT(slotClose()));
627  } else {
628  KDialogBase::closeEvent(e);
629  }
630 }
631 
632 //-----------------------------------------------------------------------------
633 void SearchWindow::scheduleRename( const TQString &s)
634 {
635  if (!s.isEmpty() ) {
636  mRenameTimer.start(250, true);
637  mSearchFolderOpenBtn->setEnabled(false);
638  } else {
639  mRenameTimer.stop();
640  mSearchFolderOpenBtn->setEnabled(!s.isEmpty());
641  }
642 }
643 
644 //-----------------------------------------------------------------------------
645 void SearchWindow::renameSearchFolder()
646 {
647  if (mFolder && (mFolder->folder()->name() != mSearchFolderEdt->text())) {
648  int i = 1;
649  TQString name = mSearchFolderEdt->text();
650  while (i < 100) {
651  if (!kmkernel->searchFolderMgr()->find( name )) {
652  mFolder->rename( name );
653  kmkernel->searchFolderMgr()->contentsChanged();
654  break;
655  }
656  name.setNum( i );
657  name = mSearchFolderEdt->text() + " " + name;
658  ++i;
659  }
660  }
661  if ( mFolder )
662  mSearchFolderOpenBtn->setEnabled(true);
663 }
664 
665 void SearchWindow::openSearchFolder()
666 {
667  Q_ASSERT( mFolder );
668  renameSearchFolder();
669  mKMMainWidget->slotSelectFolder( mFolder->folder() );
670  slotClose();
671 }
672 
673 //-----------------------------------------------------------------------------
674 void SearchWindow::folderInvalidated(KMFolder *folder)
675 {
676  if (folder->storage() == mFolder) {
677  mLbxMatches->clear();
678  if (mFolder->search())
679  connect(mFolder->search(), TQ_SIGNAL(finished(bool)),
680  this, TQ_SLOT(searchDone()));
681  mTimer->start(200);
682  enableGUI();
683  }
684 }
685 
686 //-----------------------------------------------------------------------------
687 KMMessage *SearchWindow::indexToMessage( TQListViewItem *item )
688 {
689  if( !item ) {
690  return 0;
691  }
692 
693  KMFolder *folder;
694  int msgIndex;
695  KMMsgDict::instance()->getLocation( item->text( MSGID_COLUMN ).toUInt(),
696  &folder, &msgIndex );
697 
698  if ( !folder || msgIndex < 0 ) {
699  return 0;
700  }
701 
702  mKMMainWidget->slotSelectFolder( folder );
703  return folder->getMsg( msgIndex );
704 }
705 
706 //-----------------------------------------------------------------------------
707 bool SearchWindow::slotShowMsg( TQListViewItem *item )
708 {
709  KMMessage *message = indexToMessage( item );
710  if ( message ) {
711  mKMMainWidget->slotSelectMessage( message );
712  return true;
713  }
714  return false;
715 }
716 
717 //-----------------------------------------------------------------------------
718 void SearchWindow::slotViewSelectedMsg()
719 {
720  slotViewMsg( mLbxMatches->currentItem() );
721 }
722 
723 //-----------------------------------------------------------------------------
724 bool SearchWindow::slotViewMsg( TQListViewItem *item )
725 {
726  KMMessage *message = indexToMessage( item );
727  if ( message ) {
728  mKMMainWidget->slotMsgActivated( message );
729  return true;
730  }
731  return false;
732 }
733 
734 //-----------------------------------------------------------------------------
735 void SearchWindow::slotCurrentChanged(TQListViewItem *item)
736 {
737  mSearchResultOpenBtn->setEnabled(item!=0);
738 }
739 
740 //-----------------------------------------------------------------------------
741 void SearchWindow::enableGUI()
742 {
743  KMSearch const *search = (mFolder) ? (mFolder->search()) : 0;
744  bool searching = (search) ? (search->running()) : false;
745  actionButton(KDialogBase::Close)->setEnabled(!searching);
746  mCbxFolders->setEnabled(!searching && !mChkbxAllFolders->isChecked());
747  mChkSubFolders->setEnabled(!searching && !mChkbxAllFolders->isChecked());
748  mChkbxAllFolders->setEnabled(!searching);
749  mChkbxSpecificFolders->setEnabled(!searching);
750  mPatternEdit->setEnabled(!searching);
751  mBtnSearch->setEnabled(!searching);
752  mBtnStop->setEnabled(searching);
753 }
754 
755 
756 //-----------------------------------------------------------------------------
758 {
759  KMMessageList msgList;
760  KMFolder* folder = 0;
761  int msgIndex = -1;
762  for (TQListViewItemIterator it(mLbxMatches); it.current(); it++)
763  if (it.current()->isSelected()) {
764  KMMsgDict::instance()->getLocation((*it)->text(MSGID_COLUMN).toUInt(),
765  &folder, &msgIndex);
766  if (folder && msgIndex >= 0)
767  msgList.append(folder->getMsgBase(msgIndex));
768  }
769  return msgList;
770 }
771 
772 //-----------------------------------------------------------------------------
774 {
775  TQListViewItem *item = mLbxMatches->currentItem();
776  KMFolder* folder = 0;
777  int msgIndex = -1;
778  if (!item)
779  return 0;
780  KMMsgDict::instance()->getLocation(item->text(MSGID_COLUMN).toUInt(),
781  &folder, &msgIndex);
782  if (!folder || msgIndex < 0)
783  return 0;
784 
785  return folder->getMsg(msgIndex);
786 }
787 
788 //-----------------------------------------------------------------------------
789 void SearchWindow::moveSelectedToFolder( int menuId )
790 {
791  KMFolder *dest = mMenuToFolder[menuId];
792  if (!dest)
793  return;
794 
795  KMMessageList msgList = selectedMessages();
796  KMCommand *command = new KMMoveCommand( dest, msgList );
797  command->start();
798 }
799 
800 //-----------------------------------------------------------------------------
801 void SearchWindow::copySelectedToFolder( int menuId )
802 {
803  KMFolder *dest = mMenuToFolder[menuId];
804  if (!dest)
805  return;
806 
807  KMMessageList msgList = selectedMessages();
808  KMCommand *command = new KMCopyCommand( dest, msgList );
809  command->start();
810 }
811 
812 //-----------------------------------------------------------------------------
813 void SearchWindow::updateContextMenuActions()
814 {
815  int count = selectedMessages().count();
816  bool single_actions = count == 1;
817  mReplyAction->setEnabled( single_actions );
818  mReplyAllAction->setEnabled( single_actions );
819  mReplyListAction->setEnabled( single_actions );
820  mPrintAction->setEnabled( single_actions );
821  mForwardDigestAction->setEnabled( !single_actions );
822  mRedirectAction->setEnabled( single_actions );
823  mCopyAction->setEnabled( count > 0 );
824  mCutAction->setEnabled( count > 0 );
825 }
826 
827 //-----------------------------------------------------------------------------
828 void SearchWindow::slotContextMenuRequested( TQListViewItem *lvi, const TQPoint &, int )
829 {
830  if (!lvi)
831  return;
832  mLbxMatches->setSelected( lvi, true );
833  mLbxMatches->setCurrentItem( lvi );
834  // FIXME is this ever unGetMsg()'d?
835  if (!message())
836  return;
837  TQPopupMenu *menu = new TQPopupMenu(this);
838  updateContextMenuActions();
839 
840  mMenuToFolder.clear();
841  TQPopupMenu *msgMoveMenu = new TQPopupMenu(menu);
842  mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::MoveMessage,
843  this, &mMenuToFolder, msgMoveMenu );
844  TQPopupMenu *msgCopyMenu = new TQPopupMenu(menu);
845  mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::CopyMessage,
846  this, &mMenuToFolder, msgCopyMenu );
847 
848  // show most used actions
849  mReplyAction->plug(menu);
850  mReplyAllAction->plug(menu);
851  mReplyListAction->plug(menu);
852  mForwardActionMenu->plug(menu);
853  menu->insertSeparator();
854  mCopyAction->plug(menu);
855  mCutAction->plug(menu);
856  menu->insertItem(i18n("&Copy To"), msgCopyMenu);
857  menu->insertItem(i18n("&Move To"), msgMoveMenu);
858  menu->insertSeparator();
859  mSaveAsAction->plug(menu);
860  mSaveAtchAction->plug(menu);
861  mPrintAction->plug(menu);
862  menu->insertSeparator();
863  mClearAction->plug(menu);
864  menu->exec (TQCursor::pos(), 0);
865  delete menu;
866 }
867 
868 //-----------------------------------------------------------------------------
869 void SearchWindow::slotClearSelection()
870 {
871  mLbxMatches->clearSelection();
872 }
873 
874 //-----------------------------------------------------------------------------
875 void SearchWindow::slotReplyToMsg()
876 {
877  KMCommand *command = new KMReplyToCommand(this, message());
878  command->start();
879 }
880 
881 //-----------------------------------------------------------------------------
882 void SearchWindow::slotReplyAllToMsg()
883 {
884  KMCommand *command = new KMReplyToAllCommand(this, message());
885  command->start();
886 }
887 
888 //-----------------------------------------------------------------------------
889 void SearchWindow::slotReplyListToMsg()
890 {
891  KMCommand *command = new KMReplyListCommand(this, message());
892  command->start();
893 }
894 
895 //-----------------------------------------------------------------------------
896 void SearchWindow::slotForwardInlineMsg()
897 {
898  KMCommand *command = new KMForwardInlineCommand(this, selectedMessages());
899  command->start();
900 }
901 
902 //-----------------------------------------------------------------------------
903 void SearchWindow::slotForwardAttachedMsg()
904 {
905  KMCommand *command = new KMForwardAttachedCommand(this, selectedMessages());
906  command->start();
907 }
908 
909 //-----------------------------------------------------------------------------
910 void SearchWindow::slotForwardDigestMsg()
911 {
912  KMCommand *command = new KMForwardDigestCommand(this, selectedMessages());
913  command->start();
914 }
915 
916 //-----------------------------------------------------------------------------
917 void SearchWindow::slotRedirectMsg()
918 {
919  KMCommand *command = new KMRedirectCommand(this, message());
920  command->start();
921 }
922 
923 //-----------------------------------------------------------------------------
924 void SearchWindow::slotSaveMsg()
925 {
926  KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand(this,
927  selectedMessages());
928  if (saveCommand->url().isEmpty())
929  delete saveCommand;
930  else
931  saveCommand->start();
932 }
933 //-----------------------------------------------------------------------------
934 void SearchWindow::slotSaveAttachments()
935 {
936  KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand(this,
937  selectedMessages());
938  saveCommand->start();
939 }
940 
941 
942 //-----------------------------------------------------------------------------
943 void SearchWindow::slotPrintMsg()
944 {
945  KMCommand *command = new KMPrintCommand(this, message());
946  command->start();
947 }
948 
949 void SearchWindow::slotCopyMsgs()
950 {
951  TQValueList<TQ_UINT32> list = MessageCopyHelper::serNumListFromMsgList( selectedMessages() );
952  mKMMainWidget->headers()->setCopiedMessages( list, false );
953 }
954 
955 void SearchWindow::slotCutMsgs()
956 {
957  TQValueList<TQ_UINT32> list = MessageCopyHelper::serNumListFromMsgList( selectedMessages() );
958  mKMMainWidget->headers()->setCopiedMessages( list, true );
959 }
960 
961 
962 void SearchWindow::setSearchPattern( const KMSearchPattern& pattern )
963 {
964  *mSearchPattern = pattern;
965  mPatternEdit->setSearchPattern( mSearchPattern );
966 }
967 
968 } // namespace KMail
969 #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.
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