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