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

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