Akonadi Contacts

addemailaddressjob.cpp
1 /*
2  SPDX-FileCopyrightText: 2010 Tobias Koenig <[email protected]>
3  SPDX-FileCopyrightText: 2010 Nicolas Lécureuil <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #include "addemailaddressjob.h"
9 #include "selectaddressbookdialog.h"
10 #include <Akonadi/AgentFilterProxyModel>
11 #include <Akonadi/AgentInstanceCreateJob>
12 #include <Akonadi/AgentType>
13 #include <Akonadi/AgentTypeDialog>
14 #include <Akonadi/Collection>
15 #include <Akonadi/CollectionDialog>
16 #include <Akonadi/CollectionFetchJob>
17 #include <Akonadi/CollectionFetchScope>
18 #include <Akonadi/ContactEditorDialog>
19 #include <Akonadi/ContactSearchJob>
20 #include <Akonadi/Item>
21 #include <Akonadi/ItemCreateJob>
22 #include <KContacts/ContactGroup>
23 
24 #include <KLocalizedString>
25 #include <KMessageBox>
26 
27 #include <QPointer>
28 
29 using namespace Akonadi;
30 
31 class Akonadi::AddEmailAddressJobPrivate
32 {
33 public:
34  AddEmailAddressJobPrivate(AddEmailAddressJob *qq, const QString &emailString, QWidget *parentWidget)
35  : q(qq)
36  , mCompleteAddress(emailString)
37  , mParentWidget(parentWidget)
38  , mInteractive(true)
39  {
40  KContacts::Addressee::parseEmailAddress(emailString, mName, mEmail);
41  }
42 
43  void slotResourceCreationDone(KJob *job)
44  {
45  if (job->error()) {
46  q->setError(job->error());
47  q->setErrorText(job->errorText());
48  q->emitResult();
49  return;
50  }
51  createContact();
52  }
53 
54  void slotSearchDone(KJob *job)
55  {
56  if (job->error()) {
57  q->setError(job->error());
58  q->setErrorText(job->errorText());
59  q->emitResult();
60  return;
61  }
62 
63  const Akonadi::ContactSearchJob *searchJob = qobject_cast<Akonadi::ContactSearchJob *>(job);
64 
65  const KContacts::Addressee::List contacts = searchJob->contacts();
66  if (!contacts.isEmpty()) {
67  if (mInteractive) {
68  const QString text = xi18nc("@info",
69  "A contact with the email address <email>%1</email> "
70  "is already in your address book.",
71  mCompleteAddress);
72 
73  KMessageBox::information(mParentWidget, text, QString(), QStringLiteral("alreadyInAddressBook"));
74  }
75  q->setError(KJob::UserDefinedError);
76  q->emitResult();
77  return;
78  }
79  createContact();
80  }
81 
82  void createContact()
83  {
85 
87 
88  addressBookJob->fetchScope().setContentMimeTypes(mimeTypes);
89  q->connect(addressBookJob, &Akonadi::CollectionFetchJob::result, q, [this](KJob *job) {
90  slotCollectionsFetched(job);
91  });
92  }
93 
94  void slotCollectionsFetched(KJob *job)
95  {
96  if (job->error()) {
97  q->setError(job->error());
98  q->setErrorText(job->errorText());
99  q->emitResult();
100  return;
101  }
102 
103  const Akonadi::CollectionFetchJob *addressBookJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
104 
105  Akonadi::Collection::List canCreateItemCollections;
106 
107  const Akonadi::Collection::List lstColls = addressBookJob->collections();
108  for (const Akonadi::Collection &collection : lstColls) {
109  if (Akonadi::Collection::CanCreateItem & collection.rights()) {
110  canCreateItemCollections.append(collection);
111  }
112  }
113 
114  Akonadi::Collection addressBook;
115 
116  const int nbItemCollection(canCreateItemCollections.size());
117  if (nbItemCollection == 0) {
119  mParentWidget,
120  i18nc("@info", "You must create an address book before adding a contact. Do you want to create an address book?"),
121  i18nc("@title:window", "No Address Book Available"),
122  KGuiItem(i18nc("@action:button", "Create Address Book"), QStringLiteral("address-book-new")),
124  == KMessageBox::ButtonCode::PrimaryAction) {
126  dlg->setWindowTitle(i18nc("@title:window", "Add Address Book"));
127  dlg->agentFilterProxyModel()->addMimeTypeFilter(KContacts::Addressee::mimeType());
128  dlg->agentFilterProxyModel()->addMimeTypeFilter(KContacts::ContactGroup::mimeType());
129  dlg->agentFilterProxyModel()->addCapabilityFilter(QStringLiteral("Resource"));
130 
131  if (dlg->exec()) {
132  const Akonadi::AgentType agentType = dlg->agentType();
133 
134  if (agentType.isValid()) {
135  auto job = new Akonadi::AgentInstanceCreateJob(agentType, q);
136  q->connect(job, &Akonadi::AgentInstanceCreateJob::result, q, [this](KJob *job) {
137  slotResourceCreationDone(job);
138  });
139  job->configure(mParentWidget);
140  job->start();
141  delete dlg;
142  return;
143  } else { // if agent is not valid => return error and finish job
144  q->setError(KJob::UserDefinedError);
145  q->emitResult();
146  delete dlg;
147  return;
148  }
149  } else { // Canceled create agent => return error and finish job
150  q->setError(KJob::UserDefinedError);
151  q->emitResult();
152  delete dlg;
153  return;
154  }
155  } else {
156  q->setError(KJob::UserDefinedError);
157  q->emitResult();
158  return;
159  }
160  } else if (nbItemCollection == 1) {
161  addressBook = canCreateItemCollections[0];
162  } else {
163  // ask user in which address book the new contact shall be stored
165 
166  bool gotIt = true;
167  if (dlg->exec()) {
168  addressBook = dlg->selectedCollection();
169  } else {
170  q->setError(KJob::UserDefinedError);
171  q->emitResult();
172  gotIt = false;
173  }
174  delete dlg;
175  if (!gotIt) {
176  return;
177  }
178  }
179 
180  if (!addressBook.isValid()) {
181  q->setError(KJob::UserDefinedError);
182  q->emitResult();
183  return;
184  }
185  KContacts::Addressee contact;
186  contact.setNameFromString(mName);
187  KContacts::Email email(mEmail);
188  email.setPreferred(true);
189  contact.addEmail(email);
190  // create the new item
191  Akonadi::Item item;
193  item.setPayload<KContacts::Addressee>(contact);
194 
195  // save the new item in akonadi storage
196  auto createJob = new Akonadi::ItemCreateJob(item, addressBook, q);
197  q->connect(createJob, &Akonadi::ItemCreateJob::result, q, [this](KJob *job) {
198  slotAddContactDone(job);
199  });
200  }
201 
202  void slotAddContactDone(KJob *job)
203  {
204  if (job->error()) {
205  q->setError(job->error());
206  q->setErrorText(job->errorText());
207  q->emitResult();
208  return;
209  }
210 
211  const Akonadi::ItemCreateJob *createJob = qobject_cast<Akonadi::ItemCreateJob *>(job);
212  mItem = createJob->item();
213 
214  if (mInteractive) {
215  const QString text = xi18nc("@info",
216  "<para>A contact for \"%1\" was successfully added "
217  "to your address book.</para>"
218  "<para>Do you want to edit this new contact now?</para>",
219  mCompleteAddress);
220 
221  if (KMessageBox::questionTwoActions(mParentWidget,
222  text,
223  QString(),
224  KGuiItem(i18nc("@action:button", "Edit"), QStringLiteral("document-edit")),
225  KGuiItem(i18nc("@action:button", "Finish"), QStringLiteral("dialog-ok-apply")),
226  QStringLiteral("addedtokabc"))
227  == KMessageBox::ButtonCode::PrimaryAction) {
229  dlg->setContact(mItem);
231  contactStored(item);
232  });
233  QObject::connect(dlg.data(), &Akonadi::ContactEditorDialog::error, q, [this](const QString &str) {
234  slotContactEditorError(str);
235  });
236  dlg->exec();
237  delete dlg;
238  }
239  }
240  q->emitResult();
241  }
242 
243  void slotContactEditorError(const QString &error)
244  {
245  if (mInteractive) {
246  KMessageBox::error(mParentWidget, i18n("Contact cannot be stored: %1", error), i18n("Failed to store contact"));
247  }
248  }
249 
250  void contactStored(const Akonadi::Item &)
251  {
252  if (mInteractive) {
253  Q_EMIT q->successMessage(i18n("Contact created successfully"));
254  }
255  }
256 
257  AddEmailAddressJob *const q;
258  const QString mCompleteAddress;
259  QString mEmail;
260  QString mName;
261  QWidget *const mParentWidget;
262  Akonadi::Item mItem;
263  bool mInteractive = false;
264 };
265 
266 AddEmailAddressJob::AddEmailAddressJob(const QString &email, QWidget *parentWidget, QObject *parent)
267  : KJob(parent)
268  , d(new AddEmailAddressJobPrivate(this, email, parentWidget))
269 {
270 }
271 
273 
275 {
276  // first check whether a contact with the same email exists already
277  auto searchJob = new Akonadi::ContactSearchJob(this);
278  searchJob->setLimit(1);
280  connect(searchJob, &Akonadi::ContactSearchJob::result, this, [this](KJob *job) {
281  d->slotSearchDone(job);
282  });
283 }
284 
286 {
287  return d->mItem;
288 }
289 
290 void AddEmailAddressJob::setInteractive(bool b)
291 {
292  d->mInteractive = b;
293 }
294 
295 #include "moc_addemailaddressjob.cpp"
void start() override
Starts the job.
bool isValid() const
QString xi18nc(const char *context, const char *text, const TYPE &arg...)
virtual Q_SCRIPTABLE void start()=0
void result(KJob *job)
AddEmailAddressJob(const QString &email, QWidget *parentWidget, QObject *parent=nullptr)
Creates a new add email address job.
void error(const QString &errMsg)
This signal is emitted whenever a contact is not updated or stored.
void setLimit(int limit)
Sets a limit on how many results will be returned by this search job.
void append(const T &value)
void contactStored(const Akonadi::Item &contact)
This signal is emitted whenever a contact was updated or stored.
void setMimeType(const QString &mimeType)
A job to add a new contact with a given email address to Akonadi.
Akonadi::Item contact() const
Returns the item that represents the new contact.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setQuery(Criterion criterion, const QString &value, Match match=ExactMatch)
Sets the criterion and value for the search with match.
KGuiItem cancel()
Collection::List collections() const
static void parseEmailAddress(const QString &rawEmail, QString &fullName, QString &email)
QString i18n(const char *text, const TYPE &arg...)
The SelectAddressBookDialog class This class allows to select addressbook where saving contacts.
@ Email
The email address of the contact.
QString errorText() const
static QString mimeType()
KContacts::Addressee::List contacts() const
Returns the contacts that matched the search criteria.
ButtonCode questionTwoActions(QWidget *parent, const QString &text, const QString &title, const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const QString &dontAskAgainName=QString(), Options options=Notify)
static Collection root()
Job that searches for contacts in the Akonadi storage.
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
A dialog for creating or editing a contact in Akonadi.
@ EditMode
Edits an existing contact.
void setNameFromString(const QString &s)
QStringList mimeTypes(Mode mode=Writing)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void addEmail(const Email &email)
int size() const const
bool isValid() const
~AddEmailAddressJob() override
Destroys the add email address job.
AddresseeList List
void information(QWidget *parent, const QString &text, const QString &title=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
void setPayload(const T &p)
T * data() const const
int error() const
static QString mimeType()
@ ExactMatch
The result must match exactly the pattern (case sensitive).
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sat Apr 1 2023 04:09:04 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.