Akonadi Contacts

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

KDE's Doxygen guidelines are available online.