1 /*
2    SPDX-FileCopyrightText: 2013-2021 Laurent Montel <montel@kde.org>
3 
4    SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "sieveglobalvariablewidget.h"
8 #include "autocreatescriptutil_p.h"
9 #include "commonwidgets/sievehelpbutton.h"
10 #include "editor/sieveeditorutil.h"
11 #include "sievescriptblockwidget.h"
12 #include "widgets/lineeditvalidator.h"
13 
14 #include <KLocalizedString>
15 #include <Libkdepim/LineEditCatchReturnKey>
16 #include <QIcon>
17 #include <QLineEdit>
18 #include <QPushButton>
19 
20 #include "libksieve_debug.h"
21 #include <QCheckBox>
22 #include <QGridLayout>
23 #include <QLabel>
24 #include <QWhatsThis>
25 #include <QXmlStreamReader>
26 
27 using namespace KSieveUi;
28 static const int MINIMUMGLOBALVARIABLEACTION = 1;
29 static const int MAXIMUMGLOBALVARIABLEACTION = 15;
30 
SieveGlobalVariableActionWidget(QWidget * parent)31 SieveGlobalVariableActionWidget::SieveGlobalVariableActionWidget(QWidget *parent)
32     : QWidget(parent)
33 {
34     initWidget();
35 }
36 
~SieveGlobalVariableActionWidget()37 SieveGlobalVariableActionWidget::~SieveGlobalVariableActionWidget()
38 {
39 }
40 
generatedScript(QString & script)41 void SieveGlobalVariableActionWidget::generatedScript(QString &script)
42 {
43     const QString variableName = mVariableName->text();
44     if (variableName.trimmed().isEmpty()) {
45         return;
46     }
47     script += QLatin1String("global ");
48     script += QStringLiteral("\"%1\";\n").arg(variableName);
49     if (mSetValueTo->isChecked() && !mVariableValue->text().isEmpty()) {
50         script += QStringLiteral("set \"%1\" \"%2\";\n").arg(variableName, mVariableValue->text());
51     }
52 }
53 
initWidget()54 void SieveGlobalVariableActionWidget::initWidget()
55 {
56     mLayout = new QGridLayout(this);
57     mLayout->setContentsMargins({});
58 
59     auto lab = new QLabel(i18n("Variable name:"), this);
60     mLayout->addWidget(lab, 1, 0);
61 
62     mVariableName = new LineEditValidator(this);
63     connect(mVariableName, &QLineEdit::textChanged, this, &SieveGlobalVariableActionWidget::valueChanged);
64     mLayout->addWidget(mVariableName, 1, 1);
65 
66     mSetValueTo = new QCheckBox(i18n("Set value to:"), this);
67     connect(mSetValueTo, &QCheckBox::toggled, this, &SieveGlobalVariableActionWidget::valueChanged);
68     mLayout->addWidget(mSetValueTo, 1, 2);
69     mSetValueTo->setChecked(false);
70 
71     mVariableValue = new QLineEdit(this);
72     new KPIM::LineEditCatchReturnKey(mVariableValue, this);
73     connect(mVariableValue, &QLineEdit::textChanged, this, &SieveGlobalVariableActionWidget::valueChanged);
74     mVariableValue->setEnabled(false);
75     mLayout->addWidget(mVariableValue, 1, 3);
76 
77     connect(mSetValueTo, &QCheckBox::clicked, mVariableValue, &QLineEdit::setEnabled);
78 
79     mAdd = new QPushButton(this);
80     mAdd->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
81     mAdd->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
82 
83     mRemove = new QPushButton(this);
84     mRemove->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
85     mRemove->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
86     mLayout->addWidget(mAdd, 1, 4);
87     mLayout->addWidget(mRemove, 1, 5);
88 
89     connect(mAdd, &QPushButton::clicked, this, &SieveGlobalVariableActionWidget::slotAddWidget);
90     connect(mRemove, &QPushButton::clicked, this, &SieveGlobalVariableActionWidget::slotRemoveWidget);
91 }
92 
clear()93 void SieveGlobalVariableActionWidget::clear()
94 {
95     mVariableName->clear();
96     mSetValueTo->setChecked(false);
97     mVariableValue->setEnabled(false);
98     mVariableValue->clear();
99 }
100 
isInitialized() const101 bool SieveGlobalVariableActionWidget::isInitialized() const
102 {
103     return !mVariableName->text().isEmpty();
104 }
105 
variableName() const106 QString SieveGlobalVariableActionWidget::variableName() const
107 {
108     const QString varName = mVariableName->text();
109     if (varName.trimmed().isEmpty()) {
110         return {};
111     }
112     return varName;
113 }
114 
setVariableValue(const QString & name)115 void SieveGlobalVariableActionWidget::setVariableValue(const QString &name)
116 {
117     mSetValueTo->setChecked(true);
118     mVariableValue->setText(name);
119     mVariableValue->setEnabled(true);
120 }
121 
loadScript(QXmlStreamReader & element,QString & error)122 void SieveGlobalVariableActionWidget::loadScript(QXmlStreamReader &element, QString &error)
123 {
124     while (element.readNextStartElement()) {
125         const QStringRef tagName = element.name();
126         if (tagName == QLatin1String("str")) {
127             mVariableName->setText(element.readElementText());
128         } else {
129             error += i18n("Unknown tag \"%1\" during loading of variables.", *tagName.string()) + QLatin1Char('\n');
130             qCDebug(LIBKSIEVE_LOG) << " SieveGlobalVariableActionWidget::loadScript unknown tagName " << tagName;
131         }
132     }
133 }
134 
slotAddWidget()135 void SieveGlobalVariableActionWidget::slotAddWidget()
136 {
137     Q_EMIT addWidget(this);
138     Q_EMIT valueChanged();
139 }
140 
slotRemoveWidget()141 void SieveGlobalVariableActionWidget::slotRemoveWidget()
142 {
143     Q_EMIT removeWidget(this);
144     Q_EMIT valueChanged();
145 }
146 
updateAddRemoveButton(bool addButtonEnabled,bool removeButtonEnabled)147 void SieveGlobalVariableActionWidget::updateAddRemoveButton(bool addButtonEnabled, bool removeButtonEnabled)
148 {
149     mAdd->setEnabled(addButtonEnabled);
150     mRemove->setEnabled(removeButtonEnabled);
151 }
152 
SieveGlobalVariableWidget(QWidget * parent)153 SieveGlobalVariableWidget::SieveGlobalVariableWidget(QWidget *parent)
154     : SieveWidgetPageAbstract(parent)
155 {
156     auto lay = new QVBoxLayout(this);
157     mHelpButton = new SieveHelpButton(this);
158     lay->addWidget(mHelpButton);
159     connect(mHelpButton, &SieveHelpButton::clicked, this, &SieveGlobalVariableWidget::slotHelp);
160 
161     mIncludeLister = new SieveGlobalVariableLister(this);
162     connect(mIncludeLister, &SieveGlobalVariableLister::valueChanged, this, &SieveGlobalVariableWidget::valueChanged);
163     lay->addWidget(mIncludeLister, 0, Qt::AlignTop);
164     setPageType(KSieveUi::SieveScriptBlockWidget::GlobalVariable);
165 }
166 
~SieveGlobalVariableWidget()167 SieveGlobalVariableWidget::~SieveGlobalVariableWidget()
168 {
169 }
170 
slotHelp()171 void SieveGlobalVariableWidget::slotHelp()
172 {
173     const QString help = i18n(
174         "A variable has global scope in all scripts that have declared it with the \"global\" command.  If a script uses that variable name without declaring "
175         "it global, the name specifies a separate, non-global variable within that script.");
176     const QUrl href = KSieveUi::SieveEditorUtil::helpUrl(KSieveUi::SieveEditorUtil::GlobalVariable);
177     const QString fullWhatsThis = AutoCreateScriptUtil::createFullWhatsThis(help, href.toString());
178     QWhatsThis::showText(QCursor::pos(), fullWhatsThis, mHelpButton);
179 }
180 
generatedScript(QString & script,QStringList & requireModules,bool inForEveryPartLoop)181 void SieveGlobalVariableWidget::generatedScript(QString &script, QStringList &requireModules, bool inForEveryPartLoop)
182 {
183     Q_UNUSED(inForEveryPartLoop)
184     QString result;
185     QStringList lst;
186     mIncludeLister->generatedScript(result, lst);
187     if (!result.isEmpty()) {
188         script += result;
189         requireModules << lst;
190     }
191 }
192 
loadScript(QXmlStreamReader & element,QString & error)193 void SieveGlobalVariableWidget::loadScript(QXmlStreamReader &element, QString &error)
194 {
195     mIncludeLister->loadScript(element, error);
196 }
197 
loadSetVariable(QXmlStreamReader & element,QString & error)198 SieveGlobalVariableActionWidget::VariableElement SieveGlobalVariableWidget::loadSetVariable(QXmlStreamReader &element, QString &error)
199 {
200     return mIncludeLister->loadSetVariable(element, error);
201 }
202 
SieveGlobalVariableLister(QWidget * parent)203 SieveGlobalVariableLister::SieveGlobalVariableLister(QWidget *parent)
204     : KPIM::KWidgetLister(false, MINIMUMGLOBALVARIABLEACTION, MAXIMUMGLOBALVARIABLEACTION, parent)
205 {
206     slotClear();
207     updateAddRemoveButton();
208 }
209 
~SieveGlobalVariableLister()210 SieveGlobalVariableLister::~SieveGlobalVariableLister()
211 {
212 }
213 
slotAddWidget(QWidget * w)214 void SieveGlobalVariableLister::slotAddWidget(QWidget *w)
215 {
216     addWidgetAfterThisWidget(w);
217     updateAddRemoveButton();
218 }
219 
slotRemoveWidget(QWidget * w)220 void SieveGlobalVariableLister::slotRemoveWidget(QWidget *w)
221 {
222     removeWidget(w);
223     updateAddRemoveButton();
224 }
225 
updateAddRemoveButton()226 void SieveGlobalVariableLister::updateAddRemoveButton()
227 {
228     QList<QWidget *> widgetList = widgets();
229     const int numberOfWidget(widgetList.count());
230     bool addButtonEnabled = false;
231     bool removeButtonEnabled = false;
232     if (numberOfWidget <= widgetsMinimum()) {
233         addButtonEnabled = true;
234         removeButtonEnabled = false;
235     } else if (numberOfWidget >= widgetsMaximum()) {
236         addButtonEnabled = false;
237         removeButtonEnabled = true;
238     } else {
239         addButtonEnabled = true;
240         removeButtonEnabled = true;
241     }
242     QList<QWidget *>::ConstIterator wIt = widgetList.constBegin();
243     QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
244     for (; wIt != wEnd; ++wIt) {
245         auto w = qobject_cast<SieveGlobalVariableActionWidget *>(*wIt);
246         w->updateAddRemoveButton(addButtonEnabled, removeButtonEnabled);
247     }
248 }
249 
generatedScript(QString & script,QStringList & requireModules)250 void SieveGlobalVariableLister::generatedScript(QString &script, QStringList &requireModules)
251 {
252     requireModules << QStringLiteral("include");
253     const QList<QWidget *> widgetList = widgets();
254     QList<QWidget *>::ConstIterator wIt = widgetList.constBegin();
255     QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
256     for (; wIt != wEnd; ++wIt) {
257         auto w = qobject_cast<SieveGlobalVariableActionWidget *>(*wIt);
258         w->generatedScript(script);
259     }
260 }
261 
reconnectWidget(SieveGlobalVariableActionWidget * w)262 void SieveGlobalVariableLister::reconnectWidget(SieveGlobalVariableActionWidget *w)
263 {
264     connect(w, &SieveGlobalVariableActionWidget::addWidget, this, &SieveGlobalVariableLister::slotAddWidget, Qt::UniqueConnection);
265     connect(w, &SieveGlobalVariableActionWidget::removeWidget, this, &SieveGlobalVariableLister::slotRemoveWidget, Qt::UniqueConnection);
266     connect(w, &SieveGlobalVariableActionWidget::valueChanged, this, &SieveGlobalVariableLister::valueChanged, Qt::UniqueConnection);
267 }
268 
clearWidget(QWidget * aWidget)269 void SieveGlobalVariableLister::clearWidget(QWidget *aWidget)
270 {
271     if (aWidget) {
272         auto widget = static_cast<SieveGlobalVariableActionWidget *>(aWidget);
273         widget->clear();
274     }
275     Q_EMIT valueChanged();
276 }
277 
createWidget(QWidget * parent)278 QWidget *SieveGlobalVariableLister::createWidget(QWidget *parent)
279 {
280     auto w = new SieveGlobalVariableActionWidget(parent);
281     reconnectWidget(w);
282     return w;
283 }
284 
loadScript(QXmlStreamReader & element,QString & error)285 void SieveGlobalVariableLister::loadScript(QXmlStreamReader &element, QString &error)
286 {
287     SieveGlobalVariableActionWidget *w = static_cast<SieveGlobalVariableActionWidget *>(widgets().constLast());
288     if (w->isInitialized()) {
289         addWidgetAfterThisWidget(widgets().constLast());
290         w = static_cast<SieveGlobalVariableActionWidget *>(widgets().constLast());
291     }
292     w->loadScript(element, error);
293 }
294 
loadSetVariable(QXmlStreamReader & element,QString &)295 SieveGlobalVariableActionWidget::VariableElement SieveGlobalVariableLister::loadSetVariable(QXmlStreamReader &element, QString & /*error*/)
296 {
297     SieveGlobalVariableActionWidget::VariableElement var;
298     QString variableName;
299     QString variableValue;
300     int index = 0;
301     while (element.readNextStartElement()) {
302         const QStringRef tagName = element.name();
303         if (tagName == QLatin1String("str")) {
304             if (index == 0) {
305                 variableName = element.readElementText();
306             } else if (index == 1) {
307                 variableValue = element.readElementText();
308             } else {
309                 qCDebug(LIBKSIEVE_LOG) << " SieveGlobalVariableLister::loadSetVariable too many argument:" << index;
310             }
311             ++index;
312         } else {
313             qCDebug(LIBKSIEVE_LOG) << " SieveGlobalVariableLister::loadSetVariable unknown tagName " << tagName;
314         }
315     }
316 
317     const QList<QWidget *> lstWidget = widgets();
318     bool globalVariableFound = false;
319     for (QWidget *widget : lstWidget) {
320         auto w = static_cast<SieveGlobalVariableActionWidget *>(widget);
321         if (w->variableName() == variableName) {
322             w->setVariableValue(variableValue);
323             globalVariableFound = true;
324         }
325     }
326     if (!globalVariableFound) {
327         var.variableName = variableName;
328         var.variableValue = variableValue;
329     }
330     return var;
331 }
332