Libksieve

sievescriptblockwidget.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 "sievescriptblockwidget.h"
8#include "autocreatescriptutil_p.h"
9#include "sieveactionwidgetlister.h"
10#include "sieveconditionwidgetlister.h"
11
12#include <KLocalizedString>
13#include <QComboBox>
14#include <QIcon>
15#include <QPushButton>
16
17#include "libksieveui_debug.h"
18#include <QButtonGroup>
19#include <QGroupBox>
20#include <QLabel>
21#include <QRadioButton>
22#include <QScrollArea>
23#include <QVBoxLayout>
24#include <QXmlStreamReader>
25
26using namespace KSieveUi;
27
28SieveScriptBlockWidget::SieveScriptBlockWidget(SieveEditorGraphicalModeWidget *graphicalModeWidget, QWidget *parent)
29 : SieveWidgetPageAbstract(parent)
30 , mSieveGraphicalModeWidget(graphicalModeWidget)
31{
32 auto topLayout = new QVBoxLayout(this);
33 topLayout->setContentsMargins({});
34
35 mConditions = new QGroupBox(i18n("Conditions"), this);
36 auto vbox = new QVBoxLayout;
37
38 mAllMessageRBtn = new QRadioButton(i18nc("@option:radio", "Match all messages"), this);
39 mMatchAll = new QRadioButton(i18nc("@option:radio", "Match a&ll of the following"), this);
40 mMatchAny = new QRadioButton(i18nc("@option:radio", "Match an&y of the following"), this);
41
42 vbox->addWidget(mMatchAll);
43 vbox->addWidget(mMatchAny);
44 vbox->addWidget(mAllMessageRBtn);
45 mMatchAll->setChecked(true);
46 mMatchAny->setChecked(false);
47 mAllMessageRBtn->setChecked(false);
48
49 auto bg = new QButtonGroup(this);
50 bg->addButton(mMatchAll);
51 bg->addButton(mMatchAny);
52 bg->addButton(mAllMessageRBtn);
53
54 connect(bg, &QButtonGroup::buttonClicked, this, &SieveScriptBlockWidget::slotRadioClicked);
55 mConditions->setLayout(vbox);
56
57 mScriptConditionLister = new SieveConditionWidgetLister(mSieveGraphicalModeWidget, this);
58 connect(mScriptConditionLister, &SieveConditionWidgetLister::valueChanged, this, &SieveScriptBlockWidget::valueChanged);
59 auto scrollArea = new QScrollArea(this);
60 scrollArea->setAutoFillBackground(false);
61 scrollArea->setWidget(mScriptConditionLister);
62 scrollArea->setWidgetResizable(true);
63 scrollArea->setAlignment(Qt::AlignTop);
64 vbox->addWidget(scrollArea);
65
66 topLayout->addWidget(mConditions);
67
68 auto actions = new QGroupBox(i18n("Actions"), this);
69 vbox = new QVBoxLayout;
70 actions->setLayout(vbox);
71 mScriptActionLister = new SieveActionWidgetLister(mSieveGraphicalModeWidget, this);
72 connect(mScriptActionLister, &SieveActionWidgetLister::valueChanged, this, &SieveScriptBlockWidget::valueChanged);
73
74 auto scrollAreaCondition = new QScrollArea(this);
75 scrollAreaCondition->setAutoFillBackground(false);
76 scrollAreaCondition->setWidget(mScriptActionLister);
77 scrollAreaCondition->setWidgetResizable(true);
78 scrollAreaCondition->setAlignment(Qt::AlignTop);
79 vbox->addWidget(scrollAreaCondition);
80 topLayout->addWidget(actions);
81
82 auto newBlockLayout = new QHBoxLayout;
83 auto lab = new QLabel(i18nc("@label:textbox", "Add new block:"));
84 newBlockLayout->addWidget(lab);
85 mNewBlockType = new QComboBox(this);
86 newBlockLayout->addWidget(mNewBlockType);
87 mNewBlockType->addItem(i18n("\"elsif\" block"));
88 mNewBlockType->addItem(i18n("\"else\" block"));
89
90 mAddBlockType = new QPushButton(this);
91 mAddBlockType->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
92 mAddBlockType->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
93 newBlockLayout->addWidget(mAddBlockType);
94 connect(mAddBlockType, &QPushButton::clicked, this, &SieveScriptBlockWidget::slotAddBlock);
95
96 topLayout->addLayout(newBlockLayout);
97}
98
99SieveScriptBlockWidget::~SieveScriptBlockWidget() = default;
100
101void SieveScriptBlockWidget::slotAddBlock()
102{
103 KSieveUi::SieveWidgetPageAbstract::PageType type = BlockElsIf;
104 switch (mNewBlockType->currentIndex()) {
105 case 0:
106 type = BlockElsIf;
107 break;
108 case 1:
109 type = BlockElse;
110 break;
111 }
112
113 Q_EMIT valueChanged();
114 Q_EMIT addNewBlock(this, type);
115}
116
117void SieveScriptBlockWidget::setPageType(PageType type)
118{
119 if (pageType() != type) {
120 SieveWidgetPageAbstract::setPageType(type);
121 switch (type) {
122 case BlockIf:
123 mAllMessageRBtn->show();
124 mConditions->show();
125 mAddBlockType->setEnabled(true);
126 mNewBlockType->setEnabled(true);
127 break;
128 case BlockElsIf:
129 mAllMessageRBtn->hide();
130 mConditions->show();
131 mAddBlockType->setEnabled(true);
132 mNewBlockType->setEnabled(true);
133 break;
134 case BlockElse:
135 mAllMessageRBtn->hide();
136 mConditions->hide();
137 mAddBlockType->setEnabled(false);
138 mNewBlockType->setEnabled(false);
139 break;
140 default:
141 break;
142 }
143 }
144}
145
146SieveScriptBlockWidget::MatchCondition SieveScriptBlockWidget::matchCondition() const
147{
148 return mMatchCondition;
149}
150
151void SieveScriptBlockWidget::slotRadioClicked(QAbstractButton *button)
152{
153 if (button == mMatchAll) {
154 mMatchCondition = AndCondition;
155 } else if (button == mMatchAny) {
156 mMatchCondition = OrCondition;
157 } else {
158 mMatchCondition = AllCondition;
159 }
160 Q_EMIT valueChanged();
161 updateWidget();
162}
163
164void SieveScriptBlockWidget::updateWidget()
165{
166 mScriptConditionLister->setEnabled(mMatchCondition != AllCondition);
167 mNewBlockType->setEnabled(mMatchCondition != AllCondition);
168 mAddBlockType->setEnabled(mMatchCondition != AllCondition);
169}
170
171void SieveScriptBlockWidget::generatedScript(QString &script, QStringList &required, bool inForEveryPartLoop)
172{
173 QString indentation;
174 if (inForEveryPartLoop) {
175 indentation = AutoCreateScriptUtil::indentation();
176 }
177 bool onlyActions = false;
178 if (mMatchCondition == AllCondition) {
179 onlyActions = true;
180 // Just actions type
181 } else if (pageType() == BlockElse) {
182 script += QLatin1StringView("else {\n");
183 } else {
184 QString conditionStr;
185 int numberOfCondition = 0;
186 mScriptConditionLister->generatedScript(conditionStr, numberOfCondition, required, inForEveryPartLoop);
187 const bool hasUniqCondition = (numberOfCondition == 1);
188 QString filterStr;
189 QString blockStr;
190 switch (pageType()) {
191 case BlockIf:
192 blockStr = indentation + QStringLiteral("if ");
193 break;
194 case BlockElsIf:
195 blockStr = QStringLiteral("elsif ");
196 break;
197 case BlockElse:
198 break;
199 default:
200 // We can got here.
201 break;
202 }
203
204 if (hasUniqCondition == 1) {
205 filterStr += blockStr;
206 } else if (mMatchCondition == AndCondition) {
207 filterStr += blockStr + QLatin1StringView("allof (");
208 } else if (mMatchCondition == OrCondition) {
209 filterStr += blockStr + QLatin1StringView("anyof (");
210 }
211
212 if (conditionStr.isEmpty()) {
213 return;
214 } else {
215 script += filterStr + conditionStr;
216 }
217 if (hasUniqCondition) {
218 script += indentation + QLatin1StringView("{\n");
219 } else {
220 script += indentation + QStringLiteral(")\n%1{\n").arg(indentation);
221 }
222 }
223 mScriptActionLister->generatedScript(script, required, onlyActions, inForEveryPartLoop);
224 if (!onlyActions) {
225 script += indentation + QLatin1StringView("} ");
226 }
227}
228
229void SieveScriptBlockWidget::updateCondition()
230{
231 switch (mMatchCondition) {
232 case AndCondition:
233 mMatchAll->setChecked(true);
234 break;
235 case OrCondition:
236 mMatchAny->setChecked(true);
237 break;
238 case AllCondition:
239 mAllMessageRBtn->setChecked(true);
240 break;
241 }
242 updateWidget();
243}
244
245void SieveScriptBlockWidget::loadLocalVariable(const SieveGlobalVariableActionWidget::VariableElement &var)
246{
247 mScriptActionLister->loadLocalVariable(var);
248 mMatchCondition = AllCondition;
249 updateCondition();
250}
251
252void SieveScriptBlockWidget::loadScript(QXmlStreamReader &element, bool onlyActions, QString &error)
253{
254 if (onlyActions) {
255 mScriptActionLister->loadScript(element, true, error);
256 mMatchCondition = AllCondition;
257 updateCondition();
258 } else {
259 bool uniqueTest = false;
260 while (element.readNextStartElement()) {
261 const QStringView tagName = element.name();
262 if (tagName == QLatin1StringView("test")) {
263 bool notCondition = false;
264 if (element.attributes().hasAttribute(QLatin1StringView("name"))) {
265 const QString typeCondition = element.attributes().value(QLatin1StringView("name")).toString();
266 if (typeCondition == QLatin1StringView("anyof")) {
267 mMatchCondition = OrCondition;
268 } else if (typeCondition == QLatin1StringView("allof")) {
269 mMatchAll->setChecked(true);
270 } else {
271 if (typeCondition == QLatin1StringView("not")) {
272 notCondition = true;
273 }
274 uniqueTest = true;
275 mMatchCondition = OrCondition;
276 }
277 updateCondition();
278 }
279 mScriptConditionLister->loadScript(element, uniqueTest, notCondition, error);
280 } else if (tagName == QLatin1StringView("block")) {
281 mScriptActionLister->loadScript(element, false, error);
282 } else {
283 if (tagName != QLatin1StringView("crlf")) {
284 qCDebug(LIBKSIEVEUI_LOG) << " e.tag" << tagName;
285 } else {
286 element.skipCurrentElement();
287 }
288 }
289 }
290 }
291}
292
293#include "moc_sievescriptblockwidget.cpp"
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
void setChecked(bool)
void clicked(bool checked)
void buttonClicked(QAbstractButton *button)
QIcon fromTheme(const QString &name)
Q_EMITQ_EMIT
QString arg(Args &&... args) const const
bool isEmpty() const const
QString toString() const const
AlignTop
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setEnabled(bool)
void hide()
void show()
bool hasAttribute(QAnyStringView namespaceUri, QAnyStringView name) const const
QStringView value(QAnyStringView namespaceUri, QAnyStringView name) const const
QXmlStreamAttributes attributes() const const
QStringView name() const const
bool readNextStartElement()
void skipCurrentElement()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:14:30 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.