File indexing completed on 2024-11-10 04:50:08
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"