File indexing completed on 2025-01-05 04:58:20
0001 /* 0002 SPDX-FileCopyrightText: 2015-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 0006 */ 0007 0008 #include "blacklistbalooemailcompletionwidget.h" 0009 #include "blacklistbalooemaillist.h" 0010 #include "blacklistbalooemailsearchjob.h" 0011 #include "blacklistbalooemailutil.h" 0012 #include "blacklistbalooemailwarning.h" 0013 #include <KLineEditEventHandler> 0014 0015 #include "pimcommonakonadi_debug.h" 0016 #include <KConfigGroup> 0017 #include <KListWidgetSearchLine> 0018 #include <KLocalizedString> 0019 #include <KSharedConfig> 0020 #include <QHBoxLayout> 0021 #include <QLabel> 0022 #include <QLineEdit> 0023 #include <QMenu> 0024 #include <QPushButton> 0025 #include <QVBoxLayout> 0026 0027 using namespace PimCommon; 0028 BlackListBalooEmailCompletionWidget::BlackListBalooEmailCompletionWidget(QWidget *parent) 0029 : QWidget(parent) 0030 , mNumberOfEmailsFound(new QLabel(this)) 0031 , mSearchLineEdit(new QLineEdit(this)) 0032 , mExcludeDomainLineEdit(new QLineEdit(this)) 0033 , mEmailList(new BlackListBalooEmailList(this)) 0034 , mSearchButton(new QPushButton(QIcon::fromTheme(QStringLiteral("edit-find")), i18n("Search"), this)) 0035 , mSelectButton(new QPushButton(i18n("&Select"), this)) 0036 , mUnselectButton(new QPushButton(i18n("&Unselect"), this)) 0037 , mShowAllBlackListedEmails(new QPushButton(i18n("Show Blacklisted Emails"), this)) 0038 , mMoreResult(new QLabel(i18n("<qt><a href=\"more_result\">More result...</a></qt>"), this)) 0039 , mBlackListWarning(new BlackListBalooEmailWarning(this)) 0040 , mExcludeEmailFromRegularExpressionLineEdit(new QLineEdit(this)) 0041 { 0042 auto mainLayout = new QVBoxLayout(this); 0043 0044 auto searchLayout = new QHBoxLayout; 0045 mainLayout->addLayout(searchLayout); 0046 0047 auto lab = new QLabel(i18n("Search email:"), this); 0048 lab->setObjectName(QLatin1StringView("search_label")); 0049 searchLayout->addWidget(lab); 0050 0051 mSearchLineEdit->setPlaceholderText(i18n("Research is done from 3 characters")); 0052 mSearchLineEdit->setFocus(); 0053 mSearchLineEdit->setClearButtonEnabled(true); 0054 KLineEditEventHandler::catchReturnKey(mSearchLineEdit); 0055 mSearchLineEdit->setObjectName(QLatin1StringView("search_lineedit")); 0056 connect(mSearchLineEdit, &QLineEdit::returnPressed, this, &BlackListBalooEmailCompletionWidget::slotCheckIfUpdateBlackListIsNeeded); 0057 searchLayout->addWidget(mSearchLineEdit); 0058 0059 mSearchButton->setObjectName(QLatin1StringView("search_button")); 0060 connect(mSearchButton, &QAbstractButton::clicked, this, &BlackListBalooEmailCompletionWidget::slotCheckIfUpdateBlackListIsNeeded); 0061 mSearchButton->setEnabled(false); 0062 searchLayout->addWidget(mSearchButton); 0063 0064 mShowAllBlackListedEmails->setObjectName(QLatin1StringView("show_blacklisted_email_button")); 0065 connect(mShowAllBlackListedEmails, &QAbstractButton::clicked, this, &BlackListBalooEmailCompletionWidget::slotShowAllBlacklistedEmail); 0066 searchLayout->addWidget(mShowAllBlackListedEmails); 0067 0068 mEmailList->setObjectName(QLatin1StringView("email_list")); 0069 mainLayout->addWidget(mEmailList); 0070 0071 mBlackListWarning->setObjectName(QLatin1StringView("backlistwarning")); 0072 connect(mBlackListWarning, &BlackListBalooEmailWarning::newSearch, this, &BlackListBalooEmailCompletionWidget::slotSearch); 0073 connect(mBlackListWarning, &BlackListBalooEmailWarning::saveChanges, this, &BlackListBalooEmailCompletionWidget::slotSaveChanges); 0074 mainLayout->addWidget(mBlackListWarning); 0075 0076 auto searchLineLayout = new QHBoxLayout; 0077 mainLayout->addLayout(searchLineLayout); 0078 0079 auto selectElementLayout = new QHBoxLayout; 0080 searchLineLayout->addLayout(selectElementLayout); 0081 0082 mSelectButton->setObjectName(QLatin1StringView("select_email")); 0083 connect(mSelectButton, &QAbstractButton::clicked, this, &BlackListBalooEmailCompletionWidget::slotSelectEmails); 0084 selectElementLayout->addWidget(mSelectButton); 0085 0086 mUnselectButton->setObjectName(QLatin1StringView("unselect_email")); 0087 connect(mUnselectButton, &QAbstractButton::clicked, this, &BlackListBalooEmailCompletionWidget::slotUnselectEmails); 0088 selectElementLayout->addWidget(mUnselectButton); 0089 0090 mMoreResult->setObjectName(QLatin1StringView("moreresultlabel")); 0091 selectElementLayout->addWidget(mMoreResult); 0092 0093 mMoreResult->setContextMenuPolicy(Qt::NoContextMenu); 0094 connect(mMoreResult, &QLabel::linkActivated, this, &BlackListBalooEmailCompletionWidget::slotLinkClicked); 0095 mMoreResult->setVisible(false); 0096 selectElementLayout->addStretch(1); 0097 0098 connect(mSearchLineEdit, &QLineEdit::textChanged, this, &BlackListBalooEmailCompletionWidget::slotSearchLineEditChanged); 0099 0100 mSearchInResultLineEdit = new KListWidgetSearchLine(this, mEmailList); 0101 mSearchInResultLineEdit->setObjectName(QLatin1StringView("searchinresultlineedit")); 0102 mSearchInResultLineEdit->setClearButtonEnabled(true); 0103 mSearchInResultLineEdit->setPlaceholderText(i18n("Search in result...")); 0104 KLineEditEventHandler::catchReturnKey(mSearchInResultLineEdit); 0105 0106 searchLineLayout->addStretch(0); 0107 mNumberOfEmailsFound->setObjectName(QLatin1StringView("numberofemailsfound")); 0108 0109 searchLineLayout->addWidget(mNumberOfEmailsFound, 1); 0110 searchLineLayout->addWidget(mSearchInResultLineEdit); 0111 0112 auto excludeDomainLayout = new QHBoxLayout; 0113 excludeDomainLayout->setContentsMargins({}); 0114 mainLayout->addLayout(excludeDomainLayout); 0115 0116 auto excludeDomainLabel = new QLabel(i18n("Exclude domain names:"), this); 0117 excludeDomainLabel->setObjectName(QLatin1StringView("domain_label")); 0118 excludeDomainLayout->addWidget(excludeDomainLabel); 0119 0120 excludeDomainLayout->addWidget(mExcludeDomainLineEdit); 0121 mExcludeDomainLineEdit->setObjectName(QLatin1StringView("domain_lineedit")); 0122 mExcludeDomainLineEdit->setClearButtonEnabled(true); 0123 KLineEditEventHandler::catchReturnKey(mExcludeDomainLineEdit); 0124 mExcludeDomainLineEdit->setPlaceholderText(i18n("Separate domain with \'%1\'", QLatin1Char(','))); 0125 0126 auto excludeEmailRegularExpressionLayout = new QHBoxLayout; 0127 excludeEmailRegularExpressionLayout->setContentsMargins({}); 0128 mainLayout->addLayout(excludeEmailRegularExpressionLayout); 0129 0130 auto excludeEmailRegularExpressionLabel = new QLabel(i18n("Exclude email with Regular Expression:"), this); 0131 excludeEmailRegularExpressionLabel->setObjectName(QLatin1StringView("email_regularexpression_label")); 0132 excludeEmailRegularExpressionLayout->addWidget(excludeEmailRegularExpressionLabel); 0133 0134 excludeEmailRegularExpressionLayout->addWidget(mExcludeEmailFromRegularExpressionLineEdit); 0135 mExcludeEmailFromRegularExpressionLineEdit->setObjectName(QLatin1StringView("exclude_email_lineedit")); 0136 mExcludeEmailFromRegularExpressionLineEdit->setClearButtonEnabled(true); 0137 KLineEditEventHandler::catchReturnKey(mExcludeEmailFromRegularExpressionLineEdit); 0138 mExcludeEmailFromRegularExpressionLineEdit->setPlaceholderText(i18n("Separate regular expression with \'%1\'", QLatin1Char(','))); 0139 0140 connect(mEmailList, &QListWidget::itemSelectionChanged, this, &BlackListBalooEmailCompletionWidget::slotSelectionChanged); 0141 slotSelectionChanged(); 0142 connect(mEmailList, &QListWidget::customContextMenuRequested, this, &BlackListBalooEmailCompletionWidget::slotCustomContextMenuRequested); 0143 } 0144 0145 BlackListBalooEmailCompletionWidget::~BlackListBalooEmailCompletionWidget() = default; 0146 0147 void BlackListBalooEmailCompletionWidget::slotSelectionChanged() 0148 { 0149 const bool selectionIsNotEmpty = !mEmailList->selectedItems().isEmpty(); 0150 mSelectButton->setEnabled(selectionIsNotEmpty); 0151 mUnselectButton->setEnabled(selectionIsNotEmpty); 0152 } 0153 0154 void BlackListBalooEmailCompletionWidget::slotCustomContextMenuRequested(const QPoint &pos) 0155 { 0156 const bool selectionIsNotEmpty = !mEmailList->selectedItems().isEmpty(); 0157 if (selectionIsNotEmpty) { 0158 QMenu menu(this); 0159 menu.addAction(i18n("Select"), this, &BlackListBalooEmailCompletionWidget::slotSelectEmails); 0160 menu.addSeparator(); 0161 menu.addAction(i18n("Unselect"), this, &BlackListBalooEmailCompletionWidget::slotUnselectEmails); 0162 menu.exec(mapToGlobal(pos)); 0163 } 0164 } 0165 0166 void BlackListBalooEmailCompletionWidget::load() 0167 { 0168 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kpimbalooblacklist")); 0169 KConfigGroup group(config, QStringLiteral("AddressLineEdit")); 0170 0171 const QStringList lstExcludeEmailsRegularExpressions = group.readEntry("ExcludeEmailsRegexp", QStringList()); 0172 mEmailList->setExcludeEmailsRegularExpressions(lstExcludeEmailsRegularExpressions); 0173 mExcludeEmailFromRegularExpressionLineEdit->setText(lstExcludeEmailsRegularExpressions.join(QLatin1Char(','))); 0174 mOriginalExcludeEmailRegexp = lstExcludeEmailsRegularExpressions; 0175 0176 const QStringList lstExcludeDomains = group.readEntry("ExcludeDomain", QStringList()); 0177 mEmailList->setExcludeDomains(lstExcludeDomains); 0178 mExcludeDomainLineEdit->setText(lstExcludeDomains.join(QLatin1Char(','))); 0179 mOriginalExcludeDomain = lstExcludeDomains; 0180 slotSelectionChanged(); 0181 } 0182 0183 void BlackListBalooEmailCompletionWidget::save() 0184 { 0185 const QString excludeEmailsRegexp = mExcludeEmailFromRegularExpressionLineEdit->text().remove(QLatin1Char(' ')); 0186 const QStringList newExcludeEmailsRegExp = excludeEmailsRegexp.split(QLatin1Char(','), Qt::SkipEmptyParts); 0187 bool needToSave = (mOriginalExcludeEmailRegexp != newExcludeEmailsRegExp); 0188 0189 const QString excludeDomains = mExcludeDomainLineEdit->text().remove(QLatin1Char(' ')); 0190 const QStringList newExcludeDomain = excludeDomains.split(QLatin1Char(','), Qt::SkipEmptyParts); 0191 needToSave |= (mOriginalExcludeDomain != newExcludeDomain); 0192 0193 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kpimbalooblacklist")); 0194 KConfigGroup group(config, QStringLiteral("AddressLineEdit")); 0195 const QHash<QString, bool> result = mEmailList->blackListItemChanged(); 0196 if (!result.isEmpty()) { 0197 needToSave = true; 0198 QStringList blackList = group.readEntry("BalooBackList", QStringList()); 0199 PimCommon::BlackListBalooEmailUtil util; 0200 util.initialBlackList(blackList); 0201 util.setNewBlackList(result); 0202 blackList = util.createNewBlackList(); 0203 group.writeEntry("BalooBackList", blackList); 0204 } 0205 if (needToSave) { 0206 group.writeEntry("ExcludeEmailsRegexp", newExcludeEmailsRegExp); 0207 mEmailList->setExcludeEmailsRegularExpressions(newExcludeEmailsRegExp); 0208 mOriginalExcludeEmailRegexp = newExcludeEmailsRegExp; 0209 0210 group.writeEntry("ExcludeDomain", newExcludeDomain); 0211 mEmailList->setExcludeDomains(newExcludeDomain); 0212 mOriginalExcludeDomain = newExcludeDomain; 0213 group.sync(); 0214 } 0215 config->reparseConfiguration(); 0216 } 0217 0218 void BlackListBalooEmailCompletionWidget::slotSaveChanges() 0219 { 0220 // TODO avoid to save a lot. 0221 const QHash<QString, bool> result = mEmailList->blackListItemChanged(); 0222 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kpimbalooblacklist")); 0223 KConfigGroup group(config, QStringLiteral("AddressLineEdit")); 0224 QStringList blackList = group.readEntry("BalooBackList", QStringList()); 0225 PimCommon::BlackListBalooEmailUtil util; 0226 util.initialBlackList(blackList); 0227 util.setNewBlackList(result); 0228 blackList = util.createNewBlackList(); 0229 group.writeEntry("BalooBackList", blackList); 0230 group.sync(); 0231 mEmailList->setEmailBlackList(blackList); 0232 slotSearch(); 0233 } 0234 0235 void BlackListBalooEmailCompletionWidget::slotUnselectEmails() 0236 { 0237 const QList<QListWidgetItem *> lstSelected = mEmailList->selectedItems(); 0238 for (QListWidgetItem *item : lstSelected) { 0239 item->setCheckState(Qt::Unchecked); 0240 } 0241 } 0242 0243 void BlackListBalooEmailCompletionWidget::slotSelectEmails() 0244 { 0245 const QList<QListWidgetItem *> lstSelected = mEmailList->selectedItems(); 0246 for (QListWidgetItem *item : lstSelected) { 0247 item->setCheckState(Qt::Checked); 0248 } 0249 } 0250 0251 void BlackListBalooEmailCompletionWidget::slotSearchLineEditChanged(const QString &text) 0252 { 0253 mSearchButton->setEnabled(text.trimmed().length() > 2); 0254 hideMoreResultAndChangeLimit(); 0255 } 0256 0257 void BlackListBalooEmailCompletionWidget::hideMoreResultAndChangeLimit() 0258 { 0259 mMoreResult->setVisible(false); 0260 mLimit = 500; 0261 } 0262 0263 void BlackListBalooEmailCompletionWidget::slotSearch() 0264 { 0265 const QString searchEmail = mSearchLineEdit->text().trimmed(); 0266 if (searchEmail.length() > 2) { 0267 mSearchInResultLineEdit->clear(); 0268 auto job = new PimCommon::BlackListBalooEmailSearchJob(this); 0269 job->setSearchEmail(searchEmail); 0270 job->setLimit(mLimit); 0271 connect(job, &BlackListBalooEmailSearchJob::emailsFound, this, &BlackListBalooEmailCompletionWidget::slotEmailFound); 0272 if (!job->start()) { 0273 qCWarning(PIMCOMMONAKONADI_LOG) << "Impossible to start search job"; 0274 } 0275 } 0276 } 0277 0278 void BlackListBalooEmailCompletionWidget::slotEmailFound(const QStringList &list) 0279 { 0280 const int numberOfEmails = mEmailList->setEmailFound(list); 0281 mMoreResult->setVisible(numberOfEmails == mLimit); 0282 mEmailList->scrollToBottom(); 0283 if (numberOfEmails == 0) { 0284 mNumberOfEmailsFound->setText(i18n("No email found.")); 0285 } else { 0286 mNumberOfEmailsFound->setText(i18np("1 email found", "%1 emails found", numberOfEmails)); 0287 } 0288 } 0289 0290 void BlackListBalooEmailCompletionWidget::setEmailBlackList(const QStringList &list) 0291 { 0292 mEmailList->setEmailBlackList(list); 0293 } 0294 0295 void BlackListBalooEmailCompletionWidget::slotCheckIfUpdateBlackListIsNeeded() 0296 { 0297 const QHash<QString, bool> result = mEmailList->blackListItemChanged(); 0298 if (result.isEmpty()) { 0299 slotSearch(); 0300 } else { 0301 mBlackListWarning->animatedShow(); 0302 } 0303 } 0304 0305 void BlackListBalooEmailCompletionWidget::slotLinkClicked(const QString &link) 0306 { 0307 if (link == QLatin1StringView("more_result")) { 0308 mLimit += 200; 0309 slotSearch(); 0310 } 0311 } 0312 0313 void BlackListBalooEmailCompletionWidget::slotShowAllBlacklistedEmail() 0314 { 0315 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("kpimbalooblacklist")); 0316 KConfigGroup group(config, QStringLiteral("AddressLineEdit")); 0317 const QStringList balooBlackList = group.readEntry("BalooBackList", QStringList()); 0318 slotEmailFound(balooBlackList); 0319 } 0320 0321 #include "moc_blacklistbalooemailcompletionwidget.cpp"