kmail

searchwindow.cpp

00001 /*
00002  * kmail: KDE mail client
00003  * Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
00004  * Copyright (c) 2001 Aaron J. Seigo <aseigo@kde.org>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  */
00021 #include <config.h>
00022 #include "kmcommands.h"
00023 #include "searchwindow.h"
00024 #include "kmmainwidget.h"
00025 #include "kmmsgdict.h"
00026 #include "kmmsgpart.h"
00027 #include "kmfolderimap.h"
00028 #include "kmfoldermgr.h"
00029 #include "kmfoldersearch.h"
00030 #include "kmfoldertree.h"
00031 #include "kmheaders.h"
00032 #include "kmsearchpatternedit.h"
00033 #include "kmsearchpattern.h"
00034 #include "folderrequester.h"
00035 #include "messagecopyhelper.h"
00036 #include "textsource.h"
00037 
00038 #include <kapplication.h>
00039 #include <kdebug.h>
00040 #include <kstatusbar.h>
00041 #include <kwin.h>
00042 #include <kconfig.h>
00043 #include <kstdaction.h>
00044 #include <kiconloader.h>
00045 
00046 #include <qcheckbox.h>
00047 #include <qlayout.h>
00048 #include <klineedit.h>
00049 #include <qpushbutton.h>
00050 #include <qradiobutton.h>
00051 #include <qbuttongroup.h>
00052 #include <qcombobox.h>
00053 #include <qobjectlist.h> //for mPatternEdit->queryList( 0, "mRuleField" )->first();
00054 #include <qcursor.h>
00055 #include <qpopupmenu.h>
00056 
00057 #include <maillistdrag.h>
00058 using namespace KPIM;
00059 
00060 #include <mimelib/enum.h>
00061 #include <mimelib/boyermor.h>
00062 
00063 #include <assert.h>
00064 #include <stdlib.h>
00065 
00066 namespace KMail {
00067 
00068 const int SearchWindow::MSGID_COLUMN = 4;
00069 
00070 // KListView sub-class for dnd support
00071 class MatchListView : public KListView
00072 {
00073   public:
00074     MatchListView( QWidget *parent, SearchWindow* sw, const char* name = 0 ) :
00075       KListView( parent, name ),
00076       mSearchWindow( sw )
00077     {}
00078 
00079   protected:
00080     virtual QDragObject* dragObject()
00081     {
00082       KMMessageList list = mSearchWindow->selectedMessages();
00083       MailList mailList;
00084       for ( KMMsgBase* msg = list.first(); msg; msg = list.next() ) {
00085         if ( !msg )
00086           continue;
00087         MailSummary mailSummary( msg->getMsgSerNum(), msg->msgIdMD5(),
00088                                  msg->subject(), msg->fromStrip(),
00089                                  msg->toStrip(), msg->date() );
00090         mailList.append( mailSummary );
00091       }
00092       MailListDrag *d = new MailListDrag( mailList, viewport(), new KMTextSource );
00093 
00094       QPixmap pixmap;
00095       if( mailList.count() == 1 )
00096         pixmap = QPixmap( DesktopIcon("message", KIcon::SizeSmall) );
00097       else
00098         pixmap = QPixmap( DesktopIcon("kmultiple", KIcon::SizeSmall) );
00099 
00100       d->setPixmap( pixmap );
00101       return d;
00102     }
00103 
00104   private:
00105     SearchWindow* mSearchWindow;
00106 };
00107 
00108 //-----------------------------------------------------------------------------
00109 SearchWindow::SearchWindow(KMMainWidget* w, const char* name,
00110                          KMFolder *curFolder, bool modal):
00111   KDialogBase(0, name, modal, i18n("Find Messages"),
00112               User1 | User2 | Close, User1, false,
00113               KGuiItem( i18n("&Search"), "find" ),
00114               KStdGuiItem::stop()),
00115   mStopped(false),
00116   mCloseRequested(false),
00117   mSortColumn(0),
00118   mSortOrder(Ascending),
00119   mFolder(0),
00120   mTimer(new QTimer(this, "mTimer")),
00121   mLastFocus(0),
00122   mKMMainWidget(w)
00123 {
00124 #if !KDE_IS_VERSION( 3, 2, 91 )
00125   // HACK - KWin keeps all dialogs on top of their mainwindows, but that's probably
00126   // wrong (#76026), and should be done only for modals. CVS HEAD should get
00127   // proper fix in KWin (l.lunak@kde.org)
00128   XDeleteProperty( qt_xdisplay(), winId(), XA_WM_TRANSIENT_FOR );
00129 #endif
00130   KWin::setIcons(winId(), kapp->icon(), kapp->miniIcon());
00131 
00132   KConfig* config = KMKernel::config();
00133   config->setGroup("SearchDialog");
00134 
00135   QWidget* searchWidget = new QWidget(this);
00136   QVBoxLayout *vbl = new QVBoxLayout( searchWidget, 0, spacingHint(), "kmfs_vbl" );
00137 
00138   QButtonGroup * radioGroup = new QButtonGroup( searchWidget );
00139   radioGroup->hide();
00140 
00141   mChkbxAllFolders = new QRadioButton(i18n("Search in &all local folders"), searchWidget);
00142   vbl->addWidget( mChkbxAllFolders );
00143   radioGroup->insert( mChkbxAllFolders );
00144 
00145   QHBoxLayout *hbl = new QHBoxLayout( vbl, spacingHint(), "kmfs_hbl" );
00146   mChkbxSpecificFolders = new QRadioButton(i18n("Search &only in:"), searchWidget);
00147   hbl->addWidget(mChkbxSpecificFolders);
00148   mChkbxSpecificFolders->setChecked(true);
00149   radioGroup->insert( mChkbxSpecificFolders );
00150 
00151   mCbxFolders = new FolderRequester( searchWidget,
00152       kmkernel->getKMMainWidget()->folderTree() );
00153   mCbxFolders->setMustBeReadWrite( false );
00154   mCbxFolders->setFolder(curFolder);
00155   hbl->addWidget(mCbxFolders);
00156 
00157   mChkSubFolders = new QCheckBox(i18n("I&nclude sub-folders"), searchWidget);
00158   mChkSubFolders->setChecked(true);
00159   hbl->addWidget(mChkSubFolders);
00160 
00161   QWidget *spacer = new QWidget( searchWidget, "spacer" );
00162   spacer->setMinimumHeight( 2 );
00163   vbl->addWidget( spacer );
00164 
00165   mPatternEdit = new KMSearchPatternEdit( "", searchWidget , "spe", false, true );
00166   mPatternEdit->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
00167   mPatternEdit->setInsideMargin( 0 );
00168   mSearchPattern = new KMSearchPattern();
00169   KMFolderSearch *searchFolder = 0;
00170   if (curFolder)
00171       searchFolder = dynamic_cast<KMFolderSearch*>(curFolder->storage());
00172   if (searchFolder) {
00173       KConfig config(curFolder->location());
00174       KMFolder *root = searchFolder->search()->root();
00175       config.setGroup("Search Folder");
00176       mSearchPattern->readConfig(&config);
00177       if (root) {
00178           mChkbxSpecificFolders->setChecked(true);
00179           mCbxFolders->setFolder(root);
00180           mChkSubFolders->setChecked(searchFolder->search()->recursive());
00181       } else {
00182           mChkbxAllFolders->setChecked(true);
00183       }
00184       mFolder = searchFolder;
00185   }
00186   mPatternEdit->setSearchPattern( mSearchPattern );
00187   QObjectList *list = mPatternEdit->queryList( 0, "mRuleField" );
00188   QObject *object = 0;
00189   if ( list )
00190       object = list->first();
00191   delete list;
00192   if (!searchFolder && object && ::qt_cast<QComboBox*>(object))
00193       static_cast<QComboBox*>(object)->setCurrentText("Subject");
00194 
00195   vbl->addWidget( mPatternEdit );
00196 
00197   // enable/disable widgets depending on radio buttons:
00198   connect( mChkbxSpecificFolders, SIGNAL(toggled(bool)),
00199            mCbxFolders, SLOT(setEnabled(bool)) );
00200   connect( mChkbxSpecificFolders, SIGNAL(toggled(bool)),
00201            mChkSubFolders, SLOT(setEnabled(bool)) );
00202   connect( mChkbxAllFolders, SIGNAL(toggled(bool)),
00203            this, SLOT(setEnabledSearchButton(bool)) );
00204 
00205   mLbxMatches = new MatchListView(searchWidget, this, "Find Messages");
00206 
00207   /*
00208      Default is to sort by date. TODO: Unfortunately this sorts *while*
00209      inserting, which looks rather strange - the user cannot read
00210      the results so far as they are constantly re-sorted --dnaber
00211 
00212      Sorting is now disabled when a search is started and reenabled
00213      when it stops. Items are appended to the list. This not only
00214      solves the above problem, but speeds searches with many hits
00215      up considerably. - till
00216 
00217      TODO: subclass KListViewItem and do proper (and performant)
00218      comapare functions
00219   */
00220   mLbxMatches->setSorting(2, false);
00221   mLbxMatches->setShowSortIndicator(true);
00222   mLbxMatches->setAllColumnsShowFocus(true);
00223   mLbxMatches->setSelectionModeExt(KListView::Extended);
00224   mLbxMatches->addColumn(i18n("Subject"),
00225                          config->readNumEntry("SubjectWidth", 150));
00226   mLbxMatches->addColumn(i18n("Sender/Receiver"),
00227                          config->readNumEntry("SenderWidth", 120));
00228   mLbxMatches->addColumn(i18n("Date"),
00229                          config->readNumEntry("DateWidth", 120));
00230   mLbxMatches->addColumn(i18n("Folder"),
00231                          config->readNumEntry("FolderWidth", 100));
00232 
00233   mLbxMatches->addColumn(""); // should be hidden
00234   mLbxMatches->setColumnWidthMode( MSGID_COLUMN, QListView::Manual );
00235   mLbxMatches->setColumnWidth(MSGID_COLUMN, 0);
00236   mLbxMatches->header()->setResizeEnabled(false, MSGID_COLUMN);
00237 
00238   mLbxMatches->setDragEnabled( true );
00239 
00240   connect(mLbxMatches, SIGNAL(doubleClicked(QListViewItem *)),
00241           this, SLOT(slotShowMsg(QListViewItem *)));
00242   connect( mLbxMatches, SIGNAL( contextMenuRequested( QListViewItem*, const QPoint &, int )),
00243            this, SLOT( slotContextMenuRequested( QListViewItem*, const QPoint &, int )));
00244   vbl->addWidget(mLbxMatches);
00245 
00246   QHBoxLayout *hbl2 = new QHBoxLayout( vbl, spacingHint(), "kmfs_hbl2" );
00247   mSearchFolderLbl = new QLabel(i18n("Search folder &name:"), searchWidget);
00248   hbl2->addWidget(mSearchFolderLbl);
00249   mSearchFolderEdt = new KLineEdit(searchWidget);
00250   if (searchFolder)
00251     mSearchFolderEdt->setText(searchFolder->folder()->name());
00252   else
00253     mSearchFolderEdt->setText(i18n("Last Search"));
00254 
00255   mSearchFolderLbl->setBuddy(mSearchFolderEdt);
00256   hbl2->addWidget(mSearchFolderEdt);
00257   mSearchFolderBtn = new QPushButton(i18n("&Rename"), searchWidget);
00258   mSearchFolderBtn->setEnabled(false);
00259   hbl2->addWidget(mSearchFolderBtn);
00260   mSearchFolderOpenBtn = new QPushButton(i18n("Op&en"), searchWidget);
00261   mSearchFolderOpenBtn->setEnabled(false);
00262   hbl2->addWidget(mSearchFolderOpenBtn);
00263   connect( mSearchFolderEdt, SIGNAL( textChanged( const QString &)),
00264            this, SLOT( updateCreateButton( const QString & )));
00265   connect( mSearchFolderBtn, SIGNAL( clicked() ),
00266            this, SLOT( renameSearchFolder() ));
00267   connect( mSearchFolderOpenBtn, SIGNAL( clicked() ),
00268            this, SLOT( openSearchFolder() ));
00269   mStatusBar = new KStatusBar(searchWidget);
00270   mStatusBar->insertFixedItem(i18n("AMiddleLengthText..."), 0, true);
00271   mStatusBar->changeItem(i18n("Ready."), 0);
00272   mStatusBar->setItemAlignment(0, AlignLeft | AlignVCenter);
00273   mStatusBar->insertItem(QString::null, 1, 1, true);
00274   mStatusBar->setItemAlignment(1, AlignLeft | AlignVCenter);
00275   vbl->addWidget(mStatusBar);
00276 
00277   int mainWidth = config->readNumEntry("SearchWidgetWidth", 0);
00278   int mainHeight = config->readNumEntry("SearchWidgetHeight", 0);
00279 
00280   if (mainWidth || mainHeight)
00281     resize(mainWidth, mainHeight);
00282 
00283   setMainWidget(searchWidget);
00284   setButtonBoxOrientation(QWidget::Vertical);
00285 
00286   mBtnSearch = actionButton(KDialogBase::User1);
00287   mBtnStop = actionButton(KDialogBase::User2);
00288   mBtnStop->setEnabled(false);
00289 
00290   connect(this, SIGNAL(user1Clicked()), SLOT(slotSearch()));
00291   connect(this, SIGNAL(user2Clicked()), SLOT(slotStop()));
00292   connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
00293 
00294   // give focus to the value field of the first search rule
00295   object = mPatternEdit->child( "regExpLineEdit" );
00296   if ( object && object->isWidgetType() ) {
00297       static_cast<QWidget*>(object)->setFocus();
00298       //kdDebug(5006) << "SearchWindow: focus has been given to widget "
00299       //              << object->name() << endl;
00300   }
00301   else
00302       kdDebug(5006) << "SearchWindow: regExpLineEdit not found" << endl;
00303 
00304   //set up actions
00305   KActionCollection *ac = actionCollection();
00306   ac->setWidget( this );
00307   mReplyAction = new KAction( i18n("&Reply..."), "mail_reply", 0, this,
00308                               SLOT(slotReplyToMsg()), ac, "search_reply" );
00309   mReplyAllAction = new KAction( i18n("Reply to &All..."), "mail_replyall",
00310                                  0, this, SLOT(slotReplyAllToMsg()),
00311                                  ac, "search_reply_all" );
00312   mReplyListAction = new KAction( i18n("Reply to Mailing-&List..."),
00313                                   "mail_replylist", 0, this,
00314                                   SLOT(slotReplyListToMsg()), ac,
00315                                   "search_reply_list" );
00316   mForwardActionMenu = new KActionMenu( i18n("Message->","&Forward"),
00317                                         "mail_forward", ac,
00318                                         "search_message_forward" );
00319   connect( mForwardActionMenu, SIGNAL(activated()), this,
00320            SLOT(slotForwardInlineMsg()) );
00321   mForwardAttachedAction = new KAction( i18n("Message->Forward->","As &Attachment..."),
00322                                         "mail_forward", 0, this,
00323                                         SLOT(slotForwardAttachedMsg()), ac,
00324                                         "search_message_forward_as_attachment" );
00325   mForwardActionMenu->insert( mForwardAttachedAction );
00326   mForwardInlineAction = new KAction( i18n("&Inline..."),
00327                                       "mail_forward", 0, this,
00328                                       SLOT(slotForwardInlineMsg()), ac,
00329                                       "search_message_forward_inline" );
00330   mForwardActionMenu->insert( mForwardInlineAction );
00331   mForwardDigestAction = new KAction( i18n("Message->Forward->","As Di&gest..."),
00332                                       "mail_forward", 0, this,
00333                                       SLOT(slotForwardDigestMsg()), ac,
00334                                       "search_message_forward_as_digest" );
00335   mForwardActionMenu->insert( mForwardDigestAction );
00336   mRedirectAction = new KAction( i18n("Message->Forward->","&Redirect..."),
00337                                       "mail_forward", 0, this,
00338                                       SLOT(slotRedirectMsg()), ac,
00339                                       "search_message_forward_redirect" );
00340   mForwardActionMenu->insert( mRedirectAction );
00341   mSaveAsAction = KStdAction::saveAs( this, SLOT(slotSaveMsg()), ac, "search_file_save_as" );
00342   mSaveAtchAction = new KAction( i18n("Save Attachments..."), "attach", 0,
00343                                  this, SLOT(slotSaveAttachments()), ac, "search_save_attachments" );
00344 
00345   mPrintAction = KStdAction::print( this, SLOT(slotPrintMsg()), ac, "search_print" );
00346   mClearAction = new KAction( i18n("Clear Selection"), 0, 0, this,
00347                               SLOT(slotClearSelection()), ac, "search_clear_selection" );
00348 
00349   mCopyAction = KStdAction::copy( this, SLOT(slotCopyMsgs()), ac, "search_copy_messages" );
00350   mCutAction = KStdAction::cut( this, SLOT(slotCutMsgs()), ac, "search_cut_messages" );
00351 
00352   connect(mTimer, SIGNAL(timeout()), this, SLOT(updStatus()));
00353   connect(kmkernel->searchFolderMgr(), SIGNAL(folderInvalidated(KMFolder*)),
00354           this, SLOT(folderInvalidated(KMFolder*)));
00355 
00356   connect(mCbxFolders, SIGNAL(folderChanged(KMFolder*)),
00357           this, SLOT(slotFolderActivated()));
00358 
00359 }
00360 
00361 //-----------------------------------------------------------------------------
00362 SearchWindow::~SearchWindow()
00363 {
00364   QValueListIterator<QGuardedPtr<KMFolder> > fit;
00365   for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
00366     if (!(*fit))
00367       continue;
00368     (*fit)->close("searchwindow");
00369   }
00370 
00371   KConfig* config = KMKernel::config();
00372   config->setGroup("SearchDialog");
00373   config->writeEntry("SubjectWidth", mLbxMatches->columnWidth(0));
00374   config->writeEntry("SenderWidth", mLbxMatches->columnWidth(1));
00375   config->writeEntry("DateWidth", mLbxMatches->columnWidth(2));
00376   config->writeEntry("FolderWidth", mLbxMatches->columnWidth(3));
00377   config->writeEntry("SearchWidgetWidth", width());
00378   config->writeEntry("SearchWidgetHeight", height());
00379   config->sync();
00380 }
00381 
00382 void SearchWindow::setEnabledSearchButton(bool)
00383 {
00384   //Make sure that button is enable
00385   //Before when we selected a folder == "Local Folder" as that it was not a folder
00386   //search button was disable, and when we select "Search in all local folder"
00387   //Search button was never enabled :(
00388   mBtnSearch->setEnabled( true );
00389 }
00390 
00391 //-----------------------------------------------------------------------------
00392 void SearchWindow::updStatus(void)
00393 {
00394     QString genMsg, detailMsg, procMsg;
00395     int numMatches = 0, numProcessed = 0;
00396     KMSearch const *search = (mFolder) ? (mFolder->search()) : 0;
00397     QString folderName;
00398     if (search) {
00399         numMatches = search->foundCount();
00400         numProcessed = search->searchCount();
00401         folderName = search->currentFolder();
00402     }
00403 
00404     if (mFolder && mFolder->search() && !mFolder->search()->running()) {
00405         procMsg = i18n("%n message searched", "%n messages searched",
00406                        numProcessed);
00407         if(!mStopped) {
00408             genMsg = i18n("Done.");
00409             detailMsg = i18n("%n match in %1", "%n matches in %1",
00410                              numMatches).arg(procMsg);
00411         } else {
00412             genMsg = i18n("Search canceled.");
00413             detailMsg = i18n("%n match so far in %1", "%n matches so far in %1",
00414                              numMatches).arg(procMsg);
00415         }
00416     } else {
00417         procMsg = i18n("%n message", "%n messages", numProcessed);
00418         genMsg = i18n("%n match", "%n matches", numMatches);
00419         detailMsg = i18n("Searching in %1. %2 searched so far")
00420                     .arg(folderName).arg(procMsg);
00421     }
00422 
00423     mStatusBar->changeItem(genMsg, 0);
00424     mStatusBar->changeItem(detailMsg, 1);
00425 }
00426 
00427 
00428 //-----------------------------------------------------------------------------
00429 void SearchWindow::keyPressEvent(QKeyEvent *evt)
00430 {
00431     KMSearch const *search = (mFolder) ? mFolder->search() : 0;
00432     bool searching = (search) ? search->running() : false;
00433     if (evt->key() == Key_Escape && searching) {
00434         mFolder->stopSearch();
00435         return;
00436     }
00437 
00438     KDialogBase::keyPressEvent(evt);
00439 }
00440 
00441 
00442 //-----------------------------------------------------------------------------
00443 void SearchWindow::slotFolderActivated()
00444 {
00445     mChkbxSpecificFolders->setChecked(true);
00446 }
00447 
00448 //-----------------------------------------------------------------------------
00449 void SearchWindow::activateFolder(KMFolder *curFolder)
00450 {
00451     mChkbxSpecificFolders->setChecked(true);
00452     mCbxFolders->setFolder(curFolder);
00453 }
00454 
00455 //-----------------------------------------------------------------------------
00456 void SearchWindow::slotSearch()
00457 {
00458     mLastFocus = focusWidget();
00459     mBtnSearch->setFocus();     // set focus so we don't miss key event
00460 
00461     mStopped = false;
00462     mFetchingInProgress = 0;
00463 
00464     mSearchFolderOpenBtn->setEnabled(true);
00465     mBtnSearch->setEnabled(false);
00466     mBtnStop->setEnabled(true);
00467 
00468     mLbxMatches->clear();
00469 
00470     mSortColumn = mLbxMatches->sortColumn();
00471     mSortOrder = mLbxMatches->sortOrder();
00472     mLbxMatches->setSorting(-1);
00473     mLbxMatches->setShowSortIndicator(false);
00474 
00475     // If we haven't openend an existing search folder, find or
00476     // create one.
00477     if (!mFolder) {
00478       KMFolderMgr *mgr = kmkernel->searchFolderMgr();
00479       if (mSearchFolderEdt->text().isEmpty())
00480           mSearchFolderEdt->setText(i18n("Last Search"));
00481       QString baseName = mSearchFolderEdt->text();
00482       QString fullName = baseName;
00483       int count = 0;
00484       KMFolder *folder;
00485       while ((folder = mgr->find(fullName))) {
00486         if (folder->storage()->inherits("KMFolderSearch"))
00487           break;
00488         fullName = QString("%1 %2").arg(baseName).arg(++count);
00489       }
00490 
00491       if (!folder)
00492         folder = mgr->createFolder(fullName, FALSE, KMFolderTypeSearch,
00493             &mgr->dir());
00494 
00495       mFolder = dynamic_cast<KMFolderSearch*>( folder->storage() );
00496     }
00497     mFolder->stopSearch();
00498     disconnect(mFolder, SIGNAL(msgAdded(int)),
00499             this, SLOT(slotAddMsg(int)));
00500     disconnect(mFolder, SIGNAL(msgRemoved(KMFolder*, Q_UINT32)),
00501             this, SLOT(slotRemoveMsg(KMFolder*, Q_UINT32)));
00502     connect(mFolder, SIGNAL(msgAdded(int)),
00503             this, SLOT(slotAddMsg(int)));
00504     connect(mFolder, SIGNAL(msgRemoved(KMFolder*, Q_UINT32)),
00505             this, SLOT(slotRemoveMsg(KMFolder*, Q_UINT32)));
00506     KMSearch *search = new KMSearch();
00507     connect(search, SIGNAL(finished(bool)),
00508             this, SLOT(searchDone()));
00509     if (mChkbxAllFolders->isChecked()) {
00510         search->setRecursive(true);
00511     } else {
00512         search->setRoot(mCbxFolders->folder());
00513         search->setRecursive(mChkSubFolders->isChecked());
00514     }
00515 
00516     mPatternEdit->updateSearchPattern();
00517     KMSearchPattern *searchPattern = new KMSearchPattern();
00518     *searchPattern = *mSearchPattern; //deep copy
00519     searchPattern->purify();
00520     search->setSearchPattern(searchPattern);
00521     mFolder->setSearch(search);
00522     enableGUI();
00523 
00524     if (mFolder && !mFolders.contains(mFolder.operator->()->folder())) {
00525         mFolder->open("searchwindow");
00526         mFolders.append(mFolder.operator->()->folder());
00527     }
00528     mTimer->start(200);
00529 }
00530 
00531 //-----------------------------------------------------------------------------
00532 void SearchWindow::searchDone()
00533 {
00534     mTimer->stop();
00535     updStatus();
00536 
00537     QTimer::singleShot(0, this, SLOT(enableGUI()));
00538     if(mLastFocus)
00539         mLastFocus->setFocus();
00540     if (mCloseRequested)
00541         close();
00542 
00543     mLbxMatches->setSorting(mSortColumn, mSortOrder == Ascending);
00544     mLbxMatches->setShowSortIndicator(true);
00545 }
00546 
00547 void SearchWindow::slotAddMsg(int idx)
00548 {
00549     if (!mFolder)
00550         return;
00551     bool unget = !mFolder->isMessage(idx);
00552     KMMessage *msg = mFolder->getMsg(idx);
00553     QString from, fName;
00554     KMFolder *pFolder = msg->parent();
00555     if (!mFolders.contains(pFolder)) {
00556         mFolders.append(pFolder);
00557         pFolder->open("searchwindow");
00558     }
00559     if(pFolder->whoField() == "To")
00560         from = msg->to();
00561     else
00562         from = msg->from();
00563     if (pFolder->isSystemFolder())
00564         fName = i18n(pFolder->name().utf8());
00565     else
00566         fName = pFolder->name();
00567 
00568     (void)new KListViewItem(mLbxMatches, mLbxMatches->lastItem(),
00569                             msg->subject(), from, msg->dateIsoStr(),
00570                             fName,
00571                             QString::number(mFolder->serNum(idx)));
00572     if (unget)
00573         mFolder->unGetMsg(idx);
00574 }
00575 
00576 void SearchWindow::slotRemoveMsg(KMFolder *, Q_UINT32 serNum)
00577 {
00578     if (!mFolder)
00579         return;
00580     QListViewItemIterator it(mLbxMatches);
00581     while (it.current()) {
00582         QListViewItem *item = *it;
00583         if (serNum == (*it)->text(MSGID_COLUMN).toUInt()) {
00584             delete item;
00585             return;
00586         }
00587         ++it;
00588     }
00589 }
00590 
00591 //-----------------------------------------------------------------------------
00592 void SearchWindow::slotStop()
00593 {
00594     if (mFolder)
00595       mFolder->stopSearch();
00596     mStopped = true;
00597     mBtnStop->setEnabled(false);
00598 }
00599 
00600 //-----------------------------------------------------------------------------
00601 void SearchWindow::slotClose()
00602 {
00603     accept();
00604 }
00605 
00606 
00607 //-----------------------------------------------------------------------------
00608 void SearchWindow::closeEvent(QCloseEvent *e)
00609 {
00610     if (mFolder && mFolder->search() && mFolder->search()->running()) {
00611       mCloseRequested = true;
00612       //Cancel search in progress by setting the search folder search to
00613       //the null search
00614       mFolder->setSearch(new KMSearch());
00615       QTimer::singleShot(0, this, SLOT(slotClose()));
00616     } else {
00617       KDialogBase::closeEvent(e);
00618     }
00619 }
00620 
00621 //-----------------------------------------------------------------------------
00622 void SearchWindow::updateCreateButton( const QString &s)
00623 {
00624     mSearchFolderBtn->setEnabled(s != i18n("Last Search") && mSearchFolderOpenBtn->isEnabled());
00625 }
00626 
00627 //-----------------------------------------------------------------------------
00628 void SearchWindow::renameSearchFolder()
00629 {
00630     if (mFolder && (mFolder->folder()->name() != mSearchFolderEdt->text())) {
00631         int i = 1;
00632         QString name =  mSearchFolderEdt->text();
00633         while (i < 100) {
00634             if (!kmkernel->searchFolderMgr()->find( name )) {
00635                 mFolder->rename( name );
00636                 kmkernel->searchFolderMgr()->contentsChanged();
00637                 break;
00638             }
00639             name.setNum( i );
00640             name = mSearchFolderEdt->text() + " " + name;
00641             ++i;
00642         }
00643     }
00644 }
00645 
00646 void SearchWindow::openSearchFolder()
00647 {
00648     renameSearchFolder();
00649     mKMMainWidget->slotSelectFolder( mFolder->folder() );
00650     slotClose();
00651 }
00652 
00653 //-----------------------------------------------------------------------------
00654 void SearchWindow::folderInvalidated(KMFolder *folder)
00655 {
00656     if (folder->storage() == mFolder) {
00657         mLbxMatches->clear();
00658         if (mFolder->search())
00659             connect(mFolder->search(), SIGNAL(finished(bool)),
00660                     this, SLOT(searchDone()));
00661         mTimer->start(200);
00662         enableGUI();
00663     }
00664 }
00665 
00666 //-----------------------------------------------------------------------------
00667 bool SearchWindow::slotShowMsg(QListViewItem *item)
00668 {
00669     if(!item)
00670         return false;
00671 
00672     KMFolder* folder;
00673     int msgIndex;
00674     KMMsgDict::instance()->getLocation(item->text(MSGID_COLUMN).toUInt(),
00675                                    &folder, &msgIndex);
00676 
00677     if (!folder || msgIndex < 0)
00678         return false;
00679 
00680     mKMMainWidget->slotSelectFolder(folder);
00681     KMMessage* message = folder->getMsg(msgIndex);
00682     if (!message)
00683         return false;
00684 
00685     mKMMainWidget->slotSelectMessage(message);
00686     return true;
00687 }
00688 
00689 //-----------------------------------------------------------------------------
00690 void SearchWindow::enableGUI()
00691 {
00692     KMSearch const *search = (mFolder) ? (mFolder->search()) : 0;
00693     bool searching = (search) ? (search->running()) : false;
00694     actionButton(KDialogBase::Close)->setEnabled(!searching);
00695     mCbxFolders->setEnabled(!searching);
00696     mChkSubFolders->setEnabled(!searching);
00697     mChkbxAllFolders->setEnabled(!searching);
00698     mChkbxSpecificFolders->setEnabled(!searching);
00699     mPatternEdit->setEnabled(!searching);
00700     mBtnSearch->setEnabled(!searching);
00701     mBtnStop->setEnabled(searching);
00702 }
00703 
00704 
00705 //-----------------------------------------------------------------------------
00706 KMMessageList SearchWindow::selectedMessages()
00707 {
00708     KMMessageList msgList;
00709     KMFolder* folder = 0;
00710     int msgIndex = -1;
00711     for (QListViewItemIterator it(mLbxMatches); it.current(); it++)
00712         if (it.current()->isSelected()) {
00713             KMMsgDict::instance()->getLocation((*it)->text(MSGID_COLUMN).toUInt(),
00714                                            &folder, &msgIndex);
00715             if (folder && msgIndex >= 0)
00716                 msgList.append(folder->getMsgBase(msgIndex));
00717         }
00718     return msgList;
00719 }
00720 
00721 //-----------------------------------------------------------------------------
00722 KMMessage* SearchWindow::message()
00723 {
00724     QListViewItem *item = mLbxMatches->currentItem();
00725     KMFolder* folder = 0;
00726     int msgIndex = -1;
00727     if (!item)
00728         return 0;
00729     KMMsgDict::instance()->getLocation(item->text(MSGID_COLUMN).toUInt(),
00730                                    &folder, &msgIndex);
00731     if (!folder || msgIndex < 0)
00732         return 0;
00733 
00734     return folder->getMsg(msgIndex);
00735 }
00736 
00737 //-----------------------------------------------------------------------------
00738 void SearchWindow::moveSelectedToFolder( int menuId )
00739 {
00740     KMFolder *dest = mMenuToFolder[menuId];
00741     if (!dest)
00742         return;
00743 
00744     KMMessageList msgList = selectedMessages();
00745     KMCommand *command = new KMMoveCommand( dest, msgList );
00746     command->start();
00747 }
00748 
00749 //-----------------------------------------------------------------------------
00750 void SearchWindow::copySelectedToFolder( int menuId )
00751 {
00752     KMFolder *dest = mMenuToFolder[menuId];
00753     if (!dest)
00754         return;
00755 
00756     KMMessageList msgList = selectedMessages();
00757     KMCommand *command = new KMCopyCommand( dest, msgList );
00758     command->start();
00759 }
00760 
00761 //-----------------------------------------------------------------------------
00762 void SearchWindow::updateContextMenuActions()
00763 {
00764     int count = selectedMessages().count();
00765     bool single_actions = count == 1;
00766     mReplyAction->setEnabled( single_actions );
00767     mReplyAllAction->setEnabled( single_actions );
00768     mReplyListAction->setEnabled( single_actions );
00769     mPrintAction->setEnabled( single_actions );
00770     mForwardDigestAction->setEnabled( !single_actions );
00771     mRedirectAction->setEnabled( single_actions );
00772     mCopyAction->setEnabled( count > 0 );
00773     mCutAction->setEnabled( count > 0 );
00774 }
00775 
00776 //-----------------------------------------------------------------------------
00777 void SearchWindow::slotContextMenuRequested( QListViewItem *lvi, const QPoint &, int )
00778 {
00779     if (!lvi)
00780         return;
00781     mLbxMatches->setSelected( lvi, TRUE );
00782     mLbxMatches->setCurrentItem( lvi );
00783     // FIXME is this ever unGetMsg()'d?
00784     if (!message())
00785         return;
00786     QPopupMenu *menu = new QPopupMenu(this);
00787     updateContextMenuActions();
00788 
00789     mMenuToFolder.clear();
00790     QPopupMenu *msgMoveMenu = new QPopupMenu(menu);
00791     mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::MoveMessage,
00792         this, &mMenuToFolder, msgMoveMenu );
00793     QPopupMenu *msgCopyMenu = new QPopupMenu(menu);
00794     mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::CopyMessage,
00795         this, &mMenuToFolder, msgCopyMenu );
00796 
00797     // show most used actions
00798     mReplyAction->plug(menu);
00799     mReplyAllAction->plug(menu);
00800     mReplyListAction->plug(menu);
00801     mForwardActionMenu->plug(menu);
00802     menu->insertSeparator();
00803     mCopyAction->plug(menu);
00804     mCutAction->plug(menu);
00805     menu->insertItem(i18n("&Copy To"), msgCopyMenu);
00806     menu->insertItem(i18n("&Move To"), msgMoveMenu);
00807     menu->insertSeparator();
00808     mSaveAsAction->plug(menu);
00809     mSaveAtchAction->plug(menu);
00810     mPrintAction->plug(menu);
00811     menu->insertSeparator();
00812     mClearAction->plug(menu);
00813     menu->exec (QCursor::pos(), 0);
00814     delete menu;
00815 }
00816 
00817 //-----------------------------------------------------------------------------
00818 void SearchWindow::slotClearSelection()
00819 {
00820     mLbxMatches->clearSelection();
00821 }
00822 
00823 //-----------------------------------------------------------------------------
00824 void SearchWindow::slotReplyToMsg()
00825 {
00826     KMCommand *command = new KMReplyToCommand(this, message());
00827     command->start();
00828 }
00829 
00830 //-----------------------------------------------------------------------------
00831 void SearchWindow::slotReplyAllToMsg()
00832 {
00833     KMCommand *command = new KMReplyToAllCommand(this, message());
00834     command->start();
00835 }
00836 
00837 //-----------------------------------------------------------------------------
00838 void SearchWindow::slotReplyListToMsg()
00839 {
00840     KMCommand *command = new KMReplyListCommand(this, message());
00841     command->start();
00842 }
00843 
00844 //-----------------------------------------------------------------------------
00845 void SearchWindow::slotForwardInlineMsg()
00846 {
00847     KMCommand *command = new KMForwardInlineCommand(this, selectedMessages());
00848     command->start();
00849 }
00850 
00851 //-----------------------------------------------------------------------------
00852 void SearchWindow::slotForwardAttachedMsg()
00853 {
00854     KMCommand *command = new KMForwardAttachedCommand(this, selectedMessages());
00855     command->start();
00856 }
00857 
00858 //-----------------------------------------------------------------------------
00859 void SearchWindow::slotForwardDigestMsg()
00860 {
00861     KMCommand *command = new KMForwardDigestCommand(this, selectedMessages());
00862     command->start();
00863 }
00864 
00865 //-----------------------------------------------------------------------------
00866 void SearchWindow::slotRedirectMsg()
00867 {
00868     KMCommand *command = new KMRedirectCommand(this, message());
00869     command->start();
00870 }
00871 
00872 //-----------------------------------------------------------------------------
00873 void SearchWindow::slotSaveMsg()
00874 {
00875     KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand(this,
00876                                                          selectedMessages());
00877     if (saveCommand->url().isEmpty())
00878         delete saveCommand;
00879     else
00880         saveCommand->start();
00881 }
00882 //-----------------------------------------------------------------------------
00883 void SearchWindow::slotSaveAttachments()
00884 {
00885     KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand(this,
00886                                                                          selectedMessages());
00887     saveCommand->start();
00888 }
00889 
00890 
00891 //-----------------------------------------------------------------------------
00892 void SearchWindow::slotPrintMsg()
00893 {
00894     KMCommand *command = new KMPrintCommand(this, message());
00895     command->start();
00896 }
00897 
00898 void SearchWindow::slotCopyMsgs()
00899 {
00900   QValueList<Q_UINT32> list = MessageCopyHelper::serNumListFromMsgList( selectedMessages() );
00901   mKMMainWidget->headers()->setCopiedMessages( list, false );
00902 }
00903 
00904 void SearchWindow::slotCutMsgs()
00905 {
00906   QValueList<Q_UINT32> list = MessageCopyHelper::serNumListFromMsgList( selectedMessages() );
00907   mKMMainWidget->headers()->setCopiedMessages( list, true );
00908 }
00909 
00910 } // namespace KMail
00911 #include "searchwindow.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys