• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.10 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
35using namespace Akonadi;
36
40class FavoriteCollectionsModel::Private
41{
42public:
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
256FavoriteCollectionsModel::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
275FavoriteCollectionsModel::~FavoriteCollectionsModel()
276{
277 delete d;
278}
279
280void FavoriteCollectionsModel::setCollections(const Collection::List &collections)
281{
282 d->set(collections);
283 d->saveConfig();
284}
285
286void FavoriteCollectionsModel::addCollection(const Collection &collection)
287{
288 d->add(collection.id());
289 d->saveConfig();
290}
291
292void FavoriteCollectionsModel::removeCollection(const Collection &collection)
293{
294 d->remove(collection.id());
295 d->saveConfig();
296}
297
298Akonadi::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
309QList<Collection::Id> FavoriteCollectionsModel::collectionIds() const
310{
311 return d->collectionIds;
312}
313
314void 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
330QVariant 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
344bool 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
360QString Akonadi::FavoriteCollectionsModel::favoriteLabel(const Akonadi::Collection &collection)
361{
362 if (!collection.isValid()) {
363 return QString();
364 }
365 return d->labelForCollection(collection.id());
366}
367
368QVariant 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
379bool 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
428QStringList 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
437Qt::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
446void FavoriteCollectionsModel::pasteJobDone(KJob *job)
447{
448 if (job->error()) {
449 kDebug() << job->errorString();
450 }
451}
452
453#include "moc_favoritecollectionsmodel.cpp"
Akonadi::Collection
Represents a collection of PIM items.
Definition collection.h:76
Akonadi::Collection::contentMimeTypes
QStringList contentMimeTypes() const
Returns a list of possible content mimetypes, e.g.
Definition collection.cpp:115
Akonadi::Collection::List
QList< Collection > List
Describes a list of collections.
Definition collection.h:81
Akonadi::Collection::fromUrl
static Collection fromUrl(const KUrl &url)
Creates a collection from the given url.
Definition collection.cpp:172
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
Akonadi::EntityTreeModel::CollectionDerefRole
@ CollectionDerefRole
Definition entitytreemodel.h:347
Akonadi::EntityTreeModel::OriginalCollectionNameRole
@ OriginalCollectionNameRole
Returns original name for collection.
Definition entitytreemodel.h:354
Akonadi::EntityTreeModel::CollectionRole
@ CollectionRole
The collection.
Definition entitytreemodel.h:336
Akonadi::EntityTreeModel::CollectionIdRole
@ CollectionIdRole
The collection id.
Definition entitytreemodel.h:335
Akonadi::EntityTreeModel::CollectionRefRole
@ CollectionRefRole
Definition entitytreemodel.h:346
Akonadi::Entity::isValid
bool isValid() const
Returns whether the entity is valid.
Definition entity.cpp:97
Akonadi::Entity::id
Id id() const
Returns the unique identifier of the entity.
Definition entity.cpp:72
Akonadi::Entity::Id
qint64 Id
Describes the unique id type.
Definition entity.h:65
Akonadi::FavoriteCollectionsModel
A model that lists a set of favorite collections.
Definition favoritecollectionsmodel.h:67
Akonadi::FavoriteCollectionsModel::collections
Collection::List collections() const
Returns the list of favorite collections.
Definition favoritecollectionsmodel.cpp:298
Akonadi::FavoriteCollectionsModel::favoriteLabel
QString favoriteLabel(const Akonadi::Collection &col)
Return associate label for collection.
Definition favoritecollectionsmodel.cpp:360
Akonadi::FavoriteCollectionsModel::FavoriteCollectionsModel
FavoriteCollectionsModel(QAbstractItemModel *model, const KConfigGroup &group, QObject *parent=0)
Creates a new favorite collections model.
Definition favoritecollectionsmodel.cpp:256
Akonadi::FavoriteCollectionsModel::addCollection
void addCollection(const Collection &collection)
Adds a collection to the list of favorite collections.
Definition favoritecollectionsmodel.cpp:286
Akonadi::FavoriteCollectionsModel::~FavoriteCollectionsModel
virtual ~FavoriteCollectionsModel()
Destroys the favorite collections model.
Definition favoritecollectionsmodel.cpp:275
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::FavoriteCollectionsModel::removeCollection
void removeCollection(const Collection &collection)
Removes a collection from the list of favorite collections.
Definition favoritecollectionsmodel.cpp:292
Akonadi::FavoriteCollectionsModel::setCollections
void setCollections(const Collection::List &collections)
Sets the collections as favorite collections.
Definition favoritecollectionsmodel.cpp:280
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
Akonadi::MimeTypeChecker
Helper for checking MIME types of Collections and Items.
Definition mimetypechecker.h:110
Akonadi::MimeTypeChecker::setWantedMimeTypes
void setWantedMimeTypes(const QStringList &mimeTypes)
Sets the list of wanted MIME types this instance checks against.
Definition mimetypechecker.cpp:57
Akonadi::SelectionProxyModel
A proxy model used to reference count selected Akonadi::Collection in a view.
Definition selectionproxymodel.h:100
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
FreeBusyManager::Singleton.
Definition actionstatemanager_p.h:28
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Wed Jan 24 2024 00:00:00 by doxygen 1.10.0 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
  • Related Pages

kdepimlibs-4.14.10 API Reference

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