20 #include "itemmodel.h"
22 #include "itemfetchjob.h"
23 #include "collectionfetchjob.h"
24 #include "itemfetchscope.h"
26 #include "pastehelper_p.h"
29 #include <kmime/kmime_message.h>
35 #include <QCoreApplication>
36 #include <QtCore/QDebug>
37 #include <QtCore/QMimeData>
39 using namespace Akonadi;
51 ItemContainer(
const Item& i,
int r )
62 class ItemModel::Private
65 Private( ItemModel *parent )
66 : mParent( parent ), monitor( new Monitor() )
68 session =
new Session( QCoreApplication::instance()->applicationName().toUtf8()
69 + QByteArray(
"-ItemModel-" ) + QByteArray::number( qrand() ), mParent );
71 monitor->ignoreSession( session );
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)) );
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;
104 QList<ItemContainer*> items;
105 QHash<Item, ItemContainer*> itemHash;
107 Collection collection;
112 bool ItemModel::Private::collectionIsCompatible()
const
115 if ( mParent->mimeTypes() == QStringList( QLatin1String(
"text/uri-list" ) ) )
119 Q_FOREACH(
const QString &type, mParent->mimeTypes() ) {
120 if ( collection.contentMimeTypes().contains( type ) ) {
127 void ItemModel::Private::listingDone( KJob * job )
129 ItemFetchJob *fetch =
static_cast<ItemFetchJob*
>( job );
131 if ( job->error() ) {
133 kWarning() <<
"Item query failed:" << job->errorString();
137 void ItemModel::Private::collectionFetchResult( KJob * job )
139 CollectionFetchJob *fetch =
static_cast<CollectionFetchJob*
>( job );
141 if ( fetch->collections().isEmpty() )
144 Q_ASSERT( fetch->collections().count() == 1 );
145 Collection c = fetch->collections().first();
147 if ( !c.contentMimeTypes().isEmpty() ) {
148 mParent->setCollection(c);
150 kWarning() <<
"Failed to retrieve the contents mime type of the collection: " << c;
151 mParent->setCollection(Collection());
155 int ItemModel::Private::rowForItem(
const Akonadi::Item& item )
157 ItemContainer *container = itemHash.value( item );
166 if ( container->row < items.count()
167 && items.at( container->row ) == container )
168 return container->row;
171 const int numberOfItems( items.size() );
172 for (
int i = 0; i < numberOfItems; ++i ) {
173 if ( items.at( i )->item == item ) {
183 void ItemModel::Private::itemChanged(
const Akonadi::Item &item,
const QSet<QByteArray>& )
185 int row = rowForItem( item );
189 items[ row ]->item = item;
190 itemHash.remove( item );
191 itemHash[ item ] = items[ row ];
193 QModelIndex start = mParent->index( row, 0, QModelIndex() );
194 QModelIndex end = mParent->index( row, mParent->columnCount( QModelIndex() ) - 1 , QModelIndex() );
196 mParent->dataChanged( start, end );
199 void ItemModel::Private::itemMoved(
const Akonadi::Item &item,
const Akonadi::Collection& colSrc,
const Akonadi::Collection& colDst )
201 if ( colSrc == collection && colDst != collection )
208 if ( colDst == collection && colSrc != collection )
215 void ItemModel::Private::itemsAdded(
const Akonadi::Item::List &list )
217 if ( list.isEmpty() )
219 mParent->beginInsertRows( QModelIndex(), items.count(), items.count() + list.count() - 1 );
220 foreach (
const Item &item, list ) {
221 ItemContainer *c =
new ItemContainer( item, items.count() );
223 itemHash[ item ] = c;
225 mParent->endInsertRows();
228 void ItemModel::Private::itemAdded(
const Akonadi::Item &item )
235 void ItemModel::Private::itemRemoved(
const Akonadi::Item &_item )
237 int row = rowForItem( _item );
241 mParent->beginRemoveRows( QModelIndex(), row, row );
242 const Item item = items.at( row )->item;
243 Q_ASSERT( item.isValid() );
244 itemHash.remove( item );
245 delete items.takeAt( row );
246 mParent->endRemoveRows();
249 ItemModel::ItemModel( QObject *parent ) :
250 QAbstractTableModel( parent ),
251 d( new Private( this ) )
255 ItemModel::~ItemModel()
260 QVariant ItemModel::data(
const QModelIndex & index,
int role )
const
262 if ( !index.isValid() )
264 if ( index.row() >= d->items.count() )
266 const Item item = d->items.at( index.row() )->item;
267 if ( !item.isValid() )
270 if ( role == Qt::DisplayRole ) {
271 switch ( index.column() ) {
273 return QString::number( item.id() );
275 return item.remoteId();
277 return item.mimeType();
283 if ( role == IdRole )
286 if ( role == ItemRole ) {
288 var.setValue( item );
292 if ( role == MimeTypeRole )
293 return item.mimeType();
298 int ItemModel::rowCount(
const QModelIndex & parent )
const
300 if ( !parent.isValid() )
301 return d->items.count();
305 int ItemModel::columnCount(
const QModelIndex & parent)
const
307 if ( !parent.isValid() )
312 QVariant ItemModel::headerData(
int section, Qt::Orientation orientation,
int role )
const
314 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) {
319 return i18n(
"Remote Id" );
321 return i18n(
"MimeType" );
326 return QAbstractTableModel::headerData( section, orientation, role );
329 void ItemModel::setCollection(
const Collection &collection )
332 if ( d->collection == collection )
336 if ( collection.isValid() && collection.contentMimeTypes().isEmpty() )
338 CollectionFetchJob* job =
new CollectionFetchJob( collection, CollectionFetchJob::Base,
this );
339 connect( job, SIGNAL(result(KJob*)),
this, SLOT(collectionFetchResult(KJob*)) );
343 d->monitor->setCollectionMonitored( d->collection,
false );
345 d->collection = collection;
347 d->monitor->setCollectionMonitored( d->collection,
true );
350 qDeleteAll( d->items );
358 if ( d->collectionIsCompatible() ) {
359 ItemFetchJob* job =
new ItemFetchJob( collection, session() );
360 job->setFetchScope( d->monitor->itemFetchScope() );
361 connect( job, SIGNAL(itemsReceived(Akonadi::Item::List)),
362 SLOT(itemsAdded(Akonadi::Item::List)) );
363 connect( job, SIGNAL(result(KJob*)), SLOT(listingDone(KJob*)) );
366 emit collectionChanged( collection );
369 void ItemModel::setFetchScope(
const ItemFetchScope &fetchScope )
371 d->monitor->setItemFetchScope( fetchScope );
374 ItemFetchScope &ItemModel::fetchScope()
376 return d->monitor->itemFetchScope();
379 Item ItemModel::itemForIndex(
const QModelIndex & index )
const
381 if ( !index.isValid() )
382 return Akonadi::Item();
384 if ( index.row() >= d->items.count() )
385 return Akonadi::Item();
387 Item item = d->items.at( index.row() )->item;
388 if ( item.isValid() ) {
391 return Akonadi::Item();
395 Qt::ItemFlags ItemModel::flags(
const QModelIndex &index )
const
397 Qt::ItemFlags defaultFlags = QAbstractTableModel::flags(index);
400 return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
402 return Qt::ItemIsDropEnabled | defaultFlags;
405 QStringList ItemModel::mimeTypes()
const
407 return QStringList() << QLatin1String(
"text/uri-list" );
410 Session * ItemModel::session()
const
415 QMimeData *ItemModel::mimeData(
const QModelIndexList &indexes )
const
417 QMimeData *data =
new QMimeData();
420 foreach (
const QModelIndex &index, indexes ) {
421 if ( index.column() != 0 )
424 urls << itemForIndex( index ).url( Item::UrlWithMimeType );
426 urls.populateMimeData( data );
431 QModelIndex ItemModel::indexForItem(
const Akonadi::Item &item,
const int column )
const
433 return index( d->rowForItem( item ), column );
436 bool ItemModel::dropMimeData(
const QMimeData * data, Qt::DropAction action,
int row,
int column,
const QModelIndex & parent)
446 Collection ItemModel::collection()
const
448 return d->collection;
451 Qt::DropActions ItemModel::supportedDropActions()
const
453 return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
457 #include "itemmodel.moc"