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