File indexing completed on 2024-11-17 04:51:15

0001 /*
0002   SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
0003 
0004   SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "headersrulerwidgethandler.h"
0008 
0009 #include "search/searchpattern.h"
0010 
0011 #include <KLineEdit>
0012 #include <KLocalizedString>
0013 
0014 #include <KLazyLocalizedString>
0015 #include <QComboBox>
0016 #include <QLabel>
0017 #include <QStackedWidget>
0018 using namespace MailCommon;
0019 
0020 // also see SearchRule::matches() and SearchRule::Function
0021 // if you change the following strings!
0022 static const struct {
0023     SearchRule::Function id;
0024     const KLazyLocalizedString displayName;
0025 } HeaderFunctions[] = {{SearchRule::FuncContains, kli18n("contains")},
0026                        {SearchRule::FuncContainsNot, kli18n("does not contain")},
0027                        {SearchRule::FuncEquals, kli18n("equals")},
0028                        {SearchRule::FuncNotEqual, kli18n("does not equal")},
0029                        {SearchRule::FuncStartWith, kli18n("starts with")},
0030                        {SearchRule::FuncNotStartWith, kli18n("does not start with")},
0031                        {SearchRule::FuncEndWith, kli18n("ends with")},
0032                        {SearchRule::FuncNotEndWith, kli18n("does not end with")},
0033 
0034                        {SearchRule::FuncRegExp, kli18n("matches regular expr.")},
0035                        {SearchRule::FuncNotRegExp, kli18n("does not match reg. expr.")},
0036                        {SearchRule::FuncIsInAddressbook, kli18n("is in address book")},
0037                        {SearchRule::FuncIsNotInAddressbook, kli18n("is not in address book")}};
0038 static const int HeadersFunctionCount = sizeof(HeaderFunctions) / sizeof(*HeaderFunctions);
0039 
0040 //---------------------------------------------------------------------------
0041 
0042 QWidget *HeadersRuleWidgetHandler::createFunctionWidget(int number, QStackedWidget *functionStack, const QObject *receiver, bool isBalooSearch) const
0043 {
0044     if (number != 0) {
0045         return nullptr;
0046     }
0047 
0048     auto funcCombo = new QComboBox(functionStack);
0049     funcCombo->setMinimumWidth(50);
0050     funcCombo->setObjectName(QLatin1StringView("headerRuleFuncCombo"));
0051     for (int i = 0; i < HeadersFunctionCount; ++i) {
0052         if (!(isBalooSearch && (HeaderFunctions[i].id == SearchRule::FuncIsInAddressbook || HeaderFunctions[i].id == SearchRule::FuncIsNotInAddressbook))) {
0053             funcCombo->addItem(HeaderFunctions[i].displayName.toString());
0054         }
0055     }
0056     funcCombo->adjustSize();
0057     QObject::connect(funcCombo, SIGNAL(activated(int)), receiver, SLOT(slotFunctionChanged()));
0058     return funcCombo;
0059 }
0060 
0061 //---------------------------------------------------------------------------
0062 
0063 QWidget *HeadersRuleWidgetHandler::createValueWidget(int number, QStackedWidget *valueStack, const QObject *receiver) const
0064 {
0065     if (number == 0) {
0066         auto lineEdit = new KLineEdit(valueStack);
0067         lineEdit->setClearButtonEnabled(true);
0068         lineEdit->setTrapReturnKey(true);
0069         lineEdit->setObjectName(QLatin1StringView("regExpLineEdit"));
0070         QObject::connect(lineEdit, SIGNAL(textChanged(QString)), receiver, SLOT(slotValueChanged()));
0071         QObject::connect(lineEdit, SIGNAL(returnPressed()), receiver, SLOT(slotReturnPressed()));
0072         return lineEdit;
0073     }
0074 
0075     // blank QLabel to hide value widget for in-address-book rule
0076     if (number == 1) {
0077         auto label = new QLabel(valueStack);
0078         label->setObjectName(QLatin1StringView("headerRuleValueHider"));
0079         label->setBuddy(valueStack);
0080         return label;
0081     }
0082     return nullptr;
0083 }
0084 
0085 //---------------------------------------------------------------------------
0086 
0087 SearchRule::Function HeadersRuleWidgetHandler::currentFunction(const QStackedWidget *functionStack) const
0088 {
0089     const auto funcCombo = functionStack->findChild<QComboBox *>(QStringLiteral("headerRuleFuncCombo"));
0090 
0091     if (funcCombo && funcCombo->currentIndex() >= 0) {
0092         return HeaderFunctions[funcCombo->currentIndex()].id;
0093     }
0094 
0095     return SearchRule::FuncNone;
0096 }
0097 
0098 //---------------------------------------------------------------------------
0099 
0100 SearchRule::Function HeadersRuleWidgetHandler::function(const QByteArray &field, const QStackedWidget *functionStack) const
0101 {
0102     if (!handlesField(field)) {
0103         return SearchRule::FuncNone;
0104     }
0105     return currentFunction(functionStack);
0106 }
0107 
0108 //---------------------------------------------------------------------------
0109 QString HeadersRuleWidgetHandler::currentValue(const QStackedWidget *valueStack, SearchRule::Function func) const
0110 {
0111     Q_UNUSED(func)
0112 
0113     const KLineEdit *lineEdit = valueStack->findChild<KLineEdit *>(QStringLiteral("regExpLineEdit"));
0114 
0115     if (lineEdit) {
0116         return lineEdit->text();
0117     }
0118 
0119     // or anything else, like addressbook
0120     return {};
0121 }
0122 
0123 //---------------------------------------------------------------------------
0124 
0125 QString HeadersRuleWidgetHandler::value(const QByteArray &field, const QStackedWidget *functionStack, const QStackedWidget *valueStack) const
0126 {
0127     if (!handlesField(field)) {
0128         return {};
0129     }
0130     SearchRule::Function func = currentFunction(functionStack);
0131     if (func == SearchRule::FuncIsInAddressbook) {
0132         return QStringLiteral("is in address book"); // just a non-empty dummy value
0133     } else if (func == SearchRule::FuncIsNotInAddressbook) {
0134         return QStringLiteral("is not in address book"); // just a non-empty dummy value
0135     } else {
0136         return currentValue(valueStack, func);
0137     }
0138 }
0139 
0140 //---------------------------------------------------------------------------
0141 
0142 QString HeadersRuleWidgetHandler::prettyValue(const QByteArray &field, const QStackedWidget *functionStack, const QStackedWidget *valueStack) const
0143 {
0144     if (!handlesField(field)) {
0145         return {};
0146     }
0147 
0148     SearchRule::Function func = currentFunction(functionStack);
0149 
0150     if (func == SearchRule::FuncIsInAddressbook) {
0151         return i18n("is in address book");
0152     } else if (func == SearchRule::FuncIsNotInAddressbook) {
0153         return i18n("is not in address book");
0154     } else {
0155         return currentValue(valueStack, func);
0156     }
0157 }
0158 
0159 //---------------------------------------------------------------------------
0160 
0161 bool HeadersRuleWidgetHandler::handlesField(const QByteArray &field) const
0162 {
0163     return field == "To" || field == "From" || field == "CC" || field == "<recipients>";
0164 }
0165 
0166 //---------------------------------------------------------------------------
0167 
0168 void HeadersRuleWidgetHandler::reset(QStackedWidget *functionStack, QStackedWidget *valueStack) const
0169 {
0170     // reset the function combo box
0171     const auto funcCombo = functionStack->findChild<QComboBox *>(QStringLiteral("headerRuleFuncCombo"));
0172 
0173     if (funcCombo) {
0174         funcCombo->blockSignals(true);
0175         funcCombo->setCurrentIndex(0);
0176         funcCombo->blockSignals(false);
0177     }
0178 
0179     // reset the value widget
0180     auto lineEdit = valueStack->findChild<KLineEdit *>(QStringLiteral("regExpLineEdit"));
0181     if (lineEdit) {
0182         lineEdit->blockSignals(true);
0183         lineEdit->clear();
0184         lineEdit->blockSignals(false);
0185         lineEdit->setClearButtonEnabled(false);
0186         lineEdit->setClearButtonEnabled(true);
0187         valueStack->setCurrentWidget(lineEdit);
0188     }
0189 }
0190 
0191 //---------------------------------------------------------------------------
0192 
0193 bool HeadersRuleWidgetHandler::setRule(QStackedWidget *functionStack, QStackedWidget *valueStack, const SearchRule::Ptr rule, bool isBalooSearch) const
0194 {
0195     if (!rule || !handlesField(rule->field())) {
0196         reset(functionStack, valueStack);
0197         return false;
0198     }
0199 
0200     const SearchRule::Function func = rule->function();
0201     if ((isBalooSearch && (func == SearchRule::FuncIsInAddressbook || func == SearchRule::FuncIsNotInAddressbook))) {
0202         reset(functionStack, valueStack);
0203         return false;
0204     }
0205 
0206     int i = 0;
0207     for (; i < HeadersFunctionCount; ++i) {
0208         if (func == HeaderFunctions[i].id) {
0209             break;
0210         }
0211     }
0212 
0213     const auto funcCombo = functionStack->findChild<QComboBox *>(QStringLiteral("headerRuleFuncCombo"));
0214 
0215     if (funcCombo) {
0216         funcCombo->blockSignals(true);
0217         if (i < HeadersFunctionCount) {
0218             funcCombo->setCurrentIndex(i);
0219         } else {
0220             funcCombo->setCurrentIndex(0);
0221         }
0222         funcCombo->blockSignals(false);
0223         functionStack->setCurrentWidget(funcCombo);
0224     }
0225 
0226     if (func == SearchRule::FuncIsInAddressbook || func == SearchRule::FuncIsNotInAddressbook) {
0227         auto w = valueStack->findChild<QWidget *>(QStringLiteral("headerRuleValueHider"));
0228         valueStack->setCurrentWidget(w);
0229     } else {
0230         auto lineEdit = valueStack->findChild<KLineEdit *>(QStringLiteral("regExpLineEdit"));
0231 
0232         if (lineEdit) {
0233             lineEdit->blockSignals(true);
0234             lineEdit->setText(rule->contents());
0235             lineEdit->blockSignals(false);
0236             lineEdit->setClearButtonEnabled(false);
0237             lineEdit->setClearButtonEnabled(true);
0238             valueStack->setCurrentWidget(lineEdit);
0239         }
0240     }
0241     return true;
0242 }
0243 
0244 //---------------------------------------------------------------------------
0245 
0246 bool HeadersRuleWidgetHandler::update(const QByteArray &field, QStackedWidget *functionStack, QStackedWidget *valueStack) const
0247 {
0248     if (!handlesField(field)) {
0249         return false;
0250     }
0251 
0252     // raise the correct function widget
0253     functionStack->setCurrentWidget(functionStack->findChild<QWidget *>(QStringLiteral("headerRuleFuncCombo")));
0254 
0255     // raise the correct value widget
0256     SearchRule::Function func = currentFunction(functionStack);
0257     if (func == SearchRule::FuncIsInAddressbook || func == SearchRule::FuncIsNotInAddressbook) {
0258         valueStack->setCurrentWidget(valueStack->findChild<QWidget *>(QStringLiteral("headerRuleValueHider")));
0259     } else {
0260         auto lineEdit = valueStack->findChild<KLineEdit *>(QStringLiteral("regExpLineEdit"));
0261 
0262         if (lineEdit) {
0263             valueStack->setCurrentWidget(lineEdit);
0264         }
0265     }
0266     return true;
0267 }