2 Copyright (c) 2009 Stephen Kelly <steveire@gmail.com>
3 Copyright (C) 2010 Klarälvdalens Datakonsult AB,
4 a KDAB Group company, info@kdab.net,
5 author Stephen Kelly <stephen@kdab.com>
7 This library is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Library General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at your
10 option) any later version.
12 This library is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
15 License for more details.
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 #include "kdescendantsproxymodel.h"
25 #include <QtCore/QStringList>
26 #include <QtCore/QTimer>
28 #include "kbihash_p.h"
30 typedef KHash2Map
<QPersistentModelIndex
, int> Mapping
;
32 class KDescendantsProxyModelPrivate
34 KDescendantsProxyModelPrivate(KDescendantsProxyModel
* qq
)
37 m_ignoreNextLayoutAboutToBeChanged(false),
38 m_ignoreNextLayoutChanged(false),
40 m_displayAncestorData( false ),
41 m_ancestorSeparator( QStringLiteral( " / " ) )
45 Q_DECLARE_PUBLIC(KDescendantsProxyModel
)
46 KDescendantsProxyModel
* const q_ptr
;
48 mutable QVector
<QPersistentModelIndex
> m_pendingParents
;
50 void scheduleProcessPendingParents() const;
51 void processPendingParents();
53 void synchronousMappingRefresh();
55 void updateInternalIndexes(int start
, int offset
);
57 void resetInternalData();
59 void sourceRowsAboutToBeInserted(const QModelIndex
&, int, int);
60 void sourceRowsInserted(const QModelIndex
&, int, int);
61 void sourceRowsAboutToBeRemoved(const QModelIndex
&, int, int);
62 void sourceRowsRemoved(const QModelIndex
&, int, int);
63 void sourceRowsAboutToBeMoved(const QModelIndex
&, int, int, const QModelIndex
&, int);
64 void sourceRowsMoved(const QModelIndex
&, int, int, const QModelIndex
&, int);
65 void sourceModelAboutToBeReset();
66 void sourceModelReset();
67 void sourceLayoutAboutToBeChanged();
68 void sourceLayoutChanged();
69 void sourceDataChanged(const QModelIndex
&, const QModelIndex
&);
70 void sourceModelDestroyed();
74 QPair
<int, int> m_removePair
;
75 QPair
<int, int> m_insertPair
;
77 bool m_ignoreNextLayoutAboutToBeChanged
;
78 bool m_ignoreNextLayoutChanged
;
81 bool m_displayAncestorData
;
82 QString m_ancestorSeparator
;
84 QList
<QPersistentModelIndex
> m_layoutChangePersistentIndexes
;
85 QModelIndexList m_proxyIndexes
;
86 QHash
<int,QByteArray
> m_roleNames
;
89 void KDescendantsProxyModelPrivate::resetInternalData()
93 m_layoutChangePersistentIndexes
.clear();
94 m_proxyIndexes
.clear();
97 void KDescendantsProxyModelPrivate::synchronousMappingRefresh()
101 m_pendingParents
.clear();
103 m_pendingParents
.append(QModelIndex());
105 m_relayouting
= true;
106 while (!m_pendingParents
.isEmpty())
108 processPendingParents();
110 m_relayouting
= false;
113 void KDescendantsProxyModelPrivate::scheduleProcessPendingParents() const
115 const_cast<KDescendantsProxyModelPrivate
*>(this)->processPendingParents();
118 void KDescendantsProxyModelPrivate::processPendingParents()
120 Q_Q(KDescendantsProxyModel
);
121 const QVector
<QPersistentModelIndex
>::iterator begin
= m_pendingParents
.begin();
122 QVector
<QPersistentModelIndex
>::iterator it
= begin
;
124 const QVector
<QPersistentModelIndex
>::iterator end
= m_pendingParents
.end();
126 QVector
<QPersistentModelIndex
> newPendingParents
;
128 while (it
!= end
&& it
!= m_pendingParents
.end()) {
129 const QModelIndex sourceParent
= *it
;
130 if (!sourceParent
.isValid() && m_rowCount
> 0)
132 // It was removed from the source model before it was inserted.
133 it
= m_pendingParents
.erase(it
);
136 const int rowCount
= q
->sourceModel()->rowCount(sourceParent
);
138 Q_ASSERT(rowCount
> 0);
139 const QPersistentModelIndex sourceIndex
= q
->sourceModel()->index(rowCount
- 1, 0, sourceParent
);
141 Q_ASSERT(sourceIndex
.isValid());
143 const QModelIndex proxyParent
= q
->mapFromSource(sourceParent
);
145 Q_ASSERT(sourceParent
.isValid() == proxyParent
.isValid());
146 const int proxyEndRow
= proxyParent
.row() + rowCount
;
147 const int proxyStartRow
= proxyEndRow
- rowCount
+ 1;
150 q
->beginInsertRows(QModelIndex(), proxyStartRow
, proxyEndRow
);
152 updateInternalIndexes(proxyStartRow
, rowCount
);
153 m_mapping
.insert(sourceIndex
, proxyEndRow
);
154 it
= m_pendingParents
.erase(it
);
155 m_rowCount
+= rowCount
;
160 for (int sourceRow
= 0; sourceRow
< rowCount
; ++sourceRow
) {
161 static const int column
= 0;
162 const QModelIndex child
= q
->sourceModel()->index(sourceRow
, column
, sourceParent
);
163 Q_ASSERT(child
.isValid());
165 if (q
->sourceModel()->hasChildren(child
))
167 Q_ASSERT(q
->sourceModel()->rowCount(child
) > 0);
168 newPendingParents
.append(child
);
172 m_pendingParents
+= newPendingParents
;
173 if (!m_pendingParents
.isEmpty())
174 processPendingParents();
175 // scheduleProcessPendingParents();
178 void KDescendantsProxyModelPrivate::updateInternalIndexes(int start
, int offset
)
180 // TODO: Make KHash2Map support key updates and do this backwards.
181 QHash
<int, QPersistentModelIndex
> updates
;
183 Mapping::right_iterator it
= m_mapping
.rightLowerBound(start
);
184 const Mapping::right_iterator end
= m_mapping
.rightEnd();
188 updates
.insert(it
.key() + offset
, *it
);
194 QHash
<int, QPersistentModelIndex
>::const_iterator it
= updates
.constBegin();
195 const QHash
<int, QPersistentModelIndex
>::const_iterator end
= updates
.constEnd();
197 for ( ; it
!= end
; ++it
)
199 m_mapping
.insert(it
.value(), it
.key());
205 KDescendantsProxyModel::KDescendantsProxyModel(QObject
*parent
)
206 : QAbstractProxyModel(parent
), d_ptr(new KDescendantsProxyModelPrivate(this))
210 KDescendantsProxyModel::~KDescendantsProxyModel()
215 void KDescendantsProxyModel::setRootIndex(const QModelIndex
&index
)
220 QModelIndexList
KDescendantsProxyModel::match(const QModelIndex
&start
, int role
, const QVariant
&value
, int hits
, Qt::MatchFlags flags
) const
222 return QAbstractProxyModel::match(start
, role
, value
, hits
, flags
);
225 void KDescendantsProxyModel::setDisplayAncestorData( bool display
)
227 Q_D(KDescendantsProxyModel
);
228 d
->m_displayAncestorData
= display
;
231 bool KDescendantsProxyModel::displayAncestorData() const
233 Q_D(const KDescendantsProxyModel
);
234 return d
->m_displayAncestorData
;
237 void KDescendantsProxyModel::setAncestorSeparator( const QString
&separator
)
239 Q_D(KDescendantsProxyModel
);
240 d
->m_ancestorSeparator
= separator
;
243 QString
KDescendantsProxyModel::ancestorSeparator() const
245 Q_D(const KDescendantsProxyModel
);
246 return d
->m_ancestorSeparator
;
250 void KDescendantsProxyModel::setSourceModel(QAbstractItemModel
*_sourceModel
)
255 disconnect(_sourceModel
, SIGNAL(rowsAboutToBeInserted(const QModelIndex
&, int, int)),
256 this, SLOT(sourceRowsAboutToBeInserted(const QModelIndex
&, int, int)));
257 disconnect(_sourceModel
, SIGNAL(rowsInserted(const QModelIndex
&, int, int)),
258 this, SLOT(sourceRowsInserted(const QModelIndex
&, int, int)));
259 disconnect(_sourceModel
, SIGNAL(rowsAboutToBeRemoved(const QModelIndex
&, int, int)),
260 this, SLOT(sourceRowsAboutToBeRemoved(const QModelIndex
&, int, int)));
261 disconnect(_sourceModel
, SIGNAL(rowsRemoved(const QModelIndex
&, int, int)),
262 this, SLOT(sourceRowsRemoved(const QModelIndex
&, int, int)));
263 // disconnect(_sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
264 // this, SLOT(sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
265 // disconnect(_sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
266 // this, SLOT(sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
267 disconnect(_sourceModel
, SIGNAL(modelAboutToBeReset()),
268 this, SLOT(sourceModelAboutToBeReset()));
269 disconnect(_sourceModel
, SIGNAL(modelReset()),
270 this, SLOT(sourceModelReset()));
271 disconnect(_sourceModel
, SIGNAL(dataChanged(const QModelIndex
&, const QModelIndex
&)),
272 this, SLOT(sourceDataChanged(const QModelIndex
&, const QModelIndex
&)));
273 disconnect(_sourceModel
, SIGNAL(layoutAboutToBeChanged()),
274 this, SLOT(sourceLayoutAboutToBeChanged()));
275 disconnect(_sourceModel
, SIGNAL(layoutChanged()),
276 this, SLOT(sourceLayoutChanged()));
277 disconnect(_sourceModel
, SIGNAL(destroyed()),
278 this, SLOT(sourceModelDestroyed()));
281 QAbstractProxyModel::setSourceModel(_sourceModel
);
284 connect(_sourceModel
, SIGNAL(rowsAboutToBeInserted(const QModelIndex
&, int, int)),
285 SLOT(sourceRowsAboutToBeInserted(const QModelIndex
&, int, int)));
286 connect(_sourceModel
, SIGNAL(rowsInserted(const QModelIndex
&, int, int)),
287 SLOT(sourceRowsInserted(const QModelIndex
&, int, int)));
288 connect(_sourceModel
, SIGNAL(rowsAboutToBeRemoved(const QModelIndex
&, int, int)),
289 SLOT(sourceRowsAboutToBeRemoved(const QModelIndex
&, int, int)));
290 connect(_sourceModel
, SIGNAL(rowsRemoved(const QModelIndex
&, int, int)),
291 SLOT(sourceRowsRemoved(const QModelIndex
&, int, int)));
292 // connect(_sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
293 // SLOT(sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
294 // connect(_sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
295 // SLOT(sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
296 connect(_sourceModel
, SIGNAL(modelAboutToBeReset()),
297 SLOT(sourceModelAboutToBeReset()));
298 connect(_sourceModel
, SIGNAL(modelReset()),
299 SLOT(sourceModelReset()));
300 connect(_sourceModel
, SIGNAL(dataChanged(const QModelIndex
&, const QModelIndex
&)),
301 SLOT(sourceDataChanged(const QModelIndex
&, const QModelIndex
&)));
302 connect(_sourceModel
, SIGNAL(layoutAboutToBeChanged()),
303 SLOT(sourceLayoutAboutToBeChanged()));
304 connect(_sourceModel
, SIGNAL(layoutChanged()),
305 SLOT(sourceLayoutChanged()));
306 connect(_sourceModel
, SIGNAL(destroyed()),
307 SLOT(sourceModelDestroyed()));
313 QModelIndex
KDescendantsProxyModel::parent(const QModelIndex
&index
) const
316 return QModelIndex();
319 bool KDescendantsProxyModel::hasChildren(const QModelIndex
&parent
) const
321 Q_D(const KDescendantsProxyModel
);
322 return !(d
->m_mapping
.isEmpty() || parent
.isValid());
325 int KDescendantsProxyModel::rowCount(const QModelIndex
&parent
) const
327 Q_D(const KDescendantsProxyModel
);
328 if (d
->m_pendingParents
.contains(parent
) || parent
.isValid() || !sourceModel())
331 if (d
->m_mapping
.isEmpty() && sourceModel()->hasChildren())
333 Q_ASSERT(sourceModel()->rowCount() > 0);
334 const_cast<KDescendantsProxyModelPrivate
*>(d
)->synchronousMappingRefresh();
336 return d
->m_rowCount
;
339 QModelIndex
KDescendantsProxyModel::index(int row
, int column
, const QModelIndex
&parent
) const
341 if (parent
.isValid())
342 return QModelIndex();
344 if (!hasIndex(row
, column
, parent
))
345 return QModelIndex();
347 return createIndex(row
, column
);
350 QModelIndex
KDescendantsProxyModel::mapToSource(const QModelIndex
&proxyIndex
) const
352 Q_D(const KDescendantsProxyModel
);
353 if (d
->m_mapping
.isEmpty() || !proxyIndex
.isValid() || !sourceModel())
354 return QModelIndex();
356 const Mapping::right_const_iterator result
= d
->m_mapping
.rightLowerBound(proxyIndex
.row());
357 Q_ASSERT(result
!= d
->m_mapping
.rightEnd());
359 const int proxyLastRow
= result
.key();
360 const QModelIndex sourceLastChild
= result
.value();
361 Q_ASSERT(sourceLastChild
.isValid());
363 // proxyLastRow is greater than proxyIndex.row().
364 // sourceLastChild is vertically below the result we're looking for
365 // and not necessarily in the correct parent.
366 // We travel up through its parent hierarchy until we are in the
367 // right parent, then return the correct sibling.
369 // Source: Proxy: Row
386 // Note that L, N and O are lastChildIndexes, and therefore have a mapping. If we
387 // are trying to map G from the proxy to the source, We at this point have an iterator
388 // pointing to (L -> 11). The proxy row of G is 6. (proxyIndex.row() == 6). We seek the
389 // sourceIndex which is vertically above L by the distance proxyLastRow - proxyIndex.row().
390 // In this case the verticalDistance is 5.
392 int verticalDistance
= proxyLastRow
- proxyIndex
.row();
394 // We traverse the ancestors of L, until we can index the desired row in the source.
396 QModelIndex ancestor
= sourceLastChild
;
397 while (ancestor
.isValid())
399 const int ancestorRow
= ancestor
.row();
400 if (verticalDistance
<= ancestorRow
)
402 return ancestor
.sibling(ancestorRow
- verticalDistance
, proxyIndex
.column());
404 verticalDistance
-= (ancestorRow
+ 1);
405 ancestor
= ancestor
.parent();
407 Q_ASSERT(!"Didn't find target row.");
408 return QModelIndex();
411 QModelIndex
KDescendantsProxyModel::mapFromSource(const QModelIndex
&sourceIndex
) const
413 Q_D(const KDescendantsProxyModel
);
416 return QModelIndex();
418 if (d
->m_mapping
.isEmpty())
419 return QModelIndex();
423 // TODO: Consider a parent Mapping to speed this up.
425 Mapping::right_const_iterator it
= d
->m_mapping
.rightConstBegin();
426 const Mapping::right_const_iterator end
= d
->m_mapping
.rightConstEnd();
427 const QModelIndex sourceParent
= sourceIndex
.parent();
428 Mapping::right_const_iterator result
= end
;
430 for ( ; it
!= end
; ++it
)
432 QModelIndex index
= it
.value();
433 bool found_block
= false;
434 while (index
.isValid())
436 const QModelIndex ancestor
= index
.parent();
437 if (ancestor
== sourceParent
&& index
.row() >= sourceIndex
.row())
440 if (result
== end
|| it
.key() < result
.key())
443 break; // Leave the while loop. index is still valid.
448 if (found_block
&& !index
.isValid())
449 // Looked through the ascendants of it.key() without finding sourceParent.
450 // That means we've already got the result we need.
453 Q_ASSERT(result
!= end
);
454 const QModelIndex sourceLastChild
= result
.value();
455 int proxyRow
= result
.key();
456 QModelIndex index
= sourceLastChild
;
457 while (index
.isValid())
459 const QModelIndex ancestor
= index
.parent();
460 if (ancestor
== sourceParent
)
462 return createIndex(proxyRow
- (index
.row() - sourceIndex
.row()), sourceIndex
.column());
464 proxyRow
-= (index
.row() + 1);
467 Q_ASSERT(!"Didn't find valid proxy mapping.");
468 return QModelIndex();
473 int KDescendantsProxyModel::columnCount(const QModelIndex
&parent
) const
475 if (parent
.isValid() /* || rowCount(parent) == 0 */ || !sourceModel())
478 return sourceModel()->columnCount();
481 QVariant
KDescendantsProxyModel::data(const QModelIndex
&index
, int role
) const
483 Q_D(const KDescendantsProxyModel
);
488 if (!index
.isValid())
489 return sourceModel()->data(index
, role
);
491 QModelIndex sourceIndex
= mapToSource( index
);
493 if ((d
->m_displayAncestorData
) && ( role
== Qt::DisplayRole
) )
495 if (!sourceIndex
.isValid())
499 QString displayData
= sourceIndex
.data().toString();
500 sourceIndex
= sourceIndex
.parent();
501 while (sourceIndex
.isValid())
503 displayData
.prepend(d
->m_ancestorSeparator
);
504 displayData
.prepend(sourceIndex
.data().toString());
505 sourceIndex
= sourceIndex
.parent();
509 return sourceIndex
.data(role
);
513 QVariant
KDescendantsProxyModel::headerData(int section
, Qt::Orientation orientation
, int role
) const
515 if (!sourceModel() || columnCount() <= section
)
518 return QAbstractProxyModel::headerData(section
, orientation
, role
);
521 Qt::ItemFlags
KDescendantsProxyModel::flags(const QModelIndex
&index
) const
523 if (!index
.isValid() || !sourceModel())
524 return QAbstractProxyModel::flags(index
);
526 const QModelIndex srcIndex
= mapToSource(index
);
527 Q_ASSERT(srcIndex
.isValid());
528 return sourceModel()->flags(srcIndex
);
531 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex
&parent
, int start
, int end
)
533 Q_Q(KDescendantsProxyModel
);
535 if (!q
->sourceModel()->hasChildren(parent
))
537 Q_ASSERT(q
->sourceModel()->rowCount(parent
) == 0);
538 // parent was not a parent before.
544 const int rowCount
= q
->sourceModel()->rowCount(parent
);
546 if (rowCount
> start
)
548 const QModelIndex belowStart
= q
->sourceModel()->index(start
, 0, parent
);
549 proxyStart
= q
->mapFromSource(belowStart
).row();
550 } else if (rowCount
== 0)
552 proxyStart
= q
->mapFromSource(parent
).row() + 1;
554 Q_ASSERT(rowCount
== start
);
555 static const int column
= 0;
556 QModelIndex idx
= q
->sourceModel()->index(rowCount
- 1, column
, parent
);
557 while (q
->sourceModel()->hasChildren(idx
))
559 Q_ASSERT(q
->sourceModel()->rowCount(idx
) > 0);
560 idx
= q
->sourceModel()->index(q
->sourceModel()->rowCount(idx
) - 1, column
, idx
);
562 // The last item in the list is getting a sibling below it.
563 proxyStart
= q
->mapFromSource(idx
).row() + 1;
565 const int proxyEnd
= proxyStart
+ (end
- start
);
567 m_insertPair
= qMakePair(proxyStart
, proxyEnd
);
568 q
->beginInsertRows(QModelIndex(), proxyStart
, proxyEnd
);
571 void KDescendantsProxyModelPrivate::sourceRowsInserted(const QModelIndex
&parent
, int start
, int end
)
573 Q_Q(KDescendantsProxyModel
);
575 Q_ASSERT(q
->sourceModel()->index(start
, 0, parent
).isValid());
577 const int rowCount
= q
->sourceModel()->rowCount(parent
);
578 Q_ASSERT(rowCount
> 0);
580 const int difference
= end
- start
+ 1;
582 if (rowCount
== difference
)
584 // @p parent was not a parent before.
585 m_pendingParents
.append(parent
);
586 scheduleProcessPendingParents();
590 const int proxyStart
= m_insertPair
.first
;
592 Q_ASSERT(proxyStart
>= 0);
594 updateInternalIndexes(proxyStart
, difference
);
596 if (rowCount
- 1 == end
)
598 // The previously last row (the mapped one) is no longer the last.
611 // As last children, E, F and G have mappings.
612 // Consider that 'J' is appended to the children of 'C', below 'E'.
625 // The updateInternalIndexes call above will have updated the F and G mappings correctly because proxyStart is 5.
626 // That means that E -> 4 was not affected by the updateInternalIndexes call.
627 // Now the mapping for E -> 4 needs to be updated so that it's a mapping for J -> 5.
629 Q_ASSERT(!m_mapping
.isEmpty());
630 static const int column
= 0;
631 const QModelIndex oldIndex
= q
->sourceModel()->index(rowCount
- 1 - difference
, column
, parent
);
632 Q_ASSERT(m_mapping
.leftContains(oldIndex
));
634 const QModelIndex newIndex
= q
->sourceModel()->index(rowCount
- 1, column
, parent
);
636 QModelIndex indexAbove
= oldIndex
;
639 // If we have something like this:
645 // and we then insert D as a sibling of A below it, we need to remove the mapping for A,
646 // and the row number used for D must take into account the descendants of A.
648 while (q
->sourceModel()->hasChildren(indexAbove
)) {
649 Q_ASSERT(q
->sourceModel()->rowCount(indexAbove
) > 0);
650 indexAbove
= q
->sourceModel()->index(q
->sourceModel()->rowCount(indexAbove
) - 1, column
, indexAbove
);
652 Q_ASSERT(q
->sourceModel()->rowCount(indexAbove
) == 0);
655 Q_ASSERT(m_mapping
.leftContains(indexAbove
));
657 const int newProxyRow
= m_mapping
.leftToRight(indexAbove
) + difference
;
659 // oldIndex is E in the source. proxyRow is 4.
660 m_mapping
.removeLeft(oldIndex
);
662 // newIndex is J. (proxyRow + difference) is 5.
663 m_mapping
.insert(newIndex
, newProxyRow
);
666 for (int row
= start
; row
<= end
; ++row
)
668 static const int column
= 0;
669 const QModelIndex idx
= q
->sourceModel()->index(row
, column
, parent
);
670 Q_ASSERT(idx
.isValid());
671 if (q
->sourceModel()->hasChildren(idx
))
673 Q_ASSERT(q
->sourceModel()->rowCount(idx
) > 0);
674 m_pendingParents
.append(idx
);
678 m_rowCount
+= difference
;
681 scheduleProcessPendingParents();
684 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex
&parent
, int start
, int end
)
686 Q_Q(KDescendantsProxyModel
);
688 const int proxyStart
= q
->mapFromSource(q
->sourceModel()->index(start
, 0, parent
)).row();
690 static const int column
= 0;
691 QModelIndex idx
= q
->sourceModel()->index(end
, column
, parent
);
692 while (q
->sourceModel()->hasChildren(idx
))
694 Q_ASSERT(q
->sourceModel()->rowCount(idx
) > 0);
695 idx
= q
->sourceModel()->index(q
->sourceModel()->rowCount(idx
) - 1, column
, idx
);
697 const int proxyEnd
= q
->mapFromSource(idx
).row();
699 m_removePair
= qMakePair(proxyStart
, proxyEnd
);
701 q
->beginRemoveRows(QModelIndex(), proxyStart
, proxyEnd
);
704 static QModelIndex
getFirstDeepest(QAbstractItemModel
*model
, const QModelIndex
&parent
, int *count
) {
705 static const int column
= 0;
706 Q_ASSERT(model
->hasChildren(parent
));
707 Q_ASSERT(model
->rowCount(parent
) > 0);
708 for (int row
= 0; row
< model
->rowCount(parent
); ++row
) {
710 const QModelIndex child
= model
->index(row
, column
, parent
);
711 Q_ASSERT(child
.isValid());
712 if (model
->hasChildren(child
))
713 return getFirstDeepest(model
, child
, count
);
715 return model
->index(model
->rowCount(parent
) - 1, column
, parent
);
718 void KDescendantsProxyModelPrivate::sourceRowsRemoved(const QModelIndex
&parent
, int start
, int end
)
720 Q_Q(KDescendantsProxyModel
);
723 const int rowCount
= q
->sourceModel()->rowCount(parent
);
726 const int proxyStart
= m_removePair
.first
;
727 const int proxyEnd
= m_removePair
.second
;
729 const int difference
= proxyEnd
- proxyStart
+ 1;
731 Mapping::right_iterator it
= m_mapping
.rightLowerBound(proxyStart
);
732 const Mapping::right_iterator endIt
= m_mapping
.rightUpperBound(proxyEnd
);
734 if (endIt
!= m_mapping
.rightEnd())
736 it
= m_mapping
.eraseRight(it
);
738 while (it
!= m_mapping
.rightUpperBound(proxyEnd
))
739 it
= m_mapping
.eraseRight(it
);
742 m_removePair
= qMakePair(-1, -1);
743 m_rowCount
-= difference
;
744 Q_ASSERT(m_rowCount
>= 0);
746 updateInternalIndexes(proxyStart
, -1 * difference
);
748 if (rowCount
!= start
|| rowCount
== 0) {
753 static const int column
= 0;
754 const QModelIndex newEnd
= q
->sourceModel()->index(rowCount
- 1, column
, parent
);
755 Q_ASSERT(newEnd
.isValid());
757 if (m_mapping
.isEmpty()) {
758 m_mapping
.insert(newEnd
, newEnd
.row());
762 if (q
->sourceModel()->hasChildren(newEnd
)) {
764 const QModelIndex firstDeepest
= getFirstDeepest(q
->sourceModel(), newEnd
, &count
);
765 Q_ASSERT(firstDeepest
.isValid());
766 const int firstDeepestProxy
= m_mapping
.leftToRight(firstDeepest
);
768 m_mapping
.insert(newEnd
, firstDeepestProxy
- count
);
772 Mapping::right_iterator lowerBound
= m_mapping
.rightLowerBound(proxyStart
);
773 if (lowerBound
== m_mapping
.rightEnd()) {
774 int proxyRow
= (lowerBound
- 1).key();
776 for (int row
= newEnd
.row(); row
>= 0; --row
) {
777 const QModelIndex newEndSibling
= q
->sourceModel()->index(row
, column
, parent
);
778 if (!q
->sourceModel()->hasChildren(newEndSibling
)) {
784 m_mapping
.insert(newEnd
, proxyRow
);
787 } else if (lowerBound
== m_mapping
.rightBegin()) {
788 int proxyRow
= rowCount
- 1;
789 QModelIndex trackedParent
= parent
;
790 while (trackedParent
.isValid()) {
791 proxyRow
+= (trackedParent
.row() + 1);
792 trackedParent
= trackedParent
.parent();
794 m_mapping
.insert(newEnd
, proxyRow
);
798 const Mapping::right_iterator boundAbove
= lowerBound
- 1;
800 QVector
<QModelIndex
> targetParents
;
801 targetParents
.push_back(parent
);
803 QModelIndex target
= parent
;
805 while (target
.isValid()) {
806 if (target
== boundAbove
.value()) {
807 m_mapping
.insert(newEnd
, count
+ boundAbove
.key() + newEnd
.row() + 1);
811 count
+= (target
.row() + 1);
812 target
= target
.parent();
813 if (target
.isValid())
814 targetParents
.push_back(target
);
818 QModelIndex boundParent
= boundAbove
.value().parent();
819 QModelIndex prevParent
= boundParent
;
820 Q_ASSERT(boundParent
.isValid());
821 while (boundParent
.isValid()) {
822 prevParent
= boundParent
;
823 boundParent
= boundParent
.parent();
825 if (targetParents
.contains(prevParent
))
828 if (!m_mapping
.leftContains(prevParent
))
831 if (m_mapping
.leftToRight(prevParent
) > boundAbove
.key())
835 QModelIndex trackedParent
= parent
;
837 int proxyRow
= boundAbove
.key();
839 Q_ASSERT(prevParent
.isValid());
840 proxyRow
-= prevParent
.row();
841 while (trackedParent
!= boundParent
) {
842 proxyRow
+= (trackedParent
.row() + 1);
843 trackedParent
= trackedParent
.parent();
845 m_mapping
.insert(newEnd
, proxyRow
+ newEnd
.row());
849 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex
&srcParent
, int srcStart
, int srcEnd
, const QModelIndex
&destParent
, int destStart
)
856 Q_Q(KDescendantsProxyModel
);
857 q
->beginResetModel();
860 void KDescendantsProxyModelPrivate::sourceRowsMoved(const QModelIndex
&srcParent
, int srcStart
, int srcEnd
, const QModelIndex
&destParent
, int destStart
)
867 Q_Q(KDescendantsProxyModel
);
872 void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset()
874 Q_Q(KDescendantsProxyModel
);
875 q
->beginResetModel();
878 void KDescendantsProxyModelPrivate::sourceModelReset()
880 Q_Q(KDescendantsProxyModel
);
882 if (q
->sourceModel()->hasChildren())
884 Q_ASSERT(q
->sourceModel()->rowCount() > 0);
885 m_pendingParents
.append(QModelIndex());
886 scheduleProcessPendingParents();
891 void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged()
893 Q_Q(KDescendantsProxyModel
);
895 if (m_ignoreNextLayoutChanged
) {
896 m_ignoreNextLayoutChanged
= false;
900 if (m_mapping
.isEmpty())
903 QPersistentModelIndex srcPersistentIndex
;
904 foreach(const QPersistentModelIndex
&proxyPersistentIndex
, q
->persistentIndexList()) {
905 m_proxyIndexes
<< proxyPersistentIndex
;
906 Q_ASSERT(proxyPersistentIndex
.isValid());
907 srcPersistentIndex
= q
->mapToSource(proxyPersistentIndex
);
908 Q_ASSERT(srcPersistentIndex
.isValid());
909 m_layoutChangePersistentIndexes
<< srcPersistentIndex
;
912 q
->layoutAboutToBeChanged();
915 void KDescendantsProxyModelPrivate::sourceLayoutChanged()
917 Q_Q(KDescendantsProxyModel
);
919 if (m_ignoreNextLayoutAboutToBeChanged
) {
920 m_ignoreNextLayoutAboutToBeChanged
= false;
924 if (m_mapping
.isEmpty())
929 synchronousMappingRefresh();
931 for (int i
= 0; i
< m_proxyIndexes
.size(); ++i
) {
932 q
->changePersistentIndex(m_proxyIndexes
.at(i
), q
->mapFromSource(m_layoutChangePersistentIndexes
.at(i
)));
935 m_layoutChangePersistentIndexes
.clear();
936 m_proxyIndexes
.clear();
941 void KDescendantsProxyModelPrivate::sourceDataChanged(const QModelIndex
&topLeft
, const QModelIndex
&bottomRight
)
943 Q_Q(KDescendantsProxyModel
);
944 Q_ASSERT(topLeft
.model() == q
->sourceModel());
945 Q_ASSERT(bottomRight
.model() == q
->sourceModel());
947 const int topRow
= topLeft
.row();
948 const int bottomRow
= bottomRight
.row();
950 for(int i
= topRow
; i
<= bottomRow
; ++i
)
952 const QModelIndex sourceTopLeft
= q
->sourceModel()->index(i
, topLeft
.column(), topLeft
.parent());
953 Q_ASSERT(sourceTopLeft
.isValid());
954 const QModelIndex proxyTopLeft
= q
->mapFromSource(sourceTopLeft
);
955 // TODO. If an index does not have any descendants, then we can emit in blocks of rows.
956 // As it is we emit once for each row.
957 const QModelIndex sourceBottomRight
= q
->sourceModel()->index(i
, bottomRight
.column(), bottomRight
.parent());
958 Q_ASSERT(sourceBottomRight
.isValid());
959 const QModelIndex proxyBottomRight
= q
->mapFromSource(sourceBottomRight
);
960 Q_ASSERT(proxyTopLeft
.isValid());
961 Q_ASSERT(proxyBottomRight
.isValid());
962 emit q
->dataChanged(proxyTopLeft
, proxyBottomRight
);
966 void KDescendantsProxyModelPrivate::sourceModelDestroyed()
971 QMimeData
* KDescendantsProxyModel::mimeData( const QModelIndexList
& indexes
) const
974 return QAbstractProxyModel::mimeData(indexes
);
975 Q_ASSERT(sourceModel());
976 QModelIndexList sourceIndexes
;
977 foreach(const QModelIndex
& index
, indexes
)
978 sourceIndexes
<< mapToSource(index
);
979 return sourceModel()->mimeData(sourceIndexes
);
982 QStringList
KDescendantsProxyModel::mimeTypes() const
985 return QAbstractProxyModel::mimeTypes();
986 Q_ASSERT(sourceModel());
987 return sourceModel()->mimeTypes();
990 Qt::DropActions
KDescendantsProxyModel::supportedDropActions() const
993 return QAbstractProxyModel::supportedDropActions();
994 return sourceModel()->supportedDropActions();
997 void KDescendantsProxyModel::proxySetRoleNames(const QHash
<int, QByteArray
> &roleNames
)
999 Q_D(KDescendantsProxyModel
);
1000 d
->m_roleNames
= roleNames
;
1003 QHash
<int,QByteArray
> KDescendantsProxyModel::roleNames() const
1005 Q_D(const KDescendantsProxyModel
);
1006 return d
->m_roleNames
;
1009 #include "moc_kdescendantsproxymodel.cpp"