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"