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"