Akonadi Contacts

contactgroupeditor.cpp
1/*
2 This file is part of Akonadi Contact.
3
4 SPDX-FileCopyrightText: 2007-2009 Tobias Koenig <tokoe@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "contactgroupeditor.h"
10#include "contactgroupeditor_p.h"
11#include <KStatefulBrush>
12
13#include "contactgroupeditordelegate_p.h"
14#include "contactgroupmodel_p.h"
15#include "waitingoverlay_p.h"
16
17#include <Akonadi/CollectionDialog>
18#include <Akonadi/CollectionFetchJob>
19#include <Akonadi/ItemCreateJob>
20#include <Akonadi/ItemFetchJob>
21#include <Akonadi/ItemFetchScope>
22#include <Akonadi/ItemModifyJob>
23#include <Akonadi/Monitor>
24#include <Akonadi/Session>
25#include <KColorScheme>
26#include <KContacts/ContactGroup>
27#include <KLocalizedString>
28#include <KMessageBox>
29
30#include <QMessageBox>
31#include <QTimer>
32
33using namespace Akonadi;
34using namespace Akonadi;
35
36ContactGroupEditorPrivate::ContactGroupEditorPrivate(ContactGroupEditor *parent)
37 : mParent(parent)
38{
39}
40
41ContactGroupEditorPrivate::~ContactGroupEditorPrivate()
42{
43 delete mMonitor;
44}
45
46void ContactGroupEditorPrivate::adaptHeaderSizes()
47{
48 mGui.membersView->header()->setDefaultSectionSize(mGui.membersView->header()->width() / 2);
49 mGui.membersView->header()->resizeSections(QHeaderView::Interactive);
50}
51
52void ContactGroupEditorPrivate::itemFetchDone(KJob *job)
53{
54 if (job->error()) {
55 return;
56 }
57
58 auto fetchJob = qobject_cast<ItemFetchJob *>(job);
59 if (!fetchJob) {
60 return;
61 }
62
63 if (fetchJob->items().isEmpty()) {
64 return;
65 }
66
67 mItem = fetchJob->items().at(0);
68
69 mReadOnly = false;
70 if (mMode == ContactGroupEditor::EditMode) {
71 // if in edit mode we have to fetch the parent collection to find out
72 // about the modify rights of the item
73
74 auto collectionFetchJob = new Akonadi::CollectionFetchJob(mItem.parentCollection(), Akonadi::CollectionFetchJob::Base);
75 mParent->connect(collectionFetchJob, &CollectionFetchJob::result, mParent, [this](KJob *job) {
76 parentCollectionFetchDone(job);
77 });
78 } else {
79 const auto group = mItem.payload<KContacts::ContactGroup>();
80 loadContactGroup(group);
81
82 setReadOnly(mReadOnly);
83
84 QTimer::singleShot(0, mParent, [this]() {
85 adaptHeaderSizes();
86 });
87 }
88}
89
90void ContactGroupEditorPrivate::parentCollectionFetchDone(KJob *job)
91{
92 if (job->error()) {
93 return;
94 }
95
96 auto fetchJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
97 if (!fetchJob) {
98 return;
99 }
100
101 const Akonadi::Collection parentCollection = fetchJob->collections().at(0);
102 if (parentCollection.isValid()) {
103 mReadOnly = !(parentCollection.rights() & Collection::CanChangeItem);
104 }
105
106 const auto group = mItem.payload<KContacts::ContactGroup>();
107 loadContactGroup(group);
108
109 setReadOnly(mReadOnly);
110
111 QTimer::singleShot(0, mParent, [this]() {
112 adaptHeaderSizes();
113 });
114}
115
116void ContactGroupEditorPrivate::storeDone(KJob *job)
117{
118 if (job->error()) {
119 Q_EMIT mParent->error(job->errorString());
120 return;
121 }
122
123 if (mMode == ContactGroupEditor::EditMode) {
124 Q_EMIT mParent->contactGroupStored(mItem);
125 } else if (mMode == ContactGroupEditor::CreateMode) {
126 Q_EMIT mParent->contactGroupStored(static_cast<ItemCreateJob *>(job)->item());
127 }
128}
129
130void ContactGroupEditorPrivate::itemChanged(const Item &item, const QSet<QByteArray> &)
131{
132 Q_UNUSED(item)
133 QPointer<QMessageBox> dlg = new QMessageBox(mParent); // krazy:exclude=qclasses
134
135 dlg->setInformativeText(i18n("The contact group has been changed by someone else.\nWhat should be done?"));
136 dlg->addButton(i18n("Take over changes"), QMessageBox::AcceptRole);
137 dlg->addButton(i18n("Ignore and Overwrite changes"), QMessageBox::RejectRole);
138
139 if (dlg->exec() == QMessageBox::AcceptRole) {
140 auto job = new ItemFetchJob(mItem);
141 job->fetchScope().fetchFullPayload();
142 job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
143
144 mParent->connect(job, &ItemFetchJob::result, mParent, [this](KJob *job) {
145 itemFetchDone(job);
146 });
147 new WaitingOverlay(job, mParent);
148 } else {
149 // Still update the item so that the internal revision match
150 mItem = item;
151 }
152 delete dlg;
153}
154
155void ContactGroupEditorPrivate::loadContactGroup(const KContacts::ContactGroup &group)
156{
157 mGui.membersView->setSortingEnabled(false);
158 mGui.groupName->setText(group.name());
159
160 mGroupModel->loadContactGroup(group);
161
162 const QAbstractItemModel *model = mGui.membersView->model();
163 mGui.membersView->setCurrentIndex(model->index(model->rowCount() - 1, 0));
164
165 if (mMode == ContactGroupEditor::EditMode) {
166 mGui.membersView->setFocus();
167 }
168
169 mGui.membersView->header()->resizeSections(QHeaderView::Stretch);
170 mGui.membersView->setSortingEnabled(true);
171}
172
173bool ContactGroupEditorPrivate::storeContactGroup(KContacts::ContactGroup &group)
174{
175 if (mGui.groupName->text().isEmpty()) {
176 KMessageBox::error(mParent, i18n("The name of the contact group must not be empty."));
177 return false;
178 }
179
180 group.setName(mGui.groupName->text());
181
182 if (!mGroupModel->storeContactGroup(group)) {
183 KMessageBox::error(mParent, mGroupModel->lastErrorMessage());
184 return false;
185 }
186
187 return true;
188}
189
190void ContactGroupEditorPrivate::setupMonitor()
191{
192 delete mMonitor;
193 mMonitor = new Monitor;
194 mMonitor->setObjectName(QLatin1StringView("ContactGroupEditorMonitor"));
195 mMonitor->ignoreSession(Session::defaultSession());
196
197 QObject::connect(mMonitor, &Monitor::itemChanged, mParent, [this](const Akonadi::Item &item, const QSet<QByteArray> &arrays) {
198 itemChanged(item, arrays);
199 });
200}
201
202void ContactGroupEditorPrivate::setReadOnly(bool readOnly)
203{
204 mGui.groupName->setReadOnly(readOnly);
205 mGui.membersView->setEnabled(!readOnly);
206}
207
209 : QWidget(parent)
210 , d(new ContactGroupEditorPrivate(this))
211{
212 d->mMode = mode;
213 d->mGui.setupUi(this);
214
215 d->mGui.membersView->setEditTriggers(QAbstractItemView::AllEditTriggers);
216
217 d->mGroupModel = new ContactGroupModel(this);
218 auto proxyModel = new GroupFilterModel(this);
219 proxyModel->setSourceModel(d->mGroupModel);
220 connect(d->mGui.searchField, &QLineEdit::textChanged, this, [proxyModel](const QString &text) {
221 proxyModel->setFilterRegularExpression(text);
222 });
223 d->mGui.membersView->setModel(proxyModel);
224 d->mGui.membersView->setItemDelegate(new ContactGroupEditorDelegate(d->mGui.membersView, this));
225
226 if (mode == CreateMode) {
227 KContacts::ContactGroup dummyGroup;
228 d->mGroupModel->loadContactGroup(dummyGroup);
229
230 QTimer::singleShot(0, this, [this]() {
231 d->adaptHeaderSizes();
232 });
233 QTimer::singleShot(0, d->mGui.groupName, qOverload<>(&ContactGroupEditor::setFocus));
234 }
235
236 d->mGui.membersView->header()->setStretchLastSection(true);
237}
238
240
242{
243 if (d->mMode == CreateMode) {
244 Q_ASSERT_X(false, "ContactGroupEditor::loadContactGroup", "You are calling loadContactGroup in CreateMode!");
245 }
246
247 auto job = new ItemFetchJob(item);
248 job->fetchScope().fetchFullPayload();
249 job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
250
251 connect(job, &ItemModifyJob::result, this, [this](KJob *job) {
252 d->itemFetchDone(job);
253 });
254
255 d->setupMonitor();
256 d->mMonitor->setItemMonitored(item);
257
258 new WaitingOverlay(job, this);
259}
260
262{
263 if (d->mMode == EditMode) {
264 if (!d->mItem.isValid()) {
265 return false;
266 }
267
268 if (d->mReadOnly) {
269 return true;
270 }
271
272 auto group = d->mItem.payload<KContacts::ContactGroup>();
273
274 if (!d->storeContactGroup(group)) {
275 return false;
276 }
277
278 d->mItem.setPayload<KContacts::ContactGroup>(group);
279
280 auto job = new ItemModifyJob(d->mItem);
281 connect(job, &ItemModifyJob::result, this, [this](KJob *job) {
282 d->storeDone(job);
283 });
284 } else if (d->mMode == CreateMode) {
285 if (!d->mDefaultCollection.isValid()) {
286 const QStringList mimeTypeFilter(KContacts::ContactGroup::mimeType());
287
289 dlg->setMimeTypeFilter(mimeTypeFilter);
290 dlg->setAccessRightsFilter(Collection::CanCreateItem);
291 dlg->setWindowTitle(i18nc("@title:window", "Select Address Book"));
292 dlg->setDescription(i18n("Select the address book the new contact group shall be saved in:"));
293
294 if (dlg->exec() == QDialog::Accepted) {
295 setDefaultAddressBook(dlg->selectedCollection());
296 delete dlg;
297 } else {
298 delete dlg;
299 return false;
300 }
301 }
302
304 if (!d->storeContactGroup(group)) {
305 return false;
306 }
307
308 Item item;
311
312 auto job = new ItemCreateJob(item, d->mDefaultCollection);
313 connect(job, &ItemCreateJob::result, this, [this](KJob *job) {
314 d->storeDone(job);
315 });
316 }
317
318 return true;
319}
320
322{
323 d->mGroupModel->loadContactGroup(group);
324 d->mGui.membersView->header()->setDefaultSectionSize(d->mGui.membersView->header()->width() / 2);
325 d->mGui.membersView->header()->resizeSections(QHeaderView::Interactive);
326}
327
329{
330 d->mDefaultCollection = collection;
331}
332
333void ContactGroupEditor::groupNameIsValid(bool isValid)
334{
335#ifndef QT_NO_STYLE_STYLESHEET
337 if (!isValid) {
339 KStatefulBrush bgBrush(KColorScheme::View, bgColorScheme);
340 styleSheet = QStringLiteral("QLineEdit{ background-color:%1 }").arg(bgBrush.brush(palette()).color().name());
341 }
342 d->mGui.groupName->setStyleSheet(styleSheet);
343#endif
344}
345
346#include "moc_contactgroupeditor.cpp"
bool isValid() const
Rights rights() const
An widget to edit contact groups in Akonadi.
void setContactGroupTemplate(const KContacts::ContactGroup &group)
Sets a contact group that is used as template in create mode.
bool saveContactGroup()
Saves the contact group from the editor back to the storage.
Mode
Describes the mode of the contact group editor.
@ CreateMode
Creates a new contact group.
@ EditMode
Edits an existing contact group.
void setDefaultAddressBook(const Akonadi::Collection &addressbook)
Sets the addressbook which shall be used to store new contact groups.
ContactGroupEditor(Mode mode, QWidget *parent=nullptr)
Creates a new contact group editor.
void loadContactGroup(const Akonadi::Item &group)
Loads the contact group into the editor.
~ContactGroupEditor() override
Destroys the contact group editor.
void setMimeType(const QString &mimeType)
void setPayload(const T &p)
void itemChanged(const Akonadi::Item &item, const QSet< QByteArray > &partIdentifiers)
void setName(const QString &name)
static QString mimeType()
QString name() const
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.
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
virtual int rowCount(const QModelIndex &parent) const const=0
void textChanged(const QString &text)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void setObjectName(QAnyStringView name)
void setFocus()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:20 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.