kmail Library API Documentation

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 00014 // other KDE headers: 00015 #include <kmessagebox.h> 00016 #include <kdebug.h> 00017 #include <klocale.h> 00018 #include <kinputdialog.h> 00019 #include <kiconloader.h> 00020 #include <kapplication.h> 00021 #include <kwin.h> 00022 #include <kconfig.h> 00023 #include <kicondialog.h> 00024 00025 // other Qt headers: 00026 #include <qlayout.h> 00027 #include <qlabel.h> 00028 #include <qcombobox.h> 00029 #include <qwidgetstack.h> 00030 #include <qtooltip.h> 00031 #include <qwhatsthis.h> 00032 #include <qcheckbox.h> 00033 #include <qpushbutton.h> 00034 #include <qhbox.h> 00035 00036 // other headers: 00037 #include <assert.h> 00038 00039 00040 // What's this help texts 00041 const char * _wt_filterlist = 00042 I18N_NOOP( "<qt><p>This is the list of defined filters. " 00043 "They are processed top-to-bottom.</p>" 00044 "<p>Click on any filter to edit it " 00045 "using the controls in the right-hand half " 00046 "of the dialog.</p></qt>" ); 00047 const char * _wt_filterlist_new = 00048 I18N_NOOP( "<qt><p>Click this button to create a new filter.</p>" 00049 "<p>The filter will be inserted just before the currently " 00050 "selected one, but you can always change that " 00051 "later on.</p>" 00052 "<p>If you have clicked this button accidentally, you can undo this " 00053 "by clicking on the <em>Delete</em> button.</p></qt>" ); 00054 const char * _wt_filterlist_delete = 00055 I18N_NOOP( "<qt><p>Click this button to <em>delete</em> the currently " 00056 "selected filter from the list above.</p>" 00057 "<p>There is no way to get the filter back once " 00058 "it is deleted, but you can always leave the " 00059 "dialog by clicking <em>Cancel</em> to discard the " 00060 "changes made.</p></qt>" ); 00061 const char * _wt_filterlist_up = 00062 I18N_NOOP( "<qt><p>Click this button to move the currently " 00063 "selected filter <em>up</em> one in the list above.</p>" 00064 "<p>This is useful since the order of the filters in the list " 00065 "determines the order in which they are tried on messages: " 00066 "The topmost filter gets tried first.</p>" 00067 "<p>If you have clicked this button accidentally, you can undo this " 00068 "by clicking on the <em>Down</em> button.</p></qt>" ); 00069 const char * _wt_filterlist_down = 00070 I18N_NOOP( "<qt><p>Click this button to move the currently " 00071 "selected filter <em>down</em> one in the list above.</p>" 00072 "<p>This is useful since the order of the filters in the list " 00073 "determines the order in which they are tried on messages: " 00074 "The topmost filter gets tried first.</p>" 00075 "<p>If you have clicked this button accidentally, you can undo this " 00076 "by clicking on the <em>Up</em> button.</p></qt>" ); 00077 const char * _wt_filterlist_rename = 00078 I18N_NOOP( "<qt><p>Click this button to rename the currently selected filter.</p>" 00079 "<p>Filters are named automatically, as long as they start with " 00080 "\"<<\".</p>" 00081 "<p>If you have renamed a filter accidentally and want automatic " 00082 "naming back, click this button and select <em>Clear</em> followed " 00083 "by <em>OK</em> in the appearing dialog.</p></qt>" ); 00084 const char * _wt_filterdlg_showLater = 00085 I18N_NOOP( "<qt><p>Check this button to force the confirmation dialog to show " 00086 "up.</p><p>This is useful if you have defined a ruleset that tags " 00087 "messages to be downloaded later. Without the possibility to force " 00088 "the dialog popup, these messages could never be downloaded if no " 00089 "other large messages were waiting on the server, or if you wanted to " 00090 "change the ruleset to tag the messages differently.</p></qt>" ); 00091 00092 // The anchor of the filter dialog's help. 00093 const char * KMFilterDlgHelpAnchor = "filters-id" ; 00094 const char * KMPopFilterDlgHelpAnchor = "popfilters-id" ; 00095 00096 //============================================================================= 00097 // 00098 // class KMFilterDlg (the filter dialog) 00099 // 00100 //============================================================================= 00101 00102 KMFilterDlg::KMFilterDlg(QWidget* parent, const char* name, bool popFilter) 00103 : KDialogBase( parent, name, FALSE /* modality */, 00104 (popFilter)? i18n("POP3 Filter Rules"): i18n("Filter Rules") /* caption*/, 00105 Help|Ok|Apply|Cancel /* button mask */, 00106 Ok /* default btn */, FALSE /* separator */), 00107 bPopFilter(popFilter) 00108 { 00109 KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() ); 00110 setHelp( (bPopFilter)? KMPopFilterDlgHelpAnchor: KMFilterDlgHelpAnchor ); 00111 00112 QWidget *w = new QWidget(this); 00113 setMainWidget(w); 00114 QHBoxLayout *hbl = new QHBoxLayout( w, 0, spacingHint(), "kmfd_hbl" ); 00115 00116 mFilterList = new KMFilterListBox( i18n("Available Filters"), w, 0, bPopFilter); 00117 hbl->addWidget( mFilterList, 1 /*stretch*/ ); 00118 00119 QVBoxLayout *vbl = new QVBoxLayout( hbl, spacingHint(), "kmfd_vbl" ); 00120 hbl->setStretchFactor( vbl, 2 ); 00121 00122 mPatternEdit = new KMSearchPatternEdit( i18n("Filter Criteria"), w , "spe", bPopFilter); 00123 vbl->addWidget( mPatternEdit, 0, Qt::AlignTop ); 00124 00125 if(bPopFilter){ 00126 mActionGroup = new KMPopFilterActionWidget( i18n("Filter Action"), w ); 00127 vbl->addWidget( mActionGroup, 0, Qt::AlignTop ); 00128 00129 mGlobalsBox = new QVGroupBox(i18n("Global Options"), w); 00130 mShowLaterBtn = new QCheckBox(i18n("Always &show matched 'Download Later' messages in confirmation dialog"), mGlobalsBox); 00131 QWhatsThis::add( mShowLaterBtn, i18n(_wt_filterdlg_showLater) ); 00132 vbl->addWidget( mGlobalsBox, 0, Qt::AlignTop ); 00133 } 00134 else { 00135 QGroupBox *agb = new QGroupBox( 1 /*column*/, Vertical, i18n("Filter Actions"), w ); 00136 mActionLister = new KMFilterActionWidgetLister( agb ); 00137 vbl->addWidget( agb, 0, Qt::AlignTop ); 00138 00139 mAdvOptsGroup = new QGroupBox ( 1 /*columns*/, Vertical, 00140 i18n("Advanced Options"), w); 00141 { 00142 QWidget *adv_w = new QWidget( mAdvOptsGroup ); 00143 QGridLayout *gl = new QGridLayout( adv_w, 4 /*rows*/, 4 /*cols*/, 00144 0 /*border*/, spacingHint() ); 00145 gl->setColStretch( 0, 1 ); 00146 QLabel *l = new QLabel( i18n("Apply this filter"), adv_w ); 00147 gl->addWidget( l, 0, 0, AlignLeft ); 00148 mApplyOnIn = new QCheckBox( i18n("to &incoming messages"), adv_w ); 00149 gl->addWidget( mApplyOnIn, 0, 1 ); 00150 mApplyOnOut = new QCheckBox( i18n("to &sent messages"), adv_w ); 00151 gl->addWidget( mApplyOnOut, 0, 2 ); 00152 mApplyOnCtrlJ = new QCheckBox( i18n("on manual &filtering"), adv_w ); 00153 gl->addWidget( mApplyOnCtrlJ, 0, 3 ); 00154 mStopProcessingHere = new QCheckBox( i18n("If this filter &matches, stop processing here"), adv_w ); 00155 gl->addMultiCellWidget( mStopProcessingHere, //1, 0, Qt::AlignLeft ); 00156 1, 1, /*from to row*/ 00157 0, 3 /*from to col*/ ); 00158 mConfigureShortcut = new QCheckBox( i18n("Add this filter to the Apply Filter Actions menu"), adv_w ); 00159 gl->addMultiCellWidget( mConfigureShortcut, 2, 2, 0, 3 ); 00160 00161 QHBox *hbox = new QHBox( adv_w ); 00162 mFilterActionLabel = new QLabel( i18n( "Icon for this filter:" ), 00163 hbox ); 00164 mFilterActionLabel->setEnabled( false ); 00165 00166 mFilterActionIconButton = new KIconButton( hbox ); 00167 mFilterActionLabel->setBuddy( mFilterActionIconButton ); 00168 mFilterActionIconButton->setIconType( KIcon::NoGroup, KIcon::Any, true ); 00169 mFilterActionIconButton->setIconSize( 16 ); 00170 mFilterActionIconButton->setIcon( "gear" ); 00171 mFilterActionIconButton->setEnabled( false ); 00172 00173 gl->addMultiCellWidget( hbox, 3, 3, 0, 3 ); 00174 } 00175 vbl->addWidget( mAdvOptsGroup, 0, Qt::AlignTop ); 00176 } 00177 // spacer: 00178 vbl->addStretch( 1 ); 00179 00180 // load the filter parts into the edit widgets 00181 connect( mFilterList, SIGNAL(filterSelected(KMFilter*)), 00182 this, SLOT(slotFilterSelected(KMFilter*)) ); 00183 00184 if (bPopFilter){ 00185 // set the state of the global setting 'show later msgs' 00186 connect( mShowLaterBtn, SIGNAL(toggled(bool)), 00187 mFilterList, SLOT(slotShowLaterToggled(bool))); 00188 00189 // set the action in the filter when changed 00190 connect( mActionGroup, SIGNAL(actionChanged(const KMPopFilterAction)), 00191 this, SLOT(slotActionChanged(const KMPopFilterAction)) ); 00192 } else { 00193 // transfer changes from the 'Apply this filter on...' 00194 // combo box to the filter 00195 connect( mApplyOnIn, SIGNAL(clicked()), 00196 this, SLOT(slotApplicabilityChanged()) ); 00197 connect( mApplyOnOut, SIGNAL(clicked()), 00198 this, SLOT(slotApplicabilityChanged()) ); 00199 connect( mApplyOnCtrlJ, SIGNAL(clicked()), 00200 this, SLOT(slotApplicabilityChanged()) ); 00201 00202 // transfer changes from the 'stop processing here' 00203 // check box to the filter 00204 connect( mStopProcessingHere, SIGNAL(toggled(bool)), 00205 this, SLOT(slotStopProcessingButtonToggled(bool)) ); 00206 00207 connect( mConfigureShortcut, SIGNAL(toggled(bool)), 00208 this, SLOT(slotConfigureShortcutButtonToggled(bool)) ); 00209 00210 connect( mFilterActionIconButton, SIGNAL( iconChanged( QString ) ), 00211 this, SLOT( slotFilterActionIconChanged( QString ) ) ); 00212 } 00213 00214 // reset all widgets here 00215 connect( mFilterList, SIGNAL(resetWidgets()), 00216 this, SLOT(slotReset()) ); 00217 00218 // support auto-naming the filter 00219 connect( mPatternEdit, SIGNAL(maybeNameChanged()), 00220 mFilterList, SLOT(slotUpdateFilterName()) ); 00221 00222 // apply changes on 'Apply' 00223 connect( this, SIGNAL(applyClicked()), 00224 mFilterList, SLOT(slotApplyFilterChanges()) ); 00225 00226 // apply changes on 'OK' 00227 connect( this, SIGNAL(okClicked()), 00228 mFilterList, SLOT(slotApplyFilterChanges()) ); 00229 00230 // save dialog size on 'OK' 00231 connect( this, SIGNAL(okClicked()), 00232 this, SLOT(slotSaveSize()) ); 00233 00234 // destruct the dialog on OK, close and Cancel 00235 connect( this, SIGNAL(finished()), 00236 this, SLOT(slotFinished()) ); 00237 00238 KConfigGroup geometry( KMKernel::config(), "Geometry"); 00239 const char * configKey 00240 = bPopFilter ? "popFilterDialogSize" : "filterDialogSize"; 00241 if ( geometry.hasKey( configKey ) ) 00242 resize( geometry.readSizeEntry( configKey ) ); 00243 else 00244 adjustSize(); 00245 00246 // load the filter list (emits filterSelected()) 00247 mFilterList->loadFilterList(); 00248 } 00249 00250 void KMFilterDlg::slotFinished() { 00251 delayedDestruct(); 00252 } 00253 00254 void KMFilterDlg::slotSaveSize() { 00255 KConfigGroup geometry( KMKernel::config(), "Geometry" ); 00256 geometry.writeEntry( bPopFilter ? "popFilterDialogSize" : "filterDialogSize", size() ); 00257 } 00258 00260 void KMFilterDlg::slotActionChanged(const KMPopFilterAction aAction) 00261 { 00262 mFilter->setAction(aAction); 00263 } 00264 00265 void KMFilterDlg::slotFilterSelected( KMFilter* aFilter ) 00266 { 00267 assert( aFilter ); 00268 00269 if (bPopFilter){ 00270 mActionGroup->setAction( aFilter->action() ); 00271 mGlobalsBox->setEnabled(true); 00272 mShowLaterBtn->setChecked(mFilterList->showLaterMsgs()); 00273 } else { 00274 mActionLister->setActionList( aFilter->actions() ); 00275 00276 mAdvOptsGroup->setEnabled( true ); 00277 } 00278 00279 mPatternEdit->setSearchPattern( aFilter->pattern() ); 00280 mFilter = aFilter; 00281 00282 if (!bPopFilter) { 00283 kdDebug(5006) << "apply on inbound == " 00284 << aFilter->applyOnInbound() << endl; 00285 kdDebug(5006) << "apply on outbound == " 00286 << aFilter->applyOnOutbound() << endl; 00287 kdDebug(5006) << "apply on explicit == " 00288 << aFilter->applyOnExplicit() << endl; 00289 00290 // NOTE: setting these values activates the slot that sets them in 00291 // the filter! So make sure we have the correct values _before_ we 00292 // set the first one: 00293 const bool applyOnIn = aFilter->applyOnInbound(); 00294 const bool applyOnOut = aFilter->applyOnOutbound(); 00295 const bool applyOnExplicit = aFilter->applyOnExplicit(); 00296 const bool stopHere = aFilter->stopProcessingHere(); 00297 const bool configureShortcut = aFilter->configureShortcut(); 00298 const QString icon = aFilter->icon(); 00299 00300 mApplyOnIn->setChecked( applyOnIn ); 00301 mApplyOnOut->setChecked( applyOnOut ); 00302 mApplyOnCtrlJ->setChecked( applyOnExplicit ); 00303 mStopProcessingHere->setChecked( stopHere ); 00304 mConfigureShortcut->setChecked( configureShortcut ); 00305 mFilterActionIconButton->setIcon( icon ); 00306 } 00307 } 00308 00309 void KMFilterDlg::slotReset() 00310 { 00311 mFilter = 0; 00312 mPatternEdit->reset(); 00313 00314 if(bPopFilter) { 00315 mActionGroup->reset(); 00316 mGlobalsBox->setEnabled( false ); 00317 } else { 00318 mActionLister->reset(); 00319 mAdvOptsGroup->setEnabled( false ); 00320 } 00321 } 00322 00323 void KMFilterDlg::slotApplicabilityChanged() 00324 { 00325 if ( !mFilter ) 00326 return; 00327 00328 mFilter->setApplyOnInbound( mApplyOnIn->isChecked() ); 00329 mFilter->setApplyOnOutbound( mApplyOnOut->isChecked() ); 00330 mFilter->setApplyOnExplicit( mApplyOnCtrlJ->isChecked() ); 00331 kdDebug(5006) << "KMFilterDlg: setting filter to be applied at " 00332 << ( mFilter->applyOnInbound() ? "incoming " : "" ) 00333 << ( mFilter->applyOnOutbound() ? "outgoing " : "" ) 00334 << ( mFilter->applyOnExplicit() ? "explicit CTRL-J" : "" ) 00335 << endl; 00336 } 00337 00338 void KMFilterDlg::slotStopProcessingButtonToggled( bool aChecked ) 00339 { 00340 if ( !mFilter ) 00341 return; 00342 00343 mFilter->setStopProcessingHere( aChecked ); 00344 } 00345 00346 void KMFilterDlg::slotConfigureShortcutButtonToggled( bool aChecked ) 00347 { 00348 if ( !mFilter ) 00349 return; 00350 00351 mFilter->setConfigureShortcut( aChecked ); 00352 mFilterActionIconButton->setEnabled( aChecked ); 00353 mFilterActionLabel->setEnabled( aChecked ); 00354 } 00355 00356 void KMFilterDlg::slotFilterActionIconChanged( QString icon ) 00357 { 00358 if ( !mFilter ) 00359 return; 00360 00361 mFilter->setIcon( icon ); 00362 } 00363 00364 //============================================================================= 00365 // 00366 // class KMFilterListBox (the filter list manipulator) 00367 // 00368 //============================================================================= 00369 00370 KMFilterListBox::KMFilterListBox( const QString & title, QWidget *parent, const char* name, bool popFilter ) 00371 : QGroupBox( 1, Horizontal, title, parent, name ), 00372 bPopFilter(popFilter) 00373 { 00374 mFilterList.setAutoDelete(TRUE); 00375 mIdxSelItem = -1; 00376 00377 //----------- the list box 00378 mListBox = new QListBox(this); 00379 mListBox->setMinimumWidth(150); 00380 QWhatsThis::add( mListBox, i18n(_wt_filterlist) ); 00381 00382 //----------- the first row of buttons 00383 QHBox *hb = new QHBox(this); 00384 hb->setSpacing(4); 00385 mBtnUp = new QPushButton( QString::null, hb ); 00386 mBtnUp->setAutoRepeat( true ); 00387 mBtnUp->setPixmap( BarIcon( "up", KIcon::SizeSmall ) ); 00388 mBtnUp->setMinimumSize( mBtnUp->sizeHint() * 1.2 ); 00389 mBtnDown = new QPushButton( QString::null, hb ); 00390 mBtnDown->setAutoRepeat( true ); 00391 mBtnDown->setPixmap( BarIcon( "down", KIcon::SizeSmall ) ); 00392 mBtnDown->setMinimumSize( mBtnDown->sizeHint() * 1.2 ); 00393 QToolTip::add( mBtnUp, i18n("Up") ); 00394 QToolTip::add( mBtnDown, i18n("Down") ); 00395 QWhatsThis::add( mBtnUp, i18n(_wt_filterlist_up) ); 00396 QWhatsThis::add( mBtnDown, i18n(_wt_filterlist_down) ); 00397 00398 //----------- the second row of buttons 00399 hb = new QHBox(this); 00400 hb->setSpacing(4); 00401 mBtnNew = new QPushButton( QString::null, hb ); 00402 mBtnNew->setPixmap( BarIcon( "filenew", KIcon::SizeSmall ) ); 00403 mBtnNew->setMinimumSize( mBtnNew->sizeHint() * 1.2 ); 00404 mBtnDelete = new QPushButton( QString::null, hb ); 00405 mBtnDelete->setPixmap( BarIcon( "editdelete", KIcon::SizeSmall ) ); 00406 mBtnDelete->setMinimumSize( mBtnDelete->sizeHint() * 1.2 ); 00407 mBtnRename = new QPushButton( i18n("Rename..."), hb ); 00408 QToolTip::add( mBtnNew, i18n("New") ); 00409 QToolTip::add( mBtnDelete, i18n("Delete")); 00410 QWhatsThis::add( mBtnNew, i18n(_wt_filterlist_new) ); 00411 QWhatsThis::add( mBtnDelete, i18n(_wt_filterlist_delete) ); 00412 QWhatsThis::add( mBtnRename, i18n(_wt_filterlist_rename) ); 00413 00414 00415 //----------- now connect everything 00416 connect( mListBox, SIGNAL(highlighted(int)), 00417 this, SLOT(slotSelected(int)) ); 00418 connect( mListBox, SIGNAL( doubleClicked ( QListBoxItem * )), 00419 this, SLOT( slotRename()) ); 00420 connect( mBtnUp, SIGNAL(clicked()), 00421 this, SLOT(slotUp()) ); 00422 connect( mBtnDown, SIGNAL(clicked()), 00423 this, SLOT(slotDown()) ); 00424 connect( mBtnNew, SIGNAL(clicked()), 00425 this, SLOT(slotNew()) ); 00426 connect( mBtnDelete, SIGNAL(clicked()), 00427 this, SLOT(slotDelete()) ); 00428 connect( mBtnRename, SIGNAL(clicked()), 00429 this, SLOT(slotRename()) ); 00430 00431 // the dialog should call loadFilterList() 00432 // when all signals are connected. 00433 enableControls(); 00434 } 00435 00436 00437 void KMFilterListBox::createFilter( const QCString & field, 00438 const QString & value ) 00439 { 00440 KMSearchRule *newRule = KMSearchRule::createInstance( field, KMSearchRule::FuncContains, value ); 00441 00442 KMFilter *newFilter = new KMFilter(0, bPopFilter); 00443 newFilter->pattern()->append( newRule ); 00444 newFilter->pattern()->setName( QString("<%1>:%2").arg( field ).arg( value) ); 00445 00446 KMFilterActionDesc *desc = (*kmkernel->filterActionDict())["transfer"]; 00447 if ( desc ) 00448 newFilter->actions()->append( desc->create() ); 00449 00450 insertFilter( newFilter ); 00451 enableControls(); 00452 } 00453 00454 bool KMFilterListBox::showLaterMsgs() 00455 { 00456 return mShowLater; 00457 } 00458 00459 void KMFilterListBox::slotUpdateFilterName() 00460 { 00461 KMSearchPattern *p = mFilterList.at(mIdxSelItem)->pattern(); 00462 if ( !p ) return; 00463 00464 QString shouldBeName = p->name(); 00465 QString displayedName = mListBox->text( mIdxSelItem ); 00466 00467 if ( shouldBeName.stripWhiteSpace().isEmpty() || shouldBeName[0] == '<' ) { 00468 // auto-naming of patterns 00469 if ( p->first() && !p->first()->field().stripWhiteSpace().isEmpty() ) 00470 shouldBeName = QString( "<%1>:%2" ).arg( p->first()->field() ).arg( p->first()->contents() ); 00471 else 00472 shouldBeName = "<" + i18n("unnamed") + ">"; 00473 p->setName( shouldBeName ); 00474 } 00475 00476 if ( displayedName == shouldBeName ) return; 00477 00478 mListBox->blockSignals(TRUE); 00479 mListBox->changeItem( shouldBeName, mIdxSelItem ); 00480 mListBox->blockSignals(FALSE); 00481 } 00482 00483 void KMFilterListBox::slotShowLaterToggled(bool aOn) 00484 { 00485 mShowLater = aOn; 00486 } 00487 00488 void KMFilterListBox::slotApplyFilterChanges() 00489 { 00490 int oIdxSelItem = mIdxSelItem; 00491 // unselect all filters: 00492 mListBox->selectAll( FALSE ); 00493 // maybe QListBox doesn't emit selected(-1) on unselect, 00494 // so we make sure the edit widgets receive an equivalent: 00495 emit resetWidgets(); 00496 mIdxSelItem = -1; 00497 enableControls(); 00498 00499 // by now all edit widgets should have written back 00500 // their widget's data into our filter list. 00501 00502 KMFilterMgr *fm; 00503 if (bPopFilter) 00504 fm = kmkernel->popFilterMgr(); 00505 else 00506 fm = kmkernel->filterMgr(); 00507 00508 // block attemts to use filters (currently a no-op) 00509 fm->beginUpdate(); 00510 fm->clear(); 00511 00512 QStringList emptyFilters; 00513 QPtrListIterator<KMFilter> it( mFilterList ); 00514 for ( it.toFirst() ; it.current() ; ++it ) { 00515 KMFilter *f = new KMFilter( **it ); // deep copy 00516 f->purify(); 00517 if ( !f->isEmpty() ) 00518 // the filter is valid: 00519 fm->append( f ); 00520 else { 00521 // the filter is invalid: 00522 emptyFilters << f->name(); 00523 delete f; 00524 } 00525 } 00526 if (bPopFilter) 00527 fm->setShowLaterMsgs(mShowLater); 00528 00529 // allow usage of the filters again. 00530 fm->endUpdate(); 00531 fm->writeConfig(); 00532 00533 // report on invalid filters: 00534 if ( !emptyFilters.empty() ) { 00535 QString msg = i18n("The following filters have not been saved because they " 00536 "were invalid (e.g. containing no actions or no search " 00537 "rules)."); 00538 KMessageBox::informationList( 0, msg, emptyFilters, QString::null, 00539 "ShowInvalidFilterWarning" ); 00540 } 00541 00542 if ( oIdxSelItem >= 0 ) { 00543 mIdxSelItem = oIdxSelItem; 00544 mListBox->setSelected( oIdxSelItem, TRUE); 00545 slotSelected( mListBox->currentItem() ); 00546 } 00547 } 00548 00549 void KMFilterListBox::slotSelected( int aIdx ) 00550 { 00551 mIdxSelItem = aIdx; 00552 // QPtrList::at(i) will return 0 if i is out of range. 00553 KMFilter *f = mFilterList.at(aIdx); 00554 if ( f ) 00555 emit filterSelected( f ); 00556 else 00557 emit resetWidgets(); 00558 enableControls(); 00559 } 00560 00561 void KMFilterListBox::slotNew() 00562 { 00563 // just insert a new filter. 00564 insertFilter( new KMFilter(0, bPopFilter) ); 00565 enableControls(); 00566 } 00567 00568 void KMFilterListBox::slotDelete() 00569 { 00570 if ( mIdxSelItem < 0 ) { 00571 kdDebug(5006) << "KMFilterListBox::slotDelete called while no filter is selected, ignoring." << endl; 00572 return; 00573 } 00574 00575 int oIdxSelItem = mIdxSelItem; 00576 mIdxSelItem = -1; 00577 // unselect all 00578 mListBox->selectAll(FALSE); 00579 // broadcast that all widgets let go 00580 // of the filter 00581 emit resetWidgets(); 00582 00583 // remove the filter from both the filter list... 00584 mFilterList.remove( oIdxSelItem ); 00585 // and the listbox 00586 mListBox->removeItem( oIdxSelItem ); 00587 00588 int count = (int)mListBox->count(); 00589 // and set the new current item. 00590 if ( count > oIdxSelItem ) 00591 // oIdxItem is still a valid index 00592 mListBox->setSelected( oIdxSelItem, TRUE ); 00593 else if ( (int)mListBox->count() ) 00594 // oIdxSelIdx is no longer valid, but the 00595 // list box isn't empty 00596 mListBox->setSelected( count - 1, TRUE ); 00597 // the list is empty - keep index -1 00598 00599 enableControls(); 00600 } 00601 00602 void KMFilterListBox::slotUp() 00603 { 00604 if ( mIdxSelItem < 0 ) { 00605 kdDebug(5006) << "KMFilterListBox::slotUp called while no filter is selected, ignoring." << endl; 00606 return; 00607 } 00608 if ( mIdxSelItem == 0 ) { 00609 kdDebug(5006) << "KMFilterListBox::slotUp called while the _topmost_ filter is selected, ignoring." << endl; 00610 return; 00611 } 00612 00613 swapNeighbouringFilters( mIdxSelItem, mIdxSelItem - 1 ); 00614 enableControls(); 00615 } 00616 00617 void KMFilterListBox::slotDown() 00618 { 00619 if ( mIdxSelItem < 0 ) { 00620 kdDebug(5006) << "KMFilterListBox::slotDown called while no filter is selected, ignoring." << endl; 00621 return; 00622 } 00623 if ( mIdxSelItem == (int)mListBox->count() - 1 ) { 00624 kdDebug(5006) << "KMFilterListBox::slotDown called while the _last_ filter is selected, ignoring." << endl; 00625 return; 00626 } 00627 00628 swapNeighbouringFilters( mIdxSelItem, mIdxSelItem + 1); 00629 enableControls(); 00630 } 00631 00632 void KMFilterListBox::slotRename() 00633 { 00634 if ( mIdxSelItem < 0 ) { 00635 kdDebug(5006) << "KMFilterListBox::slotRename called while no filter is selected, ignoring." << endl; 00636 return; 00637 } 00638 00639 bool okPressed = FALSE; 00640 KMFilter *filter = mFilterList.at( mIdxSelItem ); 00641 00642 // enableControls should make sure this method is 00643 // never called when no filter is selected. 00644 assert( filter ); 00645 00646 QString newName = KInputDialog::getText 00647 ( 00648 i18n("Rename Filter"), 00649 i18n("Rename filter \"%1\" to:").arg( filter->pattern()->name() ) /*label*/, 00650 filter->pattern()->name() /* initial value */, 00651 &okPressed, topLevelWidget() 00652 ); 00653 00654 if ( !okPressed ) return; 00655 00656 if ( newName.isEmpty() ) 00657 // bait for slotUpdateFilterName to 00658 // use automatic naming again. 00659 filter->pattern()->setName( "<>" ); 00660 else 00661 filter->pattern()->setName( newName ); 00662 00663 slotUpdateFilterName(); 00664 } 00665 00666 void KMFilterListBox::enableControls() 00667 { 00668 bool theFirst = ( mIdxSelItem == 0 ); 00669 bool theLast = ( mIdxSelItem >= (int)mFilterList.count() - 1 ); 00670 bool aFilterIsSelected = ( mIdxSelItem >= 0 ); 00671 00672 mBtnUp->setEnabled( aFilterIsSelected && !theFirst ); 00673 mBtnDown->setEnabled( aFilterIsSelected && !theLast ); 00674 mBtnDelete->setEnabled( aFilterIsSelected ); 00675 mBtnRename->setEnabled( aFilterIsSelected ); 00676 00677 if ( aFilterIsSelected ) 00678 mListBox->ensureCurrentVisible(); 00679 } 00680 00681 void KMFilterListBox::loadFilterList() 00682 { 00683 assert(mListBox); 00684 setEnabled(FALSE); 00685 // we don't want the insertion to 00686 // cause flicker in the edit widgets. 00687 blockSignals(TRUE); 00688 00689 // clear both lists 00690 mFilterList.clear(); 00691 mListBox->clear(); 00692 00693 QPtrList<KMFilter> *manager; 00694 if(bPopFilter) 00695 { 00696 mShowLater = kmkernel->popFilterMgr()->showLaterMsgs(); 00697 manager = kmkernel->popFilterMgr(); 00698 } 00699 else 00700 { 00701 manager = kmkernel->filterMgr(); 00702 } 00703 00704 QPtrListIterator<KMFilter> it( *manager ); 00705 for ( it.toFirst() ; it.current() ; ++it ) { 00706 mFilterList.append( new KMFilter( **it ) ); // deep copy 00707 mListBox->insertItem( (*it)->pattern()->name() ); 00708 } 00709 00710 blockSignals(FALSE); 00711 setEnabled(TRUE); 00712 00713 // select topmost item 00714 if ( mListBox->count() ) 00715 { 00716 mListBox->setSelected( 0, TRUE ); 00717 } 00718 else 00719 { 00720 emit resetWidgets(); 00721 mIdxSelItem = -1; 00722 } 00723 00724 enableControls(); 00725 } 00726 00727 void KMFilterListBox::insertFilter( KMFilter* aFilter ) 00728 { 00729 // must be really a filter... 00730 assert( aFilter ); 00731 00732 // if mIdxSelItem < 0, QListBox::insertItem will append. 00733 mListBox->insertItem( aFilter->pattern()->name(), mIdxSelItem ); 00734 if ( mIdxSelItem < 0 ) { 00735 // none selected -> append 00736 mFilterList.append( aFilter ); 00737 mListBox->setSelected( mListBox->count() - 1, TRUE ); 00738 // slotSelected( mListBox->count() - 1 ); 00739 } else { 00740 // insert just before selected 00741 mFilterList.insert( mIdxSelItem, aFilter ); 00742 mListBox->setSelected( mIdxSelItem, TRUE ); 00743 // slotSelected( mIdxSelItem ); 00744 } 00745 00746 } 00747 00748 void KMFilterListBox::swapNeighbouringFilters( int untouchedOne, int movedOne ) 00749 { 00750 // must be neighbours... 00751 assert( untouchedOne - movedOne == 1 || movedOne - untouchedOne == 1 ); 00752 00753 // untouchedOne is at idx. to move it down(up), 00754 // remove item at idx+(-)1 w/o deleting it. 00755 QListBoxItem *item = mListBox->item( movedOne ); 00756 mListBox->takeItem( item ); 00757 // now selected item is at idx(idx-1), so 00758 // insert the other item at idx, ie. above(below). 00759 mListBox->insertItem( item, untouchedOne ); 00760 00761 KMFilter* filter = mFilterList.take( movedOne ); 00762 mFilterList.insert( untouchedOne, filter ); 00763 00764 mIdxSelItem += movedOne - untouchedOne; 00765 } 00766 00767 00768 //============================================================================= 00769 // 00770 // class KMFilterActionWidget 00771 // 00772 //============================================================================= 00773 00774 KMFilterActionWidget::KMFilterActionWidget( QWidget *parent, const char* name ) 00775 : QHBox( parent, name ) 00776 { 00777 int i; 00778 mActionList.setAutoDelete(TRUE); 00779 00780 mComboBox = new QComboBox( FALSE, this ); 00781 assert( mComboBox ); 00782 mWidgetStack = new QWidgetStack(this); 00783 assert( mWidgetStack ); 00784 00785 setSpacing( 4 ); 00786 00787 QPtrListIterator<KMFilterActionDesc> it ( kmkernel->filterActionDict()->list() ); 00788 for ( i=0, it.toFirst() ; it.current() ; ++it, ++i ) { 00789 //create an instance: 00790 KMFilterAction *a = (*it)->create(); 00791 // append to the list of actions: 00792 mActionList.append( a ); 00793 // add parameter widget to widget stack: 00794 mWidgetStack->addWidget( a->createParamWidget( mWidgetStack ), i ); 00795 // add (i18n-ized) name to combo box 00796 mComboBox->insertItem( (*it)->label ); 00797 } 00798 // widget for the case where no action is selected. 00799 mWidgetStack->addWidget( new QLabel( i18n("Please select an action."), mWidgetStack ), i ); 00800 mWidgetStack->raiseWidget(i); 00801 mComboBox->insertItem( " " ); 00802 mComboBox->setCurrentItem(i); 00803 00804 // don't show scroll bars. 00805 mComboBox->setSizeLimit( mComboBox->count() ); 00806 // layout management: 00807 // o the combo box is not to be made larger than it's sizeHint(), 00808 // the parameter widget should grow instead. 00809 // o the whole widget takes all space horizontally, but is fixed vertically. 00810 mComboBox->adjustSize(); 00811 mComboBox->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); 00812 setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); 00813 updateGeometry(); 00814 00815 // now connect the combo box and the widget stack 00816 connect( mComboBox, SIGNAL(activated(int)), 00817 mWidgetStack, SLOT(raiseWidget(int)) ); 00818 } 00819 00820 void KMFilterActionWidget::setAction( const KMFilterAction* aAction ) 00821 { 00822 int i=0; 00823 bool found = FALSE; 00824 int count = mComboBox->count() - 1 ; // last entry is the empty one 00825 QString label = ( aAction ) ? aAction->label() : QString::null ; 00826 00827 // find the index of typeOf(aAction) in mComboBox 00828 // and clear the other widgets on the way. 00829 for ( ; i < count ; i++ ) 00830 if ( aAction && mComboBox->text(i) == label ) { 00831 //...set the parameter widget to the settings 00832 // of aAction... 00833 aAction->setParamWidgetValue( mWidgetStack->widget(i) ); 00834 //...and show the correct entry of 00835 // the combo box 00836 mComboBox->setCurrentItem(i); // (mm) also raise the widget, but doesn't 00837 mWidgetStack->raiseWidget(i); 00838 found = TRUE; 00839 } else // clear the parameter widget 00840 mActionList.at(i)->clearParamWidget( mWidgetStack->widget(i) ); 00841 if ( found ) return; 00842 00843 // not found, so set the empty widget 00844 mComboBox->setCurrentItem( count ); // last item 00845 mWidgetStack->raiseWidget( count) ; 00846 } 00847 00848 KMFilterAction * KMFilterActionWidget::action() 00849 { 00850 // look up the action description via the label 00851 // returned by QComboBox::currentText()... 00852 KMFilterActionDesc *desc = (*kmkernel->filterActionDict())[ mComboBox->currentText() ]; 00853 if ( desc ) { 00854 // ...create an instance... 00855 KMFilterAction *fa = desc->create(); 00856 if ( fa ) { 00857 // ...and apply the setting of the parameter widget. 00858 fa->applyParamWidgetValue( mWidgetStack->visibleWidget() ); 00859 return fa; 00860 } 00861 } 00862 00863 return 0; 00864 } 00865 00866 //============================================================================= 00867 // 00868 // class KMFilterActionWidgetLister (the filter action editor) 00869 // 00870 //============================================================================= 00871 00872 KMFilterActionWidgetLister::KMFilterActionWidgetLister( QWidget *parent, const char* name ) 00873 : KWidgetLister( 1, FILTER_MAX_ACTIONS, parent, name ) 00874 { 00875 mActionList = 0; 00876 } 00877 00878 KMFilterActionWidgetLister::~KMFilterActionWidgetLister() 00879 { 00880 } 00881 00882 void KMFilterActionWidgetLister::setActionList( QPtrList<KMFilterAction> *aList ) 00883 { 00884 assert ( aList ); 00885 00886 if ( mActionList ) 00887 regenerateActionListFromWidgets(); 00888 00889 mActionList = aList; 00890 00891 ((QWidget*)parent())->setEnabled( TRUE ); 00892 00893 if ( aList->count() == 0 ) { 00894 slotClear(); 00895 return; 00896 } 00897 00898 int superfluousItems = (int)mActionList->count() - mMaxWidgets ; 00899 if ( superfluousItems > 0 ) { 00900 kdDebug(5006) << "KMFilterActionWidgetLister: Clipping action list to " 00901 << mMaxWidgets << " items!" << endl; 00902 00903 for ( ; superfluousItems ; superfluousItems-- ) 00904 mActionList->removeLast(); 00905 } 00906 00907 // set the right number of widgets 00908 setNumberOfShownWidgetsTo( mActionList->count() ); 00909 00910 // load the actions into the widgets 00911 QPtrListIterator<KMFilterAction> aIt( *mActionList ); 00912 QPtrListIterator<QWidget> wIt( mWidgetList ); 00913 for ( aIt.toFirst(), wIt.toFirst() ; 00914 aIt.current() && wIt.current() ; ++aIt, ++wIt ) 00915 ((KMFilterActionWidget*)(*wIt))->setAction( (*aIt) ); 00916 } 00917 00918 void KMFilterActionWidgetLister::reset() 00919 { 00920 if ( mActionList ) 00921 regenerateActionListFromWidgets(); 00922 00923 mActionList = 0; 00924 slotClear(); 00925 ((QWidget*)parent())->setEnabled( FALSE ); 00926 } 00927 00928 QWidget* KMFilterActionWidgetLister::createWidget( QWidget *parent ) 00929 { 00930 return new KMFilterActionWidget(parent); 00931 } 00932 00933 void KMFilterActionWidgetLister::clearWidget( QWidget *aWidget ) 00934 { 00935 if ( aWidget ) 00936 ((KMFilterActionWidget*)aWidget)->setAction(0); 00937 } 00938 00939 void KMFilterActionWidgetLister::regenerateActionListFromWidgets() 00940 { 00941 if ( !mActionList ) return; 00942 00943 mActionList->clear(); 00944 00945 QPtrListIterator<QWidget> it( mWidgetList ); 00946 for ( it.toFirst() ; it.current() ; ++it ) { 00947 KMFilterAction *a = ((KMFilterActionWidget*)(*it))->action(); 00948 if ( a ) 00949 mActionList->append( a ); 00950 } 00951 00952 } 00953 00954 //============================================================================= 00955 // 00956 // class KMPopFilterActionWidget 00957 // 00958 //============================================================================= 00959 00960 KMPopFilterActionWidget::KMPopFilterActionWidget( const QString& title, QWidget *parent, const char* name ) 00961 : QVButtonGroup( title, parent, name ) 00962 { 00963 mActionMap[Down] = new QRadioButton( i18n("&Download mail"), this ); 00964 mActionMap[Later] = new QRadioButton( i18n("Download mail la&ter"), this ); 00965 mActionMap[Delete] = new QRadioButton( i18n("D&elete mail from server"), this ); 00966 mIdMap[id(mActionMap[Later])] = Later; 00967 mIdMap[id(mActionMap[Down])] = Down; 00968 mIdMap[id(mActionMap[Delete])] = Delete; 00969 00970 connect( this, SIGNAL(clicked(int)), 00971 this, SLOT( slotActionClicked(int)) ); 00972 } 00973 00974 void KMPopFilterActionWidget::setAction( KMPopFilterAction aAction ) 00975 { 00976 if( aAction == NoAction) 00977 { 00978 aAction = Later; 00979 } 00980 00981 mAction = aAction; 00982 00983 blockSignals( true ); 00984 if(!mActionMap[aAction]->isChecked()) 00985 { 00986 mActionMap[aAction]->setChecked(true); 00987 } 00988 blockSignals( false ); 00989 00990 setEnabled(true); 00991 } 00992 00993 KMPopFilterAction KMPopFilterActionWidget::action() 00994 { 00995 return mAction; 00996 } 00997 00998 void KMPopFilterActionWidget::slotActionClicked(int aId) 00999 { 01000 emit actionChanged(mIdMap[aId]); 01001 setAction(mIdMap[aId]); 01002 } 01003 01004 void KMPopFilterActionWidget::reset() 01005 { 01006 blockSignals(TRUE); 01007 mActionMap[Down]->setChecked( TRUE ); 01008 blockSignals(FALSE); 01009 01010 setEnabled( FALSE ); 01011 } 01012 01013 #include "kmfilterdlg.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 23:58:00 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003