kmail

kmfilterdlg.cpp

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