File indexing completed on 2024-09-22 04:50:05

0001 /*
0002   Filter Dialog
0003 
0004   SPDX-FileCopyrightText: Marc Mutz <mutz@kde.org>
0005   SPDX-FileCopyrightText: 2011-2024 Laurent Montel <montel@kde.org>
0006 
0007   based upon work by Stefan Taferner <taferner@kde.org>
0008 
0009   SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 
0012 #include "kmfilterdialog.h"
0013 #include "kmfilterlistbox.h"
0014 #include "mailcommon_debug.h"
0015 
0016 #include "filteractions/filteractionwidget.h"
0017 #include "filterimporterpathcache.h"
0018 #include "filterselectiondialog.h"
0019 #include "kmfilteraccountlist.h"
0020 using MailCommon::FilterImporterExporter;
0021 #include "filterconverter/filterconverttosieve.h"
0022 #include "filtermanager.h"
0023 #include "folder/folderrequester.h"
0024 #include "kernel/mailkernel.h"
0025 #include "search/searchpatternedit.h"
0026 #include <PimCommon/PimUtil>
0027 
0028 #include <Akonadi/ItemFetchJob>
0029 
0030 #include <KConfigGroup>
0031 
0032 #include <KIconButton>
0033 #include <KIconLoader>
0034 #include <KJob>
0035 #include <KKeySequenceWidget>
0036 #include <KListWidgetSearchLine>
0037 #include <KLocalizedString>
0038 #include <KMessageBox>
0039 #include <QIcon>
0040 #include <QPushButton>
0041 #include <QTabWidget>
0042 
0043 #include <QButtonGroup>
0044 #include <QCheckBox>
0045 #include <QDialogButtonBox>
0046 #include <QFormLayout>
0047 #include <QGridLayout>
0048 #include <QGroupBox>
0049 #include <QHBoxLayout>
0050 #include <QKeyEvent>
0051 #include <QLabel>
0052 #include <QMenu>
0053 #include <QPointer>
0054 #include <QRadioButton>
0055 #include <QShortcut>
0056 #include <QSplitter>
0057 #include <QTreeWidget>
0058 #include <QVBoxLayout>
0059 
0060 Q_DECLARE_METATYPE(MailCommon::FilterImporterExporter::FilterType)
0061 using namespace MailCommon;
0062 
0063 //=============================================================================
0064 //
0065 // class KMFilterDialog (the filter dialog)
0066 //
0067 //=============================================================================
0068 
0069 KMFilterDialog::KMFilterDialog(const QList<KActionCollection *> &actionCollection, QWidget *parent, bool createDummyFilter)
0070     : QDialog(parent)
0071 {
0072     setWindowTitle(i18nc("@title:window", "Filter Rules"));
0073     auto mainLayout = new QVBoxLayout(this);
0074 
0075     auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Apply, this);
0076     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0077     okButton->setDefault(true);
0078     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0079     auto user1Button = new QPushButton(this);
0080     buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole);
0081     auto user2Button = new QPushButton(this);
0082     buttonBox->addButton(user2Button, QDialogButtonBox::ActionRole);
0083     auto user3Button = new QPushButton(this);
0084     buttonBox->addButton(user3Button, QDialogButtonBox::ActionRole);
0085     connect(buttonBox, &QDialogButtonBox::accepted, this, &KMFilterDialog::accept);
0086     connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0087     connect(buttonBox->button(QDialogButtonBox::Help), &QAbstractButton::clicked, this, &KMFilterDialog::slotHelp);
0088     setModal(false);
0089     okButton->setFocus();
0090     user1Button->setText(i18n("Import..."));
0091     user1Button->setIcon(QIcon::fromTheme("document-import"));
0092     user2Button->setText(i18n("Export..."));
0093     user2Button->setIcon(QIcon::fromTheme("document-export"));
0094     user3Button->setText(i18n("Convert to..."));
0095     user3Button->setIcon(QIcon::fromTheme("document-save-as"));
0096     auto menu = new QMenu(this);
0097 
0098     auto act = new QAction(i18n("KMail filters"), this);
0099     act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::KMailFilter));
0100     menu->addAction(act);
0101 
0102     act = new QAction(i18n("Thunderbird filters"), this);
0103     act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::ThunderBirdFilter));
0104     menu->addAction(act);
0105 
0106     act = new QAction(i18n("Evolution filters"), this);
0107     act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::EvolutionFilter));
0108     menu->addAction(act);
0109 
0110     act = new QAction(i18n("Sylpheed filters"), this);
0111     act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::SylpheedFilter));
0112     menu->addAction(act);
0113 
0114     act = new QAction(i18n("Procmail filters"), this);
0115     act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::ProcmailFilter));
0116     menu->addAction(act);
0117 
0118     act = new QAction(i18n("Balsa filters"), this);
0119     act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::BalsaFilter));
0120     menu->addAction(act);
0121 
0122     act = new QAction(i18n("Claws Mail filters"), this);
0123     act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::ClawsMailFilter));
0124     menu->addAction(act);
0125 
0126     act = new QAction(i18n("Icedove Mail filters"), this);
0127     act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::IcedoveFilter));
0128     menu->addAction(act);
0129 
0130     connect(menu, &QMenu::triggered, this, &KMFilterDialog::slotImportFilter);
0131 
0132     act = new QAction(i18n("Gmail filters"), this);
0133     act->setData(QVariant::fromValue(MailCommon::FilterImporterExporter::GmailFilter));
0134     menu->addAction(act);
0135 
0136     user1Button->setMenu(menu);
0137 
0138     menu = new QMenu(this);
0139 
0140     act = new QAction(i18n("Sieve script"), this);
0141     connect(act, &QAction::triggered, this, &KMFilterDialog::slotExportAsSieveScript);
0142     menu->addAction(act);
0143     user3Button->setMenu(menu);
0144 
0145     connect(user2Button, &QAbstractButton::clicked, this, &KMFilterDialog::slotExportFilters);
0146     mApplyButton = buttonBox->button(QDialogButtonBox::Apply);
0147     mApplyButton->setEnabled(false);
0148 
0149     auto w = new QWidget(this);
0150     mainLayout->addWidget(w);
0151     mainLayout->addWidget(buttonBox);
0152     auto topVLayout = new QVBoxLayout(w);
0153     topVLayout->setContentsMargins({});
0154     auto topLayout = new QHBoxLayout;
0155     topVLayout->addLayout(topLayout);
0156     topLayout->setContentsMargins({});
0157 
0158     auto splitter = new QSplitter;
0159     splitter->setChildrenCollapsible(false);
0160     topLayout->addWidget(splitter);
0161 
0162     mFilterList = new KMFilterListBox(i18n("Available Filters"), this);
0163     splitter->addWidget(mFilterList);
0164     auto tabWidget = new QTabWidget(this);
0165     splitter->addWidget(tabWidget);
0166 
0167     auto page1 = new QWidget(tabWidget);
0168     tabWidget->addTab(page1, i18nc("General mail filter settings.", "General"));
0169     auto hbl = new QHBoxLayout(page1);
0170 
0171     auto page2 = new QWidget(tabWidget);
0172     tabWidget->addTab(page2, i18nc("Advanced mail filter settings.", "Advanced"));
0173     auto vbl2 = new QVBoxLayout(page2);
0174 
0175     auto vbl = new QVBoxLayout();
0176     hbl->addLayout(vbl);
0177     hbl->setStretchFactor(vbl, 2);
0178 
0179     mPatternEdit = new MailCommon::SearchPatternEdit(page1, MailCommon::SearchPatternEdit::MatchAllMessages);
0180     vbl->addWidget(mPatternEdit, 0, Qt::AlignTop);
0181 
0182     auto actionLabel = new QLabel(i18n("Filter actions:"), page1);
0183     vbl->addWidget(actionLabel);
0184 
0185     mActionLister = new MailCommon::FilterActionWidgetLister(page1);
0186     vbl->addWidget(mActionLister);
0187 
0188     mAdvOptsGroup = new QGroupBox(QString(), page2);
0189     mAdvOptsGroup->setFlat(true);
0190     mAdvOptsGroup->setContentsMargins({});
0191     {
0192         auto gl = new QGridLayout();
0193         mApplyOnIn = new QCheckBox(i18n("Apply this filter to incoming messages:"), mAdvOptsGroup);
0194         gl->addWidget(mApplyOnIn, 0, 0);
0195 
0196         auto radioGroupWidget = new QWidget(page2);
0197         radioGroupWidget->setContentsMargins(20, 0, 0, 0);
0198         gl->addWidget(radioGroupWidget, 1, 0);
0199         auto vbl3 = new QVBoxLayout(radioGroupWidget);
0200 
0201         auto bg = new QButtonGroup(mAdvOptsGroup);
0202 
0203         mApplyOnForAll = new QRadioButton(i18n("From all accounts"), radioGroupWidget);
0204         bg->addButton(mApplyOnForAll);
0205         vbl3->addWidget(mApplyOnForAll);
0206 
0207         mApplyOnForTraditional = new QRadioButton(i18n("From all but online IMAP accounts"), radioGroupWidget);
0208         bg->addButton(mApplyOnForTraditional);
0209         vbl3->addWidget(mApplyOnForTraditional);
0210 
0211         mApplyOnForChecked = new QRadioButton(i18n("From selected accounts only"), radioGroupWidget);
0212         bg->addButton(mApplyOnForChecked);
0213         vbl3->addWidget(mApplyOnForChecked);
0214         vbl3->addStretch(100);
0215 
0216         mAccountList = new KMFilterAccountList(mAdvOptsGroup);
0217         gl->addWidget(mAccountList, 0, 1, 4, 3);
0218 
0219         mApplyOnOut = new QCheckBox(i18n("Apply this filter to &sent messages"), mAdvOptsGroup);
0220         mApplyOnOut->setToolTip(
0221             i18n("<p>The filter will be triggered <b>after</b> the message is sent "
0222                  "and it will only affect the local copy of the message.</p>"
0223                  "<p>If the recipient's copy also needs to be modified, "
0224                  "please use \"Apply this filter <b>before</b> sending messages\".</p>"));
0225         gl->addWidget(mApplyOnOut, 5, 0, 1, 4);
0226 
0227         mApplyBeforeOut = new QCheckBox(i18n("Apply this filter &before sending messages"), mAdvOptsGroup);
0228         mApplyBeforeOut->setToolTip(
0229             i18n("<p>The filter will be triggered <b>before</b> the message is sent "
0230                  "and it will affect both the local copy and the sent copy of the message.</p>"
0231                  "<p>This is required if the recipient's copy also needs to be modified.</p>"));
0232         gl->addWidget(mApplyBeforeOut, 6, 0, 1, 4);
0233 
0234         mApplyOnCtrlJ = new QCheckBox(i18n("Apply this filter on manual &filtering"), mAdvOptsGroup);
0235         gl->addWidget(mApplyOnCtrlJ, 7, 0, 1, 4);
0236 
0237         mApplyOnAllFolders = new QCheckBox(i18n("Apply this filter on inbound emails in all folders"), mAdvOptsGroup);
0238         mApplyOnAllFolders->setToolTip(
0239             i18n("<p>The filter will be applied on inbound emails from all folders "
0240                  "belonging to all accounts selected above. This is useful when using local filters "
0241                  "with IMAP accounts where new emails may have already been moved to different folders "
0242                  "by server-side filters.</p>"));
0243         gl->addWidget(mApplyOnAllFolders, 8, 0, 1, 4);
0244 
0245         mStopProcessingHere = new QCheckBox(i18n("If this filter &matches, stop processing here"), mAdvOptsGroup);
0246         gl->addWidget(mStopProcessingHere, 9, 0, 1, 4);
0247 
0248         mConfigureShortcut = new QCheckBox(i18n("Add this filter to the Apply Filter menu"), mAdvOptsGroup);
0249         gl->addWidget(mConfigureShortcut, 10, 0, 1, 2);
0250 
0251         mInMenuWidget = new QWidget(mAdvOptsGroup);
0252         mInMenuWidget->setContentsMargins(20, 0, 0, 0);
0253         gl->addWidget(mInMenuWidget, 11, 0, 1, 4);
0254         auto inMenuLayout = new QFormLayout(mInMenuWidget);
0255 
0256         connect(mConfigureShortcut, &QCheckBox::toggled, this, [this](bool aChecked) {
0257             if (mFilter) {
0258                 mFilter->setConfigureShortcut(aChecked);
0259                 mInMenuWidget->setEnabled(aChecked);
0260 
0261                 // Enable the apply button
0262                 slotDialogUpdated();
0263             }
0264         });
0265 
0266         mConfigureToolbar = new QCheckBox(i18n("Additionally add this filter to the toolbar"), mInMenuWidget);
0267         inMenuLayout->addRow(mConfigureToolbar);
0268 
0269         mKeySeqWidget = new KKeySequenceWidget(mInMenuWidget);
0270         mKeySeqWidget->setObjectName(QLatin1StringView("FilterShortcutSelector"));
0271         mKeySeqWidget->setModifierlessAllowed(true);
0272         mKeySeqWidget->setCheckActionCollections(actionCollection);
0273         inMenuLayout->addRow(i18n("Shortcut:"), mKeySeqWidget);
0274 
0275         mFilterActionIconButton = new KIconButton(mInMenuWidget);
0276         mFilterActionIconButton->setIconType(KIconLoader::NoGroup, KIconLoader::Action, false);
0277         mFilterActionIconButton->setIconSize(16);
0278         mFilterActionIconButton->setIcon(QIcon::fromTheme(QStringLiteral("system-run")));
0279         inMenuLayout->addRow(i18n("Icon for this filter:"), mFilterActionIconButton);
0280 
0281         mAdvOptsGroup->setLayout(gl);
0282         mInMenuWidget->setEnabled(false);
0283     }
0284     vbl2->addWidget(mAdvOptsGroup, 0, Qt::AlignTop);
0285 
0286     auto applySpecificFiltersLayout = new QHBoxLayout;
0287     auto lab = new QLabel(i18n("Run selected filter(s) on: "), this);
0288     applySpecificFiltersLayout->addWidget(lab);
0289     mFolderRequester = new MailCommon::FolderRequester(this);
0290     mFolderRequester->setNotAllowToCreateNewFolder(true);
0291     applySpecificFiltersLayout->addWidget(mFolderRequester);
0292     connect(mFolderRequester, &FolderRequester::folderChanged, this, &KMFilterDialog::slotFolderChanged);
0293     mRunNow = new QPushButton(i18n("Run Now"), this);
0294     mRunNow->setEnabled(false);
0295     applySpecificFiltersLayout->addWidget(mRunNow);
0296     connect(mRunNow, &QPushButton::clicked, this, &KMFilterDialog::slotRunFilters);
0297     topVLayout->addLayout(applySpecificFiltersLayout);
0298     // spacer:
0299     vbl->addStretch(1);
0300 
0301     // load the filter parts into the edit widgets
0302     connect(mFilterList, &KMFilterListBox::filterSelected, this, &KMFilterDialog::slotFilterSelected);
0303 
0304     // transfer changes from the 'Apply this filter on...'
0305     // combo box to the filter
0306     connect(mApplyOnIn, &QCheckBox::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
0307     connect(mApplyOnForAll, &QRadioButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
0308     connect(mApplyOnForTraditional, &QAbstractButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
0309     connect(mApplyOnForChecked, &QAbstractButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
0310     connect(mApplyBeforeOut, &QAbstractButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
0311     connect(mApplyOnAllFolders, &QAbstractButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
0312     connect(mApplyOnOut, &QAbstractButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
0313     connect(mApplyOnCtrlJ, &QAbstractButton::clicked, this, &KMFilterDialog::slotApplicabilityChanged);
0314     connect(mAccountList, &KMFilterAccountList::itemChanged, this, &KMFilterDialog::slotApplicableAccountsChanged);
0315 
0316     // transfer changes from the 'stop processing here'
0317     // check box to the filter
0318     connect(mStopProcessingHere, &QCheckBox::toggled, this, &KMFilterDialog::slotStopProcessingButtonToggled);
0319 
0320     connect(mKeySeqWidget, &KKeySequenceWidget::keySequenceChanged, this, &KMFilterDialog::slotShortcutChanged);
0321 
0322     connect(mConfigureToolbar, &QCheckBox::toggled, this, &KMFilterDialog::slotConfigureToolbarButtonToggled);
0323 
0324     connect(mFilterActionIconButton, &KIconButton::iconChanged, this, &KMFilterDialog::slotFilterActionIconChanged);
0325 
0326     // reset all widgets here
0327     connect(mFilterList, &KMFilterListBox::resetWidgets, this, &KMFilterDialog::slotReset);
0328 
0329     connect(mFilterList, &KMFilterListBox::applyWidgets, this, &KMFilterDialog::slotUpdateFilter);
0330 
0331     // support auto-naming the filter
0332     connect(mPatternEdit, &MailCommon::SearchPatternEdit::maybeNameChanged, mFilterList, &KMFilterListBox::slotUpdateFilterName);
0333 
0334     // save filters on 'Apply' or 'OK'
0335     connect(mApplyButton, &QAbstractButton::clicked, this, &KMFilterDialog::slotApply);
0336 
0337     // save dialog size on 'OK'
0338     connect(okButton, &QAbstractButton::clicked, this, &KMFilterDialog::slotSaveSize);
0339 
0340     // destruct the dialog on close and Cancel
0341     connect(buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, this, &KMFilterDialog::slotFinished);
0342 
0343     // disable closing when user wants to continue editing
0344     connect(mFilterList, &KMFilterListBox::abortClosing, this, &KMFilterDialog::slotDisableAccept);
0345 
0346     connect(mFilterList, &KMFilterListBox::filterCreated, this, &KMFilterDialog::slotDialogUpdated);
0347     connect(mFilterList, &KMFilterListBox::filterRemoved, this, &KMFilterDialog::slotDialogUpdated);
0348     connect(mFilterList, &KMFilterListBox::filterUpdated, this, &KMFilterDialog::slotDialogUpdated);
0349     connect(mFilterList, &KMFilterListBox::filterOrderAltered, this, &KMFilterDialog::slotDialogUpdated);
0350     connect(mPatternEdit, &MailCommon::SearchPatternEdit::patternChanged, this, &KMFilterDialog::slotDialogUpdated);
0351     connect(mActionLister, qOverload<QWidget *>(&FilterActionWidgetLister::widgetAdded), this, &KMFilterDialog::slotDialogUpdated);
0352     connect(mActionLister, qOverload<QWidget *>(&FilterActionWidgetLister::widgetRemoved), this, &KMFilterDialog::slotDialogUpdated);
0353     connect(mActionLister, &MailCommon::FilterActionWidgetLister::filterModified, this, &KMFilterDialog::slotDialogUpdated);
0354     connect(mActionLister, &MailCommon::FilterActionWidgetLister::clearWidgets, this, &KMFilterDialog::slotDialogUpdated);
0355     KConfigGroup myGroup(KSharedConfig::openStateConfig(), QStringLiteral("Geometry"));
0356     const QSize size = myGroup.readEntry("filterDialogSize", QSize());
0357     if (size != QSize()) {
0358         resize(size);
0359     } else {
0360         adjustSize();
0361     }
0362 
0363     // load the filter list (emits filterSelected())
0364     mFilterList->loadFilterList(createDummyFilter);
0365     mIgnoreFilterUpdates = false;
0366 }
0367 
0368 void KMFilterDialog::createFilter(const QByteArray &field, const QString &value)
0369 {
0370     mFilterList->createFilter(field, value);
0371 }
0372 
0373 void KMFilterDialog::accept()
0374 {
0375     if (mDoNotClose) {
0376         mDoNotClose = false; // only abort current close attempt
0377     } else {
0378         QDialog::accept();
0379         slotFinished();
0380     }
0381 }
0382 
0383 bool KMFilterDialog::event(QEvent *e)
0384 {
0385     // Close the bar when pressing Escape.
0386     // Not using a QShortcut for this because it could conflict with
0387     // window-global actions (e.g. Emil Sedgh binds Esc to "close tab").
0388     // With a shortcut override we can catch this before it gets to kactions.
0389     const bool shortCutOverride = (e->type() == QEvent::ShortcutOverride);
0390     if (shortCutOverride || e->type() == QEvent::KeyPress) {
0391         auto kev = static_cast<QKeyEvent *>(e);
0392         if (kev->key() == Qt::Key_Escape) {
0393             e->ignore();
0394             return true;
0395         }
0396     }
0397     return QDialog::event(e);
0398 }
0399 
0400 void KMFilterDialog::slotApply()
0401 {
0402     mApplyButton->setEnabled(false);
0403     mFilterList->slotApplied();
0404 }
0405 
0406 void KMFilterDialog::slotFinished()
0407 {
0408     deleteLater();
0409 }
0410 
0411 void KMFilterDialog::slotFolderChanged(const Akonadi::Collection &collection)
0412 {
0413     mRunNow->setEnabled(collection.isValid());
0414 }
0415 
0416 void KMFilterDialog::slotRunFilters()
0417 {
0418     if (!mFolderRequester->collection().isValid()) {
0419         KMessageBox::information(this, i18nc("@info", "Unable to apply this filter since there are no folders selected."), i18n("No folder selected."));
0420         return;
0421     }
0422 
0423     if (mApplyButton->isEnabled()) {
0424         KMessageBox::information(this,
0425                                  i18nc("@info",
0426                                        "Some filters were changed and not saved yet. "
0427                                        "You must save your filters before they can be applied."),
0428                                  i18n("Filters changed."));
0429         return;
0430     }
0431     SearchRule::RequiredPart requiredPart = SearchRule::Envelope;
0432     const QStringList selectedFiltersId = mFilterList->selectedFilterId(requiredPart, mFolderRequester->collection().resource());
0433     if (selectedFiltersId.isEmpty()) {
0434         KMessageBox::information(this, i18nc("@info", "Unable to apply a filter since there are no filters currently selected."), i18n("No filters selected."));
0435         return;
0436     }
0437     auto job = new Akonadi::ItemFetchJob(mFolderRequester->collection(), this);
0438     job->setProperty("requiredPart", QVariant::fromValue(requiredPart));
0439     job->setProperty("listFilters", QVariant::fromValue(selectedFiltersId));
0440 
0441     connect(job, &KJob::result, this, &KMFilterDialog::slotFetchItemsForFolderDone);
0442 
0443     mRunNow->setEnabled(false); // Disable it
0444 }
0445 
0446 void KMFilterDialog::slotFetchItemsForFolderDone(KJob *job)
0447 {
0448     auto fjob = qobject_cast<Akonadi::ItemFetchJob *>(job);
0449     Q_ASSERT(fjob);
0450 
0451     QStringList filtersId;
0452     if (fjob->property("listFilters").isValid()) {
0453         filtersId = fjob->property("listFilters").toStringList();
0454     }
0455 
0456     SearchRule::RequiredPart requiredPart = SearchRule::Envelope;
0457     if (fjob->property("requiredPart").isValid()) {
0458         requiredPart = fjob->property("requiredPart").value<SearchRule::RequiredPart>();
0459     }
0460     Akonadi::Item::List items = fjob->items();
0461     mRunNow->setEnabled(true);
0462     MailCommon::FilterManager::instance()->filter(items, requiredPart, filtersId);
0463 }
0464 
0465 void KMFilterDialog::slotSaveSize()
0466 {
0467     mFilterList->slotAccepted();
0468     KConfigGroup myGroup(KSharedConfig::openStateConfig(), QStringLiteral("Geometry"));
0469     myGroup.writeEntry("filterDialogSize", size());
0470     myGroup.sync();
0471 }
0472 
0473 void KMFilterDialog::slotFilterSelected(MailFilter *aFilter)
0474 {
0475     Q_ASSERT(aFilter);
0476     mIgnoreFilterUpdates = true;
0477     mActionLister->setActionList(aFilter->actions());
0478 
0479     mAdvOptsGroup->setEnabled(true);
0480 
0481     mPatternEdit->setSearchPattern(aFilter->pattern());
0482     mFilter = aFilter;
0483 
0484     qCDebug(MAILCOMMON_LOG) << "apply on inbound ==" << aFilter->applyOnInbound();
0485     qCDebug(MAILCOMMON_LOG) << "apply on outbound ==" << aFilter->applyOnOutbound();
0486     qCDebug(MAILCOMMON_LOG) << "apply before outbound == " << aFilter->applyBeforeOutbound();
0487     qCDebug(MAILCOMMON_LOG) << "apply on explicit ==" << aFilter->applyOnExplicit();
0488     qCDebug(MAILCOMMON_LOG) << "apply on all folders inboud == " << aFilter->applyOnAllFoldersInbound();
0489 
0490     // NOTE: setting these values activates the slot that sets them in
0491     // the filter! So make sure we have the correct values _before_ we
0492     // set the first one:
0493     const bool applyOnIn = aFilter->applyOnInbound();
0494     const bool applyOnForAll = aFilter->applicability() == MailFilter::All;
0495     const bool applyOnTraditional = aFilter->applicability() == MailFilter::ButImap;
0496     const bool applyBeforeOut = aFilter->applyBeforeOutbound();
0497     const bool applyOnOut = aFilter->applyOnOutbound();
0498     const bool applyOnAllFolders = aFilter->applyOnAllFoldersInbound();
0499     const bool applyOnExplicit = aFilter->applyOnExplicit();
0500     const bool stopHere = aFilter->stopProcessingHere();
0501     const bool configureShortcut = aFilter->configureShortcut();
0502     const bool configureToolbar = aFilter->configureToolbar();
0503     const QString icon = aFilter->icon();
0504     const QKeySequence shortcut(aFilter->shortcut());
0505 
0506     mApplyOnIn->setChecked(applyOnIn);
0507     mApplyOnForAll->setEnabled(applyOnIn);
0508     mApplyOnForTraditional->setEnabled(applyOnIn);
0509     mApplyOnForChecked->setEnabled(applyOnIn);
0510     mApplyOnForAll->setChecked(applyOnForAll);
0511     mApplyOnAllFolders->setChecked(applyOnAllFolders);
0512     mApplyOnForTraditional->setChecked(applyOnTraditional);
0513     mApplyOnForChecked->setChecked(!applyOnForAll && !applyOnTraditional);
0514     mAccountList->setEnabled(mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked());
0515     slotUpdateAccountList();
0516     mApplyBeforeOut->setChecked(applyBeforeOut);
0517     mApplyOnOut->setChecked(applyOnOut);
0518     mApplyOnCtrlJ->setChecked(applyOnExplicit);
0519     mStopProcessingHere->setChecked(stopHere);
0520     mConfigureShortcut->setChecked(configureShortcut);
0521     mKeySeqWidget->setKeySequence(shortcut, KKeySequenceWidget::NoValidate);
0522     mConfigureToolbar->setChecked(configureToolbar);
0523     mFilterActionIconButton->setIcon(icon);
0524     mIgnoreFilterUpdates = false;
0525 }
0526 
0527 void KMFilterDialog::slotReset()
0528 {
0529     mFilter = nullptr;
0530     mPatternEdit->reset();
0531 
0532     mActionLister->reset();
0533     mAdvOptsGroup->setEnabled(false);
0534     slotUpdateAccountList();
0535 }
0536 
0537 void KMFilterDialog::slotUpdateFilter()
0538 {
0539     mPatternEdit->updateSearchPattern();
0540     mActionLister->updateActionList();
0541 }
0542 
0543 void KMFilterDialog::slotApplicabilityChanged()
0544 {
0545     if (mFilter) {
0546         mFilter->setApplyOnInbound(mApplyOnIn->isChecked());
0547         mFilter->setApplyBeforeOutbound(mApplyBeforeOut->isChecked());
0548         mFilter->setApplyOnOutbound(mApplyOnOut->isChecked());
0549         mFilter->setApplyOnExplicit(mApplyOnCtrlJ->isChecked());
0550         mFilter->setApplyOnAllFoldersInbound(mApplyOnAllFolders->isChecked());
0551         if (mApplyOnForAll->isChecked()) {
0552             mFilter->setApplicability(MailFilter::All);
0553             mFilter->clearApplyOnAccount();
0554         } else if (mApplyOnForTraditional->isChecked()) {
0555             mFilter->setApplicability(MailFilter::ButImap);
0556         } else if (mApplyOnForChecked->isChecked()) {
0557             mFilter->setApplicability(MailFilter::Checked);
0558         }
0559 
0560         mApplyOnForAll->setEnabled(mApplyOnIn->isChecked());
0561         mApplyOnForTraditional->setEnabled(mApplyOnIn->isChecked());
0562         mApplyOnForChecked->setEnabled(mApplyOnIn->isChecked());
0563         mAccountList->setEnabled(mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked());
0564 
0565         // Advanced tab functionality - Update list of accounts this filter applies to
0566         if (!mApplyOnForAll->isChecked()) {
0567             mAccountList->applyOnAccount(mFilter);
0568         }
0569 
0570         // Enable the apply button
0571         slotDialogUpdated();
0572 
0573         qCDebug(MAILCOMMON_LOG) << "Setting filter to be applied at" << (mFilter->applyOnInbound() ? "incoming " : "")
0574                                 << (mFilter->applyOnOutbound() ? "outgoing " : "") << (mFilter->applyBeforeOutbound() ? "before_outgoing " : "")
0575                                 << (mFilter->applyOnAllFoldersInbound() ? "all folders inboud " : "") << (mFilter->applyOnExplicit() ? "explicit CTRL-J" : "");
0576     }
0577 }
0578 
0579 void KMFilterDialog::slotApplicableAccountsChanged()
0580 {
0581     // Advanced tab functionality - Update list of accounts this filter applies to
0582     if (mFilter && mApplyOnForChecked->isEnabled() && mApplyOnForChecked->isChecked()) {
0583         QTreeWidgetItemIterator it(mAccountList);
0584 
0585         while (QTreeWidgetItem *item = *it) {
0586             const QString id = item->text(2);
0587             mFilter->setApplyOnAccount(id, item->checkState(0) == Qt::Checked);
0588             ++it;
0589         }
0590 
0591         // Enable the apply button
0592         slotDialogUpdated();
0593     }
0594 }
0595 
0596 void KMFilterDialog::slotStopProcessingButtonToggled(bool aChecked)
0597 {
0598     if (mFilter) {
0599         mFilter->setStopProcessingHere(aChecked);
0600 
0601         // Enable the apply button
0602         slotDialogUpdated();
0603     }
0604 }
0605 
0606 void KMFilterDialog::slotShortcutChanged(const QKeySequence &newSeq)
0607 {
0608     if (mFilter) {
0609         mKeySeqWidget->applyStealShortcut();
0610         mFilter->setShortcut(newSeq);
0611 
0612         // Enable the apply button
0613         slotDialogUpdated();
0614     }
0615 }
0616 
0617 void KMFilterDialog::slotConfigureToolbarButtonToggled(bool aChecked)
0618 {
0619     if (mFilter) {
0620         mFilter->setConfigureToolbar(aChecked);
0621         // Enable the apply button
0622         slotDialogUpdated();
0623     }
0624 }
0625 
0626 void KMFilterDialog::slotFilterActionIconChanged(const QString &icon)
0627 {
0628     if (mFilter) {
0629         mFilter->setIcon(icon);
0630         // Enable the apply button
0631         slotDialogUpdated();
0632     }
0633 }
0634 
0635 void KMFilterDialog::slotUpdateAccountList()
0636 {
0637     mAccountList->updateAccountList(mFilter);
0638 }
0639 
0640 void KMFilterDialog::slotImportFilter(QAction *act)
0641 {
0642     if (act) {
0643         importFilters(act->data().value<MailCommon::FilterImporterExporter::FilterType>());
0644     }
0645 }
0646 
0647 void KMFilterDialog::importFilters(MailCommon::FilterImporterExporter::FilterType type)
0648 {
0649     MailCommon::FilterImporterPathCache::self()->clear();
0650     FilterImporterExporter importer(this);
0651     bool canceled = false;
0652     QList<MailFilter *> filters = importer.importFilters(canceled, type);
0653     if (canceled) {
0654         return;
0655     }
0656 
0657     if (filters.isEmpty()) {
0658         KMessageBox::information(this, i18n("No filter was imported."));
0659         return;
0660     }
0661     QStringList listOfFilter;
0662     QList<MailFilter *>::ConstIterator end(filters.constEnd());
0663 
0664     for (QList<MailFilter *>::ConstIterator it = filters.constBegin(); it != end; ++it) {
0665         mFilterList->appendFilter(*it); // no need to deep copy, ownership passes to the list
0666         listOfFilter << (*it)->name();
0667     }
0668 
0669     KMessageBox::informationList(this, i18n("Filters which were imported:"), listOfFilter);
0670 }
0671 
0672 void KMFilterDialog::slotExportFilters()
0673 {
0674     bool wasCanceled = false;
0675     const QList<MailFilter *> filters = mFilterList->filtersForSaving(false, wasCanceled);
0676     if (filters.isEmpty()) {
0677         KMessageBox::information(this, i18n("Any filter found."));
0678         return;
0679     }
0680     if (wasCanceled) {
0681         qDeleteAll(filters);
0682         return;
0683     }
0684     FilterImporterExporter exporter(this);
0685     exporter.exportFilters(filters);
0686 }
0687 
0688 void KMFilterDialog::slotDisableAccept()
0689 {
0690     mDoNotClose = true;
0691 }
0692 
0693 void KMFilterDialog::slotDialogUpdated()
0694 {
0695     qCDebug(MAILCOMMON_LOG) << "Detected a change in data bound to the dialog!";
0696     if (!mIgnoreFilterUpdates) {
0697         mApplyButton->setEnabled(true);
0698     }
0699 }
0700 
0701 void KMFilterDialog::slotExportAsSieveScript()
0702 {
0703     if (mApplyButton->isEnabled()) {
0704         KMessageBox::information(this,
0705                                  i18nc("@info",
0706                                        "Some filters were changed and not saved yet.<br>"
0707                                        "You must save your filters before they can be exported."),
0708                                  i18n("Filters changed."));
0709         return;
0710     }
0711     KMessageBox::information(this,
0712                              i18n("We cannot convert all KMail filters to sieve scripts but we can try :)"),
0713                              i18n("Convert KMail filters to sieve scripts"));
0714     bool wasCanceled = false;
0715     const QList<MailFilter *> filters = mFilterList->filtersForSaving(false, wasCanceled);
0716     if (filters.isEmpty()) {
0717         return;
0718     }
0719     if (!wasCanceled) {
0720         QPointer<FilterSelectionDialog> dlg = new FilterSelectionDialog(this);
0721         dlg->setFilters(filters);
0722         if (dlg->exec() == QDialog::Accepted) {
0723             QList<MailFilter *> lst = dlg->selectedFilters();
0724             if (!lst.isEmpty()) {
0725                 FilterConvertToSieve convert(lst);
0726                 convert.convert();
0727                 qDeleteAll(lst);
0728             } else {
0729                 KMessageBox::information(this, i18n("No filters selected."), i18n("Convert KMail filters to sieve scripts"));
0730             }
0731         }
0732         delete dlg;
0733     } else {
0734         qDeleteAll(filters);
0735     }
0736 }
0737 
0738 void KMFilterDialog::slotHelp()
0739 {
0740     PimCommon::Util::invokeHelp(QStringLiteral("kmail2/filters.html"));
0741 }
0742 
0743 #include "moc_kmfilterdialog.cpp"