kmail

kmfilterdlg.cpp

Go to the documentation of this file.
00001 // -*- mode: C++; c-file-style: "gnu" -*-
00002 // kmfilterdlg.cpp
00003 // Author: Marc Mutz <Marc@Mutz.com>
00004 // based on work by Stefan Taferner <taferner@kde.org>
00005 // This code is under the GPL
00006 
00007 #include <config.h>
00008 #include "kmfilterdlg.h"
00009 
00010 // other KMail headers:
00011 #include "kmsearchpatternedit.h"
00012 #include "kmfiltermgr.h"
00013 #include "kmmainwidget.h"
00014 #include "accountmanager.h"
00015 using KMail::AccountManager;
00016 #include "filterimporterexporter.h"
00017 using KMail::FilterImporterExporter;
00018 
00019 // other KDE headers:
00020 #include <kmessagebox.h>
00021 #include <kdebug.h>
00022 #include <klocale.h>
00023 #include <kinputdialog.h>
00024 #include <kiconloader.h>
00025 #include <kapplication.h>
00026 #include <kwin.h>
00027 #include <kconfig.h>
00028 #include <kicondialog.h>
00029 #include <kkeybutton.h>
00030 #include <klistview.h>
00031 #include <kpushbutton.h>
00032 
00033 // other Qt headers:
00034 #include <qlayout.h>
00035 #include <qlabel.h>
00036 #include <qcombobox.h>
00037 #include <qwidgetstack.h>
00038 #include <qtooltip.h>
00039 #include <qwhatsthis.h>
00040 #include <qcheckbox.h>
00041 #include <qhbox.h>
00042 #include <qvalidator.h>
00043 #include <qtabwidget.h>
00044 
00045 // other headers:
00046 #include <assert.h>
00047 
00048 
00049 // What's this help texts
00050 const char * _wt_filterlist =
00051 I18N_NOOP( "<qt><p>This is the list of defined filters. "
00052        "They are processed top-to-bottom.</p>"
00053        "<p>Click on any filter to edit it "
00054        "using the controls in the right-hand half "
00055        "of the dialog.</p></qt>" );
00056 const char * _wt_filterlist_new =
00057 I18N_NOOP( "<qt><p>Click this button to create a new filter.</p>"
00058        "<p>The filter will be inserted just before the currently-"
00059        "selected one, but you can always change that "
00060        "later on.</p>"
00061        "<p>If you have clicked this button accidentally, you can undo this "
00062        "by clicking on the <em>Delete</em> button.</p></qt>" );
00063 const char * _wt_filterlist_copy =
00064 I18N_NOOP( "<qt><p>Click this button to copy a filter.</p>"
00065        "<p>If you have clicked this button accidentally, you can undo this "
00066        "by clicking on the <em>Delete</em> button.</p></qt>" );
00067 const char * _wt_filterlist_delete =
00068 I18N_NOOP( "<qt><p>Click this button to <em>delete</em> the currently-"
00069        "selected filter from the list above.</p>"
00070        "<p>There is no way to get the filter back once "
00071        "it is deleted, but you can always leave the "
00072        "dialog by clicking <em>Cancel</em> to discard the "
00073        "changes made.</p></qt>" );
00074 const char * _wt_filterlist_top =
00075 I18N_NOOP( "<qt><p>Click this button to move the currently-"
00076        "selected filter to the <em>top</em> of the list above.</p>"
00077        "<p>This is useful since the order of the filters in the list "
00078        "determines the order in which they are tried on messages: "
00079        "The topmost filter gets tried first.</p></qt>" );
00080 const char * _wt_filterlist_up =
00081 I18N_NOOP( "<qt><p>Click this button to move the currently-"
00082        "selected filter <em>up</em> one in the list above.</p>"
00083        "<p>This is useful since the order of the filters in the list "
00084        "determines the order in which they are tried on messages: "
00085        "The topmost filter gets tried first.</p>"
00086        "<p>If you have clicked this button accidentally, you can undo this "
00087        "by clicking on the <em>Down</em> button.</p></qt>" );
00088 const char * _wt_filterlist_down =
00089 I18N_NOOP( "<qt><p>Click this button to move the currently-"
00090        "selected filter <em>down</em> one in the list above.</p>"
00091        "<p>This is useful since the order of the filters in the list "
00092        "determines the order in which they are tried on messages: "
00093        "The topmost filter gets tried first.</p>"
00094        "<p>If you have clicked this button accidentally, you can undo this "
00095        "by clicking on the <em>Up</em> button.</p></qt>" );
00096 const char * _wt_filterlist_bot =
00097 I18N_NOOP( "<qt><p>Click this button to move the currently-"
00098        "selected filter to the <em>bottom</em> of the list above.</p>"
00099        "<p>This is useful since the order of the filters in the list "
00100        "determines the order in which they are tried on messages: "
00101        "The topmost filter gets tried first.</p></qt>" );
00102 const char * _wt_filterlist_rename =
00103 I18N_NOOP( "<qt><p>Click this button to rename the currently-selected filter.</p>"
00104        "<p>Filters are named automatically, as long as they start with "
00105        "\"&lt;\".</p>"
00106        "<p>If you have renamed a filter accidentally and want automatic "
00107        "naming back, click this button and select <em>Clear</em> followed "
00108        "by <em>OK</em> in the appearing dialog.</p></qt>" );
00109 const char * _wt_filterdlg_showLater =
00110 I18N_NOOP( "<qt><p>Check this button to force the confirmation dialog to be "
00111        "displayed.</p><p>This is useful if you have defined a ruleset that tags "
00112            "messages to be downloaded later. Without the possibility to force "
00113            "the dialog popup, these messages could never be downloaded if no "
00114            "other large messages were waiting on the server, or if you wanted to "
00115            "change the ruleset to tag the messages differently.</p></qt>" );
00116 
00117 // The anchor of the filter dialog's help.
00118 const char * KMFilterDlgHelpAnchor =  "filters-id" ;
00119 const char * KMPopFilterDlgHelpAnchor =  "popfilters-id" ;
00120 
00121 //=============================================================================
00122 //
00123 // class KMFilterDlg (the filter dialog)
00124 //
00125 //=============================================================================
00126 
00127 KMFilterDlg::KMFilterDlg(QWidget* parent, const char* name, bool popFilter, bool createDummyFilter )
00128   : KDialogBase( parent, name,  false  /* modality */,
00129          (popFilter)? i18n("POP3 Filter Rules"): i18n("Filter Rules") /* caption*/,
00130          Help|Ok|Apply|Cancel|User1|User2 /* button mask */,
00131          Ok /* default btn */,  false  /* separator */),
00132   bPopFilter(popFilter)
00133 {
00134   KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() );
00135   setHelp( (bPopFilter)? KMPopFilterDlgHelpAnchor: KMFilterDlgHelpAnchor );
00136   setButtonText( User1, i18n("Import") );
00137   setButtonText( User2, i18n("Export") );
00138   connect( this, SIGNAL(user1Clicked()),
00139            this, SLOT( slotImportFilters()) );
00140   connect( this, SIGNAL(user2Clicked()),
00141            this, SLOT( slotExportFilters()) );
00142 
00143   QWidget *w = new QWidget( this );
00144   setMainWidget( w );
00145   QHBoxLayout *topLayout = new QHBoxLayout( w, 0, spacingHint(), "topLayout" );
00146   QHBoxLayout *hbl = topLayout;
00147   QVBoxLayout *vbl2 = 0;
00148   QWidget *page1 = 0;
00149   QWidget *page2 = 0;
00150 
00151   mFilterList = new KMFilterListBox( i18n("Available Filters"), w, 0, bPopFilter);
00152   topLayout->addWidget( mFilterList, 1 /*stretch*/ );
00153 
00154   if(!bPopFilter) {
00155     QTabWidget *tabWidget = new QTabWidget( w, "kmfd_tab" );
00156     tabWidget->setMargin( KDialog::marginHint() );
00157     topLayout->addWidget( tabWidget );
00158 
00159     page1 = new QWidget( tabWidget );
00160     tabWidget->addTab( page1, i18n("&General") );
00161     hbl = new QHBoxLayout( page1, 0, spacingHint(), "kmfd_hbl" );
00162 
00163     page2 = new QWidget( tabWidget );
00164     tabWidget->addTab( page2, i18n("A&dvanced") );
00165     vbl2 = new QVBoxLayout( page2, 0, spacingHint(), "kmfd_vbl2" );
00166   }
00167 
00168   QVBoxLayout *vbl = new QVBoxLayout( hbl, spacingHint(), "kmfd_vbl" );
00169   hbl->setStretchFactor( vbl, 2 );
00170 
00171   mPatternEdit = new KMSearchPatternEdit( i18n("Filter Criteria"), bPopFilter ? w : page1 , "spe", bPopFilter);
00172   vbl->addWidget( mPatternEdit, 0, Qt::AlignTop );
00173 
00174   if(bPopFilter){
00175     mActionGroup = new KMPopFilterActionWidget( i18n("Filter Action"), w );
00176     vbl->addWidget( mActionGroup, 0, Qt::AlignTop );
00177 
00178     mGlobalsBox = new QVGroupBox(i18n("Global Options"), w);
00179     mShowLaterBtn = new QCheckBox(i18n("Always &show matched 'Download Later' messages in confirmation dialog"), mGlobalsBox);
00180     QWhatsThis::add( mShowLaterBtn, i18n(_wt_filterdlg_showLater) );
00181     vbl->addWidget( mGlobalsBox, 0, Qt::AlignTop );
00182   }
00183   else {
00184     QGroupBox *agb = new QGroupBox( 1 /*column*/, Vertical, i18n("Filter Actions"), page1 );
00185     mActionLister = new KMFilterActionWidgetLister( agb );
00186     vbl->addWidget( agb, 0, Qt::AlignTop );
00187 
00188     mAdvOptsGroup = new QGroupBox ( 1 /*columns*/, Vertical,
00189                     i18n("Advanced Options"), page2);
00190     {
00191       QWidget *adv_w = new QWidget( mAdvOptsGroup );
00192       QGridLayout *gl = new QGridLayout( adv_w, 8 /*rows*/, 3 /*cols*/,
00193                              0 /*border*/, spacingHint() );
00194 
00195       QVBoxLayout *vbl3 = new QVBoxLayout( gl, spacingHint(), "vbl3" );
00196       vbl3->addStretch( 1 );
00197       mApplyOnIn = new QCheckBox( i18n("Apply this filter to incoming messages:"), adv_w );
00198       vbl3->addWidget( mApplyOnIn );
00199       QButtonGroup *bg = new QButtonGroup( 0, "bg" );
00200       bg->setExclusive( true );
00201       mApplyOnForAll = new QRadioButton( i18n("from all accounts"), adv_w );
00202       bg->insert( mApplyOnForAll );
00203       vbl3->addWidget( mApplyOnForAll );
00204       mApplyOnForTraditional = new QRadioButton( i18n("from all but online IMAP accounts"), adv_w );
00205       bg->insert( mApplyOnForTraditional );
00206       vbl3->addWidget( mApplyOnForTraditional );
00207       mApplyOnForChecked = new QRadioButton( i18n("from checked accounts only"), adv_w );
00208       bg->insert( mApplyOnForChecked );
00209       vbl3->addWidget( mApplyOnForChecked );
00210       vbl3->addStretch( 2 );
00211 
00212       mAccountList = new KListView( adv_w, "accountList" );
00213       mAccountList->addColumn( i18n("Account Name") );
00214       mAccountList->addColumn( i18n("Type") );
00215       mAccountList->setAllColumnsShowFocus( true );
00216       mAccountList->setFrameStyle( QFrame::WinPanel + QFrame::Sunken );
00217       mAccountList->setSorting( -1 );
00218       gl->addMultiCellWidget( mAccountList, 0, 3, 1, 3 );
00219 
00220       mApplyOnOut = new QCheckBox( i18n("Apply this filter to &sent messages"), adv_w );
00221       gl->addMultiCellWidget( mApplyOnOut, 4, 4, 0, 3 );
00222 
00223       mApplyOnCtrlJ = new QCheckBox( i18n("Apply this filter on manual &filtering"), adv_w );
00224       gl->addMultiCellWidget( mApplyOnCtrlJ, 5, 5, 0, 3 );
00225 
00226       mStopProcessingHere = new QCheckBox( i18n("If this filter &matches, stop processing here"), adv_w );
00227       gl->addMultiCellWidget( mStopProcessingHere,
00228                   6, 6, /*from to row*/
00229                   0, 3 /*from to col*/ );
00230       mConfigureShortcut = new QCheckBox( i18n("Add this filter to the Apply Filter menu"), adv_w );
00231       gl->addMultiCellWidget( mConfigureShortcut, 7, 7, 0, 1 );
00232       QLabel *keyButtonLabel = new QLabel( i18n( "Shortcut:" ), adv_w );
00233       keyButtonLabel->setAlignment( AlignVCenter | AlignRight );
00234       gl->addMultiCellWidget( keyButtonLabel, 7, 7, 2, 2 );
00235       mKeyButton = new KKeyButton( adv_w, "FilterShortcutSelector" );
00236       gl->addMultiCellWidget( mKeyButton, 7, 7, 3, 3 );
00237       mKeyButton->setEnabled( false );
00238       mConfigureToolbar = new QCheckBox( i18n("Additionally add this filter to the toolbar"), adv_w );
00239       gl->addMultiCellWidget( mConfigureToolbar, 8, 8, 0, 3 );
00240       mConfigureToolbar->setEnabled( false );
00241 
00242       QHBox *hbox = new QHBox( adv_w );
00243       mFilterActionLabel = new QLabel( i18n( "Icon for this filter:" ),
00244                                        hbox );
00245       mFilterActionLabel->setEnabled( false );
00246 
00247       mFilterActionIconButton = new KIconButton( hbox );
00248       mFilterActionLabel->setBuddy( mFilterActionIconButton );
00249       mFilterActionIconButton->setIconType( KIcon::NoGroup, KIcon::Any, true );
00250       mFilterActionIconButton->setIconSize( 16 );
00251       mFilterActionIconButton->setIcon( "gear" );
00252       mFilterActionIconButton->setEnabled( false );
00253 
00254       gl->addMultiCellWidget( hbox, 9, 9, 0, 3 );
00255     }
00256     vbl2->addWidget( mAdvOptsGroup, 0, Qt::AlignTop );
00257   }
00258   // spacer:
00259   vbl->addStretch( 1 );
00260 
00261   // load the filter parts into the edit widgets
00262   connect( mFilterList, SIGNAL(filterSelected(KMFilter*)),
00263        this, SLOT(slotFilterSelected(KMFilter*)) );
00264 
00265   if (bPopFilter){
00266     // set the state of the global setting 'show later msgs'
00267     connect( mShowLaterBtn, SIGNAL(toggled(bool)),
00268              mFilterList, SLOT(slotShowLaterToggled(bool)));
00269 
00270     // set the action in the filter when changed
00271     connect( mActionGroup, SIGNAL(actionChanged(const KMPopFilterAction)),
00272          this, SLOT(slotActionChanged(const KMPopFilterAction)) );
00273   } else {
00274     // transfer changes from the 'Apply this filter on...'
00275     // combo box to the filter
00276     connect( mApplyOnIn, SIGNAL(clicked()),
00277          this, SLOT(slotApplicabilityChanged()) );
00278     connect( mApplyOnForAll, SIGNAL(clicked()),
00279          this, SLOT(slotApplicabilityChanged()) );
00280     connect( mApplyOnForTraditional, SIGNAL(clicked()),
00281          this, SLOT(slotApplicabilityChanged()) );
00282     connect( mApplyOnForChecked, SIGNAL(clicked()),
00283          this, SLOT(slotApplicabilityChanged()) );
00284     connect( mApplyOnOut, SIGNAL(clicked()),
00285          this, SLOT(slotApplicabilityChanged()) );
00286     connect( mApplyOnCtrlJ, SIGNAL(clicked()),
00287          this, SLOT(slotApplicabilityChanged()) );
00288     connect( mAccountList, SIGNAL(clicked(QListViewItem*)),
00289          this, SLOT(slotApplicableAccountsChanged()) );
00290     connect( mAccountList, SIGNAL(spacePressed(QListViewItem*)),
00291          this, SLOT(slotApplicableAccountsChanged()) );
00292 
00293     // transfer changes from the 'stop processing here'
00294     // check box to the filter
00295     connect( mStopProcessingHere, SIGNAL(toggled(bool)),
00296          this, SLOT(slotStopProcessingButtonToggled(bool)) );
00297 
00298     connect( mConfigureShortcut, SIGNAL(toggled(bool)),
00299          this, SLOT(slotConfigureShortcutButtonToggled(bool)) );
00300 
00301     connect( mKeyButton, SIGNAL( capturedShortcut( const KShortcut& ) ),
00302              this, SLOT( slotCapturedShortcutChanged( const KShortcut& ) ) );
00303 
00304     connect( mConfigureToolbar, SIGNAL(toggled(bool)),
00305          this, SLOT(slotConfigureToolbarButtonToggled(bool)) );
00306 
00307     connect( mFilterActionIconButton, SIGNAL( iconChanged( QString ) ),
00308              this, SLOT( slotFilterActionIconChanged( QString ) ) );
00309   }
00310 
00311   // reset all widgets here
00312   connect( mFilterList, SIGNAL(resetWidgets()),
00313        this, SLOT(slotReset()) );
00314 
00315   connect( mFilterList, SIGNAL( applyWidgets() ),
00316            this, SLOT( slotUpdateFilter() ) );
00317 
00318   // support auto-naming the filter
00319   connect( mPatternEdit, SIGNAL(maybeNameChanged()),
00320        mFilterList, SLOT(slotUpdateFilterName()) );
00321 
00322   // apply changes on 'Apply'
00323   connect( this, SIGNAL(applyClicked()),
00324        mFilterList, SLOT(slotApplyFilterChanges()) );
00325 
00326   // apply changes on 'OK'
00327   connect( this, SIGNAL(okClicked()),
00328        mFilterList, SLOT(slotApplyFilterChanges()) );
00329 
00330   // save dialog size on 'OK'
00331   connect( this, SIGNAL(okClicked()),
00332        this, SLOT(slotSaveSize()) );
00333 
00334   // destruct the dialog on OK, close and Cancel
00335   connect( this, SIGNAL(finished()),
00336        this, SLOT(slotFinished()) );
00337 
00338   KConfigGroup geometry( KMKernel::config(), "Geometry");
00339   const char * configKey
00340     = bPopFilter ? "popFilterDialogSize" : "filterDialogSize";
00341   if ( geometry.hasKey( configKey ) )
00342     resize( geometry.readSizeEntry( configKey ) );
00343   else
00344     adjustSize();
00345 
00346   // load the filter list (emits filterSelected())
00347   mFilterList->loadFilterList( createDummyFilter );
00348 }
00349 
00350 void KMFilterDlg::slotFinished() {
00351     delayedDestruct();
00352 }
00353 
00354 void KMFilterDlg::slotSaveSize() {
00355   KConfigGroup geometry( KMKernel::config(), "Geometry" );
00356   geometry.writeEntry( bPopFilter ? "popFilterDialogSize" : "filterDialogSize", size() );
00357 }
00358 
00360 void KMFilterDlg::slotActionChanged(const KMPopFilterAction aAction)
00361 {
00362   mFilter->setAction(aAction);
00363 }
00364 
00365 void KMFilterDlg::slotFilterSelected( KMFilter* aFilter )
00366 {
00367   assert( aFilter );
00368 
00369   if (bPopFilter){
00370     mActionGroup->setAction( aFilter->action() );
00371     mGlobalsBox->setEnabled( true );
00372     mShowLaterBtn->setChecked(mFilterList->showLaterMsgs());
00373   } else {
00374     mActionLister->setActionList( aFilter->actions() );
00375 
00376     mAdvOptsGroup->setEnabled( true );
00377   }
00378 
00379   mPatternEdit->setSearchPattern( aFilter->pattern() );
00380   mFilter = aFilter;
00381 
00382   if (!bPopFilter) {
00383     kdDebug(5006) << "apply on inbound == "
00384           << aFilter->applyOnInbound() << endl;
00385     kdDebug(5006) << "apply on outbound == "
00386           << aFilter->applyOnOutbound() << endl;
00387     kdDebug(5006) << "apply on explicit == "
00388           << aFilter->applyOnExplicit() << endl;
00389 
00390     // NOTE: setting these values activates the slot that sets them in
00391     // the filter! So make sure we have the correct values _before_ we
00392     // set the first one:
00393     const bool applyOnIn = aFilter->applyOnInbound();
00394     const bool applyOnForAll = aFilter->applicability() == KMFilter::All;
00395     const bool applyOnTraditional = aFilter->applicability() == KMFilter::ButImap;
00396     const bool applyOnOut = aFilter->applyOnOutbound();
00397     const bool applyOnExplicit = aFilter->applyOnExplicit();
00398     const bool stopHere = aFilter->stopProcessingHere();
00399     const bool configureShortcut = aFilter->configureShortcut();
00400     const bool configureToolbar = aFilter->configureToolbar();
00401     const QString icon = aFilter->icon();
00402     const KShortcut shortcut( aFilter->shortcut() );
00403 
00404     mApplyOnIn->setChecked( applyOnIn );
00405     mApplyOnForAll->setEnabled( applyOnIn );
00406     mApplyOnForTraditional->setEnabled( applyOnIn );
00407     mApplyOnForChecked->setEnabled( applyOnIn );
00408     mApplyOnForAll->setChecked( applyOnForAll );
00409     mApplyOnForTraditional->setChecked( applyOnTraditional );
00410     mApplyOnForChecked->setChecked( !applyOnForAll && !applyOnTraditional );
00411     mAccountList->setEnabled( mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked() );
00412     slotUpdateAccountList();
00413     mApplyOnOut->setChecked( applyOnOut );
00414     mApplyOnCtrlJ->setChecked( applyOnExplicit );
00415     mStopProcessingHere->setChecked( stopHere );
00416     mConfigureShortcut->setChecked( configureShortcut );
00417     mKeyButton->setShortcut( shortcut, false );
00418     mConfigureToolbar->setChecked( configureToolbar );
00419     mFilterActionIconButton->setIcon( icon );
00420   }
00421 }
00422 
00423 void KMFilterDlg::slotReset()
00424 {
00425   mFilter = 0;
00426   mPatternEdit->reset();
00427 
00428   if(bPopFilter) {
00429     mActionGroup->reset();
00430     mGlobalsBox->setEnabled( false );
00431   } else {
00432     mActionLister->reset();
00433     mAdvOptsGroup->setEnabled( false );
00434     slotUpdateAccountList();
00435   }
00436 }
00437 
00438 void KMFilterDlg::slotUpdateFilter()
00439 {
00440   mPatternEdit->updateSearchPattern();
00441   if ( !bPopFilter ) {
00442     mActionLister->updateActionList();
00443   }
00444 }
00445 
00446 void KMFilterDlg::slotApplicabilityChanged()
00447 {
00448   if ( mFilter ) {
00449     mFilter->setApplyOnInbound( mApplyOnIn->isChecked() );
00450     mFilter->setApplyOnOutbound( mApplyOnOut->isChecked() );
00451     mFilter->setApplyOnExplicit( mApplyOnCtrlJ->isChecked() );
00452     if ( mApplyOnForAll->isChecked() )
00453       mFilter->setApplicability( KMFilter::All );
00454     else if ( mApplyOnForTraditional->isChecked() )
00455       mFilter->setApplicability( KMFilter::ButImap );
00456     else if ( mApplyOnForChecked->isChecked() )
00457       mFilter->setApplicability( KMFilter::Checked );
00458 
00459     mApplyOnForAll->setEnabled( mApplyOnIn->isChecked() );
00460     mApplyOnForTraditional->setEnabled(  mApplyOnIn->isChecked() );
00461     mApplyOnForChecked->setEnabled( mApplyOnIn->isChecked() );
00462     mAccountList->setEnabled( mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked() );
00463 
00464     // Advanced tab functionality - Update list of accounts this filter applies to
00465     QListViewItemIterator it( mAccountList );
00466     while ( it.current() ) {
00467       QCheckListItem *item = dynamic_cast<QCheckListItem*>( it.current() );
00468       if (item) {
00469     int id = item->text( 2 ).toInt();
00470       item->setOn( mFilter->applyOnAccount( id ) );
00471       }
00472       ++it;
00473     }
00474 
00475     kdDebug(5006) << "KMFilterDlg: setting filter to be applied at "
00476                   << ( mFilter->applyOnInbound() ? "incoming " : "" )
00477                   << ( mFilter->applyOnOutbound() ? "outgoing " : "" )
00478                   << ( mFilter->applyOnExplicit() ? "explicit CTRL-J" : "" )
00479                   << endl;
00480   }
00481 }
00482 
00483 void KMFilterDlg::slotApplicableAccountsChanged()
00484 {
00485   if ( mFilter && mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked() ) {
00486     // Advanced tab functionality - Update list of accounts this filter applies to
00487     QListViewItemIterator it( mAccountList );
00488     while ( it.current() ) {
00489       QCheckListItem *item = dynamic_cast<QCheckListItem*>( it.current() );
00490       if (item) {
00491     int id = item->text( 2 ).toInt();
00492     mFilter->setApplyOnAccount( id, item->isOn() );
00493       }
00494       ++it;
00495     }
00496   }
00497 }
00498 
00499 void KMFilterDlg::slotStopProcessingButtonToggled( bool aChecked )
00500 {
00501   if ( mFilter )
00502     mFilter->setStopProcessingHere( aChecked );
00503 }
00504 
00505 void KMFilterDlg::slotConfigureShortcutButtonToggled( bool aChecked )
00506 {
00507   if ( mFilter ) {
00508     mFilter->setConfigureShortcut( aChecked );
00509     mKeyButton->setEnabled( aChecked );
00510     mConfigureToolbar->setEnabled( aChecked );
00511     mFilterActionIconButton->setEnabled( aChecked );
00512     mFilterActionLabel->setEnabled( aChecked );
00513   }
00514 }
00515 
00516 void KMFilterDlg::slotCapturedShortcutChanged( const KShortcut& sc )
00517 {
00518   KShortcut mySc(sc);
00519   if ( mySc == mKeyButton->shortcut() ) return;
00520   // FIXME work around a problem when reseting the shortcut via the shortcut dialog
00521   // somehow the returned shortcut does not evaluate to true in KShortcut::isNull(),
00522   // so we additionally have to check for an empty string
00523   if ( mySc.isNull() || mySc.toString().isEmpty() )
00524     mySc.clear();
00525   if ( !mySc.isNull() && !( kmkernel->getKMMainWidget()->shortcutIsValid( mySc ) ) ) {
00526     QString msg( i18n( "The selected shortcut is already used, "
00527           "please select a different one." ) );
00528     KMessageBox::sorry( this, msg );
00529   } else {
00530     mKeyButton->setShortcut( mySc, false );
00531     if ( mFilter )
00532       mFilter->setShortcut( mKeyButton->shortcut() );
00533   }
00534 }
00535 
00536 void KMFilterDlg::slotConfigureToolbarButtonToggled( bool aChecked )
00537 {
00538   if ( mFilter )
00539     mFilter->setConfigureToolbar( aChecked );
00540 }
00541 
00542 void KMFilterDlg::slotFilterActionIconChanged( QString icon )
00543 {
00544   if ( mFilter )
00545     mFilter->setIcon( icon );
00546 }
00547 
00548 void KMFilterDlg::slotUpdateAccountList()
00549 {
00550   mAccountList->clear();
00551   QListViewItem *top = 0;
00552   for( KMAccount *a = kmkernel->acctMgr()->first(); a!=0;
00553        a = kmkernel->acctMgr()->next() ) {
00554     QCheckListItem *listItem =
00555       new QCheckListItem( mAccountList, top, a->name(), QCheckListItem::CheckBox );
00556     listItem->setText( 1, a->type() );
00557     listItem->setText( 2, QString( "%1" ).arg( a->id() ) );
00558     if ( mFilter )
00559       listItem->setOn( mFilter->applyOnAccount( a->id() ) );
00560     top = listItem;
00561   }
00562 
00563   QListViewItem *listItem = mAccountList->firstChild();
00564   if ( listItem ) {
00565     mAccountList->setCurrentItem( listItem );
00566     mAccountList->setSelected( listItem, true );
00567   }
00568 }
00569 
00570 //=============================================================================
00571 //
00572 // class KMFilterListBox (the filter list manipulator)
00573 //
00574 //=============================================================================
00575 
00576 KMFilterListBox::KMFilterListBox( const QString & title, QWidget *parent, const char* name, bool popFilter )
00577   : QGroupBox( 1, Horizontal, title, parent, name ),
00578     bPopFilter(popFilter)
00579 {
00580   mFilterList.setAutoDelete( true );
00581   mIdxSelItem = -1;
00582 
00583   //----------- the list box
00584   mListBox = new QListBox(this);
00585   mListBox->setMinimumWidth(150);
00586   QWhatsThis::add( mListBox, i18n(_wt_filterlist) );
00587 
00588   //----------- the first row of buttons
00589   QHBox *hb = new QHBox(this);
00590   hb->setSpacing(4);
00591   mBtnTop = new KPushButton( QString::null, hb );
00592   mBtnTop->setAutoRepeat( true );
00593   mBtnTop->setIconSet( BarIconSet( "top", KIcon::SizeSmall ) );
00594   mBtnTop->setMinimumSize( mBtnTop->sizeHint() * 1.2 );
00595   mBtnUp = new KPushButton( QString::null, hb );
00596   mBtnUp->setAutoRepeat( true );
00597   mBtnUp->setIconSet( BarIconSet( "up", KIcon::SizeSmall ) );
00598   mBtnUp->setMinimumSize( mBtnUp->sizeHint() * 1.2 );
00599   mBtnDown = new KPushButton( QString::null, hb );
00600   mBtnDown->setAutoRepeat( true );
00601   mBtnDown->setIconSet( BarIconSet( "down", KIcon::SizeSmall ) );
00602   mBtnDown->setMinimumSize( mBtnDown->sizeHint() * 1.2 );
00603   mBtnBot = new KPushButton( QString::null, hb );
00604   mBtnBot->setAutoRepeat( true );
00605   mBtnBot->setIconSet( BarIconSet( "bottom", KIcon::SizeSmall ) );
00606   mBtnBot->setMinimumSize( mBtnBot->sizeHint() * 1.2 );
00607   QToolTip::add( mBtnTop, i18n("Top") );
00608   QToolTip::add( mBtnUp, i18n("Up") );
00609   QToolTip::add( mBtnDown, i18n("Down") );
00610   QToolTip::add( mBtnBot, i18n("Bottom") );
00611   QWhatsThis::add( mBtnTop, i18n(_wt_filterlist_top) );
00612   QWhatsThis::add( mBtnUp, i18n(_wt_filterlist_up) );
00613   QWhatsThis::add( mBtnDown, i18n(_wt_filterlist_down) );
00614   QWhatsThis::add( mBtnBot, i18n(_wt_filterlist_bot) );
00615 
00616   //----------- the second row of buttons
00617   hb = new QHBox(this);
00618   hb->setSpacing(4);
00619   mBtnNew = new QPushButton( QString::null, hb );
00620   mBtnNew->setPixmap( BarIcon( "filenew", KIcon::SizeSmall ) );
00621   mBtnNew->setMinimumSize( mBtnNew->sizeHint() * 1.2 );
00622   mBtnCopy = new QPushButton( QString::null, hb );
00623   mBtnCopy->setIconSet( BarIconSet( "editcopy", KIcon::SizeSmall ) );
00624   mBtnCopy->setMinimumSize( mBtnCopy->sizeHint() * 1.2 );
00625   mBtnDelete = new QPushButton( QString::null, hb );
00626   mBtnDelete->setIconSet( BarIconSet( "editdelete", KIcon::SizeSmall ) );
00627   mBtnDelete->setMinimumSize( mBtnDelete->sizeHint() * 1.2 );
00628   mBtnRename = new QPushButton( i18n("Rename..."), hb );
00629   QToolTip::add( mBtnNew, i18n("New") );
00630   QToolTip::add( mBtnCopy, i18n("Copy") );
00631   QToolTip::add( mBtnDelete, i18n("Delete"));
00632   QWhatsThis::add( mBtnNew, i18n(_wt_filterlist_new) );
00633   QWhatsThis::add( mBtnCopy, i18n(_wt_filterlist_copy) );
00634   QWhatsThis::add( mBtnDelete, i18n(_wt_filterlist_delete) );
00635   QWhatsThis::add( mBtnRename, i18n(_wt_filterlist_rename) );
00636 
00637 
00638   //----------- now connect everything
00639   connect( mListBox, SIGNAL(highlighted(int)),
00640        this, SLOT(slotSelected(int)) );
00641   connect( mListBox, SIGNAL( doubleClicked ( QListBoxItem * )),
00642            this, SLOT( slotRename()) );
00643   connect( mBtnTop, SIGNAL(clicked()),
00644        this, SLOT(slotTop()) );
00645   connect( mBtnUp, SIGNAL(clicked()),
00646        this, SLOT(slotUp()) );
00647   connect( mBtnDown, SIGNAL(clicked()),
00648        this, SLOT(slotDown()) );
00649   connect( mBtnBot, SIGNAL(clicked()),
00650        this, SLOT(slotBottom()) );
00651   connect( mBtnNew, SIGNAL(clicked()),
00652        this, SLOT(slotNew()) );
00653   connect( mBtnCopy, SIGNAL(clicked()),
00654        this, SLOT(slotCopy()) );
00655   connect( mBtnDelete, SIGNAL(clicked()),
00656        this, SLOT(slotDelete()) );
00657   connect( mBtnRename, SIGNAL(clicked()),
00658        this, SLOT(slotRename()) );
00659 
00660   // the dialog should call loadFilterList()
00661   // when all signals are connected.
00662   enableControls();
00663 }
00664 
00665 
00666 void KMFilterListBox::createFilter( const QCString & field,
00667                     const QString & value )
00668 {
00669   KMSearchRule *newRule = KMSearchRule::createInstance( field, KMSearchRule::FuncContains, value );
00670 
00671   KMFilter *newFilter = new KMFilter(0, bPopFilter);
00672   newFilter->pattern()->append( newRule );
00673   newFilter->pattern()->setName( QString("<%1>:%2").arg( field ).arg( value) );
00674 
00675   KMFilterActionDesc *desc = (*kmkernel->filterActionDict())["transfer"];
00676   if ( desc )
00677     newFilter->actions()->append( desc->create() );
00678 
00679   insertFilter( newFilter );
00680   enableControls();
00681 }
00682 
00683 bool KMFilterListBox::showLaterMsgs()
00684 {
00685     return mShowLater;
00686 }
00687 
00688 void KMFilterListBox::slotUpdateFilterName()
00689 {
00690   KMSearchPattern *p = mFilterList.at(mIdxSelItem)->pattern();
00691   if ( !p ) return;
00692 
00693   QString shouldBeName = p->name();
00694   QString displayedName = mListBox->text( mIdxSelItem );
00695 
00696   if ( shouldBeName.stripWhiteSpace().isEmpty() ) {
00697     mFilterList.at(mIdxSelItem)->setAutoNaming( true );
00698   }
00699 
00700   if ( mFilterList.at(mIdxSelItem)->isAutoNaming() ) {
00701     // auto-naming of patterns
00702     if ( p->first() && !p->first()->field().stripWhiteSpace().isEmpty() )
00703       shouldBeName = QString( "<%1>: %2" ).arg( p->first()->field() ).arg( p->first()->contents() );
00704     else
00705       shouldBeName = "<" + i18n("unnamed") + ">";
00706     p->setName( shouldBeName );
00707   }
00708 
00709   if ( displayedName == shouldBeName ) return;
00710 
00711   mListBox->blockSignals( true );
00712   mListBox->changeItem( shouldBeName, mIdxSelItem );
00713   mListBox->blockSignals( false );
00714 }
00715 
00716 void KMFilterListBox::slotShowLaterToggled(bool aOn)
00717 {
00718   mShowLater = aOn;
00719 }
00720 
00721 void KMFilterListBox::slotApplyFilterChanges()
00722 {
00723   if ( mIdxSelItem >= 0 ) {
00724     emit applyWidgets();
00725     slotSelected( mListBox->currentItem() );
00726   }
00727 
00728   // by now all edit widgets should have written back
00729   // their widget's data into our filter list.
00730 
00731   KMFilterMgr *fm;
00732   if (bPopFilter)
00733     fm = kmkernel->popFilterMgr();
00734   else
00735     fm = kmkernel->filterMgr();
00736 
00737   QValueList<KMFilter*> newFilters = filtersForSaving();
00738 
00739   if (bPopFilter)
00740     fm->setShowLaterMsgs(mShowLater);
00741 
00742   fm->setFilters( newFilters );
00743   if (fm->atLeastOneOnlineImapFolderTarget()) {
00744     QString str = i18n("At least one filter targets a folder on an online "
00745                "IMAP account. Such filters will only be applied "
00746                "when manually filtering and when filtering "
00747                "incoming online IMAP mail.");
00748     KMessageBox::information( this, str, QString::null,
00749                   "filterDlgOnlineImapCheck" );
00750   }
00751 }
00752 
00753 QValueList<KMFilter*> KMFilterListBox::filtersForSaving() const
00754 {
00755       const_cast<KMFilterListBox*>( this )->applyWidgets(); // signals aren't const
00756       QValueList<KMFilter*> filters;
00757       QStringList emptyFilters;
00758       QPtrListIterator<KMFilter> it( mFilterList );
00759       for ( it.toFirst() ; it.current() ; ++it ) {
00760         KMFilter *f = new KMFilter( **it ); // deep copy
00761         f->purify();
00762         if ( !f->isEmpty() )
00763           // the filter is valid:
00764           filters.append( f );
00765         else {
00766           // the filter is invalid:
00767           emptyFilters << f->name();
00768           delete f;
00769         }
00770       }
00771 
00772       // report on invalid filters:
00773       if ( !emptyFilters.empty() ) {
00774         QString msg = i18n("The following filters have not been saved because they "
00775                    "were invalid (e.g. containing no actions or no search "
00776                    "rules).");
00777         KMessageBox::informationList( 0, msg, emptyFilters, QString::null,
00778                       "ShowInvalidFilterWarning" );
00779       }
00780       return filters;
00781 }
00782 
00783 void KMFilterListBox::slotSelected( int aIdx )
00784 {
00785   mIdxSelItem = aIdx;
00786   // QPtrList::at(i) will return 0 if i is out of range.
00787   KMFilter *f = mFilterList.at(aIdx);
00788   if ( f )
00789     emit filterSelected( f );
00790   else
00791     emit resetWidgets();
00792   enableControls();
00793 }
00794 
00795 void KMFilterListBox::slotNew()
00796 {
00797   // just insert a new filter.
00798   insertFilter( new KMFilter(0, bPopFilter) );
00799   enableControls();
00800 }
00801 
00802 void KMFilterListBox::slotCopy()
00803 {
00804   if ( mIdxSelItem < 0 ) {
00805     kdDebug(5006) << "KMFilterListBox::slotCopy called while no filter is selected, ignoring." << endl;
00806     return;
00807   }
00808 
00809   // make sure that all changes are written to the filter before we copy it
00810   emit applyWidgets();
00811 
00812   KMFilter *filter = mFilterList.at( mIdxSelItem );
00813 
00814   // enableControls should make sure this method is
00815   // never called when no filter is selected.
00816   assert( filter );
00817 
00818   // inserts a copy of the current filter.
00819   insertFilter( new KMFilter( *filter ) );
00820   enableControls();
00821 }
00822 
00823 void KMFilterListBox::slotDelete()
00824 {
00825   if ( mIdxSelItem < 0 ) {
00826     kdDebug(5006) << "KMFilterListBox::slotDelete called while no filter is selected, ignoring." << endl;
00827     return;
00828   }
00829 
00830   int oIdxSelItem = mIdxSelItem;
00831   mIdxSelItem = -1;
00832   // unselect all
00833   mListBox->selectAll( false );
00834   // broadcast that all widgets let go
00835   // of the filter
00836   emit resetWidgets();
00837 
00838   // remove the filter from both the filter list...
00839   mFilterList.remove( oIdxSelItem );
00840   // and the listbox
00841   mListBox->removeItem( oIdxSelItem );
00842 
00843   int count = (int)mListBox->count();
00844   // and set the new current item.
00845   if ( count > oIdxSelItem )
00846     // oIdxItem is still a valid index
00847     mListBox->setSelected( oIdxSelItem, true );
00848   else if ( count )
00849     // oIdxSelIdx is no longer valid, but the
00850     // list box isn't empty
00851     mListBox->setSelected( count - 1, true );
00852   // the list is empty - keep index -1
00853 
00854   enableControls();
00855 }
00856 
00857 void KMFilterListBox::slotTop()
00858 {
00859   if ( mIdxSelItem < 0 ) {
00860     kdDebug(5006) << "KMFilterListBox::slotTop called while no filter is selected, ignoring." << endl;
00861     return;
00862   }
00863   if ( mIdxSelItem == 0 ) {
00864     kdDebug(5006) << "KMFilterListBox::slotTop called while the _topmost_ filter is selected, ignoring." << endl;
00865     return;
00866   }
00867 
00868   swapFilters( mIdxSelItem, 0 );
00869   enableControls();
00870 }
00871 
00872 void KMFilterListBox::slotUp()
00873 {
00874   if ( mIdxSelItem < 0 ) {
00875     kdDebug(5006) << "KMFilterListBox::slotUp called while no filter is selected, ignoring." << endl;
00876     return;
00877   }
00878   if ( mIdxSelItem == 0 ) {
00879     kdDebug(5006) << "KMFilterListBox::slotUp called while the _topmost_ filter is selected, ignoring." << endl;
00880     return;
00881   }
00882 
00883   swapNeighbouringFilters( mIdxSelItem, mIdxSelItem - 1 );
00884   enableControls();
00885 }
00886 
00887 void KMFilterListBox::slotDown()
00888 {
00889   if ( mIdxSelItem < 0 ) {
00890     kdDebug(5006) << "KMFilterListBox::slotDown called while no filter is selected, ignoring." << endl;
00891     return;
00892   }
00893   if ( mIdxSelItem == (int)mListBox->count() - 1 ) {
00894     kdDebug(5006) << "KMFilterListBox::slotDown called while the _last_ filter is selected, ignoring." << endl;
00895     return;
00896   }
00897 
00898   swapNeighbouringFilters( mIdxSelItem, mIdxSelItem + 1);
00899   enableControls();
00900 }
00901 
00902 void KMFilterListBox::slotBottom()
00903 {
00904   if ( mIdxSelItem < 0 ) {
00905     kdDebug(5006) << "KMFilterListBox::slotBottom called while no filter is selected, ignoring." << endl;
00906     return;
00907   }
00908   if ( mIdxSelItem == (int)mListBox->count() - 1 ) {
00909     kdDebug(5006) << "KMFilterListBox::slotBottom called while the _last_ filter is selected, ignoring." << endl;
00910     return;
00911   }
00912 
00913   swapFilters( mIdxSelItem, mListBox->count()-1 );
00914   enableControls();
00915 }
00916 
00917 void KMFilterListBox::slotRename()
00918 {
00919   if ( mIdxSelItem < 0 ) {
00920     kdDebug(5006) << "KMFilterListBox::slotRename called while no filter is selected, ignoring." << endl;
00921     return;
00922   }
00923 
00924   bool okPressed =  false ;
00925   KMFilter *filter = mFilterList.at( mIdxSelItem );
00926 
00927   // enableControls should make sure this method is
00928   // never called when no filter is selected.
00929   assert( filter );
00930 
00931   // allow empty names - those will turn auto-naming on again
00932   QValidator *validator = new QRegExpValidator( QRegExp( ".*" ), 0 );
00933   QString newName = KInputDialog::getText
00934     (
00935      i18n("Rename Filter"),
00936      i18n("Rename filter \"%1\" to:\n(leave the field empty for automatic naming)")
00937         .arg( filter->pattern()->name() ) /*label*/,
00938      filter->pattern()->name() /* initial value */,
00939      &okPressed, topLevelWidget(), 0, validator
00940      );
00941   delete validator;
00942 
00943   if ( !okPressed ) return;
00944 
00945   if ( newName.isEmpty() ) {
00946     // bait for slotUpdateFilterName to
00947     // use automatic naming again.
00948     filter->pattern()->setName( "<>" );
00949     filter->setAutoNaming( true );
00950   } else {
00951     filter->pattern()->setName( newName );
00952     filter->setAutoNaming( false );
00953   }
00954 
00955   slotUpdateFilterName();
00956 }
00957 
00958 void KMFilterListBox::enableControls()
00959 {
00960   bool theFirst = ( mIdxSelItem == 0 );
00961   bool theLast = ( mIdxSelItem >= (int)mFilterList.count() - 1 );
00962   bool aFilterIsSelected = ( mIdxSelItem >= 0 );
00963 
00964   mBtnTop->setEnabled( aFilterIsSelected && !theFirst );
00965   mBtnUp->setEnabled( aFilterIsSelected && !theFirst );
00966   mBtnDown->setEnabled( aFilterIsSelected && !theLast );
00967   mBtnBot->setEnabled( aFilterIsSelected && !theLast );
00968   mBtnCopy->setEnabled( aFilterIsSelected );
00969   mBtnDelete->setEnabled( aFilterIsSelected );
00970   mBtnRename->setEnabled( aFilterIsSelected );
00971 
00972   if ( aFilterIsSelected )
00973     mListBox->ensureCurrentVisible();
00974 }
00975 
00976 void KMFilterListBox::loadFilterList( bool createDummyFilter )
00977 {
00978   assert(mListBox);
00979   setEnabled( false );
00980   emit resetWidgets();
00981   // we don't want the insertion to
00982   // cause flicker in the edit widgets.
00983   blockSignals( true );
00984 
00985   // clear both lists
00986   mFilterList.clear();
00987   mListBox->clear();
00988 
00989   const KMFilterMgr *manager = 0;
00990   if(bPopFilter)
00991   {
00992     mShowLater = kmkernel->popFilterMgr()->showLaterMsgs();
00993     manager = kmkernel->popFilterMgr();
00994   }
00995   else
00996   {
00997     manager = kmkernel->filterMgr();
00998   }
00999   Q_ASSERT( manager );
01000 
01001   QValueListConstIterator<KMFilter*> it;
01002   for ( it = manager->filters().constBegin() ; it != manager->filters().constEnd() ; ++it ) {
01003     mFilterList.append( new KMFilter( **it ) ); // deep copy
01004     mListBox->insertItem( (*it)->pattern()->name() );
01005   }
01006 
01007   blockSignals( false );
01008   setEnabled( true );
01009 
01010   // create an empty filter when there's none, to avoid a completely
01011   // disabled dialog (usability tests indicated that the new-filter
01012   // button is too hard to find that way):
01013   if ( !mListBox->count() && createDummyFilter )
01014     slotNew();
01015 
01016   if ( mListBox->count() > 0 )
01017     mListBox->setSelected( 0, true );
01018 
01019   enableControls();
01020 }
01021 
01022 void KMFilterListBox::insertFilter( KMFilter* aFilter )
01023 {
01024   // must be really a filter...
01025   assert( aFilter );
01026 
01027   // if mIdxSelItem < 0, QListBox::insertItem will append.
01028   mListBox->insertItem( aFilter->pattern()->name(), mIdxSelItem );
01029   if ( mIdxSelItem < 0 ) {
01030     // none selected -> append
01031     mFilterList.append( aFilter );
01032     mListBox->setSelected( mListBox->count() - 1, true );
01033     //    slotSelected( mListBox->count() - 1 );
01034   } else {
01035     // insert just before selected
01036     mFilterList.insert( mIdxSelItem, aFilter );
01037     mListBox->setSelected( mIdxSelItem, true );
01038     //    slotSelected( mIdxSelItem );
01039   }
01040 
01041 }
01042 
01043 void KMFilterListBox::appendFilter( KMFilter* aFilter )
01044 {
01045     mFilterList.append( aFilter );
01046     mListBox->insertItem( aFilter->pattern()->name(), -1 );
01047 }
01048 
01049 void KMFilterListBox::swapNeighbouringFilters( int untouchedOne, int movedOne )
01050 {
01051   // must be neighbours...
01052   assert( untouchedOne - movedOne == 1 || movedOne - untouchedOne == 1 );
01053 
01054   // untouchedOne is at idx. to move it down(up),
01055   // remove item at idx+(-)1 w/o deleting it.
01056   QListBoxItem *item = mListBox->item( movedOne );
01057   mListBox->takeItem( item );
01058   // now selected item is at idx(idx-1), so
01059   // insert the other item at idx, ie. above(below).
01060   mListBox->insertItem( item, untouchedOne );
01061 
01062   KMFilter* filter = mFilterList.take( movedOne );
01063   mFilterList.insert( untouchedOne, filter );
01064 
01065   mIdxSelItem += movedOne - untouchedOne;
01066 }
01067 
01068 void KMFilterListBox::swapFilters( int from, int to )
01069 {
01070   QListBoxItem *item = mListBox->item( from );
01071   mListBox->takeItem( item );
01072   mListBox->insertItem( item, to );
01073 
01074   KMFilter* filter = mFilterList.take( from );
01075   mFilterList.insert( to, filter );
01076 
01077   mIdxSelItem = to;
01078   mListBox->setCurrentItem( mIdxSelItem );
01079   mListBox->setSelected( mIdxSelItem, true );
01080 }
01081 
01082 //=============================================================================
01083 //
01084 // class KMFilterActionWidget
01085 //
01086 //=============================================================================
01087 
01088 KMFilterActionWidget::KMFilterActionWidget( QWidget *parent, const char* name )
01089   : QHBox( parent, name )
01090 {
01091   int i;
01092   mActionList.setAutoDelete( true );
01093 
01094   mComboBox = new QComboBox(  false , this );
01095   assert( mComboBox );
01096   mWidgetStack = new QWidgetStack(this);
01097   assert( mWidgetStack );
01098 
01099   setSpacing( 4 );
01100 
01101   QPtrListIterator<KMFilterActionDesc> it ( kmkernel->filterActionDict()->list() );
01102   for ( i=0, it.toFirst() ; it.current() ; ++it, ++i ) {
01103     //create an instance:
01104     KMFilterAction *a = (*it)->create();
01105     // append to the list of actions:
01106     mActionList.append( a );
01107     // add parameter widget to widget stack:
01108     mWidgetStack->addWidget( a->createParamWidget( mWidgetStack ), i );
01109     // add (i18n-ized) name to combo box
01110     mComboBox->insertItem( (*it)->label );
01111   }
01112   // widget for the case where no action is selected.
01113   mWidgetStack->addWidget( new QLabel( i18n("Please select an action."), mWidgetStack ), i );
01114   mWidgetStack->raiseWidget(i);
01115   mComboBox->insertItem( " " );
01116   mComboBox->setCurrentItem(i);
01117 
01118   // don't show scroll bars.
01119   mComboBox->setSizeLimit( mComboBox->count() );
01120   // layout management:
01121   // o the combo box is not to be made larger than it's sizeHint(),
01122   //   the parameter widget should grow instead.
01123   // o the whole widget takes all space horizontally, but is fixed vertically.
01124   mComboBox->adjustSize();
01125   mComboBox->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
01126   setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
01127   updateGeometry();
01128 
01129   // redirect focus to the filter action combo box
01130   setFocusProxy( mComboBox );
01131 
01132   // now connect the combo box and the widget stack
01133   connect( mComboBox, SIGNAL(activated(int)),
01134        mWidgetStack, SLOT(raiseWidget(int)) );
01135 }
01136 
01137 void KMFilterActionWidget::setAction( const KMFilterAction* aAction )
01138 {
01139   int i=0;
01140   bool found =  false ;
01141   int count = mComboBox->count() - 1 ; // last entry is the empty one
01142   QString label = ( aAction ) ? aAction->label() : QString::null ;
01143 
01144   // find the index of typeOf(aAction) in mComboBox
01145   // and clear the other widgets on the way.
01146   for ( ; i < count ; i++ )
01147     if ( aAction && mComboBox->text(i) == label ) {
01148       //...set the parameter widget to the settings
01149       // of aAction...
01150       aAction->setParamWidgetValue( mWidgetStack->widget(i) );
01151       //...and show the correct entry of
01152       // the combo box
01153       mComboBox->setCurrentItem(i); // (mm) also raise the widget, but doesn't
01154       mWidgetStack->raiseWidget(i);
01155       found = true;
01156     } else // clear the parameter widget
01157       mActionList.at(i)->clearParamWidget( mWidgetStack->widget(i) );
01158   if ( found ) return;
01159 
01160   // not found, so set the empty widget
01161   mComboBox->setCurrentItem( count ); // last item
01162   mWidgetStack->raiseWidget( count) ;
01163 }
01164 
01165 KMFilterAction * KMFilterActionWidget::action()
01166 {
01167   // look up the action description via the label
01168   // returned by QComboBox::currentText()...
01169   KMFilterActionDesc *desc = (*kmkernel->filterActionDict())[ mComboBox->currentText() ];
01170   if ( desc ) {
01171     // ...create an instance...
01172     KMFilterAction *fa = desc->create();
01173     if ( fa ) {
01174       // ...and apply the setting of the parameter widget.
01175       fa->applyParamWidgetValue( mWidgetStack->visibleWidget() );
01176       return fa;
01177     }
01178   }
01179 
01180   return 0;
01181 }
01182 
01183 //=============================================================================
01184 //
01185 // class KMFilterActionWidgetLister (the filter action editor)
01186 //
01187 //=============================================================================
01188 
01189 KMFilterActionWidgetLister::KMFilterActionWidgetLister( QWidget *parent, const char* name )
01190   : KWidgetLister( 1, FILTER_MAX_ACTIONS, parent, name )
01191 {
01192   mActionList = 0;
01193 }
01194 
01195 KMFilterActionWidgetLister::~KMFilterActionWidgetLister()
01196 {
01197 }
01198 
01199 void KMFilterActionWidgetLister::setActionList( QPtrList<KMFilterAction> *aList )
01200 {
01201   assert ( aList );
01202 
01203   if ( mActionList )
01204     regenerateActionListFromWidgets();
01205 
01206   mActionList = aList;
01207 
01208   ((QWidget*)parent())->setEnabled( true );
01209 
01210   if ( aList->count() == 0 ) {
01211     slotClear();
01212     return;
01213   }
01214 
01215   int superfluousItems = (int)mActionList->count() - mMaxWidgets ;
01216   if ( superfluousItems > 0 ) {
01217     kdDebug(5006) << "KMFilterActionWidgetLister: Clipping action list to "
01218           << mMaxWidgets << " items!" << endl;
01219 
01220     for ( ; superfluousItems ; superfluousItems-- )
01221       mActionList->removeLast();
01222   }
01223 
01224   // set the right number of widgets
01225   setNumberOfShownWidgetsTo( mActionList->count() );
01226 
01227   // load the actions into the widgets
01228   QPtrListIterator<KMFilterAction> aIt( *mActionList );
01229   QPtrListIterator<QWidget> wIt( mWidgetList );
01230   for ( aIt.toFirst(), wIt.toFirst() ;
01231     aIt.current() && wIt.current() ; ++aIt, ++wIt )
01232     ((KMFilterActionWidget*)(*wIt))->setAction( (*aIt) );
01233 }
01234 
01235 void KMFilterActionWidgetLister::reset()
01236 {
01237   if ( mActionList )
01238     regenerateActionListFromWidgets();
01239 
01240   mActionList = 0;
01241   slotClear();
01242   ((QWidget*)parent())->setEnabled(  false  );
01243 }
01244 
01245 QWidget* KMFilterActionWidgetLister::createWidget( QWidget *parent )
01246 {
01247   return new KMFilterActionWidget(parent);
01248 }
01249 
01250 void KMFilterActionWidgetLister::clearWidget( QWidget *aWidget )
01251 {
01252   if ( aWidget )
01253     ((KMFilterActionWidget*)aWidget)->setAction(0);
01254 }
01255 
01256 void KMFilterActionWidgetLister::regenerateActionListFromWidgets()
01257 {
01258   if ( !mActionList ) return;
01259 
01260   mActionList->clear();
01261 
01262   QPtrListIterator<QWidget> it( mWidgetList );
01263   for ( it.toFirst() ; it.current() ; ++it ) {
01264     KMFilterAction *a = ((KMFilterActionWidget*)(*it))->action();
01265     if ( a )
01266       mActionList->append( a );
01267   }
01268 
01269 }
01270 
01271 //=============================================================================
01272 //
01273 // class KMPopFilterActionWidget
01274 //
01275 //=============================================================================
01276 
01277 KMPopFilterActionWidget::KMPopFilterActionWidget( const QString& title, QWidget *parent, const char* name )
01278   : QVButtonGroup( title, parent, name )
01279 {
01280   mActionMap[Down] = new QRadioButton( i18n("&Download mail"), this );
01281   mActionMap[Later] = new QRadioButton( i18n("Download mail la&ter"), this );
01282   mActionMap[Delete] = new QRadioButton( i18n("D&elete mail from server"), this );
01283   mIdMap[id(mActionMap[Later])] = Later;
01284   mIdMap[id(mActionMap[Down])] = Down;
01285   mIdMap[id(mActionMap[Delete])] = Delete;
01286 
01287   connect( this, SIGNAL(clicked(int)),
01288        this, SLOT( slotActionClicked(int)) );
01289 }
01290 
01291 void KMPopFilterActionWidget::setAction( KMPopFilterAction aAction )
01292 {
01293   if( aAction == NoAction)
01294   {
01295     aAction = Later;
01296   }
01297 
01298   mAction = aAction;
01299 
01300   blockSignals( true );
01301   if(!mActionMap[aAction]->isChecked())
01302   {
01303     mActionMap[aAction]->setChecked( true );
01304   }
01305   blockSignals( false );
01306 
01307   setEnabled( true );
01308 }
01309 
01310 KMPopFilterAction  KMPopFilterActionWidget::action()
01311 {
01312   return mAction;
01313 }
01314 
01315 void KMPopFilterActionWidget::slotActionClicked(int aId)
01316 {
01317   emit actionChanged(mIdMap[aId]);
01318   setAction(mIdMap[aId]);
01319 }
01320 
01321 void KMPopFilterActionWidget::reset()
01322 {
01323   blockSignals( true );
01324   mActionMap[Down]->setChecked( true );
01325   blockSignals( false );
01326 
01327   setEnabled(  false  );
01328 }
01329 
01330 void KMFilterDlg::slotImportFilters()
01331 {
01332     FilterImporterExporter importer( this, bPopFilter );
01333     QValueList<KMFilter*> filters = importer.importFilters();
01334     // FIXME message box how many were imported?
01335     if (filters.isEmpty()) return;
01336 
01337     QValueListConstIterator<KMFilter*> it;
01338 
01339     for ( it = filters.constBegin() ; it != filters.constEnd() ; ++it ) {
01340         mFilterList->appendFilter( *it ); // no need to deep copy, ownership passes to the list
01341     }
01342 }
01343 
01344 void KMFilterDlg::slotExportFilters()
01345 {
01346     FilterImporterExporter exporter( this, bPopFilter );
01347     QValueList<KMFilter*> filters = mFilterList->filtersForSaving();
01348     exporter.exportFilters( filters );
01349     QValueList<KMFilter*>::iterator it;
01350     for ( it = filters.begin(); it != filters.end(); ++it )
01351         delete *it;
01352 }
01353 
01354 #include "kmfilterdlg.moc"