You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
970 lines
34 KiB
970 lines
34 KiB
/*
|
|
* 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 <twin.h>
|
|
#include <tdeconfig.h>
|
|
#include <kstdaction.h>
|
|
#include <kiconloader.h>
|
|
|
|
#include <tqcheckbox.h>
|
|
#include <tqlayout.h>
|
|
#include <klineedit.h>
|
|
#include <tqpushbutton.h>
|
|
#include <tqradiobutton.h>
|
|
#include <tqbuttongroup.h>
|
|
#include <tqcombobox.h>
|
|
#include <tqobjectlist.h> //for mPatternEdit->queryList( 0, "mRuleField" )->first();
|
|
#include <tqcursor.h>
|
|
#include <tqpopupmenu.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;
|
|
|
|
// TDEListView sub-class for dnd support
|
|
class MatchListView : public TDEListView
|
|
{
|
|
public:
|
|
MatchListView( TQWidget *parent, SearchWindow* sw, const char* name = 0 ) :
|
|
TDEListView( parent, name ),
|
|
mSearchWindow( sw )
|
|
{}
|
|
|
|
protected:
|
|
virtual TQDragObject* 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 );
|
|
|
|
TQPixmap pixmap;
|
|
if( mailList.count() == 1 )
|
|
pixmap = TQPixmap( DesktopIcon("message", TDEIcon::SizeSmall) );
|
|
else
|
|
pixmap = TQPixmap( DesktopIcon("tdemultiple", TDEIcon::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 TQTimer(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( tqt_xdisplay(), winId(), XA_WM_TRANSIENT_FOR );
|
|
#endif
|
|
KWin::setIcons(winId(), kapp->icon(), kapp->miniIcon());
|
|
|
|
TDEConfig* config = KMKernel::config();
|
|
config->setGroup("SearchDialog");
|
|
|
|
TQWidget* searchWidget = new TQWidget(this);
|
|
TQVBoxLayout *vbl = new TQVBoxLayout( searchWidget, 0, spacingHint(), "kmfs_vbl" );
|
|
|
|
TQButtonGroup * radioGroup = new TQButtonGroup( searchWidget );
|
|
radioGroup->hide();
|
|
|
|
mChkbxAllFolders = new TQRadioButton(i18n("Search in &all local folders"), searchWidget);
|
|
vbl->addWidget( mChkbxAllFolders );
|
|
radioGroup->insert( mChkbxAllFolders );
|
|
|
|
TQHBoxLayout *hbl = new TQHBoxLayout( vbl, spacingHint(), "kmfs_hbl" );
|
|
mChkbxSpecificFolders = new TQRadioButton(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 TQCheckBox(i18n("I&nclude sub-folders"), searchWidget);
|
|
mChkSubFolders->setChecked(true);
|
|
hbl->addWidget(mChkSubFolders);
|
|
|
|
TQWidget *spacer = new TQWidget( searchWidget, "spacer" );
|
|
spacer->setMinimumHeight( 2 );
|
|
vbl->addWidget( spacer );
|
|
|
|
mPatternEdit = new KMSearchPatternEdit( "", searchWidget , "spe", false, true );
|
|
mPatternEdit->setFrameStyle( TQFrame::NoFrame | TQFrame::Plain );
|
|
mPatternEdit->setInsideMargin( 0 );
|
|
mSearchPattern = new KMSearchPattern();
|
|
KMFolderSearch *searchFolder = 0;
|
|
if (curFolder)
|
|
searchFolder = dynamic_cast<KMFolderSearch*>(curFolder->storage());
|
|
if (searchFolder) {
|
|
TDEConfig 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);
|
|
}
|
|
}
|
|
mPatternEdit->setSearchPattern( mSearchPattern );
|
|
TQObjectList *list = mPatternEdit->queryList( 0, "mRuleField" );
|
|
TQObject *object = 0;
|
|
if ( list )
|
|
object = list->first();
|
|
delete list;
|
|
if (!searchFolder && object && ::tqqt_cast<TQComboBox*>(object))
|
|
static_cast<TQComboBox*>(TQT_TQWIDGET(object))->setCurrentText("Subject");
|
|
|
|
vbl->addWidget( mPatternEdit );
|
|
|
|
// enable/disable widgets depending on radio buttons:
|
|
connect( mChkbxSpecificFolders, TQT_SIGNAL(toggled(bool)),
|
|
mCbxFolders, TQT_SLOT(setEnabled(bool)) );
|
|
connect( mChkbxSpecificFolders, TQT_SIGNAL(toggled(bool)),
|
|
mChkSubFolders, TQT_SLOT(setEnabled(bool)) );
|
|
connect( mChkbxAllFolders, TQT_SIGNAL(toggled(bool)),
|
|
TQT_TQOBJECT(this), TQT_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 TDEListViewItem and do proper (and performant)
|
|
comapare functions
|
|
*/
|
|
mLbxMatches->setSorting(2, false);
|
|
mLbxMatches->setShowSortIndicator(true);
|
|
mLbxMatches->setAllColumnsShowFocus(true);
|
|
mLbxMatches->setSelectionModeExt(TDEListView::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, TQListView::Manual );
|
|
mLbxMatches->setColumnWidth(MSGID_COLUMN, 0);
|
|
mLbxMatches->header()->setResizeEnabled(false, MSGID_COLUMN);
|
|
|
|
mLbxMatches->setDragEnabled( true );
|
|
|
|
connect( mLbxMatches, TQT_SIGNAL(clicked(TQListViewItem *)),
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotShowMsg(TQListViewItem *)) );
|
|
connect( mLbxMatches, TQT_SIGNAL(doubleClicked(TQListViewItem *)),
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotViewMsg(TQListViewItem *)) );
|
|
connect( mLbxMatches, TQT_SIGNAL(currentChanged(TQListViewItem *)),
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotCurrentChanged(TQListViewItem *)) );
|
|
connect( mLbxMatches, TQT_SIGNAL(contextMenuRequested(TQListViewItem *,const TQPoint &,int)),
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotContextMenuRequested(TQListViewItem *,const TQPoint &,int)) );
|
|
vbl->addWidget( mLbxMatches );
|
|
|
|
TQHBoxLayout *hbl2 = new TQHBoxLayout( vbl, spacingHint(), "kmfs_hbl2" );
|
|
mSearchFolderLbl = new TQLabel(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 TQPushButton(i18n("Op&en Search Folder"), searchWidget);
|
|
mSearchFolderOpenBtn->setEnabled(false);
|
|
hbl2->addWidget(mSearchFolderOpenBtn);
|
|
connect( mSearchFolderEdt, TQT_SIGNAL( textChanged( const TQString &)),
|
|
TQT_TQOBJECT(this), TQT_SLOT( scheduleRename( const TQString & )));
|
|
connect( &mRenameTimer, TQT_SIGNAL( timeout() ),
|
|
TQT_TQOBJECT(this), TQT_SLOT( renameSearchFolder() ));
|
|
connect( mSearchFolderOpenBtn, TQT_SIGNAL( clicked() ),
|
|
TQT_TQOBJECT(this), TQT_SLOT( openSearchFolder() ));
|
|
mSearchResultOpenBtn = new TQPushButton(i18n("Open &Message"), searchWidget);
|
|
mSearchResultOpenBtn->setEnabled(false);
|
|
hbl2->addWidget(mSearchResultOpenBtn);
|
|
connect( mSearchResultOpenBtn, TQT_SIGNAL( clicked() ),
|
|
TQT_TQOBJECT(this), TQT_SLOT( slotViewSelectedMsg() ));
|
|
mStatusBar = new KStatusBar(searchWidget);
|
|
mStatusBar->insertFixedItem(i18n("AMiddleLengthText..."), 0, true);
|
|
mStatusBar->changeItem(i18n("Ready."), 0);
|
|
mStatusBar->setItemAlignment(0, AlignLeft | AlignVCenter);
|
|
mStatusBar->insertItem(TQString(), 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(Qt::Vertical);
|
|
|
|
mBtnSearch = actionButton(KDialogBase::User1);
|
|
mBtnStop = actionButton(KDialogBase::User2);
|
|
mBtnStop->setEnabled(false);
|
|
|
|
connect(this, TQT_SIGNAL(user1Clicked()), TQT_SLOT(slotSearch()));
|
|
connect(this, TQT_SIGNAL(user2Clicked()), TQT_SLOT(slotStop()));
|
|
connect(this, TQT_SIGNAL(finished()), TQT_TQOBJECT(this), TQT_SLOT(deleteLater()));
|
|
|
|
// give focus to the value field of the first search rule
|
|
object = mPatternEdit->child( "regExpLineEdit" );
|
|
if ( object && object->isWidgetType() ) {
|
|
TQT_TQWIDGET(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
|
|
TDEActionCollection *ac = actionCollection();
|
|
ac->setWidget( this );
|
|
mReplyAction = new TDEAction( i18n("&Reply..."), "mail_reply", 0, TQT_TQOBJECT(this),
|
|
TQT_SLOT(slotReplyToMsg()), ac, "search_reply" );
|
|
mReplyAllAction = new TDEAction( i18n("Reply to &All..."), "mail_replyall",
|
|
0, TQT_TQOBJECT(this), TQT_SLOT(slotReplyAllToMsg()),
|
|
ac, "search_reply_all" );
|
|
mReplyListAction = new TDEAction( i18n("Reply to Mailing-&List..."),
|
|
"mail_replylist", 0, TQT_TQOBJECT(this),
|
|
TQT_SLOT(slotReplyListToMsg()), ac,
|
|
"search_reply_list" );
|
|
mForwardActionMenu = new TDEActionMenu( i18n("Message->","&Forward"),
|
|
"mail_forward", ac,
|
|
"search_message_forward" );
|
|
connect( mForwardActionMenu, TQT_SIGNAL(activated()), this,
|
|
TQT_SLOT(slotForwardInlineMsg()) );
|
|
mForwardAttachedAction = new TDEAction( i18n("Message->Forward->","As &Attachment..."),
|
|
"mail_forward", 0, TQT_TQOBJECT(this),
|
|
TQT_SLOT(slotForwardAttachedMsg()), ac,
|
|
"search_message_forward_as_attachment" );
|
|
mForwardInlineAction = new TDEAction( i18n("&Inline..."),
|
|
"mail_forward", 0, TQT_TQOBJECT(this),
|
|
TQT_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 TDEAction( i18n("Message->Forward->","As Di&gest..."),
|
|
"mail_forward", 0, TQT_TQOBJECT(this),
|
|
TQT_SLOT(slotForwardDigestMsg()), ac,
|
|
"search_message_forward_as_digest" );
|
|
mForwardActionMenu->insert( mForwardDigestAction );
|
|
mRedirectAction = new TDEAction( i18n("Message->Forward->","&Redirect..."),
|
|
"mail_forward", 0, TQT_TQOBJECT(this),
|
|
TQT_SLOT(slotRedirectMsg()), ac,
|
|
"search_message_forward_redirect" );
|
|
mForwardActionMenu->insert( mRedirectAction );
|
|
mSaveAsAction = KStdAction::saveAs( TQT_TQOBJECT(this), TQT_SLOT(slotSaveMsg()), ac, "search_file_save_as" );
|
|
mSaveAtchAction = new TDEAction( i18n("Save Attachments..."), "attach", 0,
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotSaveAttachments()), ac, "search_save_attachments" );
|
|
|
|
mPrintAction = KStdAction::print( TQT_TQOBJECT(this), TQT_SLOT(slotPrintMsg()), ac, "search_print" );
|
|
mClearAction = new TDEAction( i18n("Clear Selection"), 0, 0, TQT_TQOBJECT(this),
|
|
TQT_SLOT(slotClearSelection()), ac, "search_clear_selection" );
|
|
|
|
mCopyAction = KStdAction::copy( TQT_TQOBJECT(this), TQT_SLOT(slotCopyMsgs()), ac, "search_copy_messages" );
|
|
mCutAction = KStdAction::cut( TQT_TQOBJECT(this), TQT_SLOT(slotCutMsgs()), ac, "search_cut_messages" );
|
|
|
|
connect(mTimer, TQT_SIGNAL(timeout()), TQT_TQOBJECT(this), TQT_SLOT(updStatus()));
|
|
connect(kmkernel->searchFolderMgr(), TQT_SIGNAL(folderInvalidated(KMFolder*)),
|
|
TQT_TQOBJECT(this), TQT_SLOT(folderInvalidated(KMFolder*)));
|
|
|
|
connect(mCbxFolders, TQT_SIGNAL(folderChanged(KMFolder*)),
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotFolderActivated()));
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
SearchWindow::~SearchWindow()
|
|
{
|
|
TQValueListIterator<TQGuardedPtr<KMFolder> > fit;
|
|
for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
|
|
if (!(*fit))
|
|
continue;
|
|
(*fit)->close("searchwindow");
|
|
}
|
|
|
|
TDEConfig* 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)
|
|
{
|
|
TQString genMsg, detailMsg, procMsg;
|
|
int numMatches = 0, numProcessed = 0;
|
|
KMSearch const *search = (mFolder) ? (mFolder->search()) : 0;
|
|
TQString 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(TQKeyEvent *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);
|
|
if ( mSearchFolderEdt->text().isEmpty() ) {
|
|
mSearchFolderEdt->setText( i18n("Last Search") );
|
|
}
|
|
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();
|
|
TQString baseName = mSearchFolderEdt->text();
|
|
TQString fullName = baseName;
|
|
int count = 0;
|
|
KMFolder *folder;
|
|
while ((folder = mgr->find(fullName))) {
|
|
if (folder->storage()->inherits("KMFolderSearch"))
|
|
break;
|
|
fullName = TQString("%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, TQT_SIGNAL(msgAdded(int)),
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotAddMsg(int)));
|
|
disconnect(mFolder, TQT_SIGNAL(msgRemoved(KMFolder*, TQ_UINT32)),
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotRemoveMsg(KMFolder*, TQ_UINT32)));
|
|
connect(mFolder, TQT_SIGNAL(msgAdded(int)),
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotAddMsg(int)));
|
|
connect(mFolder, TQT_SIGNAL(msgRemoved(KMFolder*, TQ_UINT32)),
|
|
TQT_TQOBJECT(this), TQT_SLOT(slotRemoveMsg(KMFolder*, TQ_UINT32)));
|
|
mSearchFolderEdt->setEnabled(false);
|
|
KMSearch *search = new KMSearch();
|
|
connect(search, TQT_SIGNAL(finished(bool)),
|
|
TQT_TQOBJECT(this), TQT_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();
|
|
|
|
TQTimer::singleShot(0, TQT_TQOBJECT(this), TQT_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);
|
|
TQString 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 TDEListViewItem(mLbxMatches, mLbxMatches->lastItem(),
|
|
msg->subject(), from, msg->dateIsoStr(),
|
|
fName,
|
|
TQString::number(mFolder->serNum(idx)));
|
|
if (unget)
|
|
mFolder->unGetMsg(idx);
|
|
}
|
|
|
|
void SearchWindow::slotRemoveMsg(KMFolder *, TQ_UINT32 serNum)
|
|
{
|
|
if (!mFolder)
|
|
return;
|
|
TQListViewItemIterator it(mLbxMatches);
|
|
while (it.current()) {
|
|
TQListViewItem *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(TQCloseEvent *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());
|
|
TQTimer::singleShot(0, TQT_TQOBJECT(this), TQT_SLOT(slotClose()));
|
|
} else {
|
|
KDialogBase::closeEvent(e);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void SearchWindow::scheduleRename( const TQString &s)
|
|
{
|
|
if (!s.isEmpty() ) {
|
|
mRenameTimer.start(250, true);
|
|
mSearchFolderOpenBtn->setEnabled(false);
|
|
} else {
|
|
mRenameTimer.stop();
|
|
mSearchFolderOpenBtn->setEnabled(!s.isEmpty());
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void SearchWindow::renameSearchFolder()
|
|
{
|
|
if (mFolder && (mFolder->folder()->name() != mSearchFolderEdt->text())) {
|
|
int i = 1;
|
|
TQString 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;
|
|
}
|
|
}
|
|
if ( mFolder )
|
|
mSearchFolderOpenBtn->setEnabled(true);
|
|
}
|
|
|
|
void SearchWindow::openSearchFolder()
|
|
{
|
|
Q_ASSERT( mFolder );
|
|
renameSearchFolder();
|
|
mKMMainWidget->slotSelectFolder( mFolder->folder() );
|
|
slotClose();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void SearchWindow::folderInvalidated(KMFolder *folder)
|
|
{
|
|
if (folder->storage() == mFolder) {
|
|
mLbxMatches->clear();
|
|
if (mFolder->search())
|
|
connect(mFolder->search(), TQT_SIGNAL(finished(bool)),
|
|
TQT_TQOBJECT(this), TQT_SLOT(searchDone()));
|
|
mTimer->start(200);
|
|
enableGUI();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
KMMessage *SearchWindow::indexToMessage( TQListViewItem *item )
|
|
{
|
|
if( !item ) {
|
|
return 0;
|
|
}
|
|
|
|
KMFolder *folder;
|
|
int msgIndex;
|
|
KMMsgDict::instance()->getLocation( item->text( MSGID_COLUMN ).toUInt(),
|
|
&folder, &msgIndex );
|
|
|
|
if ( !folder || msgIndex < 0 ) {
|
|
return 0;
|
|
}
|
|
|
|
mKMMainWidget->slotSelectFolder( folder );
|
|
return folder->getMsg( msgIndex );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool SearchWindow::slotShowMsg( TQListViewItem *item )
|
|
{
|
|
KMMessage *message = indexToMessage( item );
|
|
if ( message ) {
|
|
mKMMainWidget->slotSelectMessage( message );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void SearchWindow::slotViewSelectedMsg()
|
|
{
|
|
slotViewMsg( mLbxMatches->currentItem() );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool SearchWindow::slotViewMsg( TQListViewItem *item )
|
|
{
|
|
KMMessage *message = indexToMessage( item );
|
|
if ( message ) {
|
|
mKMMainWidget->slotMsgActivated( message );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void SearchWindow::slotCurrentChanged(TQListViewItem *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 && !mChkbxAllFolders->isChecked());
|
|
mChkSubFolders->setEnabled(!searching && !mChkbxAllFolders->isChecked());
|
|
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 (TQListViewItemIterator 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()
|
|
{
|
|
TQListViewItem *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( TQListViewItem *lvi, const TQPoint &, int )
|
|
{
|
|
if (!lvi)
|
|
return;
|
|
mLbxMatches->setSelected( lvi, true );
|
|
mLbxMatches->setCurrentItem( lvi );
|
|
// FIXME is this ever unGetMsg()'d?
|
|
if (!message())
|
|
return;
|
|
TQPopupMenu *menu = new TQPopupMenu(this);
|
|
updateContextMenuActions();
|
|
|
|
mMenuToFolder.clear();
|
|
TQPopupMenu *msgMoveMenu = new TQPopupMenu(menu);
|
|
mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::MoveMessage,
|
|
TQT_TQOBJECT(this), &mMenuToFolder, msgMoveMenu );
|
|
TQPopupMenu *msgCopyMenu = new TQPopupMenu(menu);
|
|
mKMMainWidget->folderTree()->folderToPopupMenu( KMFolderTree::CopyMessage,
|
|
TQT_TQOBJECT(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 (TQCursor::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()
|
|
{
|
|
TQValueList<TQ_UINT32> list = MessageCopyHelper::serNumListFromMsgList( selectedMessages() );
|
|
mKMMainWidget->headers()->setCopiedMessages( list, false );
|
|
}
|
|
|
|
void SearchWindow::slotCutMsgs()
|
|
{
|
|
TQValueList<TQ_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"
|