Akonadi Contacts

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

KDE's Doxygen guidelines are available online.