sieveconditionwidgetlister.cpp 14.5 KB
Newer Older
1
/*
Laurent Montel's avatar
Laurent Montel committed
2
   SPDX-FileCopyrightText: 2013-2021 Laurent Montel <montel@kde.org>
3

4
   SPDX-License-Identifier: LGPL-2.0-or-later
5
6
7
8
9
10
*/

#include "sieveconditionwidgetlister.h"
#include "autocreatescriptdialog.h"
#include "autocreatescriptutil_p.h"
#include "commonwidgets/sievehelpbutton.h"
Laurent Montel's avatar
Laurent Montel committed
11
#include "libksieve_debug.h"
12
#include "sieveconditions/sievecondition.h"
Laurent Montel's avatar
Laurent Montel committed
13
14
#include "sieveconditions/sieveconditionlist.h"
#include "sieveeditorgraphicalmodewidget.h"
15
16

#include <KLocalizedString>
17
#include <QComboBox>
Laurent Montel's avatar
Laurent Montel committed
18
#include <QIcon>
19
#include <QPointer>
Laurent Montel's avatar
Laurent Montel committed
20
21
#include <QPushButton>
#include <QUrl>
22

Laurent Montel's avatar
Laurent Montel committed
23
#include "sievescriptdescriptiondialog.h"
24
25
26
27
28
29
30
31
32
#include <QGridLayout>
#include <QLabel>
#include <QWhatsThis>

using namespace KSieveUi;

static const int MINIMUMCONDITION = 1;
static const int MAXIMUMCONDITION = 8;

33
SieveConditionWidget::SieveConditionWidget(SieveEditorGraphicalModeWidget *sieveGraphicalModeWidget, QWidget *parent)
Laurent Montel's avatar
Laurent Montel committed
34
35
    : QWidget(parent)
    , mSieveGraphicalModeWidget(sieveGraphicalModeWidget)
36
37
38
39
40
41
42
43
44
45
46
47
{
    initWidget();
}

SieveConditionWidget::~SieveConditionWidget()
{
    qDeleteAll(mConditionList);
    mConditionList.clear();
}

void SieveConditionWidget::setFilterCondition(QWidget *widget)
{
48
49
    if (mLayout->itemAtPosition(1, 3)) {
        delete mLayout->itemAtPosition(1, 3)->widget();
50
51
52
    }

    if (widget) {
53
        mLayout->addWidget(widget, 1, 3);
54
    } else {
55
        mLayout->addWidget(new QLabel(i18n("Please select an condition."), this), 1, 3);
56
57
58
    }
}

Laurent Montel's avatar
Laurent Montel committed
59
void SieveConditionWidget::generatedScript(QString &script, QStringList &required, bool inForEveryPartLoop)
60
{
Laurent Montel's avatar
Laurent Montel committed
61
    Q_UNUSED(inForEveryPartLoop)
62
63
64
    const int index = mComboBox->currentIndex();
    if (index != mComboBox->count() - 1) {
        KSieveUi::SieveCondition *widgetCondition = mConditionList.at(mComboBox->currentIndex());
65
        QWidget *currentWidget = mLayout->itemAtPosition(1, 3)->widget();
66
        const QStringList lstRequires = widgetCondition->needRequires(currentWidget);
Laurent Montel's avatar
Laurent Montel committed
67
        for (const QString &r : lstRequires) {
Laurent Montel's avatar
Laurent Montel committed
68
69
            if (!required.contains(r)) {
                required.append(r);
70
71
72
73
74
75
76
77
78
            }
        }
        script += mConditionList.at(mComboBox->currentIndex())->code(currentWidget) + QLatin1Char('\n');
    }
}

