9#include "kdescendantsproxymodel.h"
15typedef KHash2Map<QPersistentModelIndex, int> Mapping;
17class KDescendantsProxyModelPrivate
19 KDescendantsProxyModelPrivate(KDescendantsProxyModel *qq)
22 , m_ignoreNextLayoutAboutToBeChanged(false)
23 , m_ignoreNextLayoutChanged(false)
24 , m_relayouting(false)
25 , m_displayAncestorData(false)
26 , m_ancestorSeparator(QStringLiteral(
" / "))
30 Q_DECLARE_PUBLIC(KDescendantsProxyModel)
31 KDescendantsProxyModel *
const q_ptr;
33 mutable QList<QPersistentModelIndex> m_pendingParents;
35 void scheduleProcessPendingParents()
const;
36 void processPendingParents();
38 void synchronousMappingRefresh();
40 void updateInternalIndexes(
int start,
int offset);
42 void resetInternalData();
44 void notifyhasSiblings(
const QModelIndex &parent);
45 void sourceRowsAboutToBeInserted(
const QModelIndex &,
int,
int);
46 void sourceRowsInserted(
const QModelIndex &,
int,
int);
47 void sourceRowsAboutToBeRemoved(
const QModelIndex &,
int,
int);
48 void sourceRowsRemoved(
const QModelIndex &,
int,
int);
49 void sourceRowsAboutToBeMoved(
const QModelIndex &,
int,
int,
const QModelIndex &,
int);
50 void sourceRowsMoved(
const QModelIndex &,
int,
int,
const QModelIndex &,
int);
51 void sourceModelAboutToBeReset();
52 void sourceModelReset();
53 void sourceLayoutAboutToBeChanged();
54 void sourceLayoutChanged();
55 void sourceDataChanged(
const QModelIndex &,
const QModelIndex &);
56 void sourceModelDestroyed();
60 QPair<int, int> m_removePair;
61 QPair<int, int> m_insertPair;
63 bool m_expandsByDefault =
true;
64 bool m_ignoreNextLayoutAboutToBeChanged;
65 bool m_ignoreNextLayoutChanged;
68 bool m_displayAncestorData;
69 QString m_ancestorSeparator;
71 QSet<QPersistentModelIndex> m_expandedSourceIndexes;
72 QSet<QPersistentModelIndex> m_collapsedSourceIndexes;
74 QList<QPersistentModelIndex> m_layoutChangePersistentIndexes;
75 QModelIndexList m_proxyIndexes;
78void KDescendantsProxyModelPrivate::resetInternalData()
82 m_layoutChangePersistentIndexes.clear();
83 m_proxyIndexes.clear();
86void KDescendantsProxyModelPrivate::synchronousMappingRefresh()
90 m_pendingParents.clear();
92 m_pendingParents.append(QModelIndex());
95 while (!m_pendingParents.isEmpty()) {
96 processPendingParents();
98 m_relayouting =
false;
101void KDescendantsProxyModelPrivate::scheduleProcessPendingParents()
const
103 const_cast<KDescendantsProxyModelPrivate *
>(
this)->processPendingParents();
106void KDescendantsProxyModelPrivate::processPendingParents()
108 Q_Q(KDescendantsProxyModel);
109 const QList<QPersistentModelIndex>::iterator
begin = m_pendingParents.begin();
110 QList<QPersistentModelIndex>::iterator it =
begin;
112 const QList<QPersistentModelIndex>::iterator
end = m_pendingParents.end();
114 QList<QPersistentModelIndex> newPendingParents;
116 while (it != end && it != m_pendingParents.end()) {
117 const QModelIndex sourceParent = *it;
118 if (!sourceParent.
isValid() && m_rowCount > 0) {
120 it = m_pendingParents.erase(it);
123 if (!q->isSourceIndexVisible(sourceParent)) {
125 it = m_pendingParents.erase(it);
129 const int rowCount = q->sourceModel()->rowCount(sourceParent);
133 it = m_pendingParents.erase(it);
136 const QPersistentModelIndex sourceIndex = q->sourceModel()->index(rowCount - 1, 0, sourceParent);
138 Q_ASSERT(sourceIndex.
isValid());
140 const QModelIndex proxyParent = q->mapFromSource(sourceParent);
143 const int proxyEndRow = proxyParent.
row() + rowCount;
144 const int proxyStartRow = proxyEndRow - rowCount + 1;
146 if (!m_relayouting) {
147 q->beginInsertRows(QModelIndex(), proxyStartRow, proxyEndRow);
150 updateInternalIndexes(proxyStartRow, rowCount);
151 m_mapping.insert(sourceIndex, proxyEndRow);
152 it = m_pendingParents.erase(it);
153 m_rowCount += rowCount;
155 if (!m_relayouting) {
159 for (
int sourceRow = 0; sourceRow < rowCount; ++sourceRow) {
160 static const int column = 0;
161 const QModelIndex child = q->sourceModel()->index(sourceRow, column, sourceParent);
164 if (q->sourceModel()->hasChildren(child) && q->isSourceIndexExpanded(child) && q->sourceModel()->rowCount(child) > 0) {
165 newPendingParents.
append(child);
169 m_pendingParents += newPendingParents;
170 if (!m_pendingParents.isEmpty()) {
171 processPendingParents();
176void KDescendantsProxyModelPrivate::updateInternalIndexes(
int start,
int offset)
179 QHash<int, QPersistentModelIndex> updates;
181 Mapping::right_iterator it = m_mapping.rightLowerBound(
start);
182 const Mapping::right_iterator
end = m_mapping.rightEnd();
185 updates.
insert(it.key() + offset, *it);
191 QHash<int, QPersistentModelIndex>::const_iterator it = updates.
constBegin();
192 const QHash<int, QPersistentModelIndex>::const_iterator
end = updates.
constEnd();
194 for (; it !=
end; ++it) {
195 m_mapping.insert(it.value(), it.key());
202 , d_ptr(new KDescendantsProxyModelPrivate(this))
212 roleNames[LevelRole] =
"kDescendantLevel";
213 roleNames[ExpandableRole] =
"kDescendantExpandable";
214 roleNames[ExpandedRole] =
"kDescendantExpanded";
215 roleNames[HasSiblingsRole] =
"kDescendantHasSiblings";
221 if (d_ptr->m_expandsByDefault == expand) {
226 d_ptr->m_expandsByDefault = expand;
227 d_ptr->m_expandedSourceIndexes.clear();
228 d_ptr->m_collapsedSourceIndexes.clear();
234 return d_ptr->m_expandsByDefault;
242 }
else if (d_ptr->m_expandsByDefault) {
258 index = index.parent();
259 if (!index.isValid()) {
273 if (d_ptr->m_expandsByDefault) {
279 d_ptr->m_pendingParents << sourceIndex;
280 d_ptr->scheduleProcessPendingParents();
281 Q_EMIT sourceIndexExpanded(sourceIndex);
283 const QModelIndex index = mapFromSource(sourceIndex);
293 const int row = mapFromSource(sourceIndex).row();
294 const int rowStart = row + 1;
305 for (
int i = 0; i < nRows; ++i) {
316 if (d_ptr->m_expandsByDefault) {
323 Mapping::right_iterator it = d_ptr->m_mapping.rightLowerBound(rowStart);
324 const Mapping::right_iterator endIt = d_ptr->m_mapping.rightUpperBound(rowEnd);
326 if (endIt != d_ptr->m_mapping.rightEnd()) {
327 while (it != endIt) {
328 it = d_ptr->m_mapping.eraseRight(it);
331 while (it != d_ptr->m_mapping.rightUpperBound(rowEnd)) {
332 it = d_ptr->m_mapping.eraseRight(it);
337 d_ptr->m_removePair = qMakePair(rowStart, rowEnd);
339 d_ptr->synchronousMappingRefresh();
341 Q_EMIT sourceIndexCollapsed(sourceIndex);
343 const QModelIndex ownIndex = mapFromSource(sourceIndex);
361 bool displayChanged = (display != d->m_displayAncestorData);
362 d->m_displayAncestorData = display;
363 if (displayChanged) {
364 Q_EMIT displayAncestorDataChanged();
366 Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1), changedRoles);
373 return d->m_displayAncestorData;
379 bool separatorChanged = (separator != d->m_ancestorSeparator);
380 d->m_ancestorSeparator = separator;
381 if (separatorChanged) {
382 Q_EMIT ancestorSeparatorChanged();
383 if (d->m_displayAncestorData) {
385 Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1), changedRoles);
393 return d->m_ancestorSeparator;
407 d_ptr->m_expandedSourceIndexes.clear();
411 d->sourceRowsAboutToBeInserted(parent,
start, end);
415 d->sourceRowsInserted(parent,
start, end);
419 d->sourceRowsAboutToBeRemoved(parent,
start, end);
423 d->sourceRowsRemoved(parent,
start, end);
429 [d](
const QModelIndex &srcParent,
int srcStart,
int srcEnd,
const QModelIndex &destParent,
int destStart) {
430 d->sourceRowsAboutToBeMoved(srcParent, srcStart, srcEnd, destParent, destStart);
436 [d](
const QModelIndex &srcParent,
int srcStart,
int srcEnd,
const QModelIndex &destParent,
int destStart) {
437 d->sourceRowsMoved(srcParent, srcStart, srcEnd, destParent, destStart);
441 d->sourceModelAboutToBeReset();
445 d->sourceModelReset();
449 d->sourceDataChanged(topLeft, bottomRight);
453 d->sourceLayoutAboutToBeChanged();
457 d->sourceLayoutChanged();
461 d->sourceModelDestroyed();
467 d->synchronousMappingRefresh();
471 Q_EMIT sourceModelChanged();
480bool KDescendantsProxyModel::hasChildren(
const QModelIndex &parent)
const
483 return !(d->m_mapping.isEmpty() || parent.isValid());
486int KDescendantsProxyModel::rowCount(
const QModelIndex &parent)
const
489 if (d->m_pendingParents.contains(parent) || parent.isValid() || !
sourceModel()) {
493 if (d->m_mapping.isEmpty() &&
sourceModel()->hasChildren()) {
494 const_cast<KDescendantsProxyModelPrivate *
>(d)->synchronousMappingRefresh();
496 return d->m_rowCount;
501 if (parent.isValid()) {
502 return QModelIndex();
505 if (!
hasIndex(row, column, parent)) {
506 return QModelIndex();
516 return QModelIndex();
519 const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.
row());
520 Q_ASSERT(result != d->m_mapping.rightEnd());
522 const int proxyLastRow = result.key();
523 const QModelIndex sourceLastChild = result.value();
524 Q_ASSERT(sourceLastChild.
isValid());
555 int verticalDistance = proxyLastRow - proxyIndex.
row();
559 QModelIndex ancestor = sourceLastChild;
561 const int ancestorRow = ancestor.
row();
562 if (verticalDistance <= ancestorRow) {
563 return ancestor.
sibling(ancestorRow - verticalDistance, proxyIndex.
column());
565 verticalDistance -= (ancestorRow + 1);
566 ancestor = ancestor.
parent();
568 Q_ASSERT(!
"Didn't find target row.");
569 return QModelIndex();
577 return QModelIndex();
580 if (d->m_mapping.isEmpty()) {
581 return QModelIndex();
587 Mapping::right_const_iterator it = d->m_mapping.rightConstBegin();
588 const Mapping::right_const_iterator
end = d->m_mapping.rightConstEnd();
589 const QModelIndex sourceParent = sourceIndex.
parent();
590 Mapping::right_const_iterator result =
end;
593 return QModelIndex();
596 for (; it !=
end; ++it) {
597 QModelIndex index = it.value();
598 bool found_block =
false;
599 while (index.isValid()) {
600 const QModelIndex ancestor = index.
parent();
601 if (ancestor == sourceParent && index.row() >= sourceIndex.
row()) {
603 if (result == end || it.key() < result.key()) {
610 if (found_block && !index.isValid())
617 Q_ASSERT(result != end);
618 const QModelIndex sourceLastChild = result.value();
619 int proxyRow = result.key();
620 QModelIndex index = sourceLastChild;
621 while (index.isValid()) {
622 const QModelIndex ancestor = index.
parent();
623 if (ancestor == sourceParent) {
626 proxyRow -= (index.row() + 1);
629 Q_ASSERT(!
"Didn't find valid proxy mapping.");
630 return QModelIndex();
634int KDescendantsProxyModel::columnCount(
const QModelIndex &parent)
const
651 if (!index.isValid()) {
655 QModelIndex sourceIndex = mapToSource(index);
662 sourceIndex = sourceIndex.
parent();
663 while (sourceIndex.
isValid()) {
664 displayData.
prepend(d->m_ancestorSeparator);
666 sourceIndex = sourceIndex.
parent();
669 }
else if (role == LevelRole) {
670 QModelIndex sourceIndex = mapToSource(index);
672 while (sourceIndex.
isValid()) {
673 sourceIndex = sourceIndex.
parent();
677 }
else if (role == ExpandableRole) {
678 QModelIndex sourceIndex = mapToSource(index);
680 }
else if (role == ExpandedRole) {
682 }
else if (role == HasSiblingsRole) {
683 QModelIndex sourceIndex = mapToSource(index);
684 QList<bool> hasSibling;
685 while (sourceIndex.
isValid()) {
687 sourceIndex = sourceIndex.
parent();
691 return sourceIndex.
data(role);
702 return sourceModel()->headerData(section, orientation, role);
711 const QModelIndex srcIndex = mapToSource(index);
716void KDescendantsProxyModelPrivate::notifyhasSiblings(
const QModelIndex &parent)
718 Q_Q(KDescendantsProxyModel);
724 QModelIndex localParent = q->mapFromSource(parent);
725 Q_EMIT q->dataChanged(localParent, localParent, {KDescendantsProxyModel::HasSiblingsRole});
726 for (
int i = 0; i < q->sourceModel()->rowCount(parent); ++i) {
727 notifyhasSiblings(q->sourceModel()->index(i, 0, parent));
731void KDescendantsProxyModelPrivate::sourceRowsAboutToBeInserted(
const QModelIndex &parent,
int start,
int end)
733 Q_Q(KDescendantsProxyModel);
735 if (parent.
isValid() && (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent))) {
739 if (!q->sourceModel()->hasChildren(parent)) {
740 Q_ASSERT(q->sourceModel()->rowCount(parent) == 0);
747 const int rowCount = q->sourceModel()->rowCount(parent);
749 if (rowCount >
start) {
750 const QModelIndex belowStart = q->sourceModel()->index(
start, 0, parent);
751 proxyStart = q->mapFromSource(belowStart).row();
752 }
else if (rowCount == 0) {
753 proxyStart = q->mapFromSource(parent).row() + 1;
755 Q_ASSERT(rowCount ==
start);
756 static const int column = 0;
757 QModelIndex idx = q->sourceModel()->index(rowCount - 1, column, parent);
758 while (q->isSourceIndexExpanded(idx) && q->sourceModel()->hasChildren(idx) && q->sourceModel()->rowCount(idx) > 0) {
759 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
762 proxyStart = q->mapFromSource(idx).row() + 1;
764 const int proxyEnd = proxyStart + (
end -
start);
766 m_insertPair = qMakePair(proxyStart, proxyEnd);
767 q->beginInsertRows(QModelIndex(), proxyStart, proxyEnd);
770void KDescendantsProxyModelPrivate::sourceRowsInserted(
const QModelIndex &parent,
int start,
int end)
772 Q_Q(KDescendantsProxyModel);
773 if (parent.
isValid() && (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent))) {
774 const QModelIndex index = q->mapFromSource(parent);
775 Q_EMIT q->dataChanged(index,
777 {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole, KDescendantsProxyModel::HasSiblingsRole});
779 notifyhasSiblings(q->sourceModel()->index(
start - 1, 0, parent));
783 Q_ASSERT(q->sourceModel()->index(
start, 0, parent).isValid());
785 const int rowCount = q->sourceModel()->rowCount(parent);
786 Q_ASSERT(rowCount > 0);
788 const int difference =
end -
start + 1;
790 if (rowCount == difference) {
791 const QModelIndex index = q->mapFromSource(parent);
793 Q_EMIT q->dataChanged(index,
795 {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole, KDescendantsProxyModel::HasSiblingsRole});
798 m_pendingParents.append(parent);
799 scheduleProcessPendingParents();
801 notifyhasSiblings(q->sourceModel()->index(
start - 1, 0, parent));
806 const int proxyStart = m_insertPair.first;
808 Q_ASSERT(proxyStart >= 0);
810 updateInternalIndexes(proxyStart, difference);
812 if (rowCount - 1 == end) {
844 Q_ASSERT(!m_mapping.isEmpty());
845 static const int column = 0;
846 const QModelIndex oldIndex = q->sourceModel()->index(rowCount - 1 - difference, column, parent);
847 Q_ASSERT(m_mapping.leftContains(oldIndex));
849 const QModelIndex newIndex = q->sourceModel()->index(rowCount - 1, column, parent);
851 QModelIndex indexAbove = oldIndex;
863 while (q->isSourceIndexExpanded(indexAbove) && q->sourceModel()->hasChildren(indexAbove)) {
864 Q_ASSERT(q->sourceModel()->rowCount(indexAbove) > 0);
865 indexAbove = q->sourceModel()->index(q->sourceModel()->rowCount(indexAbove) - 1, column, indexAbove);
867 Q_ASSERT(!q->isSourceIndexExpanded(indexAbove) || q->sourceModel()->rowCount(indexAbove) == 0);
870 Q_ASSERT(m_mapping.leftContains(indexAbove));
872 const int newProxyRow = m_mapping.leftToRight(indexAbove) + difference;
875 m_mapping.removeLeft(oldIndex);
878 m_mapping.insert(newIndex, newProxyRow);
881 for (
int row =
start; row <=
end; ++row) {
882 static const int column = 0;
883 const QModelIndex idx = q->sourceModel()->index(row, column, parent);
886 if (q->isSourceIndexExpanded(idx) && q->sourceModel()->hasChildren(idx) && q->sourceModel()->rowCount(idx) > 0) {
887 m_pendingParents.append(idx);
891 m_rowCount += difference;
894 scheduleProcessPendingParents();
896 const QModelIndex index = q->mapFromSource(parent);
897 Q_EMIT q->dataChanged(index,
899 {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole, KDescendantsProxyModel::HasSiblingsRole});
903 notifyhasSiblings(q->sourceModel()->index(
start - 1, 0, parent));
907void KDescendantsProxyModelPrivate::sourceRowsAboutToBeRemoved(
const QModelIndex &parent,
int start,
int end)
909 Q_Q(KDescendantsProxyModel);
911 if (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent)) {
915 const int proxyStart = q->mapFromSource(q->sourceModel()->index(
start, 0, parent)).row();
917 static const int column = 0;
918 QModelIndex idx = q->sourceModel()->index(end, column, parent);
919 while (q->sourceModel()->hasChildren(idx) && q->sourceModel()->rowCount(idx) > 0) {
920 idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
922 const int proxyEnd = q->mapFromSource(idx).row();
924 for (
int i =
start; i <=
end; ++i) {
925 QModelIndex idx = q->sourceModel()->index(i, column, parent);
926 m_expandedSourceIndexes.remove(QPersistentModelIndex(idx));
929 m_removePair = qMakePair(proxyStart, proxyEnd);
931 q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd);
936 static const int column = 0;
938 Q_ASSERT(model->
rowCount(parent) > 0);
939 for (
int row = 0; row < model->
rowCount(parent); ++row) {
944 return getFirstDeepest(model, child, count);
947 return model->
index(model->
rowCount(parent) - 1, column, parent);
950void KDescendantsProxyModelPrivate::sourceRowsRemoved(
const QModelIndex &parent,
int start,
int end)
952 Q_Q(KDescendantsProxyModel);
955 if (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent)) {
957 const QModelIndex index = q->mapFromSource(parent);
958 Q_EMIT q->dataChanged(index, index, {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole});
963 const int rowCount = q->sourceModel()->rowCount(parent);
965 const int proxyStart = m_removePair.first;
966 const int proxyEnd = m_removePair.second;
968 const int difference = proxyEnd - proxyStart + 1;
970 Mapping::right_iterator it = m_mapping.rightLowerBound(proxyStart);
971 const Mapping::right_iterator endIt = m_mapping.rightUpperBound(proxyEnd);
973 if (endIt != m_mapping.rightEnd()) {
974 while (it != endIt) {
975 it = m_mapping.eraseRight(it);
978 while (it != m_mapping.rightUpperBound(proxyEnd)) {
979 it = m_mapping.eraseRight(it);
984 m_removePair = qMakePair(-1, -1);
985 m_rowCount -= difference;
986 Q_ASSERT(m_rowCount >= 0);
988 updateInternalIndexes(proxyStart, -1 * difference);
990 if (rowCount !=
start || rowCount == 0) {
993 const QModelIndex index = q->mapFromSource(parent);
994 Q_EMIT q->dataChanged(index, index, {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole});
997 notifyhasSiblings(q->sourceModel()->index(
start - 1, 0, parent));
1002 static const int column = 0;
1003 const QModelIndex newEnd = q->sourceModel()->index(rowCount - 1, column, parent);
1006 if (m_mapping.isEmpty()) {
1007 m_mapping.insert(newEnd, newEnd.
row());
1010 notifyhasSiblings(q->sourceModel()->index(
start - 1, 0, parent));
1014 if (q->sourceModel()->hasChildren(newEnd)) {
1016 const QModelIndex firstDeepest = getFirstDeepest(q->sourceModel(), newEnd, &count);
1017 Q_ASSERT(firstDeepest.
isValid());
1018 const int firstDeepestProxy = m_mapping.leftToRight(firstDeepest);
1020 m_mapping.insert(newEnd, firstDeepestProxy - count);
1023 notifyhasSiblings(q->sourceModel()->index(
start - 1, 0, parent));
1027 Mapping::right_iterator lowerBound = m_mapping.rightLowerBound(proxyStart);
1028 if (lowerBound == m_mapping.rightEnd()) {
1029 int proxyRow = std::prev(lowerBound).key();
1031 for (
int row = newEnd.
row(); row >= 0; --row) {
1032 const QModelIndex newEndSibling = q->sourceModel()->index(row, column, parent);
1033 if (!q->sourceModel()->hasChildren(newEndSibling)) {
1039 m_mapping.insert(newEnd, proxyRow);
1042 notifyhasSiblings(q->sourceModel()->index(
start - 1, 0, parent));
1045 }
else if (lowerBound == m_mapping.rightBegin()) {
1046 int proxyRow = rowCount - 1;
1047 QModelIndex trackedParent = parent;
1048 while (trackedParent.
isValid()) {
1049 proxyRow += (trackedParent.
row() + 1);
1050 trackedParent = trackedParent.
parent();
1052 m_mapping.insert(newEnd, proxyRow);
1055 notifyhasSiblings(q->sourceModel()->index(
start - 1, 0, parent));
1059 const Mapping::right_iterator boundAbove = std::prev(lowerBound);
1061 QList<QModelIndex> targetParents;
1064 QModelIndex target = parent;
1067 if (target == boundAbove.value()) {
1068 m_mapping.insert(newEnd, count + boundAbove.key() + newEnd.
row() + 1);
1071 notifyhasSiblings(q->sourceModel()->index(
start - 1, 0, parent));
1075 count += (target.
row() + 1);
1076 target = target.
parent();
1083 QModelIndex boundParent = boundAbove.value().parent();
1084 QModelIndex prevParent = boundParent;
1085 Q_ASSERT(boundParent.
isValid());
1086 while (boundParent.
isValid()) {
1087 prevParent = boundParent;
1088 boundParent = boundParent.
parent();
1090 if (targetParents.
contains(prevParent)) {
1094 if (!m_mapping.leftContains(prevParent)) {
1098 if (m_mapping.leftToRight(prevParent) > boundAbove.key()) {
1103 QModelIndex trackedParent = parent;
1105 int proxyRow = boundAbove.key();
1107 Q_ASSERT(prevParent.
isValid());
1108 proxyRow -= prevParent.
row();
1109 while (trackedParent != boundParent) {
1110 proxyRow += (trackedParent.
row() + 1);
1111 trackedParent = trackedParent.
parent();
1113 m_mapping.insert(newEnd, proxyRow + newEnd.
row());
1117 const QModelIndex oindex = q->mapFromSource(parent);
1118 QList<int> rolesChanged({KDescendantsProxyModel::ExpandableRole});
1120 if (!q->sourceModel()->hasChildren(parent)) {
1121 rolesChanged << KDescendantsProxyModel::ExpandedRole;
1122 }
else if (q->sourceModel()->rowCount(parent) <=
start) {
1123 const QModelIndex index = q->mapFromSource(q->sourceModel()->index(q->sourceModel()->rowCount(parent) - 1, 0, parent));
1124 Q_EMIT q->dataChanged(index, index, {KDescendantsProxyModel::ExpandedRole});
1127 Q_EMIT q->dataChanged(oindex, oindex, rolesChanged);
1131 notifyhasSiblings(q->sourceModel()->index(
start - 1, 0, parent));
1135void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(
const QModelIndex &srcParent,
1141 Q_Q(KDescendantsProxyModel);
1145 if (q->isSourceIndexExpanded(srcParent) && q->isSourceIndexVisible(srcParent)
1146 && (!q->isSourceIndexExpanded(destParent) || !q->isSourceIndexVisible(destParent))) {
1147 const QModelIndex proxySrcParent = q->mapFromSource(srcParent);
1148 const int proxyParentRow = proxySrcParent.
isValid() ? proxySrcParent.
row() : 0;
1149 q->beginRemoveRows(QModelIndex(), proxyParentRow + srcStart, proxyParentRow + srcEnd);
1151 }
else if ((!q->isSourceIndexExpanded(srcParent) || !q->isSourceIndexVisible(srcParent)) && q->isSourceIndexExpanded(destParent)
1152 && q->isSourceIndexVisible(destParent)) {
1153 const QModelIndex proxyDestParent = q->mapFromSource(srcParent);
1154 const int proxyParentRow = proxyDestParent.
isValid() ? proxyDestParent.
row() : 0;
1156 q->beginInsertRows(QModelIndex(), proxyParentRow + destStart, proxyParentRow + destStart + (srcEnd - srcStart));
1159 sourceLayoutAboutToBeChanged();
1162void KDescendantsProxyModelPrivate::sourceRowsMoved(
const QModelIndex &srcParent,
int srcStart,
int srcEnd,
const QModelIndex &destParent,
int destStart)
1164 Q_Q(KDescendantsProxyModel);
1169 Q_UNUSED(destParent)
1172 if (q->isSourceIndexExpanded(srcParent) && q->isSourceIndexVisible(srcParent)
1173 && (!q->isSourceIndexExpanded(destParent) || !q->isSourceIndexVisible(destParent))) {
1175 }
else if (!q->isSourceIndexExpanded(srcParent) && q->isSourceIndexExpanded(destParent)) {
1179 sourceLayoutChanged();
1181 const QModelIndex index1 = q->mapFromSource(srcParent);
1182 const QModelIndex index2 = q->mapFromSource(destParent);
1183 Q_EMIT q->dataChanged(index1, index1, {KDescendantsProxyModel::ExpandableRole});
1184 if (index1 != index2) {
1185 Q_EMIT q->dataChanged(index2, index2, {KDescendantsProxyModel::ExpandableRole});
1186 if (!q->sourceModel()->hasChildren(destParent)) {
1187 Q_EMIT q->dataChanged(index2, index2, {KDescendantsProxyModel::ExpandableRole});
1190 const QModelIndex lastIndex = q->mapFromSource(q->sourceModel()->index(q->sourceModel()->rowCount(srcParent) - 1, 0, srcParent));
1191 Q_EMIT q->dataChanged(lastIndex, lastIndex, {KDescendantsProxyModel::ExpandableRole});
1194 notifyhasSiblings(q->sourceModel()->index(srcStart - 1, 0, srcParent));
1196 if (destStart > 0) {
1197 notifyhasSiblings(q->sourceModel()->index(destStart - 1, 0, destParent));
1201void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset()
1203 Q_Q(KDescendantsProxyModel);
1204 q->beginResetModel();
1205 m_relayouting =
true;
1208void KDescendantsProxyModelPrivate::sourceModelReset()
1210 Q_Q(KDescendantsProxyModel);
1211 resetInternalData();
1212 if (q->sourceModel()->hasChildren() && q->sourceModel()->rowCount() > 0) {
1213 m_pendingParents.append(QModelIndex());
1214 scheduleProcessPendingParents();
1216 m_relayouting =
false;
1220void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged()
1222 Q_Q(KDescendantsProxyModel);
1224 if (m_ignoreNextLayoutChanged) {
1225 m_ignoreNextLayoutChanged =
false;
1229 if (m_mapping.isEmpty()) {
1233 Q_EMIT q->layoutAboutToBeChanged();
1235 QPersistentModelIndex srcPersistentIndex;
1236 const auto lst = q->persistentIndexList();
1237 for (
const QModelIndex &proxyPersistentIndex : lst) {
1238 m_proxyIndexes << proxyPersistentIndex;
1239 Q_ASSERT(proxyPersistentIndex.isValid());
1240 srcPersistentIndex = q->mapToSource(proxyPersistentIndex);
1241 Q_ASSERT(srcPersistentIndex.
isValid());
1242 m_layoutChangePersistentIndexes << srcPersistentIndex;
1246void KDescendantsProxyModelPrivate::sourceLayoutChanged()
1248 Q_Q(KDescendantsProxyModel);
1250 if (m_ignoreNextLayoutAboutToBeChanged) {
1251 m_ignoreNextLayoutAboutToBeChanged =
false;
1255 if (m_mapping.isEmpty()) {
1261 synchronousMappingRefresh();
1263 for (
int i = 0; i < m_proxyIndexes.size(); ++i) {
1264 q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i)));
1267 m_layoutChangePersistentIndexes.clear();
1268 m_proxyIndexes.clear();
1270 Q_EMIT q->layoutChanged();
1273void KDescendantsProxyModelPrivate::sourceDataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight)
1275 Q_Q(KDescendantsProxyModel);
1284 Q_ASSERT(topLeft.
model() == q->sourceModel());
1285 Q_ASSERT(bottomRight.
model() == q->sourceModel());
1287 if (!q->isSourceIndexExpanded(topLeft.
parent()) || !q->isSourceIndexVisible(topLeft.
parent())) {
1291 const int topRow = topLeft.
row();
1292 const int bottomRow = bottomRight.
row();
1294 for (
int i = topRow; i <= bottomRow; ++i) {
1295 const QModelIndex sourceTopLeft = q->sourceModel()->index(i, topLeft.
column(), topLeft.
parent());
1297 Q_ASSERT(sourceTopLeft.
isValid());
1298 const QModelIndex proxyTopLeft = q->mapFromSource(sourceTopLeft);
1301 const QModelIndex sourceBottomRight = q->sourceModel()->index(i, bottomRight.
column(), bottomRight.
parent());
1302 const QModelIndex proxyBottomRight = q->mapFromSource(sourceBottomRight);
1303 Q_ASSERT(proxyTopLeft.
isValid());
1304 Q_ASSERT(proxyBottomRight.
isValid());
1305 Q_EMIT q->dataChanged(proxyTopLeft, proxyBottomRight);
1309void KDescendantsProxyModelPrivate::sourceModelDestroyed()
1311 resetInternalData();
1314QMimeData *KDescendantsProxyModel::mimeData(
const QModelIndexList &indexes)
const
1320 QModelIndexList sourceIndexes;
1321 for (
const QModelIndex &index : indexes) {
1322 sourceIndexes << mapToSource(index);
1327QStringList KDescendantsProxyModel::mimeTypes()
const
1344#include "moc_kdescendantsproxymodel.cpp"
KDescendantsProxyModel(QObject *parent=nullptr)
Creates a new descendant entities proxy model.
~KDescendantsProxyModel() override
Destroys the descendant entities proxy model.
void collapseSourceIndex(const QModelIndex &sourceIndex)
Maps a source index as collapsed in the proxy, all its children will be hidden.
void setAncestorSeparator(const QString &separator)
Sets the ancestor separator used between data of ancestors.
bool isSourceIndexExpanded(const QModelIndex &sourceIndex) const
virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits=1, Qt::MatchFlags flags=Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const override
Reimplemented to match all descendants.
void expandSourceIndex(const QModelIndex &sourceIndex)
Maps a source index as expanded in the proxy, all its children will become visible.
bool isSourceIndexVisible(const QModelIndex &sourceIndex) const
void setDisplayAncestorData(bool display)
Set whether to show ancestor data in the model.
bool expandsByDefault
If true, all the nodes in the whole tree will be expanded upon loading and all items of the source mo...
void setExpandsByDefault(bool expand)
If true, all the nodes in the whole tree will be expanded upon loading (default)
QString ancestorSeparator
void setSourceModel(QAbstractItemModel *model) override
Sets the source model of the proxy.
Q_SCRIPTABLE QString start(QString train="")
Q_SCRIPTABLE Q_NOREPLY void start()
QStringView level(QStringView ifopt)
const QList< QKeySequence > & begin()
const QList< QKeySequence > & end()
QAbstractItemModel(QObject *parent)
void beginRemoveRows(const QModelIndex &parent, int first, int last)
QModelIndex createIndex(int row, int column, const void *ptr) const const
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles)
virtual bool hasChildren(const QModelIndex &parent) const const
bool hasIndex(int row, int column, const QModelIndex &parent) const const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
void layoutAboutToBeChanged(const QList< QPersistentModelIndex > &parents, QAbstractItemModel::LayoutChangeHint hint)
void layoutChanged(const QList< QPersistentModelIndex > &parents, QAbstractItemModel::LayoutChangeHint hint)
virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const const
void modelAboutToBeReset()
virtual void resetInternalData()
virtual int rowCount(const QModelIndex &parent) const const=0
void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
void rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
void rowsInserted(const QModelIndex &parent, int first, int last)
void rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
void rowsRemoved(const QModelIndex &parent, int first, int last)
QAbstractProxyModel(QObject *parent)
virtual Qt::ItemFlags flags(const QModelIndex &index) const const override
virtual QMimeData * mimeData(const QModelIndexList &indexes) const const override
virtual QStringList mimeTypes() const const override
virtual QHash< int, QByteArray > roleNames() const const override
virtual void setSourceModel(QAbstractItemModel *sourceModel)
virtual Qt::DropActions supportedDropActions() const const override
const_iterator constBegin() const const
const_iterator constEnd() const const
iterator insert(const Key &key, const T &value)
void append(QList< T > &&value)
bool contains(const AT &value) const const
bool isEmpty() const const
void prepend(parameter_type value)
void push_back(parameter_type value)
QVariant data(int role) const const
bool isValid() const const
const QAbstractItemModel * model() const const
QModelIndex parent() const const
QModelIndex sibling(int row, int column) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void destroyed(QObject *obj)
bool disconnect(const QMetaObject::Connection &connection)
QObject * parent() const const
bool isValid() const const
bool contains(const QSet< T > &other) const const
QString & prepend(QChar ch)
QVariant fromValue(T &&value)
QString toString() const const