00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "entitytreemodel.h"
00021 #include "entitytreemodel_p.h"
00022
00023 #include "monitor_p.h"
00024
00025 #include <QtCore/QHash>
00026 #include <QtCore/QMimeData>
00027 #include <QtCore/QTimer>
00028 #include <QtGui/QAbstractProxyModel>
00029 #include <QtGui/QApplication>
00030 #include <QtGui/QPalette>
00031
00032 #include <KDE/KIcon>
00033 #include <KDE/KLocale>
00034 #include <KDE/KUrl>
00035
00036 #include <akonadi/attributefactory.h>
00037 #include <akonadi/changerecorder.h>
00038 #include <akonadi/collectionmodifyjob.h>
00039 #include <akonadi/entitydisplayattribute.h>
00040 #include <akonadi/transactionsequence.h>
00041 #include <akonadi/itemmodifyjob.h>
00042 #include <akonadi/session.h>
00043 #include "collectionfetchscope.h"
00044
00045 #include "collectionutils_p.h"
00046
00047 #include "kdebug.h"
00048 #include "pastehelper_p.h"
00049
00050
00051
00052
00053 Q_DECLARE_METATYPE( QSet<QByteArray> )
00054
00055 using namespace Akonadi;
00056
00057 EntityTreeModel::EntityTreeModel( ChangeRecorder *monitor,
00058 QObject *parent
00059 )
00060 : QAbstractItemModel( parent ),
00061 d_ptr( new EntityTreeModelPrivate( this ) )
00062 {
00063 Q_D( EntityTreeModel );
00064 d->init( monitor );
00065 }
00066
00067 EntityTreeModel::EntityTreeModel( ChangeRecorder *monitor,
00068 EntityTreeModelPrivate *d,
00069 QObject *parent )
00070 : QAbstractItemModel( parent ),
00071 d_ptr( d )
00072 {
00073 d->init(monitor );
00074 }
00075
00076 EntityTreeModel::~EntityTreeModel()
00077 {
00078 Q_D( EntityTreeModel );
00079
00080 foreach ( const QList<Node*> &list, d->m_childEntities )
00081 qDeleteAll( list );
00082
00083 delete d_ptr;
00084 }
00085
00086 bool EntityTreeModel::includeUnsubscribed() const
00087 {
00088 Q_D( const EntityTreeModel );
00089 return d->m_includeUnsubscribed;
00090 }
00091
00092 void EntityTreeModel::setIncludeUnsubscribed( bool show )
00093 {
00094 Q_D( EntityTreeModel );
00095 d->m_includeUnsubscribed = show;
00096 }
00097
00098
00099 bool EntityTreeModel::systemEntitiesShown() const
00100 {
00101 Q_D( const EntityTreeModel );
00102 return d->m_showSystemEntities;
00103 }
00104
00105 void EntityTreeModel::setShowSystemEntities( bool show )
00106 {
00107 Q_D( EntityTreeModel );
00108 d->m_showSystemEntities = show;
00109 }
00110
00111 void EntityTreeModel::clearAndReset()
00112 {
00113 Q_D( EntityTreeModel );
00114 d->beginResetModel();
00115 d->endResetModel();
00116 }
00117
00118 int EntityTreeModel::columnCount( const QModelIndex & parent ) const
00119 {
00120
00121 if ( parent.isValid() && parent.column() != 0 )
00122 return 0;
00123
00124 return qMax( entityColumnCount( CollectionTreeHeaders ), entityColumnCount( ItemListHeaders ) );
00125 }
00126
00127
00128 QVariant EntityTreeModel::entityData( const Item &item, int column, int role ) const
00129 {
00130 if ( column == 0 ) {
00131 switch ( role ) {
00132 case Qt::DisplayRole:
00133 case Qt::EditRole:
00134 if ( item.hasAttribute<EntityDisplayAttribute>() &&
00135 !item.attribute<EntityDisplayAttribute>()->displayName().isEmpty() ) {
00136 return item.attribute<EntityDisplayAttribute>()->displayName();
00137 } else {
00138 return item.remoteId();
00139 }
00140 break;
00141 case Qt::DecorationRole:
00142 if ( item.hasAttribute<EntityDisplayAttribute>() &&
00143 !item.attribute<EntityDisplayAttribute>()->iconName().isEmpty() )
00144 return item.attribute<EntityDisplayAttribute>()->icon();
00145 break;
00146 default:
00147 break;
00148 }
00149 }
00150
00151 return QVariant();
00152 }
00153
00154 QVariant EntityTreeModel::entityData( const Collection &collection, int column, int role ) const
00155 {
00156 Q_D( const EntityTreeModel );
00157
00158 if ( column > 0 )
00159 return QString();
00160
00161 if ( collection == Collection::root() ) {
00162
00163 if ( role == Qt::DisplayRole )
00164 return d->m_rootCollectionDisplayName;
00165
00166 if ( role == Qt::EditRole )
00167 return QVariant();
00168 }
00169
00170 switch ( role ) {
00171 case Qt::DisplayRole:
00172 case Qt::EditRole:
00173 if ( column == 0 ) {
00174 if ( collection.hasAttribute<EntityDisplayAttribute>() &&
00175 !collection.attribute<EntityDisplayAttribute>()->displayName().isEmpty() ) {
00176 return collection.attribute<EntityDisplayAttribute>()->displayName();
00177 }
00178 return collection.name();
00179 }
00180 break;
00181 case Qt::DecorationRole:
00182 if ( collection.hasAttribute<EntityDisplayAttribute>() &&
00183 !collection.attribute<EntityDisplayAttribute>()->iconName().isEmpty() ) {
00184 return collection.attribute<EntityDisplayAttribute>()->icon();
00185 }
00186 return KIcon( CollectionUtils::defaultIconName( collection ) );
00187 default:
00188 break;
00189 }
00190
00191 return QVariant();
00192 }
00193
00194 QVariant EntityTreeModel::data( const QModelIndex & index, int role ) const
00195 {
00196 Q_D( const EntityTreeModel );
00197 if ( role == SessionRole )
00198 return QVariant::fromValue( qobject_cast<QObject *>( d->m_session ) );
00199
00200
00201 const HeaderGroup headerGroup = static_cast<HeaderGroup>( ( role / static_cast<int>( TerminalUserRole ) ) );
00202
00203 role %= TerminalUserRole;
00204 if ( !index.isValid() ) {
00205 if ( ColumnCountRole != role )
00206 return QVariant();
00207
00208 return entityColumnCount( headerGroup );
00209 }
00210
00211 if ( ColumnCountRole == role )
00212 return entityColumnCount( headerGroup );
00213
00214 const Node *node = reinterpret_cast<Node *>( index.internalPointer() );
00215
00216 if ( ParentCollectionRole == role ) {
00217 const Collection parentCollection = d->m_collections.value( node->parent );
00218 Q_ASSERT( parentCollection.isValid() );
00219
00220 return QVariant::fromValue( parentCollection );
00221 }
00222
00223 if ( Node::Collection == node->type ) {
00224
00225 const Collection collection = d->m_collections.value( node->id );
00226
00227 if ( !collection.isValid() )
00228 return QVariant();
00229
00230 switch ( role ) {
00231 case MimeTypeRole:
00232 return collection.mimeType();
00233 break;
00234 case RemoteIdRole:
00235 return collection.remoteId();
00236 break;
00237 case CollectionIdRole:
00238 return collection.id();
00239 break;
00240 case ItemIdRole:
00241
00242
00243 return -1;
00244 break;
00245 case CollectionRole:
00246 return QVariant::fromValue( collection );
00247 break;
00248 case EntityUrlRole:
00249 return collection.url().url();
00250 break;
00251 case UnreadCountRole:
00252 {
00253 CollectionStatistics statistics = collection.statistics();
00254 return statistics.unreadCount();
00255 }
00256 case FetchStateRole :
00257 {
00258 return d->m_pendingCollectionRetrieveJobs.contains(collection.id()) ? FetchingState : IdleState;
00259 }
00260 case Qt::BackgroundRole:
00261 {
00262 if ( collection.hasAttribute<EntityDisplayAttribute>() )
00263 {
00264 EntityDisplayAttribute *eda = collection.attribute<EntityDisplayAttribute>();
00265 QColor color = eda->backgroundColor();
00266 if ( color.isValid() )
00267 return color;
00268 }
00269
00270 }
00271 default:
00272 return entityData( collection, index.column(), role );
00273 break;
00274 }
00275
00276 } else if ( Node::Item == node->type ) {
00277 const Item item = d->m_items.value( node->id );
00278 if ( !item.isValid() )
00279 return QVariant();
00280
00281 switch ( role ) {
00282 case MimeTypeRole:
00283 return item.mimeType();
00284 break;
00285 case RemoteIdRole:
00286 return item.remoteId();
00287 break;
00288 case ItemRole:
00289 return QVariant::fromValue( item );
00290 break;
00291 case ItemIdRole:
00292 return item.id();
00293 break;
00294 case CollectionIdRole:
00295 return -1;
00296 break;
00297 case LoadedPartsRole:
00298 return QVariant::fromValue( item.loadedPayloadParts() );
00299 break;
00300 case AvailablePartsRole:
00301 return QVariant::fromValue( item.availablePayloadParts() );
00302 break;
00303 case EntityUrlRole:
00304 return item.url( Akonadi::Item::UrlWithMimeType ).url();
00305 break;
00306 case Qt::BackgroundRole:
00307 {
00308 if ( item.hasAttribute<EntityDisplayAttribute>() )
00309 {
00310 EntityDisplayAttribute *eda = item.attribute<EntityDisplayAttribute>();
00311 QColor color = eda->backgroundColor();
00312 if ( color.isValid() )
00313 return color;
00314 }
00315
00316 }
00317 default:
00318 return entityData( item, index.column(), role );
00319 break;
00320 }
00321 }
00322
00323 return QVariant();
00324 }
00325
00326
00327 Qt::ItemFlags EntityTreeModel::flags( const QModelIndex & index ) const
00328 {
00329 Q_D( const EntityTreeModel );
00330
00331
00332 if ( !index.isValid() )
00333 return 0;
00334
00335 Qt::ItemFlags flags = QAbstractItemModel::flags( index );
00336
00337 const Node *node = reinterpret_cast<Node *>( index.internalPointer() );
00338
00339 if ( Node::Collection == node->type ) {
00340
00341 if ( d->m_pendingCutCollections.contains( node->id ) )
00342 return Qt::ItemIsSelectable;
00343
00344 const Collection collection = d->m_collections.value( node->id );
00345 if ( collection.isValid() ) {
00346
00347 if ( collection == Collection::root() ) {
00348
00349 return flags;
00350 }
00351
00352 const int rights = collection.rights();
00353
00354 if ( rights & Collection::CanChangeCollection ) {
00355 if ( index.column() == 0 )
00356 flags |= Qt::ItemIsEditable;
00357
00358
00359 flags |= Qt::ItemIsDropEnabled;
00360 }
00361 if ( rights & ( Collection::CanCreateCollection | Collection::CanCreateItem | Collection::CanLinkItem ) ) {
00362
00363 flags |= Qt::ItemIsDropEnabled;
00364 }
00365
00366
00367 flags |= Qt::ItemIsDragEnabled;
00368
00369 }
00370 } else if ( Node::Item == node->type ) {
00371 if ( d->m_pendingCutItems.contains( node->id ) )
00372 return Qt::ItemIsSelectable;
00373
00374
00375
00376 Collection parentCollection;
00377 if ( !index.parent().isValid() )
00378 {
00379 parentCollection = d->m_rootCollection;
00380 }
00381 else
00382 {
00383 const Node *parentNode = reinterpret_cast<Node *>( index.parent().internalPointer() );
00384
00385 parentCollection = d->m_collections.value( parentNode->id );
00386 }
00387 if ( parentCollection.isValid() ) {
00388 const int rights = parentCollection.rights();
00389
00390
00391 if ( rights & Collection::CanChangeItem && index.column() == 0 ) {
00392 flags = flags | Qt::ItemIsEditable;
00393 }
00394
00395 flags |= Qt::ItemIsDragEnabled;
00396 }
00397 }
00398
00399 return flags;
00400 }
00401
00402 Qt::DropActions EntityTreeModel::supportedDropActions() const
00403 {
00404 return (Qt::CopyAction | Qt::MoveAction | Qt::LinkAction);
00405 }
00406
00407 QStringList EntityTreeModel::mimeTypes() const
00408 {
00409
00410 return QStringList() << QLatin1String( "text/uri-list" );
00411 }
00412
00413 bool EntityTreeModel::dropMimeData( const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent )
00414 {
00415 Q_UNUSED( row );
00416 Q_UNUSED( column );
00417 Q_D( EntityTreeModel );
00418
00419
00420 if ( !parent.isValid() )
00421 return false;
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437 if ( action == Qt::IgnoreAction )
00438 return true;
00439
00440
00441
00442
00443
00444 Node *node = reinterpret_cast<Node *>( parent.internalId() );
00445
00446 Q_ASSERT( node );
00447
00448 if ( Node::Item == node->type ) {
00449 if ( !parent.parent().isValid() ) {
00450
00451
00452 kWarning() << "Dropped onto item with no parent collection";
00453 return true;
00454 }
00455
00456
00457 node = reinterpret_cast<Node *>( parent.parent().internalId() );
00458 }
00459
00460 if ( Node::Collection == node->type ) {
00461 const Collection destCollection = d->m_collections.value( node->id );
00462
00463
00464 if ( destCollection == Collection::root() )
00465
00466 return true;
00467
00468 if ( data->hasFormat( QLatin1String( "text/uri-list" ) ) ) {
00469
00470 MimeTypeChecker mimeChecker;
00471 mimeChecker.setWantedMimeTypes( destCollection.contentMimeTypes() );
00472
00473 const KUrl::List urls = KUrl::List::fromMimeData( data );
00474 foreach ( const KUrl &url, urls ) {
00475 const Collection collection = d->m_collections.value( Collection::fromUrl( url ).id() );
00476 if ( collection.isValid() ) {
00477 if ( collection.parentCollection().id() == destCollection.id() ) {
00478 kDebug() << "Error: source and destination of move are the same.";
00479 return false;
00480 }
00481
00482 if ( !mimeChecker.isWantedCollection( collection ) ) {
00483 kDebug() << "unwanted collection" << mimeChecker.wantedMimeTypes() << collection.contentMimeTypes();
00484 return false;
00485 }
00486 } else {
00487 const Item item = d->m_items.value( Item::fromUrl( url ).id() );
00488 if ( item.isValid() ) {
00489 if ( item.parentCollection().id() == destCollection.id() ) {
00490 kDebug() << "Error: source and destination of move are the same.";
00491 return false;
00492 }
00493
00494 if ( !mimeChecker.isWantedItem( item ) ) {
00495 kDebug() << "unwanted item" << mimeChecker.wantedMimeTypes() << item.mimeType();
00496 return false;
00497 }
00498 }
00499 }
00500 }
00501
00502 KJob *job = PasteHelper::pasteUriList( data, destCollection, action, d->m_session );
00503 if ( !job )
00504 return false;
00505
00506 connect( job, SIGNAL( result( KJob* ) ), SLOT( pasteJobDone( KJob* ) ) );
00507
00508
00509 return true;
00510 } else {
00511
00512
00513
00514 }
00515 }
00516
00517 return false;
00518 }
00519
00520 QModelIndex EntityTreeModel::index( int row, int column, const QModelIndex & parent ) const
00521 {
00522
00523 Q_D( const EntityTreeModel );
00524
00525 if ( parent.column() > 0 )
00526 return QModelIndex();
00527
00528
00529 if ( column >= columnCount() || column < 0 )
00530 return QModelIndex();
00531
00532 QList<Node*> childEntities;
00533
00534 const Node *parentNode = reinterpret_cast<Node*>( parent.internalPointer() );
00535
00536 if ( !parentNode || !parent.isValid() ) {
00537 if ( d->m_showRootCollection )
00538 childEntities << d->m_childEntities.value( -1 );
00539 else
00540 childEntities = d->m_childEntities.value( d->m_rootCollection.id() );
00541 } else {
00542 if ( parentNode->id >= 0 )
00543 childEntities = d->m_childEntities.value( parentNode->id );
00544 }
00545
00546 const int size = childEntities.size();
00547 if ( row < 0 || row >= size )
00548 return QModelIndex();
00549
00550 Node *node = childEntities.at( row );
00551
00552 return createIndex( row, column, reinterpret_cast<void*>( node ) );
00553 }
00554
00555 QModelIndex EntityTreeModel::parent( const QModelIndex & index ) const
00556 {
00557 Q_D( const EntityTreeModel );
00558
00559 if ( !index.isValid() )
00560 return QModelIndex();
00561
00562 if ( d->m_collectionFetchStrategy == InvisibleCollectionFetch )
00563 return QModelIndex();
00564
00565 const Node *node = reinterpret_cast<Node*>( index.internalPointer() );
00566
00567 if ( !node )
00568 return QModelIndex();
00569
00570 const Collection collection = d->m_collections.value( node->parent );
00571
00572 if ( !collection.isValid() )
00573 return QModelIndex();
00574
00575 if ( collection.id() == d->m_rootCollection.id() ) {
00576 if ( !d->m_showRootCollection )
00577 return QModelIndex();
00578 else
00579 return createIndex( 0, 0, reinterpret_cast<void *>( d->m_rootNode ) );
00580 }
00581
00582 const int row = d->indexOf<Node::Collection>( d->m_childEntities.value( collection.parentCollection().id() ), collection.id() );
00583
00584 Q_ASSERT( row >= 0 );
00585 Node *parentNode = d->m_childEntities.value( collection.parentCollection().id() ).at( row );
00586
00587 return createIndex( row, 0, reinterpret_cast<void*>( parentNode ) );
00588 }
00589
00590 int EntityTreeModel::rowCount( const QModelIndex & parent ) const
00591 {
00592 Q_D( const EntityTreeModel );
00593
00594 if ( d->m_collectionFetchStrategy == InvisibleCollectionFetch )
00595 {
00596 if ( parent.isValid() )
00597 return 0;
00598 else
00599 return d->m_items.size();
00600 }
00601
00602 const Node *node = reinterpret_cast<Node*>( parent.internalPointer() );
00603
00604 qint64 id;
00605 if ( !parent.isValid() ) {
00606
00607 if ( d->m_showRootCollection )
00608 return d->m_childEntities.value( -1 ).size();
00609
00610 id = d->m_rootCollection.id();
00611 } else {
00612
00613 if ( !node )
00614 return 0;
00615
00616 if ( Node::Item == node->type )
00617 return 0;
00618
00619 id = node->id;
00620 }
00621
00622 if ( parent.column() <= 0 )
00623 return d->m_childEntities.value( id ).size();
00624
00625 return 0;
00626 }
00627
00628 int EntityTreeModel::entityColumnCount( HeaderGroup headerGroup ) const
00629 {
00630
00631 Q_UNUSED( headerGroup );
00632
00633 return 1;
00634 }
00635
00636 QVariant EntityTreeModel::entityHeaderData( int section, Qt::Orientation orientation, int role, HeaderGroup headerGroup ) const
00637 {
00638 Q_D( const EntityTreeModel );
00639
00640 Q_UNUSED( headerGroup );
00641
00642 if ( section == 0 && orientation == Qt::Horizontal && role == Qt::DisplayRole )
00643 {
00644 if ( d->m_rootCollection == Collection::root() )
00645 return i18nc( "@title:column Name of a thing", "Name" );
00646 return d->m_rootCollection.name();
00647 }
00648
00649 return QAbstractItemModel::headerData( section, orientation, role );
00650 }
00651
00652 QVariant EntityTreeModel::headerData( int section, Qt::Orientation orientation, int role ) const
00653 {
00654 const HeaderGroup headerGroup = static_cast<HeaderGroup>( (role / static_cast<int>( TerminalUserRole ) ) );
00655
00656 role %= TerminalUserRole;
00657 return entityHeaderData( section, orientation, role, headerGroup );
00658 }
00659
00660 QMimeData *EntityTreeModel::mimeData( const QModelIndexList &indexes ) const
00661 {
00662 Q_D( const EntityTreeModel );
00663
00664 QMimeData *data = new QMimeData();
00665 KUrl::List urls;
00666 foreach ( const QModelIndex &index, indexes ) {
00667 if ( index.column() != 0 )
00668 continue;
00669
00670 if ( !index.isValid() )
00671 continue;
00672
00673 const Node *node = reinterpret_cast<Node*>( index.internalPointer() );
00674
00675 if ( Node::Collection == node->type )
00676 urls << d->m_collections.value( node->id ).url();
00677 else if ( Node::Item == node->type )
00678 urls << d->m_items.value( node->id ).url( Item::UrlWithMimeType );
00679 else
00680 Q_ASSERT( false );
00681 }
00682
00683 urls.populateMimeData( data );
00684
00685 return data;
00686 }
00687
00688
00689 bool EntityTreeModel::setData( const QModelIndex &index, const QVariant &value, int role )
00690 {
00691 Q_D( EntityTreeModel );
00692
00693 const Node *node = reinterpret_cast<Node*>( index.internalPointer() );
00694
00695 if ( role == PendingCutRole ) {
00696 if ( index.isValid() && value.toBool() ) {
00697 if ( Node::Collection == node->type )
00698 d->m_pendingCutCollections.append( node->id );
00699
00700 if ( Node::Item == node->type )
00701 d->m_pendingCutItems.append( node->id );
00702 } else {
00703 d->m_pendingCutCollections.clear();
00704 d->m_pendingCutItems.clear();
00705 }
00706 return true;
00707 }
00708
00709 if ( index.isValid() && node->type == Node::Collection && (role == CollectionRefRole || role == CollectionDerefRole) ) {
00710 const Collection collection = index.data( CollectionRole ).value<Collection>();
00711 Q_ASSERT( collection.isValid() );
00712
00713 if ( role == CollectionDerefRole )
00714 d->deref( collection.id() );
00715 else if ( role == CollectionRefRole )
00716 d->ref( collection.id() );
00717 }
00718
00719 if ( index.column() == 0 && ( role & ( Qt::EditRole | ItemRole | CollectionRole ) ) ) {
00720 if ( Node::Collection == node->type ) {
00721
00722 Collection collection = d->m_collections.value( node->id );
00723
00724 if ( !collection.isValid() || !value.isValid() )
00725 return false;
00726
00727 if ( Qt::EditRole == role ) {
00728 collection.setName( value.toString() );
00729
00730 if ( collection.hasAttribute<EntityDisplayAttribute>() ) {
00731 EntityDisplayAttribute *displayAttribute = collection.attribute<EntityDisplayAttribute>();
00732 displayAttribute->setDisplayName( value.toString() );
00733 }
00734 }
00735
00736 if ( Qt::BackgroundRole == role )
00737 {
00738 QColor color = value.value<QColor>();
00739
00740 if ( !color.isValid() )
00741 return false;
00742
00743 EntityDisplayAttribute *eda = collection.attribute<EntityDisplayAttribute>( Entity::AddIfMissing );
00744 eda->setBackgroundColor( color );
00745 }
00746
00747 if ( CollectionRole == role )
00748 collection = value.value<Collection>();
00749
00750 CollectionModifyJob *job = new CollectionModifyJob( collection, d->m_session );
00751 connect( job, SIGNAL( result( KJob* ) ),
00752 SLOT( updateJobDone( KJob* ) ) );
00753
00754 return false;
00755 } else if ( Node::Item == node->type ) {
00756
00757 Item item = d->m_items.value( node->id );
00758
00759 if ( !item.isValid() || !value.isValid() )
00760 return false;
00761
00762 if ( Qt::EditRole == role ) {
00763 if ( item.hasAttribute<EntityDisplayAttribute>() ) {
00764 EntityDisplayAttribute *displayAttribute = item.attribute<EntityDisplayAttribute>( Entity::AddIfMissing );
00765 displayAttribute->setDisplayName( value.toString() );
00766 }
00767 }
00768
00769 if ( Qt::BackgroundRole == role )
00770 {
00771 QColor color = value.value<QColor>();
00772
00773 if ( !color.isValid() )
00774 return false;
00775
00776 EntityDisplayAttribute *eda = item.attribute<EntityDisplayAttribute>( Entity::AddIfMissing );
00777 eda->setBackgroundColor( color );
00778 }
00779
00780 if ( ItemRole == role )
00781 {
00782 item = value.value<Item>();
00783 Q_ASSERT( item.id() == node->id );
00784 }
00785
00786 ItemModifyJob *itemModifyJob = new ItemModifyJob( item, d->m_session );
00787 connect( itemModifyJob, SIGNAL( result( KJob* ) ),
00788 SLOT( updateJobDone( KJob* ) ) );
00789
00790 return false;
00791 }
00792 }
00793
00794 return QAbstractItemModel::setData( index, value, role );
00795 }
00796
00797 bool EntityTreeModel::canFetchMore( const QModelIndex & parent ) const
00798 {
00799 Q_UNUSED(parent)
00800 return false;
00801 }
00802
00803 void EntityTreeModel::fetchMore( const QModelIndex & parent )
00804 {
00805 Q_D( EntityTreeModel );
00806
00807 if ( !d->canFetchMore( parent ) )
00808 return;
00809
00810 if ( d->m_collectionFetchStrategy == InvisibleCollectionFetch )
00811 return;
00812
00813 if ( d->m_itemPopulation == ImmediatePopulation )
00814
00815 return;
00816 else if ( d->m_itemPopulation == LazyPopulation ) {
00817 const Collection collection = parent.data( CollectionRole ).value<Collection>();
00818
00819 if ( !collection.isValid() )
00820 return;
00821
00822 d->fetchItems( collection );
00823 }
00824 }
00825
00826 bool EntityTreeModel::hasChildren( const QModelIndex &parent ) const
00827 {
00828 Q_D( const EntityTreeModel );
00829
00830 if ( d->m_collectionFetchStrategy == InvisibleCollectionFetch )
00831 return parent.isValid() ? false : !d->m_items.isEmpty();
00832
00833
00834
00835
00836
00837 return ((rowCount( parent ) > 0) || (canFetchMore( parent ) && d->m_itemPopulation == LazyPopulation));
00838 }
00839
00840 bool EntityTreeModel::entityMatch( const Item &item, const QVariant &value, Qt::MatchFlags flags ) const
00841 {
00842 Q_UNUSED( item );
00843 Q_UNUSED( value );
00844 Q_UNUSED( flags );
00845 return false;
00846 }
00847
00848 bool EntityTreeModel::entityMatch( const Collection &collection, const QVariant &value, Qt::MatchFlags flags ) const
00849 {
00850 Q_UNUSED( collection );
00851 Q_UNUSED( value );
00852 Q_UNUSED( flags );
00853 return false;
00854 }
00855
00856 QModelIndexList EntityTreeModel::match( const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags ) const
00857 {
00858 Q_D( const EntityTreeModel );
00859
00860 if ( role == CollectionIdRole || role == CollectionRole ) {
00861 Collection::Id id;
00862 if ( role == CollectionRole ) {
00863 const Collection collection = value.value<Collection>();
00864 id = collection.id();
00865 } else {
00866 id = value.toLongLong();
00867 }
00868
00869 QModelIndexList list;
00870
00871 const Collection collection = d->m_collections.value( id );
00872
00873 if ( !collection.isValid() )
00874 return list;
00875
00876 const QModelIndex collectionIndex = d->indexForCollection( collection );
00877 Q_ASSERT( collectionIndex.isValid() );
00878 list << collectionIndex;
00879
00880 return list;
00881 }
00882
00883 if ( role == ItemIdRole || role == ItemRole ) {
00884 Item::Id id;
00885 if ( role == ItemRole ) {
00886 const Item item = value.value<Item>();
00887 id = item.id();
00888 } else {
00889 id = value.toLongLong();
00890 }
00891 QModelIndexList list;
00892
00893 const Item item = d->m_items.value( id );
00894 if ( !item.isValid() )
00895 return list;
00896
00897 return d->indexesForItem( item );
00898 }
00899
00900 if ( role == EntityUrlRole ) {
00901 const KUrl url( value.toString() );
00902 const Item item = Item::fromUrl( url );
00903
00904 if ( item.isValid() )
00905 return d->indexesForItem( d->m_items.value( item.id() ) );
00906
00907 const Collection collection = Collection::fromUrl( url );
00908 QModelIndexList list;
00909 if ( collection.isValid() )
00910 list << d->indexForCollection( collection );
00911
00912 return list;
00913 }
00914
00915 if ( role != AmazingCompletionRole )
00916 return QAbstractItemModel::match( start, role, value, hits, flags );
00917
00918
00919 QModelIndexList list;
00920
00921 if ( role < 0 || !start.isValid() || !value.isValid() )
00922 return list;
00923
00924 const int column = 0;
00925 int row = start.row();
00926 const QModelIndex parentIndex = start.parent();
00927 const int parentRowCount = rowCount( parentIndex );
00928
00929 while ( row < parentRowCount && (hits == -1 || list.size() < hits) ) {
00930 const QModelIndex idx = index( row, column, parentIndex );
00931 const Item item = idx.data( ItemRole ).value<Item>();
00932
00933 if ( !item.isValid() ) {
00934 const Collection collection = idx.data( CollectionRole ).value<Collection>();
00935 if ( !collection.isValid() )
00936 continue;
00937
00938 if ( entityMatch( collection, value, flags ) )
00939 list << idx;
00940
00941 } else {
00942 if ( entityMatch( item, value, flags ) )
00943 list << idx;
00944 }
00945
00946 ++row;
00947 }
00948
00949 return list;
00950 }
00951
00952 bool EntityTreeModel::insertRows( int, int, const QModelIndex& )
00953 {
00954 return false;
00955 }
00956
00957 bool EntityTreeModel::insertColumns( int, int, const QModelIndex& )
00958 {
00959 return false;
00960 }
00961
00962 bool EntityTreeModel::removeRows( int, int, const QModelIndex& )
00963 {
00964 return false;
00965 }
00966
00967 bool EntityTreeModel::removeColumns( int, int, const QModelIndex& )
00968 {
00969 return false;
00970 }
00971
00972 void EntityTreeModel::setItemPopulationStrategy( ItemPopulationStrategy strategy )
00973 {
00974 Q_D( EntityTreeModel );
00975 d->beginResetModel();
00976 d->m_itemPopulation = strategy;
00977
00978 if ( strategy == NoItemPopulation ) {
00979 disconnect( d->m_monitor, SIGNAL( itemAdded( const Akonadi::Item&, const Akonadi::Collection& ) ),
00980 this, SLOT( monitoredItemAdded( const Akonadi::Item&, const Akonadi::Collection& ) ) );
00981 disconnect( d->m_monitor, SIGNAL( itemChanged( const Akonadi::Item&, const QSet<QByteArray>& ) ),
00982 this, SLOT( monitoredItemChanged( const Akonadi::Item&, const QSet<QByteArray>& ) ) );
00983 disconnect( d->m_monitor, SIGNAL( itemRemoved( const Akonadi::Item& ) ),
00984 this, SLOT( monitoredItemRemoved( const Akonadi::Item& ) ) );
00985 disconnect( d->m_monitor, SIGNAL( itemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& ) ),
00986 this, SLOT( monitoredItemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& ) ) );
00987
00988 disconnect( d->m_monitor, SIGNAL( itemLinked( const Akonadi::Item&, const Akonadi::Collection& ) ),
00989 this, SLOT( monitoredItemLinked( const Akonadi::Item&, const Akonadi::Collection& ) ) );
00990 disconnect( d->m_monitor, SIGNAL( itemUnlinked( const Akonadi::Item&, const Akonadi::Collection& ) ),
00991 this, SLOT( monitoredItemUnlinked( const Akonadi::Item&, const Akonadi::Collection& ) ) );
00992 }
00993
00994 d->m_monitor->d_ptr->useRefCounting = (strategy == LazyPopulation);
00995
00996 d->endResetModel();
00997 }
00998
00999 EntityTreeModel::ItemPopulationStrategy EntityTreeModel::itemPopulationStrategy() const
01000 {
01001 Q_D( const EntityTreeModel );
01002 return d->m_itemPopulation;
01003 }
01004
01005 void EntityTreeModel::setIncludeRootCollection( bool include )
01006 {
01007 Q_D( EntityTreeModel );
01008 d->beginResetModel();
01009 d->m_showRootCollection = include;
01010 d->endResetModel();
01011 }
01012
01013 bool EntityTreeModel::includeRootCollection() const
01014 {
01015 Q_D( const EntityTreeModel );
01016 return d->m_showRootCollection;
01017 }
01018
01019 void EntityTreeModel::setRootCollectionDisplayName( const QString &displayName )
01020 {
01021 Q_D( EntityTreeModel );
01022 d->m_rootCollectionDisplayName = displayName;
01023
01024
01025 }
01026
01027 QString EntityTreeModel::rootCollectionDisplayName() const
01028 {
01029 Q_D( const EntityTreeModel );
01030 return d->m_rootCollectionDisplayName;
01031 }
01032
01033 void EntityTreeModel::setCollectionFetchStrategy( CollectionFetchStrategy strategy )
01034 {
01035 Q_D( EntityTreeModel );
01036 d->beginResetModel();
01037 d->m_collectionFetchStrategy = strategy;
01038
01039
01040 if ( strategy == FetchNoCollections || strategy == InvisibleCollectionFetch ) {
01041 disconnect( d->m_monitor, SIGNAL( collectionChanged( const Akonadi::Collection& ) ),
01042 this, SLOT( monitoredCollectionChanged( const Akonadi::Collection& ) ) );
01043 disconnect( d->m_monitor, SIGNAL( collectionAdded( const Akonadi::Collection&, const Akonadi::Collection& ) ),
01044 this, SLOT( monitoredCollectionAdded( const Akonadi::Collection&, const Akonadi::Collection& ) ) );
01045 disconnect( d->m_monitor, SIGNAL( collectionRemoved( const Akonadi::Collection& ) ),
01046 this, SLOT( monitoredCollectionRemoved( const Akonadi::Collection& ) ) );
01047 disconnect( d->m_monitor,
01048 SIGNAL( collectionMoved( const Akonadi::Collection&, const Akonadi::Collection&, const Akonadi::Collection& ) ),
01049 this, SLOT( monitoredCollectionMoved( const Akonadi::Collection&, const Akonadi::Collection&, const Akonadi::Collection& ) ) );
01050 d->m_monitor->fetchCollection( false );
01051 } else
01052 d->m_monitor->fetchCollection( true );
01053
01054 d->endResetModel();
01055 }
01056
01057 EntityTreeModel::CollectionFetchStrategy EntityTreeModel::collectionFetchStrategy() const
01058 {
01059 Q_D( const EntityTreeModel );
01060 return d->m_collectionFetchStrategy;
01061 }
01062
01063 static QPair<QList<const QAbstractProxyModel *>, const EntityTreeModel *> proxiesAndModel( const QAbstractItemModel *model )
01064 {
01065 QList<const QAbstractProxyModel *> proxyChain;
01066 const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel *>( model );
01067 const QAbstractItemModel *_model = model;
01068 while ( proxy )
01069 {
01070 proxyChain.prepend( proxy );
01071 _model = proxy->sourceModel();
01072 proxy = qobject_cast<const QAbstractProxyModel *>( _model );
01073 }
01074
01075 const EntityTreeModel *etm = qobject_cast<const EntityTreeModel *>( _model );
01076 return qMakePair(proxyChain, etm);
01077 }
01078
01079 static QModelIndex proxiedIndex( const QModelIndex &idx, QList<const QAbstractProxyModel *> proxyChain )
01080 {
01081 QListIterator<const QAbstractProxyModel *> it( proxyChain );
01082 QModelIndex _idx = idx;
01083 while ( it.hasNext() )
01084 _idx = it.next()->mapFromSource( _idx );
01085 return _idx;
01086 }
01087
01088 QModelIndex EntityTreeModel::modelIndexForCollection( const QAbstractItemModel *model, const Collection &collection )
01089 {
01090 QPair<QList<const QAbstractProxyModel *>, const EntityTreeModel*> pair = proxiesAndModel( model );
01091 QModelIndex idx = pair.second->d_ptr->indexForCollection( collection );
01092 return proxiedIndex( idx, pair.first );
01093 }
01094
01095 QModelIndexList EntityTreeModel::modelIndexesForItem( const QAbstractItemModel *model, const Item &item )
01096 {
01097 QPair<QList<const QAbstractProxyModel *>, const EntityTreeModel*> pair = proxiesAndModel( model );
01098 QModelIndexList list = pair.second->d_ptr->indexesForItem( item );
01099 QModelIndexList proxyList;
01100 foreach( const QModelIndex &idx, list )
01101 {
01102 const QModelIndex pIdx = proxiedIndex( idx, pair.first );
01103 if ( pIdx.isValid() )
01104 proxyList << pIdx;
01105 }
01106 return proxyList;
01107 }
01108
01109 #include "entitytreemodel.moc"