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