Mailcommon

kmfilterdialog.cpp
1 /*
2  Filter Dialog
3 
4  SPDX-FileCopyrightText: Marc Mutz <[email protected]>
5  SPDX-FileCopyrightText: 2011-2022 Laurent Montel <[email protected]>
6 
7  based upon work by Stefan Taferner <[email protected]>
8 
9  SPDX-License-Identifier: GPL-2.0-or-later
10 */
11 
12 #include "kmfilterdialog.h"
13 #include "kmfilterlistbox.h"
14 #include "mailcommon_debug.h"
15 
16 #include "filteractions/filteractiondict.h"
17 #include "filteractions/filteractionwidget.h"
18 #include "filterimporterpathcache.h"
19 #include "filterselectiondialog.h"
20 #include "kmfilteraccountlist.h"
22 #include "filterconverter/filterconverttosieve.h"
23 #include "filtermanager.h"
24 #include "folder/folderrequester.h"
25 #include "kernel/mailkernel.h"
26 #include "search/searchpatternedit.h"
27 #include "util/mailutil.h"
28 #include <PimCommon/PimUtil>
29 
30 #include <Akonadi/ItemFetchJob>
31 
32 #include <KConfigGroup>
33 
34 #include <KIconButton>
35 #include <KIconLoader>
36 #include <KJob>
37 #include <KKeySequenceWidget>
38 #include <KListWidgetSearchLine>
39 #include <KLocalizedString>
40 #include <KMessageBox>
41 #include <QIcon>
42 #include <QPushButton>
43 #include <QTabWidget>
44 
45 #include <QButtonGroup>
46 #include <QCheckBox>
47 #include <QDialogButtonBox>
48 #include <QFormLayout>
49 #include <QGridLayout>
50 #include <QGroupBox>
51 #include <QHBoxLayout>
52 #include <QKeyEvent>
53 #include <QLabel>
54 #include <QMenu>
55 #include <QPointer>
56 #include <QRadioButton>
57 #include <QShortcut>
58 #include <QSplitter>
59 #include <QTreeWidget>
60 #include <QVBoxLayout>
61 
62 Q_DECLARE_METATYPE(MailCommon::FilterImporterExporter::FilterType)
63 using namespace MailCommon;
64 
65 //=============================================================================
66 //
67 // class KMFilterDialog (the filter dialog)
68 //
69 //=============================================================================
70 
71 KMFilterDialog::KMFilterDialog(const QList<KActionCollection *> &actionCollection, QWidget *parent, bool createDummyFilter)
72  : QDialog(parent)
73 {
74  setWindowTitle(i18nc("@title:window", "Filter Rules"));
75  auto mainLayout = new QVBoxLayout(this);
76 
78  QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
79  okButton->setDefault(true);
80  okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
81  auto user1Button = new QPushButton(this);
82  buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole);
83  auto user2Button = new QPushButton(this);
84  buttonBox->addButton(user2Button, QDialogButtonBox::ActionRole);
85  auto user3Button = new QPushButton(this);
86  buttonBox->addButton(user3Button, QDialogButtonBox::ActionRole);
87  connect(buttonBox, &QDialogButtonBox::accepted, this, &KMFilterDialog::accept);
89  connect(buttonBox->button(QDialogButtonBox::Help), &QAbstractButton::clicked, this, &KMFilterDialog::slotHelp);
90  setModal(false);
91  okButton->setFocus();
92  user1Button->setText(i18n("Import..."));
93  user2Button->setText(i18n("Export..."));
94  user3Button->setText(i18n("Convert to..."));
95  auto menu = new QMenu(this);
96 
97  auto act = new QAction(i18n("KMail filters"), this);
98  act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::KMailFilter));
99  menu->addAction(act);
100 
101  act = new QAction(i18n("Thunderbird filters"), this);
102  act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::ThunderBirdFilter));
103  menu->addAction(act);
104 
105  act = new QAction(i18n("Evolution filters"), this);
106  act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::EvolutionFilter));
107  menu->addAction(act);
108 
109  act = new QAction(i18n("Sylpheed filters"), this);
110  act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::SylpheedFilter));
111  menu->addAction(act);
112 
113  act = new QAction(i18n("Procmail filters"), this);
114  act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::ProcmailFilter));
115  menu->addAction(act);
116 
117  act = new QAction(i18n("Balsa filters"), this);
118  act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::BalsaFilter));
119  menu->addAction(act);
120 
121  act = new QAction(i18n("Claws Mail filters"), this);
122  act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::ClawsMailFilter));
123  menu->addAction(act);
124 
125  act = new QAction(i18n("Icedove Mail filters"), this);
126  act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::IcedoveFilter));
127  menu->addAction(act);
128 
129  connect(menu, &QMenu::triggered, this, &KMFilterDialog::slotImportFilter);
130 
131  act = new QAction(i18n("Gmail filters"), this);
132  act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::GmailFilter));
133  menu->addAction(act);
134 
135  user1Button->setMenu(menu);
136 
137  menu = new QMenu(this);
138 
139  act = new QAction(i18n("Sieve script"), this);
140  connect(act, &QAction::triggered, this, &KMFilterDialog::slotExportAsSieveScript);
141  menu->addAction(act);
142  user3Button->setMenu(menu);
143 
144  connect(user2Button, &QAbstractButton::clicked, this, &KMFilterDialog::slotExportFilters);
145  mApplyButton = buttonBox->button(QDialogButtonBox::Apply);
146  mApplyButton->setEnabled(false);
147 
148  auto w = new QWidget(this);
149  mainLayout->addWidget(w);
150  mainLayout->addWidget(buttonBox);
151  auto topVLayout = new QVBoxLayout(w);
152  topVLayout->setContentsMargins({});
153  auto topLayout = new QHBoxLayout;
154  topVLayout->addLayout(topLayout);
155  topLayout->setContentsMargins({});
156 
157  auto splitter = new QSplitter;
158  splitter->setChildrenCollapsible(false);
159  topLayout->addWidget(splitter);
160 
161  mFilterList = new KMFilterListBox(i18n("Available Filters"), this);
162  splitter->addWidget(mFilterList);
163  auto tabWidget = new QTabWidget(this);
164  splitter->addWidget(tabWidget);
165 
166  auto page1 = new QWidget(tabWidget);
167  tabWidget->addTab(page1, i18nc("General mail filter settings.", "General"));
168  auto hbl = new QHBoxLayout(page1);
169 
170  auto page2 = new QWidget(tabWidget);
171  tabWidget->addTab(page2, i18nc("Advanced mail filter settings.", "Advanced"));
172  auto vbl2 = new QVBoxLayout(page2);
173 
174  auto vbl = new QVBoxLayout();
175  hbl->addLayout(vbl);
176  hbl->setStretchFactor(vbl, 2);
177 
178  mPatternEdit = new MailCommon::SearchPatternEdit(page1, MailCommon::SearchPatternEdit::MatchAllMessages);
179  vbl->addWidget(mPatternEdit, 0, Qt::AlignTop);
180 
181  auto actionLabel = new QLabel(i18n("Filter actions:"), page1);
182  vbl->addWidget(actionLabel);
183 
184  mActionLister = new MailCommon::FilterActionWidgetLister(page1);
185  vbl->addWidget(mActionLister);
186 
187  mAdvOptsGroup = new QGroupBox(QString(), page2);
188  mAdvOptsGroup->setFlat(true);
189  mAdvOptsGroup->setContentsMargins({});
190  {
191  auto gl = new QGridLayout();
192  mApplyOnIn = new QCheckBox(i18n("Apply this filter to incoming messages:"), mAdvOptsGroup);
193  gl->addWidget(mApplyOnIn, 0, 0);
194 
195  auto radioGroupWidget = new QWidget(page2);
196  radioGroupWidget->setContentsMargins(20, 0, 0, 0);
197  gl->addWidget(radioGroupWidget, 1, 0);
198  auto vbl3 = new QVBoxLayout(radioGroupWidget);
199 
200  auto bg = new QButtonGroup(mAdvOptsGroup);
201 
202  mApplyOnForAll = new QRadioButton(i18n("From all accounts"), radioGroupWidget);
203  bg->addButton(mApplyOnForAll);
204  vbl3->addWidget(mApplyOnForAll);
205 
206  mApplyOnForTraditional = new QRadioButton(i18n("From all but online IMAP accounts"), radioGroupWidget);
207  bg->addButton(mApplyOnForTraditional);
208  vbl3->addWidget(mApplyOnForTraditional);
209 
210  mApplyOnForChecked = new QRadioButton(i18n("From selected accounts only"), radioGroupWidget);
211  bg->addButton(mApplyOnForChecked);
212  vbl3->addWidget(mApplyOnForChecked);
213  vbl3->addStretch(100);
214 
215  mAccountList = new KMFilterAccountList(mAdvOptsGroup);
216  gl->addWidget(mAccountList, 0, 1, 4, 3);
217 
218  mApplyOnOut = new QCheckBox(i18n("Apply this filter to &sent messages"), mAdvOptsGroup);
219  mApplyOnOut->setToolTip(
220  i18n("<p>The filter will be triggered <b>after</b> the message is sent "
221  "and it will only affect the local copy of the message.</p>"
222  "<p>If the recipient's copy also needs to be modified, "
223  "please use \"Apply this filter <b>before</b> sending messages\".</p>"));
224  gl->addWidget(mApplyOnOut, 5, 0, 1, 4);
225 
226  mApplyBeforeOut = new QCheckBox(i18n("Apply this filter &before sending messages"), mAdvOptsGroup);
227  mApplyBeforeOut->setToolTip(
228  i18n("<p>The filter will be triggered <b>before</b> the message is sent "
229  "and it will affect both the local copy and the sent copy of the message.</p>"
230  "<p>This is required if the recipient's copy also needs to be modified.</p>"));
231  gl->addWidget(mApplyBeforeOut, 6, 0, 1, 4);
232 
233  mApplyOnCtrlJ = new QCheckBox(i18n("Apply this filter on manual &filtering"), mAdvOptsGroup);
234  gl->addWidget(mApplyOnCtrlJ, 7, 0, 1, 4);
235 
236  mApplyOnAllFolders = new QCheckBox(i18n("Apply this filter on inbound emails in all folders"), mAdvOptsGroup);
237  mApplyOnAllFolders->setToolTip(
238  i18n("<p>The filter will be applied on inbound emails from all folders "
239  "belonging to all accounts selected above. This is useful when using local filters "
240  "with IMAP accounts where new emails may have already been moved to different folders "
241  "by server-side filters.</p>"));
242  gl->addWidget(mApplyOnAllFolders, 8, 0, 1, 4);
243 
244  mStopProcessingHere = new QCheckBox(i18n("If this filter &matches, stop processing here"), mAdvOptsGroup);
245  gl->addWidget(mStopProcessingHere, 9, 0, 1, 4);
246 
247  mConfigureShortcut = new QCheckBox(i18n("Add this filter to the Apply Filter menu"), mAdvOptsGroup);
248  gl->addWidget(mConfigureShortcut, 10, 0, 1, 2);
249 
250  mInMenuWidget = new QWidget(mAdvOptsGroup);
251  mInMenuWidget->setContentsMargins(20, 0, 0, 0);
252  gl->addWidget(mInMenuWidget, 11, 0, 1, 4);
253  auto inMenuLayout = new QFormLayout(mInMenuWidget);
254 
255  connect(mConfigureShortcut, &QCheckBox::toggled, this, [this](bool aChecked) {
256  if (mFilter) {
257  mFilter->setConfigureShortcut(aChecked);
258  mInMenuWidget->setEnabled(aChecked);
259 
260  // Enable the apply button
261  slotDialogUpdated();
262  }
263  });
264 
265  mConfigureToolbar = new QCheckBox(i18n("Additionally add this filter to the toolbar"), mInMenuWidget);
266  inMenuLayout->addRow(mConfigureToolbar);
267 
268  mKeySeqWidget = new KKeySequenceWidget(mInMenuWidget);
269  mKeySeqWidget->setObjectName(QStringLiteral("FilterShortcutSelector"));
270  mKeySeqWidget->setModifierlessAllowed(true);
271  mKeySeqWidget->setCheckActionCollections(actionCollection);
272  inMenuLayout->addRow(i18n("Shortcut:"), mKeySeqWidget);
273 
274  mFilterActionIconButton = new KIconButton(mInMenuWidget);
275  mFilterActionIconButton->setIconType(KIconLoader::NoGroup, KIconLoader::Action, false);
276  mFilterActionIconButton->setIconSize(16);
277  mFilterActionIconButton->setIcon(QIcon::fromTheme(QStringLiteral("system-run")));
278  inMenuLayout->addRow(i18n("Icon for this filter:"), mFilterActionIconButton);
279 
280  mAdvOptsGroup->setLayout(gl);
281  mInMenuWidget->setEnabled(false);
282  }
283  vbl2->addWidget(mAdvOptsGroup, 0, Qt::AlignTop);
284 
285  auto applySpecificFiltersLayout = new QHBoxLayout;
286  auto lab = new QLabel(i18n("Run selected filter(s) on: "), this);
287  applySpecificFiltersLayout->addWidget(lab);
288  mFolderRequester = new MailCommon::FolderRequester(this);
289  mFolderRequester->setNotAllowToCreateNewFolder(true);
290  applySpecificFiltersLayout->addWidget(mFolderRequester);
291  connect(mFolderRequester, &FolderRequester::folderChanged, this, &KMFilterDialog::slotFolderChanged);
292  mRunNow = new QPushButton(i18n("Run Now"), this);
293  mRunNow->setEnabled(false);
294  applySpecificFiltersLayout->addWidget(mRunNow);
295  connect(mRunNow, &QPushButton::clicked, this, &KMFilterDialog::slotRunFilters);
296  topVLayout->addLayout(applySpecificFiltersLayout);
297  // spacer:
298  vbl->addStretch(1);
299 
300  // load the filter parts into the edit widgets
301  connect(mFilterList, &KMFilterListBox::filterSelected, this, &KMFilterDialog::slotFilterSelected);
302 
303  // transfer changes from the 'Apply this filter on...'
304  // combo box to the filter
305  connect(mApplyOnIn, &QCheckBox::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
306  connect(mApplyOnForAll, &QRadioButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
307  connect(mApplyOnForTraditional, &QAbstractButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
308  connect(mApplyOnForChecked, &QAbstractButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
309  connect(mApplyBeforeOut, &QAbstractButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
310  connect(mApplyOnAllFolders, &QAbstractButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
311  connect(mApplyOnOut, &QAbstractButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
312  connect(mApplyOnCtrlJ, &QAbstractButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
313  connect(mAccountList, &KMFilterAccountList::itemChanged, this, &KMFilterDialog::slotApplicableAccountsChanged);
314 
315  // transfer changes from the 'stop processing here'
316  // check box to the filter
317  connect(mStopProcessingHere, &QCheckBox::toggled, this, &KMFilterDialog::slotStopProcessingButtonToggled);
318 
319  connect(mKeySeqWidget, &KKeySequenceWidget::keySequenceChanged, this, &KMFilterDialog::slotShortcutChanged);
320 
321  connect(mConfigureToolbar, &QCheckBox::toggled, this, &KMFilterDialog::slotConfigureToolbarButtonToggled);
322 
323  connect(mFilterActionIconButton, &KIconButton::iconChanged, this, &KMFilterDialog::slotFilterActionIconChanged);
324 
325  // reset all widgets here
326  connect(mFilterList, &KMFilterListBox::resetWidgets, this, &KMFilterDialog::slotReset);
327 
328  connect(mFilterList, &KMFilterListBox::applyWidgets, this, &KMFilterDialog::slotUpdateFilter);
329 
330  // support auto-naming the filter
331  connect(mPatternEdit, &MailCommon::SearchPatternEdit::maybeNameChanged, mFilterList, &KMFilterListBox::slotUpdateFilterName);
332 
333  // save filters on 'Apply' or 'OK'
334  connect(mApplyButton, &QAbstractButton::clicked, this, &KMFilterDialog::slotApply);
335 
336  // save dialog size on 'OK'
337  connect(okButton, &QAbstractButton::clicked, this, &KMFilterDialog::slotSaveSize);
338 
339  // destruct the dialog on close and Cancel
340  connect(buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, this, &KMFilterDialog::slotFinished);
341 
342  // disable closing when user wants to continue editing
343  connect(mFilterList, &KMFilterListBox::abortClosing, this, &KMFilterDialog::slotDisableAccept);
344 
345  connect(mFilterList, &KMFilterListBox::filterCreated, this, &KMFilterDialog::slotDialogUpdated);
346  connect(mFilterList, &KMFilterListBox::filterRemoved, this, &KMFilterDialog::slotDialogUpdated);
347  connect(mFilterList, &KMFilterListBox::filterUpdated, this, &KMFilterDialog::slotDialogUpdated);
348  connect(mFilterList, &KMFilterListBox::filterOrderAltered, this, &KMFilterDialog::slotDialogUpdated);
349  connect(mPatternEdit, &MailCommon::SearchPatternEdit::patternChanged, this, &KMFilterDialog::slotDialogUpdated);
350  connect(mActionLister, qOverload<QWidget *>(&FilterActionWidgetLister::widgetAdded), this, &KMFilterDialog::slotDialogUpdated);
351  connect(mActionLister, qOverload<QWidget *>(&FilterActionWidgetLister::widgetRemoved), this, &KMFilterDialog::slotDialogUpdated);
352  connect(mActionLister, &MailCommon::FilterActionWidgetLister::filterModified, this, &KMFilterDialog::slotDialogUpdated);
353  connect(mActionLister, &MailCommon::FilterActionWidgetLister::clearWidgets, this, &KMFilterDialog::slotDialogUpdated);
354  KConfigGroup myGroup(KernelIf->config(), "Geometry");
355  const QSize size = myGroup.readEntry("filterDialogSize", QSize());
356  if (size != QSize()) {
357  resize(size);
358  } else {
359  adjustSize();
360  }
361 
362  // load the filter list (emits filterSelected())
363  mFilterList->loadFilterList(createDummyFilter);
364  mIgnoreFilterUpdates = false;
365 }
366 
367 void KMFilterDialog::createFilter(const QByteArray &field, const QString &value)
368 {
369  mFilterList->createFilter(field, value);
370 }
371 
372 void KMFilterDialog::accept()
373 {
374  if (mDoNotClose) {
375  mDoNotClose = false; // only abort current close attempt
376  } else {
377  QDialog::accept();
378  slotFinished();
379  }
380 }
381 
382 bool KMFilterDialog::event(QEvent *e)
383 {
384  // Close the bar when pressing Escape.
385  // Not using a QShortcut for this because it could conflict with
386  // window-global actions (e.g. Emil Sedgh binds Esc to "close tab").
387  // With a shortcut override we can catch this before it gets to kactions.
388  const bool shortCutOverride = (e->type() == QEvent::ShortcutOverride);
389  if (shortCutOverride || e->type() == QEvent::KeyPress) {
390  auto kev = static_cast<QKeyEvent *>(e);
391  if (kev->key() == Qt::Key_Escape) {
392  e->ignore();
393  return true;
394  }
395  }
396  return QDialog::event(e);
397 }
398 
399 void KMFilterDialog::slotApply()
400 {
401  mApplyButton->setEnabled(false);
402  mFilterList->slotApplied();
403 }
404 
405 void KMFilterDialog::slotFinished()
406 {
407  deleteLater();
408 }
409 
410 void KMFilterDialog::slotFolderChanged(const Akonadi::Collection &collection)
411 {
412  mRunNow->setEnabled(collection.isValid());
413 }
414 
415 void KMFilterDialog::slotRunFilters()
416 {
417  if (!mFolderRequester->collection().isValid()) {
418  KMessageBox::information(this, i18nc("@info", "Unable to apply this filter since there are no folders selected."), i18n("No folder selected."));
419  return;
420  }
421 
422  if (mApplyButton->isEnabled()) {
424  i18nc("@info",
425  "Some filters were changed and not saved yet. "
426  "You must save your filters before they can be applied."),
427  i18n("Filters changed."));
428  return;
429  }
431  const QStringList selectedFiltersId = mFilterList->selectedFilterId(requiredPart, mFolderRequester->collection().resource());
432  if (selectedFiltersId.isEmpty()) {
433  KMessageBox::information(this, i18nc("@info", "Unable to apply a filter since there are no filters currently selected."), i18n("No filters selected."));
434  return;
435  }
436  auto job = new Akonadi::ItemFetchJob(mFolderRequester->collection(), this);
437  job->setProperty("requiredPart", QVariant::fromValue(requiredPart));
438  job->setProperty("listFilters", QVariant::fromValue(selectedFiltersId));
439 
440  connect(job, &KJob::result, this, &KMFilterDialog::slotFetchItemsForFolderDone);
441 
442  mRunNow->setEnabled(false); // Disable it
443 }
444 
445 void KMFilterDialog::slotFetchItemsForFolderDone(KJob *job)
446 {
447  auto fjob = qobject_cast<Akonadi::ItemFetchJob *>(job);
448  Q_ASSERT(fjob);
449 
450  QStringList filtersId;
451  if (fjob->property("listFilters").isValid()) {
452  filtersId = fjob->property("listFilters").toStringList();
453  }
454 
456  if (fjob->property("requiredPart").isValid()) {
457  requiredPart = fjob->property("requiredPart").value<SearchRule::RequiredPart>();
458  }
459  Akonadi::Item::List items = fjob->items();
460  mRunNow->setEnabled(true);
461  MailCommon::FilterManager::instance()->filter(items, requiredPart, filtersId);
462 }
463 
464 void KMFilterDialog::slotSaveSize()
465 {
466  mFilterList->slotAccepted();
467  KConfigGroup myGroup(KernelIf->config(), "Geometry");
468  myGroup.writeEntry("filterDialogSize", size());
469  myGroup.sync();
470 }
471 
472 void KMFilterDialog::slotFilterSelected(MailFilter *aFilter)
473 {
474  Q_ASSERT(aFilter);
475  mIgnoreFilterUpdates = true;
476  mActionLister->setActionList(aFilter->actions());
477 
478  mAdvOptsGroup->setEnabled(true);
479 
480  mPatternEdit->setSearchPattern(aFilter->pattern());
481  mFilter = aFilter;
482 
483  qCDebug(MAILCOMMON_LOG) << "apply on inbound ==" << aFilter->applyOnInbound();
484  qCDebug(MAILCOMMON_LOG) << "apply on outbound ==" << aFilter->applyOnOutbound();
485  qCDebug(MAILCOMMON_LOG) << "apply before outbound == " << aFilter->applyBeforeOutbound();
486  qCDebug(MAILCOMMON_LOG) << "apply on explicit ==" << aFilter->applyOnExplicit();
487  qCDebug(MAILCOMMON_LOG) << "apply on all folders inboud == " << aFilter->applyOnAllFoldersInbound();
488 
489  // NOTE: setting these values activates the slot that sets them in
490  // the filter! So make sure we have the correct values _before_ we
491  // set the first one:
492  const bool applyOnIn = aFilter->applyOnInbound();
493  const bool applyOnForAll = aFilter->applicability() == MailFilter::All;
494  const bool applyOnTraditional = aFilter->applicability() == MailFilter::ButImap;
495  const bool applyBeforeOut = aFilter->applyBeforeOutbound();
496  const bool applyOnOut = aFilter->applyOnOutbound();
497  const bool applyOnAllFolders = aFilter->applyOnAllFoldersInbound();
498  const bool applyOnExplicit = aFilter->applyOnExplicit();
499  const bool stopHere = aFilter->stopProcessingHere();
500  const bool configureShortcut = aFilter->configureShortcut();
501  const bool configureToolbar = aFilter->configureToolbar();
502  const QString icon = aFilter->icon();
503  const QKeySequence shortcut(aFilter->shortcut());
504 
505  mApplyOnIn->setChecked(applyOnIn);
506  mApplyOnForAll->setEnabled(applyOnIn);
507  mApplyOnForTraditional->setEnabled(applyOnIn);
508  mApplyOnForChecked->setEnabled(applyOnIn);
509  mApplyOnForAll->setChecked(applyOnForAll);
510  mApplyOnAllFolders->setChecked(applyOnAllFolders);
511  mApplyOnForTraditional->setChecked(applyOnTraditional);
512  mApplyOnForChecked->setChecked(!applyOnForAll && !applyOnTraditional);
513  mAccountList->setEnabled(mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked());
514  slotUpdateAccountList();
515  mApplyBeforeOut->setChecked(applyBeforeOut);
516  mApplyOnOut->setChecked(applyOnOut);
517  mApplyOnCtrlJ->setChecked(applyOnExplicit);
518  mStopProcessingHere->setChecked(stopHere);
519  mConfigureShortcut->setChecked(configureShortcut);
520  mKeySeqWidget->setKeySequence(shortcut, KKeySequenceWidget::NoValidate);
521  mConfigureToolbar->setChecked(configureToolbar);
522  mFilterActionIconButton->setIcon(icon);
523  mIgnoreFilterUpdates = false;
524 }
525 
526 void KMFilterDialog::slotReset()
527 {
528  mFilter = nullptr;
529  mPatternEdit->reset();
530 
531  mActionLister->reset();
532  mAdvOptsGroup->setEnabled(false);
533  slotUpdateAccountList();
534 }
535 
536 void KMFilterDialog::slotUpdateFilter()
537 {
538  mPatternEdit->updateSearchPattern();
539  mActionLister->updateActionList();
540 }
541 
542 void KMFilterDialog::slotApplicabilityChanged()
543 {
544  if (mFilter) {
545  mFilter->setApplyOnInbound(mApplyOnIn->isChecked());
546  mFilter->setApplyBeforeOutbound(mApplyBeforeOut->isChecked());
547  mFilter->setApplyOnOutbound(mApplyOnOut->isChecked());
548  mFilter->setApplyOnExplicit(mApplyOnCtrlJ->isChecked());
549  mFilter->setApplyOnAllFoldersInbound(mApplyOnAllFolders->isChecked());
550  if (mApplyOnForAll->isChecked()) {
551  mFilter->setApplicability(MailFilter::All);
552  mFilter->clearApplyOnAccount();
553  } else if (mApplyOnForTraditional->isChecked()) {
554  mFilter->setApplicability(MailFilter::ButImap);
555  } else if (mApplyOnForChecked->isChecked()) {
556  mFilter->setApplicability(MailFilter::Checked);
557  }
558 
559  mApplyOnForAll->setEnabled(mApplyOnIn->isChecked());
560  mApplyOnForTraditional->setEnabled(mApplyOnIn->isChecked());
561  mApplyOnForChecked->setEnabled(mApplyOnIn->isChecked());
562  mAccountList->setEnabled(mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked());
563 
564  // Advanced tab functionality - Update list of accounts this filter applies to
565  if (!mApplyOnForAll->isChecked()) {
566  mAccountList->applyOnAccount(mFilter);
567  }
568 
569  // Enable the apply button
570  slotDialogUpdated();
571 
572  qCDebug(MAILCOMMON_LOG) << "Setting filter to be applied at" << (mFilter->applyOnInbound() ? "incoming " : "")
573  << (mFilter->applyOnOutbound() ? "outgoing " : "") << (mFilter->applyBeforeOutbound() ? "before_outgoing " : "")
574  << (mFilter->applyOnAllFoldersInbound() ? "all folders inboud " : "") << (mFilter->applyOnExplicit() ? "explicit CTRL-J" : "");
575  }
576 }
577 
578 void KMFilterDialog::slotApplicableAccountsChanged()
579 {
580  // Advanced tab functionality - Update list of accounts this filter applies to
581  if (mFilter && mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked()) {
582  QTreeWidgetItemIterator it(mAccountList);
583 
584  while (QTreeWidgetItem *item = *it) {
585  const QString id = item->text(2);
586  mFilter->setApplyOnAccount(id, item->checkState(0) == Qt::Checked);
587  ++it;
588  }
589 
590  // Enable the apply button
591  slotDialogUpdated();
592  }
593 }
594 
595 void KMFilterDialog::slotStopProcessingButtonToggled(bool aChecked)
596 {
597  if (mFilter) {
598  mFilter->setStopProcessingHere(aChecked);
599 
600  // Enable the apply button
601  slotDialogUpdated();
602  }
603 }
604 
605 void KMFilterDialog::slotShortcutChanged(const QKeySequence &newSeq)
606 {
607  if (mFilter) {
608  mKeySeqWidget->applyStealShortcut();
609  mFilter->setShortcut(newSeq);
610 
611  // Enable the apply button
612  slotDialogUpdated();
613  }
614 }
615 
616 void KMFilterDialog::slotConfigureToolbarButtonToggled(bool aChecked)
617 {
618  if (mFilter) {
619  mFilter->setConfigureToolbar(aChecked);
620  // Enable the apply button
621  slotDialogUpdated();
622  }
623 }
624 
625 void KMFilterDialog::slotFilterActionIconChanged(const QString &icon)
626 {
627  if (mFilter) {
628  mFilter->setIcon(icon);
629  // Enable the apply button
630  slotDialogUpdated();
631  }
632 }
633 
634 void KMFilterDialog::slotUpdateAccountList()
635 {
636  mAccountList->updateAccountList(mFilter);
637 }
638 
639 void KMFilterDialog::slotImportFilter(QAction *act)
640 {
641  if (act) {
642  importFilters(act->data().value<MailCommon::FilterImporterExporter::FilterType>());
643  }
644 }
645 
646 void KMFilterDialog::importFilters(MailCommon::FilterImporterExporter::FilterType type)
647 {
648  MailCommon::FilterImporterPathCache::self()->clear();
649  FilterImporterExporter importer(this);
650  bool canceled = false;
651  QVector<MailFilter *> filters = importer.importFilters(canceled, type);
652  if (canceled) {
653  return;
654  }
655 
656  if (filters.isEmpty()) {
657  KMessageBox::information(this, i18n("No filter was imported."));
658  return;
659  }
660  QStringList listOfFilter;
662 
663  for (QVector<MailFilter *>::ConstIterator it = filters.constBegin(); it != end; ++it) {
664  mFilterList->appendFilter(*it); // no need to deep copy, ownership passes to the list
665  listOfFilter << (*it)->name();
666  }
667 
668  KMessageBox::informationList(this, i18n("Filters which were imported:"), listOfFilter);
669 }
670 
671 void KMFilterDialog::slotExportFilters()
672 {
673  bool wasCanceled = false;
674  const QVector<MailFilter *> filters = mFilterList->filtersForSaving(false, wasCanceled);
675  if (filters.isEmpty()) {
676  KMessageBox::information(this, i18n("Any filter found."));
677  return;
678  }
679  if (wasCanceled) {
680  qDeleteAll(filters);
681  return;
682  }
683  FilterImporterExporter exporter(this);
684  exporter.exportFilters(filters);
685 }
686 
687 void KMFilterDialog::slotDisableAccept()
688 {
689  mDoNotClose = true;
690 }
691 
692 void KMFilterDialog::slotDialogUpdated()
693 {
694  qCDebug(MAILCOMMON_LOG) << "Detected a change in data bound to the dialog!";
695  if (!mIgnoreFilterUpdates) {
696  mApplyButton->setEnabled(true);
697  }
698 }
699 
700 void KMFilterDialog::slotExportAsSieveScript()
701 {
702  if (mApplyButton->isEnabled()) {
704  i18nc("@info",
705  "Some filters were changed and not saved yet.<br>"
706  "You must save your filters before they can be exported."),
707  i18n("Filters changed."));
708  return;
709  }
711  i18n("We cannot convert all KMail filters to sieve scripts but we can try :)"),
712  i18n("Convert KMail filters to sieve scripts"));
713  bool wasCanceled = false;
714  const QVector<MailFilter *> filters = mFilterList->filtersForSaving(false, wasCanceled);
715  if (filters.isEmpty()) {
716  return;
717  }
718  if (!wasCanceled) {
719  QPointer<FilterSelectionDialog> dlg = new FilterSelectionDialog(this);
720  dlg->setFilters(filters);
721  if (dlg->exec() == QDialog::Accepted) {
722  QVector<MailFilter *> lst = dlg->selectedFilters();
723  if (!lst.isEmpty()) {
724  FilterConvertToSieve convert(lst);
725  convert.convert();
726  qDeleteAll(lst);
727  } else {
728  KMessageBox::information(this, i18n("No filters selected."), i18n("Convert KMail filters to sieve scripts"));
729  }
730  }
731  delete dlg;
732  } else {
733  qDeleteAll(filters);
734  }
735 }
736 
737 void KMFilterDialog::slotHelp()
738 {
739  PimCommon::Util::invokeHelp(QStringLiteral("kmail2/filters.html"));
740 }
Utility class that provides persisting of filters to/from KConfig.
void triggered(QAction *action)
AlignTop
bool isEmpty() const const
ShortcutOverride
const QList< QKeySequence > & shortcut(StandardShortcut id)
virtual void reject()
void setShortcut(const QKeySequence &key)
QVariant fromValue(const T &value)
void result(KJob *job)
T value() const const
void clicked(bool checked)
virtual bool event(QEvent *event) override
QIcon fromTheme(const QString &name)
QVector::const_iterator constEnd() const const
A container widget for a list of FilterActionWidgets.
The MailFilter class.
Definition: mailfilter.h:30
bool applyOnOutbound() const
Definition: mailfilter.cpp:191
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void toggled(bool checked)
const QKeySequence & shortcut() const
Definition: mailfilter.cpp:357
QString i18n(const char *text, const TYPE &arg...)
bool applyBeforeOutbound() const
Definition: mailfilter.cpp:196
RequiredPart
Possible required parts.
Definition: searchrule.h:68
static FilterManager * instance()
Returns the global filter manager object.
bool configureToolbar() const
Definition: mailfilter.cpp:342
virtual void accept()
void keySequenceChanged(const QKeySequence &seq)
bool isEmpty() const const
bool applyOnAllFoldersInbound() const
Returns whether the filter should be applied on inbound emails in all folders, not just Inbox.
Definition: mailfilter.cpp:226
Key_Return
void filter(const Akonadi::Item &item, const QString &identifier, const QString &resourceId) const
Apply filters interface.
bool configureShortcut() const
Definition: mailfilter.cpp:332
QVector< FilterAction * > * actions()
Provides a reference to the internal action list.
Definition: mailfilter.cpp:161
T convert(const QVariant &value)
QString icon() const
Definition: mailfilter.cpp:367
QVariant data() const const
void iconChanged(const QString &icon)
void triggered(bool checked)
SearchPattern * pattern()
Provides a reference to the internal pattern.
Definition: mailfilter.cpp:171
bool applyOnInbound() const
Definition: mailfilter.cpp:206
QEvent::Type type() const const
void setChildrenCollapsible(bool)
void ignore()
AccountType applicability() const
Definition: mailfilter.cpp:236
bool applyOnExplicit() const
Definition: mailfilter.cpp:216
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void setDefault(bool)
bool isValid() const
void addLayout(QLayout *layout, int stretch)
void information(QWidget *parent, const QString &text, const QString &title=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
QVector::const_iterator constBegin() const const
void informationList(QWidget *parent, const QString &text, const QStringList &strlist, const QString &title=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
void setFocus()
const QList< QKeySequence > & end()
The filter dialog.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Sep 24 2022 03:58:15 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.