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
47 return dynamic_cast<MessageModel*
>( mParent->sourceModel() );
53 void slotCollectionChanged()
58 realPerfectParentsMap.clear();
59 realUnperfectParentsMap.clear();
60 realSubjectParentsMap.clear();
62 realPerfectChildrenMap.clear();
63 realUnperfectChildrenMap.clear();
64 realSubjectChildrenMap.clear();
73 void slotInsertRows(
const QModelIndex& sourceIndex,
int begin,
int end )
75 Q_UNUSED( sourceIndex );
79 for (
int i=begin; i <= end; i++ )
82 Item item = sourceMessageModel()->itemForIndex( sourceMessageModel()->
index( i, 0 ) );
85 readParentsFromParts( item );
86 Entity::Id parentId = parentForItem( item.id() );
91 int row = childrenMap[ parentId ].count();
92 mParent->beginInsertRows( indexMap[ parentId ], row, row );
93 childrenMap[ parentId ] << item.id();
94 parentMap[ id ] = parentId;
95 QModelIndex
index = mParent->createIndex( childrenMap[ parentId ].count() - 1, 0,
id );
96 mParent->endInsertRows();
101 QList<Entity::Id> potentialChildren = realPerfectChildrenMap[ id ]
102 << realUnperfectChildrenMap[ id ]
103 << realSubjectChildrenMap[ id ];
104 foreach(
Entity::Id potentialChildId, potentialChildren ) {
109 if ( potentialChildId !=
id &&
110 parentMap.constFind( potentialChildId ) != parentMap.constEnd() &&
111 parentMap[ potentialChildId ] !=
id &&
112 parentMap[ potentialChildId ]
117 QList<Entity::Id> realParentsList = realPerfectParentsMap[ potentialChildId ]
118 << realUnperfectParentsMap[ potentialChildId ]
119 << realSubjectParentsMap[ potentialChildId ];
120 int currentParentPos = realParentsList.indexOf( parentMap[ potentialChildId ] );
122 if ( currentParentPos == 0 || ( currentParentPos != -1 && realParentsList.indexOf(
id ) > currentParentPos ) )
127 int childRow = childrenMap[ parentMap[ potentialChildId ] ].indexOf( potentialChildId );
128 mParent->beginRemoveRows( indexMap[ parentMap[ potentialChildId ] ], childRow, childRow );
129 mParent->endRemoveRows();
130 childrenMap[ parentMap[ potentialChildId ] ].removeAt( childRow );
133 mParent->beginInsertRows( index, childrenMap[
id ].count(), childrenMap[
id ].count() );
134 parentMap[ potentialChildId ] = id;
135 childrenMap[ id ] << potentialChildId;
138 mParent->createIndex( childrenMap[
id ].count() - 1, 0, potentialChildId );
139 mParent->endInsertRows();
144 qDebug() << time.elapsed() <<
"ms for" << end - begin + 1 <<
"items";
151 void slotRemoveRows(
const QModelIndex& sourceIndex,
int begin,
int end )
153 Q_UNUSED( sourceIndex );
154 for (
int i = begin; i <= end; i++ )
156 Item item = sourceMessageModel()->itemForIndex( sourceMessageModel()->
index( i, 0 ) );
159 int row = childrenMap[ parentId ].indexOf(
id );
162 foreach(
Entity::Id childId, childrenMap[
id ] ) {
163 int childRow = childrenMap[ id ].indexOf( childId );
164 mParent->beginRemoveRows( indexMap[
id ], childRow, childRow );
165 childrenMap[ id ].removeAll( childId );
166 mParent->endRemoveRows();
168 mParent->beginInsertRows( indexMap[ parentId ], childrenMap[ parentId ].count(),
169 childrenMap[ parentId ].count() );
170 parentMap[ childId ] = parentId;
171 childrenMap[ parentId ] << childId;
172 mParent->endInsertRows();
174 mParent->createIndex( childrenMap[ parentId ].count() - 1, 0, childId );
177 mParent->beginRemoveRows( indexMap[ parentId ], row, row );
178 childrenMap[ parentId ].removeAll(
id );
179 parentMap.remove(
id );
180 indexMap.remove(
id );
181 mParent->endRemoveRows();
195 void readParentsFromParts(
const Item& item )
199 QList<Entity::Id> realPerfectParentsList = attr->
perfectParents();
201 QList<Entity::Id> realSubjectParentsList = attr->
subjectParents();
203 realPerfectParentsMap[ item.id() ] = realPerfectParentsList;
204 realUnperfectParentsMap[ item.id() ] = realUnperfectParentsList;
205 realSubjectParentsMap[ item.id() ] = realSubjectParentsList;
208 foreach(
Entity::Id parentId, realPerfectParentsList )
209 realPerfectChildrenMap[ parentId ] << item.id();
210 foreach(
Entity::Id parentId, realUnperfectParentsList )
211 realUnperfectChildrenMap[ parentId ] << item.id();
212 foreach(
Entity::Id parentId, realSubjectParentsList )
213 realSubjectChildrenMap[ parentId ] << item.id();
225 QList<Entity::Id> parentsIds;
226 parentsIds << realPerfectParentsMap[ id ] << realUnperfectParentsMap[ id ] << realSubjectParentsMap[ id ];
232 if ( sourceMessageModel()->indexForItem( Item( parentId ), 0 ).isValid() )
242 Entity::Id idForIndex(
const QModelIndex& index )
244 return index.isValid() ? index.internalId() : -1;
254 QHash<Entity::Id, QList<Entity::Id> > childrenMap;
255 QHash<Entity::Id, Entity::Id> parentMap;
256 QHash<Entity::Id, QModelIndex> indexMap;
263 QHash<Entity::Id, QList<Entity::Id> > realPerfectParentsMap;
264 QHash<Entity::Id, QList<Entity::Id> > realUnperfectParentsMap;
265 QHash<Entity::Id, QList<Entity::Id> > realSubjectParentsMap;
267 QHash<Entity::Id, QList<Entity::Id> > realPerfectChildrenMap;
268 QHash<Entity::Id, QList<Entity::Id> > realUnperfectChildrenMap;
269 QHash<Entity::Id, QList<Entity::Id> > realSubjectChildrenMap;
273 : QAbstractProxyModel( parent ),
274 d( new Private( this ) )
276 AttributeFactory::registerAttribute<MessageThreadingAttribute>();
286 Entity::Id parentId = d->idForIndex( parent );
290 || row >= d->childrenMap[ parentId ].count()
293 return QModelIndex();
295 Entity::Id id = d->childrenMap[ parentId ].at( row );
302 if ( !index.isValid() )
303 return QModelIndex();
305 Entity::Id parentId = d->parentMap[ index.internalId() ];
307 if ( parentId == -1 )
308 return QModelIndex();
312 return d->indexMap[ d->parentMap[ index.internalId() ] ];
319 return d->sourceMessageModel()->indexForItem( Item( index.internalId() ), index.column() );
324 Item item = d->sourceMessageModel()->itemForIndex( index );
332 QModelIndex index = QAbstractProxyModel::createIndex( row, column, internalId );
334 d->indexMap[ internalId ] =
index;
341 QAbstractProxyModel::setSourceModel( model );
346 connect( sourceModel(), SIGNAL(rowsInserted(QModelIndex,
int,
int)), SLOT(slotInsertRows(QModelIndex,
int,
int)) );
347 connect( sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,
int,
int)), SLOT(slotRemoveRows(QModelIndex,
int,
int)) );
348 connect( d->sourceMessageModel(), SIGNAL(collectionChanged(
Akonadi::Collection)), SLOT(slotCollectionChanged()) );
359 return sourceModel()->columnCount( QModelIndex() );
366 return d->childrenMap[ -1 ].count();
368 if ( index.column() == 0 )
369 return d->childrenMap[
id ].count();
376 return d->sourceMessageModel()->mimeTypes();
381 QModelIndexList sourceIndexes;
382 for (
int i = 0; i < indexes.count(); i++)
385 return sourceModel()->mimeData(sourceIndexes);
388 #include "moc_messagethreaderproxymodel.cpp"
void setSourceModel(QAbstractItemModel *sourceMessageModel)
Set the source model.
QStringList mimeTypes() const
Reimplemented.
QModelIndex createIndex(int row, int column, quint32 internalId) const
Reimplemented.
QList< Item::Id > subjectParents() const
Returns the list of possible parent message ids based on analyzing the subject.
QModelIndex mapToSource(const QModelIndex &index) const
Reimplemented.
Represents a collection of PIM items.
qint64 Id
Describes the unique id type.
int rowCount(const QModelIndex &index) const
Reimplemented.
Proxy to thread message using the Mailthreader agent.
QModelIndex mapFromSource(const QModelIndex &index) const
Reimplemented.
Message threading information.
int columnCount(const QModelIndex &index) const
Reimplemented.
QModelIndex parent(const QModelIndex &index) const
Reimplemented to actually do the threading.
QMimeData * mimeData(const QModelIndexList &indexes) const
Reimplemented.
QList< Item::Id > perfectParents() const
Returns the list of perfect parent message ids.
QList< Item::Id > unperfectParents() const
Returns the list of non-perfect parent message ids.
virtual ~MessageThreaderProxyModel()
Destroy the model.
A flat self-updating message model.
MessageThreaderProxyModel(QObject *parent=0)
Create a new MessageThreaderProxyModel.
bool hasChildren(const QModelIndex &index) const
Reimplemented.
QModelIndex index(int row, int column, const QModelIndex &parent) const
Reimplemented.