void SieveConditionWidget::initWidget()
{
    mLayout = new QGridLayout(this);
Laurent Montel's avatar
Laurent Montel committed
79
    mLayout->setContentsMargins({});
80

81
82
    mComboBox = new QComboBox;
    mComboBox->setMinimumWidth(50);
83
84
    mComboBox->setEditable(false);

85
    const QList<KSieveUi::SieveCondition *> list = KSieveUi::SieveConditionList::conditionList(mSieveGraphicalModeWidget);
86
87
88
89
90
    QList<KSieveUi::SieveCondition *>::const_iterator it;
    QList<KSieveUi::SieveCondition *>::const_iterator end(list.constEnd());
    int index = 0;
    for (index = 0, it = list.constBegin(); it != end; ++it, ++index) {
        if ((*it)->needCheckIfServerHasCapability()) {
91
            if (mSieveGraphicalModeWidget->sieveCapabilities().contains((*it)->serverNeedsCapability())) {
92
93
94
95
96
97
                // append to the list of actions:
                mConditionList.append(*it);
                connect(*it, &SieveCondition::valueChanged, this, &SieveConditionWidget::valueChanged);
                // add (i18n-ized) name to combo box
                mComboBox->addItem((*it)->label(), (*it)->name());
            } else {
Laurent Montel's avatar
Laurent Montel committed
98
                delete (*it);
99
100
101
102
103
104
105
106
107
108
            }
        } else {
            // append to the list of actions:
            mConditionList.append(*it);
            connect(*it, &SieveCondition::valueChanged, this, &SieveConditionWidget::valueChanged);
            // add (i18n-ized) name to combo box
            mComboBox->addItem((*it)->label(), (*it)->name());
        }
    }

Laurent Montel's avatar
Laurent Montel committed
109
    mHelpButton = new SieveHelpButton(this);
110
111
112
    mLayout->addWidget(mHelpButton, 1, 0);
    connect(mHelpButton, &SieveHelpButton::clicked, this, &SieveConditionWidget::slotHelp);

113
114
115
116
117
118
    mCommentButton = new QToolButton(this);
    mCommentButton->setToolTip(i18n("Add comment"));
    mLayout->addWidget(mCommentButton, 1, 1);
    mCommentButton->setIcon(QIcon::fromTheme(QStringLiteral("view-pim-notes")));
    connect(mCommentButton, &QToolButton::clicked, this, &SieveConditionWidget::slotAddComment);

119
    mComboBox->addItem(QLatin1String(""));
120
    mLayout->addWidget(mComboBox, 1, 2);
121
    connect(mComboBox, &QComboBox::activated, this, &SieveConditionWidget::slotConditionChanged);
122
123
124
125
126
127
128
129
130
131
132
133
134
135

    mComboBox->setMaxCount(mComboBox->count());
    mComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
    setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
    mComboBox->adjustSize();

    mAdd = new QPushButton(this);
    mAdd->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
    mAdd->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));

    mRemove = new QPushButton(this);
    mRemove->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
    mRemove->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));

136
137
    mLayout->addWidget(mAdd, 1, 4);
    mLayout->addWidget(mRemove, 1, 5);
138
139
140
141
142
143

    // redirect focus to the filter action combo box
    setFocusProxy(mComboBox);

    connect(mAdd, &QPushButton::clicked, this, &SieveConditionWidget::slotAddWidget);
    connect(mRemove, &QPushButton::clicked, this, &SieveConditionWidget::slotRemoveWidget);
144
145
146
147
148
149
150
151
152
153

    clear();
}

void SieveConditionWidget::slotAddComment()
{
    const int index = mComboBox->currentIndex();
    if (index < mConditionList.count()) {
        KSieveUi::SieveCondition *condition = mConditionList.at(index);
        const QString comment = condition->comment();
Laurent Montel's avatar
Laurent Montel committed
154
        QPointer<SieveScriptDescriptionDialog> dlg = new SieveScriptDescriptionDialog(this);
155
156
157
158
159
160
161
        dlg->setDescription(comment);
        if (dlg->exec()) {
            condition->setComment(dlg->description());
            Q_EMIT valueChanged();
        }
        delete dlg;
    }
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
}

void SieveConditionWidget::slotHelp()
{
    const int index = mComboBox->currentIndex();
    if (index < mConditionList.count()) {
        KSieveUi::SieveCondition *condition = mConditionList.at(index);
        const QString help = condition->help();
        const QUrl href = condition->href();
        const QString fullWhatsThis = AutoCreateScriptUtil::createFullWhatsThis(help, href.toString());
        QWhatsThis::showText(QCursor::pos(), fullWhatsThis, mHelpButton);
    }
}

void SieveConditionWidget::slotConditionChanged(int index)
{
    if (index < mConditionList.count()) {
        KSieveUi::SieveCondition *condition = mConditionList.at(index);
        mHelpButton->setEnabled(!condition->help().isEmpty());
        setFilterCondition(condition->createParamWidget(this));
182
        mCommentButton->setEnabled(true);
183
    } else {
Laurent Montel's avatar
Laurent Montel committed
184
        setFilterCondition(nullptr);
185
        mHelpButton->setEnabled(false);
186
        mCommentButton->setEnabled(false);
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
    }
    Q_EMIT valueChanged();
}

void SieveConditionWidget::slotAddWidget()
{
    Q_EMIT addWidget(this);
    Q_EMIT valueChanged();
}

void SieveConditionWidget::slotRemoveWidget()
{
    Q_EMIT removeWidget(this);
    Q_EMIT valueChanged();
}

Laurent Montel's avatar
Laurent Montel committed
203
void SieveConditionWidget::clear()
204
{
Laurent Montel's avatar
Laurent Montel committed
205
206
207
    mComboBox->setCurrentIndex(mComboBox->count() - 1);
    setFilterCondition(nullptr);
    mHelpButton->setEnabled(false);
208
    mCommentButton->setEnabled(false);
209
210
211
212
213
214
215
216
}

