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

akonadi

  • akonadi
itemmodel.cpp
1 /*
2  Copyright (c) 2006 - 2007 Volker Krause <vkrause@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 "itemmodel.h"
21 
22 #include "itemfetchjob.h"
23 #include "collectionfetchjob.h"
24 #include "itemfetchscope.h"
25 #include "monitor.h"
26 #include "pastehelper_p.h"
27 #include "session.h"
28 
29 #include <kdebug.h>
30 #include <klocalizedstring.h>
31 #include <kurl.h>
32 
33 #include <QCoreApplication>
34 #include <QtCore/QDebug>
35 #include <QtCore/QMimeData>
36 
37 using namespace Akonadi;
38 
47 struct ItemContainer
48 {
49  ItemContainer( const Item& i, int r )
50  : item( i ), row( r )
51  {
52  }
53  Item item;
54  int row;
55 };
56 
60 class ItemModel::Private
61 {
62  public:
63  Private( ItemModel *parent )
64  : mParent( parent ), monitor( new Monitor() )
65  {
66  session = new Session( QCoreApplication::instance()->applicationName().toUtf8()
67  + QByteArray( "-ItemModel-" ) + QByteArray::number( qrand() ), mParent );
68 
69  monitor->ignoreSession( session );
70 
71  mParent->connect( monitor, SIGNAL(itemChanged(Akonadi::Item,QSet<QByteArray>)),
72  mParent, SLOT(itemChanged(Akonadi::Item,QSet<QByteArray>)) );
73  mParent->connect( monitor, SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)),
74  mParent, SLOT(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)) );
75  mParent->connect( monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)),
76  mParent, SLOT(itemAdded(Akonadi::Item)) );
77  mParent->connect( monitor, SIGNAL(itemRemoved(Akonadi::Item)),
78  mParent, SLOT(itemRemoved(Akonadi::Item)) );
79  mParent->connect( monitor, SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection)),
80  mParent, SLOT(itemAdded(Akonadi::Item)) );
81  mParent->connect( monitor, SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection)),
82  mParent, SLOT(itemRemoved(Akonadi::Item)) );
83  }
84 
85  ~Private()
86  {
87  delete monitor;
88  }
89 
90  void listingDone( KJob* );
91  void collectionFetchResult( KJob* );
92  void itemChanged( const Akonadi::Item&, const QSet<QByteArray>& );
93  void itemsAdded( const Akonadi::Item::List &list );
94  void itemAdded( const Akonadi::Item &item );
95  void itemMoved( const Akonadi::Item&, const Akonadi::Collection& src, const Akonadi::Collection& dst );
96  void itemRemoved( const Akonadi::Item& );
97  int rowForItem( const Akonadi::Item& );
98  bool collectionIsCompatible() const;
99 
100  ItemModel *mParent;
101 
102  QList<ItemContainer*> items;
103  QHash<Item, ItemContainer*> itemHash;
104 
105  Collection collection;
106  Monitor *monitor;
107  Session *session;
108 };
109 
110 bool ItemModel::Private::collectionIsCompatible() const
111 {
112  // in the generic case, we show any collection
113  if ( mParent->mimeTypes() == QStringList( QLatin1String( "text/uri-list" ) ) )
114  return true;
115  // if the model's mime types are more specific, limit to those
116  // collections that have matching types
117  Q_FOREACH( const QString &type, mParent->mimeTypes() ) {
118  if ( collection.contentMimeTypes().contains( type ) ) {
119  return true;
120  }
121  }
122  return false;
123 }
124 
125 void ItemModel::Private::listingDone( KJob * job )
126 {
127  ItemFetchJob *fetch = static_cast<ItemFetchJob*>( job );
128  Q_UNUSED( fetch );
129  if ( job->error() ) {
130  // TODO
131  kWarning() << "Item query failed:" << job->errorString();
132  }
133 }
134 
135 void ItemModel::Private::collectionFetchResult( KJob * job )
136 {
137  CollectionFetchJob *fetch = static_cast<CollectionFetchJob*>( job );
138 
139  if ( fetch->collections().isEmpty() )
140  return;
141 
142  Q_ASSERT( fetch->collections().count() == 1 ); // we only listed base
143  Collection c = fetch->collections().first();
144  // avoid recursion, if this fails for some reason
145  if ( !c.contentMimeTypes().isEmpty() ) {
146  mParent->setCollection(c);
147  } else {
148  kWarning() << "Failed to retrieve the contents mime type of the collection: " << c;
149  mParent->setCollection(Collection());
150  }
151 }
152 
153 int ItemModel::Private::rowForItem( const Akonadi::Item& item )
154 {
155  ItemContainer *container = itemHash.value( item );
156  if ( !container )
157  return -1;
158 
159  /* Try to find the item directly;
160 
161  If items have been removed, this first try won't succeed because
162  the ItemContainer rows have not been updated (costs too much).
163  */
164  if ( container->row < items.count()
165  && items.at( container->row ) == container )
166  return container->row;
167  else { // Slow solution if the fist one has not succeeded
168  int row = -1;
169  const int numberOfItems( items.size() );
170  for ( int i = 0; i < numberOfItems; ++i ) {
171  if ( items.at( i )->item == item ) {
172  row = i;
173  break;
174  }
175  }
176  return row;
177  }
178 
179 }
180 
181 void ItemModel::Private::itemChanged( const Akonadi::Item &item, const QSet<QByteArray>& )
182 {
183  int row = rowForItem( item );
184  if ( row < 0 )
185  return;
186 
187  items[ row ]->item = item;
188  itemHash.remove( item );
189  itemHash[ item ] = items[ row ];
190 
191  QModelIndex start = mParent->index( row, 0, QModelIndex() );
192  QModelIndex end = mParent->index( row, mParent->columnCount( QModelIndex() ) - 1 , QModelIndex() );
193 
194  mParent->dataChanged( start, end );
195 }
196 
197 void ItemModel::Private::itemMoved( const Akonadi::Item &item, const Akonadi::Collection& colSrc, const Akonadi::Collection& colDst )
198 {
199  if ( colSrc == collection && colDst != collection ) // item leaving this model
200  {
201  itemRemoved( item );
202  return;
203  }
204 
205  if ( colDst == collection && colSrc != collection )
206  {
207  itemAdded( item );
208  return;
209  }
210 }
211 
212 void ItemModel::Private::itemsAdded( const Akonadi::Item::List &list )
213 {
214  if ( list.isEmpty() )
215  return;
216  mParent->beginInsertRows( QModelIndex(), items.count(), items.count() + list.count() - 1 );
217  foreach ( const Item &item, list ) {
218  ItemContainer *c = new ItemContainer( item, items.count() );
219  items.append( c );
220  itemHash[ item ] = c;
221  }
222  mParent->endInsertRows();
223 }
224 
225 void ItemModel::Private::itemAdded( const Akonadi::Item &item )
226 {
227  Item::List l;
228  l << item;
229  itemsAdded( l );
230 }
231 
232 void ItemModel::Private::itemRemoved( const Akonadi::Item &_item )
233 {
234  int row = rowForItem( _item );
235  if ( row < 0 )
236  return;
237 
238  mParent->beginRemoveRows( QModelIndex(), row, row );
239  const Item item = items.at( row )->item;
240  Q_ASSERT( item.isValid() );
241  itemHash.remove( item );
242  delete items.takeAt( row );
243  mParent->endRemoveRows();
244 }
245 
246 ItemModel::ItemModel( QObject *parent ) :
247  QAbstractTableModel( parent ),
248  d( new Private( this ) )
249 {
250 }
251 
252 ItemModel::~ItemModel()
253 {
254  delete d;
255 }
256 
257 QVariant ItemModel::data( const QModelIndex & index, int role ) const
258 {
259  if ( !index.isValid() )
260  return QVariant();
261  if ( index.row() >= d->items.count() )
262  return QVariant();
263  const Item item = d->items.at( index.row() )->item;
264  if ( !item.isValid() )
265  return QVariant();
266 
267  if ( role == Qt::DisplayRole ) {
268  switch ( index.column() ) {
269  case Id:
270  return QString::number( item.id() );
271  case RemoteId:
272  return item.remoteId();
273  case MimeType:
274  return item.mimeType();
275  default:
276  return QVariant();
277  }
278  }
279 
280  if ( role == IdRole )
281  return item.id();
282 
283  if ( role == ItemRole ) {
284  QVariant var;
285  var.setValue( item );
286  return var;
287  }
288 
289  if ( role == MimeTypeRole )
290  return item.mimeType();
291 
292  return QVariant();
293 }
294 
295 int ItemModel::rowCount( const QModelIndex & parent ) const
296 {
297  if ( !parent.isValid() )
298  return d->items.count();
299  return 0;
300 }
301 
302 int ItemModel::columnCount(const QModelIndex & parent) const
303 {
304  if ( !parent.isValid() )
305  return 3; // keep in sync with Column enum
306  return 0;
307 }
308 
309 QVariant ItemModel::headerData( int section, Qt::Orientation orientation, int role ) const
310 {
311  if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) {
312  switch ( section ) {
313  case Id:
314  return i18n( "Id" );
315  case RemoteId:
316  return i18n( "Remote Id" );
317  case MimeType:
318  return i18n( "MimeType" );
319  default:
320  return QString();
321  }
322  }
323  return QAbstractTableModel::headerData( section, orientation, role );
324 }
325 
326 void ItemModel::setCollection( const Collection &collection )
327 {
328  kDebug();
329  if ( d->collection == collection )
330  return;
331 
332  // if we don't know anything about this collection yet, fetch it
333  if ( collection.isValid() && collection.contentMimeTypes().isEmpty() )
334  {
335  CollectionFetchJob* job = new CollectionFetchJob( collection, CollectionFetchJob::Base, this );
336  connect( job, SIGNAL(result(KJob*)), this, SLOT(collectionFetchResult(KJob*)) );
337  return;
338  }
339 
340  d->monitor->setCollectionMonitored( d->collection, false );
341 
342  d->collection = collection;
343 
344  d->monitor->setCollectionMonitored( d->collection, true );
345 
346  // the query changed, thus everything we have already is invalid
347  qDeleteAll( d->items );
348  d->items.clear();
349  reset();
350 
351  // stop all running jobs
352  d->session->clear();
353 
354  // start listing job
355  if ( d->collectionIsCompatible() ) {
356  ItemFetchJob* job = new ItemFetchJob( collection, session() );
357  job->setFetchScope( d->monitor->itemFetchScope() );
358  connect( job, SIGNAL(itemsReceived(Akonadi::Item::List)),
359  SLOT(itemsAdded(Akonadi::Item::List)) );
360  connect( job, SIGNAL(result(KJob*)), SLOT(listingDone(KJob*)) );
361  }
362 
363  emit collectionChanged( collection );
364 }
365 
366 void ItemModel::setFetchScope( const ItemFetchScope &fetchScope )
367 {
368  d->monitor->setItemFetchScope( fetchScope );
369 }
370 
371 ItemFetchScope &ItemModel::fetchScope()
372 {
373  return d->monitor->itemFetchScope();
374 }
375 
376 Item ItemModel::itemForIndex( const QModelIndex & index ) const
377 {
378  if ( !index.isValid() )
379  return Akonadi::Item();
380 
381  if ( index.row() >= d->items.count() )
382  return Akonadi::Item();
383 
384  Item item = d->items.at( index.row() )->item;
385  if ( item.isValid() ) {
386  return item;
387  } else {
388  return Akonadi::Item();
389  }
390 }
391 
392 Qt::ItemFlags ItemModel::flags( const QModelIndex &index ) const
393 {
394  Qt::ItemFlags defaultFlags = QAbstractTableModel::flags(index);
395 
396  if (index.isValid())
397  return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
398  else
399  return Qt::ItemIsDropEnabled | defaultFlags;
400 }
401 
402 QStringList ItemModel::mimeTypes() const
403 {
404  return QStringList() << QLatin1String( "text/uri-list" );
405 }
406 
407 Session * ItemModel::session() const
408 {
409  return d->session;
410 }
411 
412 QMimeData *ItemModel::mimeData( const QModelIndexList &indexes ) const
413 {
414  QMimeData *data = new QMimeData();
415  // Add item uri to the mimedata for dropping in external applications
416  KUrl::List urls;
417  foreach ( const QModelIndex &index, indexes ) {
418  if ( index.column() != 0 )
419  continue;
420 
421  urls << itemForIndex( index ).url( Item::UrlWithMimeType );
422  }
423  urls.populateMimeData( data );
424 
425  return data;
426 }
427 
428 QModelIndex ItemModel::indexForItem( const Akonadi::Item &item, const int column ) const
429 {
430  return index( d->rowForItem( item ), column );
431 }
432 
433 bool ItemModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent)
434 {
435  Q_UNUSED( row );
436  Q_UNUSED( column );
437  Q_UNUSED( parent );
438  KJob* job = PasteHelper::paste( data, d->collection, action != Qt::MoveAction );
439  // TODO: error handling
440  return job;
441 }
442 
443 Collection ItemModel::collection() const
444 {
445  return d->collection;
446 }
447 
448 Qt::DropActions ItemModel::supportedDropActions() const
449 {
450  return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
451 }
452 
453 #include "moc_itemmodel.cpp"
Akonadi::ItemModel::collectionChanged
void collectionChanged(const Akonadi::Collection &collection)
This signal is emitted whenever setCollection is called.
Akonadi::CollectionFetchJob::collections
Collection::List collections() const
Returns the list of fetched collection.
Definition: collectionfetchjob.cpp:179
Akonadi::ItemModel::session
Session * session() const
Returns the Session object used for all operations by this model.
Definition: itemmodel.cpp:407
Akonadi::Collection
Represents a collection of PIM items.
Definition: collection.h:75
Akonadi::PasteHelper::paste
KJob * paste(const QMimeData *mimeData, const Collection &collection, bool copy=true, Session *session=0)
Paste/drop the given mime data into the given collection.
Definition: pastehelper.cpp:91
Akonadi::ItemModel::fetchScope
ItemFetchScope & fetchScope()
Returns the item fetch scope.
Definition: itemmodel.cpp:371
Akonadi::CollectionFetchJob
Job that fetches collections from the Akonadi storage.
Definition: collectionfetchjob.h:53
Akonadi::CollectionFetchJob::Base
Only fetch the base collection.
Definition: collectionfetchjob.h:62
Akonadi::ItemModel::itemForIndex
Item itemForIndex(const QModelIndex &index) const
Returns the item at the given index.
Definition: itemmodel.cpp:376
Akonadi::ItemFetchJob::setFetchScope
void setFetchScope(ItemFetchScope &fetchScope)
Sets the item fetch scope.
Definition: itemfetchjob.cpp:259
Akonadi::ItemModel::IdRole
The id of the item.
Definition: itemmodel.h:74
Akonadi::ItemModel::MimeType
The item's mime type.
Definition: itemmodel.h:67
Akonadi::ItemModel
A table model for items.
Definition: itemmodel.h:56
Akonadi::ItemModel::RemoteId
The remote identifier.
Definition: itemmodel.h:66
Akonadi::ItemModel::Id
The unique id.
Definition: itemmodel.h:65
Akonadi::Session
A communication session with the Akonadi storage.
Definition: session.h:59
Akonadi::ItemModel::MimeTypeRole
The mime type of the item.
Definition: itemmodel.h:76
Akonadi::ItemFetchScope
Specifies which parts of an item should be fetched from the Akonadi storage.
Definition: itemfetchscope.h:68
Akonadi::ItemModel::setCollection
void setCollection(const Akonadi::Collection &collection)
Sets the collection the model should display.
Definition: itemmodel.cpp:326
Akonadi::ItemModel::ItemRole
The item object.
Definition: itemmodel.h:75
Akonadi::Monitor
Monitors an item or collection for changes.
Definition: monitor.h:75
Akonadi::ItemModel::setFetchScope
void setFetchScope(const ItemFetchScope &fetchScope)
Sets the item fetch scope.
Definition: itemmodel.cpp:366
Akonadi::ItemModel::indexForItem
QModelIndex indexForItem(const Akonadi::Item &item, const int column) const
Returns the model index for the given item, with the given column.
Definition: itemmodel.cpp:428
Akonadi::ItemFetchJob
Job that fetches items from the Akonadi storage.
Definition: itemfetchjob.h:82
Akonadi::Collection::contentMimeTypes
QStringList contentMimeTypes() const
Returns a list of possible content mimetypes, e.g.
Definition: collection.cpp:115
Akonadi::ItemModel::collection
Collection collection() const
Returns the collection being displayed in the model.
Definition: itemmodel.cpp:443
Akonadi::Entity::isValid
bool isValid() const
Returns whether the entity is valid.
Definition: entity.cpp:97
Akonadi::ItemModel::~ItemModel
virtual ~ItemModel()
Destroys the item model.
Definition: itemmodel.cpp:252
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Mon Jul 21 2014 08:03:53 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