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 "sieveincludewidget.h" 0008 #include "autocreatescripts/autocreatescriptutil_p.h" 0009 #include "autocreatescriptutil_p.h" 0010 #include "commonwidgets/sievehelpbutton.h" 0011 #include "sievescriptblockwidget.h" 0012 #include "widgets/includefilelineedit.h" 0013 #include <KLineEditEventHandler> 0014 0015 #include <KLocalizedString> 0016 #include <QIcon> 0017 #include <QPushButton> 0018 #include <QScrollArea> 0019 0020 #include "libksieveui_debug.h" 0021 #include <QCheckBox> 0022 #include <QGridLayout> 0023 #include <QLabel> 0024 #include <QWhatsThis> 0025 #include <QXmlStreamReader> 0026 0027 using namespace KSieveUi; 0028 0029 static const int MINIMUMINCLUDEACTION = 1; 0030 static const int MAXIMUMINCLUDEACTION = 20; 0031 0032 SieveIncludeLocation::SieveIncludeLocation(QWidget *parent) 0033 : QComboBox(parent) 0034 { 0035 initialize(); 0036 connect(this, &SieveIncludeLocation::activated, this, &SieveIncludeLocation::valueChanged); 0037 } 0038 0039 SieveIncludeLocation::~SieveIncludeLocation() = default; 0040 0041 void SieveIncludeLocation::initialize() 0042 { 0043 addItem(i18n("personal"), QStringLiteral(":personal")); 0044 addItem(i18n("global"), QStringLiteral(":global")); 0045 } 0046 0047 QString SieveIncludeLocation::code() const 0048 { 0049 return itemData(currentIndex()).toString(); 0050 } 0051 0052 void SieveIncludeLocation::setCode(const QString &code, QString &error) 0053 { 0054 const int index = findData(code); 0055 if (index != -1) { 0056 setCurrentIndex(index); 0057 } else { 0058 error += i18n("Unknown location type \"%1\" during parsing includes", code) + QLatin1Char('\n'); 0059 setCurrentIndex(0); 0060 } 0061 } 0062 0063 SieveIncludeActionWidget::SieveIncludeActionWidget(QWidget *parent) 0064 : QWidget(parent) 0065 { 0066 initWidget(); 0067 } 0068 0069 SieveIncludeActionWidget::~SieveIncludeActionWidget() = default; 0070 0071 void SieveIncludeActionWidget::clear() 0072 { 0073 mOptional->setChecked(false); 0074 mOnce->setChecked(false); 0075 mLocation->setCurrentIndex(0); 0076 mIncludeFileName->clear(); 0077 } 0078 0079 void SieveIncludeActionWidget::setListOfIncludeFile(const QStringList &listOfIncludeFile) 0080 { 0081 mIncludeFileName->setListOfIncludeFile(listOfIncludeFile); 0082 } 0083 0084 void SieveIncludeActionWidget::loadScript(QXmlStreamReader &element, QString &error) 0085 { 0086 while (element.readNextStartElement()) { 0087 const QStringView tagName = element.name(); 0088 if (tagName == QLatin1StringView("tag")) { 0089 const QString tagValue = element.readElementText(); 0090 if (tagValue == QLatin1StringView("personal") || tagValue == QLatin1StringView("global")) { 0091 mLocation->setCode(AutoCreateScriptUtil::tagValue(tagValue), error); 0092 } else if (tagValue == QLatin1StringView("optional")) { 0093 mOptional->setChecked(true); 0094 } else if (tagValue == QLatin1StringView("once")) { 0095 mOnce->setChecked(true); 0096 } else { 0097 qCDebug(LIBKSIEVEUI_LOG) << " SieveIncludeActionWidget::loadScript unknown tagValue " << tagValue; 0098 } 0099 } else if (tagName == QLatin1StringView("str")) { 0100 mIncludeFileName->setText(element.readElementText()); 0101 } else { 0102 qCDebug(LIBKSIEVEUI_LOG) << " SieveIncludeActionWidget::loadScript unknown tagName " << tagName; 0103 } 0104 } 0105 } 0106 0107 void SieveIncludeActionWidget::generatedScript(QString &script) 0108 { 0109 const QString includeName = mIncludeFileName->text().trimmed(); 0110 if (includeName.isEmpty()) { 0111 return; 0112 } 0113 script += QLatin1StringView("include "); 0114 script += mLocation->code() + QLatin1Char(' '); 0115 if (mOptional->isChecked()) { 0116 script += QLatin1StringView(":optional "); 0117 } 0118 if (mOnce->isChecked()) { 0119 script += QLatin1StringView(":once "); 0120 } 0121 script += QStringLiteral("\"%1\";\n").arg(includeName); 0122 } 0123 0124 void SieveIncludeActionWidget::initWidget() 0125 { 0126 mLayout = new QGridLayout(this); 0127 mLayout->setContentsMargins({}); 0128 0129 auto lab = new QLabel(i18n("Include:"), this); 0130 mLayout->addWidget(lab, 1, 0); 0131 mLocation = new SieveIncludeLocation(this); 0132 connect(mLocation, &SieveIncludeLocation::valueChanged, this, &SieveIncludeActionWidget::valueChanged); 0133 mLayout->addWidget(mLocation, 1, 1); 0134 0135 lab = new QLabel(i18n("Name:"), this); 0136 mLayout->addWidget(lab, 1, 2); 0137 0138 mIncludeFileName = new IncludeFileLineEdit(this); 0139 KLineEditEventHandler::catchReturnKey(mIncludeFileName); 0140 mIncludeFileName->setClearButtonEnabled(true); 0141 connect(mIncludeFileName, &QLineEdit::textChanged, this, &SieveIncludeActionWidget::valueChanged); 0142 mLayout->addWidget(mIncludeFileName, 1, 3); 0143 0144 mOptional = new QCheckBox(i18n("Optional"), this); 0145 connect(mOptional, &QCheckBox::toggled, this, &SieveIncludeActionWidget::valueChanged); 0146 mLayout->addWidget(mOptional, 1, 4); 0147 0148 mOnce = new QCheckBox(i18n("Once"), this); 0149 connect(mOnce, &QCheckBox::toggled, this, &SieveIncludeActionWidget::valueChanged); 0150 mLayout->addWidget(mOnce, 1, 5); 0151 0152 mAdd = new QPushButton(this); 0153 mAdd->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); 0154 mAdd->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); 0155 0156 mRemove = new QPushButton(this); 0157 mRemove->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); 0158 mRemove->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); 0159 mLayout->addWidget(mAdd, 1, 6); 0160 mLayout->addWidget(mRemove, 1, 7); 0161 0162 connect(mAdd, &QPushButton::clicked, this, &SieveIncludeActionWidget::slotAddWidget); 0163 connect(mRemove, &QPushButton::clicked, this, &SieveIncludeActionWidget::slotRemoveWidget); 0164 } 0165 0166 void SieveIncludeActionWidget::slotAddWidget() 0167 { 0168 Q_EMIT valueChanged(); 0169 Q_EMIT addWidget(this); 0170 } 0171 0172 void SieveIncludeActionWidget::slotRemoveWidget() 0173 { 0174 Q_EMIT valueChanged(); 0175 Q_EMIT removeWidget(this); 0176 } 0177 0178 bool SieveIncludeActionWidget::isInitialized() const 0179 { 0180 return !mIncludeFileName->text().isEmpty(); 0181 } 0182 0183 void SieveIncludeActionWidget::updateAddRemoveButton(bool addButtonEnabled, bool removeButtonEnabled) 0184 { 0185 mAdd->setEnabled(addButtonEnabled); 0186 mRemove->setEnabled(removeButtonEnabled); 0187 } 0188 0189 SieveIncludeWidget::SieveIncludeWidget(QWidget *parent) 0190 : SieveWidgetPageAbstract(parent) 0191 { 0192 auto lay = new QVBoxLayout(this); 0193 mHelpButton = new SieveHelpButton(this); 0194 lay->addWidget(mHelpButton); 0195 connect(mHelpButton, &SieveHelpButton::clicked, this, &SieveIncludeWidget::slotHelp); 0196 0197 mIncludeLister = new SieveIncludeWidgetLister(this); 0198 connect(mIncludeLister, &SieveIncludeWidgetLister::valueChanged, this, &SieveIncludeWidget::valueChanged); 0199 0200 auto scrollArea = new QScrollArea(this); 0201 scrollArea->setAutoFillBackground(false); 0202 scrollArea->setWidget(mIncludeLister); 0203 scrollArea->setWidgetResizable(true); 0204 scrollArea->setAlignment(Qt::AlignTop); 0205 lay->addWidget(scrollArea); 0206 0207 setPageType(KSieveUi::SieveScriptBlockWidget::Include); 0208 } 0209 0210 SieveIncludeWidget::~SieveIncludeWidget() = default; 0211 0212 void SieveIncludeWidget::setListOfIncludeFile(const QStringList &lst) 0213 { 0214 mIncludeLister->setListOfIncludeFile(lst); 0215 } 0216 0217 void SieveIncludeWidget::slotHelp() 0218 { 0219 const QString help = i18n( 0220 "The \"include\" command takes an optional \"location\" parameter, an optional \":once\" parameter, an optional \":optional\" parameter, and a single " 0221 "string argument representing the name of the script to include for processing at that point."); 0222 const QString href = QStringLiteral("https://tools.ietf.org/html/rfc6609#page-4"); 0223 const QString fullWhatsThis = AutoCreateScriptUtil::createFullWhatsThis(help, href); 0224 QWhatsThis::showText(QCursor::pos(), fullWhatsThis, mHelpButton); 0225 } 0226 0227 void SieveIncludeWidget::generatedScript(QString &script, QStringList &requireModules, bool inForEveryPartLoop) 0228 { 0229 Q_UNUSED(inForEveryPartLoop) 0230 QString result; 0231 QStringList lst; 0232 mIncludeLister->generatedScript(result, lst); 0233 if (!result.isEmpty()) { 0234 script += result; 0235 requireModules << lst; 0236 } 0237 } 0238 0239 void SieveIncludeWidget::loadScript(QXmlStreamReader &element, QString &error) 0240 { 0241 mIncludeLister->loadScript(element, error); 0242 } 0243 0244 SieveIncludeWidgetLister::SieveIncludeWidgetLister(QWidget *parent) 0245 : KPIM::KWidgetLister(false, MINIMUMINCLUDEACTION, MAXIMUMINCLUDEACTION, parent) 0246 { 0247 slotClear(); 0248 updateAddRemoveButton(); 0249 } 0250 0251 SieveIncludeWidgetLister::~SieveIncludeWidgetLister() = default; 0252 0253 void SieveIncludeWidgetLister::slotAddWidget(QWidget *w) 0254 { 0255 addWidgetAfterThisWidget(w); 0256 updateAddRemoveButton(); 0257 } 0258 0259 void SieveIncludeWidgetLister::slotRemoveWidget(QWidget *w) 0260 { 0261 removeWidget(w); 0262 updateAddRemoveButton(); 0263 } 0264 0265 void SieveIncludeWidgetLister::updateAddRemoveButton() 0266 { 0267 QList<QWidget *> widgetList = widgets(); 0268 const int numberOfWidget(widgetList.count()); 0269 bool addButtonEnabled = false; 0270 bool removeButtonEnabled = false; 0271 if (numberOfWidget <= widgetsMinimum()) { 0272 addButtonEnabled = true; 0273 removeButtonEnabled = false; 0274 } else if (numberOfWidget >= widgetsMaximum()) { 0275 addButtonEnabled = false; 0276 removeButtonEnabled = true; 0277 } else { 0278 addButtonEnabled = true; 0279 removeButtonEnabled = true; 0280 } 0281 QList<QWidget *>::ConstIterator wIt = widgetList.constBegin(); 0282 QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd(); 0283 for (; wIt != wEnd; ++wIt) { 0284 auto w = qobject_cast<SieveIncludeActionWidget *>(*wIt); 0285 w->updateAddRemoveButton(addButtonEnabled, removeButtonEnabled); 0286 } 0287 } 0288 0289 void SieveIncludeWidgetLister::setListOfIncludeFile(const QStringList &listOfIncludeFile) 0290 { 0291 mListOfIncludeFile = listOfIncludeFile; 0292 // Update all lineedit 0293 const QList<QWidget *> widgetList = widgets(); 0294 QList<QWidget *>::ConstIterator wIt = widgetList.constBegin(); 0295 QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd(); 0296 for (; wIt != wEnd; ++wIt) { 0297 auto w = qobject_cast<SieveIncludeActionWidget *>(*wIt); 0298 w->setListOfIncludeFile(mListOfIncludeFile); 0299 } 0300 } 0301 0302 void SieveIncludeWidgetLister::generatedScript(QString &script, QStringList &requireModules) 0303 { 0304 requireModules << QStringLiteral("include"); 0305 const QList<QWidget *> widgetList = widgets(); 0306 QList<QWidget *>::ConstIterator wIt = widgetList.constBegin(); 0307 QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd(); 0308 for (; wIt != wEnd; ++wIt) { 0309 auto w = qobject_cast<SieveIncludeActionWidget *>(*wIt); 0310 w->generatedScript(script); 0311 } 0312 } 0313 0314 void SieveIncludeWidgetLister::reconnectWidget(SieveIncludeActionWidget *w) 0315 { 0316 connect(w, &SieveIncludeActionWidget::addWidget, this, &SieveIncludeWidgetLister::slotAddWidget, Qt::UniqueConnection); 0317 connect(w, &SieveIncludeActionWidget::removeWidget, this, &SieveIncludeWidgetLister::slotRemoveWidget, Qt::UniqueConnection); 0318 connect(w, &SieveIncludeActionWidget::valueChanged, this, &SieveIncludeWidgetLister::valueChanged, Qt::UniqueConnection); 0319 } 0320 0321 void SieveIncludeWidgetLister::clearWidget(QWidget *aWidget) 0322 { 0323 if (aWidget) { 0324 auto widget = static_cast<SieveIncludeActionWidget *>(aWidget); 0325 widget->clear(); 0326 updateAddRemoveButton(); 0327 } 0328 Q_EMIT valueChanged(); 0329 } 0330 0331 QWidget *SieveIncludeWidgetLister::createWidget(QWidget *parent) 0332 { 0333 auto w = new SieveIncludeActionWidget(parent); 0334 w->setListOfIncludeFile(mListOfIncludeFile); 0335 reconnectWidget(w); 0336 return w; 0337 } 0338 0339 void SieveIncludeWidgetLister::loadScript(QXmlStreamReader &element, QString &error) 0340 { 0341 if (widgets().count() == MAXIMUMINCLUDEACTION) { 0342 error += QLatin1Char('\n') + i18n("We can not add more includes elements.") + QLatin1Char('\n'); 0343 return; 0344 } 0345 SieveIncludeActionWidget *w = static_cast<SieveIncludeActionWidget *>(widgets().constLast()); 0346 if (w->isInitialized()) { 0347 addWidgetAfterThisWidget(widgets().constLast()); 0348 w = static_cast<SieveIncludeActionWidget *>(widgets().constLast()); 0349 } 0350 w->loadScript(element, error); 0351 } 0352 0353 #include "moc_sieveincludewidget.cpp"