void SieveConditionWidget::updateAddRemoveButton(bool addButtonEnabled, bool removeButtonEnabled)
{
    mAdd->setEnabled(addButtonEnabled);
    mRemove->setEnabled(removeButtonEnabled);
}

Laurent Montel's avatar
Laurent Montel committed
217
void SieveConditionWidget::setCondition(const QString &conditionName, QXmlStreamReader &element, bool notCondition, QString &error)
218
219
220
221
222
223
224
{
    const int index = mComboBox->findData(conditionName);
    if (index != -1) {
        mComboBox->setCurrentIndex(index);
        slotConditionChanged(index);
        KSieveUi::SieveCondition *condition = mConditionList.at(index);
        condition->setParamWidgetValue(element, this, notCondition, error);
225
    } else {
Laurent Montel's avatar
Laurent Montel committed
226
        error += i18n("Script contains unsupported feature \"%1\"", conditionName) + QLatin1Char('\n');
227
        qCDebug(LIBKSIEVE_LOG) << "Condition " << conditionName << " not supported";
Laurent Montel's avatar
Laurent Montel committed
228
        element.skipCurrentElement();
229
230
231
    }
}

232
SieveConditionWidgetLister::SieveConditionWidgetLister(SieveEditorGraphicalModeWidget *sieveGraphicalModeWidget, QWidget *parent)
Laurent Montel's avatar
Laurent Montel committed
233
234
    : KPIM::KWidgetLister(false, MINIMUMCONDITION, MAXIMUMCONDITION, parent)
    , mSieveGraphicalModeWidget(sieveGraphicalModeWidget)
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
{
    slotClear();
    updateAddRemoveButton();
}

SieveConditionWidgetLister::~SieveConditionWidgetLister()
{
}

void SieveConditionWidgetLister::slotAddWidget(QWidget *w)
{
    addWidgetAfterThisWidget(w);
    updateAddRemoveButton();
}

void SieveConditionWidgetLister::slotRemoveWidget(QWidget *w)
{
    removeWidget(w);
    updateAddRemoveButton();
}

void SieveConditionWidgetLister::updateAddRemoveButton()
{
    QList<QWidget *> widgetList = widgets();
    const int numberOfWidget(widgetList.count());
    bool addButtonEnabled = false;
    bool removeButtonEnabled = false;
    if (numberOfWidget <= widgetsMinimum()) {
        addButtonEnabled = true;
        removeButtonEnabled = false;
    } else if (numberOfWidget >= widgetsMaximum()) {
        addButtonEnabled = false;
        removeButtonEnabled = true;
    } else {
        addButtonEnabled = true;
        removeButtonEnabled = true;
    }
    QList<QWidget *>::ConstIterator wIt = widgetList.constBegin();
    QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
    for (; wIt != wEnd; ++wIt) {
275
        auto w = qobject_cast<SieveConditionWidget *>(*wIt);
276
277
278
279
280
281
282
283
284
285
286
287
288
        w->updateAddRemoveButton(addButtonEnabled, removeButtonEnabled);
    }
}

void SieveConditionWidgetLister::reconnectWidget(SieveConditionWidget *w)
{
    connect(w, &SieveConditionWidget::addWidget, this, &SieveConditionWidgetLister::slotAddWidget, Qt::UniqueConnection);
    connect(w, &SieveConditionWidget::removeWidget, this, &SieveConditionWidgetLister::slotRemoveWidget, Qt::UniqueConnection);
    connect(w, &SieveConditionWidget::valueChanged, this, &SieveConditionWidgetLister::valueChanged, Qt::UniqueConnection);
}

void SieveConditionWidgetLister::clearWidget(QWidget *aWidget)
{
Laurent Montel's avatar
Laurent Montel committed
289
    if (aWidget) {
290
        auto widget = static_cast<SieveConditionWidget *>(aWidget);
Laurent Montel's avatar
Laurent Montel committed
291
292
        widget->clear();
    }
293
294
295
296
297
    Q_EMIT valueChanged();
}

QWidget *SieveConditionWidgetLister::createWidget(QWidget *parent)
{
298
    auto w = new SieveConditionWidget(mSieveGraphicalModeWidget, parent);
299
300
301
302
    reconnectWidget(w);
    return w;
}

