Libksieve

sieveincludewidget.cpp
1/*
2 SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "sieveincludewidget.h"
8#include "autocreatescripts/autocreatescriptutil_p.h"
9#include "autocreatescriptutil_p.h"
10#include "commonwidgets/sievehelpbutton.h"
11#include "sievescriptblockwidget.h"
12#include "widgets/includefilelineedit.h"
13#include <KLineEditEventHandler>
14
15#include <KLocalizedString>
16#include <QIcon>
17#include <QPushButton>
18#include <QScrollArea>
19
20#include "libksieveui_debug.h"
21#include <QCheckBox>
22#include <QGridLayout>
23#include <QLabel>
24#include <QWhatsThis>
25#include <QXmlStreamReader>
26
27using namespace KSieveUi;
28
29static const int MINIMUMINCLUDEACTION = 1;
30static const int MAXIMUMINCLUDEACTION = 20;
31
32SieveIncludeLocation::SieveIncludeLocation(QWidget *parent)
33 : QComboBox(parent)
34{
35 initialize();
36 connect(this, &SieveIncludeLocation::activated, this, &SieveIncludeLocation::valueChanged);
37}
38
39SieveIncludeLocation::~SieveIncludeLocation() = default;
40
41void SieveIncludeLocation::initialize()
42{
43 addItem(i18n("personal"), QStringLiteral(":personal"));
44 addItem(i18n("global"), QStringLiteral(":global"));
45}
46
47QString SieveIncludeLocation::code() const
48{
49 return itemData(currentIndex()).toString();
50}
51
52void SieveIncludeLocation::setCode(const QString &code, QString &error)
53{
54 const int index = findData(code);
55 if (index != -1) {
56 setCurrentIndex(index);
57 } else {
58 error += i18n("Unknown location type \"%1\" during parsing includes", code) + QLatin1Char('\n');
60 }
61}
62
63SieveIncludeActionWidget::SieveIncludeActionWidget(QWidget *parent)
64 : QWidget(parent)
65{
66 initWidget();
67}
68
69SieveIncludeActionWidget::~SieveIncludeActionWidget() = default;
70
71void SieveIncludeActionWidget::clear()
72{
73 mOptional->setChecked(false);
74 mOnce->setChecked(false);
75 mLocation->setCurrentIndex(0);
76 mIncludeFileName->clear();
77}
78
79void SieveIncludeActionWidget::setListOfIncludeFile(const QStringList &listOfIncludeFile)
80{
81 mIncludeFileName->setListOfIncludeFile(listOfIncludeFile);
82}
83
84void SieveIncludeActionWidget::loadScript(QXmlStreamReader &element, QString &error)
85{
86 while (element.readNextStartElement()) {
87 const QStringView tagName = element.name();
88 if (tagName == QLatin1StringView("tag")) {
89 const QString tagValue = element.readElementText();
90 if (tagValue == QLatin1StringView("personal") || tagValue == QLatin1StringView("global")) {
91 mLocation->setCode(AutoCreateScriptUtil::tagValue(tagValue), error);
92 } else if (tagValue == QLatin1StringView("optional")) {
93 mOptional->setChecked(true);
94 } else if (tagValue == QLatin1StringView("once")) {
95 mOnce->setChecked(true);
96 } else {
97 qCDebug(LIBKSIEVEUI_LOG) << " SieveIncludeActionWidget::loadScript unknown tagValue " << tagValue;
98 }
99 } else if (tagName == QLatin1StringView("str")) {
100 mIncludeFileName->setText(element.readElementText());
101 } else {
102 qCDebug(LIBKSIEVEUI_LOG) << " SieveIncludeActionWidget::loadScript unknown tagName " << tagName;
103 }
104 }
105}
106
107void SieveIncludeActionWidget::generatedScript(QString &script)
108{
109 const QString includeName = mIncludeFileName->text().trimmed();
110 if (includeName.isEmpty()) {
111 return;
112 }
113 script += QLatin1StringView("include ");
114 script += mLocation->code() + QLatin1Char(' ');
115 if (mOptional->isChecked()) {
116 script += QLatin1StringView(":optional ");
117 }
118 if (mOnce->isChecked()) {
119 script += QLatin1StringView(":once ");
120 }
121 script += QStringLiteral("\"%1\";\n").arg(includeName);
122}
123
124void SieveIncludeActionWidget::initWidget()
125{
126 mLayout = new QGridLayout(this);
127 mLayout->setContentsMargins({});
128
129 auto lab = new QLabel(i18nc("@label:textbox", "Include:"), this);
130 mLayout->addWidget(lab, 1, 0);
131 mLocation = new SieveIncludeLocation(this);
132 connect(mLocation, &SieveIncludeLocation::valueChanged, this, &SieveIncludeActionWidget::valueChanged);
133 mLayout->addWidget(mLocation, 1, 1);
134
135 lab = new QLabel(i18nc("@label:textbox", "Name:"), this);
136 mLayout->addWidget(lab, 1, 2);
137
138 mIncludeFileName = new IncludeFileLineEdit(this);
140 mIncludeFileName->setClearButtonEnabled(true);
141 connect(mIncludeFileName, &QLineEdit::textChanged, this, &SieveIncludeActionWidget::valueChanged);
142 mLayout->addWidget(mIncludeFileName, 1, 3);
143
144 mOptional = new QCheckBox(i18nc("@option:check", "Optional"), this);
145 connect(mOptional, &QCheckBox::toggled, this, &SieveIncludeActionWidget::valueChanged);
146 mLayout->addWidget(mOptional, 1, 4);
147
148 mOnce = new QCheckBox(i18nc("@option:check", "Once"), this);
149 connect(mOnce, &QCheckBox::toggled, this, &SieveIncludeActionWidget::valueChanged);
150 mLayout->addWidget(mOnce, 1, 5);
151
152 mAdd = new QPushButton(this);
153 mAdd->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
155
156 mRemove = new QPushButton(this);
157 mRemove->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
159 mLayout->addWidget(mAdd, 1, 6);
160 mLayout->addWidget(mRemove, 1, 7);
161
162 connect(mAdd, &QPushButton::clicked, this, &SieveIncludeActionWidget::slotAddWidget);
163 connect(mRemove, &QPushButton::clicked, this, &SieveIncludeActionWidget::slotRemoveWidget);
164}
165
166void SieveIncludeActionWidget::slotAddWidget()
167{
168 Q_EMIT valueChanged();
169 Q_EMIT addWidget(this);
170}
171
172void SieveIncludeActionWidget::slotRemoveWidget()
173{
174 Q_EMIT valueChanged();
175 Q_EMIT removeWidget(this);
176}
177
178bool SieveIncludeActionWidget::isInitialized() const
179{
180 return !mIncludeFileName->text().isEmpty();
181}
182
183void SieveIncludeActionWidget::updateAddRemoveButton(bool addButtonEnabled, bool removeButtonEnabled)
184{
185 mAdd->setEnabled(addButtonEnabled);
186 mRemove->setEnabled(removeButtonEnabled);
187}
188
189SieveIncludeWidget::SieveIncludeWidget(QWidget *parent)
190 : SieveWidgetPageAbstract(parent)
191{
192 auto lay = new QVBoxLayout(this);
193 mHelpButton = new SieveHelpButton(this);
194 lay->addWidget(mHelpButton);
195 connect(mHelpButton, &SieveHelpButton::clicked, this, &SieveIncludeWidget::slotHelp);
196
197 mIncludeLister = new SieveIncludeWidgetLister(this);
198 connect(mIncludeLister, &SieveIncludeWidgetLister::valueChanged, this, &SieveIncludeWidget::valueChanged);
199
200 auto scrollArea = new QScrollArea(this);
201 scrollArea->setAutoFillBackground(false);
202 scrollArea->setWidget(mIncludeLister);
203 scrollArea->setWidgetResizable(true);
204 scrollArea->setAlignment(Qt::AlignTop);
205 lay->addWidget(scrollArea);
206
207 setPageType(KSieveUi::SieveScriptBlockWidget::Include);
208}
209
210SieveIncludeWidget::~SieveIncludeWidget() = default;
211
212void SieveIncludeWidget::setListOfIncludeFile(const QStringList &lst)
213{
214 mIncludeLister->setListOfIncludeFile(lst);
215}
216
217void SieveIncludeWidget::slotHelp()
218{
219 const QString help = i18n(
220 "The \"include\" command takes an optional \"location\" parameter, an optional \":once\" parameter, an optional \":optional\" parameter, and a single "
221 "string argument representing the name of the script to include for processing at that point.");
222 const QString href = QStringLiteral("https://tools.ietf.org/html/rfc6609#page-4");
223 const QString fullWhatsThis = AutoCreateScriptUtil::createFullWhatsThis(help, href);
224 QWhatsThis::showText(QCursor::pos(), fullWhatsThis, mHelpButton);
225}
226
227void SieveIncludeWidget::generatedScript(QString &script, QStringList &requireModules, bool inForEveryPartLoop)
228{
229 Q_UNUSED(inForEveryPartLoop)
230 QString result;
231 QStringList lst;
232 mIncludeLister->generatedScript(result, lst);
233 if (!result.isEmpty()) {
234 script += result;
235 requireModules << lst;
236 }
237}
238
239void SieveIncludeWidget::loadScript(QXmlStreamReader &element, QString &error)
240{
241 mIncludeLister->loadScript(element, error);
242}
243
244SieveIncludeWidgetLister::SieveIncludeWidgetLister(QWidget *parent)
245 : KPIM::KWidgetLister(false, MINIMUMINCLUDEACTION, MAXIMUMINCLUDEACTION, parent)
246{
247 slotClear();
248 updateAddRemoveButton();
249}
250
251SieveIncludeWidgetLister::~SieveIncludeWidgetLister() = default;
252
253void SieveIncludeWidgetLister::slotAddWidget(QWidget *w)
254{
256 updateAddRemoveButton();
257}
258
259void SieveIncludeWidgetLister::slotRemoveWidget(QWidget *w)
260{
261 removeWidget(w);
262 updateAddRemoveButton();
263}
264
265void SieveIncludeWidgetLister::updateAddRemoveButton()
266{
267 QList<QWidget *> widgetList = widgets();
268 const int numberOfWidget(widgetList.count());
269 bool addButtonEnabled = false;
270 bool removeButtonEnabled = false;
271 if (numberOfWidget <= widgetsMinimum()) {
272 addButtonEnabled = true;
273 removeButtonEnabled = false;
274 } else if (numberOfWidget >= widgetsMaximum()) {
275 addButtonEnabled = false;
276 removeButtonEnabled = true;
277 } else {
278 addButtonEnabled = true;
279 removeButtonEnabled = true;
280 }
282 QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
283 for (; wIt != wEnd; ++wIt) {
285 w->updateAddRemoveButton(addButtonEnabled, removeButtonEnabled);
286 }
287}
288
289void SieveIncludeWidgetLister::setListOfIncludeFile(const QStringList &listOfIncludeFile)
290{
291 mListOfIncludeFile = listOfIncludeFile;
292 // Update all lineedit
293 const QList<QWidget *> widgetList = widgets();
295 QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
296 for (; wIt != wEnd; ++wIt) {
298 w->setListOfIncludeFile(mListOfIncludeFile);
299 }
300}
301
302void SieveIncludeWidgetLister::generatedScript(QString &script, QStringList &requireModules)
303{
304 requireModules << QStringLiteral("include");
305 const QList<QWidget *> widgetList = widgets();
307 QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
308 for (; wIt != wEnd; ++wIt) {
310 w->generatedScript(script);
311 }
312}
313
314void SieveIncludeWidgetLister::reconnectWidget(SieveIncludeActionWidget *w)
315{
316 connect(w, &SieveIncludeActionWidget::addWidget, this, &SieveIncludeWidgetLister::slotAddWidget, Qt::UniqueConnection);
317 connect(w, &SieveIncludeActionWidget::removeWidget, this, &SieveIncludeWidgetLister::slotRemoveWidget, Qt::UniqueConnection);
318 connect(w, &SieveIncludeActionWidget::valueChanged, this, &SieveIncludeWidgetLister::valueChanged, Qt::UniqueConnection);
319}
320
321void SieveIncludeWidgetLister::clearWidget(QWidget *aWidget)
322{
323 if (aWidget) {
324 auto widget = static_cast<SieveIncludeActionWidget *>(aWidget);
325 widget->clear();
326 updateAddRemoveButton();
327 }
328 Q_EMIT valueChanged();
329}
330
331QWidget *SieveIncludeWidgetLister::createWidget(QWidget *parent)
332{
333 auto w = new SieveIncludeActionWidget(parent);
334 w->setListOfIncludeFile(mListOfIncludeFile);
335 reconnectWidget(w);
336 return w;
337}
338
339void SieveIncludeWidgetLister::loadScript(QXmlStreamReader &element, QString &error)
340{
341 if (widgets().count() == MAXIMUMINCLUDEACTION) {
342 error += QLatin1Char('\n') + i18n("We can not add more includes elements.") + QLatin1Char('\n');
343 return;
344 }
345 SieveIncludeActionWidget *w = static_cast<SieveIncludeActionWidget *>(widgets().constLast());
346 if (w->isInitialized()) {
347 addWidgetAfterThisWidget(widgets().constLast());
348 w = static_cast<SieveIncludeActionWidget *>(widgets().constLast());
349 }
350 w->loadScript(element, error);
351}
352
353#include "moc_sieveincludewidget.cpp"
virtual void addWidgetAfterThisWidget(QWidget *currentWidget, QWidget *widget=nullptr)
virtual void removeWidget(QWidget *widget)
int widgetsMaximum() const
QList< QWidget * > widgets() const
int widgetsMinimum() const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KCRASH_EXPORT void initialize()
void catchReturnKey(QObject *lineEdit)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
const QList< QKeySequence > & help()
QByteArray tagValue(const Elem &elem, const char *keyName)
void setChecked(bool)
void clicked(bool checked)
void setIcon(const QIcon &icon)
void toggled(bool checked)
void addItem(const QIcon &icon, const QString &text, const QVariant &userData)
int findData(const QVariant &data, int role, Qt::MatchFlags flags) const const
QVariant itemData(int index, int role) const const
QPoint pos()
void addWidget(QWidget *widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment)
QIcon fromTheme(const QString &name)
void setContentsMargins(const QMargins &margins)
void clear()
void setClearButtonEnabled(bool enable)
void setText(const QString &)
void textChanged(const QString &text)
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
T qobject_cast(QObject *object)
QString arg(Args &&... args) const const
bool isEmpty() const const
AlignTop
UniqueConnection
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QString toString() const const
void showText(const QPoint &pos, const QString &text, QWidget *w)
void setEnabled(bool)
void setSizePolicy(QSizePolicy)
QStringView name() const const
QString readElementText(ReadElementTextBehaviour behaviour)
bool readNextStartElement()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 16:57:10 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.