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