7#include "sievescriptlistbox.h"
8#include "sieveeditorgraphicalmodewidget.h"
9#include "sieveforeverypartwidget.h"
10#include "sieveglobalvariablewidget.h"
11#include "sieveincludewidget.h"
12#include "sievescriptdescriptiondialog.h"
13#include "sievescriptpage.h"
14#include <KLocalizedString>
18#include <QInputDialog>
20#include <QXmlStreamReader>
22#include "libksieveui_debug.h"
30inline const QString defaultScriptName()
32 return QStringLiteral(
"SCRIPTNAME: ");
35inline const QString roundcubeRuleName()
37 return QStringLiteral(
" rule:");
41using namespace KSieveUi;
48SieveScriptListItem::~SieveScriptListItem() =
default;
50void SieveScriptListItem::setDescription(
const QString &desc)
55QString SieveScriptListItem::description()
const
60SieveScriptPage *SieveScriptListItem::scriptPage()
const
65void SieveScriptListItem::setScriptPage(SieveScriptPage *page)
70QString SieveScriptListItem::generatedScript(QStringList &required)
const
73 if (!mDescription.trimmed().isEmpty()) {
74 const QList<QStringView> commentList = QStringView(mDescription).split(QLatin1Char(
'\n'));
75 for (
const QStringView str : commentList) {
77 script += QLatin1Char(
'\n');
79 script += QLatin1Char(
'#') + str + QLatin1Char(
'\n');
84 mScriptPage->generatedScript(script, required);
89SieveScriptListBox::SieveScriptListBox(
const QString &title, QWidget *parent)
90 : QGroupBox(title, parent)
91 , mSieveListScript(new QListWidget(this))
99 layout->addWidget(mSieveListScript);
104 hbHBoxLayout->setContentsMargins({});
105 hbHBoxLayout->setSpacing(4);
108 hbHBoxLayout->addWidget(mBtnTop);
110 mBtnTop->setMinimumSize(mBtnTop->sizeHint() * 1.2);
113 hbHBoxLayout->addWidget(mBtnUp);
114 mBtnUp->setAutoRepeat(
true);
116 mBtnUp->setMinimumSize(mBtnUp->sizeHint() * 1.2);
118 hbHBoxLayout->addWidget(mBtnDown);
119 mBtnDown->setAutoRepeat(
true);
121 mBtnDown->setMinimumSize(mBtnDown->sizeHint() * 1.2);
124 hbHBoxLayout->addWidget(mBtnBottom);
126 mBtnBottom->setMinimumSize(mBtnBottom->sizeHint() * 1.2);
128 mBtnUp->setToolTip(
i18nc(
"Move selected filter up.",
"Up"));
129 mBtnDown->setToolTip(
i18nc(
"Move selected filter down.",
"Down"));
130 mBtnTop->setToolTip(
i18nc(
"Move selected filter to the top.",
"Top"));
131 mBtnBottom->setToolTip(
i18nc(
"Move selected filter to the bottom.",
"Bottom"));
133 layout->addWidget(hb);
137 hbHBoxLayout->setContentsMargins({});
138 hbHBoxLayout->setSpacing(4);
141 hbHBoxLayout->addWidget(mBtnNew);
143 mBtnNew->setToolTip(
i18nc(
"@info:tooltip",
"New Script"));
144 mBtnNew->setMinimumSize(mBtnNew->sizeHint() * 1.2);
147 hbHBoxLayout->addWidget(mBtnDelete);
149 mBtnDelete->setToolTip(
i18nc(
"@info:tooltip",
"Delete Script"));
150 mBtnDelete->setMinimumSize(mBtnDelete->sizeHint() * 1.2);
153 mBtnRename->setToolTip(
i18nc(
"@info:tooltip",
"Rename Script"));
155 mBtnRename->setMinimumSize(mBtnRename->sizeHint() * 1.2);
156 hbHBoxLayout->addWidget(mBtnRename);
159 mBtnDescription->setToolTip(
i18nc(
"@info:tooltip",
"Edit Script Description"));
161 mBtnDescription->setMinimumSize(mBtnDescription->sizeHint() * 1.2);
163 hbHBoxLayout->addWidget(mBtnDescription);
165 layout->addWidget(hb);
183SieveScriptListBox::~SieveScriptListBox() =
default;
185void SieveScriptListBox::slotCustomMenuRequested(
const QPoint &pos)
188 QAction *newScriptAction = menu.addAction(
i18nc(
"@action:inmenu",
"New Script"));
192 if (mSieveListScript->itemAt(
pos)) {
193 QAction *renameScriptAction = menu.addAction(
i18nc(
"@action:inmenu",
"Rename Script"));
198 QAction *editScriptDescriptionAction = menu.addAction(
i18nc(
"@action:inmenu",
"Edit Script Description"));
203 QAction *deleteScriptAction = menu.addAction(
i18nc(
"@action:inmenu",
"Delete Script"));
210void SieveScriptListBox::setSieveEditorGraphicalModeWidget(SieveEditorGraphicalModeWidget *graphicalModeWidget)
212 mSieveGraphicalModeWidget = graphicalModeWidget;
215void SieveScriptListBox::slotItemClicked(QListWidgetItem *item)
218 auto itemScript =
static_cast<SieveScriptListItem *
>(item);
219 Q_EMIT activatePage(itemScript->scriptPage());
223void SieveScriptListBox::updateButtons()
225 const int currentIndex = mSieveListScript->currentRow();
226 const bool theFirst = (currentIndex == 0);
227 const int numberOfElement(mSieveListScript->count());
228 const bool theLast = (currentIndex >= numberOfElement - 1);
230 const QList<QListWidgetItem *> lst = mSieveListScript->selectedItems();
231 mBtnDelete->setEnabled(!lst.
isEmpty());
232 mBtnRename->setEnabled(lst.
count() == 1);
233 mBtnDescription->setEnabled(lst.
count() == 1);
234 mBtnBottom->setEnabled(!lst.
isEmpty() && !theLast);
235 mBtnTop->setEnabled(!lst.
isEmpty() && !theFirst);
236 mBtnDown->setEnabled(!lst.
isEmpty() && !theLast);
237 mBtnUp->setEnabled(!lst.
isEmpty() && !theFirst);
240SieveScriptPage *SieveScriptListBox::createNewScript(
const QString &newName,
const QString &description)
242 auto item =
new SieveScriptListItem(newName, mSieveListScript);
243 item->setDescription(description);
244 auto page =
new SieveScriptPage(mSieveGraphicalModeWidget);
245 page->setListOfIncludeFile(mSieveGraphicalModeWidget->listOfIncludeFile());
246 item->setScriptPage(page);
248 Q_EMIT enableButtonOk(
true);
249 mSieveListScript->setCurrentItem(item);
254void SieveScriptListBox::slotNew()
259 createNewScript(newName);
264void SieveScriptListBox::slotDelete()
266 QListWidgetItem *item = mSieveListScript->currentItem();
269 i18n(
"Do you want to delete \"%1\" script?", item->
text()),
270 i18nc(
"@title:window",
"Delete Script"),
273 if (answer == KMessageBox::ButtonCode::PrimaryAction) {
274 auto itemScript =
static_cast<SieveScriptListItem *
>(item);
275 Q_EMIT removePage(itemScript->scriptPage());
277 Q_EMIT enableButtonOk(mSieveListScript->count() > 0);
284void SieveScriptListBox::slotRename()
286 QListWidgetItem *item = mSieveListScript->currentItem();
301void SieveScriptListBox::slotEditDescription()
303 QListWidgetItem *item = mSieveListScript->currentItem();
305 auto sieveItem =
static_cast<SieveScriptListItem *
>(item);
306 QPointer<SieveScriptDescriptionDialog> dlg =
new SieveScriptDescriptionDialog(
this);
307 dlg->setDescription(sieveItem->description());
309 sieveItem->setDescription(dlg->description());
316void SieveScriptListBox::slotTop()
318 QListWidgetItem *item = mSieveListScript->currentItem();
320 const int currentIndex = mSieveListScript->currentRow();
321 if (currentIndex != 0) {
322 item = mSieveListScript->takeItem(currentIndex);
323 mSieveListScript->insertItem(0, item);
324 mSieveListScript->setCurrentItem(item);
330void SieveScriptListBox::slotBottom()
332 QListWidgetItem *item = mSieveListScript->currentItem();
334 const int currentIndex = mSieveListScript->currentRow();
335 if (currentIndex != mSieveListScript->count() - 1) {
336 item = mSieveListScript->takeItem(currentIndex);
337 mSieveListScript->insertItem(mSieveListScript->count(), item);
338 mSieveListScript->setCurrentItem(item);
344void SieveScriptListBox::slotDown()
346 QListWidgetItem *item = mSieveListScript->currentItem();
348 const int currentIndex = mSieveListScript->currentRow();
349 if (currentIndex < mSieveListScript->count() - 1) {
350 item = mSieveListScript->takeItem(currentIndex);
351 mSieveListScript->insertItem(currentIndex + 1, item);
352 mSieveListScript->setCurrentItem(item);
358void SieveScriptListBox::slotUp()
360 QListWidgetItem *item = mSieveListScript->currentItem();
362 const int currentIndex = mSieveListScript->currentRow();
363 if (currentIndex >= 1) {
364 item = mSieveListScript->takeItem(currentIndex);
365 mSieveListScript->insertItem(currentIndex - 1, item);
366 mSieveListScript->setCurrentItem(item);
372QString SieveScriptListBox::generatedScript(QStringList &requireModules)
const
374 QString resultScript;
375 QStringList lstRequires;
376 const int numberOfScripts(mSieveListScript->count());
377 for (
int i = 0; i < numberOfScripts; ++i) {
378 auto item =
static_cast<SieveScriptListItem *
>(mSieveListScript->item(i));
380 resultScript += QLatin1StringView(
"\n\n");
382 resultScript += QLatin1Char(
'#') + QStringLiteral(
"%1[%2]").
arg(roundcubeRuleName(), item->
text()) + QLatin1Char(
'\n');
383 resultScript += item->generatedScript(lstRequires);
386 resultScript += QLatin1Char(
'\n');
389 QStringList endRequires;
390 for (
const QString &r : std::as_const(lstRequires)) {
393 requireModules += QStringLiteral(
"require \"%1\";").arg(r);
400void SieveScriptListBox::clear()
403 Q_EMIT enableButtonOk(
false);
405 mSieveListScript->clear();
409void SieveScriptListBox::loadScript(
const QString &doc, QString &error)
412 QXmlStreamReader streamReader(doc);
413 if (streamReader.readNextStartElement()) {
414 if (streamReader.name() == QLatin1StringView(
"script")) {
415 SieveScriptPage *currentPage =
nullptr;
416 ParseSieveScriptTypeBlock typeBlock = TypeUnknown;
417 loadBlock(streamReader, currentPage, typeBlock, error);
422void SieveScriptListBox::loadBlock(QXmlStreamReader &n, SieveScriptPage *currentPage, ParseSieveScriptTypeBlock typeBlock, QString &error)
426 bool hasCreatedAIfBlock =
false;
427 bool previousElementWasAComment =
false;
429 const QStringView tagName = n.
name();
431 if (tagName == QLatin1StringView(
"control")) {
432 previousElementWasAComment =
false;
434 if (typeBlock == TypeBlockAction) {
435 currentPage =
nullptr;
440 if (controlType == QLatin1StringView(
"if")) {
441 typeBlock = TypeBlockIf;
442 if (!currentPage || hasCreatedAIfBlock) {
443 currentPage = createNewScript(scriptName.
isEmpty() ? createUniqName() : scriptName, comment);
445 hasCreatedAIfBlock =
true;
447 currentPage->blockIfWidget()->loadScript(n,
false, error);
448 }
else if (controlType == QLatin1StringView(
"elsif")) {
449 typeBlock = TypeBlockElsif;
451 qCDebug(LIBKSIEVEUI_LOG) <<
" script is not correct missing if block";
452 currentPage = createNewScript(scriptName.
isEmpty() ? createUniqName() : scriptName, comment);
454 SieveScriptBlockWidget *blockWidget = currentPage->addScriptBlock(KSieveUi::SieveWidgetPageAbstract::BlockElsIf);
456 blockWidget->loadScript(n,
false, error);
458 }
else if (controlType == QLatin1StringView(
"else")) {
459 typeBlock = TypeBlockElse;
461 currentPage = createNewScript(scriptName.
isEmpty() ? createUniqName() : scriptName, comment);
462 qCDebug(LIBKSIEVEUI_LOG) <<
" script is not correct missing if block";
464 SieveScriptBlockWidget *blockWidget = currentPage->addScriptBlock(KSieveUi::SieveWidgetPageAbstract::BlockElse);
466 blockWidget->loadScript(n,
false, error);
469 currentPage =
nullptr;
470 }
else if (controlType == QLatin1StringView(
"foreverypart")) {
471 typeBlock = TypeBlockForeachBlock;
473 currentPage = createNewScript(scriptName.
isEmpty() ? createUniqName() : scriptName, comment);
476 if (currentPage->forEveryPartWidget()) {
477 currentPage->forEveryPartWidget()->loadScript(n, error);
479 error +=
i18n(
"forEveryPart is not supported by your server") + QLatin1Char(
'\n');
482#ifdef QDOMELEMENT_FIXME
483 QDomNode block = e.firstChildElement(QStringLiteral(
"block")).firstChild();
484 loadBlock(block, currentPage, typeBlock, error);
486 }
else if (controlType == QLatin1StringView(
"require")) {
490 qCDebug(LIBKSIEVEUI_LOG) <<
" unknown controlType :" << controlType;
493 }
else if (tagName == QLatin1StringView(
"comment")) {
494 previousElementWasAComment =
true;
496 if (e.hasAttribute(QStringLiteral(
"hash"))) {
498 }
else if (e.hasAttribute(QStringLiteral(
"bracket"))) {
503 if (str.contains(defaultScriptName())) {
504 scriptName = str.
remove(defaultScriptName());
505 }
else if (str.contains(roundcubeRuleName())) {
506 scriptName = str.
remove(roundcubeRuleName());
507 if (scriptName.
startsWith(QLatin1Char(
'[')) && scriptName.
endsWith(QLatin1Char(
']'))) {
513 comment += QLatin1Char(
'\n');
518 }
else if (tagName == QLatin1StringView(
"action")) {
519 previousElementWasAComment =
false;
522 if (actionName == QLatin1StringView(
"include")) {
523 if (!currentPage || (typeBlock == TypeBlockIf) || (typeBlock == TypeBlockElse) || (typeBlock == TypeBlockElsif)) {
524 currentPage = createNewScript(scriptName.
isEmpty() ? createUniqName() : scriptName, comment);
527 typeBlock = TypeBlockInclude;
528 if (currentPage->includeWidget()) {
529 currentPage->includeWidget()->loadScript(n, error);
531 qCDebug(LIBKSIEVEUI_LOG) <<
" include not supported";
533 }
else if (actionName == QLatin1StringView(
"global")) {
534 if (!currentPage || (typeBlock == TypeBlockIf) || (typeBlock == TypeBlockElse) || (typeBlock == TypeBlockElsif)) {
535 currentPage = createNewScript(scriptName.
isEmpty() ? createUniqName() : scriptName, comment);
538 typeBlock = TypeBlockGlobal;
539 if (currentPage->globalVariableWidget()) {
540 currentPage->globalVariableWidget()->loadScript(n, error);
542 qCDebug(LIBKSIEVEUI_LOG) <<
" globalVariable not supported";
544 }
else if (actionName == QLatin1StringView(
"set") && (typeBlock == TypeBlockGlobal)) {
546 if (currentPage->globalVariableWidget()) {
547 const SieveGlobalVariableActionWidget::VariableElement var = currentPage->globalVariableWidget()->loadSetVariable(n, error);
549 qCDebug(LIBKSIEVEUI_LOG) <<
"It's not a global variable";
550 if ((typeBlock == TypeBlockIf) || (typeBlock == TypeBlockElse) || (typeBlock == TypeBlockElsif)) {
551 currentPage = createNewScript(scriptName.
isEmpty() ? createUniqName() : scriptName, comment);
553 typeBlock = TypeBlockAction;
555 currentPage->blockIfWidget()->loadLocalVariable(var);
558 qCDebug(LIBKSIEVEUI_LOG) <<
" set not supported";
561 if (!currentPage || (typeBlock == TypeBlockIf) || (typeBlock == TypeBlockElse) || (typeBlock == TypeBlockElsif)) {
562 currentPage = createNewScript(scriptName.
isEmpty() ? createUniqName() : scriptName, comment);
564 typeBlock = TypeBlockAction;
566 currentPage->blockIfWidget()->loadScript(n,
true, error);
569 }
else if (tagName == QLatin1StringView(
"crlf")) {
571 if (previousElementWasAComment) {
572 comment += QLatin1Char(
'\n');
576 qCDebug(LIBKSIEVEUI_LOG) <<
" unknown tagname" << tagName;
581QString SieveScriptListBox::createUniqName()
583 const QString pattern =
i18n(
"Script part %1", mScriptNumber);
588#include "moc_sievescriptlistbox.cpp"
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
ButtonCode warningTwoActions(QWidget *parent, const QString &text, const QString &title, const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const QString &dontAskAgainName=QString(), Options options=Options(Notify|Dangerous))
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
void setIcon(const QIcon &icon)
void triggered(bool checked)
QIcon fromTheme(const QString &name)
QString getText(QWidget *parent, const QString &title, const QString &label, QLineEdit::EchoMode mode, const QString &text, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
void append(QList< T > &&value)
qsizetype count() const const
bool isEmpty() const const
void setText(const QString &text)
QString text() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString arg(Args &&... args) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype length() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & removeAt(qsizetype pos)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QString trimmed() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QString toString() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool hasAttribute(QAnyStringView namespaceUri, QAnyStringView name) const const
QStringView value(QAnyStringView namespaceUri, QAnyStringView name) const const
QXmlStreamAttributes attributes() const const
QStringView name() const const
QString readElementText(ReadElementTextBehaviour behaviour)
bool readNextStartElement()
void skipCurrentElement()