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 <tdemessagebox.h> 00023 #include <kdebug.h> 00024 #include <tdelocale.h> 00025 #include <kinputdialog.h> 00026 #include <kiconloader.h> 00027 #include <tdeapplication.h> 00028 #include <twin.h> 00029 #include <tdeconfig.h> 00030 #include <kicondialog.h> 00031 #include <kkeybutton.h> 00032 #include <tdelistview.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 "\"<\".</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 TDEListView( 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 TDEIconButton( hbox ); 00252 mFilterActionLabel->setBuddy( mFilterActionIconButton ); 00253 mFilterActionIconButton->setIconType( TDEIcon::NoGroup, TDEIcon::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 TDEShortcut& ) ), 00306 this, TQT_SLOT( slotCapturedShortcutChanged( const TDEShortcut& ) ) ); 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 TDEConfigGroup 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 TDEConfigGroup 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 TDEShortcut 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 TDEShortcut& sc ) 00521 { 00522 TDEShortcut 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 TDEShortcut::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( "go-top", TDEIcon::SizeSmall ) ); 00598 mBtnTop->setMinimumSize( mBtnTop->sizeHint() * 1.2 ); 00599 mBtnUp = new KPushButton( TQString(), hb ); 00600 mBtnUp->setAutoRepeat( true ); 00601 mBtnUp->setIconSet( BarIconSet( "go-up", TDEIcon::SizeSmall ) ); 00602 mBtnUp->setMinimumSize( mBtnUp->sizeHint() * 1.2 ); 00603 mBtnDown = new KPushButton( TQString(), hb ); 00604 mBtnDown->setAutoRepeat( true ); 00605 mBtnDown->setIconSet( BarIconSet( "go-down", TDEIcon::SizeSmall ) ); 00606 mBtnDown->setMinimumSize( mBtnDown->sizeHint() * 1.2 ); 00607 mBtnBot = new KPushButton( TQString(), hb ); 00608 mBtnBot->setAutoRepeat( true ); 00609 mBtnBot->setIconSet( BarIconSet( "go-bottom", TDEIcon::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( "document-new", TDEIcon::SizeSmall ) ); 00625 mBtnNew->setMinimumSize( mBtnNew->sizeHint() * 1.2 ); 00626 mBtnCopy = new TQPushButton( TQString(), hb ); 00627 mBtnCopy->setIconSet( BarIconSet( "edit-copy", TDEIcon::SizeSmall ) ); 00628 mBtnCopy->setMinimumSize( mBtnCopy->sizeHint() * 1.2 ); 00629 mBtnDelete = new TQPushButton( TQString(), hb ); 00630 mBtnDelete->setIconSet( BarIconSet( "edit-delete", TDEIcon::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"