20 #include "messagethreaderproxymodel.h"
21 #include "messagethreadingattribute.h"
22 #include "messagemodel.h"
24 #include <akonadi/attributefactory.h>
25 #include <akonadi/itemfetchjob.h>
26 #include <akonadi/itemfetchscope.h>
28 #include <QtCore/QDebug>
29 #include <QtCore/QString>
30 #include <QtCore/QStringList>
31 #include <QtCore/QHash>
32 #include <QtCore/QTime>
33 #include <QtCore/QModelIndex>
35 using namespace Akonadi;
37 class MessageThreaderProxyModel::Private
48 return dynamic_cast<MessageModel*
>( mParent->sourceModel() );
54 void slotCollectionChanged()
59 realPerfectParentsMap.clear();
60 realUnperfectParentsMap.clear();
61 realSubjectParentsMap.clear();
63 realPerfectChildrenMap.clear();
64 realUnperfectChildrenMap.clear();
65 realSubjectChildrenMap.clear();
74 void slotInsertRows(
const QModelIndex& sourceIndex,
int begin,
int end )
76 Q_UNUSED( sourceIndex );
80 for (
int i=begin; i <= end; i++ )
83 Item item = sourceMessageModel()->itemForIndex( sourceMessageModel()->
index( i, 0 ) );
84 Entity::Id
id = item.id();
86 readParentsFromParts( item );
87 Entity::Id parentId = parentForItem( item.id() );
92 int row = childrenMap[ parentId ].count();
93 mParent->beginInsertRows( indexMap[ parentId ], row, row );
94 childrenMap[ parentId ] << item.id();
95 parentMap[ id ] = parentId;
96 QModelIndex
index = mParent->createIndex( childrenMap[ parentId ].count() - 1, 0,
id );
97 mParent->endInsertRows();
103 QList<Entity::Id> potentialChildren = realPerfectChildrenMap[ id ]
104 << realUnperfectChildrenMap[ id ]
105 << realSubjectChildrenMap[ id ];
106 foreach( Entity::Id potentialChildId, potentialChildren ) {
111 if ( potentialChildId !=
id &&
112 parentMap.constFind( potentialChildId ) != parentMap.constEnd() &&
113 parentMap[ potentialChildId ] !=
id &&
114 parentMap[ potentialChildId ]
119 QList<Entity::Id> realParentsList = realPerfectParentsMap[ potentialChildId ]
120 << realUnperfectParentsMap[ potentialChildId ]
121 << realSubjectParentsMap[ potentialChildId ];
122 int currentParentPos = realParentsList.indexOf( parentMap[ potentialChildId ] );
124 if ( currentParentPos == 0 || ( currentParentPos != -1 && realParentsList.indexOf(
id ) > currentParentPos ) )
129 int childRow = childrenMap[ parentMap[ potentialChildId ] ].indexOf( potentialChildId );
130 mParent->beginRemoveRows( indexMap[ parentMap[ potentialChildId ] ], childRow, childRow );
131 mParent->endRemoveRows();
132 childrenMap[ parentMap[ potentialChildId ] ].removeAt( childRow );
135 mParent->beginInsertRows( index, childrenMap[
id ].count(), childrenMap[
id ].count() );
136 parentMap[ potentialChildId ] = id;
137 childrenMap[ id ] << potentialChildId;
140 mParent->createIndex( childrenMap[
id ].count() - 1, 0, potentialChildId );
141 mParent->endInsertRows();
146 qDebug() << time.elapsed() <<
"ms for" << end - begin + 1 <<
"items";
153 void slotRemoveRows(
const QModelIndex& sourceIndex,
int begin,
int end )
155 Q_UNUSED( sourceIndex );
156 for (
int i = begin; i <= end; i++ )
158 Item item = sourceMessageModel()->itemForIndex( sourceMessageModel()->
index( i, 0 ) );
159 Entity::Id
id = item.id();
160 Entity::Id parentId = parentMap[ id ];
161 int row = childrenMap[ parentId ].indexOf(
id );
164 foreach( Entity::Id childId, childrenMap[
id ] ) {
165 int childRow = childrenMap[ id ].indexOf( childId );
166 mParent->beginRemoveRows( indexMap[
id ], childRow, childRow );
167 childrenMap[ id ].removeAll( childId );
168 mParent->endRemoveRows();
170 mParent->beginInsertRows( indexMap[ parentId ], childrenMap[ parentId ].count(),
171 childrenMap[ parentId ].count() );
172 parentMap[ childId ] = parentId;
173 childrenMap[ parentId ] << childId;
174 mParent->endInsertRows();
176 mParent->createIndex( childrenMap[ parentId ].count() - 1, 0, childId );
179 mParent->beginRemoveRows( indexMap[ parentId ], row, row );
180 childrenMap[ parentId ].removeAll(
id );
181 parentMap.remove(
id );
182 indexMap.remove(
id );
183 mParent->endRemoveRows();
197 void readParentsFromParts(
const Item& item )
201 QList<Entity::Id> realPerfectParentsList = attr->
perfectParents();
203 QList<Entity::Id> realSubjectParentsList = attr->
subjectParents();
205 realPerfectParentsMap[ item.id() ] = realPerfectParentsList;
206 realUnperfectParentsMap[ item.id() ] = realUnperfectParentsList;
207 realSubjectParentsMap[ item.id() ] = realSubjectParentsList;
210 foreach( Entity::Id parentId, realPerfectParentsList )
211 realPerfectChildrenMap[ parentId ] << item.id();
212 foreach( Entity::Id parentId, realUnperfectParentsList )
213 realUnperfectChildrenMap[ parentId ] << item.id();
214 foreach( Entity::Id parentId, realSubjectParentsList )
215 realSubjectChildrenMap[ parentId ] << item.id();
224 Entity::Id parentForItem( Entity::Id
id )
227 QList<Entity::Id> parentsIds;
228 parentsIds << realPerfectParentsMap[ id ] << realUnperfectParentsMap[ id ] << realSubjectParentsMap[ id ];
230 foreach( Entity::Id parentId, parentsIds )
234 if ( sourceMessageModel()->indexForItem( Item( parentId ), 0 ).isValid() )
244 Entity::Id idForIndex(
const QModelIndex& index )
246 return index.isValid() ? index.internalId() : -1;
256 QHash<Entity::Id, QList<Entity::Id> > childrenMap;
257 QHash<Entity::Id, Entity::Id> parentMap;
258 QHash<Entity::Id, QModelIndex> indexMap;
265 QHash<Entity::Id, QList<Entity::Id> > realPerfectParentsMap;
266 QHash<Entity::Id, QList<Entity::Id> > realUnperfectParentsMap;
267 QHash<Entity::Id, QList<Entity::Id> > realSubjectParentsMap;
269 QHash<Entity::Id, QList<Entity::Id> > realPerfectChildrenMap;
270 QHash<Entity::Id, QList<Entity::Id> > realUnperfectChildrenMap;
271 QHash<Entity::Id, QList<Entity::Id> > realSubjectChildrenMap;
275 : QAbstractProxyModel( parent ),
276 d( new Private( this ) )
278 AttributeFactory::registerAttribute<MessageThreadingAttribute>();
288 Entity::Id parentId = d->idForIndex( parent );
292 || row >= d->childrenMap[ parentId ].count()
295 return QModelIndex();
297 Entity::Id
id = d->childrenMap[ parentId ].at( row );
304 if ( !index.isValid() )
305 return QModelIndex();
307 Entity::Id parentId = d->parentMap[ index.internalId() ];
309 if ( parentId == -1 )
310 return QModelIndex();
314 return d->indexMap[ d->parentMap[ index.internalId() ] ];
321 return d->sourceMessageModel()->indexForItem( Item( index.internalId() ), index.column() );
326 Item item = d->sourceMessageModel()->itemForIndex( index );
327 Entity::Id
id = item.id();
334 QModelIndex index = QAbstractProxyModel::createIndex( row, column, internalId );
336 d->indexMap[ internalId ] =
index;
343 QAbstractProxyModel::setSourceModel( model );
348 connect( sourceModel(), SIGNAL(rowsInserted(QModelIndex,
int,
int)), SLOT(slotInsertRows(QModelIndex,
int,
int)) );
349 connect( sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,
int,
int)), SLOT(slotRemoveRows(QModelIndex,
int,
int)) );
350 connect( d->sourceMessageModel(), SIGNAL(collectionChanged(Akonadi::Collection)), SLOT(slotCollectionChanged()) );
362 return sourceModel()->columnCount( QModelIndex() );
367 Entity::Id
id = d->idForIndex( index );
369 return d->childrenMap[ -1 ].count();
371 if ( index.column() == 0 )
372 return d->childrenMap[
id ].count();
379 return d->sourceMessageModel()->mimeTypes();
384 QModelIndexList sourceIndexes;
385 for (
int i = 0; i < indexes.count(); i++)
388 return sourceModel()->mimeData(sourceIndexes);
391 #include "moc_messagethreaderproxymodel.cpp"