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

akonadi

  • sources
  • kde-4.14
  • kdepimlibs
  • 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(EntityTreeModel::OriginalCollectionNameRole).toString();
64  idx = idx.parent();
65  }
66  if (accountName.isEmpty()) {
67  return nameOfCollection;
68  } else {
69  return nameOfCollection + QLatin1String(" (") + accountName + QLatin1Char(')');
70  }
71  }
72 
73  void insertIfAvailable(Collection::Id col)
74  {
75  if (collectionIds.contains(col)) {
76  select(col);
77  }
78  }
79 
80  void insertIfAvailable(const QModelIndex &idx)
81  {
82  insertIfAvailable(idx.data(EntityTreeModel::CollectionIdRole).value<Collection::Id>());
83  }
84 
88  void reload()
89  {
90  //don't clear the selection model here. Otherwise we mess up the users selection as collections get removed and re-inserted.
91  foreach (const Collection::Id &collectionId, collectionIds) {
92  insertIfAvailable(collectionId);
93  }
94  //TODO remove what's no longer here
95  }
96 
97  void rowsInserted(const QModelIndex &parent, int begin, int end)
98  {
99  for (int row = begin; row <= end; row++) {
100  const QModelIndex child = parent.child(row, 0);
101  if (!child.isValid()) {
102  continue;
103  }
104  insertIfAvailable(child);
105  const int childRows = q->sourceModel()->rowCount(child);
106  if (childRows > 0) {
107  rowsInserted(child, 0, childRows - 1);
108  }
109  }
110  }
111 
115  void select(const Collection::Id &collectionId)
116  {
117  const QModelIndex index = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId));
118  if (index.isValid() && !q->selectionModel()->isSelected(index)) {
119  q->selectionModel()->select(index, QItemSelectionModel::Select);
120  if (!referencedCollections.contains(collectionId)) {
121  reference(collectionId);
122  }
123  }
124  }
125 
126  void deselect(const Collection::Id &collectionId)
127  {
128  const QModelIndex idx = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId));
129  if (idx.isValid()) {
130  q->selectionModel()->select(idx, QItemSelectionModel::Deselect);
131  if (referencedCollections.contains(collectionId)) {
132  dereference(collectionId);
133  }
134  }
135  }
136 
137  void reference(const Collection::Id &collectionId)
138  {
139  if (referencedCollections.contains(collectionId)) {
140  kWarning() << "already referenced" << collectionId;
141  return;
142  }
143  const QModelIndex index = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId));
144  if (index.isValid()) {
145  if (q->sourceModel()->setData(index, QVariant(), EntityTreeModel::CollectionRefRole)) {
146  referencedCollections << collectionId;
147  } else {
148  kWarning() << "failed to reference collection";
149  }
150  q->sourceModel()->fetchMore(index);
151  }
152  }
153 
154  void dereference(const Collection::Id &collectionId)
155  {
156  if (!referencedCollections.contains(collectionId)) {
157  kWarning() << "not referenced" << collectionId;
158  return;
159  }
160  const QModelIndex index = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId));
161  if (index.isValid()) {
162  q->sourceModel()->setData(index, QVariant(), EntityTreeModel::CollectionDerefRole);
163  }
164  referencedCollections.remove(collectionId);
165  }
166 
167  void clearReferences()
168  {
169  foreach (const Collection::Id &collectionId, referencedCollections) {
170  dereference(collectionId);
171  }
172  }
173 
177  void add(const Collection::Id &collectionId)
178  {
179  if (collectionIds.contains(collectionId)) {
180  kDebug() << "already in model " << collectionId;
181  return;
182  }
183  collectionIds << collectionId;
184  select(collectionId);
185  }
186 
187  void remove(const Collection::Id &collectionId)
188  {
189  collectionIds.removeAll(collectionId);
190  labelMap.remove(collectionId);
191  deselect(collectionId);
192  }
193 
194  void set(const QList<Collection::Id> &collections)
195  {
196  QList<Collection::Id> colIds = collectionIds;
197  foreach (const Collection::Id &col, collections) {
198  const int removed = colIds.removeAll(col);
199  const bool isNewCollection = removed <= 0;
200  if (isNewCollection) {
201  add(col);
202  }
203  }
204  //Remove what's left
205  foreach (const Akonadi::Collection::Id &colId, colIds) {
206  remove(colId);
207  }
208  }
209 
210  void set(const Akonadi::Collection::List &collections)
211  {
212  QList<Akonadi::Collection::Id> colIds;
213  foreach (const Akonadi::Collection &col, collections) {
214  colIds << col.id();
215  }
216  set(colIds);
217  }
218 
219  void loadConfig()
220  {
221  const QList<Collection::Id> collections = configGroup.readEntry("FavoriteCollectionIds", QList<qint64>());
222  const QStringList labels = configGroup.readEntry("FavoriteCollectionLabels", QStringList());
223  const int numberOfLabels(labels.size());
224  for (int i = 0; i < collections.size(); ++i) {
225  if (i < numberOfLabels) {
226  labelMap[collections[i]] = labels[i];
227  }
228  add(collections[i]);
229  }
230  }
231 
232  void saveConfig()
233  {
234  QStringList labels;
235  QList<Collection::Id> ids;
236  foreach (const Collection::Id &collectionId, collectionIds) {
237  const QModelIndex idx = EntityTreeModel::modelIndexForCollection(q->sourceModel(), Collection(collectionId));
238  if (idx.isValid()) {
239  labels << labelForCollection(collectionId);
240  ids << collectionId;
241  }
242  }
243  configGroup.writeEntry("FavoriteCollectionIds", ids);
244  configGroup.writeEntry("FavoriteCollectionLabels", labels);
245  configGroup.config()->sync();
246  }
247 
248  FavoriteCollectionsModel *const q;
249 
250  QList<Collection::Id> collectionIds;
251  QSet<Collection::Id> referencedCollections;
252  QHash<qint64, QString> labelMap;
253  KConfigGroup configGroup;
254 };
255 
256 FavoriteCollectionsModel::FavoriteCollectionsModel(QAbstractItemModel *source, const KConfigGroup &group, QObject *parent)
257  : Akonadi::SelectionProxyModel(new QItemSelectionModel(source, parent), parent)
258  , d(new Private(group, this))
259 {
260  //This should only be a KRecursiveFilterProxyModel, but remains a SelectionProxyModel for backwards compatiblity.
261  // We therefore disable what we anyways don't want (the referencing is handled separately).
262  disconnect(this, SIGNAL(rootIndexAdded(QModelIndex)), this, SLOT(rootIndexAdded(QModelIndex)));
263  disconnect(this, SIGNAL(rootIndexAboutToBeRemoved(QModelIndex)), this, SLOT(rootIndexAboutToBeRemoved(QModelIndex)));
264 
265  setSourceModel(source);
266  setFilterBehavior(ExactSelection);
267 
268  d->loadConfig();
269  //React to various changes in the source model
270  connect(source, SIGNAL(modelReset()), this, SLOT(reload()));
271  connect(source, SIGNAL(layoutChanged()), this, SLOT(reload()));
272  connect(source, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int)));
273 }
274 
275 FavoriteCollectionsModel::~FavoriteCollectionsModel()
276 {
277  delete d;
278 }
279 
280 void FavoriteCollectionsModel::setCollections(const Collection::List &collections)
281 {
282  d->set(collections);
283  d->saveConfig();
284 }
285 
286 void FavoriteCollectionsModel::addCollection(const Collection &collection)
287 {
288  d->add(collection.id());
289  d->saveConfig();
290 }
291 
292 void FavoriteCollectionsModel::removeCollection(const Collection &collection)
293 {
294  d->remove(collection.id());
295  d->saveConfig();
296 }
297 
298 Akonadi::Collection::List FavoriteCollectionsModel::collections() const
299 {
300  Collection::List cols;
301  foreach (const Collection::Id &colId, d->collectionIds) {
302  const QModelIndex idx = EntityTreeModel::modelIndexForCollection(sourceModel(), Collection(colId));
303  const Collection collection = sourceModel()->data(idx, EntityTreeModel::CollectionRole).value<Collection>();
304  cols << collection;
305  }
306  return cols;
307 }
308 
309 QList<Collection::Id> FavoriteCollectionsModel::collectionIds() const
310 {
311  return d->collectionIds;
312 }
313 
314 void Akonadi::FavoriteCollectionsModel::setFavoriteLabel(const Collection &collection, const QString &label)
315 {
316  Q_ASSERT(d->collectionIds.contains(collection.id()));
317  d->labelMap[collection.id()] = label;
318  d->saveConfig();
319 
320  const QModelIndex idx = EntityTreeModel::modelIndexForCollection(sourceModel(), collection);
321 
322  if (!idx.isValid()) {
323  return;
324  }
325 
326  const QModelIndex index = mapFromSource(idx);
327  emit dataChanged(index, index);
328 }
329 
330 QVariant Akonadi::FavoriteCollectionsModel::data(const QModelIndex &index, int role) const
331 {
332  if (index.column() == 0 &&
333  (role == Qt::DisplayRole ||
334  role == Qt::EditRole)) {
335  const QModelIndex sourceIndex = mapToSource(index);
336  const Collection::Id collectionId = sourceModel()->data(sourceIndex, EntityTreeModel::CollectionIdRole).toLongLong();
337 
338  return d->labelForCollection(collectionId);
339  } else {
340  return KSelectionProxyModel::data(index, role);
341  }
342 }
343 
344 bool FavoriteCollectionsModel::setData(const QModelIndex &index, const QVariant &value, int role)
345 {
346  if (index.isValid() && index.column() == 0 &&
347  role == Qt::EditRole) {
348  const QString newLabel = value.toString();
349  if (newLabel.isEmpty()) {
350  return false;
351  }
352  const QModelIndex sourceIndex = mapToSource(index);
353  const Collection collection = sourceModel()->data(sourceIndex, EntityTreeModel::CollectionRole).value<Collection>();
354  setFavoriteLabel(collection, newLabel);
355  return true;
356  }
357  return Akonadi::SelectionProxyModel::setData(index, value, role);
358 }
359 
360 QString Akonadi::FavoriteCollectionsModel::favoriteLabel(const Akonadi::Collection &collection)
361 {
362  if (!collection.isValid()) {
363  return QString();
364  }
365  return d->labelForCollection(collection.id());
366 }
367 
368 QVariant FavoriteCollectionsModel::headerData(int section, Qt::Orientation orientation, int role) const
369 {
370  if (section == 0 &&
371  orientation == Qt::Horizontal &&
372  role == Qt::DisplayRole) {
373  return i18n("Favorite Folders");
374  } else {
375  return KSelectionProxyModel::headerData(section, orientation, role);
376  }
377 }
378 
379 bool FavoriteCollectionsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
380 {
381  Q_UNUSED(action);
382  Q_UNUSED(row);
383  Q_UNUSED(column);
384  if (data->hasFormat(QLatin1String("text/uri-list"))) {
385  const KUrl::List urls = KUrl::List::fromMimeData(data);
386 
387  const QModelIndex sourceIndex = mapToSource(parent);
388  const Collection destCollection = sourceModel()->data(sourceIndex, EntityTreeModel::CollectionRole).value<Collection>();
389 
390  MimeTypeChecker mimeChecker;
391  mimeChecker.setWantedMimeTypes(destCollection.contentMimeTypes());
392 
393  foreach (const KUrl &url, urls) {
394  const Collection col = Collection::fromUrl(url);
395  if (col.isValid()) {
396  addCollection(col);
397  } else {
398  const Item item = Item::fromUrl(url);
399  if (item.isValid()) {
400  if (item.parentCollection().id() == destCollection.id() &&
401  action != Qt::CopyAction) {
402  kDebug() << "Error: source and destination of move are the same.";
403  return false;
404  }
405 #if 0
406  if (!mimeChecker.isWantedItem(item)) {
407  kDebug() << "unwanted item" << mimeChecker.wantedMimeTypes() << item.mimeType();
408  return false;
409  }
410 #endif
411  KJob *job = PasteHelper::pasteUriList(data, destCollection, action);
412  if (!job) {
413  return false;
414  }
415  connect(job, SIGNAL(result(KJob*)), SLOT(pasteJobDone(KJob*)));
416  // Accept the event so that it doesn't propagate.
417  return true;
418 
419  }
420  }
421 
422  }
423  return true;
424  }
425  return false;
426 }
427 
428 QStringList FavoriteCollectionsModel::mimeTypes() const
429 {
430  QStringList mts = Akonadi::SelectionProxyModel::mimeTypes();
431  if (!mts.contains(QLatin1String("text/uri-list"))) {
432  mts.append(QLatin1String("text/uri-list"));
433  }
434  return mts;
435 }
436 
437 Qt::ItemFlags FavoriteCollectionsModel::flags(const QModelIndex &index) const
438 {
439  Qt::ItemFlags fs = Akonadi::SelectionProxyModel::flags(index);
440  if (!index.isValid()) {
441  fs |= Qt::ItemIsDropEnabled;
442  }
443  return fs;
444 }
445 
446 void FavoriteCollectionsModel::pasteJobDone(KJob *job)
447 {
448  if (job->error()) {
449  kDebug() << job->errorString();
450  }
451 }
452 
453 #include "moc_favoritecollectionsmodel.cpp"
QModelIndex
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
QMimeData::hasFormat
virtual bool hasFormat(const QString &mimeType) const
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:280
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const
Akonadi::Entity::Id
qint64 Id
Describes the unique id type.
Definition: entity.h:65
QVariant::value
T value() const
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:256
QMimeData
QList::size
int size() const
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:314
QModelIndex::isValid
bool isValid() const
QList::append
void append(const T &value)
QHash< qint64, QString >
QObject
QString::isEmpty
bool isEmpty() const
QList::removeAll
int removeAll(const T &value)
Akonadi::FavoriteCollectionsModel::addCollection
void addCollection(const Collection &collection)
Adds a collection to the list of favorite collections.
Definition: favoritecollectionsmodel.cpp:286
QSet
Definition: itemfetchscope.h:29
Akonadi::EntityTreeModel::CollectionRole
The collection.
Definition: entitytreemodel.h:336
QString
QList
QModelIndex::parent
QModelIndex parent() const
Akonadi::Entity::id
Id id() const
Returns the unique identifier of the entity.
Definition: entity.cpp:72
QStringList
Akonadi::EntityTreeModel::modelIndexForCollection
static QModelIndex modelIndexForCollection(const QAbstractItemModel *model, const Collection &collection)
Returns a QModelIndex in model which points to collection.
Definition: entitytreemodel.cpp:1238
QLatin1Char
Akonadi::FavoriteCollectionsModel::collections
Collection::List collections() const
Returns the list of favorite collections.
Definition: favoritecollectionsmodel.cpp:298
Akonadi::EntityTreeModel::OriginalCollectionNameRole
Returns original name for collection.
Definition: entitytreemodel.h:354
Akonadi::FavoriteCollectionsModel::removeCollection
void removeCollection(const Collection &collection)
Removes a collection from the list of favorite collections.
Definition: favoritecollectionsmodel.cpp:292
QModelIndex::child
QModelIndex child(int row, int column) const
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:360
QModelIndex::data
QVariant data(int role) const
QLatin1String
Akonadi::FavoriteCollectionsModel::~FavoriteCollectionsModel
virtual ~FavoriteCollectionsModel()
Destroys the favorite collections model.
Definition: favoritecollectionsmodel.cpp:275
QModelIndex::column
int column() const
Akonadi::Collection::contentMimeTypes
QStringList contentMimeTypes() const
Returns a list of possible content mimetypes, e.g.
Definition: collection.cpp:115
QAbstractItemModel
Akonadi::Entity::isValid
bool isValid() const
Returns whether the entity is valid.
Definition: entity.cpp:97
QItemSelectionModel
Akonadi::Collection::fromUrl
static Collection fromUrl(const KUrl &url)
Creates a collection from the given url.
Definition: collection.cpp:172
QString::data
QChar * data()
QVariant::toString
QString toString() const
Akonadi::FavoriteCollectionsModel::collectionIds
QList< Collection::Id > collectionIds() const
Returns the list of ids of favorite collections set on the FavoriteCollectionsModel.
Definition: favoritecollectionsmodel.cpp:309
Akonadi::EntityTreeModel::CollectionDerefRole
Definition: entitytreemodel.h:347
Akonadi::FavoriteCollectionsModel
A model that lists a set of favorite collections.
Definition: favoritecollectionsmodel.h:66
QVariant
Qt::ItemFlags
typedef ItemFlags
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:38:03 by doxygen 1.8.7 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 API Reference

Skip menu "kdepimlibs 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

Search



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