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

akonadi

itemmodel.cpp
00001 /*
00002     Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or modify it
00005     under the terms of the GNU Library General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or (at your
00007     option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful, but WITHOUT
00010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00012     License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to the
00016     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301, USA.
00018 */
00019 
00020 #include "itemmodel.h"
00021 
00022 #include "itemfetchjob.h"
00023 #include "collectionfetchjob.h"
00024 #include "itemfetchscope.h"
00025 #include "monitor.h"
00026 #include "pastehelper_p.h"
00027 #include "session.h"
00028 
00029 #include <kmime/kmime_message.h>
00030 
00031 #include <kdebug.h>
00032 #include <klocale.h>
00033 #include <kurl.h>
00034 
00035 #include <QCoreApplication>
00036 #include <QtCore/QDebug>
00037 #include <QtCore/QMimeData>
00038 
00039 using namespace Akonadi;
00040 
00049 struct ItemContainer
00050 {
00051   ItemContainer( const Item& i, int r )
00052     : item( i ), row( r )
00053   {
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(Akonadi::Item,QSet<QByteArray>)),
00074                         mParent, SLOT(itemChanged(Akonadi::Item,QSet<QByteArray>)) );
00075       mParent->connect( monitor, SIGNAL(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)),
00076                         mParent, SLOT(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)) );
00077       mParent->connect( monitor, SIGNAL(itemAdded(Akonadi::Item,Akonadi::Collection)),
00078                         mParent, SLOT(itemAdded(Akonadi::Item)) );
00079       mParent->connect( monitor, SIGNAL(itemRemoved(Akonadi::Item)),
00080                         mParent, SLOT(itemRemoved(Akonadi::Item)) );
00081       mParent->connect( monitor, SIGNAL(itemLinked(Akonadi::Item,Akonadi::Collection)),
00082                         mParent, SLOT(itemAdded(Akonadi::Item)) );
00083       mParent->connect( monitor, SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection)),
00084                         mParent, SLOT(itemRemoved(Akonadi::Item)) );
00085     }
00086 
00087     ~Private()
00088     {
00089       delete monitor;
00090     }
00091 
00092     void listingDone( KJob* );
00093     void collectionFetchResult( KJob* );
00094     void itemChanged( const Akonadi::Item&, const QSet<QByteArray>& );
00095     void itemsAdded( const Akonadi::Item::List &list );
00096     void itemAdded( const Akonadi::Item &item );
00097     void itemMoved( const Akonadi::Item&, const Akonadi::Collection& src, const Akonadi::Collection& dst );
00098     void itemRemoved( const Akonadi::Item& );
00099     int rowForItem( const Akonadi::Item& );
00100     bool collectionIsCompatible() const;
00101 
00102     ItemModel *mParent;
00103 
00104     QList<ItemContainer*> items;
00105     QHash<Item, ItemContainer*> itemHash;
00106 
00107     Collection collection;
00108     Monitor *monitor;
00109     Session *session;
00110 };
00111 
00112 bool ItemModel::Private::collectionIsCompatible() const
00113 {
00114   // in the generic case, we show any collection
00115   if ( mParent->mimeTypes() == QStringList( QLatin1String( "text/uri-list" ) ) )
00116     return true;
00117   // if the model's mime types are more specific, limit to those
00118   // collections that have matching types
00119   Q_FOREACH( const QString &type, mParent->mimeTypes() ) {
00120     if ( collection.contentMimeTypes().contains( type ) ) {
00121       return true;
00122     }
00123   }
00124   return false;
00125 }
00126 
00127 void ItemModel::Private::listingDone( KJob * job )
00128 {
00129   ItemFetchJob *fetch = static_cast<ItemFetchJob*>( job );
00130   Q_UNUSED( fetch );
00131   if ( job->error() ) {
00132     // TODO
00133     kWarning() << "Item query failed:" << job->errorString();
00134   }
00135 }
00136 
00137 void ItemModel::Private::collectionFetchResult( KJob * job )
00138 {
00139   CollectionFetchJob *fetch = static_cast<CollectionFetchJob*>( job );
00140 
00141   if ( fetch->collections().isEmpty() )
00142     return;
00143 
00144   Q_ASSERT( fetch->collections().count() == 1 ); // we only listed base
00145   Collection c = fetch->collections().first();
00146    // avoid recursion, if this fails for some reason
00147   if ( !c.contentMimeTypes().isEmpty() ) {
00148     mParent->setCollection(c);
00149   } else {
00150     kWarning() << "Failed to retrieve the contents mime type of the collection: " << c;
00151     mParent->setCollection(Collection());
00152   }
00153 }
00154 
00155 int ItemModel::Private::rowForItem( const Akonadi::Item& item )
00156 {
00157   ItemContainer *container = itemHash.value( item );
00158   if ( !container )
00159     return -1;
00160 
00161   /* Try to find the item directly;
00162 
00163      If items have been removed, this first try won't succeed because
00164      the ItemContainer rows have not been updated (costs too much).
00165   */
00166   if ( container->row < items.count()
00167        && items.at( container->row ) == container )
00168     return container->row;
00169   else { // Slow solution if the fist one has not succeeded
00170     int row = -1;
00171     const int numberOfItems( items.size() );
00172     for ( int i = 0; i < numberOfItems; ++i ) {
00173       if ( items.at( i )->item == item ) {
00174         row = i;
00175         break;
00176       }
00177     }
00178     return row;
00179   }
00180 
00181 }
00182 
00183 void ItemModel::Private::itemChanged( const Akonadi::Item &item, const QSet<QByteArray>& )
00184 {
00185   int row = rowForItem( item );
00186   if ( row < 0 )
00187     return;
00188 
00189   items[ row ]->item = item;
00190   itemHash.remove( item );
00191   itemHash[ item ] = items[ row ];
00192 
00193   QModelIndex start = mParent->index( row, 0, QModelIndex() );
00194   QModelIndex end = mParent->index( row, mParent->columnCount( QModelIndex() ) - 1 , QModelIndex() );
00195 
00196   mParent->dataChanged( start, end );
00197 }
00198 
00199 void ItemModel::Private::itemMoved( const Akonadi::Item &item, const Akonadi::Collection& colSrc, const Akonadi::Collection& colDst )
00200 {
00201   if ( colSrc == collection && colDst != collection ) // item leaving this model
00202   {
00203     itemRemoved( item );
00204     return;
00205   }
00206 
00207 
00208   if ( colDst == collection && colSrc != collection )
00209   {
00210     itemAdded( item );
00211     return;
00212   }
00213 }
00214 
00215 void ItemModel::Private::itemsAdded( const Akonadi::Item::List &list )
00216 {
00217   if ( list.isEmpty() )
00218     return;
00219   mParent->beginInsertRows( QModelIndex(), items.count(), items.count() + list.count() - 1 );
00220   foreach ( const Item &item, list ) {
00221     ItemContainer *c = new ItemContainer( item, items.count() );
00222     items.append( c );
00223     itemHash[ item ] = c;
00224   }
00225   mParent->endInsertRows();
00226 }
00227 
00228 void ItemModel::Private::itemAdded( const Akonadi::Item &item )
00229 {
00230   Item::List l;
00231   l << item;
00232   itemsAdded( l );
00233 }
00234 
00235 void ItemModel::Private::itemRemoved( const Akonadi::Item &_item )
00236 {
00237   int row = rowForItem( _item );
00238   if ( row < 0 )
00239     return;
00240 
00241   mParent->beginRemoveRows( QModelIndex(), row, row );
00242   const Item item = items.at( row )->item;
00243   Q_ASSERT( item.isValid() );
00244   itemHash.remove( item );
00245   delete items.takeAt( row );
00246   mParent->endRemoveRows();
00247 }
00248 
00249 ItemModel::ItemModel( QObject *parent ) :
00250     QAbstractTableModel( parent ),
00251     d( new Private( this ) )
00252 {
00253 }
00254 
00255 ItemModel::~ItemModel()
00256 {
00257   delete d;
00258 }
00259 
00260 QVariant ItemModel::data( const QModelIndex & index, int role ) const
00261 {
00262   if ( !index.isValid() )
00263     return QVariant();
00264   if ( index.row() >= d->items.count() )
00265     return QVariant();
00266   const Item item = d->items.at( index.row() )->item;
00267   if ( !item.isValid() )
00268     return QVariant();
00269 
00270   if ( role == Qt::DisplayRole ) {
00271     switch ( index.column() ) {
00272       case Id:
00273         return QString::number( item.id() );
00274       case RemoteId:
00275         return item.remoteId();
00276       case MimeType:
00277         return item.mimeType();
00278       default:
00279         return QVariant();
00280     }
00281   }
00282 
00283   if ( role == IdRole )
00284     return item.id();
00285 
00286   if ( role == ItemRole ) {
00287     QVariant var;
00288     var.setValue( item );
00289     return var;
00290   }
00291 
00292   if ( role == MimeTypeRole )
00293     return item.mimeType();
00294 
00295   return QVariant();
00296 }
00297 
00298 int ItemModel::rowCount( const QModelIndex & parent ) const
00299 {
00300   if ( !parent.isValid() )
00301     return d->items.count();
00302   return 0;
00303 }
00304 
00305 int ItemModel::columnCount(const QModelIndex & parent) const
00306 {
00307   if ( !parent.isValid() )
00308     return 3; // keep in sync with Column enum
00309   return 0;
00310 }
00311 
00312 QVariant ItemModel::headerData( int section, Qt::Orientation orientation, int role ) const
00313 {
00314   if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) {
00315     switch ( section ) {
00316       case Id:
00317         return i18n( "Id" );
00318       case RemoteId:
00319         return i18n( "Remote Id" );
00320       case MimeType:
00321         return i18n( "MimeType" );
00322       default:
00323         return QString();
00324     }
00325   }
00326   return QAbstractTableModel::headerData( section, orientation, role );
00327 }
00328 
00329 void ItemModel::setCollection( const Collection &collection )
00330 {
00331   kDebug();
00332   if ( d->collection == collection )
00333     return;
00334 
00335   // if we don't know anything about this collection yet, fetch it
00336   if ( collection.isValid() && collection.contentMimeTypes().isEmpty() )
00337   {
00338     CollectionFetchJob* job = new CollectionFetchJob( collection, CollectionFetchJob::Base, this );
00339     connect( job, SIGNAL(result(KJob*)), this, SLOT(collectionFetchResult(KJob*)) );
00340     return;
00341   }
00342 
00343   d->monitor->setCollectionMonitored( d->collection, false );
00344 
00345   d->collection = collection;
00346 
00347   d->monitor->setCollectionMonitored( d->collection, true );
00348 
00349   // the query changed, thus everything we have already is invalid
00350   qDeleteAll( d->items );
00351   d->items.clear();
00352   reset();
00353 
00354   // stop all running jobs
00355   d->session->clear();
00356 
00357   // start listing job
00358   if ( d->collectionIsCompatible() ) {
00359     ItemFetchJob* job = new ItemFetchJob( collection, session() );
00360     job->setFetchScope( d->monitor->itemFetchScope() );
00361     connect( job, SIGNAL(itemsReceived(Akonadi::Item::List)),
00362              SLOT(itemsAdded(Akonadi::Item::List)) );
00363     connect( job, SIGNAL(result(KJob*)), SLOT(listingDone(KJob*)) );
00364   }
00365 
00366   emit collectionChanged( collection );
00367 }
00368 
00369 void ItemModel::setFetchScope( const ItemFetchScope &fetchScope )
00370 {
00371   d->monitor->setItemFetchScope( fetchScope );
00372 }
00373 
00374 ItemFetchScope &ItemModel::fetchScope()
00375 {
00376   return d->monitor->itemFetchScope();
00377 }
00378 
00379 Item ItemModel::itemForIndex( const QModelIndex & index ) const
00380 {
00381   if ( !index.isValid() )
00382     return Akonadi::Item();
00383 
00384   if ( index.row() >= d->items.count() )
00385     return Akonadi::Item();
00386 
00387   Item item = d->items.at( index.row() )->item;
00388   if ( item.isValid() ) {
00389     return item;
00390   } else {
00391     return Akonadi::Item();
00392   }
00393 }
00394 
00395 Qt::ItemFlags ItemModel::flags( const QModelIndex &index ) const
00396 {
00397   Qt::ItemFlags defaultFlags = QAbstractTableModel::flags(index);
00398 
00399   if (index.isValid())
00400     return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
00401   else
00402     return Qt::ItemIsDropEnabled | defaultFlags;
00403 }
00404 
00405 QStringList ItemModel::mimeTypes() const
00406 {
00407   return QStringList() << QLatin1String( "text/uri-list" );
00408 }
00409 
00410 Session * ItemModel::session() const
00411 {
00412   return d->session;
00413 }
00414 
00415 QMimeData *ItemModel::mimeData( const QModelIndexList &indexes ) const
00416 {
00417   QMimeData *data = new QMimeData();
00418   // Add item uri to the mimedata for dropping in external applications
00419   KUrl::List urls;
00420   foreach ( const QModelIndex &index, indexes ) {
00421     if ( index.column() != 0 )
00422       continue;
00423 
00424     urls << itemForIndex( index ).url( Item::UrlWithMimeType );
00425   }
00426   urls.populateMimeData( data );
00427 
00428   return data;
00429 }
00430 
00431 QModelIndex ItemModel::indexForItem( const Akonadi::Item &item, const int column ) const
00432 {
00433   return index( d->rowForItem( item ), column );
00434 }
00435 
00436 bool ItemModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent)
00437 {
00438   Q_UNUSED( row );
00439   Q_UNUSED( column );
00440   Q_UNUSED( parent );
00441   KJob* job = PasteHelper::paste( data, d->collection, action != Qt::MoveAction );
00442   // TODO: error handling
00443   return job;
00444 }
00445 
00446 Collection ItemModel::collection() const
00447 {
00448   return d->collection;
00449 }
00450 
00451 Qt::DropActions ItemModel::supportedDropActions() const
00452 {
00453   return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
00454 }
00455 
00456 
00457 #include "itemmodel.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon May 14 2012 04:52:57 by doxygen 1.7.5 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.8.3 API Reference

Skip menu "kdepimlibs-4.8.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • 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