Laurent Montel's avatar
Laurent Montel committed
303
void SieveConditionWidgetLister::generatedScript(QString &script, int &numberOfCondition, QStringList &requireModules, bool inForEveryPartLoop)
304
305
306
307
308
309
310
{
    const QList<QWidget *> widgetList = widgets();
    QList<QWidget *>::ConstIterator wIt = widgetList.constBegin();
    QList<QWidget *>::ConstIterator wEnd = widgetList.constEnd();
    bool wasFirst = true;
    for (; wIt != wEnd; ++wIt) {
        QString condition;
311
        auto w = qobject_cast<SieveConditionWidget *>(*wIt);
Laurent Montel's avatar
Laurent Montel committed
312
        w->generatedScript(condition, requireModules, inForEveryPartLoop);
313
314
        if (!condition.isEmpty()) {
            if (!wasFirst) {
315
316
317
                if (inForEveryPartLoop) {
                    script += AutoCreateScriptUtil::indentation();
                }
318
319
320
321
322
323
324
325
326
327
328
329
330
331
                script += QLatin1String(", ");
            }
            script += condition;
            wasFirst = false;
            ++numberOfCondition;
        }
    }
}

int SieveConditionWidgetLister::conditionNumber() const
{
    return widgets().count();
}

Laurent Montel's avatar
Laurent Montel committed
332
void SieveConditionWidgetLister::loadTest(QXmlStreamReader &element, bool notCondition, QString &error)
333
{
Laurent Montel's avatar
Porting    
Laurent Montel committed
334
335
336
    if (notCondition) {
        element.readNextStartElement();
    }
Laurent Montel's avatar
Laurent Montel committed
337
338
    if (element.attributes().hasAttribute(QLatin1String("name"))) {
        const QString conditionName = element.attributes().value(QLatin1String("name")).toString();
339
        auto w = qobject_cast<SieveConditionWidget *>(widgets().constLast());
Laurent Montel's avatar
Porting    
Laurent Montel committed
340
341
        w->setCondition(conditionName, element, notCondition, error);
    }
Laurent Montel's avatar
Laurent Montel committed
342
343
344
    if (notCondition) {
        element.skipCurrentElement();
    }
345
346
}

Laurent Montel's avatar
Porting    
Laurent Montel committed
347
void SieveConditionWidgetLister::loadScript(QXmlStreamReader &element, bool uniqTest, bool notCondition, QString &error)
348
{
Laurent Montel's avatar
Porting    
Laurent Montel committed
349
350
351
352
353
354
355
356
357
358
359
360
361
    if (uniqTest) {
        loadTest(element, notCondition, error);
    } else {
        bool firstCondition = true;
        if (notCondition) {
            element.readNextStartElement();
        }
        while (element.readNextStartElement()) {
            const QStringRef tagName = element.name();
            if (tagName == QLatin1String("testlist")) {
                while (element.readNextStartElement()) {
                    const QStringRef testTagName = element.name();
                    if (testTagName == QLatin1String("test")) {
Laurent Montel's avatar
Laurent Montel committed
362
363
                        if (element.attributes().hasAttribute(QLatin1String("name"))) {
                            QString conditionName = element.attributes().value(QLatin1String("name")).toString();
Laurent Montel's avatar
Porting    
Laurent Montel committed
364
365
366
367
368
                            if (firstCondition) {
                                firstCondition = false;
                            } else {
                                addWidgetAfterThisWidget(widgets().constLast());
                            }
369
                            auto w = qobject_cast<SieveConditionWidget *>(widgets().constLast());
Laurent Montel's avatar
Porting    
Laurent Montel committed
370
371
                            if (conditionName == QLatin1String("not")) {
                                notCondition = true;
Laurent Montel's avatar
Laurent Montel committed
372
                                element.readNextStartElement();
Laurent Montel's avatar
Laurent Montel committed
373
374
                                if (element.attributes().hasAttribute(QLatin1String("name"))) {
                                    conditionName = element.attributes().value(QLatin1String("name")).toString();
Laurent Montel's avatar
Porting    
Laurent Montel committed
375
                                }
Laurent Montel's avatar
Laurent Montel committed
376
377
                                w->setCondition(conditionName, element, notCondition, error);
                                element.skipCurrentElement();
Laurent Montel's avatar
Porting    
Laurent Montel committed
378
379
380
381
382
383
                            } else {
                                notCondition = false;
                                w->setCondition(conditionName, element, notCondition, error);
                            }
                        }
                    } else if (testTagName == QLatin1String("crlf")) {
Laurent Montel's avatar
Laurent Montel committed
384
                        element.skipCurrentElement();
Laurent Montel's avatar
Laurent Montel committed
385
                        // nothing
Laurent Montel's avatar
Porting    
Laurent Montel committed
386
387
                    } else if (testTagName == QLatin1String("comment")) {
                        qDebug() << "Need to implement comment here ";
Laurent Montel's avatar
Laurent Montel committed
388
                        element.skipCurrentElement();
Laurent Montel's avatar
Laurent Montel committed
389
390
                        // nothing
                        // implement in the future ?
Laurent Montel's avatar
Porting    
Laurent Montel committed
391
392
393
394
395
396
397
                    } else {
                        qCDebug(LIBKSIEVE_LOG) << " SieveConditionWidgetLister::loadScript unknown condition tag: " << testTagName;
                    }
                }
            }
        }
    }
398
}