Libksieve

sieveconditionwidgetlister.cpp
1 /*
2  Copyright (C) 2013-2020 Laurent Montel <[email protected]>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 #include "sieveconditionwidgetlister.h"
21 #include "autocreatescriptdialog.h"
22 #include "autocreatescriptutil_p.h"
23 #include "libksieve_debug.h"
24 #include "commonwidgets/sievehelpbutton.h"
25 #include "sieveeditorgraphicalmodewidget.h"
26 #include "sieveconditions/sieveconditionlist.h"
27 #include "sieveconditions/sievecondition.h"
28 
29 #include <QPushButton>
30 #include <KLocalizedString>
31 #include <QIcon>
32 #include <QComboBox>
33 #include <QPointer>
34 
35 #include <QGridLayout>
36 #include <QLabel>
37 #include <QWhatsThis>
38 #include "sievescriptdescriptiondialog.h"
39 
40 using namespace KSieveUi;
41 
42 static const int MINIMUMCONDITION = 1;
43 static const int MAXIMUMCONDITION = 8;
44 
45 SieveConditionWidget::SieveConditionWidget(SieveEditorGraphicalModeWidget *sieveGraphicalModeWidget, QWidget *parent)
46  : QWidget(parent)
47  , mSieveGraphicalModeWidget(sieveGraphicalModeWidget)
48 {
49  initWidget();
50 }
51 
52 SieveConditionWidget::~SieveConditionWidget()
53 {
54  qDeleteAll(mConditionList);
55  mConditionList.clear();
56 }
57 
58 void SieveConditionWidget::setFilterCondition(QWidget *widget)
59 {
60  if (mLayout->itemAtPosition(1, 3)) {
61  delete mLayout->itemAtPosition(1, 3)->widget();
62  }
63 
64  if (widget) {
65  mLayout->addWidget(widget, 1, 3);
66  } else {
67  mLayout->addWidget(new QLabel(i18n("Please select an condition."), this), 1, 3);
68  }
69 }
70 
71 void SieveConditionWidget::generatedScript(QString &script, QStringList &required, bool inForEveryPartLoop)
72 {
73  Q_UNUSED(inForEveryPartLoop);
74  const int index = mComboBox->currentIndex();
75  if (index != mComboBox->count() - 1) {
76  KSieveUi::SieveCondition *widgetCondition = mConditionList.at(mComboBox->currentIndex());
77  QWidget *currentWidget = mLayout->itemAtPosition(1, 3)->widget();
78  const QStringList lstRequires = widgetCondition->needRequires(currentWidget);
79  for (const QString &r : lstRequires) {
80  if (!required.contains(r)) {
81  required.append(r);
82  }
83  }
84  script += mConditionList.at(mComboBox->currentIndex())->code(currentWidget) + QLatin1Char('\n');
85  }
86 }
87 
88 void SieveConditionWidget::initWidget()
89 {
90  mLayout = new QGridLayout(this);
91  mLayout->setContentsMargins(0, 0, 0, 0);
92 
93  mComboBox = new QComboBox;
94  mComboBox->setMinimumWidth(50);
95  mComboBox->setEditable(false);
96 
97  const QList<KSieveUi::SieveCondition *> list = KSieveUi::SieveConditionList::conditionList(mSieveGraphicalModeWidget);
100  int index = 0;
101  for (index = 0, it = list.constBegin(); it != end; ++it, ++index) {
102  if ((*it)->needCheckIfServerHasCapability()) {
103  if (mSieveGraphicalModeWidget->sieveCapabilities().contains((*it)->serverNeedsCapability())) {
104  // append to the list of actions:
105  mConditionList.append(*it);
106  connect(*it, &SieveCondition::valueChanged, this, &SieveConditionWidget::valueChanged);
107  // add (i18n-ized) name to combo box
108  mComboBox->addItem((*it)->label(), (*it)->name());
109  } else {
110  delete(*it);
111  }
112  } else {
113  // append to the list of actions:
114  mConditionList.append(*it);
115  connect(*it, &SieveCondition::valueChanged, this, &SieveConditionWidget::valueChanged);
116  // add (i18n-ized) name to combo box
117  mComboBox->addItem((*it)->label(), (*it)->name());
118  }
119  }
120 
121  mHelpButton = new SieveHelpButton(this);
122  mLayout->addWidget(mHelpButton, 1, 0);
123  connect(mHelpButton, &SieveHelpButton::clicked, this, &SieveConditionWidget::slotHelp);
124 
125  mCommentButton = new QToolButton(this);
126  mCommentButton->setToolTip(i18n("Add comment"));
127  mLayout->addWidget(mCommentButton, 1, 1);
128  mCommentButton->setIcon(QIcon::fromTheme(QStringLiteral("view-pim-notes")));
129  connect(mCommentButton, &QToolButton::clicked, this, &SieveConditionWidget::slotAddComment);
130 
131  mComboBox->addItem(QLatin1String(""));
132  mLayout->addWidget(mComboBox, 1, 2);
133  connect(mComboBox, QOverload<int>::of(&QComboBox::activated), this, &SieveConditionWidget::slotConditionChanged);
134 
135  mComboBox->setMaxCount(mComboBox->count());
136  mComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
138  mComboBox->adjustSize();
139 
140  mAdd = new QPushButton(this);
141  mAdd->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
142  mAdd->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
143 
144  mRemove = new QPushButton(this);
145  mRemove->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
146  mRemove->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
147 
148  mLayout->addWidget(mAdd, 1, 4);
149  mLayout->addWidget(mRemove, 1, 5);
150 
151  // redirect focus to the filter action combo box
152  setFocusProxy(mComboBox);
153 
154  connect(mAdd, &QPushButton::clicked, this, &SieveConditionWidget::slotAddWidget);
155  connect(mRemove, &QPushButton::clicked, this, &SieveConditionWidget::slotRemoveWidget);
156 
157  clear();
158 }
159 
160 void SieveConditionWidget::slotAddComment()
161 {
162  const int index = mComboBox->currentIndex();
163  if (index < mConditionList.count()) {
164  KSieveUi::SieveCondition *condition = mConditionList.at(index);
165  const QString comment = condition->comment();
166  QPointer<SieveScriptDescriptionDialog> dlg = new SieveScriptDescriptionDialog;
167  dlg->setDescription(comment);
168  if (dlg->exec()) {
169  condition->setComment(dlg->description());
170  Q_EMIT valueChanged();
171  }
172  delete dlg;
173  }
174 }
175 
176 void SieveConditionWidget::slotHelp()
177 {
178  const int index = mComboBox->currentIndex();
179  if (index < mConditionList.count()) {
180  KSieveUi::SieveCondition *condition = mConditionList.at(index);
181  const QString help = condition->help();
182  const QUrl href = condition->href();
183  const QString fullWhatsThis = AutoCreateScriptUtil::createFullWhatsThis(help, href.toString());
184  QWhatsThis::showText(QCursor::pos(), fullWhatsThis, mHelpButton);
185  }
186 }
187 
188 void SieveConditionWidget::slotConditionChanged(int index)
189 {
190  if (index < mConditionList.count()) {
191  KSieveUi::SieveCondition *condition = mConditionList.at(index);
192  mHelpButton->setEnabled(!condition->help().isEmpty());
193  setFilterCondition(condition->createParamWidget(this));
194  mCommentButton->setEnabled(true);
195  } else {
196  setFilterCondition(nullptr);
197  mHelpButton->setEnabled(false);
198  mCommentButton->setEnabled(false);
199  }
200  Q_EMIT valueChanged();
201 }
202 
203 void SieveConditionWidget::slotAddWidget()
204 {
205  Q_EMIT addWidget(this);
206  Q_EMIT valueChanged();
207 }
208 
209 void SieveConditionWidget::slotRemoveWidget()
210 {
211  Q_EMIT removeWidget(this);
212  Q_EMIT valueChanged();
213 }
214 
215 void SieveConditionWidget::clear()
216 {
217  mComboBox->setCurrentIndex(mComboBox->count() - 1);
218  setFilterCondition(nullptr);
219  mHelpButton->setEnabled(false);
220  mCommentButton->setEnabled(false);
221 }
222 
223 void SieveConditionWidget::updateAddRemoveButton(bool addButtonEnabled, bool removeButtonEnabled)
224 {
225  mAdd->setEnabled(addButtonEnabled);
226  mRemove->setEnabled(removeButtonEnabled);
227 }
228 
229 void SieveConditionWidget::setCondition(const QString &conditionName, QXmlStreamReader &element, bool notCondition, QString &error)
230 {
231  const int index = mComboBox->findData(conditionName);
232  if (index != -1) {
233  mComboBox->setCurrentIndex(index);
234  slotConditionChanged(index);
235  KSieveUi::SieveCondition *condition = mConditionList.at(index);
236  condition->setParamWidgetValue(element, this, notCondition, error);
237  } else {
238  error += i18n("Script contains unsupported feature \"%1\"", conditionName) + QLatin1Char('\n');
239  qCDebug(LIBKSIEVE_LOG) << "Condition " << conditionName << " not supported";
240  element.skipCurrentElement();
241  }
242 }
243 
244 SieveConditionWidgetLister::SieveConditionWidgetLister(SieveEditorGraphicalModeWidget *sieveGraphicalModeWidget, QWidget *parent)
245  : KPIM::KWidgetLister(false, MINIMUMCONDITION, MAXIMUMCONDITION, parent)
246  , mSieveGraphicalModeWidget(sieveGraphicalModeWidget)
247 {
248  slotClear();
249  updateAddRemoveButton();
250 }
251 
252 SieveConditionWidgetLister::~SieveConditionWidgetLister()
253 {
254 }
255 
256 void SieveConditionWidgetLister::slotAddWidget(QWidget *w)
257 {
258  addWidgetAfterThisWidget(w);
259  updateAddRemoveButton();
260 }
261 
262 void SieveConditionWidgetLister::slotRemoveWidget(QWidget *w)
263 {
264  removeWidget(w);
265  updateAddRemoveButton();
266 }
267 
268 void SieveConditionWidgetLister::updateAddRemoveButton()
269 {
270  QList<QWidget *> widgetList = widgets();
271  const int numberOfWidget(widgetList.count());
272  bool addButtonEnabled = false;
273  bool removeButtonEnabled = false;
274  if (numberOfWidget <= widgetsMinimum()) {
275  addButtonEnabled = true;
276  removeButtonEnabled = false;
277  } else if (numberOfWidget >= widgetsMaximum()) {
278  addButtonEnabled = false;
279  removeButtonEnabled = true;
280  } else {
281  addButtonEnabled = true;
282  removeButtonEnabled = true;
283  }
284  QList<QWidget *>::ConstIterator wIt = widgetList.constBegin();
285  QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
286  for (; wIt != wEnd; ++wIt) {
287  SieveConditionWidget *w = qobject_cast<SieveConditionWidget *>(*wIt);
288  w->updateAddRemoveButton(addButtonEnabled, removeButtonEnabled);
289  }
290 }
291 
292 void SieveConditionWidgetLister::reconnectWidget(SieveConditionWidget *w)
293 {
294  connect(w, &SieveConditionWidget::addWidget, this, &SieveConditionWidgetLister::slotAddWidget, Qt::UniqueConnection);
295  connect(w, &SieveConditionWidget::removeWidget, this, &SieveConditionWidgetLister::slotRemoveWidget, Qt::UniqueConnection);
296  connect(w, &SieveConditionWidget::valueChanged, this, &SieveConditionWidgetLister::valueChanged, Qt::UniqueConnection);
297 }
298 
299 void SieveConditionWidgetLister::clearWidget(QWidget *aWidget)
300 {
301  if (aWidget) {
302  SieveConditionWidget *widget = static_cast<SieveConditionWidget *>(aWidget);
303  widget->clear();
304  }
305  Q_EMIT valueChanged();
306 }
307 
308 QWidget *SieveConditionWidgetLister::createWidget(QWidget *parent)
309 {
310  SieveConditionWidget *w = new SieveConditionWidget(mSieveGraphicalModeWidget, parent);
311  reconnectWidget(w);
312  return w;
313 }
314 
315 void SieveConditionWidgetLister::generatedScript(QString &script, int &numberOfCondition, QStringList &requireModules, bool inForEveryPartLoop)
316 {
317  const QList<QWidget *> widgetList = widgets();
318  QList<QWidget *>::ConstIterator wIt = widgetList.constBegin();
319  QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
320  bool wasFirst = true;
321  for (; wIt != wEnd; ++wIt) {
322  QString condition;
323  SieveConditionWidget *w = qobject_cast<SieveConditionWidget *>(*wIt);
324  w->generatedScript(condition, requireModules, inForEveryPartLoop);
325  if (!condition.isEmpty()) {
326  if (!wasFirst) {
327  if (inForEveryPartLoop) {
328  script += AutoCreateScriptUtil::indentation();
329  }
330  script += QLatin1String(", ");
331  }
332  script += condition;
333  wasFirst = false;
334  ++numberOfCondition;
335  }
336  }
337 }
338 
339 int SieveConditionWidgetLister::conditionNumber() const
340 {
341  return widgets().count();
342 }
343 
344 void SieveConditionWidgetLister::loadTest(QXmlStreamReader &element, bool notCondition, QString &error)
345 {
346  if (notCondition) {
347  element.readNextStartElement();
348  }
349  if (element.attributes().hasAttribute(QLatin1String("name"))) {
350  const QString conditionName = element.attributes().value(QLatin1String("name")).toString();
351  SieveConditionWidget *w = qobject_cast<SieveConditionWidget *>(widgets().constLast());
352  w->setCondition(conditionName, element, notCondition, error);
353  }
354  if (notCondition) {
355  element.skipCurrentElement();
356  }
357 }
358 
359 void SieveConditionWidgetLister::loadScript(QXmlStreamReader &element, bool uniqTest, bool notCondition, QString &error)
360 {
361  if (uniqTest) {
362  loadTest(element, notCondition, error);
363  } else {
364  bool firstCondition = true;
365  if (notCondition) {
366  element.readNextStartElement();
367  }
368  while (element.readNextStartElement()) {
369  const QStringRef tagName = element.name();
370  if (tagName == QLatin1String("testlist")) {
371  while (element.readNextStartElement()) {
372  const QStringRef testTagName = element.name();
373  if (testTagName == QLatin1String("test")) {
374  if (element.attributes().hasAttribute(QLatin1String("name"))) {
375  QString conditionName = element.attributes().value(QLatin1String("name")).toString();
376  if (firstCondition) {
377  firstCondition = false;
378  } else {
379  addWidgetAfterThisWidget(widgets().constLast());
380  }
381  SieveConditionWidget *w = qobject_cast<SieveConditionWidget *>(widgets().constLast());
382  if (conditionName == QLatin1String("not")) {
383  notCondition = true;
384  element.readNextStartElement();
385  if (element.attributes().hasAttribute(QLatin1String("name"))) {
386  conditionName = element.attributes().value(QLatin1String("name")).toString();
387  }
388  w->setCondition(conditionName, element, notCondition, error);
389  element.skipCurrentElement();
390  } else {
391  notCondition = false;
392  w->setCondition(conditionName, element, notCondition, error);
393  }
394  }
395  } else if (testTagName == QLatin1String("crlf")) {
396  element.skipCurrentElement();
397  //nothing
398  } else if (testTagName == QLatin1String("comment")) {
399  qDebug() << "Need to implement comment here ";
400  element.skipCurrentElement();
401  //nothing
402  //implement in the future ?
403  } else {
404  qCDebug(LIBKSIEVE_LOG) << " SieveConditionWidgetLister::loadScript unknown condition tag: " << testTagName;
405  }
406  }
407  }
408  }
409  }
410 }
void showText(const QPoint &pos, const QString &text, QWidget *w)
bool readNextStartElement()
QString toString() const const
void setMinimumWidth(int minw)
const T & at(int i) const const
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
QStringRef value(const QString &namespaceUri, const QString &name) const const
QString toString(QUrl::FormattingOptions options) const const
void skipCurrentElement()
int count(const T &value) const const
void append(const T &value)
const QList< QKeySequence > & help()
bool isEmpty() const const
void clicked(bool checked)
void activated(int index)
bool hasAttribute(const QString &qualifiedName) const const
QString i18n(const char *text, const TYPE &arg...)
const QList< QKeySequence > & end()
QPoint pos()
int count() const const
const QChar at(int position) const const
QXmlStreamAttributes attributes() const const
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)
QObject * parent() const const
QStringRef name() const const
Q_EMITQ_EMIT
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Aug 10 2020 23:12:59 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.