1 /*
2   SPDX-FileCopyrightText: 2013-2021 Laurent Montel <montel@kde.org>
3 
4   SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "textrulerwidgethandler.h"
8 
9 #include "search/searchpattern.h"
10 #include <KLineEdit>
11 #include <KLocalizedString>
12 #include <QComboBox>
13 #include <QStackedWidget>
14 
15 using namespace MailCommon;
16 
17 #include <QLabel>
18 
19 // also see SearchRule::matches() and SearchRule::Function
20 // if you change the following strings!
21 static const struct {
22     SearchRule::Function id;
23     const char *displayName;
24 } TextFunctions[] = {{SearchRule::FuncContains, I18N_NOOP("contains")},
25                      {SearchRule::FuncContainsNot, I18N_NOOP("does not contain")},
26                      {SearchRule::FuncEquals, I18N_NOOP("equals")},
27                      {SearchRule::FuncNotEqual, I18N_NOOP("does not equal")},
28                      {SearchRule::FuncStartWith, I18N_NOOP("starts with")},
29                      {SearchRule::FuncNotStartWith, I18N_NOOP("does not start with")},
30                      {SearchRule::FuncEndWith, I18N_NOOP("ends with")},
31                      {SearchRule::FuncNotEndWith, I18N_NOOP("does not end with")},
32 
33                      {SearchRule::FuncRegExp, I18N_NOOP("matches regular expr.")},
34                      {SearchRule::FuncNotRegExp, I18N_NOOP("does not match reg. expr.")}};
35 static const int TextFunctionCount = sizeof(TextFunctions) / sizeof(*TextFunctions);
36 
37 //---------------------------------------------------------------------------
38 
createFunctionWidget(int number,QStackedWidget * functionStack,const QObject * receiver,bool) const39 QWidget *TextRuleWidgetHandler::createFunctionWidget(int number, QStackedWidget *functionStack, const QObject *receiver, bool /*isBalooSearch*/) const
40 {
41     if (number != 0) {
42         return nullptr;
43     }
44 
45     auto funcCombo = new QComboBox(functionStack);
46     funcCombo->setMinimumWidth(50);
47     funcCombo->setObjectName(QStringLiteral("textRuleFuncCombo"));
48     for (int i = 0; i < TextFunctionCount; ++i) {
49         funcCombo->addItem(i18n(TextFunctions[i].displayName));
50     }
51     funcCombo->adjustSize();
52     QObject::connect(funcCombo, SIGNAL(activated(int)), receiver, SLOT(slotFunctionChanged()));
53     return funcCombo;
54 }
55 
56 //---------------------------------------------------------------------------
57 
createValueWidget(int number,QStackedWidget * valueStack,const QObject * receiver) const58 QWidget *TextRuleWidgetHandler::createValueWidget(int number, QStackedWidget *valueStack, const QObject *receiver) const
59 {
60     if (number == 0) {
61         auto lineEdit = new KLineEdit(valueStack);
62         lineEdit->setClearButtonEnabled(true);
63         lineEdit->setTrapReturnKey(true);
64         lineEdit->setObjectName(QStringLiteral("regExpLineEdit"));
65         QObject::connect(lineEdit, SIGNAL(textChanged(QString)), receiver, SLOT(slotValueChanged()));
66         QObject::connect(lineEdit, SIGNAL(returnPressed()), receiver, SLOT(slotReturnPressed()));
67         return lineEdit;
68     }
69 
70     // blank QLabel to hide value widget for in-address-book rule
71     if (number == 1) {
72         auto label = new QLabel(valueStack);
73         label->setObjectName(QStringLiteral("textRuleValueHider"));
74         label->setBuddy(valueStack);
75         return label;
76     }
77     return nullptr;
78 }
79 
80 //---------------------------------------------------------------------------
81 
currentFunction(const QStackedWidget * functionStack) const82 SearchRule::Function TextRuleWidgetHandler::currentFunction(const QStackedWidget *functionStack) const
83 {
84     const auto funcCombo = functionStack->findChild<QComboBox *>(QStringLiteral("textRuleFuncCombo"));
85 
86     if (funcCombo && funcCombo->currentIndex() >= 0) {
87         return TextFunctions[funcCombo->currentIndex()].id;
88     }
89 
90     return SearchRule::FuncNone;
91 }
92 
93 //---------------------------------------------------------------------------
94 
function(const QByteArray &,const QStackedWidget * functionStack) const95 SearchRule::Function TextRuleWidgetHandler::function(const QByteArray &, const QStackedWidget *functionStack) const
96 {
97     return currentFunction(functionStack);
98 }
99 
100 //---------------------------------------------------------------------------
101 
currentValue(const QStackedWidget * valueStack,SearchRule::Function) const102 QString TextRuleWidgetHandler::currentValue(const QStackedWidget *valueStack, SearchRule::Function) const
103 {
104     // in other cases of func it is a lineedit
105     const KLineEdit *lineEdit = valueStack->findChild<KLineEdit *>(QStringLiteral("regExpLineEdit"));
106 
107     if (lineEdit) {
108         return lineEdit->text();
109     }
110 
111     // or anything else, like addressbook
112     return QString();
113 }
114 
115 //---------------------------------------------------------------------------
116 
value(const QByteArray &,const QStackedWidget * functionStack,const QStackedWidget * valueStack) const117 QString TextRuleWidgetHandler::value(const QByteArray &, const QStackedWidget *functionStack, const QStackedWidget *valueStack) const
118 {
119     SearchRule::Function func = currentFunction(functionStack);
120     return currentValue(valueStack, func);
121 }
122 
123 //---------------------------------------------------------------------------
124 
prettyValue(const QByteArray &,const QStackedWidget * functionStack,const QStackedWidget * valueStack) const125 QString TextRuleWidgetHandler::prettyValue(const QByteArray &, const QStackedWidget *functionStack, const QStackedWidget *valueStack) const
126 {
127     SearchRule::Function func = currentFunction(functionStack);
128     return currentValue(valueStack, func);
129 }
130 
131 //---------------------------------------------------------------------------
132 
handlesField(const QByteArray &) const133 bool TextRuleWidgetHandler::handlesField(const QByteArray &) const
134 {
135     return true; // we handle all fields (as fallback)
136 }
137 
138 //---------------------------------------------------------------------------
139 
reset(QStackedWidget * functionStack,QStackedWidget * valueStack) const140 void TextRuleWidgetHandler::reset(QStackedWidget *functionStack, QStackedWidget *valueStack) const
141 {
142     // reset the function combo box
143     const auto funcCombo = functionStack->findChild<QComboBox *>(QStringLiteral("textRuleFuncCombo"));
144 
145     if (funcCombo) {
146         funcCombo->blockSignals(true);
147         funcCombo->setCurrentIndex(0);
148         funcCombo->blockSignals(false);
149     }
150 
151     // reset the value widget
152     auto *lineEdit = valueStack->findChild<KLineEdit *>(QStringLiteral("regExpLineEdit"));
153     if (lineEdit) {
154         lineEdit->blockSignals(true);
155         lineEdit->clear();
156         lineEdit->blockSignals(false);
157         lineEdit->setClearButtonEnabled(false);
158         lineEdit->setClearButtonEnabled(true);
159         valueStack->setCurrentWidget(lineEdit);
160     }
161 }
162 
163 //---------------------------------------------------------------------------
164 
setRule(QStackedWidget * functionStack,QStackedWidget * valueStack,const SearchRule::Ptr rule,bool) const165 bool TextRuleWidgetHandler::setRule(QStackedWidget *functionStack, QStackedWidget *valueStack, const SearchRule::Ptr rule, bool /*isBalooSearch*/) const
166 {
167     if (!rule) {
168         reset(functionStack, valueStack);
169         return false;
170     }
171 
172     const SearchRule::Function func = rule->function();
173     int i = 0;
174     for (; i < TextFunctionCount; ++i) {
175         if (func == TextFunctions[i].id) {
176             break;
177         }
178     }
179 
180     const auto funcCombo = functionStack->findChild<QComboBox *>(QStringLiteral("textRuleFuncCombo"));
181 
182     if (funcCombo) {
183         funcCombo->blockSignals(true);
184         if (i < TextFunctionCount) {
185             funcCombo->setCurrentIndex(i);
186         } else {
187             funcCombo->setCurrentIndex(0);
188         }
189         funcCombo->blockSignals(false);
190         functionStack->setCurrentWidget(funcCombo);
191     }
192     auto *lineEdit = valueStack->findChild<KLineEdit *>(QStringLiteral("regExpLineEdit"));
193 
194     if (lineEdit) {
195         lineEdit->blockSignals(true);
196         lineEdit->setText(rule->contents());
197         lineEdit->blockSignals(false);
198         lineEdit->setClearButtonEnabled(false);
199         lineEdit->setClearButtonEnabled(true);
200         valueStack->setCurrentWidget(lineEdit);
201     }
202     return true;
203 }
204 
205 //---------------------------------------------------------------------------
206 
update(const QByteArray &,QStackedWidget * functionStack,QStackedWidget * valueStack) const207 bool TextRuleWidgetHandler::update(const QByteArray &, QStackedWidget *functionStack, QStackedWidget *valueStack) const
208 {
209     // raise the correct function widget
210     functionStack->setCurrentWidget(functionStack->findChild<QWidget *>(QStringLiteral("textRuleFuncCombo")));
211 
212     // raise the correct value widget
213     SearchRule::Function func = currentFunction(functionStack);
214     if (func == SearchRule::FuncIsInAddressbook || func == SearchRule::FuncIsNotInAddressbook) {
215         valueStack->setCurrentWidget(valueStack->findChild<QWidget *>(QStringLiteral("textRuleValueHider")));
216     } else {
217         auto *lineEdit = valueStack->findChild<KLineEdit *>(QStringLiteral("regExpLineEdit"));
218 
219         if (lineEdit) {
220             valueStack->setCurrentWidget(lineEdit);
221         }
222     }
223     return true;
224 }
225