00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "messagethreaderproxymodel.h"
00021 #include "messagethreadingattribute.h"
00022 #include "messagemodel.h"
00023
00024 #include <akonadi/attributefactory.h>
00025 #include <akonadi/itemfetchjob.h>
00026 #include <akonadi/itemfetchscope.h>
00027
00028 #include <QtCore/QDebug>
00029 #include <QtCore/QString>
00030 #include <QtCore/QStringList>
00031 #include <QtCore/QHash>
00032 #include <QtCore/QTime>
00033 #include <QtCore/QModelIndex>
00034
00035 using namespace Akonadi;
00036
00037 class MessageThreaderProxyModel::Private
00038 {
00039 public:
00040 Private( MessageThreaderProxyModel *parent )
00041 : mParent( parent )
00042 {
00043 }
00044
00045
00046 MessageModel* sourceMessageModel()
00047 {
00048 return dynamic_cast<MessageModel*>( mParent->sourceModel() );
00049 }
00050
00051
00052
00053
00054 void slotCollectionChanged()
00055 {
00056 childrenMap.clear();
00057 indexMap.clear();
00058 parentMap.clear();
00059 realPerfectParentsMap.clear();
00060 realUnperfectParentsMap.clear();
00061 realSubjectParentsMap.clear();
00062
00063 realPerfectChildrenMap.clear();
00064 realUnperfectChildrenMap.clear();
00065 realSubjectChildrenMap.clear();
00066
00067 mParent->reset();
00068 }
00069
00070
00071
00072
00073
00074 void slotInsertRows( const QModelIndex& sourceIndex, int begin, int end )
00075 {
00076 Q_UNUSED( sourceIndex );
00077 QTime time;
00078 time.start();
00079
00080 for ( int i=begin; i <= end; i++ )
00081 {
00082
00083 Item item = sourceMessageModel()->itemForIndex( sourceMessageModel()->index( i, 0 ) );
00084 Entity::Id id = item.id();
00085
00086 readParentsFromParts( item );
00087 Entity::Id parentId = parentForItem( item.id() );
00088
00089
00090
00091
00092 int row = childrenMap[ parentId ].count();
00093 mParent->beginInsertRows( indexMap[ parentId ], row, row );
00094 childrenMap[ parentId ] << item.id();
00095 parentMap[ id ] = parentId;
00096 QModelIndex index = mParent->createIndex( childrenMap[ parentId ].count() - 1, 0, id );
00097 mParent->endInsertRows();
00098
00099
00100
00101
00102
00103 QList<Entity::Id> potentialChildren = realPerfectChildrenMap[ id ]
00104 << realUnperfectChildrenMap[ id ]
00105 << realSubjectChildrenMap[ id ];
00106 foreach( Entity::Id potentialChildId, potentialChildren ) {
00107
00108
00109
00110
00111 if ( potentialChildId != id &&
00112 parentMap.constFind( potentialChildId ) != parentMap.constEnd() &&
00113 parentMap[ potentialChildId ] != id &&
00114 parentMap[ potentialChildId ]
00115 )
00116
00117 {
00118
00119 QList<Entity::Id> realParentsList = realPerfectParentsMap[ potentialChildId ]
00120 << realUnperfectParentsMap[ potentialChildId ]
00121 << realSubjectParentsMap[ potentialChildId ];
00122 int currentParentPos = realParentsList.indexOf( parentMap[ potentialChildId ] );
00123
00124 if ( currentParentPos == 0 || ( currentParentPos != -1 && realParentsList.indexOf( id ) > currentParentPos ) )
00125
00126 continue;
00127
00128
00129 int childRow = childrenMap[ parentMap[ potentialChildId ] ].indexOf( potentialChildId );
00130 mParent->beginRemoveRows( indexMap[ parentMap[ potentialChildId ] ], childRow, childRow );
00131 mParent->endRemoveRows();
00132 childrenMap[ parentMap[ potentialChildId ] ].removeAt( childRow );
00133
00134
00135 mParent->beginInsertRows( index, childrenMap[ id ].count(), childrenMap[ id ].count() );
00136 parentMap[ potentialChildId ] = id;
00137 childrenMap[ id ] << potentialChildId;
00138
00139
00140 mParent->createIndex( childrenMap[ id ].count() - 1, 0, potentialChildId );
00141 mParent->endInsertRows();
00142 }
00143 }
00144 }
00145
00146 qDebug() << time.elapsed() << "ms for" << end - begin + 1 << "items";
00147 }
00148
00149
00150
00151
00152
00153 void slotRemoveRows( const QModelIndex& sourceIndex, int begin, int end )
00154 {
00155 Q_UNUSED( sourceIndex );
00156 for ( int i = begin; i <= end; i++ )
00157 {
00158 Item item = sourceMessageModel()->itemForIndex( sourceMessageModel()->index( i, 0 ) );
00159 Entity::Id id = item.id();
00160 Entity::Id parentId = parentMap[ id ];
00161 int row = childrenMap[ parentId ].indexOf( id );
00162
00163
00164 foreach( Entity::Id childId, childrenMap[ id ] ) {
00165 int childRow = childrenMap[ id ].indexOf( childId );
00166 mParent->beginRemoveRows( indexMap[ id ], childRow, childRow );
00167 childrenMap[ id ].removeAll( childId );
00168 mParent->endRemoveRows();
00169
00170 mParent->beginInsertRows( indexMap[ parentId ], childrenMap[ parentId ].count(),
00171 childrenMap[ parentId ].count() );
00172 parentMap[ childId ] = parentId;
00173 childrenMap[ parentId ] << childId;
00174 mParent->endInsertRows();
00175
00176 mParent->createIndex( childrenMap[ parentId ].count() - 1, 0, childId );
00177 }
00178
00179 mParent->beginRemoveRows( indexMap[ parentId ], row, row );
00180 childrenMap[ parentId ].removeAll( id );
00181 parentMap.remove( id );
00182 indexMap.remove( id );
00183 mParent->endRemoveRows();
00184
00185
00186 }
00187 }
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 void readParentsFromParts( const Item& item )
00198 {
00199 MessageThreadingAttribute *attr = item.attribute<MessageThreadingAttribute>();
00200 if ( attr ) {
00201 QList<Entity::Id> realPerfectParentsList = attr->perfectParents();
00202 QList<Entity::Id> realUnperfectParentsList = attr->unperfectParents();
00203 QList<Entity::Id> realSubjectParentsList = attr->subjectParents();
00204
00205 realPerfectParentsMap[ item.id() ] = realPerfectParentsList;
00206 realUnperfectParentsMap[ item.id() ] = realUnperfectParentsList;
00207 realSubjectParentsMap[ item.id() ] = realSubjectParentsList;
00208
00209
00210 foreach( Entity::Id parentId, realPerfectParentsList )
00211 realPerfectChildrenMap[ parentId ] << item.id();
00212 foreach( Entity::Id parentId, realUnperfectParentsList )
00213 realUnperfectChildrenMap[ parentId ] << item.id();
00214 foreach( Entity::Id parentId, realSubjectParentsList )
00215 realSubjectChildrenMap[ parentId ] << item.id();
00216 }
00217 }
00218
00219
00220
00221
00222
00223
00224 Entity::Id parentForItem( Entity::Id id )
00225 {
00226
00227 QList<Entity::Id> parentsIds;
00228 parentsIds << realPerfectParentsMap[ id ] << realUnperfectParentsMap[ id ] << realSubjectParentsMap[ id ];
00229
00230 foreach( Entity::Id parentId, parentsIds )
00231 {
00232
00233
00234 if ( sourceMessageModel()->indexForItem( Item( parentId ), 0 ).isValid() )
00235 return parentId;
00236
00237 }
00238
00239
00240 return -1;
00241 }
00242
00243
00244 Entity::Id idForIndex( const QModelIndex& index )
00245 {
00246 return index.isValid() ? index.internalId() : -1;
00247 }
00248
00249 MessageThreaderProxyModel *mParent;
00250
00251
00252
00253
00254
00255
00256 QHash<Entity::Id, QList<Entity::Id> > childrenMap;
00257 QHash<Entity::Id, Entity::Id> parentMap;
00258 QHash<Entity::Id, QModelIndex> indexMap;
00259
00260
00261
00262
00263
00264
00265 QHash<Entity::Id, QList<Entity::Id> > realPerfectParentsMap;
00266 QHash<Entity::Id, QList<Entity::Id> > realUnperfectParentsMap;
00267 QHash<Entity::Id, QList<Entity::Id> > realSubjectParentsMap;
00268
00269 QHash<Entity::Id, QList<Entity::Id> > realPerfectChildrenMap;
00270 QHash<Entity::Id, QList<Entity::Id> > realUnperfectChildrenMap;
00271 QHash<Entity::Id, QList<Entity::Id> > realSubjectChildrenMap;
00272 };
00273
00274 MessageThreaderProxyModel::MessageThreaderProxyModel( QObject *parent )
00275 : QAbstractProxyModel( parent ),
00276 d( new Private( this ) )
00277 {
00278 AttributeFactory::registerAttribute<MessageThreadingAttribute>();
00279 setSupportedDragActions( Qt::MoveAction | Qt::CopyAction );
00280 }
00281
00282 MessageThreaderProxyModel::~MessageThreaderProxyModel()
00283 {
00284 delete d;
00285 }
00286
00287 QModelIndex MessageThreaderProxyModel::index( int row, int column, const QModelIndex& parent ) const
00288 {
00289 Entity::Id parentId = d->idForIndex( parent );
00290
00291 if ( row < 0
00292 || column < 0
00293 || row >= d->childrenMap[ parentId ].count()
00294 || column >= columnCount( parent )
00295 )
00296 return QModelIndex();
00297
00298 Entity::Id id = d->childrenMap[ parentId ].at( row );
00299
00300 return createIndex( row, column, id );
00301 }
00302
00303 QModelIndex MessageThreaderProxyModel::parent( const QModelIndex & index ) const
00304 {
00305 if ( !index.isValid() )
00306 return QModelIndex();
00307
00308 Entity::Id parentId = d->parentMap[ index.internalId() ];
00309
00310 if ( parentId == -1 )
00311 return QModelIndex();
00312
00313
00314
00315 return d->indexMap[ d->parentMap[ index.internalId() ] ];
00316
00317 }
00318
00319 QModelIndex MessageThreaderProxyModel::mapToSource( const QModelIndex& index ) const
00320 {
00321
00322 return d->sourceMessageModel()->indexForItem( Item( index.internalId() ), index.column() );
00323 }
00324
00325 QModelIndex MessageThreaderProxyModel::mapFromSource( const QModelIndex& index ) const
00326 {
00327 Item item = d->sourceMessageModel()->itemForIndex( index );
00328 Entity::Id id = item.id();
00329
00330 return MessageThreaderProxyModel::index( d->indexMap[ id ].row(), index.column(), d->indexMap[ id ].parent() );
00331 }
00332
00333 QModelIndex MessageThreaderProxyModel::createIndex( int row, int column, quint32 internalId ) const
00334 {
00335 QModelIndex index = QAbstractProxyModel::createIndex( row, column, internalId );
00336 if ( column == 0 )
00337 d->indexMap[ internalId ] = index;
00338 return index;
00339 }
00340
00341 void MessageThreaderProxyModel::setSourceModel( QAbstractItemModel* model )
00342 {
00343
00344 QAbstractProxyModel::setSourceModel( model );
00345
00346 d->sourceMessageModel()->fetchScope().fetchAttribute<MessageThreadingAttribute>();
00347
00348
00349 connect( sourceModel(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( slotInsertRows( QModelIndex, int, int ) ) );
00350 connect( sourceModel(), SIGNAL( rowsAboutToBeRemoved( QModelIndex, int, int ) ), SLOT( slotRemoveRows( QModelIndex, int, int ) ) );
00351 connect( d->sourceMessageModel(), SIGNAL( collectionChanged( Collection ) ), SLOT( slotCollectionChanged() ) );
00352 }
00353
00354
00355 bool MessageThreaderProxyModel::hasChildren( const QModelIndex& index ) const
00356 {
00357 return rowCount( index ) > 0;
00358 }
00359
00360 int MessageThreaderProxyModel::columnCount( const QModelIndex& index ) const
00361 {
00362
00363 return sourceModel()->columnCount( QModelIndex() );
00364 }
00365
00366 int MessageThreaderProxyModel::rowCount( const QModelIndex& index ) const
00367 {
00368 Entity::Id id = d->idForIndex( index );
00369 if ( id == -1 )
00370 return d->childrenMap[ -1 ].count();
00371
00372 if ( index.column() == 0 )
00373 return d->childrenMap[ id ].count();
00374
00375 return 0;
00376 }
00377
00378 QStringList MessageThreaderProxyModel::mimeTypes() const
00379 {
00380 return d->sourceMessageModel()->mimeTypes();
00381 }
00382
00383 QMimeData *MessageThreaderProxyModel::mimeData(const QModelIndexList &indexes) const
00384 {
00385 QModelIndexList sourceIndexes;
00386 for (int i = 0; i < indexes.count(); i++)
00387 sourceIndexes << mapToSource( indexes.at(i) );
00388
00389 return sourceModel()->mimeData(sourceIndexes);
00390 }
00391
00392 #include "messagethreaderproxymodel.moc"