Mailcommon

filteractionaddtoaddressbook.cpp
1/*
2 * SPDX-FileCopyrightText: 1996-1998 Stefan Taferner <taferner@kde.org>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 *
6 */
7
8#include "filteractionaddtoaddressbook.h"
9
10#include <Akonadi/AddContactJob>
11
12#include <Akonadi/TagSelectionDialog>
13#include <Akonadi/TagWidget>
14
15#include <Akonadi/CollectionComboBox>
16#include <KComboBox>
17#include <KContacts/Addressee>
18#include <KEmailAddress>
19#include <KLocalizedString>
20
21#include <QGridLayout>
22#include <QLabel>
23
24using namespace MailCommon;
25
26FilterAction *FilterActionAddToAddressBook::newAction()
27{
28 return new FilterActionAddToAddressBook;
29}
30
31FilterActionAddToAddressBook::FilterActionAddToAddressBook(QObject *parent)
32 : FilterActionWithStringList(QStringLiteral("add to address book"), i18n("Add to Address Book"), parent)
33 , mFromStr(i18nc("Email sender", "From"))
34 , mToStr(i18nc("Email recipient", "To"))
35 , mCCStr(i18n("CC"))
36 , mBCCStr(i18n("BCC"))
37 , mHeaderType(UnknownHeader)
38 , mCollectionId(-1)
39 , mCategory(i18n("KMail Filter"))
40{
41}
42
43bool FilterActionAddToAddressBook::isEmpty() const
44{
45 return (mCollectionId == -1) || (mHeaderType == UnknownHeader);
46}
47
48FilterAction::ReturnCode FilterActionAddToAddressBook::process(ItemContext &context, bool) const
49{
50 if (isEmpty()) {
51 return ErrorButGoOn;
52 }
53
54 const auto msg = context.item().payload<KMime::Message::Ptr>();
55
56 QString headerLine;
57 switch (mHeaderType) {
58 case FromHeader:
59 headerLine = msg->from()->asUnicodeString();
60 break;
61 case ToHeader:
62 headerLine = msg->to()->asUnicodeString();
63 break;
64 case CcHeader:
65 headerLine = msg->cc()->asUnicodeString();
66 break;
67 case BccHeader:
68 headerLine = msg->bcc()->asUnicodeString();
69 break;
70 case UnknownHeader:
71 break;
72 }
73 if (headerLine.isEmpty()) {
74 return ErrorButGoOn;
75 }
76
77 const QStringList emails = KEmailAddress::splitAddressList(headerLine);
78
79 for (const QString &singleEmail : emails) {
81 QString emailString;
82 KContacts::Addressee::parseEmailAddress(singleEmail, name, emailString);
83
85 contact.setNameFromString(name);
86 KContacts::Email email(emailString);
87 email.setPreferred(true);
88 contact.addEmail(email);
89 if (!mCategory.isEmpty()) {
90 contact.setCategories(mCategory.split(QLatin1Char(';')));
91 }
92
93 auto job = new Akonadi::AddContactJob(contact, Akonadi::Collection(mCollectionId));
94 job->showMessageBox(false);
95 job->start();
96 }
97
98 return GoOn;
99}
100
101SearchRule::RequiredPart FilterActionAddToAddressBook::requiredPart() const
102{
104}
105
106QWidget *FilterActionAddToAddressBook::createParamWidget(QWidget *parent) const
107{
108 auto widget = new QWidget(parent);
109 auto layout = new QGridLayout(widget);
110
111 const auto headerCombo = new KComboBox(widget);
112 headerCombo->setMinimumWidth(50);
113 headerCombo->setObjectName(QLatin1StringView("HeaderComboBox"));
114 layout->addWidget(headerCombo, 0, 0, 2, 1, Qt::AlignVCenter);
115
116 auto label = new QLabel(i18n("with category"), widget);
117 label->setObjectName(QLatin1StringView("label_with_category"));
118 layout->addWidget(label, 0, 1);
119
120 auto categoryEdit = new Akonadi::TagWidget(widget);
121 categoryEdit->setObjectName(QLatin1StringView("CategoryEdit"));
122 layout->addWidget(categoryEdit, 0, 2);
123
124 label = new QLabel(i18n("in address book"), widget);
125 label->setObjectName(QLatin1StringView("label_in_addressbook"));
126 layout->addWidget(label, 1, 1);
127
128 auto collectionComboBox = new Akonadi::CollectionComboBox(widget);
129 collectionComboBox->setMimeTypeFilter(QStringList() << KContacts::Addressee::mimeType());
130 collectionComboBox->setAccessRightsFilter(Akonadi::Collection::CanCreateItem);
131
132 collectionComboBox->setObjectName(QLatin1StringView("AddressBookComboBox"));
133 collectionComboBox->setToolTip(
134 i18n("This defines the preferred address book.\n"
135 "If it is not accessible, the filter will fallback to the default address book."));
136 layout->addWidget(collectionComboBox, 1, 2);
139 connect(categoryEdit, &Akonadi::TagWidget::selectionChanged, this, &FilterActionAddToAddressBook::filterActionModified);
140
141 setParamWidgetValue(widget);
142
143 return widget;
144}
145
146namespace
147{
148Akonadi::Tag::List namesToTags(const QStringList &names)
149{
150 Akonadi::Tag::List tags;
151 tags.reserve(names.size());
152 std::transform(names.cbegin(), names.cend(), std::back_inserter(tags), [](const QString &name) {
153 return Akonadi::Tag{name};
154 });
155 return tags;
156}
157
158QStringList tagsToNames(const Akonadi::Tag::List &tags)
159{
160 QStringList names;
161 names.reserve(tags.size());
162 std::transform(tags.cbegin(), tags.cend(), std::back_inserter(names), std::bind(&Akonadi::Tag::name, std::placeholders::_1));
163 return names;
164}
165}
166
167void FilterActionAddToAddressBook::setParamWidgetValue(QWidget *paramWidget) const
168{
169 const auto headerCombo = paramWidget->findChild<KComboBox *>(QStringLiteral("HeaderComboBox"));
170 Q_ASSERT(headerCombo);
171 headerCombo->clear();
172 headerCombo->addItem(mFromStr, FromHeader);
173 headerCombo->addItem(mToStr, ToHeader);
174 headerCombo->addItem(mCCStr, CcHeader);
175 headerCombo->addItem(mBCCStr, BccHeader);
176
177 headerCombo->setCurrentIndex(headerCombo->findData(mHeaderType));
178
179 auto categoryEdit = paramWidget->findChild<Akonadi::TagWidget *>(QStringLiteral("CategoryEdit"));
180 Q_ASSERT(categoryEdit);
181 categoryEdit->setSelection(namesToTags(mCategory.split(QLatin1Char(';'))));
182
183 auto collectionComboBox = paramWidget->findChild<Akonadi::CollectionComboBox *>(QStringLiteral("AddressBookComboBox"));
184 Q_ASSERT(collectionComboBox);
185 collectionComboBox->setDefaultCollection(Akonadi::Collection(mCollectionId));
186 collectionComboBox->setProperty("collectionId", mCollectionId);
187}
188
189void FilterActionAddToAddressBook::applyParamWidgetValue(QWidget *paramWidget)
190{
191 const auto headerCombo = paramWidget->findChild<QComboBox *>(QStringLiteral("HeaderComboBox"));
192 Q_ASSERT(headerCombo);
193 mHeaderType = static_cast<HeaderType>(headerCombo->itemData(headerCombo->currentIndex()).toInt());
194
195 const auto categoryEdit = paramWidget->findChild<Akonadi::TagWidget *>(QStringLiteral("CategoryEdit"));
196 Q_ASSERT(categoryEdit);
197 mCategory = tagsToNames(categoryEdit->selection()).join(QLatin1Char(';'));
198
199 const Akonadi::CollectionComboBox *collectionComboBox = paramWidget->findChild<Akonadi::CollectionComboBox *>(QStringLiteral("AddressBookComboBox"));
200 Q_ASSERT(collectionComboBox);
201 const Akonadi::Collection collection = collectionComboBox->currentCollection();
202
203 // it might be that the model of collectionComboBox has not finished loading yet, so
204 // we use the previously 'stored' value from the 'collectionId' property
205 if (collection.isValid()) {
206 mCollectionId = collection.id();
208 } else {
209 const QVariant value = collectionComboBox->property("collectionId");
210 if (value.isValid()) {
211 mCollectionId = value.toLongLong();
212 }
213 }
214}
215
216void FilterActionAddToAddressBook::clearParamWidget(QWidget *paramWidget) const
217{
218 const auto headerCombo = paramWidget->findChild<QComboBox *>(QStringLiteral("HeaderComboBox"));
219 Q_ASSERT(headerCombo);
220 headerCombo->setCurrentIndex(0);
221
222 auto categoryEdit = paramWidget->findChild<Akonadi::TagWidget *>(QStringLiteral("CategoryEdit"));
223 Q_ASSERT(categoryEdit);
224 categoryEdit->setSelection(namesToTags(mCategory.split(QLatin1Char(';'))));
225}
226
227QString FilterActionAddToAddressBook::argsAsString() const
228{
229 QString result;
230
231 switch (mHeaderType) {
232 case FromHeader:
233 result = QStringLiteral("From");
234 break;
235 case ToHeader:
236 result = QStringLiteral("To");
237 break;
238 case CcHeader:
239 result = QStringLiteral("CC");
240 break;
241 case BccHeader:
242 result = QStringLiteral("BCC");
243 break;
244 case UnknownHeader:
245 break;
246 }
247
248 result += QLatin1Char('\t');
249 result += QString::number(mCollectionId);
250 result += QLatin1Char('\t');
251 result += mCategory;
252
253 return result;
254}
255
256void FilterActionAddToAddressBook::argsFromString(const QString &argsStr)
257{
258 const QStringList parts = argsStr.split(QLatin1Char('\t'), Qt::KeepEmptyParts);
259 const QString firstElement = parts[0];
260 if (firstElement == QLatin1StringView("From")) {
261 mHeaderType = FromHeader;
262 } else if (firstElement == QLatin1StringView("To")) {
263 mHeaderType = ToHeader;
264 } else if (firstElement == QLatin1StringView("CC")) {
265 mHeaderType = CcHeader;
266 } else if (firstElement == QLatin1StringView("BCC")) {
267 mHeaderType = BccHeader;
268 } else {
269 mHeaderType = UnknownHeader;
270 }
271 if (parts.count() >= 2) {
272 mCollectionId = parts[1].toLongLong();
273 }
274
275 if (parts.count() < 3) {
276 mCategory.clear();
277 } else {
278 mCategory = parts[2];
279 }
280}
281
282QString FilterActionAddToAddressBook::informationAboutNotValidAction() const
283{
284 QString result;
285 if (mHeaderType == UnknownHeader) {
286 result = i18n("Header type selected is unknown.");
287 }
288 if (mCollectionId == -1) {
289 if (!result.isEmpty()) {
290 result += QLatin1Char('\n');
291 }
292 result += i18n("No addressbook selected.");
293 }
294 return result;
295}
296
297#include "moc_filteractionaddtoaddressbook.cpp"
Akonadi::Collection currentCollection() const
bool isValid() const
T payload() const
void setNameFromString(const QString &s)
void addEmail(const Email &email)
static QString mimeType()
static void parseEmailAddress(const QString &rawEmail, QString &fullName, QString &email)
void setCategories(const QStringList &category)
Abstract base class for filter actions with a fixed set of string parameters.
Abstract base class for mail filter actions.
QString name() const
Returns identifier name, ie.
ReturnCode
Describes the possible return codes of filter processing:
@ ErrorButGoOn
A non-critical error occurred.
@ GoOn
Go on with applying filter actions.
void filterActionModified()
Called to notify that the current FilterAction has had some value modification.
QString label() const
Returns i18n'd label, ie.
A helper class for the filtering process.
Definition itemcontext.h:27
Akonadi::Item & item()
Returns the item of the context.
RequiredPart
Possible required parts.
Definition searchrule.h:68
KCODECS_EXPORT QStringList splitAddressList(const QString &aStr)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
The filter dialog.
void activated(int index)
void currentIndexChanged(int index)
const_iterator cbegin() const const
const_iterator cend() const const
qsizetype count() const const
void reserve(qsizetype size)
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T findChild(const QString &name, Qt::FindChildOptions options) const const
QObject * parent() const const
QVariant property(const char *name) const const
void clear()
bool isEmpty() const const
QString number(double n, char format, int precision)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
AlignVCenter
KeepEmptyParts
bool isValid() const const
qlonglong toLongLong(bool *ok) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:00 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.