File indexing completed on 2024-12-29 04:54:45

0001 /*
0002    SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "sievescriptblockwidget.h"
0008 #include "autocreatescriptutil_p.h"
0009 #include "sieveactionwidgetlister.h"
0010 #include "sieveconditionwidgetlister.h"
0011 
0012 #include <KLocalizedString>
0013 #include <QComboBox>
0014 #include <QIcon>
0015 #include <QPushButton>
0016 
0017 #include "libksieveui_debug.h"
0018 #include <QButtonGroup>
0019 #include <QGroupBox>
0020 #include <QLabel>
0021 #include <QRadioButton>
0022 #include <QScrollArea>
0023 #include <QVBoxLayout>
0024 #include <QXmlStreamReader>
0025 
0026 using namespace KSieveUi;
0027 
0028 SieveScriptBlockWidget::SieveScriptBlockWidget(SieveEditorGraphicalModeWidget *graphicalModeWidget, QWidget *parent)
0029     : SieveWidgetPageAbstract(parent)
0030     , mSieveGraphicalModeWidget(graphicalModeWidget)
0031 {
0032     auto topLayout = new QVBoxLayout(this);
0033     topLayout->setContentsMargins({});
0034 
0035     mConditions = new QGroupBox(i18n("Conditions"), this);
0036     auto vbox = new QVBoxLayout;
0037 
0038     mAllMessageRBtn = new QRadioButton(i18n("Match all messages"), this);
0039     mMatchAll = new QRadioButton(i18n("Match a&ll of the following"), this);
0040     mMatchAny = new QRadioButton(i18n("Match an&y of the following"), this);
0041 
0042     vbox->addWidget(mMatchAll);
0043     vbox->addWidget(mMatchAny);
0044     vbox->addWidget(mAllMessageRBtn);
0045     mMatchAll->setChecked(true);
0046     mMatchAny->setChecked(false);
0047     mAllMessageRBtn->setChecked(false);
0048 
0049     auto bg = new QButtonGroup(this);
0050     bg->addButton(mMatchAll);
0051     bg->addButton(mMatchAny);
0052     bg->addButton(mAllMessageRBtn);
0053 
0054     connect(bg, &QButtonGroup::buttonClicked, this, &SieveScriptBlockWidget::slotRadioClicked);
0055     mConditions->setLayout(vbox);
0056 
0057     mScriptConditionLister = new SieveConditionWidgetLister(mSieveGraphicalModeWidget, this);
0058     connect(mScriptConditionLister, &SieveConditionWidgetLister::valueChanged, this, &SieveScriptBlockWidget::valueChanged);
0059     auto scrollArea = new QScrollArea(this);
0060     scrollArea->setAutoFillBackground(false);
0061     scrollArea->setWidget(mScriptConditionLister);
0062     scrollArea->setWidgetResizable(true);
0063     scrollArea->setAlignment(Qt::AlignTop);
0064     vbox->addWidget(scrollArea);
0065 
0066     topLayout->addWidget(mConditions);
0067 
0068     auto actions = new QGroupBox(i18n("Actions"), this);
0069     vbox = new QVBoxLayout;
0070     actions->setLayout(vbox);
0071     mScriptActionLister = new SieveActionWidgetLister(mSieveGraphicalModeWidget, this);
0072     connect(mScriptActionLister, &SieveActionWidgetLister::valueChanged, this, &SieveScriptBlockWidget::valueChanged);
0073 
0074     auto scrollAreaCondition = new QScrollArea(this);
0075     scrollAreaCondition->setAutoFillBackground(false);
0076     scrollAreaCondition->setWidget(mScriptActionLister);
0077     scrollAreaCondition->setWidgetResizable(true);
0078     scrollAreaCondition->setAlignment(Qt::AlignTop);
0079     vbox->addWidget(scrollAreaCondition);
0080     topLayout->addWidget(actions);
0081 
0082     auto newBlockLayout = new QHBoxLayout;
0083     auto lab = new QLabel(i18n("Add new block:"));
0084     newBlockLayout->addWidget(lab);
0085     mNewBlockType = new QComboBox(this);
0086     newBlockLayout->addWidget(mNewBlockType);
0087     mNewBlockType->addItem(i18n("\"elsif\" block"));
0088     mNewBlockType->addItem(i18n("\"else\" block"));
0089 
0090     mAddBlockType = new QPushButton(this);
0091     mAddBlockType->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
0092     mAddBlockType->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
0093     newBlockLayout->addWidget(mAddBlockType);
0094     connect(mAddBlockType, &QPushButton::clicked, this, &SieveScriptBlockWidget::slotAddBlock);
0095 
0096     topLayout->addLayout(newBlockLayout);
0097 }
0098 
0099 SieveScriptBlockWidget::~SieveScriptBlockWidget() = default;
0100 
0101 void SieveScriptBlockWidget::slotAddBlock()
0102 {
0103     KSieveUi::SieveWidgetPageAbstract::PageType type = BlockElsIf;
0104     switch (mNewBlockType->currentIndex()) {
0105     case 0:
0106         type = BlockElsIf;
0107         break;
0108     case 1:
0109         type = BlockElse;
0110         break;
0111     }
0112 
0113     Q_EMIT valueChanged();
0114     Q_EMIT addNewBlock(this, type);
0115 }
0116 
0117 void SieveScriptBlockWidget::setPageType(PageType type)
0118 {
0119     if (pageType() != type) {
0120         SieveWidgetPageAbstract::setPageType(type);
0121         switch (type) {
0122         case BlockIf:
0123             mAllMessageRBtn->show();
0124             mConditions->show();
0125             mAddBlockType->setEnabled(true);
0126             mNewBlockType->setEnabled(true);
0127             break;
0128         case BlockElsIf:
0129             mAllMessageRBtn->hide();
0130             mConditions->show();
0131             mAddBlockType->setEnabled(true);
0132             mNewBlockType->setEnabled(true);
0133             break;
0134         case BlockElse:
0135             mAllMessageRBtn->hide();
0136             mConditions->hide();
0137             mAddBlockType->setEnabled(false);
0138             mNewBlockType->setEnabled(false);
0139             break;
0140         default:
0141             break;
0142         }
0143     }
0144 }
0145 
0146 SieveScriptBlockWidget::MatchCondition SieveScriptBlockWidget::matchCondition() const
0147 {
0148     return mMatchCondition;
0149 }
0150 
0151 void SieveScriptBlockWidget::slotRadioClicked(QAbstractButton *button)
0152 {
0153     if (button == mMatchAll) {
0154         mMatchCondition = AndCondition;
0155     } else if (button == mMatchAny) {
0156         mMatchCondition = OrCondition;
0157     } else {
0158         mMatchCondition = AllCondition;
0159     }
0160     Q_EMIT valueChanged();
0161     updateWidget();
0162 }
0163 
0164 void SieveScriptBlockWidget::updateWidget()
0165 {
0166     mScriptConditionLister->setEnabled(mMatchCondition != AllCondition);
0167     mNewBlockType->setEnabled(mMatchCondition != AllCondition);
0168     mAddBlockType->setEnabled(mMatchCondition != AllCondition);
0169 }
0170 
0171 void SieveScriptBlockWidget::generatedScript(QString &script, QStringList &required, bool inForEveryPartLoop)
0172 {
0173     QString indentation;
0174     if (inForEveryPartLoop) {
0175         indentation = AutoCreateScriptUtil::indentation();
0176     }
0177     bool onlyActions = false;
0178     if (mMatchCondition == AllCondition) {
0179         onlyActions = true;
0180         // Just actions type
0181     } else if (pageType() == BlockElse) {
0182         script += QLatin1StringView("else {\n");
0183     } else {
0184         QString conditionStr;
0185         int numberOfCondition = 0;
0186         mScriptConditionLister->generatedScript(conditionStr, numberOfCondition, required, inForEveryPartLoop);
0187         const bool hasUniqCondition = (numberOfCondition == 1);
0188         QString filterStr;
0189         QString blockStr;
0190         switch (pageType()) {
0191         case BlockIf:
0192             blockStr = indentation + QStringLiteral("if ");
0193             break;
0194         case BlockElsIf:
0195             blockStr = QStringLiteral("elsif ");
0196             break;
0197         case BlockElse:
0198             break;
0199         default:
0200             // We can got here.
0201             break;
0202         }
0203 
0204         if (hasUniqCondition == 1) {
0205             filterStr += blockStr;
0206         } else if (mMatchCondition == AndCondition) {
0207             filterStr += blockStr + QLatin1StringView("allof (");
0208         } else if (mMatchCondition == OrCondition) {
0209             filterStr += blockStr + QLatin1StringView("anyof (");
0210         }
0211 
0212         if (conditionStr.isEmpty()) {
0213             return;
0214         } else {
0215             script += filterStr + conditionStr;
0216         }
0217         if (hasUniqCondition) {
0218             script += indentation + QLatin1StringView("{\n");
0219         } else {
0220             script += indentation + QStringLiteral(")\n%1{\n").arg(indentation);
0221         }
0222     }
0223     mScriptActionLister->generatedScript(script, required, onlyActions, inForEveryPartLoop);
0224     if (!onlyActions) {
0225         script += indentation + QLatin1StringView("} ");
0226     }
0227 }
0228 
0229 void SieveScriptBlockWidget::updateCondition()
0230 {
0231     switch (mMatchCondition) {
0232     case AndCondition:
0233         mMatchAll->setChecked(true);
0234         break;
0235     case OrCondition:
0236         mMatchAny->setChecked(true);
0237         break;
0238     case AllCondition:
0239         mAllMessageRBtn->setChecked(true);
0240         break;
0241     }
0242     updateWidget();
0243 }
0244 
0245 void SieveScriptBlockWidget::loadLocalVariable(const SieveGlobalVariableActionWidget::VariableElement &var)
0246 {
0247     mScriptActionLister->loadLocalVariable(var);
0248     mMatchCondition = AllCondition;
0249     updateCondition();
0250 }
0251 
0252 void SieveScriptBlockWidget::loadScript(QXmlStreamReader &element, bool onlyActions, QString &error)
0253 {
0254     if (onlyActions) {
0255         mScriptActionLister->loadScript(element, true, error);
0256         mMatchCondition = AllCondition;
0257         updateCondition();
0258     } else {
0259         bool uniqueTest = false;
0260         while (element.readNextStartElement()) {
0261             const QStringView tagName = element.name();
0262             if (tagName == QLatin1StringView("test")) {
0263                 bool notCondition = false;
0264                 if (element.attributes().hasAttribute(QLatin1StringView("name"))) {
0265                     const QString typeCondition = element.attributes().value(QLatin1StringView("name")).toString();
0266                     if (typeCondition == QLatin1StringView("anyof")) {
0267                         mMatchCondition = OrCondition;
0268                     } else if (typeCondition == QLatin1StringView("allof")) {
0269                         mMatchAll->setChecked(true);
0270                     } else {
0271                         if (typeCondition == QLatin1StringView("not")) {
0272                             notCondition = true;
0273                         }
0274                         uniqueTest = true;
0275                         mMatchCondition = OrCondition;
0276                     }
0277                     updateCondition();
0278                 }
0279                 mScriptConditionLister->loadScript(element, uniqueTest, notCondition, error);
0280             } else if (tagName == QLatin1StringView("block")) {
0281                 mScriptActionLister->loadScript(element, false, error);
0282             } else {
0283                 if (tagName != QLatin1StringView("crlf")) {
0284                     qCDebug(LIBKSIEVEUI_LOG) << " e.tag" << tagName;
0285                 } else {
0286                     element.skipCurrentElement();
0287                 }
0288             }
0289         }
0290     }
0291 }
0292 
0293 #include "moc_sievescriptblockwidget.cpp"