summaryrefslogtreecommitdiffstats
path: root/kmail/searchwindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmail/searchwindow.cpp')
-rw-r--r--kmail/searchwindow.cpp946
1 files changed, 946 insertions, 0 deletions
diff --git a/kmail/searchwindow.cpp b/kmail/searchwindow.cpp
new file mode 100644
index 000000000..7b9ef5588
--- /dev/null
+++ b/kmail/searchwindow.cpp
@@ -0,0 +1,946 @@
+/*
+ * kmail: KDE mail client
+ * Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
+ * Copyright (c) 2001 Aaron J. Seigo <aseigo@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+#include <config.h>
+#include "kmcommands.h"
+#include "searchwindow.h"
+#include "kmmainwidget.h"
+#include "kmmsgdict.h"
+#include "kmmsgpart.h"
+#include "kmfolderimap.h"
+#include "kmfoldermgr.h"
+#include "kmfoldersearch.h"
+#include "kmfoldertree.h"
+#include "kmheaders.h"
+#include "kmsearchpatternedit.h"
+#include "kmsearchpattern.h"
+#include "folderrequester.h"
+#include "messagecopyhelper.h"
+#include "textsource.h"
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kstatusbar.h>
+#include <kwin.h>
+#include <kconfig.h>
+#include <kstdaction.h>
+#include <kiconloader.h>
+
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <klineedit.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qbuttongroup.h>
+#include <qcombobox.h>
+#include <qobjectlist.h> //for mPatternEdit->queryList( 0, "mRuleField" )->first();
+#include <qcursor.h>
+#include <qpopupmenu.h>
+
+#include <maillistdrag.h>
+using namespace KPIM;
+
+#include <mimelib/enum.h>
+#include <mimelib/boyermor.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+namespace KMail {
+
+const int SearchWindow::MSGID_COLUMN = 4;
+
+// KListView sub-class for dnd support
+class MatchListView : public KListView
+{
+ public:
+ MatchListView( QWidget *parent, SearchWindow* sw, const char* name = 0 ) :
+ KListView( parent, name ),
+ mSearchWindow( sw )
+ {}
+
+ protected:
+ virtual QDragObject* dragObject()
+ {
+ KMMessageList list = mSearchWindow->selectedMessages();
+ MailList mailList;
+ for ( KMMsgBase* msg = list.first(); msg; msg = list.next() ) {
+ if ( !msg )
+ continue;
+ MailSummary mailSummary( msg->getMsgSerNum(), msg->msgIdMD5(),
+ msg->subject(), msg->fromStrip(),
+ msg->toStrip(), msg->date() );
+ mailList.append( mailSummary );
+ }
+ MailListDrag *d = new MailListDrag( mailList, viewport(), new KMTextSource );
+
+ QPixmap pixmap;
+ if( mailList.count() == 1 )
+ pixmap = QPixmap( DesktopIcon("message", KIcon::SizeSmall) );
+ else
+ pixmap = QPixmap( DesktopIcon("kmultiple", KIcon::SizeSmall) );
+
+ d->setPixmap( pixmap );
+ return d;
+ }
+
+ private:
+ SearchWindow* mSearchWindow;
+};
+
+//-----------------------------------------------------------------------------
+SearchWindow::SearchWindow(KMMainWidget* w, const char* name,
+ KMFolder *curFolder, bool modal):
+ KDialogBase(0, name, modal, i18n("Find Messages"),
+ User1 | User2 | Close, User1, false,
+ KGuiItem( i18n("&Search"), "find" ),
+ KStdGuiItem::stop()),
+ mStopped(false),
+ mCloseRequested(false),
+ mSortColumn(0),
+ mSortOrder(Ascending),
+ mFolder(0),
+ mTimer(new QTimer(this, "mTimer")),
+ mLastFocus(0),
+ mKMMainWidget(w)
+{
+#if !KDE_IS_VERSION( 3, 2, 91 )
+ // HACK - KWin keeps all dialogs on top of their mainwindows, but that's probably
+ // wrong (#76026), and should be done only for modals. CVS HEAD should get
+ // proper fix in KWin (l.lunak@kde.org)
+ XDeleteProperty( qt_xdisplay(), winId(), XA_WM_TRANSIENT_FOR );
+#endif
+ KWin::setIcons(winId(), kapp->icon(), kapp->miniIcon());
+
+ KConfig* config = KMKernel::config();
+ config->setGroup("SearchDialog");
+
+ QWidget* searchWidget = new QWidget(this);
+ QVBoxLayout *vbl = new QVBoxLayout( searchWidget, 0, spacingHint(), "kmfs_vbl" );
+
+ QButtonGroup * radioGroup = new QButtonGroup( searchWidget );
+ radioGroup->hide();
+
+ mChkbxAllFolders = new QRadioButton(i18n("Search in &all local folders"), searchWidget);
+ vbl->addWidget( mChkbxAllFolders );
+ radioGroup->insert( mChkbxAllFolders );
+
+ QHBoxLayout *hbl = new QHBoxLayout( vbl, spacingHint(), "kmfs_hbl" );
+ mChkbxSpecificFolders = new QRadioButton(i18n("Search &only in:"), searchWidget);
+ hbl->addWidget(mChkbxSpecificFolders);
+ mChkbxSpecificFolders->setChecked(true);
+ radioGroup->insert( mChkbxSpecificFolders );
+
+ mCbxFolders = new FolderRequester( searchWidget,
+ kmkernel->getKMMainWidget()->folderTree() );
+ mCbxFolders->setMustBeReadWrite( false );
+ mCbxFolders->setFolder(curFolder);
+ hbl->addWidget(mCbxFolders);
+
+ mChkSubFolders = new QCheckBox(i18n("I&nclude sub-folders"), searchWidget);
+ mChkSubFolders->setChecked(true);
+ hbl->addWidget(mChkSubFolders);
+
+ QWidget *spacer = new QWidget( searchWidget, "spacer" );
+ spacer->setMinimumHeight( 2 );
+ vbl->addWidget( spacer );
+
+ mPatternEdit = new KMSearchPatternEdit( "", searchWidget , "spe", false, true );
+ mPatternEdit->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
+ mPatternEdit->setInsideMargin( 0 );
+ mSearchPattern = new KMSearchPattern();
+ KMFolderSearch *searchFolder = 0;
+ if (curFolder)
+ searchFolder = dynamic_cast<KMFolderSearch*>(curFolder->storage());
+ if (searchFolder) {
+ KConfig config(curFolder->location());
+ KMFolder *root = searchFolder->search()->root();
+ config.setGroup("Search Folder");
+ mSearchPattern->readConfig(&config);
+ if (root) {
+ mChkbxSpecificFolders->setChecked(true);
+ mCbxFolders->setFolder(root);
+ mChkSubFolders->setChecked(searchFolder->search()->recursive());
+ } else {
+ mChkbxAllFolders->setChecked(true);
+ }
+ mFolder = searchFolder;
+ }
+ mPatternEdit->setSearchPattern( mSearchPattern );
+ QObjectList *list = mPatternEdit->queryList( 0, "mRuleField" );
+ QObject *object = 0;
+ if ( list )
+ object = list->first();
+ delete list;
+ if (!searchFolder && object && ::qt_cast<QComboBox*>(object))
+ static_cast<QComboBox*>(object)->setCurrentText("Subject");
+
+ vbl->addWidget( mPatternEdit );
+
+ // enable/disable widgets depending on radio buttons:
+ connect( mChkbxSpecificFolders, SIGNAL(toggled(bool)),
+ mCbxFolders, SLOT(setEnabled(bool)) );
+ connect( mChkbxSpecificFolders, SIGNAL(toggled(bool)),
+ mChkSubFolders, SLOT(setEnabled(bool)) );
+ connect( mChkbxAllFolders, SIGNAL(toggled(bool)),
+ this, SLOT(setEnabledSearchButton(bool)) );
+
+ mLbxMatches = new MatchListView(searchWidget, this, "Find Messages");
+
+ /*
+ Default is to sort by date. TODO: Unfortunately this sorts *while*
+ inserting, which looks rather strange - the user cannot read
+ the results so far as they are constantly re-sorted --dnaber
+
+ Sorting is now disabled when a search is started and reenabled
+ when it stops. Items are appended to the list. This not only
+ solves the above problem, but speeds searches with many hits
+ up considerably. - till
+
+ TODO: subclass KListViewItem and do proper (and performant)
+ comapare functions
+ */
+ mLbxMatches->setSorting(2, false);
+ mLbxMatches->setShowSortIndicator(true);
+ mLbxMatches->setAllColumnsShowFocus(true);
+ mLbxMatches->setSelectionModeExt(KListView::Extended);
+ mLbxMatches->addColumn(i18n("Subject"),
+ config->readNumEntry("SubjectWidth", 150));
+ mLbxMatches->addColumn(i18n("Sender/Receiver"),
+ config->readNumEntry("SenderWidth", 120));
+ mLbxMatches->addColumn(i18n("Date"),
+ config->readNumEntry("DateWidth", 120));
+ mLbxMatches->addColumn(i18n("Folder"),
+ config->readNumEntry("FolderWidth", 100));
+
+ mLbxMatches->addColumn(""); // should be hidden
+ mLbxMatches->setColumnWidthMode( MSGID_COLUMN, QListView::Manual );
+ mLbxMatches->setColumnWidth(MSGID_COLUMN, 0);
+ mLbxMatches->header()->setResizeEnabled(false, MSGID_COLUMN);
+
+ mLbxMatches->setDragEnabled( true );
+
+ connect(mLbxMatches, SIGNAL(doubleClicked(QListViewItem *)),
+ this, SLOT(slotShowMsg(QListViewItem *)));
+ connect(mLbxMatches, SIGNAL(currentChanged(QListViewItem *)),
+ this, SLOT(slotCurrentChanged(QListViewItem *)));
+ connect( mLbxMatches, SIGNAL( contextMenuRequested( QListViewItem*, const QPoint &, int )),
+ this, SLOT( slotContextMenuRequested( QListViewItem*, const QPoint &, int )));
+ vbl->addWidget(mLbxMatches);
+
+ QHBoxLayout *hbl2 = new QHBoxLayout( vbl, spacingHint(), "kmfs_hbl2" );
+ mSearchFolderLbl = new QLabel(i18n("Search folder &name:"), searchWidget);
+ hbl2->addWidget(mSearchFolderLbl);
+ mSearchFolderEdt = new KLineEdit(searchWidget);
+ if (searchFolder)
+ mSearchFolderEdt->setText(searchFolder->folder()->name());
+ else
+ mSearchFolderEdt->setText(i18n("Last Search"));
+
+ mSearchFolderLbl->setBuddy(mSearchFolderEdt);
+ hbl2->addWidget(mSearchFolderEdt);
+ mSearchFolderOpenBtn = new QPushButton(i18n("Op&en Search Folder"), searchWidget);
+ mSearchFolderOpenBtn->setEnabled(false);
+ hbl2->addWidget(mSearchFolderOpenBtn);
+ connect( mSearchFolderEdt, SIGNAL( textChanged( const QString &)),
+ this, SLOT( scheduleRename( const QString & )));
+ connect( &mRenameTimer, SIGNAL( timeout() ),
+ this, SLOT( renameSearchFolder() ));
+ connect( mSearchFolderOpenBtn, SIGNAL( clicked() ),
+ this, SLOT( openSearchFolder() ));
+ mSearchResultOpenBtn = new QPushButton(i18n("Open &Message"), searchWidget);
+ mSearchResultOpenBtn->setEnabled(false);
+ hbl2->addWidget(mSearchResultOpenBtn);
+ connect( mSearchResultOpenBtn, SIGNAL( clicked() ),
+ this, SLOT( slotShowSelectedMsg() ));
+ mStatusBar = new KStatusBar(searchWidget);
+ mStatusBar->insertFixedItem(i18n("AMiddleLengthText..."), 0, true);
+ mStatusBar->changeItem(i18n("Ready."), 0);
+ mStatusBar->setItemAlignment(0, AlignLeft | AlignVCenter);
+ mStatusBar->insertItem(QString::null, 1, 1, true);
+ mStatusBar->setItemAlignment(1, AlignLeft | AlignVCenter);
+ vbl->addWidget(mStatusBar);
+
+ int mainWidth = config->readNumEntry("SearchWidgetWidth", 0);
+ int mainHeight = config->readNumEntry("SearchWidgetHeight", 0);
+
+ if (mainWidth || mainHeight)
+ resize(mainWidth, mainHeight);
+
+ setMainWidget(searchWidget);
+ setButtonBoxOrientation(QWidget::Vertical);
+
+ mBtnSearch = actionButton(KDialogBase::User1);
+ mBtnStop = actionButton(KDialogBase::User2);
+ mBtnStop->setEnabled(false);
+
+ connect(this, SIGNAL(user1Clicked()), SLOT(slotSearch()));
+ connect(this, SIGNAL(user2Clicked()), SLOT(slotStop()));
+ connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
+
+ // give focus to the value field of the first search rule
+ object = mPatternEdit->child( "regExpLineEdit" );
+ if ( object && object->isWidgetType() ) {
+ static_cast<QWidget*>(object)->setFocus();
+ //kdDebug(5006) << "SearchWindow: focus has been given to widget "
+ // << object->name() << endl;
+ }
+ else
+ kdDebug(5006) << "SearchWindow: regExpLineEdit not found" << endl;
+
+ //set up actions
+ KActionCollection *ac = actionCollection();
+ ac->setWidget( this );
+ mReplyAction = new KAction( i18n("&Reply..."), "mail_reply", 0, this,
+ SLOT(slotReplyToMsg()), ac, "search_reply" );
+ mReplyAllAction = new KAction( i18n("Reply to &All..."), "mail_replyall",
+ 0, this, SLOT(slotReplyAllToMsg()),
+ ac, "search_reply_all" );
+ mReplyListAction = new KAction( i18n("Reply to Mailing-&List..."),
+ "mail_replylist", 0, this,
+ SLOT(slotReplyListToMsg()), ac,
+ "search_reply_list" );
+ mForwardActionMenu = new KActionMenu( i18n("Message->","&Forward"),
+ "mail_forward", ac,
+ "search_message_forward" );
+ connect( mForwardActionMenu, SIGNAL(activated()), this,
+ SLOT(slotForwardInlineMsg()) );
+ mForwardAttachedAction = new KAction( i18n("Message->Forward->","As &Attachment..."),
+ "mail_forward", 0, this,
+ SLOT(slotForwardAttachedMsg()), ac,
+ "search_message_forward_as_attachment" );
+ mForwardInlineAction = new KAction( i18n("&Inline..."),
+ "mail_forward", 0, this,
+ SLOT(slotForwardInlineMsg()), ac,
+ "search_message_forward_inline" );
+ if ( GlobalSettings::self()->forwardingInlineByDefault() ) {
+ mForwardActionMenu->insert( mForwardInlineAction );
+ mForwardActionMenu->insert( mForwardAttachedAction );
+ } else {
+ mForwardActionMenu->insert( mForwardAttachedAction );
+ mForwardActionMenu->insert( mForwardInlineAction );
+ }
+
+ mForwardDigestAction = new KAction( i18n("Message->Forward->","As Di&gest..."),
+ "mail_forward", 0, this,
+ SLOT(slotForwardDigestMsg()), ac,
+ "search_message_forward_as_digest" );
+ mForwardActionMenu->insert( mForwardDigestAction );
+ mRedirectAction = new KAction( i18n("Message->Forward->","&Redirect..."),
+ "mail_forward", 0, this,
+ SLOT(slotRedirectMsg()), ac,
+ "search_message_forward_redirect" );
+ mForwardActionMenu->insert( mRedirectAction );
+ mSaveAsAction = KStdAction::saveAs( this, SLOT(slotSaveMsg()), ac, "search_file_save_as" );
+ mSaveAtchAction = new KAction( i18n("Save Attachments..."), "attach", 0,
+ this, SLOT(slotSaveAttachments()), ac, "search_save_attachments" );
+
+ mPrintAction = KStdAction::print( this, SLOT(slotPrintMsg()), ac, "search_print" );
+ mClearAction = new KAction( i18n("Clear Selection"), 0, 0, this,
+ SLOT(slotClearSelection()), ac, "search_clear_selection" );
+
+ mCopyAction = KStdAction::copy( this, SLOT(slotCopyMsgs()), ac, "search_copy_messages" );
+ mCutAction = KStdAction::cut( this, SLOT(slotCutMsgs()), ac, "search_cut_messages" );
+
+ connect(mTimer, SIGNAL(timeout()), this, SLOT(updStatus()));
+ connect(kmkernel->searchFolderMgr(), SIGNAL(folderInvalidated(KMFolder*)),
+ this, SLOT(folderInvalidated(KMFolder*)));
+
+ connect(mCbxFolders, SIGNAL(folderChanged(KMFolder*)),
+ this, SLOT(slotFolderActivated()));
+
+}
+
+//-----------------------------------------------------------------------------
+SearchWindow::~SearchWindow()
+{
+ QValueListIterator<QGuardedPtr<KMFolder> > fit;
+ for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
+ if (!(*fit))
+ continue;
+ (*fit)->close("searchwindow");
+ }
+
+ KConfig* config = KMKernel::config();
+ config->setGroup("SearchDialog");
+ config->writeEntry("SubjectWidth", mLbxMatches->columnWidth(0));
+ config->writeEntry("SenderWidth", mLbxMatches->columnWidth(1));
+ config->writeEntry("DateWidth", mLbxMatches->columnWidth(2));
+ config->writeEntry("FolderWidth", mLbxMatches->columnWidth(3));
+ config->writeEntry("SearchWidgetWidth", width());
+ config->writeEntry("SearchWidgetHeight", height());
+ config->sync();
+}
+
+void SearchWindow::setEnabledSearchButton(bool)
+{
+ //Make sure that button is enable
+ //Before when we selected a folder == "Local Folder" as that it was not a folder
+ //search button was disable, and when we select "Search in all local folder"
+ //Search button was never enabled :(
+ mBtnSearch->setEnabled( true );
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::updStatus(void)
+{
+ QString genMsg, detailMsg, procMsg;
+ int numMatches = 0, numProcessed = 0;
+ KMSearch const *search = (mFolder) ? (mFolder->search()) : 0;
+ QString folderName;
+ if (search) {
+ numMatches = search->foundCount();
+ numProcessed = search->searchCount();
+ folderName = search->currentFolder();
+ }
+
+ if (search && !search->running()) {
+ procMsg = i18n("%n message searched", "%n messages searched",
+ numProcessed);
+ if(!mStopped) {
+ genMsg = i18n("Done.");
+ detailMsg = i18n("%n match in %1", "%n matches in %1",
+ numMatches).arg(procMsg);
+ } else {
+ genMsg = i18n("Search canceled.");
+ detailMsg = i18n("%n match so far in %1", "%n matches so far in %1",
+ numMatches).arg(procMsg);
+ }
+ } else {
+ procMsg = i18n("%n message", "%n messages", numProcessed);
+ genMsg = i18n("%n match", "%n matches", numMatches);
+ detailMsg = i18n("Searching in %1. %2 searched so far")
+ .arg(folderName).arg(procMsg);
+ }
+
+ mStatusBar->changeItem(genMsg, 0);
+ mStatusBar->changeItem(detailMsg, 1);
+}
+
+
+//-----------------------------------------------------------------------------
+void SearchWindow::keyPressEvent(QKeyEvent *evt)
+{
+ KMSearch const *search = (mFolder) ? mFolder->search() : 0;
+ bool searching = (search) ? search->running() : false;
+ if (evt->key() == Key_Escape && searching) {
+ mFolder->stopSearch();
+ return;
+ }
+
+ KDialogBase::keyPressEvent(evt);
+}
+
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotFolderActivated()
+{
+ mChkbxSpecificFolders->setChecked(true);
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::activateFolder(KMFolder *curFolder)
+{
+ mChkbxSpecificFolders->setChecked(true);
+ mCbxFolders->setFolder(curFolder);
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotSearch()
+{
+ mLastFocus = focusWidget();
+ mBtnSearch->setFocus(); // set focus so we don't miss key event
+
+ mStopped = false;
+ mFetchingInProgress = 0;
+
+ mSearchFolderOpenBtn->setEnabled(true);
+ mBtnSearch->setEnabled(false);
+ mBtnStop->setEnabled(true);
+
+ mLbxMatches->clear();
+
+ mSortColumn = mLbxMatches->sortColumn();
+ mSortOrder = mLbxMatches->sortOrder();
+ mLbxMatches->setSorting(-1);
+ mLbxMatches->setShowSortIndicator(false);
+
+ // If we haven't openend an existing search folder, find or
+ // create one.
+ if (!mFolder) {
+ KMFolderMgr *mgr = kmkernel->searchFolderMgr();
+ if (mSearchFolderEdt->text().isEmpty())
+ mSearchFolderEdt->setText(i18n("Last Search"));
+ QString baseName = mSearchFolderEdt->text();
+ QString fullName = baseName;
+ int count = 0;
+ KMFolder *folder;
+ while ((folder = mgr->find(fullName))) {
+ if (folder->storage()->inherits("KMFolderSearch"))
+ break;
+ fullName = QString("%1 %2").arg(baseName).arg(++count);
+ }
+
+ if (!folder)
+ folder = mgr->createFolder(fullName, false, KMFolderTypeSearch,
+ &mgr->dir());
+
+ mFolder = dynamic_cast<KMFolderSearch*>( folder->storage() );
+ }
+ mFolder->stopSearch();
+ disconnect(mFolder, SIGNAL(msgAdded(int)),
+ this, SLOT(slotAddMsg(int)));
+ disconnect(mFolder, SIGNAL(msgRemoved(KMFolder*, Q_UINT32)),
+ this, SLOT(slotRemoveMsg(KMFolder*, Q_UINT32)));
+ connect(mFolder, SIGNAL(msgAdded(int)),
+ this, SLOT(slotAddMsg(int)));
+ connect(mFolder, SIGNAL(msgRemoved(KMFolder*, Q_UINT32)),
+ this, SLOT(slotRemoveMsg(KMFolder*, Q_UINT32)));
+ mSearchFolderEdt->setEnabled(false);
+ KMSearch *search = new KMSearch();
+ connect(search, SIGNAL(finished(bool)),
+ this, SLOT(searchDone()));
+ if (mChkbxAllFolders->isChecked()) {
+ search->setRecursive(true);
+ } else {
+ search->setRoot(mCbxFolders->folder());
+ search->setRecursive(mChkSubFolders->isChecked());
+ }
+
+ mPatternEdit->updateSearchPattern();
+ KMSearchPattern *searchPattern = new KMSearchPattern();
+ *searchPattern = *mSearchPattern; //deep copy
+ searchPattern->purify();
+ search->setSearchPattern(searchPattern);
+ mFolder->setSearch(search);
+ enableGUI();
+
+ mTimer->start(200);
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::searchDone()
+{
+ mTimer->stop();
+ updStatus();
+
+ QTimer::singleShot(0, this, SLOT(enableGUI()));
+ if(mLastFocus)
+ mLastFocus->setFocus();
+ if (mCloseRequested)
+ close();
+
+ mLbxMatches->setSorting(mSortColumn, mSortOrder == Ascending);
+ mLbxMatches->setShowSortIndicator(true);
+
+ mSearchFolderEdt->setEnabled(true);
+}
+
+void SearchWindow::slotAddMsg(int idx)
+{
+ if (!mFolder)
+ return;
+ bool unget = !mFolder->isMessage(idx);
+ KMMessage *msg = mFolder->getMsg(idx);
+ QString from, fName;
+ KMFolder *pFolder = msg->parent();
+ if (!mFolders.contains(pFolder)) {
+ mFolders.append(pFolder);
+ pFolder->open("searchwindow");
+ }
+ if(pFolder->whoField() == "To")
+ from = msg->to();
+ else
+ from = msg->from();
+ if (pFolder->isSystemFolder())
+ fName = i18n(pFolder->name().utf8());
+ else
+ fName = pFolder->name();
+
+ (void)new KListViewItem(mLbxMatches, mLbxMatches->lastItem(),
+ msg->subject(), from, msg->dateIsoStr(),
+ fName,
+ QString::number(mFolder->serNum(idx)));
+ if (unget)
+ mFolder->unGetMsg(idx);
+}
+
+void SearchWindow::slotRemoveMsg(KMFolder *, Q_UINT32 serNum)
+{
+ if (!mFolder)
+ return;
+ QListViewItemIterator it(mLbxMatches);
+ while (it.current()) {
+ QListViewItem *item = *it;
+ if (serNum == (*it)->text(MSGID_COLUMN).toUInt()) {
+ delete item;
+ return;
+ }
+ ++it;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotStop()
+{
+ if (mFolder)
+ mFolder->stopSearch();
+ mStopped = true;
+ mBtnStop->setEnabled(false);
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotClose()
+{
+ accept();
+}
+
+
+//-----------------------------------------------------------------------------
+void SearchWindow::closeEvent(QCloseEvent *e)
+{
+ if (mFolder && mFolder->search() && mFolder->search()->running()) {
+ mCloseRequested = true;
+ //Cancel search in progress by setting the search folder search to
+ //the null search
+ mFolder->setSearch(new KMSearch());
+ QTimer::singleShot(0, this, SLOT(slotClose()));
+ } else {
+ KDialogBase::closeEvent(e);
+ }
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::scheduleRename( const QString &s)
+{
+ if (!s.isEmpty() && s != i18n("Last Search")) {
+ mRenameTimer.start(250, true);
+ mSearchFolderOpenBtn->setEnabled(false);
+ } else {
+ mRenameTimer.stop();
+ mSearchFolderOpenBtn->setEnabled(true);
+ }
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::renameSearchFolder()
+{
+ if (mFolder && (mFolder->folder()->name() != mSearchFolderEdt->text())) {
+ int i = 1;
+ QString name = mSearchFolderEdt->text();
+ while (i < 100) {
+ if (!kmkernel->searchFolderMgr()->find( name )) {
+ mFolder->rename( name );
+ kmkernel->searchFolderMgr()->contentsChanged();
+ break;
+ }
+ name.setNum( i );
+ name = mSearchFolderEdt->text() + " " + name;
+ ++i;
+ }
+ }
+ mSearchFolderOpenBtn->setEnabled(true);
+}
+
+void SearchWindow::openSearchFolder()
+{
+ renameSearchFolder();
+ mKMMainWidget->slotSelectFolder( mFolder->folder() );
+ slotClose();
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::folderInvalidated(KMFolder *folder)
+{
+ if (folder->storage() == mFolder) {
+ mLbxMatches->clear();
+ if (mFolder->search())
+ connect(mFolder->search(), SIGNAL(finished(bool)),
+ this, SLOT(searchDone()));
+ mTimer->start(200);
+ enableGUI();
+ }
+}
+
+//-----------------------------------------------------------------------------
+bool SearchWindow::slotShowMsg(QListViewItem *item)
+{
+ if(!item)
+ return false;
+
+ KMFolder* folder;
+ int msgIndex;
+ KMMsgDict::instance()->getLocation(item->text(MSGID_COLUMN).toUInt(),
+ &folder, &msgIndex);
+
+ if (!folder || msgIndex < 0)
+ return false;
+
+ mKMMainWidget->slotSelectFolder(folder);
+ KMMessage* message = folder->getMsg(msgIndex);
+ if (!message)
+ return false;
+
+ mKMMainWidget->slotSelectMessage(message);
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotShowSelectedMsg()
+{
+ slotShowMsg(mLbxMatches->currentItem());
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotCurrentChanged(QListViewItem *item)
+{
+ mSearchResultOpenBtn->setEnabled(item!=0);
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::enableGUI()
+{
+ KMSearch const *search = (mFolder) ? (mFolder->search()) : 0;
+ bool searching = (search) ? (search->running()) : false;
+ actionButton(KDialogBase::Close)->setEnabled(!searching);
+ mCbxFolders->setEnabled(!searching);
+ mChkSubFolders->setEnabled(!searching);
+ mChkbxAllFolders->setEnabled(!searching);
+ mChkbxSpecificFolders->setEnabled(!searching);
+ mPatternEdit->setEnabled(!searching);
+ mBtnSearch->setEnabled(!searching);
+ mBtnStop->setEnabled(searching);
+}
+
+
+//-----------------------------------------------------------------------------
+KMMessageList SearchWindow::selectedMessages()
+{
+ KMMessageList msgList;
+ KMFolder* folder = 0;
+ int msgIndex = -1;
+ for (QListViewItemIterator it(mLbxMatches); it.current(); it++)
+ if (it.current()->isSelected()) {
+ KMMsgDict::instance()->getLocation((*it)->text(MSGID_COLUMN).toUInt(),
+ &folder, &msgIndex);
+ if (folder && msgIndex >= 0)
+ msgList.append(folder->getMsgBase(msgIndex));
+ }
+ return msgList;
+}
+
+//-----------------------------------------------------------------------------
+KMMessage* SearchWindow::message()
+{
+ QListViewItem *item = mLbxMatches->currentItem();
+ KMFolder* folder = 0;
+ int msgIndex = -1;
+ if (!item)
+ return 0;
+ KMMsgDict::instance()->getLocation(item->text(MSGID_COLUMN).toUInt(),
+ &folder, &msgIndex);
+ if (!folder || msgIndex < 0)
+ return 0;
+
+ return folder->getMsg(msgIndex);
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::moveSelectedToFolder( int menuId )
+{
+ KMFolder *dest = mMenuToFolder[menuId];
+ if (!dest)
+ return;
+
+ KMMessageList msgList = selectedMessages();
+ KMCommand *command = new KMMoveCommand( dest, msgList );
+ command->start();
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::copySelectedToFolder( int menuId )
+{
+ KMFolder *dest = mMenuToFolder[menuId];
+ if (!dest)
+ return;
+
+ KMMessageList msgList = selectedMessages();
+ KMCommand *command = new KMCopyCommand( dest, msgList );
+ command->start();
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::updateContextMenuActions()
+{
+ int count = selectedMessages().count();
+ bool single_actions = count == 1;
+ mReplyAction->setEnabled( single_actions );
+ mReplyAllAction->setEnabled( single_actions );
+ mReplyListAction->setEnabled( single_actions );
+ mPrintAction->setEnabled( single_actions );
+ mForwardDigestAction->setEnabled( !single_actions );
+ mRedirectAction->setEnabled( single_actions );
+ mCopyAction->setEnabled( count > 0 );
+ mCutAction->setEnabled( count > 0 );
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotContextMenuRequested( QListViewItem *lvi, const QPoint &, int )
+{
+ if (!lvi)
+ return;
+ mLbxMatches->setSelected( lvi, true );
+ mLbxMatches->setCurrentItem( lvi );
+ // FIXME is this ever unGetMsg()'d?
+ if (!message())
+ return;
+ QPopupMenu *menu = new QPopupMenu(this);
+ updateContextMenuActions();
+
+ mMenuToFolder.clear();
+ QPopupMenu *msgMoveMenu = new QPopupMenu(menu);
+ mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::MoveMessage,
+ this, &mMenuToFolder, msgMoveMenu );
+ QPopupMenu *msgCopyMenu = new QPopupMenu(menu);
+ mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::CopyMessage,
+ this, &mMenuToFolder, msgCopyMenu );
+
+ // show most used actions
+ mReplyAction->plug(menu);
+ mReplyAllAction->plug(menu);
+ mReplyListAction->plug(menu);
+ mForwardActionMenu->plug(menu);
+ menu->insertSeparator();
+ mCopyAction->plug(menu);
+ mCutAction->plug(menu);
+ menu->insertItem(i18n("&Copy To"), msgCopyMenu);
+ menu->insertItem(i18n("&Move To"), msgMoveMenu);
+ menu->insertSeparator();
+ mSaveAsAction->plug(menu);
+ mSaveAtchAction->plug(menu);
+ mPrintAction->plug(menu);
+ menu->insertSeparator();
+ mClearAction->plug(menu);
+ menu->exec (QCursor::pos(), 0);
+ delete menu;
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotClearSelection()
+{
+ mLbxMatches->clearSelection();
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotReplyToMsg()
+{
+ KMCommand *command = new KMReplyToCommand(this, message());
+ command->start();
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotReplyAllToMsg()
+{
+ KMCommand *command = new KMReplyToAllCommand(this, message());
+ command->start();
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotReplyListToMsg()
+{
+ KMCommand *command = new KMReplyListCommand(this, message());
+ command->start();
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotForwardInlineMsg()
+{
+ KMCommand *command = new KMForwardInlineCommand(this, selectedMessages());
+ command->start();
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotForwardAttachedMsg()
+{
+ KMCommand *command = new KMForwardAttachedCommand(this, selectedMessages());
+ command->start();
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotForwardDigestMsg()
+{
+ KMCommand *command = new KMForwardDigestCommand(this, selectedMessages());
+ command->start();
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotRedirectMsg()
+{
+ KMCommand *command = new KMRedirectCommand(this, message());
+ command->start();
+}
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotSaveMsg()
+{
+ KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand(this,
+ selectedMessages());
+ if (saveCommand->url().isEmpty())
+ delete saveCommand;
+ else
+ saveCommand->start();
+}
+//-----------------------------------------------------------------------------
+void SearchWindow::slotSaveAttachments()
+{
+ KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand(this,
+ selectedMessages());
+ saveCommand->start();
+}
+
+
+//-----------------------------------------------------------------------------
+void SearchWindow::slotPrintMsg()
+{
+ KMCommand *command = new KMPrintCommand(this, message());
+ command->start();
+}
+
+void SearchWindow::slotCopyMsgs()
+{
+ QValueList<Q_UINT32> list = MessageCopyHelper::serNumListFromMsgList( selectedMessages() );
+ mKMMainWidget->headers()->setCopiedMessages( list, false );
+}
+
+void SearchWindow::slotCutMsgs()
+{
+ QValueList<Q_UINT32> list = MessageCopyHelper::serNumListFromMsgList( selectedMessages() );
+ mKMMainWidget->headers()->setCopiedMessages( list, true );
+}
+
+
+void SearchWindow::setSearchPattern( const KMSearchPattern& pattern )
+{
+ *mSearchPattern = pattern;
+ mPatternEdit->setSearchPattern( mSearchPattern );
+}
+
+} // namespace KMail
+#include "searchwindow.moc"