7#include "kmfilterlistbox.h"
8#include "filteractions/filteractiondict.h"
9#include "filtermanager.h"
10#include "invalidfilters/invalidfilterdialog.h"
11#include "invalidfilters/invalidfilterinfo.h"
12#include "mailcommon_debug.h"
13#include "mailfilter.h"
14#include <KListWidgetSearchLine>
15#include <KLocalizedString>
18#include <QInputDialog>
32KMFilterListBox::KMFilterListBox(
const QString &title,
QWidget *parent)
39 mListWidget->setMinimumWidth(150);
40 mListWidget->setWhatsThis(
41 i18n(
"<qt><p>This is the list of defined filters. "
42 "They are processed top-to-bottom.</p>"
43 "<p>Click on any filter to edit it "
44 "using the controls in the right-hand half "
45 "of the dialog.</p></qt>"));
51 mSearchListWidget->setPlaceholderText(
i18nc(
"@info Displayed grayed-out inside the textbox, verb to search",
"Search"));
52 mSearchListWidget->installEventFilter(
this);
53 layout->addWidget(mSearchListWidget);
54 layout->addWidget(mListWidget);
59 hbHBoxLayout->setContentsMargins({});
60 hbHBoxLayout->setSpacing(4);
63 hbHBoxLayout->addWidget(mBtnTop);
65 mBtnTop->setMinimumSize(mBtnTop->sizeHint() * 1.2);
68 hbHBoxLayout->addWidget(mBtnUp);
69 mBtnUp->setAutoRepeat(
true);
71 mBtnUp->setMinimumSize(mBtnUp->sizeHint() * 1.2);
73 hbHBoxLayout->addWidget(mBtnDown);
74 mBtnDown->setAutoRepeat(
true);
76 mBtnDown->setMinimumSize(mBtnDown->sizeHint() * 1.2);
79 hbHBoxLayout->addWidget(mBtnBottom);
81 mBtnBottom->setMinimumSize(mBtnBottom->sizeHint() * 1.2);
83 mBtnUp->setToolTip(
i18nc(
"Move selected filter up.",
"Up"));
84 mBtnDown->setToolTip(
i18nc(
"Move selected filter down.",
"Down"));
85 mBtnTop->setToolTip(
i18nc(
"Move selected filter to the top.",
"Top"));
86 mBtnBottom->setToolTip(
i18nc(
"Move selected filter to the bottom.",
"Bottom"));
88 i18n(
"<qt><p>Click this button to move the currently-"
89 "selected filter <em>up</em> one in the list above.</p>"
90 "<p>This is useful since the order of the filters in the list "
91 "determines the order in which they are tried on messages: "
92 "The topmost filter gets tried first.</p>"
93 "<p>If you have clicked this button accidentally, you can undo this "
94 "by clicking on the <em>Down</em> button.</p></qt>"));
95 mBtnDown->setWhatsThis(
96 i18n(
"<qt><p>Click this button to move the currently-"
97 "selected filter <em>down</em> one in the list above.</p>"
98 "<p>This is useful since the order of the filters in the list "
99 "determines the order in which they are tried on messages: "
100 "The topmost filter gets tried first.</p>"
101 "<p>If you have clicked this button accidentally, you can undo this "
102 "by clicking on the <em>Up</em> button.</p></qt>"));
103 mBtnBottom->setWhatsThis(
104 i18n(
"<qt><p>Click this button to move the currently-"
105 "selected filter to bottom of list.</p>"
106 "<p>This is useful since the order of the filters in the list "
107 "determines the order in which they are tried on messages: "
108 "The topmost filter gets tried first.</p></qt>"));
109 mBtnTop->setWhatsThis(
110 i18n(
"<qt><p>Click this button to move the currently-"
111 "selected filter to top of list.</p>"
112 "<p>This is useful since the order of the filters in the list "
113 "determines the order in which they are tried on messages: "
114 "The topmost filter gets tried first.</p></qt>"));
116 layout->addWidget(hb);
121 hbHBoxLayout->setContentsMargins({});
122 hbHBoxLayout->setSpacing(4);
124 hbHBoxLayout->addWidget(mBtnNew);
126 mBtnNew->setMinimumSize(mBtnNew->sizeHint() * 1.2);
128 hbHBoxLayout->addWidget(mBtnCopy);
130 mBtnCopy->setMinimumSize(mBtnCopy->sizeHint() * 1.2);
132 hbHBoxLayout->addWidget(mBtnDelete);
134 mBtnDelete->setMinimumSize(mBtnDelete->sizeHint() * 1.2);
137 mBtnRename->setMinimumSize(mBtnDelete->sizeHint() * 1.2);
139 hbHBoxLayout->addWidget(mBtnRename);
140 mBtnNew->setToolTip(
i18nc(
"@action:button in filter list manipulator",
"New"));
141 mBtnCopy->setToolTip(
i18nc(
"@info:tooltip",
"Copy"));
142 mBtnDelete->setToolTip(
i18nc(
"@info:tooltip",
"Delete"));
143 mBtnRename->setToolTip(
i18nc(
"@info:tooltip",
"Rename"));
144 mBtnNew->setWhatsThis(
145 i18n(
"<qt><p>Click this button to create a new filter.</p>"
146 "<p>The filter will be inserted just before the currently-"
147 "selected one, but you can always change that "
149 "<p>If you have clicked this button accidentally, you can undo this "
150 "by clicking on the <em>Delete</em> button.</p></qt>"));
151 mBtnCopy->setWhatsThis(
152 i18n(
"<qt><p>Click this button to copy a filter.</p>"
153 "<p>If you have clicked this button accidentally, you can undo this "
154 "by clicking on the <em>Delete</em> button.</p></qt>"));
155 mBtnDelete->setWhatsThis(
156 i18n(
"<qt><p>Click this button to <em>delete</em> the currently-"
157 "selected filter from the list above.</p>"
158 "<p>There is no way to get the filter back once "
159 "it is deleted, but you can always leave the "
160 "dialog by clicking <em>Cancel</em> to discard the "
161 "changes made.</p></qt>"));
162 mBtnRename->setWhatsThis(
163 i18n(
"<qt><p>Click this button to rename the currently-selected filter.</p>"
164 "<p>Filters are named automatically, as long as they start with "
166 "<p>If you have renamed a filter accidentally and want automatic "
167 "naming back, click this button and select <em>Clear</em> followed "
168 "by <em>OK</em> in the appearing dialog.</p></qt>"));
170 layout->addWidget(hb);
198KMFilterListBox::~KMFilterListBox() =
default;
200bool KMFilterListBox::eventFilter(
QObject *obj,
QEvent *event)
215 qCDebug(MAILCOMMON_LOG) <<
"Called while no filter is selected, ignoring.";
227 qCDebug(MAILCOMMON_LOG) <<
"Called while no filter is selected, ignoring.";
230 auto itemFilter =
static_cast<QListWidgetFilterItem *
>(item);
233 Q_EMIT filterUpdated(filter);
236void KMFilterListBox::slotRowsMoved(
const QModelIndex &,
int sourcestart,
int sourceEnd,
const QModelIndex &,
int destinationRow)
239 Q_UNUSED(sourcestart)
240 Q_UNUSED(destinationRow)
243 Q_EMIT filterOrderAltered();
251 newFilter->pattern()->append(newRule);
252 newFilter->pattern()->setName(QStringLiteral(
"<%1>: %2").arg(
QString::fromLatin1(field), value));
256 newFilter->actions()->append(desc->create());
259 insertFilter(newFilter);
263void KMFilterListBox::slotUpdateFilterName()
267 qCDebug(MAILCOMMON_LOG) <<
"Called while no filter is selected, ignoring.";
270 auto itemFilter =
static_cast<QListWidgetFilterItem *
>(item);
279 QString displayedName = itemFilter->text();
282 filter->setAutoNaming(
true);
285 if (
filter->isAutoNaming()) {
295 if (displayedName == shouldBeName) {
299 filter->setToolbarName(shouldBeName);
302 itemFilter->setText(shouldBeName);
306void KMFilterListBox::slotAccepted()
308 applyFilterChanged(
true);
311void KMFilterListBox::slotApplied()
313 applyFilterChanged(
false);
316void KMFilterListBox::applyFilterChanged(
bool closeAfterSaving)
326 bool wasCanceled =
false;
333QList<MailFilter *> KMFilterListBox::filtersForSaving(
bool closeAfterSaving,
bool &wasCanceled)
const
335 Q_EMIT const_cast<KMFilterListBox *
>(
this)->applyWidgets();
339 const int numberOfFilter(mListWidget->
count());
340 for (
int i = 0; i < numberOfFilter; ++i) {
341 auto itemFilter =
static_cast<QListWidgetFilterItem *
>(mListWidget->
item(i));
342 auto f =
new MailFilter(*itemFilter->filter());
350 emptyFilters << f->name();
351 listInvalidFilters.
append(MailCommon::InvalidFilterInfo(f->name(), information));
357 if (!emptyFilters.
empty()) {
359 dlg->setInvalidFilters(listInvalidFilters);
361 if (closeAfterSaving) {
371void KMFilterListBox::slotSelectionChanged()
379void KMFilterListBox::slotSelected(
int aIdx)
381 if (aIdx >= 0 && aIdx < mListWidget->count()) {
382 auto itemFilter =
static_cast<QListWidgetFilterItem *
>(mListWidget->
item(aIdx));
396void KMFilterListBox::slotNew()
407void KMFilterListBox::slotCopy()
410 if (!itemIsValid(item)) {
416 auto itemFilter =
static_cast<QListWidgetFilterItem *
>(item);
426 copyFilter->generateRandomIdentifier();
429 insertFilter(copyFilter);
433void KMFilterListBox::slotDelete()
436 if (!itemIsValid(itemFirst)) {
439 const bool uniqFilterSelected = (mListWidget->
selectedItems().count() == 1);
441 auto itemFilter =
static_cast<QListWidgetFilterItem *
>(itemFirst);
444 uniqFilterSelected ?
i18n(
"Do you want to remove the filter \"%1\"?",
filter->pattern()->name()) :
i18n(
"Do you want to remove selected filters?");
445 const QString dialogTitle = uniqFilterSelected ?
i18nc(
"@title:window",
"Remove Filter") :
i18nc(
"@title:window",
"Remove Filters");
447 if (answer == KMessageBox::ButtonCode::SecondaryAction) {
451 const int oIdxSelItem = mListWidget->
currentRow();
458 auto itemFilter =
static_cast<QListWidgetFilterItem *
>(item);
467 const int count = mListWidget->
count();
469 if (count > oIdxSelItem) {
483 if (oIdxSelItem == 0) {
488 Q_EMIT filterRemoved(lst);
491void KMFilterListBox::slotTop()
494 if (listWidgetItem.
isEmpty()) {
498 const int numberOfItem(listWidgetItem.
count());
499 if ((numberOfItem == 1) && (mListWidget->
currentRow() == 0)) {
500 qCDebug(MAILCOMMON_LOG) <<
"Called while the _topmost_ filter is selected, ignoring.";
505 bool wasMoved =
false;
506 for (
int i = 0; i < numberOfItem; ++i) {
507 const int posItem = mListWidget->
row(listWidgetItem.
at(i));
511 item = mListWidget->
takeItem(mListWidget->
row(listWidgetItem.
at(i)));
518 Q_EMIT filterOrderAltered();
525 const int numberOfFilters = mListWidget->
count();
526 for (
int i = 0; i < numberOfFilters; ++i) {
528 listWidgetItem << mListWidget->
item(i);
531 return listWidgetItem;
538 const int numberOfFilters = mListWidget->
count();
539 for (
int i = 0; i < numberOfFilters; ++i) {
545 requiredPart = qMax(requiredPart,
static_cast<QListWidgetFilterItem *
>(mListWidget->
item(i))->filter()->requiredPart(resource));
552void KMFilterListBox::slotBottom()
555 if (listWidgetItem.
isEmpty()) {
559 const int numberOfElement(mListWidget->
count());
560 const int numberOfItem(listWidgetItem.
count());
561 if ((numberOfItem == 1) && (mListWidget->
currentRow() == numberOfElement - 1)) {
562 qCDebug(MAILCOMMON_LOG) <<
"Called while the _last_ filter is selected, ignoring.";
568 bool wasMoved =
false;
569 for (
int i = numberOfItem - 1; i >= 0; --i, j++) {
570 const int posItem = mListWidget->
row(listWidgetItem.
at(i));
571 if (posItem == (numberOfElement - 1 - j)) {
574 item = mListWidget->
takeItem(mListWidget->
row(listWidgetItem.
at(i)));
575 mListWidget->
insertItem(numberOfElement - j, item);
581 Q_EMIT filterOrderAltered();
585void KMFilterListBox::slotUp()
588 if (listWidgetItem.
isEmpty()) {
592 const int numberOfItem(listWidgetItem.
count());
593 if ((numberOfItem == 1) && (mListWidget->
currentRow() == 0)) {
594 qCDebug(MAILCOMMON_LOG) <<
"Called while the _topmost_ filter is selected, ignoring.";
597 bool wasMoved =
false;
599 for (
int i = 0; i < numberOfItem; ++i) {
600 const int posItem = mListWidget->
row(listWidgetItem.
at(i));
604 swapNeighbouringFilters(posItem, posItem - 1);
609 Q_EMIT filterOrderAltered();
613void KMFilterListBox::slotDown()
616 if (listWidgetItem.
isEmpty()) {
620 const int numberOfElement(mListWidget->
count());
621 const int numberOfItem(listWidgetItem.
count());
622 if ((numberOfItem == 1) && (mListWidget->
currentRow() == numberOfElement - 1)) {
623 qCDebug(MAILCOMMON_LOG) <<
"Called while the _last_ filter is selected, ignoring.";
628 bool wasMoved =
false;
629 for (
int i = numberOfItem - 1; i >= 0; --i, j++) {
630 const int posItem = mListWidget->
row(listWidgetItem.
at(i));
631 if (posItem == (numberOfElement - 1 - j)) {
634 swapNeighbouringFilters(posItem, posItem + 1);
640 Q_EMIT filterOrderAltered();
644void KMFilterListBox::slotRename()
647 if (!itemIsValid(item)) {
650 auto itemFilter =
static_cast<QListWidgetFilterItem *
>(item);
652 bool okPressed =
false;
661 i18n(
"Rename Filter"),
662 i18n(
"Rename filter \"%1\" to:\n(leave the field empty for automatic naming)",
filter->pattern()->name()),
664 filter->pattern()->name(),
674 filter->pattern()->setName(QStringLiteral(
"<>"));
675 filter->setAutoNaming(
true);
677 filter->pattern()->setName(newName);
678 filter->setAutoNaming(
false);
681 slotUpdateFilterName();
683 Q_EMIT filterUpdated(filter);
686void KMFilterListBox::enableControls()
688 const int currentIndex = mListWidget->
currentRow();
689 const bool theFirst = (currentIndex == 0);
690 const int numberOfElement(mListWidget->
count());
691 const bool theLast = (currentIndex >= numberOfElement - 1);
692 const bool aFilterIsSelected = (currentIndex >= 0);
694 const int numberOfSelectedItem(mListWidget->
selectedItems().count());
695 const bool uniqFilterSelected = (numberOfSelectedItem == 1);
696 const bool allItemSelected = (numberOfSelectedItem == numberOfElement);
698 mBtnUp->
setEnabled(aFilterIsSelected && ((uniqFilterSelected && !theFirst) || (!uniqFilterSelected)) && !allItemSelected);
699 mBtnDown->
setEnabled(aFilterIsSelected && ((uniqFilterSelected && !theLast) || (!uniqFilterSelected)) && !allItemSelected);
701 mBtnCopy->
setEnabled(aFilterIsSelected && uniqFilterSelected);
703 mBtnRename->
setEnabled(aFilterIsSelected && uniqFilterSelected);
705 mBtnTop->
setEnabled(aFilterIsSelected && ((uniqFilterSelected && !theFirst) || (!uniqFilterSelected)) && !allItemSelected);
707 mBtnBottom->
setEnabled(aFilterIsSelected && ((uniqFilterSelected && !theLast) || (!uniqFilterSelected)) && !allItemSelected);
708 if (aFilterIsSelected) {
713void KMFilterListBox::loadFilterList(
bool createDummyFilter)
715 Q_ASSERT(mListWidget);
723 mListWidget->
clear();
727 auto item =
new QListWidgetFilterItem(
filter->pattern()->name(), mListWidget);
738 const int numberOfItem(mListWidget->
count());
739 if (numberOfItem == 0) {
740 if (createDummyFilter) {
750void KMFilterListBox::insertFilter(
MailFilter *aFilter)
754 const int currentIndex = mListWidget->
currentRow();
756 auto item =
new QListWidgetFilterItem(aFilter->
pattern()->
name());
757 item->setFilter(aFilter);
760 if (currentIndex < 0) {
768 Q_EMIT filterOrderAltered();
771void KMFilterListBox::appendFilter(
MailFilter *aFilter)
773 auto item =
new QListWidgetFilterItem(aFilter->
pattern()->
name(), mListWidget);
775 item->setFilter(aFilter);
781void KMFilterListBox::swapNeighbouringFilters(
int untouchedOne,
int movedOne)
784 Q_ASSERT(untouchedOne - movedOne == 1 || movedOne - untouchedOne == 1);
799QListWidgetFilterItem::~QListWidgetFilterItem()
815#include "moc_kmfilterlistbox.cpp"
static FilterActionDict * filterActionDict()
Returns the global filter action dictionary.
void setFilters(const QList< MailCommon::MailFilter * > &filters)
Replace the list of filters of the filter manager with the given list of filters.
QList< MailCommon::MailFilter * > filters() const
Returns the filter list of the manager.
static FilterManager * instance()
Returns the global filter manager object.
SearchPattern * pattern()
Provides a reference to the internal pattern.
This class is an abstraction of a search over messages.
void setName(const QString &newName)
Sets the name of the search pattern.
QString name() const
Returns the name of the search pattern.
std::shared_ptr< SearchRule > Ptr
Defines a pointer to a search rule.
RequiredPart
Possible required parts.
static SearchRule::Ptr createInstance(const QByteArray &field=QByteArray(), Function function=FuncContains, const QString &contents=QString())
Creates a new search rule of a certain type by instantiating the appropriate subclass depending on th...
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void information(QWidget *parent, const QString &text, const QString &title=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
ButtonCode questionTwoActions(QWidget *parent, const QString &text, const QString &title, const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const QString &dontAskAgainName=QString(), Options options=Notify)
const QList< QKeySequence > & shortcut(StandardShortcut id)
void rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
virtual bool event(QEvent *e) override
QIcon fromTheme(const QString &name)
QString getText(QWidget *parent, const QString &title, const QString &label, QLineEdit::EchoMode mode, const QString &text, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
qsizetype count() const const
bool isEmpty() const const
T value(const Key &key) const const
bool blockSignals(bool block)
virtual bool eventFilter(QObject *watched, QEvent *event)
QString arg(Args &&... args) const const
QString fromLatin1(QByteArrayView str)
bool isEmpty() const const
QString trimmed() const const
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
Auxiliary struct for FilterActionDict.