summaryrefslogtreecommitdiffstats
path: root/kmail/kmfilterdlg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmail/kmfilterdlg.cpp')
-rw-r--r--kmail/kmfilterdlg.cpp1354
1 files changed, 1354 insertions, 0 deletions
diff --git a/kmail/kmfilterdlg.cpp b/kmail/kmfilterdlg.cpp
new file mode 100644
index 000000000..29bbe037a
--- /dev/null
+++ b/kmail/kmfilterdlg.cpp
@@ -0,0 +1,1354 @@
+// -*- mode: C++; c-file-style: "gnu" -*-
+// kmfilterdlg.cpp
+// Author: Marc Mutz <Marc@Mutz.com>
+// based on work by Stefan Taferner <taferner@kde.org>
+// This code is under the GPL
+
+#include <config.h>
+#include "kmfilterdlg.h"
+
+// other KMail headers:
+#include "kmsearchpatternedit.h"
+#include "kmfiltermgr.h"
+#include "kmmainwidget.h"
+#include "accountmanager.h"
+using KMail::AccountManager;
+#include "filterimporterexporter.h"
+using KMail::FilterImporterExporter;
+
+// other KDE headers:
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kinputdialog.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+#include <kwin.h>
+#include <kconfig.h>
+#include <kicondialog.h>
+#include <kkeybutton.h>
+#include <klistview.h>
+#include <kpushbutton.h>
+
+// other Qt headers:
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qwidgetstack.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+#include <qcheckbox.h>
+#include <qhbox.h>
+#include <qvalidator.h>
+#include <qtabwidget.h>
+
+// other headers:
+#include <assert.h>
+
+
+// What's this help texts
+const char * _wt_filterlist =
+I18N_NOOP( "<qt><p>This is the list of defined filters. "
+ "They are processed top-to-bottom.</p>"
+ "<p>Click on any filter to edit it "
+ "using the controls in the right-hand half "
+ "of the dialog.</p></qt>" );
+const char * _wt_filterlist_new =
+I18N_NOOP( "<qt><p>Click this button to create a new filter.</p>"
+ "<p>The filter will be inserted just before the currently-"
+ "selected one, but you can always change that "
+ "later on.</p>"
+ "<p>If you have clicked this button accidentally, you can undo this "
+ "by clicking on the <em>Delete</em> button.</p></qt>" );
+const char * _wt_filterlist_copy =
+I18N_NOOP( "<qt><p>Click this button to copy a filter.</p>"
+ "<p>If you have clicked this button accidentally, you can undo this "
+ "by clicking on the <em>Delete</em> button.</p></qt>" );
+const char * _wt_filterlist_delete =
+I18N_NOOP( "<qt><p>Click this button to <em>delete</em> the currently-"
+ "selected filter from the list above.</p>"
+ "<p>There is no way to get the filter back once "
+ "it is deleted, but you can always leave the "
+ "dialog by clicking <em>Cancel</em> to discard the "
+ "changes made.</p></qt>" );
+const char * _wt_filterlist_top =
+I18N_NOOP( "<qt><p>Click this button to move the currently-"
+ "selected filter to the <em>top</em> of the list above.</p>"
+ "<p>This is useful since the order of the filters in the list "
+ "determines the order in which they are tried on messages: "
+ "The topmost filter gets tried first.</p></qt>" );
+const char * _wt_filterlist_up =
+I18N_NOOP( "<qt><p>Click this button to move the currently-"
+ "selected filter <em>up</em> one in the list above.</p>"
+ "<p>This is useful since the order of the filters in the list "
+ "determines the order in which they are tried on messages: "
+ "The topmost filter gets tried first.</p>"
+ "<p>If you have clicked this button accidentally, you can undo this "
+ "by clicking on the <em>Down</em> button.</p></qt>" );
+const char * _wt_filterlist_down =
+I18N_NOOP( "<qt><p>Click this button to move the currently-"
+ "selected filter <em>down</em> one in the list above.</p>"
+ "<p>This is useful since the order of the filters in the list "
+ "determines the order in which they are tried on messages: "
+ "The topmost filter gets tried first.</p>"
+ "<p>If you have clicked this button accidentally, you can undo this "
+ "by clicking on the <em>Up</em> button.</p></qt>" );
+const char * _wt_filterlist_bot =
+I18N_NOOP( "<qt><p>Click this button to move the currently-"
+ "selected filter to the <em>bottom</em> of the list above.</p>"
+ "<p>This is useful since the order of the filters in the list "
+ "determines the order in which they are tried on messages: "
+ "The topmost filter gets tried first.</p></qt>" );
+const char * _wt_filterlist_rename =
+I18N_NOOP( "<qt><p>Click this button to rename the currently-selected filter.</p>"
+ "<p>Filters are named automatically, as long as they start with "
+ "\"&lt;\".</p>"
+ "<p>If you have renamed a filter accidentally and want automatic "
+ "naming back, click this button and select <em>Clear</em> followed "
+ "by <em>OK</em> in the appearing dialog.</p></qt>" );
+const char * _wt_filterdlg_showLater =
+I18N_NOOP( "<qt><p>Check this button to force the confirmation dialog to be "
+ "displayed.</p><p>This is useful if you have defined a ruleset that tags "
+ "messages to be downloaded later. Without the possibility to force "
+ "the dialog popup, these messages could never be downloaded if no "
+ "other large messages were waiting on the server, or if you wanted to "
+ "change the ruleset to tag the messages differently.</p></qt>" );
+
+// The anchor of the filter dialog's help.
+const char * KMFilterDlgHelpAnchor = "filters-id" ;
+const char * KMPopFilterDlgHelpAnchor = "popfilters-id" ;
+
+//=============================================================================
+//
+// class KMFilterDlg (the filter dialog)
+//
+//=============================================================================
+
+KMFilterDlg::KMFilterDlg(QWidget* parent, const char* name, bool popFilter, bool createDummyFilter )
+ : KDialogBase( parent, name, false /* modality */,
+ (popFilter)? i18n("POP3 Filter Rules"): i18n("Filter Rules") /* caption*/,
+ Help|Ok|Apply|Cancel|User1|User2 /* button mask */,
+ Ok /* default btn */, false /* separator */),
+ bPopFilter(popFilter)
+{
+ KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() );
+ setHelp( (bPopFilter)? KMPopFilterDlgHelpAnchor: KMFilterDlgHelpAnchor );
+ setButtonText( User1, i18n("Import") );
+ setButtonText( User2, i18n("Export") );
+ connect( this, SIGNAL(user1Clicked()),
+ this, SLOT( slotImportFilters()) );
+ connect( this, SIGNAL(user2Clicked()),
+ this, SLOT( slotExportFilters()) );
+
+ QWidget *w = new QWidget( this );
+ setMainWidget( w );
+ QHBoxLayout *topLayout = new QHBoxLayout( w, 0, spacingHint(), "topLayout" );
+ QHBoxLayout *hbl = topLayout;
+ QVBoxLayout *vbl2 = 0;
+ QWidget *page1 = 0;
+ QWidget *page2 = 0;
+
+ mFilterList = new KMFilterListBox( i18n("Available Filters"), w, 0, bPopFilter);
+ topLayout->addWidget( mFilterList, 1 /*stretch*/ );
+
+ if(!bPopFilter) {
+ QTabWidget *tabWidget = new QTabWidget( w, "kmfd_tab" );
+ tabWidget->setMargin( KDialog::marginHint() );
+ topLayout->addWidget( tabWidget );
+
+ page1 = new QWidget( tabWidget );
+ tabWidget->addTab( page1, i18n("&General") );
+ hbl = new QHBoxLayout( page1, 0, spacingHint(), "kmfd_hbl" );
+
+ page2 = new QWidget( tabWidget );
+ tabWidget->addTab( page2, i18n("A&dvanced") );
+ vbl2 = new QVBoxLayout( page2, 0, spacingHint(), "kmfd_vbl2" );
+ }
+
+ QVBoxLayout *vbl = new QVBoxLayout( hbl, spacingHint(), "kmfd_vbl" );
+ hbl->setStretchFactor( vbl, 2 );
+
+ mPatternEdit = new KMSearchPatternEdit( i18n("Filter Criteria"), bPopFilter ? w : page1 , "spe", bPopFilter);
+ vbl->addWidget( mPatternEdit, 0, Qt::AlignTop );
+
+ if(bPopFilter){
+ mActionGroup = new KMPopFilterActionWidget( i18n("Filter Action"), w );
+ vbl->addWidget( mActionGroup, 0, Qt::AlignTop );
+
+ mGlobalsBox = new QVGroupBox(i18n("Global Options"), w);
+ mShowLaterBtn = new QCheckBox(i18n("Always &show matched 'Download Later' messages in confirmation dialog"), mGlobalsBox);
+ QWhatsThis::add( mShowLaterBtn, i18n(_wt_filterdlg_showLater) );
+ vbl->addWidget( mGlobalsBox, 0, Qt::AlignTop );
+ }
+ else {
+ QGroupBox *agb = new QGroupBox( 1 /*column*/, Vertical, i18n("Filter Actions"), page1 );
+ mActionLister = new KMFilterActionWidgetLister( agb );
+ vbl->addWidget( agb, 0, Qt::AlignTop );
+
+ mAdvOptsGroup = new QGroupBox ( 1 /*columns*/, Vertical,
+ i18n("Advanced Options"), page2);
+ {
+ QWidget *adv_w = new QWidget( mAdvOptsGroup );
+ QGridLayout *gl = new QGridLayout( adv_w, 8 /*rows*/, 3 /*cols*/,
+ 0 /*border*/, spacingHint() );
+
+ QVBoxLayout *vbl3 = new QVBoxLayout( gl, spacingHint(), "vbl3" );
+ vbl3->addStretch( 1 );
+ mApplyOnIn = new QCheckBox( i18n("Apply this filter to incoming messages:"), adv_w );
+ vbl3->addWidget( mApplyOnIn );
+ QButtonGroup *bg = new QButtonGroup( 0, "bg" );
+ bg->setExclusive( true );
+ mApplyOnForAll = new QRadioButton( i18n("from all accounts"), adv_w );
+ bg->insert( mApplyOnForAll );
+ vbl3->addWidget( mApplyOnForAll );
+ mApplyOnForTraditional = new QRadioButton( i18n("from all but online IMAP accounts"), adv_w );
+ bg->insert( mApplyOnForTraditional );
+ vbl3->addWidget( mApplyOnForTraditional );
+ mApplyOnForChecked = new QRadioButton( i18n("from checked accounts only"), adv_w );
+ bg->insert( mApplyOnForChecked );
+ vbl3->addWidget( mApplyOnForChecked );
+ vbl3->addStretch( 2 );
+
+ mAccountList = new KListView( adv_w, "accountList" );
+ mAccountList->addColumn( i18n("Account Name") );
+ mAccountList->addColumn( i18n("Type") );
+ mAccountList->setAllColumnsShowFocus( true );
+ mAccountList->setFrameStyle( QFrame::WinPanel + QFrame::Sunken );
+ mAccountList->setSorting( -1 );
+ gl->addMultiCellWidget( mAccountList, 0, 3, 1, 3 );
+
+ mApplyOnOut = new QCheckBox( i18n("Apply this filter to &sent messages"), adv_w );
+ gl->addMultiCellWidget( mApplyOnOut, 4, 4, 0, 3 );
+
+ mApplyOnCtrlJ = new QCheckBox( i18n("Apply this filter on manual &filtering"), adv_w );
+ gl->addMultiCellWidget( mApplyOnCtrlJ, 5, 5, 0, 3 );
+
+ mStopProcessingHere = new QCheckBox( i18n("If this filter &matches, stop processing here"), adv_w );
+ gl->addMultiCellWidget( mStopProcessingHere,
+ 6, 6, /*from to row*/
+ 0, 3 /*from to col*/ );
+ mConfigureShortcut = new QCheckBox( i18n("Add this filter to the Apply Filter menu"), adv_w );
+ gl->addMultiCellWidget( mConfigureShortcut, 7, 7, 0, 1 );
+ QLabel *keyButtonLabel = new QLabel( i18n( "Shortcut:" ), adv_w );
+ keyButtonLabel->setAlignment( AlignVCenter | AlignRight );
+ gl->addMultiCellWidget( keyButtonLabel, 7, 7, 2, 2 );
+ mKeyButton = new KKeyButton( adv_w, "FilterShortcutSelector" );
+ gl->addMultiCellWidget( mKeyButton, 7, 7, 3, 3 );
+ mKeyButton->setEnabled( false );
+ mConfigureToolbar = new QCheckBox( i18n("Additionally add this filter to the toolbar"), adv_w );
+ gl->addMultiCellWidget( mConfigureToolbar, 8, 8, 0, 3 );
+ mConfigureToolbar->setEnabled( false );
+
+ QHBox *hbox = new QHBox( adv_w );
+ mFilterActionLabel = new QLabel( i18n( "Icon for this filter:" ),
+ hbox );
+ mFilterActionLabel->setEnabled( false );
+
+ mFilterActionIconButton = new KIconButton( hbox );
+ mFilterActionLabel->setBuddy( mFilterActionIconButton );
+ mFilterActionIconButton->setIconType( KIcon::NoGroup, KIcon::Any, true );
+ mFilterActionIconButton->setIconSize( 16 );
+ mFilterActionIconButton->setIcon( "gear" );
+ mFilterActionIconButton->setEnabled( false );
+
+ gl->addMultiCellWidget( hbox, 9, 9, 0, 3 );
+ }
+ vbl2->addWidget( mAdvOptsGroup, 0, Qt::AlignTop );
+ }
+ // spacer:
+ vbl->addStretch( 1 );
+
+ // load the filter parts into the edit widgets
+ connect( mFilterList, SIGNAL(filterSelected(KMFilter*)),
+ this, SLOT(slotFilterSelected(KMFilter*)) );
+
+ if (bPopFilter){
+ // set the state of the global setting 'show later msgs'
+ connect( mShowLaterBtn, SIGNAL(toggled(bool)),
+ mFilterList, SLOT(slotShowLaterToggled(bool)));
+
+ // set the action in the filter when changed
+ connect( mActionGroup, SIGNAL(actionChanged(const KMPopFilterAction)),
+ this, SLOT(slotActionChanged(const KMPopFilterAction)) );
+ } else {
+ // transfer changes from the 'Apply this filter on...'
+ // combo box to the filter
+ connect( mApplyOnIn, SIGNAL(clicked()),
+ this, SLOT(slotApplicabilityChanged()) );
+ connect( mApplyOnForAll, SIGNAL(clicked()),
+ this, SLOT(slotApplicabilityChanged()) );
+ connect( mApplyOnForTraditional, SIGNAL(clicked()),
+ this, SLOT(slotApplicabilityChanged()) );
+ connect( mApplyOnForChecked, SIGNAL(clicked()),
+ this, SLOT(slotApplicabilityChanged()) );
+ connect( mApplyOnOut, SIGNAL(clicked()),
+ this, SLOT(slotApplicabilityChanged()) );
+ connect( mApplyOnCtrlJ, SIGNAL(clicked()),
+ this, SLOT(slotApplicabilityChanged()) );
+ connect( mAccountList, SIGNAL(clicked(QListViewItem*)),
+ this, SLOT(slotApplicableAccountsChanged()) );
+ connect( mAccountList, SIGNAL(spacePressed(QListViewItem*)),
+ this, SLOT(slotApplicableAccountsChanged()) );
+
+ // transfer changes from the 'stop processing here'
+ // check box to the filter
+ connect( mStopProcessingHere, SIGNAL(toggled(bool)),
+ this, SLOT(slotStopProcessingButtonToggled(bool)) );
+
+ connect( mConfigureShortcut, SIGNAL(toggled(bool)),
+ this, SLOT(slotConfigureShortcutButtonToggled(bool)) );
+
+ connect( mKeyButton, SIGNAL( capturedShortcut( const KShortcut& ) ),
+ this, SLOT( slotCapturedShortcutChanged( const KShortcut& ) ) );
+
+ connect( mConfigureToolbar, SIGNAL(toggled(bool)),
+ this, SLOT(slotConfigureToolbarButtonToggled(bool)) );
+
+ connect( mFilterActionIconButton, SIGNAL( iconChanged( QString ) ),
+ this, SLOT( slotFilterActionIconChanged( QString ) ) );
+ }
+
+ // reset all widgets here
+ connect( mFilterList, SIGNAL(resetWidgets()),
+ this, SLOT(slotReset()) );
+
+ connect( mFilterList, SIGNAL( applyWidgets() ),
+ this, SLOT( slotUpdateFilter() ) );
+
+ // support auto-naming the filter
+ connect( mPatternEdit, SIGNAL(maybeNameChanged()),
+ mFilterList, SLOT(slotUpdateFilterName()) );
+
+ // apply changes on 'Apply'
+ connect( this, SIGNAL(applyClicked()),
+ mFilterList, SLOT(slotApplyFilterChanges()) );
+
+ // apply changes on 'OK'
+ connect( this, SIGNAL(okClicked()),
+ mFilterList, SLOT(slotApplyFilterChanges()) );
+
+ // save dialog size on 'OK'
+ connect( this, SIGNAL(okClicked()),
+ this, SLOT(slotSaveSize()) );
+
+ // destruct the dialog on OK, close and Cancel
+ connect( this, SIGNAL(finished()),
+ this, SLOT(slotFinished()) );
+
+ KConfigGroup geometry( KMKernel::config(), "Geometry");
+ const char * configKey
+ = bPopFilter ? "popFilterDialogSize" : "filterDialogSize";
+ if ( geometry.hasKey( configKey ) )
+ resize( geometry.readSizeEntry( configKey ) );
+ else
+ adjustSize();
+
+ // load the filter list (emits filterSelected())
+ mFilterList->loadFilterList( createDummyFilter );
+}
+
+void KMFilterDlg::slotFinished() {
+ delayedDestruct();
+}
+
+void KMFilterDlg::slotSaveSize() {
+ KConfigGroup geometry( KMKernel::config(), "Geometry" );
+ geometry.writeEntry( bPopFilter ? "popFilterDialogSize" : "filterDialogSize", size() );
+}
+
+/** Set action of popFilter */
+void KMFilterDlg::slotActionChanged(const KMPopFilterAction aAction)
+{
+ mFilter->setAction(aAction);
+}
+
+void KMFilterDlg::slotFilterSelected( KMFilter* aFilter )
+{
+ assert( aFilter );
+
+ if (bPopFilter){
+ mActionGroup->setAction( aFilter->action() );
+ mGlobalsBox->setEnabled( true );
+ mShowLaterBtn->setChecked(mFilterList->showLaterMsgs());
+ } else {
+ mActionLister->setActionList( aFilter->actions() );
+
+ mAdvOptsGroup->setEnabled( true );
+ }
+
+ mPatternEdit->setSearchPattern( aFilter->pattern() );
+ mFilter = aFilter;
+
+ if (!bPopFilter) {
+ kdDebug(5006) << "apply on inbound == "
+ << aFilter->applyOnInbound() << endl;
+ kdDebug(5006) << "apply on outbound == "
+ << aFilter->applyOnOutbound() << endl;
+ kdDebug(5006) << "apply on explicit == "
+ << aFilter->applyOnExplicit() << endl;
+
+ // NOTE: setting these values activates the slot that sets them in
+ // the filter! So make sure we have the correct values _before_ we
+ // set the first one:
+ const bool applyOnIn = aFilter->applyOnInbound();
+ const bool applyOnForAll = aFilter->applicability() == KMFilter::All;
+ const bool applyOnTraditional = aFilter->applicability() == KMFilter::ButImap;
+ const bool applyOnOut = aFilter->applyOnOutbound();
+ const bool applyOnExplicit = aFilter->applyOnExplicit();
+ const bool stopHere = aFilter->stopProcessingHere();
+ const bool configureShortcut = aFilter->configureShortcut();
+ const bool configureToolbar = aFilter->configureToolbar();
+ const QString icon = aFilter->icon();
+ const KShortcut shortcut( aFilter->shortcut() );
+
+ mApplyOnIn->setChecked( applyOnIn );
+ mApplyOnForAll->setEnabled( applyOnIn );
+ mApplyOnForTraditional->setEnabled( applyOnIn );
+ mApplyOnForChecked->setEnabled( applyOnIn );
+ mApplyOnForAll->setChecked( applyOnForAll );
+ mApplyOnForTraditional->setChecked( applyOnTraditional );
+ mApplyOnForChecked->setChecked( !applyOnForAll && !applyOnTraditional );
+ mAccountList->setEnabled( mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked() );
+ slotUpdateAccountList();
+ mApplyOnOut->setChecked( applyOnOut );
+ mApplyOnCtrlJ->setChecked( applyOnExplicit );
+ mStopProcessingHere->setChecked( stopHere );
+ mConfigureShortcut->setChecked( configureShortcut );
+ mKeyButton->setShortcut( shortcut, false );
+ mConfigureToolbar->setChecked( configureToolbar );
+ mFilterActionIconButton->setIcon( icon );
+ }
+}
+
+void KMFilterDlg::slotReset()
+{
+ mFilter = 0;
+ mPatternEdit->reset();
+
+ if(bPopFilter) {
+ mActionGroup->reset();
+ mGlobalsBox->setEnabled( false );
+ } else {
+ mActionLister->reset();
+ mAdvOptsGroup->setEnabled( false );
+ slotUpdateAccountList();
+ }
+}
+
+void KMFilterDlg::slotUpdateFilter()
+{
+ mPatternEdit->updateSearchPattern();
+ if ( !bPopFilter ) {
+ mActionLister->updateActionList();
+ }
+}
+
+void KMFilterDlg::slotApplicabilityChanged()
+{
+ if ( mFilter ) {
+ mFilter->setApplyOnInbound( mApplyOnIn->isChecked() );
+ mFilter->setApplyOnOutbound( mApplyOnOut->isChecked() );
+ mFilter->setApplyOnExplicit( mApplyOnCtrlJ->isChecked() );
+ if ( mApplyOnForAll->isChecked() )
+ mFilter->setApplicability( KMFilter::All );
+ else if ( mApplyOnForTraditional->isChecked() )
+ mFilter->setApplicability( KMFilter::ButImap );
+ else if ( mApplyOnForChecked->isChecked() )
+ mFilter->setApplicability( KMFilter::Checked );
+
+ mApplyOnForAll->setEnabled( mApplyOnIn->isChecked() );
+ mApplyOnForTraditional->setEnabled( mApplyOnIn->isChecked() );
+ mApplyOnForChecked->setEnabled( mApplyOnIn->isChecked() );
+ mAccountList->setEnabled( mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked() );
+
+ // Advanced tab functionality - Update list of accounts this filter applies to
+ QListViewItemIterator it( mAccountList );
+ while ( it.current() ) {
+ QCheckListItem *item = dynamic_cast<QCheckListItem*>( it.current() );
+ if (item) {
+ int id = item->text( 2 ).toInt();
+ item->setOn( mFilter->applyOnAccount( id ) );
+ }
+ ++it;
+ }
+
+ kdDebug(5006) << "KMFilterDlg: setting filter to be applied at "
+ << ( mFilter->applyOnInbound() ? "incoming " : "" )
+ << ( mFilter->applyOnOutbound() ? "outgoing " : "" )
+ << ( mFilter->applyOnExplicit() ? "explicit CTRL-J" : "" )
+ << endl;
+ }
+}
+
+void KMFilterDlg::slotApplicableAccountsChanged()
+{
+ if ( mFilter && mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked() ) {
+ // Advanced tab functionality - Update list of accounts this filter applies to
+ QListViewItemIterator it( mAccountList );
+ while ( it.current() ) {
+ QCheckListItem *item = dynamic_cast<QCheckListItem*>( it.current() );
+ if (item) {
+ int id = item->text( 2 ).toInt();
+ mFilter->setApplyOnAccount( id, item->isOn() );
+ }
+ ++it;
+ }
+ }
+}
+
+void KMFilterDlg::slotStopProcessingButtonToggled( bool aChecked )
+{
+ if ( mFilter )
+ mFilter->setStopProcessingHere( aChecked );
+}
+
+void KMFilterDlg::slotConfigureShortcutButtonToggled( bool aChecked )
+{
+ if ( mFilter ) {
+ mFilter->setConfigureShortcut( aChecked );
+ mKeyButton->setEnabled( aChecked );
+ mConfigureToolbar->setEnabled( aChecked );
+ mFilterActionIconButton->setEnabled( aChecked );
+ mFilterActionLabel->setEnabled( aChecked );
+ }
+}
+
+void KMFilterDlg::slotCapturedShortcutChanged( const KShortcut& sc )
+{
+ KShortcut mySc(sc);
+ if ( mySc == mKeyButton->shortcut() ) return;
+ // FIXME work around a problem when reseting the shortcut via the shortcut dialog
+ // somehow the returned shortcut does not evaluate to true in KShortcut::isNull(),
+ // so we additionally have to check for an empty string
+ if ( mySc.isNull() || mySc.toString().isEmpty() )
+ mySc.clear();
+ if ( !mySc.isNull() && !( kmkernel->getKMMainWidget()->shortcutIsValid( mySc ) ) ) {
+ QString msg( i18n( "The selected shortcut is already used, "
+ "please select a different one." ) );
+ KMessageBox::sorry( this, msg );
+ } else {
+ mKeyButton->setShortcut( mySc, false );
+ if ( mFilter )
+ mFilter->setShortcut( mKeyButton->shortcut() );
+ }
+}
+
+void KMFilterDlg::slotConfigureToolbarButtonToggled( bool aChecked )
+{
+ if ( mFilter )
+ mFilter->setConfigureToolbar( aChecked );
+}
+
+void KMFilterDlg::slotFilterActionIconChanged( QString icon )
+{
+ if ( mFilter )
+ mFilter->setIcon( icon );
+}
+
+void KMFilterDlg::slotUpdateAccountList()
+{
+ mAccountList->clear();
+ QListViewItem *top = 0;
+ for( KMAccount *a = kmkernel->acctMgr()->first(); a!=0;
+ a = kmkernel->acctMgr()->next() ) {
+ QCheckListItem *listItem =
+ new QCheckListItem( mAccountList, top, a->name(), QCheckListItem::CheckBox );
+ listItem->setText( 1, a->type() );
+ listItem->setText( 2, QString( "%1" ).arg( a->id() ) );
+ if ( mFilter )
+ listItem->setOn( mFilter->applyOnAccount( a->id() ) );
+ top = listItem;
+ }
+
+ QListViewItem *listItem = mAccountList->firstChild();
+ if ( listItem ) {
+ mAccountList->setCurrentItem( listItem );
+ mAccountList->setSelected( listItem, true );
+ }
+}
+
+//=============================================================================
+//
+// class KMFilterListBox (the filter list manipulator)
+//
+//=============================================================================
+
+KMFilterListBox::KMFilterListBox( const QString & title, QWidget *parent, const char* name, bool popFilter )
+ : QGroupBox( 1, Horizontal, title, parent, name ),
+ bPopFilter(popFilter)
+{
+ mFilterList.setAutoDelete( true );
+ mIdxSelItem = -1;
+
+ //----------- the list box
+ mListBox = new QListBox(this);
+ mListBox->setMinimumWidth(150);
+ QWhatsThis::add( mListBox, i18n(_wt_filterlist) );
+
+ //----------- the first row of buttons
+ QHBox *hb = new QHBox(this);
+ hb->setSpacing(4);
+ mBtnTop = new KPushButton( QString::null, hb );
+ mBtnTop->setAutoRepeat( true );
+ mBtnTop->setIconSet( BarIconSet( "top", KIcon::SizeSmall ) );
+ mBtnTop->setMinimumSize( mBtnTop->sizeHint() * 1.2 );
+ mBtnUp = new KPushButton( QString::null, hb );
+ mBtnUp->setAutoRepeat( true );
+ mBtnUp->setIconSet( BarIconSet( "up", KIcon::SizeSmall ) );
+ mBtnUp->setMinimumSize( mBtnUp->sizeHint() * 1.2 );
+ mBtnDown = new KPushButton( QString::null, hb );
+ mBtnDown->setAutoRepeat( true );
+ mBtnDown->setIconSet( BarIconSet( "down", KIcon::SizeSmall ) );
+ mBtnDown->setMinimumSize( mBtnDown->sizeHint() * 1.2 );
+ mBtnBot = new KPushButton( QString::null, hb );
+ mBtnBot->setAutoRepeat( true );
+ mBtnBot->setIconSet( BarIconSet( "bottom", KIcon::SizeSmall ) );
+ mBtnBot->setMinimumSize( mBtnBot->sizeHint() * 1.2 );
+ QToolTip::add( mBtnTop, i18n("Top") );
+ QToolTip::add( mBtnUp, i18n("Up") );
+ QToolTip::add( mBtnDown, i18n("Down") );
+ QToolTip::add( mBtnBot, i18n("Bottom") );
+ QWhatsThis::add( mBtnTop, i18n(_wt_filterlist_top) );
+ QWhatsThis::add( mBtnUp, i18n(_wt_filterlist_up) );
+ QWhatsThis::add( mBtnDown, i18n(_wt_filterlist_down) );
+ QWhatsThis::add( mBtnBot, i18n(_wt_filterlist_bot) );
+
+ //----------- the second row of buttons
+ hb = new QHBox(this);
+ hb->setSpacing(4);
+ mBtnNew = new QPushButton( QString::null, hb );
+ mBtnNew->setPixmap( BarIcon( "filenew", KIcon::SizeSmall ) );
+ mBtnNew->setMinimumSize( mBtnNew->sizeHint() * 1.2 );
+ mBtnCopy = new QPushButton( QString::null, hb );
+ mBtnCopy->setIconSet( BarIconSet( "editcopy", KIcon::SizeSmall ) );
+ mBtnCopy->setMinimumSize( mBtnCopy->sizeHint() * 1.2 );
+ mBtnDelete = new QPushButton( QString::null, hb );
+ mBtnDelete->setIconSet( BarIconSet( "editdelete", KIcon::SizeSmall ) );
+ mBtnDelete->setMinimumSize( mBtnDelete->sizeHint() * 1.2 );
+ mBtnRename = new QPushButton( i18n("Rename..."), hb );
+ QToolTip::add( mBtnNew, i18n("New") );
+ QToolTip::add( mBtnCopy, i18n("Copy") );
+ QToolTip::add( mBtnDelete, i18n("Delete"));
+ QWhatsThis::add( mBtnNew, i18n(_wt_filterlist_new) );
+ QWhatsThis::add( mBtnCopy, i18n(_wt_filterlist_copy) );
+ QWhatsThis::add( mBtnDelete, i18n(_wt_filterlist_delete) );
+ QWhatsThis::add( mBtnRename, i18n(_wt_filterlist_rename) );
+
+
+ //----------- now connect everything
+ connect( mListBox, SIGNAL(highlighted(int)),
+ this, SLOT(slotSelected(int)) );
+ connect( mListBox, SIGNAL( doubleClicked ( QListBoxItem * )),
+ this, SLOT( slotRename()) );
+ connect( mBtnTop, SIGNAL(clicked()),
+ this, SLOT(slotTop()) );
+ connect( mBtnUp, SIGNAL(clicked()),
+ this, SLOT(slotUp()) );
+ connect( mBtnDown, SIGNAL(clicked()),
+ this, SLOT(slotDown()) );
+ connect( mBtnBot, SIGNAL(clicked()),
+ this, SLOT(slotBottom()) );
+ connect( mBtnNew, SIGNAL(clicked()),
+ this, SLOT(slotNew()) );
+ connect( mBtnCopy, SIGNAL(clicked()),
+ this, SLOT(slotCopy()) );
+ connect( mBtnDelete, SIGNAL(clicked()),
+ this, SLOT(slotDelete()) );
+ connect( mBtnRename, SIGNAL(clicked()),
+ this, SLOT(slotRename()) );
+
+ // the dialog should call loadFilterList()
+ // when all signals are connected.
+ enableControls();
+}
+
+
+void KMFilterListBox::createFilter( const QCString & field,
+ const QString & value )
+{
+ KMSearchRule *newRule = KMSearchRule::createInstance( field, KMSearchRule::FuncContains, value );
+
+ KMFilter *newFilter = new KMFilter(0, bPopFilter);
+ newFilter->pattern()->append( newRule );
+ newFilter->pattern()->setName( QString("<%1>:%2").arg( field ).arg( value) );
+
+ KMFilterActionDesc *desc = (*kmkernel->filterActionDict())["transfer"];
+ if ( desc )
+ newFilter->actions()->append( desc->create() );
+
+ insertFilter( newFilter );
+ enableControls();
+}
+
+bool KMFilterListBox::showLaterMsgs()
+{
+ return mShowLater;
+}
+
+void KMFilterListBox::slotUpdateFilterName()
+{
+ KMSearchPattern *p = mFilterList.at(mIdxSelItem)->pattern();
+ if ( !p ) return;
+
+ QString shouldBeName = p->name();
+ QString displayedName = mListBox->text( mIdxSelItem );
+
+ if ( shouldBeName.stripWhiteSpace().isEmpty() ) {
+ mFilterList.at(mIdxSelItem)->setAutoNaming( true );
+ }
+
+ if ( mFilterList.at(mIdxSelItem)->isAutoNaming() ) {
+ // auto-naming of patterns
+ if ( p->first() && !p->first()->field().stripWhiteSpace().isEmpty() )
+ shouldBeName = QString( "<%1>: %2" ).arg( p->first()->field() ).arg( p->first()->contents() );
+ else
+ shouldBeName = "<" + i18n("unnamed") + ">";
+ p->setName( shouldBeName );
+ }
+
+ if ( displayedName == shouldBeName ) return;
+
+ mListBox->blockSignals( true );
+ mListBox->changeItem( shouldBeName, mIdxSelItem );
+ mListBox->blockSignals( false );
+}
+
+void KMFilterListBox::slotShowLaterToggled(bool aOn)
+{
+ mShowLater = aOn;
+}
+
+void KMFilterListBox::slotApplyFilterChanges()
+{
+ if ( mIdxSelItem >= 0 ) {
+ emit applyWidgets();
+ slotSelected( mListBox->currentItem() );
+ }
+
+ // by now all edit widgets should have written back
+ // their widget's data into our filter list.
+
+ KMFilterMgr *fm;
+ if (bPopFilter)
+ fm = kmkernel->popFilterMgr();
+ else
+ fm = kmkernel->filterMgr();
+
+ QValueList<KMFilter*> newFilters = filtersForSaving();
+
+ if (bPopFilter)
+ fm->setShowLaterMsgs(mShowLater);
+
+ fm->setFilters( newFilters );
+ if (fm->atLeastOneOnlineImapFolderTarget()) {
+ QString str = i18n("At least one filter targets a folder on an online "
+ "IMAP account. Such filters will only be applied "
+ "when manually filtering and when filtering "
+ "incoming online IMAP mail.");
+ KMessageBox::information( this, str, QString::null,
+ "filterDlgOnlineImapCheck" );
+ }
+}
+
+QValueList<KMFilter*> KMFilterListBox::filtersForSaving() const
+{
+ const_cast<KMFilterListBox*>( this )->applyWidgets(); // signals aren't const
+ QValueList<KMFilter*> filters;
+ QStringList emptyFilters;
+ QPtrListIterator<KMFilter> it( mFilterList );
+ for ( it.toFirst() ; it.current() ; ++it ) {
+ KMFilter *f = new KMFilter( **it ); // deep copy
+ f->purify();
+ if ( !f->isEmpty() )
+ // the filter is valid:
+ filters.append( f );
+ else {
+ // the filter is invalid:
+ emptyFilters << f->name();
+ delete f;
+ }
+ }
+
+ // report on invalid filters:
+ if ( !emptyFilters.empty() ) {
+ QString msg = i18n("The following filters have not been saved because they "
+ "were invalid (e.g. containing no actions or no search "
+ "rules).");
+ KMessageBox::informationList( 0, msg, emptyFilters, QString::null,
+ "ShowInvalidFilterWarning" );
+ }
+ return filters;
+}
+
+void KMFilterListBox::slotSelected( int aIdx )
+{
+ mIdxSelItem = aIdx;
+ // QPtrList::at(i) will return 0 if i is out of range.
+ KMFilter *f = mFilterList.at(aIdx);
+ if ( f )
+ emit filterSelected( f );
+ else
+ emit resetWidgets();
+ enableControls();
+}
+
+void KMFilterListBox::slotNew()
+{
+ // just insert a new filter.
+ insertFilter( new KMFilter(0, bPopFilter) );
+ enableControls();
+}
+
+void KMFilterListBox::slotCopy()
+{
+ if ( mIdxSelItem < 0 ) {
+ kdDebug(5006) << "KMFilterListBox::slotCopy called while no filter is selected, ignoring." << endl;
+ return;
+ }
+
+ // make sure that all changes are written to the filter before we copy it
+ emit applyWidgets();
+
+ KMFilter *filter = mFilterList.at( mIdxSelItem );
+
+ // enableControls should make sure this method is
+ // never called when no filter is selected.
+ assert( filter );
+
+ // inserts a copy of the current filter.
+ insertFilter( new KMFilter( *filter ) );
+ enableControls();
+}
+
+void KMFilterListBox::slotDelete()
+{
+ if ( mIdxSelItem < 0 ) {
+ kdDebug(5006) << "KMFilterListBox::slotDelete called while no filter is selected, ignoring." << endl;
+ return;
+ }
+
+ int oIdxSelItem = mIdxSelItem;
+ mIdxSelItem = -1;
+ // unselect all
+ mListBox->selectAll( false );
+ // broadcast that all widgets let go
+ // of the filter
+ emit resetWidgets();
+
+ // remove the filter from both the filter list...
+ mFilterList.remove( oIdxSelItem );
+ // and the listbox
+ mListBox->removeItem( oIdxSelItem );
+
+ int count = (int)mListBox->count();
+ // and set the new current item.
+ if ( count > oIdxSelItem )
+ // oIdxItem is still a valid index
+ mListBox->setSelected( oIdxSelItem, true );
+ else if ( count )
+ // oIdxSelIdx is no longer valid, but the
+ // list box isn't empty
+ mListBox->setSelected( count - 1, true );
+ // the list is empty - keep index -1
+
+ enableControls();
+}
+
+void KMFilterListBox::slotTop()
+{
+ if ( mIdxSelItem < 0 ) {
+ kdDebug(5006) << "KMFilterListBox::slotTop called while no filter is selected, ignoring." << endl;
+ return;
+ }
+ if ( mIdxSelItem == 0 ) {
+ kdDebug(5006) << "KMFilterListBox::slotTop called while the _topmost_ filter is selected, ignoring." << endl;
+ return;
+ }
+
+ swapFilters( mIdxSelItem, 0 );
+ enableControls();
+}
+
+void KMFilterListBox::slotUp()
+{
+ if ( mIdxSelItem < 0 ) {
+ kdDebug(5006) << "KMFilterListBox::slotUp called while no filter is selected, ignoring." << endl;
+ return;
+ }
+ if ( mIdxSelItem == 0 ) {
+ kdDebug(5006) << "KMFilterListBox::slotUp called while the _topmost_ filter is selected, ignoring." << endl;
+ return;
+ }
+
+ swapNeighbouringFilters( mIdxSelItem, mIdxSelItem - 1 );
+ enableControls();
+}
+
+void KMFilterListBox::slotDown()
+{
+ if ( mIdxSelItem < 0 ) {
+ kdDebug(5006) << "KMFilterListBox::slotDown called while no filter is selected, ignoring." << endl;
+ return;
+ }
+ if ( mIdxSelItem == (int)mListBox->count() - 1 ) {
+ kdDebug(5006) << "KMFilterListBox::slotDown called while the _last_ filter is selected, ignoring." << endl;
+ return;
+ }
+
+ swapNeighbouringFilters( mIdxSelItem, mIdxSelItem + 1);
+ enableControls();
+}
+
+void KMFilterListBox::slotBottom()
+{
+ if ( mIdxSelItem < 0 ) {
+ kdDebug(5006) << "KMFilterListBox::slotBottom called while no filter is selected, ignoring." << endl;
+ return;
+ }
+ if ( mIdxSelItem == (int)mListBox->count() - 1 ) {
+ kdDebug(5006) << "KMFilterListBox::slotBottom called while the _last_ filter is selected, ignoring." << endl;
+ return;
+ }
+
+ swapFilters( mIdxSelItem, mListBox->count()-1 );
+ enableControls();
+}
+
+void KMFilterListBox::slotRename()
+{
+ if ( mIdxSelItem < 0 ) {
+ kdDebug(5006) << "KMFilterListBox::slotRename called while no filter is selected, ignoring." << endl;
+ return;
+ }
+
+ bool okPressed = false ;
+ KMFilter *filter = mFilterList.at( mIdxSelItem );
+
+ // enableControls should make sure this method is
+ // never called when no filter is selected.
+ assert( filter );
+
+ // allow empty names - those will turn auto-naming on again
+ QValidator *validator = new QRegExpValidator( QRegExp( ".*" ), 0 );
+ QString newName = KInputDialog::getText
+ (
+ i18n("Rename Filter"),
+ i18n("Rename filter \"%1\" to:\n(leave the field empty for automatic naming)")
+ .arg( filter->pattern()->name() ) /*label*/,
+ filter->pattern()->name() /* initial value */,
+ &okPressed, topLevelWidget(), 0, validator
+ );
+ delete validator;
+
+ if ( !okPressed ) return;
+
+ if ( newName.isEmpty() ) {
+ // bait for slotUpdateFilterName to
+ // use automatic naming again.
+ filter->pattern()->setName( "<>" );
+ filter->setAutoNaming( true );
+ } else {
+ filter->pattern()->setName( newName );
+ filter->setAutoNaming( false );
+ }
+
+ slotUpdateFilterName();
+}
+
+void KMFilterListBox::enableControls()
+{
+ bool theFirst = ( mIdxSelItem == 0 );
+ bool theLast = ( mIdxSelItem >= (int)mFilterList.count() - 1 );
+ bool aFilterIsSelected = ( mIdxSelItem >= 0 );
+
+ mBtnTop->setEnabled( aFilterIsSelected && !theFirst );
+ mBtnUp->setEnabled( aFilterIsSelected && !theFirst );
+ mBtnDown->setEnabled( aFilterIsSelected && !theLast );
+ mBtnBot->setEnabled( aFilterIsSelected && !theLast );
+ mBtnCopy->setEnabled( aFilterIsSelected );
+ mBtnDelete->setEnabled( aFilterIsSelected );
+ mBtnRename->setEnabled( aFilterIsSelected );
+
+ if ( aFilterIsSelected )
+ mListBox->ensureCurrentVisible();
+}
+
+void KMFilterListBox::loadFilterList( bool createDummyFilter )
+{
+ assert(mListBox);
+ setEnabled( false );
+ emit resetWidgets();
+ // we don't want the insertion to
+ // cause flicker in the edit widgets.
+ blockSignals( true );
+
+ // clear both lists
+ mFilterList.clear();
+ mListBox->clear();
+
+ const KMFilterMgr *manager = 0;
+ if(bPopFilter)
+ {
+ mShowLater = kmkernel->popFilterMgr()->showLaterMsgs();
+ manager = kmkernel->popFilterMgr();
+ }
+ else
+ {
+ manager = kmkernel->filterMgr();
+ }
+ Q_ASSERT( manager );
+
+ QValueListConstIterator<KMFilter*> it;
+ for ( it = manager->filters().constBegin() ; it != manager->filters().constEnd() ; ++it ) {
+ mFilterList.append( new KMFilter( **it ) ); // deep copy
+ mListBox->insertItem( (*it)->pattern()->name() );
+ }
+
+ blockSignals( false );
+ setEnabled( true );
+
+ // create an empty filter when there's none, to avoid a completely
+ // disabled dialog (usability tests indicated that the new-filter
+ // button is too hard to find that way):
+ if ( !mListBox->count() && createDummyFilter )
+ slotNew();
+
+ if ( mListBox->count() > 0 )
+ mListBox->setSelected( 0, true );
+
+ enableControls();
+}
+
+void KMFilterListBox::insertFilter( KMFilter* aFilter )
+{
+ // must be really a filter...
+ assert( aFilter );
+
+ // if mIdxSelItem < 0, QListBox::insertItem will append.
+ mListBox->insertItem( aFilter->pattern()->name(), mIdxSelItem );
+ if ( mIdxSelItem < 0 ) {
+ // none selected -> append
+ mFilterList.append( aFilter );
+ mListBox->setSelected( mListBox->count() - 1, true );
+ // slotSelected( mListBox->count() - 1 );
+ } else {
+ // insert just before selected
+ mFilterList.insert( mIdxSelItem, aFilter );
+ mListBox->setSelected( mIdxSelItem, true );
+ // slotSelected( mIdxSelItem );
+ }
+
+}
+
+void KMFilterListBox::appendFilter( KMFilter* aFilter )
+{
+ mFilterList.append( aFilter );
+ mListBox->insertItem( aFilter->pattern()->name(), -1 );
+}
+
+void KMFilterListBox::swapNeighbouringFilters( int untouchedOne, int movedOne )
+{
+ // must be neighbours...
+ assert( untouchedOne - movedOne == 1 || movedOne - untouchedOne == 1 );
+
+ // untouchedOne is at idx. to move it down(up),
+ // remove item at idx+(-)1 w/o deleting it.
+ QListBoxItem *item = mListBox->item( movedOne );
+ mListBox->takeItem( item );
+ // now selected item is at idx(idx-1), so
+ // insert the other item at idx, ie. above(below).
+ mListBox->insertItem( item, untouchedOne );
+
+ KMFilter* filter = mFilterList.take( movedOne );
+ mFilterList.insert( untouchedOne, filter );
+
+ mIdxSelItem += movedOne - untouchedOne;
+}
+
+void KMFilterListBox::swapFilters( int from, int to )
+{
+ QListBoxItem *item = mListBox->item( from );
+ mListBox->takeItem( item );
+ mListBox->insertItem( item, to );
+
+ KMFilter* filter = mFilterList.take( from );
+ mFilterList.insert( to, filter );
+
+ mIdxSelItem = to;
+ mListBox->setCurrentItem( mIdxSelItem );
+ mListBox->setSelected( mIdxSelItem, true );
+}
+
+//=============================================================================
+//
+// class KMFilterActionWidget
+//
+//=============================================================================
+
+KMFilterActionWidget::KMFilterActionWidget( QWidget *parent, const char* name )
+ : QHBox( parent, name )
+{
+ int i;
+ mActionList.setAutoDelete( true );
+
+ mComboBox = new QComboBox( false , this );
+ assert( mComboBox );
+ mWidgetStack = new QWidgetStack(this);
+ assert( mWidgetStack );
+
+ setSpacing( 4 );
+
+ QPtrListIterator<KMFilterActionDesc> it ( kmkernel->filterActionDict()->list() );
+ for ( i=0, it.toFirst() ; it.current() ; ++it, ++i ) {
+ //create an instance:
+ KMFilterAction *a = (*it)->create();
+ // append to the list of actions:
+ mActionList.append( a );
+ // add parameter widget to widget stack:
+ mWidgetStack->addWidget( a->createParamWidget( mWidgetStack ), i );
+ // add (i18n-ized) name to combo box
+ mComboBox->insertItem( (*it)->label );
+ }
+ // widget for the case where no action is selected.
+ mWidgetStack->addWidget( new QLabel( i18n("Please select an action."), mWidgetStack ), i );
+ mWidgetStack->raiseWidget(i);
+ mComboBox->insertItem( " " );
+ mComboBox->setCurrentItem(i);
+
+ // don't show scroll bars.
+ mComboBox->setSizeLimit( mComboBox->count() );
+ // layout management:
+ // o the combo box is not to be made larger than it's sizeHint(),
+ // the parameter widget should grow instead.
+ // o the whole widget takes all space horizontally, but is fixed vertically.
+ mComboBox->adjustSize();
+ mComboBox->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+ setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
+ updateGeometry();
+
+ // redirect focus to the filter action combo box
+ setFocusProxy( mComboBox );
+
+ // now connect the combo box and the widget stack
+ connect( mComboBox, SIGNAL(activated(int)),
+ mWidgetStack, SLOT(raiseWidget(int)) );
+}
+
+void KMFilterActionWidget::setAction( const KMFilterAction* aAction )
+{
+ int i=0;
+ bool found = false ;
+ int count = mComboBox->count() - 1 ; // last entry is the empty one
+ QString label = ( aAction ) ? aAction->label() : QString::null ;
+
+ // find the index of typeOf(aAction) in mComboBox
+ // and clear the other widgets on the way.
+ for ( ; i < count ; i++ )
+ if ( aAction && mComboBox->text(i) == label ) {
+ //...set the parameter widget to the settings
+ // of aAction...
+ aAction->setParamWidgetValue( mWidgetStack->widget(i) );
+ //...and show the correct entry of
+ // the combo box
+ mComboBox->setCurrentItem(i); // (mm) also raise the widget, but doesn't
+ mWidgetStack->raiseWidget(i);
+ found = true;
+ } else // clear the parameter widget
+ mActionList.at(i)->clearParamWidget( mWidgetStack->widget(i) );
+ if ( found ) return;
+
+ // not found, so set the empty widget
+ mComboBox->setCurrentItem( count ); // last item
+ mWidgetStack->raiseWidget( count) ;
+}
+
+KMFilterAction * KMFilterActionWidget::action()
+{
+ // look up the action description via the label
+ // returned by QComboBox::currentText()...
+ KMFilterActionDesc *desc = (*kmkernel->filterActionDict())[ mComboBox->currentText() ];
+ if ( desc ) {
+ // ...create an instance...
+ KMFilterAction *fa = desc->create();
+ if ( fa ) {
+ // ...and apply the setting of the parameter widget.
+ fa->applyParamWidgetValue( mWidgetStack->visibleWidget() );
+ return fa;
+ }
+ }
+
+ return 0;
+}
+
+//=============================================================================
+//
+// class KMFilterActionWidgetLister (the filter action editor)
+//
+//=============================================================================
+
+KMFilterActionWidgetLister::KMFilterActionWidgetLister( QWidget *parent, const char* name )
+ : KWidgetLister( 1, FILTER_MAX_ACTIONS, parent, name )
+{
+ mActionList = 0;
+}
+
+KMFilterActionWidgetLister::~KMFilterActionWidgetLister()
+{
+}
+
+void KMFilterActionWidgetLister::setActionList( QPtrList<KMFilterAction> *aList )
+{
+ assert ( aList );
+
+ if ( mActionList )
+ regenerateActionListFromWidgets();
+
+ mActionList = aList;
+
+ ((QWidget*)parent())->setEnabled( true );
+
+ if ( aList->count() == 0 ) {
+ slotClear();
+ return;
+ }
+
+ int superfluousItems = (int)mActionList->count() - mMaxWidgets ;
+ if ( superfluousItems > 0 ) {
+ kdDebug(5006) << "KMFilterActionWidgetLister: Clipping action list to "
+ << mMaxWidgets << " items!" << endl;
+
+ for ( ; superfluousItems ; superfluousItems-- )
+ mActionList->removeLast();
+ }
+
+ // set the right number of widgets
+ setNumberOfShownWidgetsTo( mActionList->count() );
+
+ // load the actions into the widgets
+ QPtrListIterator<KMFilterAction> aIt( *mActionList );
+ QPtrListIterator<QWidget> wIt( mWidgetList );
+ for ( aIt.toFirst(), wIt.toFirst() ;
+ aIt.current() && wIt.current() ; ++aIt, ++wIt )
+ ((KMFilterActionWidget*)(*wIt))->setAction( (*aIt) );
+}
+
+void KMFilterActionWidgetLister::reset()
+{
+ if ( mActionList )
+ regenerateActionListFromWidgets();
+
+ mActionList = 0;
+ slotClear();
+ ((QWidget*)parent())->setEnabled( false );
+}
+
+QWidget* KMFilterActionWidgetLister::createWidget( QWidget *parent )
+{
+ return new KMFilterActionWidget(parent);
+}
+
+void KMFilterActionWidgetLister::clearWidget( QWidget *aWidget )
+{
+ if ( aWidget )
+ ((KMFilterActionWidget*)aWidget)->setAction(0);
+}
+
+void KMFilterActionWidgetLister::regenerateActionListFromWidgets()
+{
+ if ( !mActionList ) return;
+
+ mActionList->clear();
+
+ QPtrListIterator<QWidget> it( mWidgetList );
+ for ( it.toFirst() ; it.current() ; ++it ) {
+ KMFilterAction *a = ((KMFilterActionWidget*)(*it))->action();
+ if ( a )
+ mActionList->append( a );
+ }
+
+}
+
+//=============================================================================
+//
+// class KMPopFilterActionWidget
+//
+//=============================================================================
+
+KMPopFilterActionWidget::KMPopFilterActionWidget( const QString& title, QWidget *parent, const char* name )
+ : QVButtonGroup( title, parent, name )
+{
+ mActionMap[Down] = new QRadioButton( i18n("&Download mail"), this );
+ mActionMap[Later] = new QRadioButton( i18n("Download mail la&ter"), this );
+ mActionMap[Delete] = new QRadioButton( i18n("D&elete mail from server"), this );
+ mIdMap[id(mActionMap[Later])] = Later;
+ mIdMap[id(mActionMap[Down])] = Down;
+ mIdMap[id(mActionMap[Delete])] = Delete;
+
+ connect( this, SIGNAL(clicked(int)),
+ this, SLOT( slotActionClicked(int)) );
+}
+
+void KMPopFilterActionWidget::setAction( KMPopFilterAction aAction )
+{
+ if( aAction == NoAction)
+ {
+ aAction = Later;
+ }
+
+ mAction = aAction;
+
+ blockSignals( true );
+ if(!mActionMap[aAction]->isChecked())
+ {
+ mActionMap[aAction]->setChecked( true );
+ }
+ blockSignals( false );
+
+ setEnabled( true );
+}
+
+KMPopFilterAction KMPopFilterActionWidget::action()
+{
+ return mAction;
+}
+
+void KMPopFilterActionWidget::slotActionClicked(int aId)
+{
+ emit actionChanged(mIdMap[aId]);
+ setAction(mIdMap[aId]);
+}
+
+void KMPopFilterActionWidget::reset()
+{
+ blockSignals( true );
+ mActionMap[Down]->setChecked( true );
+ blockSignals( false );
+
+ setEnabled( false );
+}
+
+void KMFilterDlg::slotImportFilters()
+{
+ FilterImporterExporter importer( this, bPopFilter );
+ QValueList<KMFilter*> filters = importer.importFilters();
+ // FIXME message box how many were imported?
+ if (filters.isEmpty()) return;
+
+ QValueListConstIterator<KMFilter*> it;
+
+ for ( it = filters.constBegin() ; it != filters.constEnd() ; ++it ) {
+ mFilterList->appendFilter( *it ); // no need to deep copy, ownership passes to the list
+ }
+}
+
+void KMFilterDlg::slotExportFilters()
+{
+ FilterImporterExporter exporter( this, bPopFilter );
+ QValueList<KMFilter*> filters = mFilterList->filtersForSaving();
+ exporter.exportFilters( filters );
+ QValueList<KMFilter*>::iterator it;
+ for ( it = filters.begin(); it != filters.end(); ++it )
+ delete *it;
+}
+
+#include "kmfilterdlg.moc"