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 "contactgroupmodel_p.h"
13 #include "contactgroupeditordelegate_p.h"
14 #include "waitingoverlay_p.h"
15 
16 #include <collectiondialog.h>
17 #include <collectionfetchjob.h>
18 #include <itemcreatejob.h>
19 #include <itemfetchjob.h>
20 #include <itemfetchscope.h>
21 #include <itemmodifyjob.h>
22 #include <monitor.h>
23 #include <session.h>
24 #include <kcontacts/contactgroup.h>
25 #include <KLocalizedString>
26 #include <KMessageBox>
27 #include <KColorScheme>
28 
29 #include <QTimer>
30 #include <QMessageBox>
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(),
74  mParent->connect(collectionFetchJob, &CollectionFetchJob::result, mParent, [this](KJob *job) {
75  parentCollectionFetchDone(job);
76  });
77  } else {
78  const KContacts::ContactGroup group = mItem.payload<KContacts::ContactGroup>();
79  loadContactGroup(group);
80 
81  setReadOnly(mReadOnly);
82 
83  QTimer::singleShot(0, mParent, [this]() {
84  adaptHeaderSizes();
85  });
86  }
87 }
88 
89 void ContactGroupEditor::Private::parentCollectionFetchDone(KJob *job)
90 {
91  if (job->error()) {
92  return;
93  }
94 
95  auto *fetchJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
96  if (!fetchJob) {
97  return;
98  }
99 
100  const Akonadi::Collection parentCollection = fetchJob->collections().at(0);
101  if (parentCollection.isValid()) {
102  mReadOnly = !(parentCollection.rights() & Collection::CanChangeItem);
103  }
104 
105  const KContacts::ContactGroup group = mItem.payload<KContacts::ContactGroup>();
106  loadContactGroup(group);
107 
108  setReadOnly(mReadOnly);
109 
110  QTimer::singleShot(0, mParent, [this]() {
111  adaptHeaderSizes();
112  });
113 }
114 
115 void ContactGroupEditor::Private::storeDone(KJob *job)
116 {
117  if (job->error()) {
118  Q_EMIT mParent->error(job->errorString());
119  return;
120  }
121 
122  if (mMode == EditMode) {
123  Q_EMIT mParent->contactGroupStored(mItem);
124  } else if (mMode == CreateMode) {
125  Q_EMIT mParent->contactGroupStored(static_cast<ItemCreateJob *>(job)->item());
126  }
127 }
128 
129 void ContactGroupEditor::Private::itemChanged(const Item &item, const QSet<QByteArray> &)
130 {
131  Q_UNUSED(item)
132  QPointer<QMessageBox> dlg = new QMessageBox(mParent); //krazy:exclude=qclasses
133 
134  dlg->setInformativeText(i18n("The contact group has been changed by someone else.\nWhat should be done?"));
135  dlg->addButton(i18n("Take over changes"), QMessageBox::AcceptRole);
136  dlg->addButton(i18n("Ignore and Overwrite changes"), QMessageBox::RejectRole);
137 
138  if (dlg->exec() == QMessageBox::AcceptRole) {
139  auto *job = new ItemFetchJob(mItem);
140  job->fetchScope().fetchFullPayload();
141  job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
142 
143  mParent->connect(job, &ItemFetchJob::result, mParent, [this](KJob *job) {
144  itemFetchDone(job);
145  });
146  new WaitingOverlay(job, mParent);
147  }
148  delete dlg;
149 }
150 
151 void ContactGroupEditor::Private::loadContactGroup(const KContacts::ContactGroup &group)
152 {
153  mGui.groupName->setText(group.name());
154 
155  mGroupModel->loadContactGroup(group);
156 
157  const QAbstractItemModel *model = mGui.membersView->model();
158  mGui.membersView->setCurrentIndex(model->index(model->rowCount() - 1, 0));
159 
160  if (mMode == EditMode) {
161  mGui.membersView->setFocus();
162  }
163 
164  mGui.membersView->header()->resizeSections(QHeaderView::Stretch);
165 }
166 
167 bool ContactGroupEditor::Private::storeContactGroup(KContacts::ContactGroup &group)
168 {
169  if (mGui.groupName->text().isEmpty()) {
170  KMessageBox::error(mParent, i18n("The name of the contact group must not be empty."));
171  return false;
172  }
173 
174  group.setName(mGui.groupName->text());
175 
176  if (!mGroupModel->storeContactGroup(group)) {
177  KMessageBox::error(mParent, mGroupModel->lastErrorMessage());
178  return false;
179  }
180 
181  return true;
182 }
183 
184 void ContactGroupEditor::Private::setupMonitor()
185 {
186  delete mMonitor;
187  mMonitor = new Monitor;
188  mMonitor->setObjectName(QStringLiteral("ContactGroupEditorMonitor"));
189  mMonitor->ignoreSession(Session::defaultSession());
190 
191  connect(mMonitor, &Monitor::itemChanged,
192  mParent, [this](const Akonadi::Item &item, const QSet<QByteArray> &arrays) {
193  itemChanged(item, arrays);
194  });
195 }
196 
197 void ContactGroupEditor::Private::setReadOnly(bool readOnly)
198 {
199  mGui.groupName->setReadOnly(readOnly);
200  mGui.membersView->setEnabled(!readOnly);
201 }
202 
203 ContactGroupEditor::ContactGroupEditor(Mode mode, QWidget *parent)
204  : QWidget(parent)
205  , d(new Private(this))
206 {
207  d->mMode = mode;
208  d->mGui.setupUi(this);
209 
210  d->mGui.membersView->setEditTriggers(QAbstractItemView::AllEditTriggers);
211 
212  d->mGroupModel = new ContactGroupModel(this);
213  d->mGui.membersView->setModel(d->mGroupModel);
214  d->mGui.membersView->setItemDelegate(new ContactGroupEditorDelegate(d->mGui.membersView, this));
215 
216  if (mode == CreateMode) {
217  KContacts::ContactGroup dummyGroup;
218  d->mGroupModel->loadContactGroup(dummyGroup);
219 
220  QTimer::singleShot(0, this, [this]() {
221  d->adaptHeaderSizes();
222  });
223  QTimer::singleShot(0, d->mGui.groupName, QOverload<>::of(&ContactGroupEditor::setFocus));
224  }
225 
226  d->mGui.membersView->header()->setStretchLastSection(true);
227 }
228 
230 {
231  delete d;
232 }
233 
234 void ContactGroupEditor::loadContactGroup(const Akonadi::Item &item)
235 {
236  if (d->mMode == CreateMode) {
237  Q_ASSERT_X(false, "ContactGroupEditor::loadContactGroup", "You are calling loadContactGroup in CreateMode!");
238  }
239 
240  auto *job = new ItemFetchJob(item);
241  job->fetchScope().fetchFullPayload();
242  job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
243 
244  connect(job, &ItemModifyJob::result, this, [this](KJob *job) {
245  d->itemFetchDone(job);
246  });
247 
248  d->setupMonitor();
249  d->mMonitor->setItemMonitored(item);
250 
251  new WaitingOverlay(job, this);
252 }
253 
255 {
256  if (d->mMode == EditMode) {
257  if (!d->mItem.isValid()) {
258  return false;
259  }
260 
261  if (d->mReadOnly) {
262  return true;
263  }
264 
265  KContacts::ContactGroup group = d->mItem.payload<KContacts::ContactGroup>();
266 
267  if (!d->storeContactGroup(group)) {
268  return false;
269  }
270 
271  d->mItem.setPayload<KContacts::ContactGroup>(group);
272 
273  auto *job = new ItemModifyJob(d->mItem);
274  connect(job, &ItemModifyJob::result, this, [this](KJob *job) {
275  d->storeDone(job);
276  });
277  } else if (d->mMode == CreateMode) {
278  if (!d->mDefaultCollection.isValid()) {
279  const QStringList mimeTypeFilter(KContacts::ContactGroup::mimeType());
280 
282  dlg->setMimeTypeFilter(mimeTypeFilter);
283  dlg->setAccessRightsFilter(Collection::CanCreateItem);
284  dlg->setWindowTitle(i18nc("@title:window", "Select Address Book"));
285  dlg->setDescription(i18n("Select the address book the new contact group shall be saved in:"));
286 
287  if (dlg->exec() == QDialog::Accepted) {
288  setDefaultAddressBook(dlg->selectedCollection());
289  delete dlg;
290  } else {
291  delete dlg;
292  return false;
293  }
294  }
295 
297  if (!d->storeContactGroup(group)) {
298  return false;
299  }
300 
301  Item item;
302  item.setPayload<KContacts::ContactGroup>(group);
303  item.setMimeType(KContacts::ContactGroup::mimeType());
304 
305  auto *job = new ItemCreateJob(item, d->mDefaultCollection);
306  connect(job, &ItemCreateJob::result, this, [this](KJob *job) {
307  d->storeDone(job);
308  });
309  }
310 
311  return true;
312 }
313 
315 {
316  d->mGroupModel->loadContactGroup(group);
317  d->mGui.membersView->header()->setDefaultSectionSize(d->mGui.membersView->header()->width() / 2);
318  d->mGui.membersView->header()->resizeSections(QHeaderView::Interactive);
319 }
320 
322 {
323  d->mDefaultCollection = collection;
324 }
325 
326 void ContactGroupEditor::groupNameIsValid(bool isValid)
327 {
328 #ifndef QT_NO_STYLE_STYLESHEET
330  if (!isValid) {
332  KStatefulBrush bgBrush(KColorScheme::View, bgColorScheme);
333  styleSheet = QStringLiteral("QLineEdit{ background-color:%1 }").
334  arg(bgBrush.brush(this).color().name());
335  }
336  d->mGui.groupName->setStyleSheet(styleSheet);
337 #endif
338 }
339 
340 #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.
Item::List items() const
const QColor & color() const const
QString name() const
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...)
Edits an existing contact group.
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 Wed Jan 20 2021 23:14:17 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.