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