1 /*
2    SPDX-FileCopyrightText: 2019-2021 Laurent Montel <montel@kde.org>
3 
4    SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "dkimmanageruleswidget.h"
8 #include "dkimmanagerulescombobox.h"
9 #include "dkimruledialog.h"
10 #include "messageviewer_dkimcheckerdebug.h"
11 #include <KLocalizedString>
12 #include <KMessageBox>
13 #include <KTreeWidgetSearchLine>
14 #include <MessageViewer/DKIMManagerRules>
15 #include <QHeaderView>
16 #include <QMenu>
17 #include <QPointer>
18 #include <QTreeWidget>
19 #include <QVBoxLayout>
20 using namespace MessageViewer;
DKIMManageRulesWidgetItem(QTreeWidget * parent)21 DKIMManageRulesWidgetItem::DKIMManageRulesWidgetItem(QTreeWidget *parent)
22     : QTreeWidgetItem(parent)
23     , mRuleTypeCombobox(new DKIMManageRulesComboBox)
24 {
25     treeWidget()->setItemWidget(this, ColumnType::RuleType, mRuleTypeCombobox);
26 }
27 
~DKIMManageRulesWidgetItem()28 DKIMManageRulesWidgetItem::~DKIMManageRulesWidgetItem()
29 {
30 }
31 
rule() const32 MessageViewer::DKIMRule DKIMManageRulesWidgetItem::rule() const
33 {
34     MessageViewer::DKIMRule rule;
35     rule.setEnabled(checkState(ColumnType::Enabled) == Qt::Checked);
36     rule.setDomain(text(ColumnType::Domain));
37     rule.setFrom(text(ColumnType::From));
38     rule.setListId(text(ColumnType::ListId));
39     rule.setPriority(text(ColumnType::Priority).toInt());
40     rule.setRuleType(mRuleTypeCombobox->ruleType());
41     rule.setSignedDomainIdentifier(text(ColumnType::SDid).split(QLatin1Char(' ')));
42     return rule;
43 }
44 
setRule(const MessageViewer::DKIMRule & rule)45 void DKIMManageRulesWidgetItem::setRule(const MessageViewer::DKIMRule &rule)
46 {
47     if (mRule != rule) {
48         mRule = rule;
49         updateInfo();
50     }
51 }
52 
updateInfo()53 void DKIMManageRulesWidgetItem::updateInfo()
54 {
55     setCheckState(ColumnType::Enabled, mRule.enabled() ? Qt::Checked : Qt::Unchecked);
56     setText(ColumnType::Domain, mRule.domain());
57     setText(ColumnType::ListId, mRule.listId());
58     setText(ColumnType::From, mRule.from());
59     setText(ColumnType::SDid, mRule.signedDomainIdentifier().join(QLatin1Char(' ')));
60     setText(ColumnType::Priority, QString::number(mRule.priority()));
61     mRuleTypeCombobox->setRuleType(mRule.ruleType());
62 }
63 
DKIMManageRulesWidget(QWidget * parent)64 DKIMManageRulesWidget::DKIMManageRulesWidget(QWidget *parent)
65     : QWidget(parent)
66     , mTreeWidget(new QTreeWidget(this))
67 {
68     auto mainLayout = new QVBoxLayout(this);
69     mainLayout->setObjectName(QStringLiteral("mainLayout"));
70     mainLayout->setContentsMargins({});
71 
72     mTreeWidget->setObjectName(QStringLiteral("treewidget"));
73     mTreeWidget->setRootIsDecorated(false);
74     mTreeWidget->setHeaderLabels({i18n("Active"), i18n("Domain"), i18n("List-ID"), i18n("From"), i18n("SDID"), i18n("Rule type"), i18n("Priority")});
75     mTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
76     mTreeWidget->setAlternatingRowColors(true);
77 
78     auto searchLineEdit = new KTreeWidgetSearchLine(this, mTreeWidget);
79     searchLineEdit->setObjectName(QStringLiteral("searchlineedit"));
80     searchLineEdit->setClearButtonEnabled(true);
81     mainLayout->addWidget(searchLineEdit);
82 
83     mainLayout->addWidget(mTreeWidget);
84     connect(mTreeWidget, &QTreeWidget::customContextMenuRequested, this, &DKIMManageRulesWidget::slotCustomContextMenuRequested);
85     connect(mTreeWidget, &QTreeWidget::itemDoubleClicked, this, [this](QTreeWidgetItem *item) {
86         if (item) {
87             auto rulesItem = static_cast<DKIMManageRulesWidgetItem *>(item);
88             modifyRule(rulesItem);
89         }
90     });
91 }
92 
~DKIMManageRulesWidget()93 DKIMManageRulesWidget::~DKIMManageRulesWidget()
94 {
95 }
96 
loadSettings()97 void DKIMManageRulesWidget::loadSettings()
98 {
99     const QVector<MessageViewer::DKIMRule> rules = MessageViewer::DKIMManagerRules::self()->rules();
100 
101     for (const MessageViewer::DKIMRule &rule : rules) {
102         auto item = new DKIMManageRulesWidgetItem(mTreeWidget);
103         item->setRule(rule);
104     }
105     mTreeWidget->setSortingEnabled(true);
106     mTreeWidget->header()->setSortIndicatorShown(true);
107     mTreeWidget->header()->setSectionsClickable(true);
108     mTreeWidget->sortByColumn(0, Qt::AscendingOrder);
109 }
110 
rules() const111 QVector<MessageViewer::DKIMRule> DKIMManageRulesWidget::rules() const
112 {
113     QVector<MessageViewer::DKIMRule> rules;
114     const int total = mTreeWidget->topLevelItemCount();
115     rules.reserve(total);
116     for (int i = 0; i < total; ++i) {
117         QTreeWidgetItem *item = mTreeWidget->topLevelItem(i);
118         auto ruleItem = static_cast<DKIMManageRulesWidgetItem *>(item);
119         rules.append(ruleItem->rule());
120     }
121     return rules;
122 }
123 
saveSettings()124 void DKIMManageRulesWidget::saveSettings()
125 {
126     MessageViewer::DKIMManagerRules::self()->saveRules(rules());
127 }
128 
saveHeaders() const129 QByteArray DKIMManageRulesWidget::saveHeaders() const
130 {
131     return mTreeWidget->header()->saveState();
132 }
133 
restoreHeaders(const QByteArray & header)134 void DKIMManageRulesWidget::restoreHeaders(const QByteArray &header)
135 {
136     mTreeWidget->header()->restoreState(header);
137 }
138 
addRule()139 void DKIMManageRulesWidget::addRule()
140 {
141     QPointer<DKIMRuleDialog> dlg = new DKIMRuleDialog(this);
142     if (dlg->exec()) {
143         const MessageViewer::DKIMRule rule = dlg->rule();
144         if (rule.isValid()) {
145             auto item = new DKIMManageRulesWidgetItem(mTreeWidget);
146             item->setRule(rule);
147         } else {
148             qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Rule is not valid";
149         }
150     }
151     delete dlg;
152 }
153 
duplicateRule(DKIMManageRulesWidgetItem * rulesItem)154 void DKIMManageRulesWidget::duplicateRule(DKIMManageRulesWidgetItem *rulesItem)
155 {
156     QPointer<DKIMRuleDialog> dlg = new DKIMRuleDialog(this);
157     dlg->loadRule(rulesItem->rule());
158     if (dlg->exec()) {
159         const MessageViewer::DKIMRule rule = dlg->rule();
160         if (rule.isValid()) {
161             auto item = new DKIMManageRulesWidgetItem(mTreeWidget);
162             item->setRule(rule);
163         }
164     }
165     delete dlg;
166 }
167 
modifyRule(DKIMManageRulesWidgetItem * rulesItem)168 void DKIMManageRulesWidget::modifyRule(DKIMManageRulesWidgetItem *rulesItem)
169 {
170     QPointer<DKIMRuleDialog> dlg = new DKIMRuleDialog(this);
171     dlg->loadRule(rulesItem->rule());
172     if (dlg->exec()) {
173         const MessageViewer::DKIMRule rule = dlg->rule();
174         if (rule.isValid()) {
175             rulesItem->setRule(rule);
176         }
177     }
178     delete dlg;
179 }
180 
slotCustomContextMenuRequested(const QPoint & pos)181 void DKIMManageRulesWidget::slotCustomContextMenuRequested(const QPoint &pos)
182 {
183     QTreeWidgetItem *item = mTreeWidget->itemAt(pos);
184     QMenu menu(this);
185     menu.addAction(QIcon::fromTheme(QStringLiteral("list-add")), i18n("Add..."), this, [this]() {
186         addRule();
187     });
188     auto rulesItem = dynamic_cast<DKIMManageRulesWidgetItem *>(item);
189     if (rulesItem) {
190         menu.addAction(QIcon::fromTheme(QStringLiteral("document-edit")), i18n("Modify..."), this, [this, rulesItem]() {
191             modifyRule(rulesItem);
192         });
193         menu.addSeparator();
194         menu.addAction(QIcon::fromTheme(QStringLiteral("edit-duplicate")), i18n("Duplicate Rule"), this, [this, rulesItem]() {
195             duplicateRule(rulesItem);
196         });
197         menu.addSeparator();
198         menu.addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Remove Rule"), this, [this, item]() {
199             const int answer = KMessageBox::warningYesNo(this,
200                                                          i18n("Do you want to delete this rule?"),
201                                                          i18n("Delete Rule"),
202                                                          KStandardGuiItem::del(),
203                                                          KStandardGuiItem::cancel());
204             if (answer == KMessageBox::Yes) {
205                 delete item;
206             }
207         });
208     }
209     if (mTreeWidget->topLevelItemCount() > 0) {
210         menu.addSeparator();
211         menu.addAction(i18n("Delete All"), this, [this]() {
212             const int answer = KMessageBox::warningYesNo(this,
213                                                          i18n("Do you want to delete all the rules?"),
214                                                          i18n("Delete Rules"),
215                                                          KStandardGuiItem::del(),
216                                                          KStandardGuiItem::cancel());
217             if (answer == KMessageBox::Yes) {
218                 mTreeWidget->clear();
219             }
220         });
221     }
222     menu.exec(QCursor::pos());
223 }
224