kmail

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