Libksieve

sieveincludewidget.cpp
1 /*
2  SPDX-FileCopyrightText: 2013-2021 Laurent Montel <[email protected]>
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 "editor/sieveeditorutil.h"
12 #include "sievescriptblockwidget.h"
13 #include "widgets/includefilelineedit.h"
14 #include <Libkdepim/LineEditCatchReturnKey>
15 
16 #include <KLocalizedString>
17 #include <QIcon>
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 
29 static const int MINIMUMINCLUDEACTION = 1;
30 static const int MAXIMUMINCLUDEACTION = 20;
31 
32 SieveIncludeLocation::SieveIncludeLocation(QWidget *parent)
33  : QComboBox(parent)
34 {
35  initialize();
36  connect(this, QOverload<int>::of(&SieveIncludeLocation::activated), this, &SieveIncludeLocation::valueChanged);
37 }
38 
39 SieveIncludeLocation::~SieveIncludeLocation()
40 {
41 }
42 
43 void SieveIncludeLocation::initialize()
44 {
45  addItem(i18n("personal"), QStringLiteral(":personal"));
46  addItem(i18n("global"), QStringLiteral(":global"));
47 }
48 
49 QString SieveIncludeLocation::code() const
50 {
51  return itemData(currentIndex()).toString();
52 }
53 
54 void SieveIncludeLocation::setCode(const QString &code, QString &error)
55 {
56  const int index = findData(code);
57  if (index != -1) {
58  setCurrentIndex(index);
59  } else {
60  error += i18n("Unknown location type \"%1\" during parsing includes", code) + QLatin1Char('\n');
61  setCurrentIndex(0);
62  }
63 }
64 
65 SieveIncludeActionWidget::SieveIncludeActionWidget(QWidget *parent)
66  : QWidget(parent)
67 {
68  initWidget();
69 }
70 
71 SieveIncludeActionWidget::~SieveIncludeActionWidget()
72 {
73 }
74 
75 void SieveIncludeActionWidget::clear()
76 {
77  mOptional->setChecked(false);
78  mOnce->setChecked(false);
79  mLocation->setCurrentIndex(0);
80  mIncludeFileName->clear();
81 }
82 
83 void SieveIncludeActionWidget::setListOfIncludeFile(const QStringList &listOfIncludeFile)
84 {
85  mIncludeFileName->setListOfIncludeFile(listOfIncludeFile);
86 }
87 
88 void SieveIncludeActionWidget::loadScript(QXmlStreamReader &element, QString &error)
89 {
90  while (element.readNextStartElement()) {
91  const QStringRef tagName = element.name();
92  if (tagName == QLatin1String("tag")) {
93  const QString tagValue = element.readElementText();
94  if (tagValue == QLatin1String("personal") || tagValue == QLatin1String("global")) {
95  mLocation->setCode(AutoCreateScriptUtil::tagValue(tagValue), error);
96  } else if (tagValue == QLatin1String("optional")) {
97  mOptional->setChecked(true);
98  } else if (tagValue == QLatin1String("once")) {
99  mOnce->setChecked(true);
100  } else {
101  qCDebug(LIBKSIEVE_LOG) << " SieveIncludeActionWidget::loadScript unknown tagValue " << tagValue;
102  }
103  } else if (tagName == QLatin1String("str")) {
104  mIncludeFileName->setText(element.readElementText());
105  } else {
106  qCDebug(LIBKSIEVE_LOG) << " SieveIncludeActionWidget::loadScript unknown tagName " << tagName;
107  }
108  }
109 }
110 
111 void SieveIncludeActionWidget::generatedScript(QString &script)
112 {
113  const QString includeName = mIncludeFileName->text();
114  if (includeName.trimmed().isEmpty()) {
115  return;
116  }
117  script += QLatin1String("include ");
118  script += mLocation->code() + QLatin1Char(' ');
119  if (mOptional->isChecked()) {
120  script += QLatin1String(":optional ");
121  }
122  if (mOnce->isChecked()) {
123  script += QLatin1String(":once ");
124  }
125  script += QStringLiteral("\"%1\";\n").arg(includeName);
126 }
127 
128 void SieveIncludeActionWidget::initWidget()
129 {
130  mLayout = new QGridLayout(this);
131  mLayout->setContentsMargins({});
132 
133  auto lab = new QLabel(i18n("Include:"), this);
134  mLayout->addWidget(lab, 1, 0);
135  mLocation = new SieveIncludeLocation(this);
136  connect(mLocation, &SieveIncludeLocation::valueChanged, this, &SieveIncludeActionWidget::valueChanged);
137  mLayout->addWidget(mLocation, 1, 1);
138 
139  lab = new QLabel(i18n("Name:"), this);
140  mLayout->addWidget(lab, 1, 2);
141 
142  mIncludeFileName = new IncludeFileLineEdit(this);
143  new KPIM::LineEditCatchReturnKey(mIncludeFileName, this);
144  mIncludeFileName->setClearButtonEnabled(true);
145  connect(mIncludeFileName, &QLineEdit::textChanged, this, &SieveIncludeActionWidget::valueChanged);
146  mLayout->addWidget(mIncludeFileName, 1, 3);
147 
148  mOptional = new QCheckBox(i18n("Optional"), this);
149  connect(mOptional, &QCheckBox::toggled, this, &SieveIncludeActionWidget::valueChanged);
150  mLayout->addWidget(mOptional, 1, 4);
151 
152  mOnce = new QCheckBox(i18n("Once"), this);
153  connect(mOnce, &QCheckBox::toggled, this, &SieveIncludeActionWidget::valueChanged);
154  mLayout->addWidget(mOnce, 1, 5);
155 
156  mAdd = new QPushButton(this);
157  mAdd->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
158  mAdd->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
159 
160  mRemove = new QPushButton(this);
161  mRemove->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
162  mRemove->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
163  mLayout->addWidget(mAdd, 1, 6);
164  mLayout->addWidget(mRemove, 1, 7);
165 
166  connect(mAdd, &QPushButton::clicked, this, &SieveIncludeActionWidget::slotAddWidget);
167  connect(mRemove, &QPushButton::clicked, this, &SieveIncludeActionWidget::slotRemoveWidget);
168 }
169 
170 void SieveIncludeActionWidget::slotAddWidget()
171 {
172  Q_EMIT valueChanged();
173  Q_EMIT addWidget(this);
174 }
175 
176 void SieveIncludeActionWidget::slotRemoveWidget()
177 {
178  Q_EMIT valueChanged();
179  Q_EMIT removeWidget(this);
180 }
181 
182 bool SieveIncludeActionWidget::isInitialized() const
183 {
184  return !mIncludeFileName->text().isEmpty();
185 }
186 
187 void SieveIncludeActionWidget::updateAddRemoveButton(bool addButtonEnabled, bool removeButtonEnabled)
188 {
189  mAdd->setEnabled(addButtonEnabled);
190  mRemove->setEnabled(removeButtonEnabled);
191 }
192 
193 SieveIncludeWidget::SieveIncludeWidget(QWidget *parent)
194  : SieveWidgetPageAbstract(parent)
195 {
196  auto lay = new QVBoxLayout(this);
197  mHelpButton = new SieveHelpButton(this);
198  lay->addWidget(mHelpButton);
199  connect(mHelpButton, &SieveHelpButton::clicked, this, &SieveIncludeWidget::slotHelp);
200 
201  mIncludeLister = new SieveIncludeWidgetLister(this);
202  connect(mIncludeLister, &SieveIncludeWidgetLister::valueChanged, this, &SieveIncludeWidget::valueChanged);
203  lay->addWidget(mIncludeLister, 0, Qt::AlignTop);
204  setPageType(KSieveUi::SieveScriptBlockWidget::Include);
205 }
206 
207 SieveIncludeWidget::~SieveIncludeWidget()
208 {
209 }
210 
211 void SieveIncludeWidget::setListOfIncludeFile(const QStringList &lst)
212 {
213  mIncludeLister->setListOfIncludeFile(lst);
214 }
215 
216 void SieveIncludeWidget::slotHelp()
217 {
218  const QString help = i18n(
219  "The \"include\" command takes an optional \"location\" parameter, an optional \":once\" parameter, an optional \":optional\" parameter, and a single "
220  "string argument representing the name of the script to include for processing at that point.");
221  const QString href = QStringLiteral("https://tools.ietf.org/html/rfc6609#page-4");
222  const QString fullWhatsThis = AutoCreateScriptUtil::createFullWhatsThis(help, href);
223  QWhatsThis::showText(QCursor::pos(), fullWhatsThis, mHelpButton);
224 }
225 
226 void SieveIncludeWidget::generatedScript(QString &script, QStringList &requireModules, bool inForEveryPartLoop)
227 {
228  Q_UNUSED(inForEveryPartLoop)
229  QString result;
230  QStringList lst;
231  mIncludeLister->generatedScript(result, lst);
232  if (!result.isEmpty()) {
233  script += result;
234  requireModules << lst;
235  }
236 }
237 
238 void SieveIncludeWidget::loadScript(QXmlStreamReader &element, QString &error)
239 {
240  mIncludeLister->loadScript(element, error);
241 }
242 
243 SieveIncludeWidgetLister::SieveIncludeWidgetLister(QWidget *parent)
244  : KPIM::KWidgetLister(false, MINIMUMINCLUDEACTION, MAXIMUMINCLUDEACTION, parent)
245 {
246  slotClear();
247  updateAddRemoveButton();
248 }
249 
250 SieveIncludeWidgetLister::~SieveIncludeWidgetLister()
251 {
252 }
253 
254 void SieveIncludeWidgetLister::slotAddWidget(QWidget *w)
255 {
256  addWidgetAfterThisWidget(w);
257  updateAddRemoveButton();
258 }
259 
260 void SieveIncludeWidgetLister::slotRemoveWidget(QWidget *w)
261 {
262  removeWidget(w);
263  updateAddRemoveButton();
264 }
265 
266 void SieveIncludeWidgetLister::updateAddRemoveButton()
267 {
268  QList<QWidget *> widgetList = widgets();
269  const int numberOfWidget(widgetList.count());
270  bool addButtonEnabled = false;
271  bool removeButtonEnabled = false;
272  if (numberOfWidget <= widgetsMinimum()) {
273  addButtonEnabled = true;
274  removeButtonEnabled = false;
275  } else if (numberOfWidget >= widgetsMaximum()) {
276  addButtonEnabled = false;
277  removeButtonEnabled = true;
278  } else {
279  addButtonEnabled = true;
280  removeButtonEnabled = true;
281  }
282  QList<QWidget *>::ConstIterator wIt = widgetList.constBegin();
283  QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
284  for (; wIt != wEnd; ++wIt) {
285  auto w = qobject_cast<SieveIncludeActionWidget *>(*wIt);
286  w->updateAddRemoveButton(addButtonEnabled, removeButtonEnabled);
287  }
288 }
289 
290 void SieveIncludeWidgetLister::setListOfIncludeFile(const QStringList &listOfIncludeFile)
291 {
292  mListOfIncludeFile = listOfIncludeFile;
293  // Update all lineedit
294  const QList<QWidget *> widgetList = widgets();
295  QList<QWidget *>::ConstIterator wIt = widgetList.constBegin();
296  QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
297  for (; wIt != wEnd; ++wIt) {
298  auto w = qobject_cast<SieveIncludeActionWidget *>(*wIt);
299  w->setListOfIncludeFile(mListOfIncludeFile);
300  }
301 }
302 
303 void SieveIncludeWidgetLister::generatedScript(QString &script, QStringList &requireModules)
304 {
305  requireModules << QStringLiteral("include");
306  const QList<QWidget *> widgetList = widgets();
307  QList<QWidget *>::ConstIterator wIt = widgetList.constBegin();
308  QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
309  for (; wIt != wEnd; ++wIt) {
310  auto w = qobject_cast<SieveIncludeActionWidget *>(*wIt);
311  w->generatedScript(script);
312  }
313 }
314 
315 void SieveIncludeWidgetLister::reconnectWidget(SieveIncludeActionWidget *w)
316 {
317  connect(w, &SieveIncludeActionWidget::addWidget, this, &SieveIncludeWidgetLister::slotAddWidget, Qt::UniqueConnection);
318  connect(w, &SieveIncludeActionWidget::removeWidget, this, &SieveIncludeWidgetLister::slotRemoveWidget, Qt::UniqueConnection);
319  connect(w, &SieveIncludeActionWidget::valueChanged, this, &SieveIncludeWidgetLister::valueChanged, Qt::UniqueConnection);
320 }
321 
322 void SieveIncludeWidgetLister::clearWidget(QWidget *aWidget)
323 {
324  if (aWidget) {
325  auto widget = static_cast<SieveIncludeActionWidget *>(aWidget);
326  widget->clear();
327  }
328  Q_EMIT valueChanged();
329 }
330 
331 QWidget *SieveIncludeWidgetLister::createWidget(QWidget *parent)
332 {
333  auto w = new SieveIncludeActionWidget(parent);
334  w->setListOfIncludeFile(mListOfIncludeFile);
335  reconnectWidget(w);
336  return w;
337 }
338 
339 void 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 }
void showText(const QPoint &pos, const QString &text, QWidget *w)
bool readNextStartElement()
KCRASH_EXPORT void initialize()
void textChanged(const QString &text)
AlignTop
int count(const T &value) const const
const QList< QKeySequence > & help()
QString readElementText(QXmlStreamReader::ReadElementTextBehaviour behaviour)
QByteArray tagValue(const Elem &elem, TagKey key)
bool isEmpty() const const
QString trimmed() const const
void clicked(bool checked)
QString i18n(const char *text, const TYPE &arg...)
QPoint pos()
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
void toggled(bool checked)
QIcon fromTheme(const QString &name)
QList::const_iterator constEnd() const const
QList::const_iterator constBegin() const const
UniqueConnection
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
T qobject_cast(QObject *object)
QStringRef name() const const
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Fri Apr 16 2021 23:09:34 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.