kmail

kmfilterdlg.cpp
1 // -*- mode: C++; c-file-style: "gnu" -*-
2 // kmfilterdlg.cpp
3 // Author: Marc Mutz <Marc@Mutz.com>
4 // based on work by Stefan Taferner <taferner@kde.org>
5 // This code is under the GPL
6 
7 #include <config.h>
8 #include "kmfilterdlg.h"
9 
10 // other KMail headers:
11 #include "kmsearchpatternedit.h"
12 #include "kmfiltermgr.h"
13 #include "kmmainwidget.h"
14 #include "accountmanager.h"
16 #include "filterimporterexporter.h"
18 #include "foldersetselector.h"
19 #include "globalsettings.h"
20 
21 // other KDE headers:
22 #include <tdemessagebox.h>
23 #include <kdebug.h>
24 #include <tdelocale.h>
25 #include <kinputdialog.h>
26 #include <kiconloader.h>
27 #include <tdeapplication.h>
28 #include <twin.h>
29 #include <tdeconfig.h>
30 #include <kicondialog.h>
31 #include <kkeybutton.h>
32 #include <tdelistview.h>
33 #include <kpushbutton.h>
34 
35 // other TQt headers:
36 #include <tqlayout.h>
37 #include <tqlabel.h>
38 #include <tqcombobox.h>
39 #include <tqwidgetstack.h>
40 #include <tqtooltip.h>
41 #include <tqwhatsthis.h>
42 #include <tqcheckbox.h>
43 #include <tqhbox.h>
44 #include <tqvalidator.h>
45 #include <tqtabwidget.h>
46 
47 // other headers:
48 #include <assert.h>
49 
50 using namespace KMail;
51 
52 
53 // What's this help texts
54 const char * _wt_filterlist =
55 I18N_NOOP( "<qt><p>This is the list of defined filters. "
56  "They are processed top-to-bottom.</p>"
57  "<p>Click on any filter to edit it "
58  "using the controls in the right-hand half "
59  "of the dialog.</p></qt>" );
60 const char * _wt_filterlist_new =
61 I18N_NOOP( "<qt><p>Click this button to create a new filter.</p>"
62  "<p>The filter will be inserted just before the currently-"
63  "selected one, but you can always change that "
64  "later on.</p>"
65  "<p>If you have clicked this button accidentally, you can undo this "
66  "by clicking on the <em>Delete</em> button.</p></qt>" );
67 const char * _wt_filterlist_copy =
68 I18N_NOOP( "<qt><p>Click this button to copy a filter.</p>"
69  "<p>If you have clicked this button accidentally, you can undo this "
70  "by clicking on the <em>Delete</em> button.</p></qt>" );
71 const char * _wt_filterlist_delete =
72 I18N_NOOP( "<qt><p>Click this button to <em>delete</em> the currently-"
73  "selected filter from the list above.</p>"
74  "<p>There is no way to get the filter back once "
75  "it is deleted, but you can always leave the "
76  "dialog by clicking <em>Cancel</em> to discard the "
77  "changes made.</p></qt>" );
78 const char * _wt_filterlist_top =
79 I18N_NOOP( "<qt><p>Click this button to move the currently-"
80  "selected filter to the <em>top</em> of the list above.</p>"
81  "<p>This is useful since the order of the filters in the list "
82  "determines the order in which they are tried on messages: "
83  "The topmost filter gets tried first.</p></qt>" );
84 const char * _wt_filterlist_up =
85 I18N_NOOP( "<qt><p>Click this button to move the currently-"
86  "selected filter <em>up</em> one in the list above.</p>"
87  "<p>This is useful since the order of the filters in the list "
88  "determines the order in which they are tried on messages: "
89  "The topmost filter gets tried first.</p>"
90  "<p>If you have clicked this button accidentally, you can undo this "
91  "by clicking on the <em>Down</em> button.</p></qt>" );
92 const char * _wt_filterlist_down =
93 I18N_NOOP( "<qt><p>Click this button to move the currently-"
94  "selected filter <em>down</em> one in the list above.</p>"
95  "<p>This is useful since the order of the filters in the list "
96  "determines the order in which they are tried on messages: "
97  "The topmost filter gets tried first.</p>"
98  "<p>If you have clicked this button accidentally, you can undo this "
99  "by clicking on the <em>Up</em> button.</p></qt>" );
100 const char * _wt_filterlist_bot =
101 I18N_NOOP( "<qt><p>Click this button to move the currently-"
102  "selected filter to the <em>bottom</em> of the list above.</p>"
103  "<p>This is useful since the order of the filters in the list "
104  "determines the order in which they are tried on messages: "
105  "The topmost filter gets tried first.</p></qt>" );
106 const char * _wt_filterlist_rename =
107 I18N_NOOP( "<qt><p>Click this button to rename the currently-selected filter.</p>"
108  "<p>Filters are named automatically, as long as they start with "
109  "\"&lt;\".</p>"
110  "<p>If you have renamed a filter accidentally and want automatic "
111  "naming back, click this button and select <em>Clear</em> followed "
112  "by <em>OK</em> in the appearing dialog.</p></qt>" );
113 const char * _wt_filterdlg_showLater =
114 I18N_NOOP( "<qt><p>Check this button to force the confirmation dialog to be "
115  "displayed.</p><p>This is useful if you have defined a ruleset that tags "
116  "messages to be downloaded later. Without the possibility to force "
117  "the dialog popup, these messages could never be downloaded if no "
118  "other large messages were waiting on the server, or if you wanted to "
119  "change the ruleset to tag the messages differently.</p></qt>" );
120 
121 // The anchor of the filter dialog's help.
122 const char * KMFilterDlgHelpAnchor = "filters-id" ;
123 const char * KMPopFilterDlgHelpAnchor = "popfilters-id" ;
124 
125 //=============================================================================
126 //
127 // class KMFilterDlg (the filter dialog)
128 //
129 //=============================================================================
130 
131 KMFilterDlg::KMFilterDlg(TQWidget* parent, const char* name, bool popFilter, bool createDummyFilter )
132  : KDialogBase( parent, name, false /* modality */,
133  (popFilter)? i18n("POP3 Filter Rules"): i18n("Filter Rules") /* caption*/,
134  Help|Ok|Apply|Cancel|User1|User2 /* button mask */,
135  Ok /* default btn */, false /* separator */),
136  bPopFilter(popFilter)
137 {
138  KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() );
139  setHelp( (bPopFilter)? KMPopFilterDlgHelpAnchor: KMFilterDlgHelpAnchor );
140  setButtonText( User1, i18n("Import") );
141  setButtonText( User2, i18n("Export") );
142  connect( this, TQT_SIGNAL(user1Clicked()),
143  this, TQT_SLOT( slotImportFilters()) );
144  connect( this, TQT_SIGNAL(user2Clicked()),
145  this, TQT_SLOT( slotExportFilters()) );
146 
147  TQWidget *w = new TQWidget( this );
148  setMainWidget( w );
149  TQHBoxLayout *topLayout = new TQHBoxLayout( w, 0, spacingHint(), "topLayout" );
150  TQHBoxLayout *hbl = topLayout;
151  TQVBoxLayout *vbl2 = 0;
152  TQWidget *page1 = 0;
153  TQWidget *page2 = 0;
154 
155  mFilterList = new KMFilterListBox( i18n("Available Filters"), w, 0, bPopFilter);
156  topLayout->addWidget( mFilterList, 1 /*stretch*/ );
157 
158  if(!bPopFilter) {
159  TQTabWidget *tabWidget = new TQTabWidget( w, "kmfd_tab" );
160  tabWidget->setMargin( KDialog::marginHint() );
161  topLayout->addWidget( tabWidget );
162 
163  page1 = new TQWidget( tabWidget );
164  tabWidget->addTab( page1, i18n("&General") );
165  hbl = new TQHBoxLayout( page1, 0, spacingHint(), "kmfd_hbl" );
166 
167  page2 = new TQWidget( tabWidget );
168  tabWidget->addTab( page2, i18n("A&dvanced") );
169  vbl2 = new TQVBoxLayout( page2, 0, spacingHint(), "kmfd_vbl2" );
170  }
171 
172  TQVBoxLayout *vbl = new TQVBoxLayout( hbl, spacingHint(), "kmfd_vbl" );
173  hbl->setStretchFactor( vbl, 2 );
174 
175  mPatternEdit = new KMSearchPatternEdit( i18n("Filter Criteria"), bPopFilter ? w : page1 , "spe", bPopFilter);
176  vbl->addWidget( mPatternEdit, 0, TQt::AlignTop );
177 
178  if(bPopFilter){
179  mActionGroup = new KMPopFilterActionWidget( i18n("Filter Action"), w );
180  vbl->addWidget( mActionGroup, 0, TQt::AlignTop );
181 
182  mGlobalsBox = new TQVGroupBox(i18n("Global Options"), w);
183  mShowLaterBtn = new TQCheckBox(i18n("Always &show matched 'Download Later' messages in confirmation dialog"), mGlobalsBox);
184  TQWhatsThis::add( mShowLaterBtn, i18n(_wt_filterdlg_showLater) );
185  vbl->addWidget( mGlobalsBox, 0, TQt::AlignTop );
186  }
187  else {
188  TQGroupBox *agb = new TQGroupBox( 1 /*column*/, Qt::Vertical, i18n("Filter Actions"), page1 );
189  mActionLister = new KMFilterActionWidgetLister( agb );
190  vbl->addWidget( agb, 0, TQt::AlignTop );
191 
192  mAdvOptsGroup = new TQGroupBox ( 1 /*columns*/, Qt::Vertical,
193  i18n("Advanced Options"), page2);
194  {
195  TQWidget *adv_w = new TQWidget( mAdvOptsGroup );
196  TQGridLayout *gl = new TQGridLayout( adv_w, 8 /*rows*/, 3 /*cols*/,
197  0 /*border*/, spacingHint() );
198 
199  TQVBoxLayout *vbl3 = new TQVBoxLayout( gl, spacingHint(), "vbl3" );
200  vbl3->addStretch( 1 );
201  mApplyOnIn = new TQCheckBox( i18n("Apply this filter to incoming messages:"), adv_w );
202  vbl3->addWidget( mApplyOnIn );
203  TQButtonGroup *bg = new TQButtonGroup( 0, "bg" );
204  bg->setExclusive( true );
205  mApplyOnForAll = new TQRadioButton( i18n("from all accounts"), adv_w );
206  bg->insert( mApplyOnForAll );
207  vbl3->addWidget( mApplyOnForAll );
208  mApplyOnForTraditional = new TQRadioButton( i18n("from all but online IMAP accounts"), adv_w );
209  bg->insert( mApplyOnForTraditional );
210  vbl3->addWidget( mApplyOnForTraditional );
211  mApplyOnForChecked = new TQRadioButton( i18n("from checked accounts only"), adv_w );
212  bg->insert( mApplyOnForChecked );
213  vbl3->addWidget( mApplyOnForChecked );
214  vbl3->addStretch( 2 );
215 
216  mAccountList = new TDEListView( adv_w, "accountList" );
217  mAccountList->addColumn( i18n("Account Name") );
218  mAccountList->addColumn( i18n("Type") );
219  mAccountList->setAllColumnsShowFocus( true );
220  mAccountList->setFrameStyle( TQFrame::WinPanel + TQFrame::Sunken );
221  mAccountList->setSorting( -1 );
222  gl->addMultiCellWidget( mAccountList, 0, 3, 1, 3 );
223 
224  mApplyOnOut = new TQCheckBox( i18n("Apply this filter to &sent messages"), adv_w );
225  gl->addMultiCellWidget( mApplyOnOut, 4, 4, 0, 3 );
226 
227  mApplyOnCtrlJ = new TQCheckBox( i18n("Apply this filter on manual &filtering"), adv_w );
228  gl->addMultiCellWidget( mApplyOnCtrlJ, 5, 5, 0, 3 );
229 
230  mStopProcessingHere = new TQCheckBox( i18n("If this filter &matches, stop processing here"), adv_w );
231  gl->addMultiCellWidget( mStopProcessingHere,
232  6, 6, /*from to row*/
233  0, 3 /*from to col*/ );
234  mConfigureShortcut = new TQCheckBox( i18n("Add this filter to the Apply Filter menu"), adv_w );
235  gl->addMultiCellWidget( mConfigureShortcut, 7, 7, 0, 1 );
236  TQLabel *keyButtonLabel = new TQLabel( i18n( "Shortcut:" ), adv_w );
237  keyButtonLabel->setAlignment( AlignVCenter | AlignRight );
238  gl->addMultiCellWidget( keyButtonLabel, 7, 7, 2, 2 );
239  mKeyButton = new KKeyButton( adv_w, "FilterShortcutSelector" );
240  gl->addMultiCellWidget( mKeyButton, 7, 7, 3, 3 );
241  mKeyButton->setEnabled( false );
242  mConfigureToolbar = new TQCheckBox( i18n("Additionally add this filter to the toolbar"), adv_w );
243  gl->addMultiCellWidget( mConfigureToolbar, 8, 8, 0, 3 );
244  mConfigureToolbar->setEnabled( false );
245 
246  TQHBox *hbox = new TQHBox( adv_w );
247  mFilterActionLabel = new TQLabel( i18n( "Icon for this filter:" ),
248  hbox );
249  mFilterActionLabel->setEnabled( false );
250 
251  mFilterActionIconButton = new TDEIconButton( hbox );
252  mFilterActionLabel->setBuddy( mFilterActionIconButton );
253  mFilterActionIconButton->setIconType( TDEIcon::NoGroup, TDEIcon::Any, true );
254  mFilterActionIconButton->setIconSize( 16 );
255  mFilterActionIconButton->setIcon( "gear" );
256  mFilterActionIconButton->setEnabled( false );
257 
258  gl->addMultiCellWidget( hbox, 9, 9, 0, 3 );
259  }
260  vbl2->addWidget( mAdvOptsGroup, 0, TQt::AlignTop );
261  }
262  // spacer:
263  vbl->addStretch( 1 );
264 
265  // load the filter parts into the edit widgets
266  connect( mFilterList, TQT_SIGNAL(filterSelected(KMFilter*)),
267  this, TQT_SLOT(slotFilterSelected(KMFilter*)) );
268 
269  if (bPopFilter){
270  // set the state of the global setting 'show later msgs'
271  connect( mShowLaterBtn, TQT_SIGNAL(toggled(bool)),
272  mFilterList, TQT_SLOT(slotShowLaterToggled(bool)));
273 
274  // set the action in the filter when changed
275  connect( mActionGroup, TQT_SIGNAL(actionChanged(const KMPopFilterAction)),
276  this, TQT_SLOT(slotActionChanged(const KMPopFilterAction)) );
277  } else {
278  // transfer changes from the 'Apply this filter on...'
279  // combo box to the filter
280  connect( mApplyOnIn, TQT_SIGNAL(clicked()),
281  this, TQT_SLOT(slotApplicabilityChanged()) );
282  connect( mApplyOnForAll, TQT_SIGNAL(clicked()),
283  this, TQT_SLOT(slotApplicabilityChanged()) );
284  connect( mApplyOnForTraditional, TQT_SIGNAL(clicked()),
285  this, TQT_SLOT(slotApplicabilityChanged()) );
286  connect( mApplyOnForChecked, TQT_SIGNAL(clicked()),
287  this, TQT_SLOT(slotApplicabilityChanged()) );
288  connect( mApplyOnOut, TQT_SIGNAL(clicked()),
289  this, TQT_SLOT(slotApplicabilityChanged()) );
290  connect( mApplyOnCtrlJ, TQT_SIGNAL(clicked()),
291  this, TQT_SLOT(slotApplicabilityChanged()) );
292  connect( mAccountList, TQT_SIGNAL(clicked(TQListViewItem*)),
293  this, TQT_SLOT(slotApplicableAccountsChanged()) );
294  connect( mAccountList, TQT_SIGNAL(spacePressed(TQListViewItem*)),
295  this, TQT_SLOT(slotApplicableAccountsChanged()) );
296 
297  // transfer changes from the 'stop processing here'
298  // check box to the filter
299  connect( mStopProcessingHere, TQT_SIGNAL(toggled(bool)),
300  this, TQT_SLOT(slotStopProcessingButtonToggled(bool)) );
301 
302  connect( mConfigureShortcut, TQT_SIGNAL(toggled(bool)),
303  this, TQT_SLOT(slotConfigureShortcutButtonToggled(bool)) );
304 
305  connect( mKeyButton, TQT_SIGNAL( capturedShortcut( const TDEShortcut& ) ),
306  this, TQT_SLOT( slotCapturedShortcutChanged( const TDEShortcut& ) ) );
307 
308  connect( mConfigureToolbar, TQT_SIGNAL(toggled(bool)),
309  this, TQT_SLOT(slotConfigureToolbarButtonToggled(bool)) );
310 
311  connect( mFilterActionIconButton, TQT_SIGNAL( iconChanged( TQString ) ),
312  this, TQT_SLOT( slotFilterActionIconChanged( TQString ) ) );
313  }
314 
315  // reset all widgets here
316  connect( mFilterList, TQT_SIGNAL(resetWidgets()),
317  this, TQT_SLOT(slotReset()) );
318 
319  connect( mFilterList, TQT_SIGNAL( applyWidgets() ),
320  this, TQT_SLOT( slotUpdateFilter() ) );
321 
322  // support auto-naming the filter
323  connect( mPatternEdit, TQT_SIGNAL(maybeNameChanged()),
324  mFilterList, TQT_SLOT(slotUpdateFilterName()) );
325 
326  // apply changes on 'Apply'
327  connect( this, TQT_SIGNAL(applyClicked()),
328  mFilterList, TQT_SLOT(slotApplyFilterChanges()) );
329 
330  // apply changes on 'OK'
331  connect( this, TQT_SIGNAL(okClicked()),
332  mFilterList, TQT_SLOT(slotApplyFilterChanges()) );
333 
334  // save dialog size on 'OK'
335  connect( this, TQT_SIGNAL(okClicked()),
336  this, TQT_SLOT(slotSaveSize()) );
337 
338  // destruct the dialog on OK, close and Cancel
339  connect( this, TQT_SIGNAL(finished()),
340  this, TQT_SLOT(slotFinished()) );
341 
342  TDEConfigGroup geometry( KMKernel::config(), "Geometry");
343  const char * configKey
344  = bPopFilter ? "popFilterDialogSize" : "filterDialogSize";
345  if ( geometry.hasKey( configKey ) )
346  resize( geometry.readSizeEntry( configKey ) );
347  else
348  adjustSize();
349 
350  // load the filter list (emits filterSelected())
351  mFilterList->loadFilterList( createDummyFilter );
352 }
353 
354 void KMFilterDlg::slotFinished() {
355  delayedDestruct();
356 }
357 
358 void KMFilterDlg::slotSaveSize() {
359  TDEConfigGroup geometry( KMKernel::config(), "Geometry" );
360  geometry.writeEntry( bPopFilter ? "popFilterDialogSize" : "filterDialogSize", size() );
361 }
362 
364 void KMFilterDlg::slotActionChanged(const KMPopFilterAction aAction)
365 {
366  mFilter->setAction(aAction);
367 }
368 
369 void KMFilterDlg::slotFilterSelected( KMFilter* aFilter )
370 {
371  assert( aFilter );
372 
373  if (bPopFilter){
374  mActionGroup->setAction( aFilter->action() );
375  mGlobalsBox->setEnabled( true );
376  mShowLaterBtn->setChecked(mFilterList->showLaterMsgs());
377  } else {
378  mActionLister->setActionList( aFilter->actions() );
379 
380  mAdvOptsGroup->setEnabled( true );
381  }
382 
383  mPatternEdit->setSearchPattern( aFilter->pattern() );
384  mFilter = aFilter;
385 
386  if (!bPopFilter) {
387  kdDebug(5006) << "apply on inbound == "
388  << aFilter->applyOnInbound() << endl;
389  kdDebug(5006) << "apply on outbound == "
390  << aFilter->applyOnOutbound() << endl;
391  kdDebug(5006) << "apply on explicit == "
392  << aFilter->applyOnExplicit() << endl;
393 
394  // NOTE: setting these values activates the slot that sets them in
395  // the filter! So make sure we have the correct values _before_ we
396  // set the first one:
397  const bool applyOnIn = aFilter->applyOnInbound();
398  const bool applyOnForAll = aFilter->applicability() == KMFilter::All;
399  const bool applyOnTraditional = aFilter->applicability() == KMFilter::ButImap;
400  const bool applyOnOut = aFilter->applyOnOutbound();
401  const bool applyOnExplicit = aFilter->applyOnExplicit();
402  const bool stopHere = aFilter->stopProcessingHere();
403  const bool configureShortcut = aFilter->configureShortcut();
404  const bool configureToolbar = aFilter->configureToolbar();
405  const TQString icon = aFilter->icon();
406  const TDEShortcut shortcut( aFilter->shortcut() );
407 
408  mApplyOnIn->setChecked( applyOnIn );
409  mApplyOnForAll->setEnabled( applyOnIn );
410  mApplyOnForTraditional->setEnabled( applyOnIn );
411  mApplyOnForChecked->setEnabled( applyOnIn );
412  mApplyOnForAll->setChecked( applyOnForAll );
413  mApplyOnForTraditional->setChecked( applyOnTraditional );
414  mApplyOnForChecked->setChecked( !applyOnForAll && !applyOnTraditional );
415  mAccountList->setEnabled( mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked() );
416  slotUpdateAccountList();
417  mApplyOnOut->setChecked( applyOnOut );
418  mApplyOnCtrlJ->setChecked( applyOnExplicit );
419  mStopProcessingHere->setChecked( stopHere );
420  mConfigureShortcut->setChecked( configureShortcut );
421  mKeyButton->setShortcut( shortcut, false );
422  mConfigureToolbar->setChecked( configureToolbar );
423  mFilterActionIconButton->setIcon( icon );
424  }
425 }
426 
427 void KMFilterDlg::slotReset()
428 {
429  mFilter = 0;
430  mPatternEdit->reset();
431 
432  if(bPopFilter) {
433  mActionGroup->reset();
434  mGlobalsBox->setEnabled( false );
435  } else {
436  mActionLister->reset();
437  mAdvOptsGroup->setEnabled( false );
438  slotUpdateAccountList();
439  }
440 }
441 
442 void KMFilterDlg::slotUpdateFilter()
443 {
445  if ( !bPopFilter ) {
446  mActionLister->updateActionList();
447  }
448 }
449 
450 void KMFilterDlg::slotApplicabilityChanged()
451 {
452  if ( mFilter ) {
453  mFilter->setApplyOnInbound( mApplyOnIn->isChecked() );
454  mFilter->setApplyOnOutbound( mApplyOnOut->isChecked() );
455  mFilter->setApplyOnExplicit( mApplyOnCtrlJ->isChecked() );
456  if ( mApplyOnForAll->isChecked() )
457  mFilter->setApplicability( KMFilter::All );
458  else if ( mApplyOnForTraditional->isChecked() )
459  mFilter->setApplicability( KMFilter::ButImap );
460  else if ( mApplyOnForChecked->isChecked() )
461  mFilter->setApplicability( KMFilter::Checked );
462 
463  mApplyOnForAll->setEnabled( mApplyOnIn->isChecked() );
464  mApplyOnForTraditional->setEnabled( mApplyOnIn->isChecked() );
465  mApplyOnForChecked->setEnabled( mApplyOnIn->isChecked() );
466  mAccountList->setEnabled( mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked() );
467 
468  // Advanced tab functionality - Update list of accounts this filter applies to
469  TQListViewItemIterator it( mAccountList );
470  while ( it.current() ) {
471  TQCheckListItem *item = dynamic_cast<TQCheckListItem*>( it.current() );
472  if (item) {
473  int id = item->text( 2 ).toInt();
474  item->setOn( mFilter->applyOnAccount( id ) );
475  }
476  ++it;
477  }
478 
479  kdDebug(5006) << "KMFilterDlg: setting filter to be applied at "
480  << ( mFilter->applyOnInbound() ? "incoming " : "" )
481  << ( mFilter->applyOnOutbound() ? "outgoing " : "" )
482  << ( mFilter->applyOnExplicit() ? "explicit CTRL-J" : "" )
483  << endl;
484  }
485 }
486 
487 void KMFilterDlg::slotApplicableAccountsChanged()
488 {
489  if ( mFilter && mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked() ) {
490  // Advanced tab functionality - Update list of accounts this filter applies to
491  TQListViewItemIterator it( mAccountList );
492  while ( it.current() ) {
493  TQCheckListItem *item = dynamic_cast<TQCheckListItem*>( it.current() );
494  if (item) {
495  int id = item->text( 2 ).toInt();
496  mFilter->setApplyOnAccount( id, item->isOn() );
497  }
498  ++it;
499  }
500  }
501 }
502 
503 void KMFilterDlg::slotStopProcessingButtonToggled( bool aChecked )
504 {
505  if ( mFilter )
506  mFilter->setStopProcessingHere( aChecked );
507 }
508 
509 void KMFilterDlg::slotConfigureShortcutButtonToggled( bool aChecked )
510 {
511  if ( mFilter ) {
512  mFilter->setConfigureShortcut( aChecked );
513  mKeyButton->setEnabled( aChecked );
514  mConfigureToolbar->setEnabled( aChecked );
515  mFilterActionIconButton->setEnabled( aChecked );
516  mFilterActionLabel->setEnabled( aChecked );
517  }
518 }
519 
520 void KMFilterDlg::slotCapturedShortcutChanged( const TDEShortcut& sc )
521 {
522  TDEShortcut mySc(sc);
523  if ( mySc == mKeyButton->shortcut() ) return;
524  // FIXME work around a problem when reseting the shortcut via the shortcut dialog
525  // somehow the returned shortcut does not evaluate to true in TDEShortcut::isNull(),
526  // so we additionally have to check for an empty string
527  if ( mySc.isNull() || mySc.toString().isEmpty() )
528  mySc.clear();
529  if ( !mySc.isNull() && !( kmkernel->getKMMainWidget()->shortcutIsValid( mySc ) ) ) {
530  TQString msg( i18n( "The selected shortcut is already used, "
531  "please select a different one." ) );
532  KMessageBox::sorry( this, msg );
533  } else {
534  mKeyButton->setShortcut( mySc, false );
535  if ( mFilter )
536  mFilter->setShortcut( mKeyButton->shortcut() );
537  }
538 }
539 
540 void KMFilterDlg::slotConfigureToolbarButtonToggled( bool aChecked )
541 {
542  if ( mFilter )
543  mFilter->setConfigureToolbar( aChecked );
544 }
545 
546 void KMFilterDlg::slotFilterActionIconChanged( TQString icon )
547 {
548  if ( mFilter )
549  mFilter->setIcon( icon );
550 }
551 
552 void KMFilterDlg::slotUpdateAccountList()
553 {
554  mAccountList->clear();
555  TQListViewItem *top = 0;
556  for( KMAccount *a = kmkernel->acctMgr()->first(); a!=0;
557  a = kmkernel->acctMgr()->next() ) {
558  TQCheckListItem *listItem =
559  new TQCheckListItem( mAccountList, top, a->name(), TQCheckListItem::CheckBox );
560  listItem->setText( 1, a->type() );
561  listItem->setText( 2, TQString( "%1" ).arg( a->id() ) );
562  if ( mFilter )
563  listItem->setOn( mFilter->applyOnAccount( a->id() ) );
564  top = listItem;
565  }
566 
567  TQListViewItem *listItem = mAccountList->firstChild();
568  if ( listItem ) {
569  mAccountList->setCurrentItem( listItem );
570  mAccountList->setSelected( listItem, true );
571  }
572 }
573 
574 //=============================================================================
575 //
576 // class KMFilterListBox (the filter list manipulator)
577 //
578 //=============================================================================
579 
580 KMFilterListBox::KMFilterListBox( const TQString & title, TQWidget *parent, const char* name, bool popFilter )
581  : TQGroupBox( 1, Qt::Horizontal, title, parent, name ),
582  bPopFilter(popFilter)
583 {
584  mFilterList.setAutoDelete( true );
585  mIdxSelItem = -1;
586 
587  //----------- the list box
588  mListBox = new TQListBox(this);
589  mListBox->setMinimumWidth(150);
590  TQWhatsThis::add( mListBox, i18n(_wt_filterlist) );
591 
592  //----------- the first row of buttons
593  TQHBox *hb = new TQHBox(this);
594  hb->setSpacing(4);
595  mBtnTop = new KPushButton( TQString(), hb );
596  mBtnTop->setAutoRepeat( true );
597  mBtnTop->setIconSet( BarIconSet( "go-top", TDEIcon::SizeSmall ) );
598  mBtnTop->setMinimumSize( mBtnTop->sizeHint() * 1.2 );
599  mBtnUp = new KPushButton( TQString(), hb );
600  mBtnUp->setAutoRepeat( true );
601  mBtnUp->setIconSet( BarIconSet( "go-up", TDEIcon::SizeSmall ) );
602  mBtnUp->setMinimumSize( mBtnUp->sizeHint() * 1.2 );
603  mBtnDown = new KPushButton( TQString(), hb );
604  mBtnDown->setAutoRepeat( true );
605  mBtnDown->setIconSet( BarIconSet( "go-down", TDEIcon::SizeSmall ) );
606  mBtnDown->setMinimumSize( mBtnDown->sizeHint() * 1.2 );
607  mBtnBot = new KPushButton( TQString(), hb );
608  mBtnBot->setAutoRepeat( true );
609  mBtnBot->setIconSet( BarIconSet( "go-bottom", TDEIcon::SizeSmall ) );
610  mBtnBot->setMinimumSize( mBtnBot->sizeHint() * 1.2 );
611  TQToolTip::add( mBtnTop, i18n("Top") );
612  TQToolTip::add( mBtnUp, i18n("Up") );
613  TQToolTip::add( mBtnDown, i18n("Down") );
614  TQToolTip::add( mBtnBot, i18n("Bottom") );
615  TQWhatsThis::add( mBtnTop, i18n(_wt_filterlist_top) );
616  TQWhatsThis::add( mBtnUp, i18n(_wt_filterlist_up) );
617  TQWhatsThis::add( mBtnDown, i18n(_wt_filterlist_down) );
618  TQWhatsThis::add( mBtnBot, i18n(_wt_filterlist_bot) );
619 
620  //----------- the second row of buttons
621  hb = new TQHBox(this);
622  hb->setSpacing(4);
623  mBtnNew = new TQPushButton( TQString(), hb );
624  mBtnNew->setPixmap( BarIcon( "document-new", TDEIcon::SizeSmall ) );
625  mBtnNew->setMinimumSize( mBtnNew->sizeHint() * 1.2 );
626  mBtnCopy = new TQPushButton( TQString(), hb );
627  mBtnCopy->setIconSet( BarIconSet( "edit-copy", TDEIcon::SizeSmall ) );
628  mBtnCopy->setMinimumSize( mBtnCopy->sizeHint() * 1.2 );
629  mBtnDelete = new TQPushButton( TQString(), hb );
630  mBtnDelete->setIconSet( BarIconSet( "edit-delete", TDEIcon::SizeSmall ) );
631  mBtnDelete->setMinimumSize( mBtnDelete->sizeHint() * 1.2 );
632  mBtnRename = new TQPushButton( i18n("Rename..."), hb );
633  TQToolTip::add( mBtnNew, i18n("New") );
634  TQToolTip::add( mBtnCopy, i18n("Copy") );
635  TQToolTip::add( mBtnDelete, i18n("Delete"));
636  TQWhatsThis::add( mBtnNew, i18n(_wt_filterlist_new) );
637  TQWhatsThis::add( mBtnCopy, i18n(_wt_filterlist_copy) );
638  TQWhatsThis::add( mBtnDelete, i18n(_wt_filterlist_delete) );
639  TQWhatsThis::add( mBtnRename, i18n(_wt_filterlist_rename) );
640 
641  // third row
642  if ( !popFilter ) {
643  hb = new TQHBox( this );
644  hb->setSpacing( 4 );
645  TQPushButton *btn = new TQPushButton( i18n("Select Source Folders"), hb );
646  connect( btn, TQT_SIGNAL(clicked()), TQT_SLOT(slotSelectSourceFolders()) );
647  }
648 
649 
650  //----------- now connect everything
651  connect( mListBox, TQT_SIGNAL(highlighted(int)),
652  this, TQT_SLOT(slotSelected(int)) );
653  connect( mListBox, TQT_SIGNAL( doubleClicked ( TQListBoxItem * )),
654  this, TQT_SLOT( slotRename()) );
655  connect( mBtnTop, TQT_SIGNAL(clicked()),
656  this, TQT_SLOT(slotTop()) );
657  connect( mBtnUp, TQT_SIGNAL(clicked()),
658  this, TQT_SLOT(slotUp()) );
659  connect( mBtnDown, TQT_SIGNAL(clicked()),
660  this, TQT_SLOT(slotDown()) );
661  connect( mBtnBot, TQT_SIGNAL(clicked()),
662  this, TQT_SLOT(slotBottom()) );
663  connect( mBtnNew, TQT_SIGNAL(clicked()),
664  this, TQT_SLOT(slotNew()) );
665  connect( mBtnCopy, TQT_SIGNAL(clicked()),
666  this, TQT_SLOT(slotCopy()) );
667  connect( mBtnDelete, TQT_SIGNAL(clicked()),
668  this, TQT_SLOT(slotDelete()) );
669  connect( mBtnRename, TQT_SIGNAL(clicked()),
670  this, TQT_SLOT(slotRename()) );
671 
672  // the dialog should call loadFilterList()
673  // when all signals are connected.
674  enableControls();
675 }
676 
677 
678 void KMFilterListBox::createFilter( const TQCString & field,
679  const TQString & value )
680 {
681  KMSearchRule *newRule = KMSearchRule::createInstance( field, KMSearchRule::FuncContains, value );
682 
683  KMFilter *newFilter = new KMFilter(0, bPopFilter);
684  newFilter->pattern()->append( newRule );
685  newFilter->pattern()->setName( TQString("<%1>:%2").arg( TQString(field) ).arg( TQString(value) ) );
686 
687  KMFilterActionDesc *desc = (*kmkernel->filterActionDict())["transfer"];
688  if ( desc )
689  newFilter->actions()->append( desc->create() );
690 
691  insertFilter( newFilter );
692  enableControls();
693 }
694 
696 {
697  return mShowLater;
698 }
699 
701 {
702  KMSearchPattern *p = mFilterList.at(mIdxSelItem)->pattern();
703  if ( !p ) return;
704 
705  TQString shouldBeName = p->name();
706  TQString displayedName = mListBox->text( mIdxSelItem );
707 
708  if ( shouldBeName.stripWhiteSpace().isEmpty() ) {
709  mFilterList.at(mIdxSelItem)->setAutoNaming( true );
710  }
711 
712  if ( mFilterList.at(mIdxSelItem)->isAutoNaming() ) {
713  // auto-naming of patterns
714  if ( !p->isEmpty() && p->first() && !p->first()->field().stripWhiteSpace().isEmpty() )
715  shouldBeName = TQString( "<%1>: %2" ).arg( TQString(p->first()->field()) ).arg( TQString(p->first()->contents()) );
716  else
717  shouldBeName = "<" + i18n("unnamed") + ">";
718  p->setName( shouldBeName );
719  }
720 
721  if ( displayedName == shouldBeName ) return;
722 
723  mListBox->blockSignals( true );
724  mListBox->changeItem( shouldBeName, mIdxSelItem );
725  mListBox->blockSignals( false );
726 }
727 
729 {
730  mShowLater = aOn;
731 }
732 
734 {
735  if ( mIdxSelItem >= 0 ) {
736  emit applyWidgets();
737  slotSelected( mListBox->currentItem() );
738  }
739 
740  // by now all edit widgets should have written back
741  // their widget's data into our filter list.
742 
743  KMFilterMgr *fm;
744  if (bPopFilter)
745  fm = kmkernel->popFilterMgr();
746  else
747  fm = kmkernel->filterMgr();
748 
749  TQValueList<KMFilter*> newFilters = filtersForSaving();
750 
751  if (bPopFilter)
752  fm->setShowLaterMsgs(mShowLater);
753 
754  fm->setFilters( newFilters );
755  if (fm->atLeastOneOnlineImapFolderTarget()) {
756  TQString str = i18n("At least one filter targets a folder on an online "
757  "IMAP account. Such filters will only be applied "
758  "when manually filtering and when filtering "
759  "incoming online IMAP mail.");
760  KMessageBox::information( this, str, TQString(),
761  "filterDlgOnlineImapCheck" );
762  }
763 }
764 
765 TQValueList<KMFilter*> KMFilterListBox::filtersForSaving() const
766 {
767  const_cast<KMFilterListBox*>( this )->applyWidgets(); // signals aren't const
768  TQValueList<KMFilter*> filters;
769  TQStringList emptyFilters;
770  TQPtrListIterator<KMFilter> it( mFilterList );
771  for ( it.toFirst() ; it.current() ; ++it ) {
772  KMFilter *f = new KMFilter( **it ); // deep copy
773  f->purify();
774  if ( !f->isEmpty() )
775  // the filter is valid:
776  filters.append( f );
777  else {
778  // the filter is invalid:
779  emptyFilters << f->name();
780  delete f;
781  }
782  }
783 
784  // report on invalid filters:
785  if ( !emptyFilters.empty() ) {
786  TQString msg = i18n("The following filters have not been saved because they "
787  "were invalid (e.g. containing no actions or no search "
788  "rules).");
789  KMessageBox::informationList( 0, msg, emptyFilters, TQString(),
790  "ShowInvalidFilterWarning" );
791  }
792  return filters;
793 }
794 
796 {
797  mIdxSelItem = aIdx;
798  // TQPtrList::at(i) will return 0 if i is out of range.
799  KMFilter *f = mFilterList.at(aIdx);
800  if ( f )
801  emit filterSelected( f );
802  else
803  emit resetWidgets();
804  enableControls();
805 }
806 
808 {
809  // just insert a new filter.
810  insertFilter( new KMFilter(0, bPopFilter) );
811  enableControls();
812 }
813 
815 {
816  if ( mIdxSelItem < 0 ) {
817  kdDebug(5006) << "KMFilterListBox::slotCopy called while no filter is selected, ignoring." << endl;
818  return;
819  }
820 
821  // make sure that all changes are written to the filter before we copy it
822  emit applyWidgets();
823 
824  KMFilter *filter = mFilterList.at( mIdxSelItem );
825 
826  // enableControls should make sure this method is
827  // never called when no filter is selected.
828  assert( filter );
829 
830  // inserts a copy of the current filter.
831  insertFilter( new KMFilter( *filter ) );
832  enableControls();
833 }
834 
836 {
837  if ( mIdxSelItem < 0 ) {
838  kdDebug(5006) << "KMFilterListBox::slotDelete called while no filter is selected, ignoring." << endl;
839  return;
840  }
841 
842  int oIdxSelItem = mIdxSelItem;
843  mIdxSelItem = -1;
844  // unselect all
845  mListBox->selectAll( false );
846  // broadcast that all widgets let go
847  // of the filter
848  emit resetWidgets();
849 
850  // remove the filter from both the filter list...
851  mFilterList.remove( oIdxSelItem );
852  // and the listbox
853  mListBox->removeItem( oIdxSelItem );
854 
855  int count = (int)mListBox->count();
856  // and set the new current item.
857  if ( count > oIdxSelItem )
858  // oIdxItem is still a valid index
859  mListBox->setSelected( oIdxSelItem, true );
860  else if ( count )
861  // oIdxSelIdx is no longer valid, but the
862  // list box isn't empty
863  mListBox->setSelected( count - 1, true );
864  // the list is empty - keep index -1
865 
866  enableControls();
867 }
868 
870 {
871  if ( mIdxSelItem < 0 ) {
872  kdDebug(5006) << "KMFilterListBox::slotTop called while no filter is selected, ignoring." << endl;
873  return;
874  }
875  if ( mIdxSelItem == 0 ) {
876  kdDebug(5006) << "KMFilterListBox::slotTop called while the _topmost_ filter is selected, ignoring." << endl;
877  return;
878  }
879 
880  swapFilters( mIdxSelItem, 0 );
881  enableControls();
882 }
883 
885 {
886  if ( mIdxSelItem < 0 ) {
887  kdDebug(5006) << "KMFilterListBox::slotUp called while no filter is selected, ignoring." << endl;
888  return;
889  }
890  if ( mIdxSelItem == 0 ) {
891  kdDebug(5006) << "KMFilterListBox::slotUp called while the _topmost_ filter is selected, ignoring." << endl;
892  return;
893  }
894 
895  swapNeighbouringFilters( mIdxSelItem, mIdxSelItem - 1 );
896  enableControls();
897 }
898 
900 {
901  if ( mIdxSelItem < 0 ) {
902  kdDebug(5006) << "KMFilterListBox::slotDown called while no filter is selected, ignoring." << endl;
903  return;
904  }
905  if ( mIdxSelItem == (int)mListBox->count() - 1 ) {
906  kdDebug(5006) << "KMFilterListBox::slotDown called while the _last_ filter is selected, ignoring." << endl;
907  return;
908  }
909 
910  swapNeighbouringFilters( mIdxSelItem, mIdxSelItem + 1);
911  enableControls();
912 }
913 
915 {
916  if ( mIdxSelItem < 0 ) {
917  kdDebug(5006) << "KMFilterListBox::slotBottom called while no filter is selected, ignoring." << endl;
918  return;
919  }
920  if ( mIdxSelItem == (int)mListBox->count() - 1 ) {
921  kdDebug(5006) << "KMFilterListBox::slotBottom called while the _last_ filter is selected, ignoring." << endl;
922  return;
923  }
924 
925  swapFilters( mIdxSelItem, mListBox->count()-1 );
926  enableControls();
927 }
928 
930 {
931  if ( mIdxSelItem < 0 ) {
932  kdDebug(5006) << "KMFilterListBox::slotRename called while no filter is selected, ignoring." << endl;
933  return;
934  }
935 
936  bool okPressed = false ;
937  KMFilter *filter = mFilterList.at( mIdxSelItem );
938 
939  // enableControls should make sure this method is
940  // never called when no filter is selected.
941  assert( filter );
942 
943  // allow empty names - those will turn auto-naming on again
944  TQValidator *validator = new TQRegExpValidator( TQRegExp( ".*" ), 0 );
945  TQString newName = KInputDialog::getText
946  (
947  i18n("Rename Filter"),
948  i18n("Rename filter \"%1\" to:\n(leave the field empty for automatic naming)")
949  .arg( filter->pattern()->name() ) /*label*/,
950  filter->pattern()->name() /* initial value */,
951  &okPressed, topLevelWidget(), 0, validator
952  );
953  delete validator;
954 
955  if ( !okPressed ) return;
956 
957  if ( newName.isEmpty() ) {
958  // bait for slotUpdateFilterName to
959  // use automatic naming again.
960  filter->pattern()->setName( "<>" );
961  filter->setAutoNaming( true );
962  } else {
963  filter->pattern()->setName( newName );
964  filter->setAutoNaming( false );
965  }
966 
968 }
969 
970 void KMFilterListBox::slotSelectSourceFolders()
971 {
972  FolderSetSelector dlg( kmkernel->getKMMainWidget()->folderTree(), this );
973  dlg.setCaption( i18n( "Select Folders to Filter" ) );
974  if ( !GlobalSettings::filterSourceFolders().isEmpty() )
975  dlg.setSelectedFolders( GlobalSettings::filterSourceFolders() );
976  if ( dlg.exec() == TQDialog::Accepted ) {
977  GlobalSettings::setFilterSourceFolders( dlg.selectedFolders() );
978  }
979 }
980 
981 void KMFilterListBox::enableControls()
982 {
983  bool theFirst = ( mIdxSelItem == 0 );
984  bool theLast = ( mIdxSelItem >= (int)mFilterList.count() - 1 );
985  bool aFilterIsSelected = ( mIdxSelItem >= 0 );
986 
987  mBtnTop->setEnabled( aFilterIsSelected && !theFirst );
988  mBtnUp->setEnabled( aFilterIsSelected && !theFirst );
989  mBtnDown->setEnabled( aFilterIsSelected && !theLast );
990  mBtnBot->setEnabled( aFilterIsSelected && !theLast );
991  mBtnCopy->setEnabled( aFilterIsSelected );
992  mBtnDelete->setEnabled( aFilterIsSelected );
993  mBtnRename->setEnabled( aFilterIsSelected );
994 
995  if ( aFilterIsSelected )
996  mListBox->ensureCurrentVisible();
997 }
998 
999 void KMFilterListBox::loadFilterList( bool createDummyFilter )
1000 {
1001  assert(mListBox);
1002  setEnabled( false );
1003  emit resetWidgets();
1004  // we don't want the insertion to
1005  // cause flicker in the edit widgets.
1006  blockSignals( true );
1007 
1008  // clear both lists
1009  mFilterList.clear();
1010  mListBox->clear();
1011 
1012  const KMFilterMgr *manager = 0;
1013  if(bPopFilter)
1014  {
1015  mShowLater = kmkernel->popFilterMgr()->showLaterMsgs();
1016  manager = kmkernel->popFilterMgr();
1017  }
1018  else
1019  {
1020  manager = kmkernel->filterMgr();
1021  }
1022  Q_ASSERT( manager );
1023 
1024  TQValueListConstIterator<KMFilter*> it;
1025  for ( it = manager->filters().constBegin() ; it != manager->filters().constEnd() ; ++it ) {
1026  mFilterList.append( new KMFilter( **it ) ); // deep copy
1027  mListBox->insertItem( (*it)->pattern()->name() );
1028  }
1029 
1030  blockSignals( false );
1031  setEnabled( true );
1032 
1033  // create an empty filter when there's none, to avoid a completely
1034  // disabled dialog (usability tests indicated that the new-filter
1035  // button is too hard to find that way):
1036  if ( !mListBox->count() && createDummyFilter )
1037  slotNew();
1038 
1039  if ( mListBox->count() > 0 )
1040  mListBox->setSelected( 0, true );
1041 
1042  enableControls();
1043 }
1044 
1045 void KMFilterListBox::insertFilter( KMFilter* aFilter )
1046 {
1047  // must be really a filter...
1048  assert( aFilter );
1049 
1050  // if mIdxSelItem < 0, TQListBox::insertItem will append.
1051  mListBox->insertItem( aFilter->pattern()->name(), mIdxSelItem );
1052  if ( mIdxSelItem < 0 ) {
1053  // none selected -> append
1054  mFilterList.append( aFilter );
1055  mListBox->setSelected( mListBox->count() - 1, true );
1056  // slotSelected( mListBox->count() - 1 );
1057  } else {
1058  // insert just before selected
1059  mFilterList.insert( mIdxSelItem, aFilter );
1060  mListBox->setSelected( mIdxSelItem, true );
1061  // slotSelected( mIdxSelItem );
1062  }
1063 
1064 }
1065 
1066 void KMFilterListBox::appendFilter( KMFilter* aFilter )
1067 {
1068  mFilterList.append( aFilter );
1069  mListBox->insertItem( aFilter->pattern()->name(), -1 );
1070 }
1071 
1072 void KMFilterListBox::swapNeighbouringFilters( int untouchedOne, int movedOne )
1073 {
1074  // must be neighbours...
1075  assert( untouchedOne - movedOne == 1 || movedOne - untouchedOne == 1 );
1076 
1077  // untouchedOne is at idx. to move it down(up),
1078  // remove item at idx+(-)1 w/o deleting it.
1079  TQListBoxItem *item = mListBox->item( movedOne );
1080  mListBox->takeItem( item );
1081  // now selected item is at idx(idx-1), so
1082  // insert the other item at idx, ie. above(below).
1083  mListBox->insertItem( item, untouchedOne );
1084 
1085  KMFilter* filter = mFilterList.take( movedOne );
1086  mFilterList.insert( untouchedOne, filter );
1087 
1088  mIdxSelItem += movedOne - untouchedOne;
1089 }
1090 
1091 void KMFilterListBox::swapFilters( int from, int to )
1092 {
1093  TQListBoxItem *item = mListBox->item( from );
1094  mListBox->takeItem( item );
1095  mListBox->insertItem( item, to );
1096 
1097  KMFilter* filter = mFilterList.take( from );
1098  mFilterList.insert( to, filter );
1099 
1100  mIdxSelItem = to;
1101  mListBox->setCurrentItem( mIdxSelItem );
1102  mListBox->setSelected( mIdxSelItem, true );
1103 }
1104 
1105 //=============================================================================
1106 //
1107 // class KMFilterActionWidget
1108 //
1109 //=============================================================================
1110 
1111 KMFilterActionWidget::KMFilterActionWidget( TQWidget *parent, const char* name )
1112  : TQHBox( parent, name )
1113 {
1114  int i;
1115  mActionList.setAutoDelete( true );
1116 
1117  mComboBox = new TQComboBox( false , this );
1118  assert( mComboBox );
1119  mWidgetStack = new TQWidgetStack(this);
1120  assert( mWidgetStack );
1121 
1122  setSpacing( 4 );
1123 
1124  TQPtrListIterator<KMFilterActionDesc> it ( kmkernel->filterActionDict()->list() );
1125  for ( i=0, it.toFirst() ; it.current() ; ++it, ++i ) {
1126  //create an instance:
1127  KMFilterAction *a = (*it)->create();
1128  // append to the list of actions:
1129  mActionList.append( a );
1130  // add parameter widget to widget stack:
1131  mWidgetStack->addWidget( a->createParamWidget( mWidgetStack ), i );
1132  // add (i18n-ized) name to combo box
1133  mComboBox->insertItem( (*it)->label );
1134  }
1135  // widget for the case where no action is selected.
1136  mWidgetStack->addWidget( new TQLabel( i18n("Please select an action."), mWidgetStack ), i );
1137  mWidgetStack->raiseWidget(i);
1138  mComboBox->insertItem( " " );
1139  mComboBox->setCurrentItem(i);
1140 
1141  // don't show scroll bars.
1142  mComboBox->setSizeLimit( mComboBox->count() );
1143  // layout management:
1144  // o the combo box is not to be made larger than it's sizeHint(),
1145  // the parameter widget should grow instead.
1146  // o the whole widget takes all space horizontally, but is fixed vertically.
1147  mComboBox->adjustSize();
1148  mComboBox->setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed ) );
1149  setSizePolicy( TQSizePolicy( TQSizePolicy::Preferred, TQSizePolicy::Fixed ) );
1150  updateGeometry();
1151 
1152  // redirect focus to the filter action combo box
1153  setFocusProxy( mComboBox );
1154 
1155  // now connect the combo box and the widget stack
1156  connect( mComboBox, TQT_SIGNAL(activated(int)),
1157  mWidgetStack, TQT_SLOT(raiseWidget(int)) );
1158 }
1159 
1161 {
1162  int i=0;
1163  bool found = false ;
1164  int count = mComboBox->count() - 1 ; // last entry is the empty one
1165  TQString label = ( aAction ) ? aAction->label() : TQString() ;
1166 
1167  // find the index of typeOf(aAction) in mComboBox
1168  // and clear the other widgets on the way.
1169  for ( ; i < count ; i++ )
1170  if ( aAction && mComboBox->text(i) == label ) {
1171  //...set the parameter widget to the settings
1172  // of aAction...
1173  aAction->setParamWidgetValue( mWidgetStack->widget(i) );
1174  //...and show the correct entry of
1175  // the combo box
1176  mComboBox->setCurrentItem(i); // (mm) also raise the widget, but doesn't
1177  mWidgetStack->raiseWidget(i);
1178  found = true;
1179  } else // clear the parameter widget
1180  mActionList.at(i)->clearParamWidget( mWidgetStack->widget(i) );
1181  if ( found ) return;
1182 
1183  // not found, so set the empty widget
1184  mComboBox->setCurrentItem( count ); // last item
1185  mWidgetStack->raiseWidget( count) ;
1186 }
1187 
1189 {
1190  // look up the action description via the label
1191  // returned by TQComboBox::currentText()...
1192  KMFilterActionDesc *desc = (*kmkernel->filterActionDict())[ mComboBox->currentText() ];
1193  if ( desc ) {
1194  // ...create an instance...
1195  KMFilterAction *fa = desc->create();
1196  if ( fa ) {
1197  // ...and apply the setting of the parameter widget.
1198  fa->applyParamWidgetValue( mWidgetStack->visibleWidget() );
1199  return fa;
1200  }
1201  }
1202 
1203  return 0;
1204 }
1205 
1206 //=============================================================================
1207 //
1208 // class KMFilterActionWidgetLister (the filter action editor)
1209 //
1210 //=============================================================================
1211 
1212 KMFilterActionWidgetLister::KMFilterActionWidgetLister( TQWidget *parent, const char* name )
1213  : KWidgetLister( 1, FILTER_MAX_ACTIONS, parent, name )
1214 {
1215  mActionList = 0;
1216 }
1217 
1218 KMFilterActionWidgetLister::~KMFilterActionWidgetLister()
1219 {
1220 }
1221 
1222 void KMFilterActionWidgetLister::setActionList( TQPtrList<KMFilterAction> *aList )
1223 {
1224  assert ( aList );
1225 
1226  if ( mActionList )
1227  regenerateActionListFromWidgets();
1228 
1229  mActionList = aList;
1230 
1231  ((TQWidget*)parent())->setEnabled( true );
1232 
1233  if ( aList->count() == 0 ) {
1234  slotClear();
1235  return;
1236  }
1237 
1238  int superfluousItems = (int)mActionList->count() - mMaxWidgets ;
1239  if ( superfluousItems > 0 ) {
1240  kdDebug(5006) << "KMFilterActionWidgetLister: Clipping action list to "
1241  << mMaxWidgets << " items!" << endl;
1242 
1243  for ( ; superfluousItems ; superfluousItems-- )
1244  mActionList->removeLast();
1245  }
1246 
1247  // set the right number of widgets
1248  setNumberOfShownWidgetsTo( mActionList->count() );
1249 
1250  // load the actions into the widgets
1251  TQPtrListIterator<KMFilterAction> aIt( *mActionList );
1252  TQPtrListIterator<TQWidget> wIt( mWidgetList );
1253  for ( aIt.toFirst(), wIt.toFirst() ;
1254  aIt.current() && wIt.current() ; ++aIt, ++wIt )
1255  ((KMFilterActionWidget*)(*wIt))->setAction( (*aIt) );
1256 }
1257 
1258 void KMFilterActionWidgetLister::reset()
1259 {
1260  if ( mActionList )
1261  regenerateActionListFromWidgets();
1262 
1263  mActionList = 0;
1264  slotClear();
1265  ((TQWidget*)parent())->setEnabled( false );
1266 }
1267 
1268 TQWidget* KMFilterActionWidgetLister::createWidget( TQWidget *parent )
1269 {
1270  return new KMFilterActionWidget(parent);
1271 }
1272 
1273 void KMFilterActionWidgetLister::clearWidget( TQWidget *aWidget )
1274 {
1275  if ( aWidget )
1276  ((KMFilterActionWidget*)aWidget)->setAction(0);
1277 }
1278 
1279 void KMFilterActionWidgetLister::regenerateActionListFromWidgets()
1280 {
1281  if ( !mActionList ) return;
1282 
1283  mActionList->clear();
1284 
1285  TQPtrListIterator<TQWidget> it( mWidgetList );
1286  for ( it.toFirst() ; it.current() ; ++it ) {
1287  KMFilterAction *a = ((KMFilterActionWidget*)(*it))->action();
1288  if ( a )
1289  mActionList->append( a );
1290  }
1291 
1292 }
1293 
1294 //=============================================================================
1295 //
1296 // class KMPopFilterActionWidget
1297 //
1298 //=============================================================================
1299 
1300 KMPopFilterActionWidget::KMPopFilterActionWidget( const TQString& title, TQWidget *parent, const char* name )
1301  : TQVButtonGroup( title, parent, name )
1302 {
1303  mActionMap[Down] = new TQRadioButton( i18n("&Download mail"), this );
1304  mActionMap[Later] = new TQRadioButton( i18n("Download mail la&ter"), this );
1305  mActionMap[Delete] = new TQRadioButton( i18n("D&elete mail from server"), this );
1306  mIdMap[id(mActionMap[Later])] = Later;
1307  mIdMap[id(mActionMap[Down])] = Down;
1308  mIdMap[id(mActionMap[Delete])] = Delete;
1309 
1310  connect( this, TQT_SIGNAL(clicked(int)),
1311  this, TQT_SLOT( slotActionClicked(int)) );
1312 }
1313 
1314 void KMPopFilterActionWidget::setAction( KMPopFilterAction aAction )
1315 {
1316  if( aAction == NoAction)
1317  {
1318  aAction = Later;
1319  }
1320 
1321  mAction = aAction;
1322 
1323  blockSignals( true );
1324  if(!mActionMap[aAction]->isChecked())
1325  {
1326  mActionMap[aAction]->setChecked( true );
1327  }
1328  blockSignals( false );
1329 
1330  setEnabled( true );
1331 }
1332 
1333 KMPopFilterAction KMPopFilterActionWidget::action()
1334 {
1335  return mAction;
1336 }
1337 
1338 void KMPopFilterActionWidget::slotActionClicked(int aId)
1339 {
1340  emit actionChanged(mIdMap[aId]);
1341  setAction(mIdMap[aId]);
1342 }
1343 
1344 void KMPopFilterActionWidget::reset()
1345 {
1346  blockSignals( true );
1347  mActionMap[Down]->setChecked( true );
1348  blockSignals( false );
1349 
1350  setEnabled( false );
1351 }
1352 
1354 {
1355  FilterImporterExporter importer( this, bPopFilter );
1356  TQValueList<KMFilter*> filters = importer.importFilters();
1357  // FIXME message box how many were imported?
1358  if (filters.isEmpty()) return;
1359 
1360  TQValueListConstIterator<KMFilter*> it;
1361 
1362  for ( it = filters.constBegin() ; it != filters.constEnd() ; ++it ) {
1363  mFilterList->appendFilter( *it ); // no need to deep copy, ownership passes to the list
1364  }
1365 }
1366 
1368 {
1369  FilterImporterExporter exporter( this, bPopFilter );
1370  TQValueList<KMFilter*> filters = mFilterList->filtersForSaving();
1371  exporter.exportFilters( filters );
1372  TQValueList<KMFilter*>::iterator it;
1373  for ( it = filters.begin(); it != filters.end(); ++it )
1374  delete *it;
1375 }
1376 
1377 #include "kmfilterdlg.moc"
This class is an abstraction of a search over messages.
static KMSearchRule * createInstance(const TQCString &field=0, Function function=FuncContains, const TQString &contents=TQString())
Create a search rule of a certain type by instantiating the appro- priate subclass depending on the f...
TQListBox * mListBox
The listbox displaying the filter list.
Definition: kmfilterdlg.h:159
void exportFilters(const TQValueList< KMFilter *> &)
Export the given filter rules to a file which is asked from the user.
void reset()
Called when the widget should let go of the currently referenced filter and disable itself...
void slotTop()
Called when the user clicks the &#39;Top&#39; button.
TQRadioButton * mApplyOnForAll
For a filter applied to inbound messages selects whether to apply this filter to all accounts or to s...
Definition: kmfilterdlg.h:409
void updateSearchPattern()
Updates the search pattern according to the current widget values.
TDEListView * mAccountList
ListView that shows the accounts in the advanced tab.
Definition: kmfilterdlg.h:411
void createFilter(const TQCString &field, const TQString &value)
Called from KMFilterDlg.
Abstract base class for KMail&#39;s filter actions.
void setSearchPattern(KMSearchPattern *aPattern)
Set the search pattern.
This widgets allows to edit a single KMFilterAction (in fact any derived class that is registered in ...
Definition: kmfilterdlg.h:196
Utility class that provides persisting of filters to/from TDEConfig.
KMFilterAction * action()
Retrieve the action.
void slotExportFilters()
Called when a user clicks the export filters button.
bool showLaterMsgs()
Returns wheather the global option &#39;Show Later Msgs&#39; is set or not.
void slotRename()
Called when the user clicks the &#39;Rename&#39; button.
virtual void applyParamWidgetValue(TQWidget *paramWidget)
The filter action shall set it&#39;s parameter from the widget&#39;s contents.
void slotImportFilters()
Called when a user clicks the import filters button.
KMFilterListBox(const TQString &title, TQWidget *parent=0, const char *name=0, bool popFilter=false)
Constuctor.
void slotCopy()
Called when the user clicks the &#39;Copy&#39; button.
void resetWidgets()
Emitted when this widget wants the edit widgets to let go of their filter reference.
void slotShowLaterToggled(bool aOn)
Called when the user toggles the &#39;Show Download Later Msgs&#39; Checkbox in the Global Options section...
Incoming mail is sent through the list of mail filter rules before it is placed in the associated mai...
virtual TQWidget * createParamWidget(TQWidget *parent) const
Creates a widget for setting the filter action parameter.
TQPushButton * mBtnNew
The various action buttons.
Definition: kmfilterdlg.h:161
void setAction(const KMFilterAction *aAction)
Set an action.
TQValueList< KMFilter * > filtersForSaving() const
Returns a list of copies of the current list of filters.
void slotDown()
Called when the user clicks the &#39;Down&#39; button.
KMSearchPatternEdit * mPatternEdit
The widget that allows editing of the filter pattern.
Definition: kmfilterdlg.h:399
void slotUp()
Called when the user clicks the &#39;Up&#39; button.
int mIdxSelItem
The index of the currently selected item.
Definition: kmfilterdlg.h:164
void setName(const TQString &newName)
Set the name of the search pattern.
KMFilterDlg(TQWidget *parent=0, const char *name=0, bool popFilter=false, bool createDummyFilter=true)
Create the filter dialog.
KMFilterListBox * mFilterList
The widget that contains the ListBox showing the filters, and the controls to remove filters...
Definition: kmfilterdlg.h:397
void slotActionChanged(const KMPopFilterAction aAction)
Action for popFilter.
TQString name() const
Get the name of the search pattern.
This widget is intended to be used in the filter configuration as well as in the message search dialo...
const TQString label() const
Returns nationalized label, ie.
KMPopFilterActionWidget * mActionGroup
The widget that allows editing the popFilter actions.
Definition: kmfilterdlg.h:403
void slotFilterSelected(KMFilter *aFilter)
Internally connected to KMFilterListBox::filterSelected.
Auxiliary struct to KMFilterActionDict.
KMFilterActionWidget(TQWidget *parent=0, const char *name=0)
Constructor.
This is a complex widget that is used to manipulate KMail&#39;s filter list.
Definition: kmfilterdlg.h:60
void slotDelete()
Called when the user clicks the &#39;Delete&#39; button.
void slotBottom()
Called when the user clicks the &#39;Bottom&#39; button.
void slotUpdateFilterName()
Called when the name of a filter might have changed (e.g.
virtual void setParamWidgetValue(TQWidget *paramWidget) const
The filter action shall set it&#39;s widget&#39;s contents from it&#39;s parameter.
void slotNew()
Called when the user clicks the &#39;New&#39; button.
void slotSelected(int aIdx)
Called when the user clicks on a filter in the filter list.
folderdiaquotatab.h
Definition: aboutdata.cpp:40
The account manager is responsible for creating accounts of various types via the factory method crea...
void applyWidgets()
Emitted when this widget wants the edit widgets to apply the changes to the current filter...
TQPtrList< KMFilter > mFilterList
The deep copy of the filter list.
Definition: kmfilterdlg.h:157
void slotApplyFilterChanges()
Called when the user clicks either &#39;Apply&#39; or &#39;OK&#39; in KMFilterDlg.
TQValueList< KMFilter * > importFilters()
Import filters.
void loadFilterList(bool createDummyFilter)
Loads the filter list and selects the first filter.
void filterSelected(KMFilter *filter)
Emitted when a new filter has been selected by the user or if the current filter has changed after a ...
KMFilterActionWidgetLister * mActionLister
The widget that allows editing of the filter actions.
Definition: kmfilterdlg.h:401
TQCheckBox * mApplyOnIn
Lets the user select whether to apply this filter on inbound/outbound messages, both, or only on explicit CTRL-J.
Definition: kmfilterdlg.h:406