File indexing completed on 2024-06-09 05:18:13

0001 /*
0002 
0003   SPDX-FileCopyrightText: Marc Mutz <mutz@kde.org>
0004 
0005   SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "searchpatternedit.h"
0009 #include "widgethandler/rulewidgethandlermanager.h"
0010 using MailCommon::RuleWidgetHandlerManager;
0011 #include "mailcommon_debug.h"
0012 
0013 #include <KComboBox>
0014 #include <KLazyLocalizedString>
0015 #include <KLineEditEventHandler>
0016 #include <KLocalizedString>
0017 #include <QButtonGroup>
0018 #include <QFormLayout>
0019 #include <QHBoxLayout>
0020 #include <QIcon>
0021 #include <QLineEdit>
0022 #include <QPushButton>
0023 #include <QRadioButton>
0024 #include <QStackedWidget>
0025 // Definition of special rule field strings
0026 // Note: Also see SearchRule::matches() and ruleFieldToEnglish() if
0027 //       you change the following i18n-ized strings!
0028 // Note: The index of the values in the following array has to correspond to
0029 //       the value of the entries in the enum in SearchRuleWidget.
0030 
0031 using namespace MailCommon;
0032 
0033 static const struct {
0034     const char *internalName;
0035     const KLazyLocalizedString displayName;
0036 
0037     [[nodiscard]] QString getLocalizedDisplayName() const
0038     {
0039         return displayName.toString();
0040     }
0041 } SpecialRuleFields[] = {{"<message>", kli18n("Complete Message")},
0042                          {"<body>", kli18n("Body of Message")},
0043                          {"<any header>", kli18n("Anywhere in Headers")},
0044                          {"<recipients>", kli18n("All Recipients")},
0045                          {"<size>", kli18n("Size in Bytes")},
0046                          {"<age in days>", kli18n("Age in Days")},
0047                          {"<status>", kli18n("Message Status")},
0048                          {"<tag>", kli18n("Message Tag")},
0049                          {"Subject", kli18n("Subject")},
0050                          {"From", kli18n("From")},
0051                          {"To", kli18n("To")},
0052                          {"CC", kli18n("CC")},
0053                          {"Reply-To", kli18n("Reply To")},
0054                          {"Organization", kli18n("Organization")},
0055                          {"<date>", kli18n("Date")},
0056                          {"<encryption>", kli18n("Encryption")}};
0057 static const int SpecialRuleFieldsCount = sizeof(SpecialRuleFields) / sizeof(*SpecialRuleFields);
0058 
0059 //=============================================================================
0060 //
0061 // class SearchRuleWidget
0062 //
0063 //=============================================================================
0064 
0065 SearchRuleWidget::SearchRuleWidget(QWidget *parent,
0066                                    SearchRule::Ptr aRule,
0067                                    SearchPatternEdit::SearchPatternEditOptions options,
0068                                    SearchPatternEdit::SearchModeType modeType)
0069     : QWidget(parent)
0070 {
0071     initFieldList(options);
0072     initWidget(modeType);
0073 
0074     if (aRule) {
0075         setRule(aRule);
0076     } else {
0077         reset();
0078     }
0079 }
0080 
0081 void SearchRuleWidget::setPatternEditOptions(SearchPatternEdit::SearchPatternEditOptions options)
0082 {
0083     SearchRule::Ptr srule = rule();
0084     QByteArray currentText = srule->field();
0085 
0086     initFieldList(options);
0087 
0088     mRuleField->clear();
0089     mRuleField->addItems(mFilterFieldList);
0090     KCompletion *comp = mRuleField->completionObject();
0091     comp->clear();
0092     comp->insertItems(mFilterFieldList);
0093     mRuleField->setMaxCount(mRuleField->count());
0094     mRuleField->adjustSize();
0095 
0096     const bool headersOnly = (options & MailCommon::SearchPatternEdit::HeadersOnly);
0097     const bool notShowSize = (options & MailCommon::SearchPatternEdit::NotShowSize);
0098     const bool notShowDate = (options & MailCommon::SearchPatternEdit::NotShowDate);
0099     const bool notShowAbsoluteDates = (options & MailCommon::SearchPatternEdit::NotShowAbsoluteDate);
0100     const bool notShowTags = (options & MailCommon::SearchPatternEdit::NotShowTags);
0101 
0102     if (headersOnly && (currentText != "<message>") && (currentText != "<body>")) {
0103         mRuleField->setItemText(0, QString::fromLatin1(currentText));
0104     } else {
0105         mRuleField->setItemText(0, QString());
0106     }
0107 
0108     if (notShowSize && (currentText != "<size>")) {
0109         mRuleField->setItemText(0, QString::fromLatin1(currentText));
0110     } else {
0111         mRuleField->setItemText(0, QString());
0112     }
0113 
0114     if (notShowDate && (currentText != "<date>")) {
0115         mRuleField->setItemText(0, QString::fromLatin1(currentText));
0116     } else {
0117         mRuleField->setItemText(0, QString());
0118     }
0119 
0120     if (notShowAbsoluteDates && (currentText != "<age in days>")) {
0121         mRuleField->setItemText(0, QString::fromLatin1(currentText));
0122     } else {
0123         mRuleField->setItemText(0, QString());
0124     }
0125     if (notShowTags && (currentText != "<tag>")) {
0126         mRuleField->setItemText(0, QString::fromLatin1(currentText));
0127     } else {
0128         mRuleField->setItemText(0, QString());
0129     }
0130 }
0131 
0132 void SearchRuleWidget::initWidget(SearchPatternEdit::SearchModeType modeType)
0133 {
0134     auto hlay = new QHBoxLayout(this);
0135     hlay->setContentsMargins({});
0136 
0137     // initialize the header field combo box
0138     mRuleField = new KComboBox(this);
0139     mRuleField->setMinimumWidth(50);
0140     mRuleField->setObjectName(QLatin1StringView("mRuleField"));
0141     mRuleField->setEditable(true);
0142     auto edit = new QLineEdit;
0143     KLineEditEventHandler::catchReturnKey(edit);
0144     edit->setPlaceholderText(i18n("Choose or type your own criteria"));
0145     mRuleField->setToolTip(i18n("Choose or type your own criteria"));
0146     edit->setClearButtonEnabled(true);
0147     mRuleField->setLineEdit(edit);
0148 
0149     mRuleField->addItems(mFilterFieldList);
0150     KCompletion *comp = mRuleField->completionObject();
0151     comp->setIgnoreCase(true);
0152     comp->insertItems(mFilterFieldList);
0153     comp->setCompletionMode(KCompletion::CompletionPopupAuto);
0154 
0155     // don't show sliders when popping up this menu
0156     mRuleField->setMaxCount(mRuleField->count());
0157     mRuleField->adjustSize();
0158     hlay->addWidget(mRuleField);
0159 
0160     // initialize the function/value widget stack
0161     mFunctionStack = new QStackedWidget(this);
0162     // Don't expand the widget in vertical direction
0163     mFunctionStack->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
0164 
0165     hlay->addWidget(mFunctionStack);
0166 
0167     mValueStack = new QStackedWidget(this);
0168     hlay->addWidget(mValueStack);
0169     hlay->setStretchFactor(mValueStack, 10);
0170 
0171     mAdd = new QPushButton(this);
0172     mAdd->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
0173     mAdd->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
0174     hlay->addWidget(mAdd);
0175 
0176     mRemove = new QPushButton(this);
0177     mRemove->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
0178     mRemove->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
0179     hlay->addWidget(mRemove);
0180 
0181     RuleWidgetHandlerManager::instance()->setIsAkonadiSearch(modeType == SearchPatternEdit::BalooMode);
0182 
0183     RuleWidgetHandlerManager::instance()->createWidgets(mFunctionStack, mValueStack, this);
0184 
0185     // redirect focus to the header field combo box
0186     setFocusProxy(mRuleField);
0187 
0188     connect(mRuleField, &QComboBox::textActivated, this, &SearchRuleWidget::slotRuleFieldChanged);
0189     connect(mRuleField, &QComboBox::editTextChanged, this, &SearchRuleWidget::slotRuleFieldChanged);
0190     connect(mRuleField, &QComboBox::editTextChanged, this, &SearchRuleWidget::fieldChanged);
0191 
0192     connect(mAdd, &QAbstractButton::clicked, this, &SearchRuleWidget::slotAddWidget);
0193     connect(mRemove, &QAbstractButton::clicked, this, &SearchRuleWidget::slotRemoveWidget);
0194 }
0195 
0196 void SearchRuleWidget::updateAddRemoveButton(bool addButtonEnabled, bool removeButtonEnabled)
0197 {
0198     mAdd->setEnabled(addButtonEnabled);
0199     mRemove->setEnabled(removeButtonEnabled);
0200 }
0201 
0202 void SearchRuleWidget::slotAddWidget()
0203 {
0204     Q_EMIT addWidget(this);
0205 }
0206 
0207 void SearchRuleWidget::slotRemoveWidget()
0208 {
0209     Q_EMIT removeWidget(this);
0210 }
0211 
0212 void SearchRuleWidget::setRule(SearchRule::Ptr aRule)
0213 {
0214     Q_ASSERT(aRule);
0215 
0216     qCDebug(MAILCOMMON_LOG) << "(" << aRule->asString() << ")";
0217 
0218     //--------------set the field
0219     int i = indexOfRuleField(aRule->field());
0220 
0221     mRuleField->blockSignals(true);
0222 
0223     if (i < 0) { // not found -> user defined field
0224         mRuleField->setItemText(0, QString::fromLatin1(aRule->field()));
0225         i = 0;
0226     } else { // found in the list of predefined fields
0227         mRuleField->setItemText(0, QString());
0228     }
0229 
0230     mRuleField->setCurrentIndex(i);
0231     mRuleField->blockSignals(false);
0232 
0233     RuleWidgetHandlerManager::instance()->setRule(mFunctionStack, mValueStack, aRule);
0234 }
0235 
0236 SearchRule::Ptr SearchRuleWidget::rule() const
0237 {
0238     const QByteArray ruleField = ruleFieldToEnglish(mRuleField->currentText());
0239 
0240     const SearchRule::Function function = RuleWidgetHandlerManager::instance()->function(ruleField, mFunctionStack);
0241 
0242     const QString value = RuleWidgetHandlerManager::instance()->value(ruleField, mFunctionStack, mValueStack);
0243 
0244     return SearchRule::createInstance(ruleField, function, value);
0245 }
0246 
0247 void SearchRuleWidget::reset()
0248 {
0249     mRuleField->blockSignals(true);
0250     mRuleField->setItemText(0, QString());
0251     mRuleField->setCurrentIndex(0);
0252     mRuleField->blockSignals(false);
0253 
0254     RuleWidgetHandlerManager::instance()->reset(mFunctionStack, mValueStack);
0255 }
0256 
0257 void SearchRuleWidget::slotFunctionChanged()
0258 {
0259     const QByteArray ruleField = ruleFieldToEnglish(mRuleField->currentText());
0260     RuleWidgetHandlerManager::instance()->update(ruleField, mFunctionStack, mValueStack);
0261     const QString prettyValue = RuleWidgetHandlerManager::instance()->prettyValue(ruleField, mFunctionStack, mValueStack);
0262 
0263     Q_EMIT contentsChanged(prettyValue);
0264 }
0265 
0266 void SearchRuleWidget::slotValueChanged()
0267 {
0268     const QByteArray ruleField = ruleFieldToEnglish(mRuleField->currentText());
0269 
0270     const QString prettyValue = RuleWidgetHandlerManager::instance()->prettyValue(ruleField, mFunctionStack, mValueStack);
0271 
0272     Q_EMIT contentsChanged(prettyValue);
0273 }
0274 
0275 void SearchRuleWidget::slotReturnPressed()
0276 {
0277     Q_EMIT returnPressed();
0278 }
0279 
0280 QByteArray SearchRuleWidget::ruleFieldToEnglish(const QString &i18nVal)
0281 {
0282     for (int i = 0; i < SpecialRuleFieldsCount; ++i) {
0283         if (i18nVal == SpecialRuleFields[i].getLocalizedDisplayName()) {
0284             return SpecialRuleFields[i].internalName;
0285         }
0286     }
0287     return i18nVal.toLatin1();
0288 }
0289 
0290 int SearchRuleWidget::ruleFieldToId(const QString &i18nVal)
0291 {
0292     for (int i = 0; i < SpecialRuleFieldsCount; ++i) {
0293         if (i18nVal == SpecialRuleFields[i].getLocalizedDisplayName()) {
0294             return i;
0295         }
0296     }
0297     return -1; // no pseudo header
0298 }
0299 
0300 static QString displayNameFromInternalName(const QString &internal)
0301 {
0302     for (int i = 0; i < SpecialRuleFieldsCount; ++i) {
0303         if (internal == QLatin1StringView(SpecialRuleFields[i].internalName)) {
0304             return SpecialRuleFields[i].getLocalizedDisplayName();
0305         }
0306     }
0307     return QLatin1StringView(internal.toLatin1());
0308 }
0309 
0310 int SearchRuleWidget::indexOfRuleField(const QByteArray &aName) const
0311 {
0312     if (aName.isEmpty()) {
0313         return -1;
0314     }
0315 
0316     const QString i18n_aName = displayNameFromInternalName(QLatin1StringView(aName));
0317     const int nbRuleField = mRuleField->count();
0318     for (int i = 1; i < nbRuleField; ++i) {
0319         if (mRuleField->itemText(i) == i18n_aName) {
0320             return i;
0321         }
0322     }
0323 
0324     return -1;
0325 }
0326 
0327 void SearchRuleWidget::initFieldList(SearchPatternEdit::SearchPatternEditOptions options)
0328 {
0329     const bool headersOnly = (options & MailCommon::SearchPatternEdit::HeadersOnly);
0330     const bool notShowAbsoluteDates = (options & MailCommon::SearchPatternEdit::NotShowAbsoluteDate);
0331     const bool notShowSize = (options & MailCommon::SearchPatternEdit::NotShowSize);
0332     const bool notShowDate = (options & MailCommon::SearchPatternEdit::NotShowDate);
0333     const bool notShowTags = (options & MailCommon::SearchPatternEdit::NotShowTags);
0334 
0335     mFilterFieldList.clear();
0336     mFilterFieldList.append(QString()); // empty entry for user input
0337 
0338     if (!headersOnly) {
0339         mFilterFieldList.append(SpecialRuleFields[Message].getLocalizedDisplayName());
0340         mFilterFieldList.append(SpecialRuleFields[Body].getLocalizedDisplayName());
0341     }
0342     mFilterFieldList.append(SpecialRuleFields[AnyHeader].getLocalizedDisplayName());
0343     mFilterFieldList.append(SpecialRuleFields[Recipients].getLocalizedDisplayName());
0344     if (!notShowSize) {
0345         mFilterFieldList.append(SpecialRuleFields[Size].getLocalizedDisplayName());
0346     }
0347     if (!notShowAbsoluteDates) {
0348         mFilterFieldList.append(SpecialRuleFields[AgeInDays].getLocalizedDisplayName());
0349     }
0350 
0351     mFilterFieldList.append(SpecialRuleFields[Subject].getLocalizedDisplayName());
0352     mFilterFieldList.append(SpecialRuleFields[From].getLocalizedDisplayName());
0353     mFilterFieldList.append(SpecialRuleFields[To].getLocalizedDisplayName());
0354     mFilterFieldList.append(SpecialRuleFields[CC].getLocalizedDisplayName());
0355     mFilterFieldList.append(SpecialRuleFields[Status].getLocalizedDisplayName());
0356     if (!notShowTags) {
0357         mFilterFieldList.append(SpecialRuleFields[Tag].getLocalizedDisplayName());
0358     }
0359     mFilterFieldList.append(SpecialRuleFields[ReplyTo].getLocalizedDisplayName());
0360     mFilterFieldList.append(SpecialRuleFields[Organization].getLocalizedDisplayName());
0361 
0362     if (!notShowDate) {
0363         mFilterFieldList.append(SpecialRuleFields[Date].getLocalizedDisplayName());
0364     }
0365 
0366     mFilterFieldList.append(SpecialRuleFields[Encryption].getLocalizedDisplayName());
0367 
0368     // these others only represent message headers and you can add to
0369     // them as you like
0370     mFilterFieldList.append(QStringLiteral("List-Id"));
0371     mFilterFieldList.append(QStringLiteral("Resent-From"));
0372     mFilterFieldList.append(QStringLiteral("X-Loop"));
0373     mFilterFieldList.append(QStringLiteral("X-Mailing-List"));
0374     mFilterFieldList.append(QStringLiteral("X-Spam-Flag"));
0375     mFilterFieldList.append(QStringLiteral("X-Spam-Status"));
0376 }
0377 
0378 void SearchRuleWidget::slotRuleFieldChanged(const QString &field)
0379 {
0380     RuleWidgetHandlerManager::instance()->update(ruleFieldToEnglish(field), mFunctionStack, mValueStack);
0381 }
0382 
0383 //=============================================================================
0384 //
0385 // class KMFilterActionWidgetLister (the filter action editor)
0386 //
0387 //=============================================================================
0388 
0389 SearchRuleWidgetLister::SearchRuleWidgetLister(QWidget *parent, SearchPatternEdit::SearchPatternEditOptions options, SearchPatternEdit::SearchModeType modeType)
0390     : KWidgetLister(false, 1, SearchPattern::filterRulesMaximumSize(), parent)
0391 {
0392     mRuleList = nullptr;
0393 
0394     mTypeMode = modeType;
0395     mOptions = options;
0396 }
0397 
0398 SearchRuleWidgetLister::~SearchRuleWidgetLister() = default;
0399 
0400 void SearchRuleWidgetLister::setPatternEditOptions(SearchPatternEdit::SearchPatternEditOptions options)
0401 {
0402     mOptions = options;
0403     const auto lst = widgets();
0404     for (QWidget *w : lst) {
0405         qobject_cast<SearchRuleWidget *>(w)->setPatternEditOptions(options);
0406     }
0407 }
0408 
0409 void SearchRuleWidgetLister::setRuleList(QList<SearchRule::Ptr> *aList)
0410 {
0411     Q_ASSERT(aList);
0412 
0413     if (mRuleList && mRuleList != aList) {
0414         regenerateRuleListFromWidgets();
0415     }
0416 
0417     mRuleList = aList;
0418 
0419     if (!widgets().isEmpty()) { // move this below next 'if'?
0420         widgets().constFirst()->blockSignals(true);
0421     }
0422 
0423     if (aList->isEmpty()) {
0424         slotClear();
0425         widgets().constFirst()->blockSignals(false);
0426         return;
0427     }
0428 
0429     int superfluousItems = (int)mRuleList->count() - widgetsMaximum();
0430     if (superfluousItems > 0) {
0431         qCDebug(MAILCOMMON_LOG) << "Clipping rule list to" << widgetsMaximum() << "items!";
0432 
0433         for (; superfluousItems; superfluousItems--) {
0434             mRuleList->removeLast();
0435         }
0436     }
0437 
0438     // set the right number of widgets
0439     setNumberOfShownWidgetsTo(qMax((int)mRuleList->count(), widgetsMinimum()));
0440 
0441     // load the actions into the widgets
0442     QList<QWidget *> widgetList = widgets();
0443     QList<SearchRule::Ptr>::const_iterator rIt;
0444     QList<SearchRule::Ptr>::const_iterator rItEnd(mRuleList->constEnd());
0445     QList<QWidget *>::const_iterator wIt = widgetList.constBegin();
0446     QList<QWidget *>::const_iterator wItEnd = widgetList.constEnd();
0447     for (rIt = mRuleList->constBegin(); rIt != rItEnd && wIt != wItEnd; ++rIt, ++wIt) {
0448         qobject_cast<SearchRuleWidget *>(*wIt)->setRule((*rIt));
0449     }
0450     for (; wIt != wItEnd; ++wIt) {
0451         qobject_cast<SearchRuleWidget *>(*wIt)->reset();
0452     }
0453 
0454     Q_ASSERT(!widgets().isEmpty());
0455     widgets().constFirst()->blockSignals(false);
0456     updateAddRemoveButton();
0457 }
0458 
0459 void SearchRuleWidgetLister::slotAddWidget(QWidget *w)
0460 {
0461     addWidgetAfterThisWidget(w);
0462     updateAddRemoveButton();
0463 }
0464 
0465 void SearchRuleWidgetLister::slotRemoveWidget(QWidget *w)
0466 {
0467     removeWidget(w);
0468     updateAddRemoveButton();
0469 }
0470 
0471 void SearchRuleWidgetLister::reconnectWidget(SearchRuleWidget *w)
0472 {
0473     connect(w, &SearchRuleWidget::addWidget, this, &SearchRuleWidgetLister::slotAddWidget, Qt::UniqueConnection);
0474     connect(w, &SearchRuleWidget::removeWidget, this, &SearchRuleWidgetLister::slotRemoveWidget, Qt::UniqueConnection);
0475 }
0476 
0477 void SearchRuleWidgetLister::updateAddRemoveButton()
0478 {
0479     QList<QWidget *> widgetList = widgets();
0480     const int numberOfWidget(widgetList.count());
0481     bool addButtonEnabled = false;
0482     bool removeButtonEnabled = false;
0483     if (numberOfWidget <= widgetsMinimum()) {
0484         addButtonEnabled = true;
0485         removeButtonEnabled = false;
0486     } else if (numberOfWidget >= widgetsMaximum()) {
0487         addButtonEnabled = false;
0488         removeButtonEnabled = true;
0489     } else {
0490         addButtonEnabled = true;
0491         removeButtonEnabled = true;
0492     }
0493     QList<QWidget *>::ConstIterator wIt = widgetList.constBegin();
0494     QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
0495     for (; wIt != wEnd; ++wIt) {
0496         auto w = qobject_cast<SearchRuleWidget *>(*wIt);
0497         w->updateAddRemoveButton(addButtonEnabled, removeButtonEnabled);
0498     }
0499 }
0500 
0501 void SearchRuleWidgetLister::reset()
0502 {
0503     if (mRuleList) {
0504         regenerateRuleListFromWidgets();
0505     }
0506 
0507     mRuleList = nullptr;
0508     slotClear();
0509     updateAddRemoveButton();
0510 }
0511 
0512 QWidget *SearchRuleWidgetLister::createWidget(QWidget *parent)
0513 {
0514     auto w = new SearchRuleWidget(parent, SearchRule::Ptr(), mOptions, mTypeMode);
0515     reconnectWidget(w);
0516     return w;
0517 }
0518 
0519 void SearchRuleWidgetLister::clearWidget(QWidget *aWidget)
0520 {
0521     if (aWidget) {
0522         auto w = static_cast<SearchRuleWidget *>(aWidget);
0523         w->reset();
0524         reconnectWidget(w);
0525         updateAddRemoveButton();
0526     }
0527 }
0528 
0529 void SearchRuleWidgetLister::regenerateRuleListFromWidgets()
0530 {
0531     if (!mRuleList) {
0532         return;
0533     }
0534 
0535     mRuleList->clear();
0536 
0537     const auto lst = widgets();
0538     for (const QWidget *w : lst) {
0539         SearchRule::Ptr r = qobject_cast<const SearchRuleWidget *>(w)->rule();
0540         if (r && !r->isEmpty()) {
0541             mRuleList->append(r);
0542         }
0543     }
0544     updateAddRemoveButton();
0545 }
0546 
0547 //=============================================================================
0548 //
0549 // class SearchPatternEdit
0550 //
0551 //=============================================================================
0552 
0553 SearchPatternEdit::SearchPatternEdit(QWidget *parent, SearchPatternEditOptions options, SearchModeType modeType)
0554     : QWidget(parent)
0555 {
0556     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
0557     setObjectName(QLatin1StringView("SearchPatternEdit"));
0558     initLayout(options, modeType);
0559 }
0560 
0561 SearchPatternEdit::~SearchPatternEdit() = default;
0562 
0563 void SearchPatternEdit::updateSearchPattern()
0564 {
0565     mRuleLister->regenerateRuleListFromWidgets();
0566 }
0567 
0568 void SearchPatternEdit::setPatternEditOptions(SearchPatternEdit::SearchPatternEditOptions options)
0569 {
0570     mRuleLister->setPatternEditOptions(options);
0571 }
0572 
0573 void SearchPatternEdit::initLayout(SearchPatternEditOptions options, SearchModeType modeType)
0574 {
0575     auto layout = new QFormLayout(this);
0576     layout->setContentsMargins({});
0577 
0578     const bool matchAllMessages = (options & MailCommon::SearchPatternEdit::MatchAllMessages);
0579     //------------the radio buttons
0580     mAllRBtn = new QRadioButton(i18n("Match a&ll of the following"), this);
0581     mAnyRBtn = new QRadioButton(i18n("Match an&y of the following"), this);
0582     if (matchAllMessages) {
0583         mAllMessageRBtn = new QRadioButton(i18n("Match all messages"), this);
0584     }
0585 
0586     mAllRBtn->setObjectName(QLatin1StringView("mAllRBtn"));
0587     mAllRBtn->setChecked(true);
0588     mAnyRBtn->setObjectName(QLatin1StringView("mAnyRBtn"));
0589     mAnyRBtn->setChecked(false);
0590     if (matchAllMessages) {
0591         mAllMessageRBtn->setObjectName(QLatin1StringView("mAllMessageRBtn"));
0592         mAllMessageRBtn->setChecked(false);
0593     }
0594     layout->addRow(i18n("Filter criteria:"), mAllRBtn);
0595     layout->addRow(QString(), mAnyRBtn);
0596     if (matchAllMessages) {
0597         layout->addRow(QString(), mAllMessageRBtn);
0598     }
0599 
0600     auto bg = new QButtonGroup(this);
0601     bg->addButton(mAllRBtn);
0602     bg->addButton(mAnyRBtn);
0603     if (matchAllMessages) {
0604         bg->addButton(mAllMessageRBtn);
0605     }
0606 
0607     //------------connect a few signals
0608     connect(bg, &QButtonGroup::buttonClicked, this, &SearchPatternEdit::slotRadioClicked);
0609 
0610     //------------the list of SearchRuleWidget's
0611     mRuleLister = new SearchRuleWidgetLister(this, options, modeType);
0612 
0613     mRuleLister->slotClear();
0614 
0615     if (!mRuleLister->widgets().isEmpty()) {
0616         const int numberOfWidget(mRuleLister->widgets().count());
0617         for (int i = 0; i < numberOfWidget; ++i) {
0618             SearchRuleWidget *srw = static_cast<SearchRuleWidget *>(mRuleLister->widgets().at(i));
0619             connect(srw, &SearchRuleWidget::fieldChanged, this, &SearchPatternEdit::slotAutoNameHack);
0620             connect(srw, &SearchRuleWidget::contentsChanged, this, &SearchPatternEdit::slotAutoNameHack);
0621             connect(srw, &SearchRuleWidget::returnPressed, this, &SearchPatternEdit::returnPressed);
0622         }
0623     } else {
0624         qCDebug(MAILCOMMON_LOG) << "No first SearchRuleWidget, though slotClear() has been called!";
0625     }
0626 
0627     connect(mRuleLister, qOverload<QWidget *>(&SearchRuleWidgetLister::widgetAdded), this, &SearchPatternEdit::slotRuleAdded);
0628     connect(mRuleLister, qOverload<>(&SearchRuleWidgetLister::widgetRemoved), this, &SearchPatternEdit::patternChanged);
0629     connect(mRuleLister, &KPIM::KWidgetLister::clearWidgets, this, &SearchPatternEdit::patternChanged);
0630 
0631     layout->addRow(mRuleLister);
0632 }
0633 
0634 void SearchPatternEdit::setSearchPattern(SearchPattern *aPattern)
0635 {
0636     Q_ASSERT(aPattern);
0637 
0638     mRuleLister->setRuleList(aPattern);
0639 
0640     mPattern = aPattern;
0641 
0642     blockSignals(true);
0643     if (mPattern->op() == SearchPattern::OpOr) {
0644         mAnyRBtn->setChecked(true);
0645     } else if (mPattern->op() == SearchPattern::OpAnd) {
0646         mAllRBtn->setChecked(true);
0647     } else if (mAllMessageRBtn && (mPattern->op() == SearchPattern::OpAll)) {
0648         mAllMessageRBtn->setChecked(true);
0649     }
0650     mRuleLister->setEnabled(mPattern->op() != SearchPattern::OpAll);
0651     blockSignals(false);
0652 
0653     setEnabled(true);
0654     Q_EMIT patternChanged();
0655 }
0656 
0657 void SearchPatternEdit::reset()
0658 {
0659     mRuleLister->reset();
0660 
0661     blockSignals(true);
0662     mAllRBtn->setChecked(true);
0663     blockSignals(false);
0664 
0665     setEnabled(false);
0666     Q_EMIT patternChanged();
0667 }
0668 
0669 void SearchPatternEdit::slotRadioClicked(QAbstractButton *aRBtn)
0670 {
0671     if (mPattern) {
0672         if (aRBtn == mAllRBtn) {
0673             mPattern->setOp(SearchPattern::OpAnd);
0674         } else if (aRBtn == mAnyRBtn) {
0675             mPattern->setOp(SearchPattern::OpOr);
0676         } else if (aRBtn == mAllMessageRBtn) {
0677             mPattern->setOp(SearchPattern::OpAll);
0678         }
0679         mRuleLister->setEnabled(mPattern->op() != SearchPattern::OpAll);
0680         Q_EMIT patternChanged();
0681     }
0682 }
0683 
0684 void SearchPatternEdit::slotAutoNameHack()
0685 {
0686     mRuleLister->regenerateRuleListFromWidgets();
0687     Q_EMIT maybeNameChanged();
0688     Q_EMIT patternChanged();
0689 }
0690 
0691 void SearchPatternEdit::slotRuleAdded(QWidget *newRuleWidget)
0692 {
0693     auto srw = static_cast<SearchRuleWidget *>(newRuleWidget);
0694     connect(srw, &SearchRuleWidget::fieldChanged, this, &SearchPatternEdit::slotAutoNameHack);
0695     connect(srw, &SearchRuleWidget::contentsChanged, this, &SearchPatternEdit::slotAutoNameHack);
0696     connect(srw, &SearchRuleWidget::returnPressed, this, &SearchPatternEdit::returnPressed);
0697     Q_EMIT patternChanged();
0698 }
0699 
0700 #include "moc_searchpatternedit.cpp"