Akonadi Contacts

contacteditor.cpp
1 /*
2  This file is part of Akonadi Contact.
3 
4  SPDX-FileCopyrightText: 2009 Tobias Koenig <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "contacteditor.h"
10 
11 #include "abstractcontacteditorwidget_p.h"
12 #include "attributes/contactmetadataattribute_p.h"
13 #include "contactmetadataakonadi_p.h"
14 #include "editor/contacteditorwidget.h"
15 
16 #include <KLocalizedString>
17 #include <collectiondialog.h>
18 #include <collectionfetchjob.h>
19 #include <itemcreatejob.h>
20 #include <itemfetchjob.h>
21 #include <itemfetchscope.h>
22 #include <itemmodifyjob.h>
23 #include <kcontacts/addressee.h>
24 #include <monitor.h>
25 #include <session.h>
26 
27 #include <QMessageBox>
28 #include <QPointer>
29 #include <QVBoxLayout>
30 
31 using namespace Akonadi;
32 
33 class Q_DECL_HIDDEN Akonadi::AkonadiContactEditor::Private
34 {
35 public:
36  Private(AkonadiContactEditor::Mode mode,
38  ContactEditor::AbstractContactEditorWidget *editorWidget,
39  AkonadiContactEditor *parent)
40  : mParent(parent)
41  , mMode(mode)
42  {
43  if (editorWidget) {
44  mEditorWidget = editorWidget;
45  } else {
46  mEditorWidget = new ContactEditorWidget(displayMode == FullMode ? ContactEditorWidget::FullMode : ContactEditorWidget::VCardMode, mParent);
47  }
48 
49  auto layout = new QVBoxLayout(mParent);
50  layout->setContentsMargins(0, 0, 0, 0);
51  layout->setSpacing(0);
52  layout->addWidget(mEditorWidget);
53  }
54 
55  ~Private()
56  {
57  delete mMonitor;
58  }
59 
60  void itemFetchDone(KJob *job);
61  void parentCollectionFetchDone(KJob *job);
62  void storeDone(KJob *job);
63  void itemChanged(const Akonadi::Item &item, const QSet<QByteArray> &);
64 
65  void loadContact(const KContacts::Addressee &addr, const ContactMetaDataAkonadi &metaData);
66  void storeContact(KContacts::Addressee &addr, ContactMetaDataAkonadi &metaData);
67  void setupMonitor();
68 
69  AkonadiContactEditor *mParent = nullptr;
71  Akonadi::Item mItem;
72  Akonadi::ContactMetaDataAkonadi mContactMetaData;
73  Akonadi::Monitor *mMonitor = nullptr;
74  Akonadi::Collection mDefaultCollection;
75  ContactEditor::AbstractContactEditorWidget *mEditorWidget = nullptr;
76  bool mReadOnly = false;
77 };
78 
79 void Akonadi::AkonadiContactEditor::Private::itemFetchDone(KJob *job)
80 {
81  if (job->error() != KJob::NoError) {
82  Q_EMIT mParent->error(job->errorString());
83  Q_EMIT mParent->finished();
84  return;
85  }
86 
87  auto fetchJob = qobject_cast<Akonadi::ItemFetchJob *>(job);
88  if (!fetchJob) {
89  return;
90  }
91 
92  if (fetchJob->items().isEmpty()) {
93  return;
94  }
95 
96  mItem = fetchJob->items().at(0);
97 
98  mReadOnly = false;
99  if (mMode == AkonadiContactEditor::EditMode) {
100  // if in edit mode we have to fetch the parent collection to find out
101  // about the modify rights of the item
102 
103  auto collectionFetchJob = new Akonadi::CollectionFetchJob(mItem.parentCollection(), Akonadi::CollectionFetchJob::Base);
104  mParent->connect(collectionFetchJob, &CollectionFetchJob::result, mParent, [this](KJob *job) {
105  parentCollectionFetchDone(job);
106  });
107  } else {
108  const auto addr = mItem.payload<KContacts::Addressee>();
109  mContactMetaData.load(mItem);
110  loadContact(addr, mContactMetaData);
111  mEditorWidget->setReadOnly(mReadOnly);
112  }
113 }
114 
115 void Akonadi::AkonadiContactEditor::Private::parentCollectionFetchDone(KJob *job)
116 {
117  if (job->error()) {
118  Q_EMIT mParent->error(job->errorString());
119  Q_EMIT mParent->finished();
120  return;
121  }
122 
123  auto fetchJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
124  if (!fetchJob) {
125  return;
126  }
127 
128  const Akonadi::Collection parentCollection = fetchJob->collections().at(0);
129  if (parentCollection.isValid()) {
130  mReadOnly = !(parentCollection.rights() & Collection::CanChangeItem);
131  }
132 
133  const auto addr = mItem.payload<KContacts::Addressee>();
134  mContactMetaData.load(mItem);
135  loadContact(addr, mContactMetaData);
136  mEditorWidget->setReadOnly(mReadOnly);
137 }
138 
139 void Akonadi::AkonadiContactEditor::Private::storeDone(KJob *job)
140 {
141  if (job->error() != KJob::NoError) {
142  Q_EMIT mParent->error(job->errorString());
143  Q_EMIT mParent->finished();
144  return;
145  }
146 
147  if (mMode == EditMode) {
148  Q_EMIT mParent->contactStored(mItem);
149  } else if (mMode == CreateMode) {
150  Q_EMIT mParent->contactStored(static_cast<Akonadi::ItemCreateJob *>(job)->item());
151  }
152  Q_EMIT mParent->finished();
153 }
154 
155 void Akonadi::AkonadiContactEditor::Private::itemChanged(const Akonadi::Item &item, const QSet<QByteArray> &)
156 {
157  Q_UNUSED(item)
158  QPointer<QMessageBox> dlg = new QMessageBox(mParent); // krazy:exclude=qclasses
159 
160  dlg->setInformativeText(i18n("The contact has been changed by someone else.\nWhat should be done?"));
161  dlg->addButton(i18n("Take over changes"), QMessageBox::AcceptRole);
162  dlg->addButton(i18n("Ignore and Overwrite changes"), QMessageBox::RejectRole);
163 
164  if (dlg->exec() == QMessageBox::AcceptRole) {
165  auto job = new Akonadi::ItemFetchJob(mItem);
166  job->fetchScope().fetchFullPayload();
167  job->fetchScope().fetchAttribute<ContactMetaDataAttribute>();
168  job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
169 
170  mParent->connect(job, &ItemFetchJob::result, mParent, [this](KJob *job) {
171  itemFetchDone(job);
172  });
173  }
174 
175  delete dlg;
176 }
177 
178 void Akonadi::AkonadiContactEditor::Private::loadContact(const KContacts::Addressee &addr, const ContactMetaDataAkonadi &metaData)
179 {
180  mEditorWidget->loadContact(addr, metaData);
181 }
182 
183 void Akonadi::AkonadiContactEditor::Private::storeContact(KContacts::Addressee &addr, ContactMetaDataAkonadi &metaData)
184 {
185  mEditorWidget->storeContact(addr, metaData);
186 }
187 
188 void Akonadi::AkonadiContactEditor::Private::setupMonitor()
189 {
190  delete mMonitor;
191  mMonitor = new Akonadi::Monitor;
192  mMonitor->setObjectName(QStringLiteral("ContactEditorMonitor"));
193  mMonitor->ignoreSession(Akonadi::Session::defaultSession());
194 
195  connect(mMonitor, &Monitor::itemChanged, mParent, [this](const Akonadi::Item &item, const QSet<QByteArray> &set) {
196  itemChanged(item, set);
197  });
198 }
199 
201  : QWidget(parent)
202  , d(new Private(mode, FullMode, nullptr, this))
203 {
204 }
205 
206 Akonadi::AkonadiContactEditor::AkonadiContactEditor(Mode mode, ContactEditor::AbstractContactEditorWidget *editorWidget, QWidget *parent)
207  : QWidget(parent)
208  , d(new Private(mode, FullMode, editorWidget, this))
209 {
210 }
211 
213  : QWidget(parent)
214  , d(new Private(mode, displayMode, nullptr, this))
215 {
216 }
217 
219 {
220  delete d;
221 }
222 
224 {
225  if (d->mMode == CreateMode) {
226  Q_ASSERT_X(false, "ContactEditor::loadContact", "You are calling loadContact in CreateMode!");
227  }
228 
229  auto job = new Akonadi::ItemFetchJob(item);
230  job->fetchScope().fetchFullPayload();
231  job->fetchScope().fetchAttribute<ContactMetaDataAttribute>();
232  job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
233 
234  connect(job, &ItemFetchJob::result, this, [this](KJob *job) {
235  d->itemFetchDone(job);
236  });
237 
238  d->setupMonitor();
239  d->mMonitor->setItemMonitored(item);
240 }
241 
243 {
245  d->storeContact(addr, d->mContactMetaData);
246  return addr;
247 }
248 
250 {
251  if (d->mMode == EditMode) {
252  if (!d->mItem.isValid() || d->mReadOnly) {
253  Q_EMIT finished();
254  return;
255  }
256 
257  auto addr = d->mItem.payload<KContacts::Addressee>();
258 
259  d->storeContact(addr, d->mContactMetaData);
260 
261  d->mContactMetaData.store(d->mItem);
262 
263  d->mItem.setPayload<KContacts::Addressee>(addr);
264 
265  auto job = new Akonadi::ItemModifyJob(d->mItem);
266  connect(job, &ItemModifyJob::result, this, [this](KJob *job) {
267  d->storeDone(job);
268  });
269  } else if (d->mMode == CreateMode) {
270  if (!d->mDefaultCollection.isValid()) {
271  const QStringList mimeTypeFilter(KContacts::Addressee::mimeType());
272 
274  dlg->setMimeTypeFilter(mimeTypeFilter);
275  dlg->setAccessRightsFilter(Collection::CanCreateItem);
276  dlg->setWindowTitle(i18nc("@title:window", "Select Address Book"));
277  dlg->setDescription(i18n("Select the address book the new contact shall be saved in:"));
278  if (dlg->exec() == QDialog::Accepted) {
279  setDefaultAddressBook(dlg->selectedCollection());
280  delete dlg;
281  } else {
282  delete dlg;
283  return;
284  }
285  }
286 
288  d->storeContact(addr, d->mContactMetaData);
289 
290  Akonadi::Item item;
291  item.setPayload<KContacts::Addressee>(addr);
293 
294  d->mContactMetaData.store(item);
295 
296  auto job = new Akonadi::ItemCreateJob(item, d->mDefaultCollection);
297  connect(job, &ItemCreateJob::result, this, [this](KJob *job) {
298  d->storeDone(job);
299  });
300  }
301 }
302 
304 {
305  d->loadContact(contact, d->mContactMetaData);
306 }
307 
309 {
310  d->mDefaultCollection = collection;
311 }
312 
313 bool Akonadi::AkonadiContactEditor::hasNoSavedData() const
314 {
315  return d->mEditorWidget->hasNoSavedData();
316 }
317 
318 #include "moc_contacteditor.cpp"
static QString mimeType()
bool isValid() const
Mode
Describes the mode of the editor.
Definition: contacteditor.h:77
A widget for editing a contact.
virtual QString errorString() const
void loadContact(const Akonadi::Item &contact)
Loads the contact into the editor.
void setPayload(const T &p)
static Session * defaultSession()
Item::List items() const
Show just pages with elements stored in vcard.
void setContactTemplate(const KContacts::Addressee &contact)
Sets a contact that is used as template in create mode.
void setDefaultAddressBook(const Akonadi::Collection &addressbook)
Sets the addressbook which shall be used to store new contacts.
void setMimeType(const QString &mimeType)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void setObjectName(const QString &name)
void saveContactInAddressBook()
Save the contact from the editor back to the storage.
Rights rights() const
QString i18n(const char *text, const TYPE &arg...)
const T & at(int i) const const
AkonadiContactEditor(Mode mode, QWidget *parent=nullptr)
Creates a new contact editor with the standard editor widget.
Edits an existing contact.
Definition: contacteditor.h:79
KContacts::Addressee contact()
ContactEditor::contact.
An widget to edit contacts in Akonadi.
Definition: contacteditor.h:69
void result(KJob *job)
~AkonadiContactEditor() override
Destroys the contact editor.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void itemChanged(const Akonadi::Item &item, const QSet< QByteArray > &partIdentifiers)
Q_EMITQ_EMIT
int error() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Wed Jun 23 2021 23:09:24 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.