Pimcommon

blacklistbalooemailcompletionwidget.cpp
1/*
2 SPDX-FileCopyrightText: 2015-2024 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5
6*/
7
8#include "blacklistbalooemailcompletionwidget.h"
9#include "blacklistbalooemaillist.h"
10#include "blacklistbalooemailsearchjob.h"
11#include "blacklistbalooemailutil.h"
12#include "blacklistbalooemailwarning.h"
13#include <KLineEditEventHandler>
14
15#include "pimcommonakonadi_debug.h"
16#include <KConfigGroup>
17#include <KListWidgetSearchLine>
18#include <KLocalizedString>
19#include <KSharedConfig>
20#include <QHBoxLayout>
21#include <QLabel>
22#include <QLineEdit>
23#include <QMenu>
24#include <QPushButton>
25#include <QVBoxLayout>
26
27using namespace PimCommon;
28BlackListBalooEmailCompletionWidget::BlackListBalooEmailCompletionWidget(QWidget *parent)
29 : QWidget(parent)
30 , mNumberOfEmailsFound(new QLabel(this))
31 , mSearchLineEdit(new QLineEdit(this))
32 , mExcludeDomainLineEdit(new QLineEdit(this))
33 , mEmailList(new BlackListBalooEmailList(this))
34 , mSearchButton(new QPushButton(QIcon::fromTheme(QStringLiteral("edit-find")), i18n("Search"), this))
35 , mSelectButton(new QPushButton(i18n("&Select"), this))
36 , mUnselectButton(new QPushButton(i18n("&Unselect"), this))
37 , mShowAllBlackListedEmails(new QPushButton(i18n("Show Blacklisted Emails"), this))
38 , mMoreResult(new QLabel(i18n("<qt><a href=\"more_result\">More result...</a></qt>"), this))
39 , mBlackListWarning(new BlackListBalooEmailWarning(this))
40 , mExcludeEmailFromRegularExpressionLineEdit(new QLineEdit(this))
41{
42 auto mainLayout = new QVBoxLayout(this);
43
44 auto searchLayout = new QHBoxLayout;
45 mainLayout->addLayout(searchLayout);
46
47 auto lab = new QLabel(i18n("Search email:"), this);
48 lab->setObjectName(QLatin1StringView("search_label"));
49 searchLayout->addWidget(lab);
50
51 mSearchLineEdit->setPlaceholderText(i18n("Research is done from 3 characters"));
52 mSearchLineEdit->setFocus();
53 mSearchLineEdit->setClearButtonEnabled(true);
55 mSearchLineEdit->setObjectName(QLatin1StringView("search_lineedit"));
56 connect(mSearchLineEdit, &QLineEdit::returnPressed, this, &BlackListBalooEmailCompletionWidget::slotCheckIfUpdateBlackListIsNeeded);
57 searchLayout->addWidget(mSearchLineEdit);
58
59 mSearchButton->setObjectName(QLatin1StringView("search_button"));
60 connect(mSearchButton, &QAbstractButton::clicked, this, &BlackListBalooEmailCompletionWidget::slotCheckIfUpdateBlackListIsNeeded);
61 mSearchButton->setEnabled(false);
62 searchLayout->addWidget(mSearchButton);
63
64 mShowAllBlackListedEmails->setObjectName(QLatin1StringView("show_blacklisted_email_button"));
65 connect(mShowAllBlackListedEmails, &QAbstractButton::clicked, this, &BlackListBalooEmailCompletionWidget::slotShowAllBlacklistedEmail);
66 searchLayout->addWidget(mShowAllBlackListedEmails);
67
68 mEmailList->setObjectName(QLatin1StringView("email_list"));
69 mainLayout->addWidget(mEmailList);
70
71 mBlackListWarning->setObjectName(QLatin1StringView("backlistwarning"));
72 connect(mBlackListWarning, &BlackListBalooEmailWarning::newSearch, this, &BlackListBalooEmailCompletionWidget::slotSearch);
73 connect(mBlackListWarning, &BlackListBalooEmailWarning::saveChanges, this, &BlackListBalooEmailCompletionWidget::slotSaveChanges);
74 mainLayout->addWidget(mBlackListWarning);
75
76 auto searchLineLayout = new QHBoxLayout;
77 mainLayout->addLayout(searchLineLayout);
78
79 auto selectElementLayout = new QHBoxLayout;
80 searchLineLayout->addLayout(selectElementLayout);
81
82 mSelectButton->setObjectName(QLatin1StringView("select_email"));
83 connect(mSelectButton, &QAbstractButton::clicked, this, &BlackListBalooEmailCompletionWidget::slotSelectEmails);
84 selectElementLayout->addWidget(mSelectButton);
85
86 mUnselectButton->setObjectName(QLatin1StringView("unselect_email"));
87 connect(mUnselectButton, &QAbstractButton::clicked, this, &BlackListBalooEmailCompletionWidget::slotUnselectEmails);
88 selectElementLayout->addWidget(mUnselectButton);
89
90 mMoreResult->setObjectName(QLatin1StringView("moreresultlabel"));
91 selectElementLayout->addWidget(mMoreResult);
92
93 mMoreResult->setContextMenuPolicy(Qt::NoContextMenu);
94 connect(mMoreResult, &QLabel::linkActivated, this, &BlackListBalooEmailCompletionWidget::slotLinkClicked);
95 mMoreResult->setVisible(false);
96 selectElementLayout->addStretch(1);
97
98 connect(mSearchLineEdit, &QLineEdit::textChanged, this, &BlackListBalooEmailCompletionWidget::slotSearchLineEditChanged);
99
100 mSearchInResultLineEdit = new KListWidgetSearchLine(this, mEmailList);
101 mSearchInResultLineEdit->setObjectName(QLatin1StringView("searchinresultlineedit"));
102 mSearchInResultLineEdit->setClearButtonEnabled(true);
103 mSearchInResultLineEdit->setPlaceholderText(i18n("Search in result..."));
104 KLineEditEventHandler::catchReturnKey(mSearchInResultLineEdit);
105
106 searchLineLayout->addStretch(0);
107 mNumberOfEmailsFound->setObjectName(QLatin1StringView("numberofemailsfound"));
108
109 searchLineLayout->addWidget(mNumberOfEmailsFound, 1);
110 searchLineLayout->addWidget(mSearchInResultLineEdit);
111
112 auto excludeDomainLayout = new QHBoxLayout;
113 excludeDomainLayout->setContentsMargins({});
114 mainLayout->addLayout(excludeDomainLayout);
115
116 auto excludeDomainLabel = new QLabel(i18n("Exclude domain names:"), this);
117 excludeDomainLabel->setObjectName(QLatin1StringView("domain_label"));
118 excludeDomainLayout->addWidget(excludeDomainLabel);
119
120 excludeDomainLayout->addWidget(mExcludeDomainLineEdit);
121 mExcludeDomainLineEdit->setObjectName(QLatin1StringView("domain_lineedit"));
122 mExcludeDomainLineEdit->setClearButtonEnabled(true);
123 KLineEditEventHandler::catchReturnKey(mExcludeDomainLineEdit);
124 mExcludeDomainLineEdit->setPlaceholderText(i18n("Separate domain with \'%1\'", QLatin1Char(',')));
125
126 auto excludeEmailRegularExpressionLayout = new QHBoxLayout;
127 excludeEmailRegularExpressionLayout->setContentsMargins({});
128 mainLayout->addLayout(excludeEmailRegularExpressionLayout);
129
130 auto excludeEmailRegularExpressionLabel = new QLabel(i18n("Exclude email with Regular Expression:"), this);
131 excludeEmailRegularExpressionLabel->setObjectName(QLatin1StringView("email_regularexpression_label"));
132 excludeEmailRegularExpressionLayout->addWidget(excludeEmailRegularExpressionLabel);
133
134 excludeEmailRegularExpressionLayout->addWidget(mExcludeEmailFromRegularExpressionLineEdit);
135 mExcludeEmailFromRegularExpressionLineEdit->setObjectName(QLatin1StringView("exclude_email_lineedit"));
136 mExcludeEmailFromRegularExpressionLineEdit->setClearButtonEnabled(true);
137 KLineEditEventHandler::catchReturnKey(mExcludeEmailFromRegularExpressionLineEdit);
138 mExcludeEmailFromRegularExpressionLineEdit->setPlaceholderText(i18n("Separate regular expression with \'%1\'", QLatin1Char(',')));
139
140 connect(mEmailList, &QListWidget::itemSelectionChanged, this, &BlackListBalooEmailCompletionWidget::slotSelectionChanged);
141 slotSelectionChanged();
142 connect(mEmailList, &QListWidget::customContextMenuRequested, this, &BlackListBalooEmailCompletionWidget::slotCustomContextMenuRequested);
143}
144
145BlackListBalooEmailCompletionWidget::~BlackListBalooEmailCompletionWidget() = default;
146
147void BlackListBalooEmailCompletionWidget::slotSelectionChanged()
148{
149 const bool selectionIsNotEmpty = !mEmailList->selectedItems().isEmpty();
150 mSelectButton->setEnabled(selectionIsNotEmpty);
151 mUnselectButton->setEnabled(selectionIsNotEmpty);
152}
153
154void BlackListBalooEmailCompletionWidget::slotCustomContextMenuRequested(const QPoint &pos)
155{
156 const bool selectionIsNotEmpty = !mEmailList->selectedItems().isEmpty();
157 if (selectionIsNotEmpty) {
158 QMenu menu(this);
159 menu.addAction(i18n("Select"), this, &BlackListBalooEmailCompletionWidget::slotSelectEmails);
160 menu.addSeparator();
161 menu.addAction(i18n("Unselect"), this, &BlackListBalooEmailCompletionWidget::slotUnselectEmails);
162 menu.exec(mapToGlobal(pos));
163 }
164}
165
166void BlackListBalooEmailCompletionWidget::load()
167{
168 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kpimbalooblacklist"));
169 KConfigGroup group(config, QStringLiteral("AddressLineEdit"));
170
171 const QStringList lstExcludeEmailsRegularExpressions = group.readEntry("ExcludeEmailsRegexp", QStringList());
172 mEmailList->setExcludeEmailsRegularExpressions(lstExcludeEmailsRegularExpressions);
173 mExcludeEmailFromRegularExpressionLineEdit->setText(lstExcludeEmailsRegularExpressions.join(QLatin1Char(',')));
174 mOriginalExcludeEmailRegexp = lstExcludeEmailsRegularExpressions;
175
176 const QStringList lstExcludeDomains = group.readEntry("ExcludeDomain", QStringList());
177 mEmailList->setExcludeDomains(lstExcludeDomains);
178 mExcludeDomainLineEdit->setText(lstExcludeDomains.join(QLatin1Char(',')));
179 mOriginalExcludeDomain = lstExcludeDomains;
180 slotSelectionChanged();
181}
182
183void BlackListBalooEmailCompletionWidget::save()
184{
185 const QString excludeEmailsRegexp = mExcludeEmailFromRegularExpressionLineEdit->text().remove(QLatin1Char(' '));
186 const QStringList newExcludeEmailsRegExp = excludeEmailsRegexp.split(QLatin1Char(','), Qt::SkipEmptyParts);
187 bool needToSave = (mOriginalExcludeEmailRegexp != newExcludeEmailsRegExp);
188
189 const QString excludeDomains = mExcludeDomainLineEdit->text().remove(QLatin1Char(' '));
190 const QStringList newExcludeDomain = excludeDomains.split(QLatin1Char(','), Qt::SkipEmptyParts);
191 needToSave |= (mOriginalExcludeDomain != newExcludeDomain);
192
193 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kpimbalooblacklist"));
194 KConfigGroup group(config, QStringLiteral("AddressLineEdit"));
195 const QHash<QString, bool> result = mEmailList->blackListItemChanged();
196 if (!result.isEmpty()) {
197 needToSave = true;
198 QStringList blackList = group.readEntry("BalooBackList", QStringList());
199 PimCommon::BlackListBalooEmailUtil util;
200 util.initialBlackList(blackList);
201 util.setNewBlackList(result);
202 blackList = util.createNewBlackList();
203 group.writeEntry("BalooBackList", blackList);
204 }
205 if (needToSave) {
206 group.writeEntry("ExcludeEmailsRegexp", newExcludeEmailsRegExp);
207 mEmailList->setExcludeEmailsRegularExpressions(newExcludeEmailsRegExp);
208 mOriginalExcludeEmailRegexp = newExcludeEmailsRegExp;
209
210 group.writeEntry("ExcludeDomain", newExcludeDomain);
211 mEmailList->setExcludeDomains(newExcludeDomain);
212 mOriginalExcludeDomain = newExcludeDomain;
213 group.sync();
214 }
215 config->reparseConfiguration();
216}
217
218void BlackListBalooEmailCompletionWidget::slotSaveChanges()
219{
220 // TODO avoid to save a lot.
221 const QHash<QString, bool> result = mEmailList->blackListItemChanged();
222 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kpimbalooblacklist"));
223 KConfigGroup group(config, QStringLiteral("AddressLineEdit"));
224 QStringList blackList = group.readEntry("BalooBackList", QStringList());
225 PimCommon::BlackListBalooEmailUtil util;
226 util.initialBlackList(blackList);
227 util.setNewBlackList(result);
228 blackList = util.createNewBlackList();
229 group.writeEntry("BalooBackList", blackList);
230 group.sync();
231 mEmailList->setEmailBlackList(blackList);
232 slotSearch();
233}
234
235void BlackListBalooEmailCompletionWidget::slotUnselectEmails()
236{
237 const QList<QListWidgetItem *> lstSelected = mEmailList->selectedItems();
238 for (QListWidgetItem *item : lstSelected) {
239 item->setCheckState(Qt::Unchecked);
240 }
241}
242
243void BlackListBalooEmailCompletionWidget::slotSelectEmails()
244{
245 const QList<QListWidgetItem *> lstSelected = mEmailList->selectedItems();
246 for (QListWidgetItem *item : lstSelected) {
247 item->setCheckState(Qt::Checked);
248 }
249}
250
251void BlackListBalooEmailCompletionWidget::slotSearchLineEditChanged(const QString &text)
252{
253 mSearchButton->setEnabled(text.trimmed().length() > 2);
254 hideMoreResultAndChangeLimit();
255}
256
257void BlackListBalooEmailCompletionWidget::hideMoreResultAndChangeLimit()
258{
259 mMoreResult->setVisible(false);
260 mLimit = 500;
261}
262
263void BlackListBalooEmailCompletionWidget::slotSearch()
264{
265 const QString searchEmail = mSearchLineEdit->text().trimmed();
266 if (searchEmail.length() > 2) {
267 mSearchInResultLineEdit->clear();
268 auto job = new PimCommon::BlackListBalooEmailSearchJob(this);
269 job->setSearchEmail(searchEmail);
270 job->setLimit(mLimit);
271 connect(job, &BlackListBalooEmailSearchJob::emailsFound, this, &BlackListBalooEmailCompletionWidget::slotEmailFound);
272 if (!job->start()) {
273 qCWarning(PIMCOMMONAKONADI_LOG) << "Impossible to start search job";
274 }
275 }
276}
277
278void BlackListBalooEmailCompletionWidget::slotEmailFound(const QStringList &list)
279{
280 const int numberOfEmails = mEmailList->setEmailFound(list);
281 mMoreResult->setVisible(numberOfEmails == mLimit);
282 mEmailList->scrollToBottom();
283 if (numberOfEmails == 0) {
284 mNumberOfEmailsFound->setText(i18n("No email found."));
285 } else {
286 mNumberOfEmailsFound->setText(i18np("1 email found", "%1 emails found", numberOfEmails));
287 }
288}
289
290void BlackListBalooEmailCompletionWidget::setEmailBlackList(const QStringList &list)
291{
292 mEmailList->setEmailBlackList(list);
293}
294
295void BlackListBalooEmailCompletionWidget::slotCheckIfUpdateBlackListIsNeeded()
296{
297 const QHash<QString, bool> result = mEmailList->blackListItemChanged();
298 if (result.isEmpty()) {
299 slotSearch();
300 } else {
301 mBlackListWarning->animatedShow();
302 }
303}
304
305void BlackListBalooEmailCompletionWidget::slotLinkClicked(const QString &link)
306{
307 if (link == QLatin1StringView("more_result")) {
308 mLimit += 200;
309 slotSearch();
310 }
311}
312
313void BlackListBalooEmailCompletionWidget::slotShowAllBlacklistedEmail()
314{
315 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kpimbalooblacklist"));
316 KConfigGroup group(config, QStringLiteral("AddressLineEdit"));
317 const QStringList balooBlackList = group.readEntry("BalooBackList", QStringList());
318 slotEmailFound(balooBlackList);
319}
320
321#include "moc_blacklistbalooemailcompletionwidget.cpp"
void animatedShow()
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void catchReturnKey(QObject *lineEdit)
folderdialogacltab.h
void clicked(bool checked)
void addLayout(QLayout *layout, int stretch)
bool isEmpty() const const
void linkActivated(const QString &link)
void setText(const QString &)
void setContentsMargins(const QMargins &margins)
void returnPressed()
void setText(const QString &)
void textChanged(const QString &text)
void itemSelectionChanged()
QList< QListWidgetItem * > selectedItems() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
qsizetype length() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString trimmed() const const
QString join(QChar separator) const const
Unchecked
NoContextMenu
SkipEmptyParts
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void customContextMenuRequested(const QPoint &pos)
void setEnabled(bool)
QPoint mapToGlobal(const QPoint &pos) const const
virtual void setVisible(bool visible)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:17:23 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.