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