• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.7 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
favoritecollectionsmodel.cpp
1 /*
2  Copyright (c) 2009 Kevin Ottens <ervin@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "favoritecollectionsmodel.h"
21 
22 #include <QItemSelectionModel>
23 #include <QtCore/QMimeData>
24 
25 #include <kconfiggroup.h>
26 #include <klocale.h>
27 #include <klocalizedstring.h>
28 #include <KJob>
29 #include <KUrl>
30 
31 #include "entitytreemodel.h"
32 #include "mimetypechecker.h"
33 #include "pastehelper_p.h"
34 
35 using namespace Akonadi;
36 
40 class FavoriteCollectionsModel::Private
41 {
42 public:
43  Private(const KConfigGroup &group, FavoriteCollectionsModel *parent)
44  : q(parent)
45  , configGroup(group)
46  {
47  }
48 
49  QString labelForCollection(Collection::Id collectionId) const
50  {
51  if (labelMap.contains(collectionId)) {
52  return labelMap[collectionId];
53  }
54 
55  const QModelIndex collectionIdx = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId));
56 
57  QString accountName;
58 
59  const QString nameOfCollection = collectionIdx.data().toString();
60 
61  QModelIndex idx = collectionIdx.parent();
62  while (idx != QModelIndex()) {
63  accountName = idx.data().toString();
64  idx = idx.parent();
65  }
66 
67  if (accountName.isEmpty()) {
68  return nameOfCollection;
69  } else {
70  return nameOfCollection + QLatin1String(" (") + accountName + QLatin1Char(')');
71  }
72  }
73 
74  void insertIfAvailable(Collection::Id col)
75  {
76  if (collectionIds.contains(col)) {
77  select(col);
78  }
79  }
80 
81  void insertIfAvailable(const QModelIndex &idx)
82  {
83  insertIfAvailable(idx.data(EntityTreeModel::CollectionIdRole).value<Collection::Id>());
84  }
85 
89  void reload()
90  {
91  //don't clear the selection model here. Otherwise we mess up the users selection as collections get removed and re-inserted.
92  foreach (const Collection::Id &collectionId, collectionIds) {
93  insertIfAvailable(collectionId);
94  }
95  //TODO remove what's no longer here
96  }
97 
98  void rowsInserted(const QModelIndex &parent, int begin, int end)
99  {
100  for (int row = begin; row <= end; row++) {
101  const QModelIndex child = parent.child(row, 0);
102  if (!child.isValid()) {
103  continue;
104  }
105  insertIfAvailable(child);
106  const int childRows = q->sourceModel()->rowCount(child);
107  if (childRows > 0) {
108  rowsInserted(child, 0, childRows - 1);
109  }
110  }
111  }
112 
116  void select(const Collection::Id &collectionId)
117  {
118  const QModelIndex index = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId));
119  if (index.isValid() && !q->selectionModel()->isSelected(index)) {
120  q->selectionModel()->select(index, QItemSelectionModel::Select);
121  if (!referencedCollections.contains(collectionId)) {
122  reference(collectionId);
123  }
124  }
125  }
126 
127  void deselect(const Collection::Id &collectionId)
128  {
129  const QModelIndex idx = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId));
130  if (idx.isValid()) {
131  q->selectionModel()->select(idx, QItemSelectionModel::Deselect);
132  if (referencedCollections.contains(collectionId)) {
133  dereference(collectionId);
134  }
135  }
136  }
137 
138  void reference(const Collection::Id &collectionId)
139  {
140  if (referencedCollections.contains(collectionId)) {
141  kWarning() << "already referenced" << collectionId;
142  return;
143  }
144  const QModelIndex index = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId));
145  if (index.isValid()) {
146  if (q->sourceModel()->setData(index, QVariant(), EntityTreeModel::CollectionRefRole)) {
147  referencedCollections << collectionId;
148  } else {
149  kWarning() << "failed to reference collection";
150  }
151  q->sourceModel()->fetchMore(index);
152  }
153  }
154 
155  void dereference(const Collection::Id &collectionId)
156  {
157  if (!referencedCollections.contains(collectionId)) {
158  kWarning() << "not referenced" << collectionId;
159  return;
160  }
161  const QModelIndex index = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId));
162  if (index.isValid()) {
163  q->sourceModel()->setData(index, QVariant(), EntityTreeModel::CollectionDerefRole);
164  }
165  referencedCollections.remove(collectionId);
166  }
167 
168  void clearReferences()
169  {
170  foreach (const Collection::Id &collectionId, referencedCollections) {
171  dereference(collectionId);
172  }
173  }
174 
178  void add(const Collection::Id &collectionId)
179  {
180  if (collectionIds.contains(collectionId)) {
181  kDebug() << "already in model " << collectionId;
182  return;
183  }
184  collectionIds << collectionId;
185  select(collectionId);
186  }
187 
188  void remove(const Collection::Id &collectionId)
189  {
190  collectionIds.removeAll(collectionId);
191  labelMap.remove(collectionId);
192  deselect(collectionId);
193  }
194 
195  void set(const QList<Collection::Id> &collections)
196  {
197  QList<Collection::Id> colIds = collectionIds;
198  foreach (const Collection::Id &col, collections) {
199  const int removed = colIds.removeAll(col);
200  const bool isNewCollection = removed <= 0;
201  if (isNewCollection) {
202  add(col);
203  }
204  }
205  //Remove what's left
206  foreach (const Akonadi::Collection::Id &colId, colIds) {
207  remove(colId);
208  }
209  }
210 
211  void set(const Akonadi::Collection::List &collections)
212  {
213  QList<Akonadi::Collection::Id> colIds;
214  foreach (const Akonadi::Collection &col, collections) {
215  colIds << col.id();
216  }
217  set(colIds);
218  }
219 
220  void loadConfig()
221  {
222  const QList<Collection::Id> collections = configGroup.readEntry("FavoriteCollectionIds", QList<qint64>());
223  const QStringList labels = configGroup.readEntry("FavoriteCollectionLabels", QStringList());
224  const int numberOfLabels(labels.size());
225  for (int i = 0; i < collections.size(); ++i) {
226  if (i < numberOfLabels) {
227  labelMap[collections[i]] = labels[i];
228  }
229  add(collections[i]);
230  }
231  }
232 
233  void saveConfig()
234  {
235  QStringList labels;
236  QList<Collection::Id> ids;
237  foreach (const Collection::Id &collectionId, collectionIds) {
238  const QModelIndex idx = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId));
239  if (idx.isValid()) {
240  labels << labelForCollection(collectionId);
241  ids << collectionId;
242  }
243  }
244  configGroup.writeEntry("FavoriteCollectionIds", ids);
245  configGroup.writeEntry("FavoriteCollectionLabels", labels);
246  configGroup.config()->sync();
247  }
248 
249  FavoriteCollectionsModel *const q;
250 
251  QList<Collection::Id> collectionIds;
252  QSet<Collection::Id> referencedCollections;
253  QHash<qint64, QString> labelMap;
254  KConfigGroup configGroup;
255 };
256 
257 FavoriteCollectionsModel::FavoriteCollectionsModel(QAbstractItemModel *source, const KConfigGroup &group, QObject *parent)
258  : Akonadi::SelectionProxyModel(new QItemSelectionModel(source, parent), parent)
259  , d(new Private(group, this))
260 {
261  //This should only be a KRecursiveFilterProxyModel, but remains a SelectionProxyModel for backwards compatiblity.
262  // We therefore disable what we anyways don't want (the referencing is handled separately).
263  disconnect(this, SIGNAL(rootIndexAdded(QModelIndex)), this, SLOT(rootIndexAdded(QModelIndex)));
264  disconnect(this, SIGNAL(rootIndexAboutToBeRemoved(QModelIndex)), this, SLOT(rootIndexAboutToBeRemoved(QModelIndex)));
265 
266  setSourceModel(source);
267  setFilterBehavior(ExactSelection);
268 
269  d->loadConfig();
270  //React to various changes in the source model
271  connect(source, SIGNAL(modelReset()), this, SLOT(reload()));
272  connect(source, SIGNAL(layoutChanged()), this, SLOT(reload()));
273  connect(source, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int)));
274 }
275 
276 FavoriteCollectionsModel::~FavoriteCollectionsModel()
277 {
278  delete d;
279 }
280 
281 void FavoriteCollectionsModel::setCollections(const Collection::List &collections)
282 {
283  d->set(collections);
284  d->saveConfig();
285 }
286 
287 void FavoriteCollectionsModel::addCollection(const Collection &collection)
288 {
289  d->add(collection.id());
290  d->saveConfig();
291 }
292 
293 void FavoriteCollectionsModel::removeCollection(const Collection &collection)
294 {
295  d->remove(collection.id());
296  d->saveConfig();
297 }
298 
299 Akonadi::Collection::List FavoriteCollectionsModel::collections() const
300 {
301  Collection::List cols;
302  foreach (const Collection::Id &colId, d->collectionIds) {
303  const QModelIndex idx = EntityTreeModel::modelIndexForCollection(sourceModel(), Collection(colId));
304  const Collection collection = sourceModel()->data(idx, EntityTreeModel::CollectionRole).value<Collection>();
305  cols << collection;
306  }
307  return cols;
308 }
309 
310 QList<Collection::Id> FavoriteCollectionsModel::collectionIds() const
311 {
312  return d->collectionIds;
313 }
314 
315 void Akonadi::FavoriteCollectionsModel::setFavoriteLabel(const Collection &collection, const QString &label)
316 {
317  Q_ASSERT(d->collectionIds.contains(collection.id()));
318  d->labelMap[collection.id()] = label;
319  d->saveConfig();
320 
321  const QModelIndex idx = EntityTreeModel::modelIndexForCollection(sourceModel(), collection);
322 
323  if (!idx.isValid()) {
324  return;
325  }
326 
327  const QModelIndex index = mapFromSource(idx);
328  emit dataChanged(index, index);
329 }
330 
331 QVariant Akonadi::FavoriteCollectionsModel::data(const QModelIndex &index, int role) const
332 {
333  if (index.column() == 0 &&
334  (role == Qt::DisplayRole ||
335  role == Qt::EditRole)) {
336  const QModelIndex sourceIndex = mapToSource(index);
337  const Collection::Id collectionId = sourceModel()->data(sourceIndex, EntityTreeModel::CollectionIdRole).toLongLong();
338 
339  return d->labelForCollection(collectionId);
340  } else {
341  return KSelectionProxyModel::data(index, role);
342  }
343 }
344 
345 bool FavoriteCollectionsModel::setData(const QModelIndex &index, const QVariant &value, int role)
346 {
347  if (index.isValid() && index.column() == 0 &&
348  role == Qt::EditRole) {
349  const QString newLabel = value.toString();
350  if (newLabel.isEmpty()) {
351  return false;
352  }
353  const QModelIndex sourceIndex = mapToSource(index);
354  const Collection collection = sourceModel()->data(sourceIndex, EntityTreeModel::CollectionRole).value<Collection>();
355  setFavoriteLabel(collection, newLabel);
356  return true;
357  }
358  return Akonadi::SelectionProxyModel::setData(index, value, role);
359 }
360 
361 QString Akonadi::FavoriteCollectionsModel::favoriteLabel(const Akonadi::Collection &collection)
362 {
363  if (!collection.isValid()) {
364  return QString();
365  }
366  return d->labelForCollection(collection.id());
367 }
368 
369 QVariant FavoriteCollectionsModel::headerData(int section, Qt::Orientation orientation, int role) const
370 {
371  if (section == 0 &&
372  orientation == Qt::Horizontal &&
373  role == Qt::DisplayRole) {
374  return i18n("Favorite Folders");
375  } else {
376  return KSelectionProxyModel::headerData(section, orientation, role);
377  }
378 }
379 
380 bool FavoriteCollectionsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
381 {
382  Q_UNUSED(action);
383  Q_UNUSED(row);
384  Q_UNUSED(column);
385  if (data->hasFormat(QLatin1String("text/uri-list"))) {
386  const KUrl::List urls = KUrl::List::fromMimeData(data);
387 
388  const QModelIndex sourceIndex = mapToSource(parent);
389  const Collection destCollection = sourceModel()->data(sourceIndex, EntityTreeModel::CollectionRole).value<Collection>();
390 
391  MimeTypeChecker mimeChecker;
392  mimeChecker.setWantedMimeTypes(destCollection.contentMimeTypes());
393 
394  foreach (const KUrl &url, urls) {
395  const Collection col = Collection::fromUrl(url);
396  if (col.isValid()) {
397  addCollection(col);
398  } else {
399  const Item item = Item::fromUrl(url);
400  if (item.isValid()) {
401  if (item.parentCollection().id() == destCollection.id() &&
402  action != Qt::CopyAction) {
403  kDebug() << "Error: source and destination of move are the same.";
404  return false;
405  }
406 #if 0
407  if (!mimeChecker.isWantedItem(item)) {
408  kDebug() << "unwanted item" << mimeChecker.wantedMimeTypes() << item.mimeType();
409  return false;
410  }
411 #endif
412  KJob *job = PasteHelper::pasteUriList(data, destCollection, action);
413  if (!job) {
414  return false;
415  }
416  connect(job, SIGNAL(result(KJob*)), SLOT(pasteJobDone(KJob*)));
417  // Accept the event so that it doesn't propagate.
418  return true;
419 
420  }
421  }
422 
423  }
424  return true;
425  }
426  return false;
427 }
428 
429 QStringList FavoriteCollectionsModel::mimeTypes() const
430 {
431  QStringList mts = Akonadi::SelectionProxyModel::mimeTypes();
432  if (!mts.contains(QLatin1String("text/uri-list"))) {
433  mts.append(QLatin1String("text/uri-list"));
434  }
435  return mts;
436 }
437 
438 Qt::ItemFlags FavoriteCollectionsModel::flags(const QModelIndex &index) const
439 {
440  Qt::ItemFlags fs = Akonadi::SelectionProxyModel::flags(index);
441  if (!index.isValid()) {
442  fs |= Qt::ItemIsDropEnabled;
443  }
444  return fs;
445 }
446 
447 void FavoriteCollectionsModel::pasteJobDone(KJob *job)
448 {
449  if (job->error()) {
450  kDebug() << job->errorString();
451  }
452 }
453 
454 #include "moc_favoritecollectionsmodel.cpp"
Akonadi::EntityTreeModel::CollectionIdRole
The collection id.
Definition: entitytreemodel.h:335
Akonadi::EntityTreeModel::CollectionRefRole
Definition: entitytreemodel.h:346
Akonadi::SelectionProxyModel
A proxy model used to reference count selected Akonadi::Collection in a view.
Definition: selectionproxymodel.h:99
Akonadi::Collection
Represents a collection of PIM items.
Definition: collection.h:75
Akonadi::FavoriteCollectionsModel::setCollections
void setCollections(const Collection::List &collections)
Sets the collections as favorite collections.
Definition: favoritecollectionsmodel.cpp:281
Akonadi::Entity::Id
qint64 Id
Describes the unique id type.
Definition: entity.h:65
Akonadi::PasteHelper::pasteUriList
KJob * pasteUriList(const QMimeData *mimeData, const Collection &collection, Qt::DropAction action, Session *session=0)
URI list paste/drop.
Definition: pastehelper.cpp:307
Akonadi::MimeTypeChecker
Helper for checking MIME types of Collections and Items.
Definition: mimetypechecker.h:109
Akonadi::FavoriteCollectionsModel::FavoriteCollectionsModel
FavoriteCollectionsModel(QAbstractItemModel *model, const KConfigGroup &group, QObject *parent=0)
Creates a new favorite collections model.
Definition: favoritecollectionsmodel.cpp:257
Akonadi::FavoriteCollectionsModel::setFavoriteLabel
void setFavoriteLabel(const Collection &collection, const QString &label)
Sets a custom label that will be used when showing the favorite collection.
Definition: favoritecollectionsmodel.cpp:315
Akonadi::FavoriteCollectionsModel::addCollection
void addCollection(const Collection &collection)
Adds a collection to the list of favorite collections.
Definition: favoritecollectionsmodel.cpp:287
Akonadi::EntityTreeModel::CollectionRole
The collection.
Definition: entitytreemodel.h:336
Akonadi::Entity::id
Id id() const
Returns the unique identifier of the entity.
Definition: entity.cpp:72
Akonadi::EntityTreeModel::modelIndexForCollection
static QModelIndex modelIndexForCollection(const QAbstractItemModel *model, const Collection &collection)
Returns a QModelIndex in model which points to collection.
Definition: entitytreemodel.cpp:1235
Akonadi::FavoriteCollectionsModel::collections
Collection::List collections() const
Returns the list of favorite collections.
Definition: favoritecollectionsmodel.cpp:299
Akonadi::FavoriteCollectionsModel::removeCollection
void removeCollection(const Collection &collection)
Removes a collection from the list of favorite collections.
Definition: favoritecollectionsmodel.cpp:293
Akonadi::MimeTypeChecker::setWantedMimeTypes
void setWantedMimeTypes(const QStringList &mimeTypes)
Sets the list of wanted MIME types this instance checks against.
Definition: mimetypechecker.cpp:57
Akonadi::FavoriteCollectionsModel::favoriteLabel
QString favoriteLabel(const Akonadi::Collection &col)
Return associate label for collection.
Definition: favoritecollectionsmodel.cpp:361
Akonadi::FavoriteCollectionsModel::~FavoriteCollectionsModel
virtual ~FavoriteCollectionsModel()
Destroys the favorite collections model.
Definition: favoritecollectionsmodel.cpp:276
Akonadi::Collection::contentMimeTypes
QStringList contentMimeTypes() const
Returns a list of possible content mimetypes, e.g.
Definition: collection.cpp:115
Akonadi::Entity::isValid
bool isValid() const
Returns whether the entity is valid.
Definition: entity.cpp:97
Akonadi::Collection::fromUrl
static Collection fromUrl(const KUrl &url)
Creates a collection from the given url.
Definition: collection.cpp:172
Akonadi::FavoriteCollectionsModel::collectionIds
QList< Collection::Id > collectionIds() const
Returns the list of ids of favorite collections set on the FavoriteCollectionsModel.
Definition: favoritecollectionsmodel.cpp:310
Akonadi::Collection::List
QList< Collection > List
Describes a list of collections.
Definition: collection.h:81
Akonadi::EntityTreeModel::CollectionDerefRole
Definition: entitytreemodel.h:347
Akonadi::FavoriteCollectionsModel
A model that lists a set of favorite collections.
Definition: favoritecollectionsmodel.h:66
This file is part of the KDE documentation.
Documentation copyright © 1996-2015 The KDE developers.
Generated on Fri Apr 10 2015 18:56:25 by doxygen 1.8.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.14.7 API Reference

Skip menu "kdepimlibs-4.14.7 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal