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

akonadi

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

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