00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "itemmodel.h"
00021
00022 #include "itemfetchjob.h"
00023 #include "itemfetchscope.h"
00024 #include "monitor.h"
00025 #include "pastehelper.h"
00026 #include "session.h"
00027
00028 #include <kmime/kmime_message.h>
00029
00030 #include <kdebug.h>
00031 #include <klocale.h>
00032 #include <kurl.h>
00033
00034 #include <QCoreApplication>
00035 #include <QtCore/QDebug>
00036 #include <QtCore/QMimeData>
00037
00038 using namespace Akonadi;
00039
00048 struct ItemContainer
00049 {
00050 ItemContainer( const Item& i, int r )
00051 {
00052 item = i;
00053 row = r;
00054 }
00055 Item item;
00056 int row;
00057 };
00058
00062 class ItemModel::Private
00063 {
00064 public:
00065 Private( ItemModel *parent )
00066 : mParent( parent ), monitor( new Monitor() )
00067 {
00068 session = new Session( QCoreApplication::instance()->applicationName().toUtf8()
00069 + QByteArray("-ItemModel-") + QByteArray::number( qrand() ), mParent );
00070
00071 monitor->ignoreSession( session );
00072
00073 mParent->connect( monitor, SIGNAL(itemChanged( const Akonadi::Item&, const QSet<QByteArray>& )),
00074 mParent, SLOT(itemChanged( const Akonadi::Item&, const QSet<QByteArray>& )) );
00075 mParent->connect( monitor, SIGNAL(itemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& )),
00076 mParent, SLOT(itemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& ) ) );
00077 mParent->connect( monitor, SIGNAL(itemAdded( const Akonadi::Item&, const Akonadi::Collection& )),
00078 mParent, SLOT(itemAdded( const Akonadi::Item& )) );
00079 mParent->connect( monitor, SIGNAL(itemRemoved(Akonadi::Item)),
00080 mParent, SLOT(itemRemoved(Akonadi::Item)) );
00081 mParent->connect( monitor, SIGNAL(itemLinked(const Akonadi::Item&, const Akonadi::Collection&)),
00082 mParent, SLOT(itemAdded(const Akonadi::Item&)) );
00083 mParent->connect( monitor, SIGNAL(itemUnlinked(const Akonadi::Item&, const Akonadi::Collection&)),
00084 mParent, SLOT(itemRemoved(const Akonadi::Item&)) );
00085 }
00086
00087 ~Private()
00088 {
00089 delete monitor;
00090 }
00091
00092 void listingDone( KJob* );
00093 void itemChanged( const Akonadi::Item&, const QSet<QByteArray>& );
00094 void itemsAdded( const Akonadi::Item::List &list );
00095 void itemAdded( const Akonadi::Item &item );
00096 void itemMoved( const Akonadi::Item&, const Akonadi::Collection& src, const Akonadi::Collection& dst );
00097 void itemRemoved( const Akonadi::Item& );
00098 int rowForItem( const Akonadi::Item& );
00099
00100 ItemModel *mParent;
00101
00102 QList<ItemContainer*> items;
00103 QHash<Item, ItemContainer*> itemHash;
00104
00105 Collection collection;
00106 Monitor *monitor;
00107 Session *session;
00108 };
00109
00110 void ItemModel::Private::listingDone( KJob * job )
00111 {
00112 ItemFetchJob *fetch = static_cast<ItemFetchJob*>( job );
00113 Q_UNUSED( fetch );
00114 if ( job->error() ) {
00115
00116 kWarning( 5250 ) << "Item query failed:" << job->errorString();
00117 }
00118 }
00119
00120 int ItemModel::Private::rowForItem( const Akonadi::Item& item )
00121 {
00122 ItemContainer *container = itemHash.value( item );
00123 if ( !container )
00124 return -1;
00125
00126
00127
00128
00129
00130
00131 if ( container->row < items.count()
00132 && items.at( container->row ) == container )
00133 return container->row;
00134 else {
00135 int row = -1;
00136 for ( int i = 0; i < items.size(); ++i ) {
00137 if ( items.at( i )->item == item ) {
00138 row = i;
00139 break;
00140 }
00141 }
00142 return row;
00143 }
00144
00145 }
00146
00147 void ItemModel::Private::itemChanged( const Akonadi::Item &item, const QSet<QByteArray>& )
00148 {
00149 int row = rowForItem( item );
00150 if ( row < 0 )
00151 return;
00152
00153 items[ row ]->item = item;
00154 itemHash.remove( item );
00155 itemHash[ item ] = items[ row ];
00156
00157 QModelIndex start = mParent->index( row, 0, QModelIndex() );
00158 QModelIndex end = mParent->index( row, mParent->columnCount( QModelIndex() ) - 1 , QModelIndex() );
00159
00160 mParent->dataChanged( start, end );
00161 }
00162
00163 void ItemModel::Private::itemMoved( const Akonadi::Item &item, const Akonadi::Collection& colSrc, const Akonadi::Collection& colDst )
00164 {
00165 if ( colSrc == collection && colDst != collection )
00166 {
00167 itemRemoved( item );
00168 return;
00169 }
00170
00171
00172 if ( colDst == collection && colSrc != collection )
00173 {
00174 itemAdded( item );
00175 return;
00176 }
00177 }
00178
00179 void ItemModel::Private::itemsAdded( const Akonadi::Item::List &list )
00180 {
00181 if ( list.isEmpty() )
00182 return;
00183 mParent->beginInsertRows( QModelIndex(), items.count(), items.count() + list.count() - 1 );
00184 foreach( const Item &item, list ) {
00185 ItemContainer *c = new ItemContainer( item, items.count() );
00186 items.append( c );
00187 itemHash[ item ] = c;
00188 }
00189 mParent->endInsertRows();
00190 }
00191
00192 void ItemModel::Private::itemAdded( const Akonadi::Item &item )
00193 {
00194 Item::List l;
00195 l << item;
00196 itemsAdded( l );
00197 }
00198
00199 void ItemModel::Private::itemRemoved( const Akonadi::Item &_item )
00200 {
00201 int row = rowForItem( _item );
00202 if ( row < 0 )
00203 return;
00204
00205 mParent->beginRemoveRows( QModelIndex(), row, row );
00206 const Item item = items.at( row )->item;
00207 Q_ASSERT( item.isValid() );
00208 itemHash.remove( item );
00209 delete items.takeAt( row );
00210 mParent->endRemoveRows();
00211 }
00212
00213 ItemModel::ItemModel( QObject *parent ) :
00214 QAbstractTableModel( parent ),
00215 d( new Private( this ) )
00216 {
00217 setSupportedDragActions( Qt::MoveAction | Qt::CopyAction );
00218 }
00219
00220 ItemModel::~ItemModel()
00221 {
00222 delete d;
00223 }
00224
00225 QVariant ItemModel::data( const QModelIndex & index, int role ) const
00226 {
00227 if ( !index.isValid() )
00228 return QVariant();
00229 if ( index.row() >= d->items.count() )
00230 return QVariant();
00231 const Item item = d->items.at( index.row() )->item;
00232 if ( !item.isValid() )
00233 return QVariant();
00234
00235 if ( role == Qt::DisplayRole ) {
00236 switch ( index.column() ) {
00237 case Id:
00238 return QString::number( item.id() );
00239 case RemoteId:
00240 return item.remoteId();
00241 case MimeType:
00242 return item.mimeType();
00243 default:
00244 return QVariant();
00245 }
00246 }
00247
00248 if ( role == IdRole )
00249 return item.id();
00250
00251 if ( role == ItemRole ) {
00252 QVariant var;
00253 var.setValue( item );
00254 return var;
00255 }
00256
00257 if ( role == MimeTypeRole )
00258 return item.mimeType();
00259
00260 return QVariant();
00261 }
00262
00263 int ItemModel::rowCount( const QModelIndex & parent ) const
00264 {
00265 if ( !parent.isValid() )
00266 return d->items.count();
00267 return 0;
00268 }
00269
00270 int ItemModel::columnCount(const QModelIndex & parent) const
00271 {
00272 if ( !parent.isValid() )
00273 return 3;
00274 return 0;
00275 }
00276
00277 QVariant ItemModel::headerData( int section, Qt::Orientation orientation, int role ) const
00278 {
00279 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) {
00280 switch ( section ) {
00281 case Id:
00282 return i18n( "Id" );
00283 case RemoteId:
00284 return i18n( "Remote Id" );
00285 case MimeType:
00286 return i18n( "MimeType" );
00287 default:
00288 return QString();
00289 }
00290 }
00291 return QAbstractTableModel::headerData( section, orientation, role );
00292 }
00293
00294 void ItemModel::setCollection( const Collection &collection )
00295 {
00296 kDebug( 5250 );
00297 if ( d->collection == collection )
00298 return;
00299
00300 d->monitor->setCollectionMonitored( d->collection, false );
00301
00302 d->collection = collection;
00303
00304 d->monitor->setCollectionMonitored( d->collection, true );
00305
00306
00307 qDeleteAll( d->items );
00308 d->items.clear();
00309 reset();
00310
00311
00312 d->session->clear();
00313
00314
00315 ItemFetchJob* job = new ItemFetchJob( collection, session() );
00316 job->setFetchScope( d->monitor->itemFetchScope() );
00317 connect( job, SIGNAL(itemsReceived(Akonadi::Item::List)), SLOT(itemsAdded(Akonadi::Item::List)) );
00318 connect( job, SIGNAL(result(KJob*)), SLOT(listingDone(KJob*)) );
00319
00320 emit collectionChanged( collection );
00321 }
00322
00323 void ItemModel::setFetchScope( const ItemFetchScope &fetchScope )
00324 {
00325 d->monitor->setItemFetchScope( fetchScope );
00326 }
00327
00328 ItemFetchScope &ItemModel::fetchScope()
00329 {
00330 return d->monitor->itemFetchScope();
00331 }
00332
00333 Item ItemModel::itemForIndex( const QModelIndex & index ) const
00334 {
00335 if ( !index.isValid() )
00336 return Akonadi::Item();
00337
00338 if ( index.row() >= d->items.count() )
00339 return Akonadi::Item();
00340
00341 Item item = d->items.at( index.row() )->item;
00342 Q_ASSERT( item.isValid() );
00343
00344 return item;
00345 }
00346
00347 Qt::ItemFlags ItemModel::flags( const QModelIndex &index ) const
00348 {
00349 Qt::ItemFlags defaultFlags = QAbstractTableModel::flags(index);
00350
00351 if (index.isValid())
00352 return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
00353 else
00354 return Qt::ItemIsDropEnabled | defaultFlags;
00355 }
00356
00357 QStringList ItemModel::mimeTypes() const
00358 {
00359 return QStringList();
00360 }
00361
00362 Session * ItemModel::session() const
00363 {
00364 return d->session;
00365 }
00366
00367 QMimeData *ItemModel::mimeData( const QModelIndexList &indexes ) const
00368 {
00369 QMimeData *data = new QMimeData();
00370
00371 KUrl::List urls;
00372 foreach ( const QModelIndex &index, indexes ) {
00373 if ( index.column() != 0 )
00374 continue;
00375
00376 urls << itemForIndex( index ).url( Item::UrlWithMimeType );
00377 }
00378 urls.populateMimeData( data );
00379
00380 return data;
00381 }
00382
00383 QModelIndex ItemModel::indexForItem( const Akonadi::Item &item, const int column ) const
00384 {
00385 return index( d->rowForItem( item ), column );
00386 }
00387
00388 bool ItemModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent)
00389 {
00390 Q_UNUSED( row );
00391 Q_UNUSED( column );
00392 Q_UNUSED( parent );
00393 KJob* job = PasteHelper::paste( data, d->collection, action != Qt::MoveAction );
00394
00395 return job;
00396 }
00397
00398 Collection ItemModel::collection() const
00399 {
00400 return d->collection;
00401 }
00402
00403 #include "itemmodel.moc"