Akonadi Contacts

contactgroupeditor.cpp
1 /*
2  This file is part of Akonadi Contact.
3 
4  Copyright (c) 2007-2009 Tobias Koenig <[email protected]>
5 
6  This library is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Library General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or (at your
9  option) any later version.
10 
11  This library is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14  License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to the
18  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  02110-1301, USA.
20 */
21 
22 #include "contactgroupeditor.h"
23 #include "contactgroupeditor_p.h"
24 
25 #include "contactgroupmodel_p.h"
26 #include "contactgroupeditordelegate_p.h"
27 #include "waitingoverlay_p.h"
28 
29 #include <collectiondialog.h>
30 #include <collectionfetchjob.h>
31 #include <itemcreatejob.h>
32 #include <itemfetchjob.h>
33 #include <itemfetchscope.h>
34 #include <itemmodifyjob.h>
35 #include <monitor.h>
36 #include <session.h>
37 #include <kcontacts/contactgroup.h>
38 #include <KLocalizedString>
39 #include <KMessageBox>
40 #include <KColorScheme>
41 
42 #include <QTimer>
43 #include <QMessageBox>
44 
45 using namespace Akonadi;
46 
47 ContactGroupEditor::Private::Private(ContactGroupEditor *parent)
48  : mParent(parent)
49 {
50 }
51 
52 ContactGroupEditor::Private::~Private()
53 {
54  delete mMonitor;
55 }
56 
57 void ContactGroupEditor::Private::adaptHeaderSizes()
58 {
59  mGui.membersView->header()->setDefaultSectionSize(mGui.membersView->header()->width() / 2);
60  mGui.membersView->header()->resizeSections(QHeaderView::Interactive);
61 }
62 
63 void ContactGroupEditor::Private::itemFetchDone(KJob *job)
64 {
65  if (job->error()) {
66  return;
67  }
68 
69  ItemFetchJob *fetchJob = qobject_cast<ItemFetchJob *>(job);
70  if (!fetchJob) {
71  return;
72  }
73 
74  if (fetchJob->items().isEmpty()) {
75  return;
76  }
77 
78  mItem = fetchJob->items().at(0);
79 
80  mReadOnly = false;
81  if (mMode == ContactGroupEditor::EditMode) {
82  // if in edit mode we have to fetch the parent collection to find out
83  // about the modify rights of the item
84 
85  Akonadi::CollectionFetchJob *collectionFetchJob = new Akonadi::CollectionFetchJob(mItem.parentCollection(),
87  mParent->connect(collectionFetchJob, &CollectionFetchJob::result, mParent, [this](KJob *job) {
88  parentCollectionFetchDone(job);
89  });
90  } else {
91  const KContacts::ContactGroup group = mItem.payload<KContacts::ContactGroup>();
92  loadContactGroup(group);
93 
94  setReadOnly(mReadOnly);
95 
96  QTimer::singleShot(0, mParent, [this]() {
97  adaptHeaderSizes();
98  });
99  }
100 }
101 
102 void ContactGroupEditor::Private::parentCollectionFetchDone(KJob *job)
103 {
104  if (job->error()) {
105  return;
106  }
107 
108  Akonadi::CollectionFetchJob *fetchJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
109  if (!fetchJob) {
110  return;
111  }
112 
113  const Akonadi::Collection parentCollection = fetchJob->collections().at(0);
114  if (parentCollection.isValid()) {
115  mReadOnly = !(parentCollection.rights() & Collection::CanChangeItem);
116  }
117 
118  const KContacts::ContactGroup group = mItem.payload<KContacts::ContactGroup>();
119  loadContactGroup(group);
120 
121  setReadOnly(mReadOnly);
122 
123  QTimer::singleShot(0, mParent, [this]() {
124  adaptHeaderSizes();
125  });
126 }
127 
128 void ContactGroupEditor::Private::storeDone(KJob *job)
129 {
130  if (job->error()) {
131  Q_EMIT mParent->error(job->errorString());
132  return;
133  }
134 
135  if (mMode == EditMode) {
136  Q_EMIT mParent->contactGroupStored(mItem);
137  } else if (mMode == CreateMode) {
138  Q_EMIT mParent->contactGroupStored(static_cast<ItemCreateJob *>(job)->item());
139  }
140 }
141 
142 void ContactGroupEditor::Private::itemChanged(const Item &item, const QSet<QByteArray> &)
143 {
144  Q_UNUSED(item)
145  QPointer<QMessageBox> dlg = new QMessageBox(mParent); //krazy:exclude=qclasses
146 
147  dlg->setInformativeText(i18n("The contact group has been changed by someone else.\nWhat should be done?"));
148  dlg->addButton(i18n("Take over changes"), QMessageBox::AcceptRole);
149  dlg->addButton(i18n("Ignore and Overwrite changes"), QMessageBox::RejectRole);
150 
151  if (dlg->exec() == QMessageBox::AcceptRole) {
152  ItemFetchJob *job = new ItemFetchJob(mItem);
153  job->fetchScope().fetchFullPayload();
155 
156  mParent->connect(job, &ItemFetchJob::result, mParent, [this](KJob *job) {
157  itemFetchDone(job);
158  });
159  new WaitingOverlay(job, mParent);
160  }
161  delete dlg;
162 }
163 
164 void ContactGroupEditor::Private::loadContactGroup(const KContacts::ContactGroup &group)
165 {
166  mGui.groupName->setText(group.name());
167 
168  mGroupModel->loadContactGroup(group);
169 
170  const QAbstractItemModel *model = mGui.membersView->model();
171  mGui.membersView->setCurrentIndex(model->index(model->rowCount() - 1, 0));
172 
173  if (mMode == EditMode) {
174  mGui.membersView->setFocus();
175  }
176 
177  mGui.membersView->header()->resizeSections(QHeaderView::Stretch);
178 }
179 
180 bool ContactGroupEditor::Private::storeContactGroup(KContacts::ContactGroup &group)
181 {
182  if (mGui.groupName->text().isEmpty()) {
183  KMessageBox::error(mParent, i18n("The name of the contact group must not be empty."));
184  return false;
185  }
186 
187  group.setName(mGui.groupName->text());
188 
189  if (!mGroupModel->storeContactGroup(group)) {
190  KMessageBox::error(mParent, mGroupModel->lastErrorMessage());
191  return false;
192  }
193 
194  return true;
195 }
196 
197 void ContactGroupEditor::Private::setupMonitor()
198 {
199  delete mMonitor;
200  mMonitor = new Monitor;
201  mMonitor->setObjectName(QStringLiteral("ContactGroupEditorMonitor"));
202  mMonitor->ignoreSession(Session::defaultSession());
203 
204  connect(mMonitor, &Monitor::itemChanged,
205  mParent, [this](const Akonadi::Item &item, const QSet<QByteArray> &arrays) {
206  itemChanged(item, arrays);
207  });
208 }
209 
210 void ContactGroupEditor::Private::setReadOnly(bool readOnly)
211 {
212  mGui.groupName->setReadOnly(readOnly);
213  mGui.membersView->setEnabled(!readOnly);
214 }
215 
216 ContactGroupEditor::ContactGroupEditor(Mode mode, QWidget *parent)
217  : QWidget(parent)
218  , d(new Private(this))
219 {
220  d->mMode = mode;
221  d->mGui.setupUi(this);
222 
223  d->mGui.membersView->setEditTriggers(QAbstractItemView::AllEditTriggers);
224 
225  d->mGroupModel = new ContactGroupModel(this);
226  d->mGui.membersView->setModel(d->mGroupModel);
227  d->mGui.membersView->setItemDelegate(new ContactGroupEditorDelegate(d->mGui.membersView, this));
228 
229  if (mode == CreateMode) {
230  KContacts::ContactGroup dummyGroup;
231  d->mGroupModel->loadContactGroup(dummyGroup);
232 
233  QTimer::singleShot(0, this, [this]() {
234  d->adaptHeaderSizes();
235  });
236  QTimer::singleShot(0, d->mGui.groupName, QOverload<>::of(&ContactGroupEditor::setFocus));
237  }
238 
239  d->mGui.membersView->header()->setStretchLastSection(true);
240 }
241 
243 {
244  delete d;
245 }
246 
247 void ContactGroupEditor::loadContactGroup(const Akonadi::Item &item)
248 {
249  if (d->mMode == CreateMode) {
250  Q_ASSERT_X(false, "ContactGroupEditor::loadContactGroup", "You are calling loadContactGroup in CreateMode!");
251  }
252 
253  ItemFetchJob *job = new ItemFetchJob(item);
254  job->fetchScope().fetchFullPayload();
256 
257  connect(job, &ItemModifyJob::result, this, [this](KJob *job) {
258  d->itemFetchDone(job);
259  });
260 
261  d->setupMonitor();
262  d->mMonitor->setItemMonitored(item);
263 
264  new WaitingOverlay(job, this);
265 }
266 
268 {
269  if (d->mMode == EditMode) {
270  if (!d->mItem.isValid()) {
271  return false;
272  }
273 
274  if (d->mReadOnly) {
275  return true;
276  }
277 
278  KContacts::ContactGroup group = d->mItem.payload<KContacts::ContactGroup>();
279 
280  if (!d->storeContactGroup(group)) {
281  return false;
282  }
283 
284  d->mItem.setPayload<KContacts::ContactGroup>(group);
285 
286  ItemModifyJob *job = new ItemModifyJob(d->mItem);
287  connect(job, &ItemModifyJob::result, this, [this](KJob *job) {
288  d->storeDone(job);
289  });
290  } else if (d->mMode == CreateMode) {
291  if (!d->mDefaultCollection.isValid()) {
292  const QStringList mimeTypeFilter(KContacts::ContactGroup::mimeType());
293 
295  dlg->setMimeTypeFilter(mimeTypeFilter);
296  dlg->setAccessRightsFilter(Collection::CanCreateItem);
297  dlg->setWindowTitle(i18nc("@title:window", "Select Address Book"));
298  dlg->setDescription(i18n("Select the address book the new contact group shall be saved in:"));
299 
300  if (dlg->exec() == QDialog::Accepted) {
301  setDefaultAddressBook(dlg->selectedCollection());
302  delete dlg;
303  } else {
304  delete dlg;
305  return false;
306  }
307  }
308 
310  if (!d->storeContactGroup(group)) {
311  return false;
312  }
313 
314  Item item;
315  item.setPayload<KContacts::ContactGroup>(group);
316  item.setMimeType(KContacts::ContactGroup::mimeType());
317 
318  ItemCreateJob *job = new ItemCreateJob(item, d->mDefaultCollection);
319  connect(job, &ItemCreateJob::result, this, [this](KJob *job) {
320  d->storeDone(job);
321  });
322  }
323 
324  return true;
325 }
326 
328 {
329  d->mGroupModel->loadContactGroup(group);
330  d->mGui.membersView->header()->setDefaultSectionSize(d->mGui.membersView->header()->width() / 2);
331  d->mGui.membersView->header()->resizeSections(QHeaderView::Interactive);
332 }
333 
335 {
336  d->mDefaultCollection = collection;
337 }
338 
339 void ContactGroupEditor::groupNameIsValid(bool isValid)
340 {
341 #ifndef QT_NO_STYLE_STYLESHEET
343  if (!isValid) {
345  KStatefulBrush bgBrush(KColorScheme::View, bgColorScheme);
346  styleSheet = QStringLiteral("QLineEdit{ background-color:%1 }").
347  arg(bgBrush.brush(this).color().name());
348  }
349  d->mGui.groupName->setStyleSheet(styleSheet);
350 #endif
351 }
352 
353 #include "moc_contactgroupeditor.cpp"
QString styleSheet() const const
virtual int rowCount(const QModelIndex &parent) const const =0
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const =0
Collection::List collections() const
bool isValid() const
void setReadOnly(bool readOnly) override
Sets whether the contact in the editor allows the user to edit the contact or not.
QString name() const const
virtual QString errorString() const
void loadContactGroup(const Akonadi::Item &group)
Loads the contact group into the editor.
void fetchFullPayload(bool fetch=true)
Item::List items() const
const QColor & color() const const
ItemFetchScope & fetchScope()
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
void setAncestorRetrieval(AncestorRetrieval ancestorDepth)
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.
QBrush brush(QPalette::ColorGroup) const
void result(KJob *job)
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-2020 The KDE developers.
Generated on Wed Aug 5 2020 23:05:57 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.