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(slotForwardInlineMsg()) );
00273   mForwardAttachedAction = new KAction( i18n("Message->Forward->","As &Attachment..."),
00274                                         "mail_forward", 0, this,
00275                                         SLOT(slotForwardAttachedMsg()), ac,
00276                                         "search_message_forward_as_attachment" );
00277   mForwardActionMenu->insert( mForwardAttachedAction );
00278   mForwardInlineAction = new KAction( i18n("&Inline..."),
00279                                       "mail_forward", 0, this,
00280                                       SLOT(slotForwardInlineMsg()), ac,
00281                                       "search_message_forward_inline" );
00282   mForwardActionMenu->insert( mForwardInlineAction );
00283   mForwardDigestAction = new KAction( i18n("Message->Forward->","As Di&gest..."),
00284                                       "mail_forward", 0, this,
00285                                       SLOT(slotForwardDigestMsg()), ac,
00286                                       "search_message_forward_as_digest" );
00287   mForwardActionMenu->insert( mForwardDigestAction );
00288   mRedirectAction = new KAction( i18n("Message->Forward->","&Redirect..."),
00289                                       "mail_forward", 0, this,
00290                                       SLOT(slotRedirectMsg()), ac,
00291                                       "search_message_forward_redirect" );
00292   mForwardActionMenu->insert( mRedirectAction );
00293   mSaveAsAction = KStdAction::saveAs( this, SLOT(slotSaveMsg()), ac, "search_file_save_as" );
00294   mSaveAtchAction = new KAction( i18n("Save Attachments..."), "attach", 0,
00295                                  this, SLOT(slotSaveAttachments()), ac, "search_save_attachments" );
00296 
00297   mPrintAction = KStdAction::print( this, SLOT(slotPrintMsg()), ac, "search_print" );
00298   mClearAction = new KAction( i18n("Clear Selection"), 0, 0, this,
00299                               SLOT(slotClearSelection()), ac, "search_clear_selection" );
00300   connect(mTimer, SIGNAL(timeout()), this, SLOT(updStatus()));
00301   connect(kmkernel->searchFolderMgr(), SIGNAL(folderInvalidated(KMFolder*)),
00302           this, SLOT(folderInvalidated(KMFolder*)));
00303 
00304   connect(mCbxFolders, SIGNAL(folderChanged(KMFolder*)),
00305           this, SLOT(slotFolderActivated()));
00306 
00307 }
00308 
00309 //-----------------------------------------------------------------------------
00310 SearchWindow::~SearchWindow()
00311 {
00312   QValueListIterator<QGuardedPtr<KMFolder> > fit;
00313   for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
00314     if (!(*fit))
00315       continue;
00316     (*fit)->close();
00317   }
00318 
00319   KConfig* config = KMKernel::config();
00320   config->setGroup("SearchDialog");
00321   config->writeEntry("SubjectWidth", mLbxMatches->columnWidth(0));
00322   config->writeEntry("SenderWidth", mLbxMatches->columnWidth(1));
00323   config->writeEntry("DateWidth", mLbxMatches->columnWidth(2));
00324   config->writeEntry("FolderWidth", mLbxMatches->columnWidth(3));
00325   config->writeEntry("SearchWidgetWidth", width());
00326   config->writeEntry("SearchWidgetHeight", height());
00327   config->sync();
00328 }
00329 
00330 void SearchWindow::setEnabledSearchButton(bool)
00331 {
00332   //Make sure that button is enable
00333   //Before when we selected a folder == "Local Folder" as that it was not a folder
00334   //search button was disable, and when we select "Search in all local folder"
00335   //Search button was never enabled :(
00336   mBtnSearch->setEnabled( true );
00337 }
00338 
00339 //-----------------------------------------------------------------------------
00340 void SearchWindow::updStatus(void)
00341 {
00342     QString genMsg, detailMsg, procMsg;
00343     int numMatches = 0, numProcessed = 0;
00344     KMSearch const *search = (mFolder) ? (mFolder->search()) : 0;
00345     QString folderName;
00346     if (search) {
00347         numMatches = search->foundCount();
00348         numProcessed = search->searchCount();
00349         folderName = search->currentFolder();
00350     }
00351 
00352     if (mFolder && mFolder->search() && !mFolder->search()->running()) {
00353         procMsg = i18n("%n message searched", "%n messages searched",
00354                        numProcessed);
00355         if(!mStopped) {
00356             genMsg = i18n("Done.");
00357             detailMsg = i18n("%n match in %1", "%n matches in %1",
00358                              numMatches).arg(procMsg);
00359         } else {
00360             genMsg = i18n("Search canceled.");
00361             detailMsg = i18n("%n match so far in %1", "%n matches so far in %1",
00362                              numMatches).arg(procMsg);
00363         }
00364     } else {
00365         procMsg = i18n("%n message", "%n messages", numProcessed);
00366         genMsg = i18n("%n match", "%n matches", numMatches);
00367         detailMsg = i18n("Searching in %1. %2 searched so far")
00368                     .arg(folderName).arg(procMsg);
00369     }
00370 
00371     mStatusBar->changeItem(genMsg, 0);
00372     mStatusBar->changeItem(detailMsg, 1);
00373 }
00374 
00375 
00376 //-----------------------------------------------------------------------------
00377 void SearchWindow::keyPressEvent(QKeyEvent *evt)
00378 {
00379     KMSearch const *search = (mFolder) ? mFolder->search() : 0;
00380     bool searching = (search) ? search->running() : false;
00381     if (evt->key() == Key_Escape && searching) {
00382         mFolder->stopSearch();
00383         return;
00384     }
00385 
00386     KDialogBase::keyPressEvent(evt);
00387 }
00388 
00389 
00390 //-----------------------------------------------------------------------------
00391 void SearchWindow::slotFolderActivated()
00392 {
00393     mChkbxSpecificFolders->setChecked(true);
00394 }
00395 
00396 //-----------------------------------------------------------------------------
00397 void SearchWindow::activateFolder(KMFolder *curFolder)
00398 {
00399     mChkbxSpecificFolders->setChecked(true);
00400     mCbxFolders->setFolder(curFolder);
00401 }
00402 
00403 //-----------------------------------------------------------------------------
00404 void SearchWindow::slotSearch()
00405 {
00406     mLastFocus = focusWidget();
00407     mBtnSearch->setFocus();     // set focus so we don't miss key event
00408 
00409     mStopped = false;
00410     mFetchingInProgress = 0;
00411 
00412     mSearchFolderOpenBtn->setEnabled(true);
00413     mBtnSearch->setEnabled(false);
00414     mBtnStop->setEnabled(true);
00415 
00416     mLbxMatches->clear();
00417 
00418     mSortColumn = mLbxMatches->sortColumn();
00419     mSortOrder = mLbxMatches->sortOrder();
00420     mLbxMatches->setSorting(-1);
00421     mLbxMatches->setShowSortIndicator(false);
00422 
00423     // If we haven't openend an existing search folder, find or
00424     // create one.
00425     if (!mFolder) {
00426       KMFolderMgr *mgr = kmkernel->searchFolderMgr();
00427       if (mSearchFolderEdt->text().isEmpty())
00428           mSearchFolderEdt->setText(i18n("Last Search"));
00429       QString baseName = mSearchFolderEdt->text();
00430       QString fullName = baseName;
00431       int count = 0;
00432       KMFolder *folder;
00433       while ((folder = mgr->find(fullName))) {
00434         if (folder->storage()->inherits("KMFolderSearch"))
00435           break;
00436         fullName = QString("%1 %2").arg(baseName).arg(++count);
00437       }
00438 
00439       if (!folder)
00440         folder = mgr->createFolder(fullName, FALSE, KMFolderTypeSearch,
00441             &mgr->dir());
00442 
00443       mFolder = dynamic_cast<KMFolderSearch*>( folder->storage() );
00444     }
00445     mFolder->stopSearch();
00446     disconnect(mFolder, SIGNAL(msgAdded(int)),
00447             this, SLOT(slotAddMsg(int)));
00448     disconnect(mFolder, SIGNAL(msgRemoved(KMFolder*, Q_UINT32)),
00449             this, SLOT(slotRemoveMsg(KMFolder*, Q_UINT32)));
00450     connect(mFolder, SIGNAL(msgAdded(int)),
00451             this, SLOT(slotAddMsg(int)));
00452     connect(mFolder, SIGNAL(msgRemoved(KMFolder*, Q_UINT32)),
00453             this, SLOT(slotRemoveMsg(KMFolder*, Q_UINT32)));
00454     KMSearch *search = new KMSearch();
00455     connect(search, SIGNAL(finished(bool)),
00456             this, SLOT(searchDone()));
00457     if (mChkbxAllFolders->isChecked()) {
00458         search->setRecursive(true);
00459     } else {
00460         search->setRoot(mCbxFolders->folder());
00461         search->setRecursive(mChkSubFolders->isChecked());
00462     }
00463 
00464     mPatternEdit->updateSearchPattern();
00465     KMSearchPattern *searchPattern = new KMSearchPattern();
00466     *searchPattern = *mSearchPattern; //deep copy
00467     searchPattern->purify();
00468     search->setSearchPattern(searchPattern);
00469     mFolder->setSearch(search);
00470     enableGUI();
00471 
00472     if (mFolder && !mFolders.contains(mFolder.operator->()->folder())) {
00473         mFolder->open();
00474         mFolders.append(mFolder.operator->()->folder());
00475     }
00476     mTimer->start(200);
00477 }
00478 
00479 //-----------------------------------------------------------------------------
00480 void SearchWindow::searchDone()
00481 {
00482     mTimer->stop();
00483     updStatus();
00484 
00485     QTimer::singleShot(0, this, SLOT(enableGUI()));
00486     if(mLastFocus)
00487         mLastFocus->setFocus();
00488     if (mCloseRequested)
00489         close();
00490 
00491     mLbxMatches->setSorting(mSortColumn, mSortOrder == Ascending);
00492     mLbxMatches->setShowSortIndicator(true);
00493 }
00494 
00495 void SearchWindow::slotAddMsg(int idx)
00496 {
00497     if (!mFolder)
00498         return;
00499     bool unget = !mFolder->isMessage(idx);
00500     KMMessage *msg = mFolder->getMsg(idx);
00501     QString from, fName;
00502     KMFolder *pFolder = msg->parent();
00503     if (!mFolders.contains(pFolder)) {
00504         mFolders.append(pFolder);
00505         pFolder->open();
00506     }
00507     if(pFolder->whoField() == "To")
00508         from = msg->to();
00509     else
00510         from = msg->from();
00511     if (pFolder->isSystemFolder())
00512         fName = i18n(pFolder->name().utf8());
00513     else
00514         fName = pFolder->name();
00515 
00516     (void)new KListViewItem(mLbxMatches, mLbxMatches->lastItem(),
00517                             msg->subject(), from, msg->dateIsoStr(),
00518                             fName,
00519                             QString::number(mFolder->serNum(idx)));
00520     if (unget)
00521         mFolder->unGetMsg(idx);
00522 }
00523 
00524 void SearchWindow::slotRemoveMsg(KMFolder *, Q_UINT32 serNum)
00525 {
00526     if (!mFolder)
00527         return;
00528     QListViewItemIterator it(mLbxMatches);
00529     while (it.current()) {
00530         QListViewItem *item = *it;
00531         if (serNum == (*it)->text(MSGID_COLUMN).toUInt()) {
00532             delete item;
00533             return;
00534         }
00535         ++it;
00536     }
00537 }
00538 
00539 //-----------------------------------------------------------------------------
00540 void SearchWindow::slotStop()
00541 {
00542     if (mFolder)
00543       mFolder->stopSearch();
00544     mStopped = true;
00545     mBtnStop->setEnabled(false);
00546 }
00547 
00548 //-----------------------------------------------------------------------------
00549 void SearchWindow::slotClose()
00550 {
00551     accept();
00552 }
00553 
00554 
00555 //-----------------------------------------------------------------------------
00556 void SearchWindow::closeEvent(QCloseEvent *e)
00557 {
00558     if (mFolder && mFolder->search() && mFolder->search()->running()) {
00559       mCloseRequested = true;
00560       //Cancel search in progress by setting the search folder search to
00561       //the null search
00562       mFolder->setSearch(new KMSearch());
00563       QTimer::singleShot(0, this, SLOT(slotClose()));
00564     } else {
00565       KDialogBase::closeEvent(e);
00566     }
00567 }
00568 
00569 //-----------------------------------------------------------------------------
00570 void SearchWindow::updateCreateButton( const QString &s)
00571 {
00572     mSearchFolderBtn->setEnabled(s != i18n("Last Search") && mSearchFolderOpenBtn->isEnabled());
00573 }
00574 
00575 //-----------------------------------------------------------------------------
00576 void SearchWindow::renameSearchFolder()
00577 {
00578     if (mFolder && (mFolder->folder()->name() != mSearchFolderEdt->text())) {
00579         int i = 1;
00580         QString name =  mSearchFolderEdt->text();
00581         while (i < 100) {
00582             if (!kmkernel->searchFolderMgr()->find( name )) {
00583                 mFolder->rename( name );
00584                 kmkernel->searchFolderMgr()->contentsChanged();
00585                 break;
00586             }
00587             name.setNum( i );
00588             name = mSearchFolderEdt->text() + " " + name;
00589             ++i;
00590         }
00591     }
00592 }
00593 
00594 void SearchWindow::openSearchFolder()
00595 {
00596     renameSearchFolder();
00597     mKMMainWidget->slotSelectFolder( mFolder->folder() );
00598     slotClose();
00599 }
00600 
00601 //-----------------------------------------------------------------------------
00602 void SearchWindow::folderInvalidated(KMFolder *folder)
00603 {
00604     if (folder->storage() == mFolder) {
00605         mLbxMatches->clear();
00606         if (mFolder->search())
00607             connect(mFolder->search(), SIGNAL(finished(bool)),
00608                     this, SLOT(searchDone()));
00609         mTimer->start(200);
00610         enableGUI();
00611     }
00612 }
00613 
00614 //-----------------------------------------------------------------------------
00615 bool SearchWindow::slotShowMsg(QListViewItem *item)
00616 {
00617     if(!item)
00618         return false;
00619 
00620     KMFolder* folder;
00621     int msgIndex;
00622     KMMsgDict::instance()->getLocation(item->text(MSGID_COLUMN).toUInt(),
00623                                    &folder, &msgIndex);
00624 
00625     if (!folder || msgIndex < 0)
00626         return false;
00627 
00628     mKMMainWidget->slotSelectFolder(folder);
00629     KMMessage* message = folder->getMsg(msgIndex);
00630     if (!message)
00631         return false;
00632 
00633     mKMMainWidget->slotSelectMessage(message);
00634     return true;
00635 }
00636 
00637 //-----------------------------------------------------------------------------
00638 void SearchWindow::enableGUI()
00639 {
00640     KMSearch const *search = (mFolder) ? (mFolder->search()) : 0;
00641     bool searching = (search) ? (search->running()) : false;
00642     actionButton(KDialogBase::Close)->setEnabled(!searching);
00643     mCbxFolders->setEnabled(!searching);
00644     mChkSubFolders->setEnabled(!searching);
00645     mChkbxAllFolders->setEnabled(!searching);
00646     mChkbxSpecificFolders->setEnabled(!searching);
00647     mPatternEdit->setEnabled(!searching);
00648     mBtnSearch->setEnabled(!searching);
00649     mBtnStop->setEnabled(searching);
00650 }
00651 
00652 
00653 //-----------------------------------------------------------------------------
00654 KMMessageList SearchWindow::selectedMessages()
00655 {
00656     KMMessageList msgList;
00657     KMFolder* folder = 0;
00658     int msgIndex = -1;
00659     for (QListViewItemIterator it(mLbxMatches); it.current(); it++)
00660         if (it.current()->isSelected()) {
00661             KMMsgDict::instance()->getLocation((*it)->text(MSGID_COLUMN).toUInt(),
00662                                            &folder, &msgIndex);
00663             if (folder && msgIndex >= 0)
00664                 msgList.append(folder->getMsgBase(msgIndex));
00665         }
00666     return msgList;
00667 }
00668 
00669 //-----------------------------------------------------------------------------
00670 KMMessage* SearchWindow::message()
00671 {
00672     QListViewItem *item = mLbxMatches->currentItem();
00673     KMFolder* folder = 0;
00674     int msgIndex = -1;
00675     if (!item)
00676         return 0;
00677     KMMsgDict::instance()->getLocation(item->text(MSGID_COLUMN).toUInt(),
00678                                    &folder, &msgIndex);
00679     if (!folder || msgIndex < 0)
00680         return 0;
00681 
00682     return folder->getMsg(msgIndex);
00683 }
00684 
00685 //-----------------------------------------------------------------------------
00686 void SearchWindow::moveSelectedToFolder( int menuId )
00687 {
00688     KMFolder *dest = mMenuToFolder[menuId];
00689     if (!dest)
00690         return;
00691 
00692     KMMessageList msgList = selectedMessages();
00693     KMCommand *command = new KMMoveCommand( dest, msgList );
00694     command->start();
00695 }
00696 
00697 //-----------------------------------------------------------------------------
00698 void SearchWindow::copySelectedToFolder( int menuId )
00699 {
00700     KMFolder *dest = mMenuToFolder[menuId];
00701     if (!dest)
00702         return;
00703 
00704     KMMessageList msgList = selectedMessages();
00705     KMCommand *command = new KMCopyCommand( dest, msgList );
00706     command->start();
00707 }
00708 
00709 //-----------------------------------------------------------------------------
00710 void SearchWindow::updateContextMenuActions()
00711 {
00712     int count = selectedMessages().count();
00713     bool single_actions = count == 1;
00714     mReplyAction->setEnabled( single_actions );
00715     mReplyAllAction->setEnabled( single_actions );
00716     mReplyListAction->setEnabled( single_actions );
00717     mPrintAction->setEnabled( single_actions );
00718     mForwardDigestAction->setEnabled( !single_actions );
00719     mRedirectAction->setEnabled( single_actions );
00720 }
00721 
00722 //-----------------------------------------------------------------------------
00723 void SearchWindow::slotContextMenuRequested( QListViewItem *lvi, const QPoint &, int )
00724 {
00725     if (!lvi)
00726         return;
00727     mLbxMatches->setSelected( lvi, TRUE );
00728     mLbxMatches->setCurrentItem( lvi );
00729     // FIXME is this ever unGetMsg()'d?
00730     if (!message())
00731         return;
00732     QPopupMenu *menu = new QPopupMenu(this);
00733     updateContextMenuActions();
00734 
00735     mMenuToFolder.clear();
00736     QPopupMenu *msgMoveMenu = new QPopupMenu(menu);
00737     mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::MoveMessage,
00738         this, &mMenuToFolder, msgMoveMenu );
00739     QPopupMenu *msgCopyMenu = new QPopupMenu(menu);
00740     mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::CopyMessage,
00741         this, &mMenuToFolder, msgCopyMenu );
00742 
00743     // show most used actions
00744     mReplyAction->plug(menu);
00745     mReplyAllAction->plug(menu);
00746     mReplyListAction->plug(menu);
00747     mForwardActionMenu->plug(menu);
00748     menu->insertSeparator();
00749     menu->insertItem(i18n("&Copy To"), msgCopyMenu);
00750     menu->insertItem(i18n("&Move To"), msgMoveMenu);
00751     mSaveAsAction->plug(menu);
00752     mSaveAtchAction->plug(menu);
00753     mPrintAction->plug(menu);
00754     menu->insertSeparator();
00755     mClearAction->plug(menu);
00756     menu->exec (QCursor::pos(), 0);
00757     delete menu;
00758 }
00759 
00760 //-----------------------------------------------------------------------------
00761 void SearchWindow::slotClearSelection()
00762 {
00763     mLbxMatches->clearSelection();
00764 }
00765 
00766 //-----------------------------------------------------------------------------
00767 void SearchWindow::slotReplyToMsg()
00768 {
00769     KMCommand *command = new KMReplyToCommand(this, message());
00770     command->start();
00771 }
00772 
00773 //-----------------------------------------------------------------------------
00774 void SearchWindow::slotReplyAllToMsg()
00775 {
00776     KMCommand *command = new KMReplyToAllCommand(this, message());
00777     command->start();
00778 }
00779 
00780 //-----------------------------------------------------------------------------
00781 void SearchWindow::slotReplyListToMsg()
00782 {
00783     KMCommand *command = new KMReplyListCommand(this, message());
00784     command->start();
00785 }
00786 
00787 //-----------------------------------------------------------------------------
00788 void SearchWindow::slotForwardInlineMsg()
00789 {
00790     KMCommand *command = new KMForwardInlineCommand(this, selectedMessages());
00791     command->start();
00792 }
00793 
00794 //-----------------------------------------------------------------------------
00795 void SearchWindow::slotForwardAttachedMsg()
00796 {
00797     KMCommand *command = new KMForwardAttachedCommand(this, selectedMessages());
00798     command->start();
00799 }
00800 
00801 //-----------------------------------------------------------------------------
00802 void SearchWindow::slotForwardDigestMsg()
00803 {
00804     KMCommand *command = new KMForwardDigestCommand(this, selectedMessages());
00805     command->start();
00806 }
00807 
00808 //-----------------------------------------------------------------------------
00809 void SearchWindow::slotRedirectMsg()
00810 {
00811     KMCommand *command = new KMRedirectCommand(this, message());
00812     command->start();
00813 }
00814 
00815 //-----------------------------------------------------------------------------
00816 void SearchWindow::slotSaveMsg()
00817 {
00818     KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand(this,
00819                                                          selectedMessages());
00820     if (saveCommand->url().isEmpty())
00821         delete saveCommand;
00822     else
00823         saveCommand->start();
00824 }
00825 //-----------------------------------------------------------------------------
00826 void SearchWindow::slotSaveAttachments()
00827 {
00828     KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand(this,
00829                                                                          selectedMessages());
00830     saveCommand->start();
00831 }
00832 
00833 
00834 //-----------------------------------------------------------------------------
00835 void SearchWindow::slotPrintMsg()
00836 {
00837     KMCommand *command = new KMPrintCommand(this, message());
00838     command->start();
00839 }
00840 
00841 } // namespace KMail
00842 #include "searchwindow.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys