File indexing completed on 2024-07-21 06:38:22

0001 /*
0002     SPDX-FileCopyrightText: 2009 Stephen Kelly <steveire@gmail.com>
0003     SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
0004     SPDX-FileContributor: Stephen Kelly <stephen@kdab.com>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "kdescendantsproxymodel.h"
0010 
0011 #include <QStringList>
0012 
0013 #include "kbihash_p.h"
0014 
0015 typedef KHash2Map<QPersistentModelIndex, int> Mapping;
0016 
0017 class KDescendantsProxyModelPrivate
0018 {
0019     KDescendantsProxyModelPrivate(KDescendantsProxyModel *qq)
0020         : q_ptr(qq)
0021         , m_rowCount(0)
0022         , m_ignoreNextLayoutAboutToBeChanged(false)
0023         , m_ignoreNextLayoutChanged(false)
0024         , m_relayouting(false)
0025         , m_displayAncestorData(false)
0026         , m_ancestorSeparator(QStringLiteral(" / "))
0027     {
0028     }
0029 
0030     Q_DECLARE_PUBLIC(KDescendantsProxyModel)
0031     KDescendantsProxyModel *const q_ptr;
0032 
0033     mutable QList<QPersistentModelIndex> m_pendingParents;
0034 
0035     void scheduleProcessPendingParents() const;
0036     void processPendingParents();
0037 
0038     void synchronousMappingRefresh();
0039 
0040     void updateInternalIndexes(int start, int offset);
0041 
0042     void resetInternalData();
0043 
0044     void notifyhasSiblings(const QModelIndex &parent);
0045     void sourceRowsAboutToBeInserted(const QModelIndex &, int, int);
0046     void sourceRowsInserted(const QModelIndex &, int, int);
0047     void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int);
0048     void sourceRowsRemoved(const QModelIndex &, int, int);
0049     void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int);
0050     void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
0051     void sourceModelAboutToBeReset();
0052     void sourceModelReset();
0053     void sourceLayoutAboutToBeChanged();
0054     void sourceLayoutChanged();
0055     void sourceDataChanged(const QModelIndex &, const QModelIndex &);
0056     void sourceModelDestroyed();
0057 
0058     Mapping m_mapping;
0059     int m_rowCount;
0060     QPair<int, int> m_removePair;
0061     QPair<int, int> m_insertPair;
0062 
0063     bool m_expandsByDefault = true;
0064     bool m_ignoreNextLayoutAboutToBeChanged;
0065     bool m_ignoreNextLayoutChanged;
0066     bool m_relayouting;
0067 
0068     bool m_displayAncestorData;
0069     QString m_ancestorSeparator;
0070 
0071     QSet<QPersistentModelIndex> m_expandedSourceIndexes;
0072     QSet<QPersistentModelIndex> m_collapsedSourceIndexes;
0073 
0074     QList<QPersistentModelIndex> m_layoutChangePersistentIndexes;
0075     QModelIndexList m_proxyIndexes;
0076 };
0077 
0078 void KDescendantsProxyModelPrivate::resetInternalData()
0079 {
0080     m_rowCount = 0;
0081     m_mapping.clear();
0082     m_layoutChangePersistentIndexes.clear();
0083     m_proxyIndexes.clear();
0084 }
0085 
0086 void KDescendantsProxyModelPrivate::synchronousMappingRefresh()
0087 {
0088     m_rowCount = 0;
0089     m_mapping.clear();
0090     m_pendingParents.clear();
0091 
0092     m_pendingParents.append(QModelIndex());
0093 
0094     m_relayouting = true;
0095     while (!m_pendingParents.isEmpty()) {
0096         processPendingParents();
0097     }
0098     m_relayouting = false;
0099 }
0100 
0101 void KDescendantsProxyModelPrivate::scheduleProcessPendingParents() const
0102 {
0103     const_cast<KDescendantsProxyModelPrivate *>(this)->processPendingParents();
0104 }
0105 
0106 void KDescendantsProxyModelPrivate::processPendingParents()
0107 {
0108     Q_Q(KDescendantsProxyModel);
0109     const QList<QPersistentModelIndex>::iterator begin = m_pendingParents.begin();
0110     QList<QPersistentModelIndex>::iterator it = begin;
0111 
0112     const QList<QPersistentModelIndex>::iterator end = m_pendingParents.end();
0113 
0114     QList<QPersistentModelIndex> newPendingParents;
0115 
0116     while (it != end && it != m_pendingParents.end()) {
0117         const QModelIndex sourceParent = *it;
0118         if (!sourceParent.isValid() && m_rowCount > 0) {
0119             // It was removed from the source model before it was inserted.
0120             it = m_pendingParents.erase(it);
0121             continue;
0122         }
0123         if (!q->isSourceIndexVisible(sourceParent)) {
0124             // It's a collapsed node, or its parents are collapsed, ignore.
0125             it = m_pendingParents.erase(it);
0126             continue;
0127         }
0128 
0129         const int rowCount = q->sourceModel()->rowCount(sourceParent);
0130 
0131         // A node can be marked as collapsed or expanded even if it doesn't have children
0132         if (rowCount == 0) {
0133             it = m_pendingParents.erase(it);
0134             continue;
0135         }
0136         const QPersistentModelIndex sourceIndex = q->sourceModel()->index(rowCount - 1, 0, sourceParent);
0137 
0138         Q_ASSERT(sourceIndex.isValid());
0139 
0140         const QModelIndex proxyParent = q->mapFromSource(sourceParent);
0141 
0142         Q_ASSERT(sourceParent.isValid() == proxyParent.isValid());
0143         const int proxyEndRow = proxyParent.row() + rowCount;
0144         const int proxyStartRow = proxyEndRow - rowCount + 1;
0145 
0146         if (!m_relayouting) {
0147             q->beginInsertRows(QModelIndex(), proxyStartRow, proxyEndRow);
0148         }
0149 
0150         updateInternalIndexes(proxyStartRow, rowCount);
0151         m_mapping.insert(sourceIndex, proxyEndRow);
0152         it = m_pendingParents.erase(it);
0153         m_rowCount += rowCount;
0154 
0155         if (!m_relayouting) {
0156             q->endInsertRows();
0157         }
0158 
0159         for (int sourceRow = 0; sourceRow < rowCount; ++sourceRow) {
0160             static const int column = 0;
0161             const QModelIndex child = q->sourceModel()->index(sourceRow, column, sourceParent);
0162             Q_ASSERT(child.isValid());
0163 
0164             if (q->sourceModel()->hasChildren(child) && q->isSourceIndexExpanded(child) && q->sourceModel()->rowCount(child) > 0) {
0165                 newPendingParents.append(child);
0166             }
0167         }
0168     }
0169     m_pendingParents += newPendingParents;
0170     if (!m_pendingParents.isEmpty()) {
0171         processPendingParents();
0172     }
0173     //   scheduleProcessPendingParents();
0174 }
0175 
0176 void KDescendantsProxyModelPrivate::updateInternalIndexes(int start, int offset)
0177 {
0178     // TODO: Make KHash2Map support key updates and do this backwards.
0179     QHash<int, QPersistentModelIndex> updates;
0180     {
0181         Mapping::right_iterator it = m_mapping.rightLowerBound(start);
0182         const Mapping::right_iterator end = m_mapping.rightEnd();
0183 
0184         while (it != end) {
0185             updates.insert(it.key() + offset, *it);
0186             ++it;
0187         }
0188     }
0189 
0190     {
0191         QHash<int, QPersistentModelIndex>::const_iterator it = updates.constBegin();
0192         const QHash<int, QPersistentModelIndex>::const_iterator end = updates.constEnd();
0193 
0194         for (; it != end; ++it) {
0195             m_mapping.insert(it.value(), it.key());
0196         }
0197     }
0198 }
0199 
0200 KDescendantsProxyModel::KDescendantsProxyModel(QObject *parent)
0201     : QAbstractProxyModel(parent)
0202     , d_ptr(new KDescendantsProxyModelPrivate(this))
0203 {
0204 }
0205 
0206 KDescendantsProxyModel::~KDescendantsProxyModel() = default;
0207 
0208 QHash<int, QByteArray> KDescendantsProxyModel::roleNames() const
0209 {
0210     QHash<int, QByteArray> roleNames = QAbstractProxyModel::roleNames();
0211 
0212     roleNames[LevelRole] = "kDescendantLevel";
0213     roleNames[ExpandableRole] = "kDescendantExpandable";
0214     roleNames[ExpandedRole] = "kDescendantExpanded";
0215     roleNames[HasSiblingsRole] = "kDescendantHasSiblings";
0216     return roleNames;
0217 }
0218 
0219 void KDescendantsProxyModel::setExpandsByDefault(bool expand)
0220 {
0221     if (d_ptr->m_expandsByDefault == expand) {
0222         return;
0223     }
0224 
0225     beginResetModel();
0226     d_ptr->m_expandsByDefault = expand;
0227     d_ptr->m_expandedSourceIndexes.clear();
0228     d_ptr->m_collapsedSourceIndexes.clear();
0229     endResetModel();
0230 }
0231 
0232 bool KDescendantsProxyModel::expandsByDefault() const
0233 {
0234     return d_ptr->m_expandsByDefault;
0235 }
0236 
0237 bool KDescendantsProxyModel::isSourceIndexExpanded(const QModelIndex &sourceIndex) const
0238 {
0239     // Root is always expanded
0240     if (!sourceIndex.isValid()) {
0241         return true;
0242     } else if (d_ptr->m_expandsByDefault) {
0243         return !d_ptr->m_collapsedSourceIndexes.contains(QPersistentModelIndex(sourceIndex));
0244     } else {
0245         return d_ptr->m_expandedSourceIndexes.contains(QPersistentModelIndex(sourceIndex));
0246     }
0247 }
0248 
0249 bool KDescendantsProxyModel::isSourceIndexVisible(const QModelIndex &sourceIndex) const
0250 {
0251     // Root is always visible
0252     if (!sourceIndex.isValid()) {
0253         return true;
0254     }
0255 
0256     QModelIndex index(sourceIndex);
0257     do {
0258         index = index.parent();
0259         if (!index.isValid()) {
0260             return true;
0261         }
0262     } while (isSourceIndexExpanded(index));
0263 
0264     return false;
0265 }
0266 
0267 void KDescendantsProxyModel::expandSourceIndex(const QModelIndex &sourceIndex)
0268 {
0269     if (!sourceIndex.isValid() || isSourceIndexExpanded(sourceIndex)) {
0270         return;
0271     }
0272 
0273     if (d_ptr->m_expandsByDefault) {
0274         d_ptr->m_collapsedSourceIndexes.remove(QPersistentModelIndex(sourceIndex));
0275     } else {
0276         d_ptr->m_expandedSourceIndexes << QPersistentModelIndex(sourceIndex);
0277     }
0278 
0279     d_ptr->m_pendingParents << sourceIndex;
0280     d_ptr->scheduleProcessPendingParents();
0281     Q_EMIT sourceIndexExpanded(sourceIndex);
0282 
0283     const QModelIndex index = mapFromSource(sourceIndex);
0284     Q_EMIT dataChanged(index, index, {ExpandedRole});
0285 }
0286 
0287 void KDescendantsProxyModel::collapseSourceIndex(const QModelIndex &sourceIndex)
0288 {
0289     if (!sourceIndex.isValid() || !isSourceIndexExpanded(sourceIndex)) {
0290         return;
0291     }
0292 
0293     const int row = mapFromSource(sourceIndex).row();
0294     const int rowStart = row + 1;
0295     int rowEnd = row;
0296 
0297     QList<QModelIndex> toVisit = {sourceIndex};
0298     QSet<QModelIndex> visited;
0299     while (!toVisit.isEmpty()) {
0300         QModelIndex index = toVisit.takeLast();
0301         if (!visited.contains(index)) {
0302             visited << index;
0303             const int nRows = sourceModel()->rowCount(index);
0304             rowEnd += nRows;
0305             for (int i = 0; i < nRows; ++i) {
0306                 QModelIndex child = sourceModel()->index(i, 0, index);
0307                 if (isSourceIndexExpanded(child)) {
0308                     toVisit << child;
0309                 }
0310             }
0311         }
0312     }
0313 
0314     beginRemoveRows(QModelIndex(), rowStart, rowEnd);
0315 
0316     if (d_ptr->m_expandsByDefault) {
0317         d_ptr->m_collapsedSourceIndexes << QPersistentModelIndex(sourceIndex);
0318     } else {
0319         d_ptr->m_expandedSourceIndexes.remove(QPersistentModelIndex(sourceIndex));
0320     }
0321 
0322     {
0323         Mapping::right_iterator it = d_ptr->m_mapping.rightLowerBound(rowStart);
0324         const Mapping::right_iterator endIt = d_ptr->m_mapping.rightUpperBound(rowEnd);
0325 
0326         if (endIt != d_ptr->m_mapping.rightEnd()) {
0327             while (it != endIt) {
0328                 it = d_ptr->m_mapping.eraseRight(it);
0329             }
0330         } else {
0331             while (it != d_ptr->m_mapping.rightUpperBound(rowEnd)) {
0332                 it = d_ptr->m_mapping.eraseRight(it);
0333             }
0334         }
0335     }
0336 
0337     d_ptr->m_removePair = qMakePair(rowStart, rowEnd);
0338 
0339     d_ptr->synchronousMappingRefresh();
0340     endRemoveRows();
0341     Q_EMIT sourceIndexCollapsed(sourceIndex);
0342 
0343     const QModelIndex ownIndex = mapFromSource(sourceIndex);
0344     Q_EMIT dataChanged(ownIndex, ownIndex, {ExpandedRole});
0345 }
0346 
0347 QModelIndexList KDescendantsProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const
0348 {
0349     return QAbstractProxyModel::match(start, role, value, hits, flags);
0350 }
0351 
0352 namespace
0353 {
0354 // we only work on DisplayRole for now
0355 static const QList<int> changedRoles = {Qt::DisplayRole};
0356 }
0357 
0358 void KDescendantsProxyModel::setDisplayAncestorData(bool display)
0359 {
0360     Q_D(KDescendantsProxyModel);
0361     bool displayChanged = (display != d->m_displayAncestorData);
0362     d->m_displayAncestorData = display;
0363     if (displayChanged) {
0364         Q_EMIT displayAncestorDataChanged();
0365         // send out big hammer. Everything needs to be updated.
0366         Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1), changedRoles);
0367     }
0368 }
0369 
0370 bool KDescendantsProxyModel::displayAncestorData() const
0371 {
0372     Q_D(const KDescendantsProxyModel);
0373     return d->m_displayAncestorData;
0374 }
0375 
0376 void KDescendantsProxyModel::setAncestorSeparator(const QString &separator)
0377 {
0378     Q_D(KDescendantsProxyModel);
0379     bool separatorChanged = (separator != d->m_ancestorSeparator);
0380     d->m_ancestorSeparator = separator;
0381     if (separatorChanged) {
0382         Q_EMIT ancestorSeparatorChanged();
0383         if (d->m_displayAncestorData) {
0384             // send out big hammer. Everything needs to be updated.
0385             Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1), changedRoles);
0386         }
0387     }
0388 }
0389 
0390 QString KDescendantsProxyModel::ancestorSeparator() const
0391 {
0392     Q_D(const KDescendantsProxyModel);
0393     return d->m_ancestorSeparator;
0394 }
0395 
0396 void KDescendantsProxyModel::setSourceModel(QAbstractItemModel *_sourceModel)
0397 {
0398     Q_D(KDescendantsProxyModel);
0399 
0400     beginResetModel();
0401 
0402     if (sourceModel()) {
0403         disconnect(sourceModel(), nullptr, this, nullptr);
0404     }
0405 
0406     QAbstractProxyModel::setSourceModel(_sourceModel);
0407     d_ptr->m_expandedSourceIndexes.clear();
0408 
0409     if (_sourceModel) {
0410         connect(_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, [d](const QModelIndex &parent, int start, int end) {
0411             d->sourceRowsAboutToBeInserted(parent, start, end);
0412         });
0413 
0414         connect(_sourceModel, &QAbstractItemModel::rowsInserted, this, [d](const QModelIndex &parent, int start, int end) {
0415             d->sourceRowsInserted(parent, start, end);
0416         });
0417 
0418         connect(_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, [d](const QModelIndex &parent, int start, int end) {
0419             d->sourceRowsAboutToBeRemoved(parent, start, end);
0420         });
0421 
0422         connect(_sourceModel, &QAbstractItemModel::rowsRemoved, this, [d](const QModelIndex &parent, int start, int end) {
0423             d->sourceRowsRemoved(parent, start, end);
0424         });
0425 
0426         connect(_sourceModel,
0427                 &QAbstractItemModel::rowsAboutToBeMoved,
0428                 this,
0429                 [d](const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart) {
0430                     d->sourceRowsAboutToBeMoved(srcParent, srcStart, srcEnd, destParent, destStart);
0431                 });
0432 
0433         connect(_sourceModel,
0434                 &QAbstractItemModel::rowsMoved,
0435                 this,
0436                 [d](const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart) {
0437                     d->sourceRowsMoved(srcParent, srcStart, srcEnd, destParent, destStart);
0438                 });
0439 
0440         connect(_sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, [d]() {
0441             d->sourceModelAboutToBeReset();
0442         });
0443 
0444         connect(_sourceModel, &QAbstractItemModel::modelReset, this, [d]() {
0445             d->sourceModelReset();
0446         });
0447 
0448         connect(_sourceModel, &QAbstractItemModel::dataChanged, this, [d](const QModelIndex &topLeft, const QModelIndex &bottomRight) {
0449             d->sourceDataChanged(topLeft, bottomRight);
0450         });
0451 
0452         connect(_sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, this, [d]() {
0453             d->sourceLayoutAboutToBeChanged();
0454         });
0455 
0456         connect(_sourceModel, &QAbstractItemModel::layoutChanged, this, [d]() {
0457             d->sourceLayoutChanged();
0458         });
0459 
0460         connect(_sourceModel, &QObject::destroyed, this, [d]() {
0461             d->sourceModelDestroyed();
0462         });
0463     }
0464 
0465     resetInternalData();
0466     if (_sourceModel && _sourceModel->hasChildren()) {
0467         d->synchronousMappingRefresh();
0468     }
0469 
0470     endResetModel();
0471     Q_EMIT sourceModelChanged();
0472 }
0473 
0474 QModelIndex KDescendantsProxyModel::parent(const QModelIndex &index) const
0475 {
0476     Q_UNUSED(index)
0477     return QModelIndex();
0478 }
0479 
0480 bool KDescendantsProxyModel::hasChildren(const QModelIndex &parent) const
0481 {
0482     Q_D(const KDescendantsProxyModel);
0483     return !(d->m_mapping.isEmpty() || parent.isValid());
0484 }
0485 
0486 int KDescendantsProxyModel::rowCount(const QModelIndex &parent) const
0487 {
0488     Q_D(const KDescendantsProxyModel);
0489     if (d->m_pendingParents.contains(parent) || parent.isValid() || !sourceModel()) {
0490         return 0;
0491     }
0492 
0493     if (d->m_mapping.isEmpty() && sourceModel()->hasChildren()) {
0494         const_cast<KDescendantsProxyModelPrivate *>(d)->synchronousMappingRefresh();
0495     }
0496     return d->m_rowCount;
0497 }
0498 
0499 QModelIndex KDescendantsProxyModel::index(int row, int column, const QModelIndex &parent) const
0500 {
0501     if (parent.isValid()) {
0502         return QModelIndex();
0503     }
0504 
0505     if (!hasIndex(row, column, parent)) {
0506         return QModelIndex();
0507     }
0508 
0509     return createIndex(row, column);
0510 }
0511 
0512 QModelIndex KDescendantsProxyModel::mapToSource(const QModelIndex &proxyIndex) const
0513 {
0514     Q_D(const KDescendantsProxyModel);
0515     if (d->m_mapping.isEmpty() || !proxyIndex.isValid() || !sourceModel()) {
0516         return QModelIndex();
0517     }
0518 
0519     const Mapping::right_const_iterator result = d->m_mapping.rightLowerBound(proxyIndex.row());
0520     Q_ASSERT(result != d->m_mapping.rightEnd());
0521 
0522     const int proxyLastRow = result.key();
0523     const QModelIndex sourceLastChild = result.value();
0524     Q_ASSERT(sourceLastChild.isValid());
0525 
0526     // proxyLastRow is greater than proxyIndex.row().
0527     // sourceLastChild is vertically below the result we're looking for
0528     // and not necessarily in the correct parent.
0529     // We travel up through its parent hierarchy until we are in the
0530     // right parent, then return the correct sibling.
0531 
0532     // Source:           Proxy:    Row
0533     // - A               - A       - 0
0534     // - B               - B       - 1
0535     // - C               - C       - 2
0536     // - D               - D       - 3
0537     // - - E             - E       - 4
0538     // - - F             - F       - 5
0539     // - - G             - G       - 6
0540     // - - H             - H       - 7
0541     // - - I             - I       - 8
0542     // - - - J           - J       - 9
0543     // - - - K           - K       - 10
0544     // - - - L           - L       - 11
0545     // - - M             - M       - 12
0546     // - - N             - N       - 13
0547     // - O               - O       - 14
0548 
0549     // Note that L, N and O are lastChildIndexes, and therefore have a mapping. If we
0550     // are trying to map G from the proxy to the source, We at this point have an iterator
0551     // pointing to (L -> 11). The proxy row of G is 6. (proxyIndex.row() == 6). We seek the
0552     // sourceIndex which is vertically above L by the distance proxyLastRow - proxyIndex.row().
0553     // In this case the verticalDistance is 5.
0554 
0555     int verticalDistance = proxyLastRow - proxyIndex.row();
0556 
0557     // We traverse the ancestors of L, until we can index the desired row in the source.
0558 
0559     QModelIndex ancestor = sourceLastChild;
0560     while (ancestor.isValid()) {
0561         const int ancestorRow = ancestor.row();
0562         if (verticalDistance <= ancestorRow) {
0563             return ancestor.sibling(ancestorRow - verticalDistance, proxyIndex.column());
0564         }
0565         verticalDistance -= (ancestorRow + 1);
0566         ancestor = ancestor.parent();
0567     }
0568     Q_ASSERT(!"Didn't find target row.");
0569     return QModelIndex();
0570 }
0571 
0572 QModelIndex KDescendantsProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
0573 {
0574     Q_D(const KDescendantsProxyModel);
0575 
0576     if (!sourceModel()) {
0577         return QModelIndex();
0578     }
0579 
0580     if (d->m_mapping.isEmpty()) {
0581         return QModelIndex();
0582     }
0583 
0584     {
0585         // TODO: Consider a parent Mapping to speed this up.
0586 
0587         Mapping::right_const_iterator it = d->m_mapping.rightConstBegin();
0588         const Mapping::right_const_iterator end = d->m_mapping.rightConstEnd();
0589         const QModelIndex sourceParent = sourceIndex.parent();
0590         Mapping::right_const_iterator result = end;
0591 
0592         if (!isSourceIndexVisible(sourceIndex)) {
0593             return QModelIndex();
0594         }
0595 
0596         for (; it != end; ++it) {
0597             QModelIndex index = it.value();
0598             bool found_block = false;
0599             while (index.isValid()) {
0600                 const QModelIndex ancestor = index.parent();
0601                 if (ancestor == sourceParent && index.row() >= sourceIndex.row()) {
0602                     found_block = true;
0603                     if (result == end || it.key() < result.key()) {
0604                         result = it;
0605                         break; // Leave the while loop. index is still valid.
0606                     }
0607                 }
0608                 index = ancestor;
0609             }
0610             if (found_block && !index.isValid())
0611             // Looked through the ascendants of it.key() without finding sourceParent.
0612             // That means we've already got the result we need.
0613             {
0614                 break;
0615             }
0616         }
0617         Q_ASSERT(result != end);
0618         const QModelIndex sourceLastChild = result.value();
0619         int proxyRow = result.key();
0620         QModelIndex index = sourceLastChild;
0621         while (index.isValid()) {
0622             const QModelIndex ancestor = index.parent();
0623             if (ancestor == sourceParent) {
0624                 return createIndex(proxyRow - (index.row() - sourceIndex.row()), sourceIndex.column());
0625             }
0626             proxyRow -= (index.row() + 1);
0627             index = ancestor;
0628         }
0629         Q_ASSERT(!"Didn't find valid proxy mapping.");
0630         return QModelIndex();
0631     }
0632 }
0633 
0634 int KDescendantsProxyModel::columnCount(const QModelIndex &parent) const
0635 {
0636     if (parent.isValid() /* || rowCount(parent) == 0 */ || !sourceModel()) {
0637         return 0;
0638     }
0639 
0640     return sourceModel()->columnCount();
0641 }
0642 
0643 QVariant KDescendantsProxyModel::data(const QModelIndex &index, int role) const
0644 {
0645     Q_D(const KDescendantsProxyModel);
0646 
0647     if (!sourceModel()) {
0648         return QVariant();
0649     }
0650 
0651     if (!index.isValid()) {
0652         return sourceModel()->data(index, role);
0653     }
0654 
0655     QModelIndex sourceIndex = mapToSource(index);
0656 
0657     if ((d->m_displayAncestorData) && (role == Qt::DisplayRole)) {
0658         if (!sourceIndex.isValid()) {
0659             return QVariant();
0660         }
0661         QString displayData = sourceIndex.data().toString();
0662         sourceIndex = sourceIndex.parent();
0663         while (sourceIndex.isValid()) {
0664             displayData.prepend(d->m_ancestorSeparator);
0665             displayData.prepend(sourceIndex.data().toString());
0666             sourceIndex = sourceIndex.parent();
0667         }
0668         return displayData;
0669     } else if (role == LevelRole) {
0670         QModelIndex sourceIndex = mapToSource(index);
0671         int level = 0;
0672         while (sourceIndex.isValid()) {
0673             sourceIndex = sourceIndex.parent();
0674             ++level;
0675         }
0676         return level;
0677     } else if (role == ExpandableRole) {
0678         QModelIndex sourceIndex = mapToSource(index);
0679         return sourceModel()->hasChildren(sourceIndex);
0680     } else if (role == ExpandedRole) {
0681         return isSourceIndexExpanded(mapToSource(index));
0682     } else if (role == HasSiblingsRole) {
0683         QModelIndex sourceIndex = mapToSource(index);
0684         QList<bool> hasSibling;
0685         while (sourceIndex.isValid()) {
0686             hasSibling.prepend(sourceModel()->rowCount(sourceIndex.parent()) > sourceIndex.row() + 1);
0687             sourceIndex = sourceIndex.parent();
0688         }
0689         return QVariant::fromValue(hasSibling);
0690     } else {
0691         return sourceIndex.data(role);
0692     }
0693 }
0694 
0695 QVariant KDescendantsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
0696 {
0697     if (!sourceModel() || columnCount() <= section) {
0698         return QVariant();
0699     }
0700 
0701     // Here is safe to do sourceModel()->headerData, as in this proxy we neither filter out nor reorder columns
0702     return sourceModel()->headerData(section, orientation, role);
0703 }
0704 
0705 Qt::ItemFlags KDescendantsProxyModel::flags(const QModelIndex &index) const
0706 {
0707     if (!index.isValid() || !sourceModel()) {
0708         return QAbstractProxyModel::flags(index);
0709     }
0710 
0711     const QModelIndex srcIndex = mapToSource(index);
0712     Q_ASSERT(srcIndex.isValid());
0713     return sourceModel()->flags(srcIndex);
0714 }
0715 
0716 void KDescendantsProxyModelPrivate::notifyhasSiblings(const QModelIndex &parent)
0717 {
0718     Q_Q(KDescendantsProxyModel);
0719 
0720     if (!parent.isValid()) {
0721         return;
0722     }
0723 
0724     QModelIndex localParent = q->mapFromSource(parent);
0725     Q_EMIT q->dataChanged(localParent, localParent, {KDescendantsProxyModel::HasSiblingsRole});
0726     for (int i = 0; i < q->sourceModel()->rowCount(parent); ++i) {
0727         notifyhasSiblings(q->sourceModel()->index(i, 0, parent));
0728     }
0729 }
0730 
0731 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
0732 {
0733     Q_Q(KDescendantsProxyModel);
0734 
0735     if (parent.isValid() && (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent))) {
0736         return;
0737     }
0738 
0739     if (!q->sourceModel()->hasChildren(parent)) {
0740         Q_ASSERT(q->sourceModel()->rowCount(parent) == 0);
0741         // parent was not a parent before.
0742         return;
0743     }
0744 
0745     int proxyStart = -1;
0746 
0747     const int rowCount = q->sourceModel()->rowCount(parent);
0748 
0749     if (rowCount > start) {
0750         const QModelIndex belowStart = q->sourceModel()->index(start, 0, parent);
0751         proxyStart = q->mapFromSource(belowStart).row();
0752     } else if (rowCount == 0) {
0753         proxyStart = q->mapFromSource(parent).row() + 1;
0754     } else {
0755         Q_ASSERT(rowCount == start);
0756         static const int column = 0;
0757         QModelIndex idx = q->sourceModel()->index(rowCount - 1, column, parent);
0758         while (q->isSourceIndexExpanded(idx) && q->sourceModel()->hasChildren(idx) && q->sourceModel()->rowCount(idx) > 0) {
0759             idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
0760         }
0761         // The last item in the list is getting a sibling below it.
0762         proxyStart = q->mapFromSource(idx).row() + 1;
0763     }
0764     const int proxyEnd = proxyStart + (end - start);
0765 
0766     m_insertPair = qMakePair(proxyStart, proxyEnd);
0767     q->beginInsertRows(QModelIndex(), proxyStart, proxyEnd);
0768 }
0769 
0770 void KDescendantsProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end)
0771 {
0772     Q_Q(KDescendantsProxyModel);
0773     if (parent.isValid() && (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent))) {
0774         const QModelIndex index = q->mapFromSource(parent);
0775         Q_EMIT q->dataChanged(index,
0776                               index,
0777                               {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole, KDescendantsProxyModel::HasSiblingsRole});
0778         if (start > 0) {
0779             notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent));
0780         }
0781         return;
0782     }
0783     Q_ASSERT(q->sourceModel()->index(start, 0, parent).isValid());
0784 
0785     const int rowCount = q->sourceModel()->rowCount(parent);
0786     Q_ASSERT(rowCount > 0);
0787 
0788     const int difference = end - start + 1;
0789 
0790     if (rowCount == difference) {
0791         const QModelIndex index = q->mapFromSource(parent);
0792         if (parent.isValid()) {
0793             Q_EMIT q->dataChanged(index,
0794                                   index,
0795                                   {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole, KDescendantsProxyModel::HasSiblingsRole});
0796         }
0797         // @p parent was not a parent before.
0798         m_pendingParents.append(parent);
0799         scheduleProcessPendingParents();
0800         if (start > 0) {
0801             notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent));
0802         }
0803         return;
0804     }
0805 
0806     const int proxyStart = m_insertPair.first;
0807 
0808     Q_ASSERT(proxyStart >= 0);
0809 
0810     updateInternalIndexes(proxyStart, difference);
0811 
0812     if (rowCount - 1 == end) {
0813         // The previously last row (the mapped one) is no longer the last.
0814         // For example,
0815 
0816         // - A            - A           0
0817         // - - B          - B           1
0818         // - - C          - C           2
0819         // - - - D        - D           3
0820         // - - - E   ->   - E           4
0821         // - - F          - F           5
0822         // - - G     ->   - G           6
0823         // - H            - H           7
0824         // - I       ->   - I           8
0825 
0826         // As last children, E, F and G have mappings.
0827         // Consider that 'J' is appended to the children of 'C', below 'E'.
0828 
0829         // - A            - A           0
0830         // - - B          - B           1
0831         // - - C          - C           2
0832         // - - - D        - D           3
0833         // - - - E   ->   - E           4
0834         // - - - J        - ???         5
0835         // - - F          - F           6
0836         // - - G     ->   - G           7
0837         // - H            - H           8
0838         // - I       ->   - I           9
0839 
0840         // The updateInternalIndexes call above will have updated the F and G mappings correctly because proxyStart is 5.
0841         // That means that E -> 4 was not affected by the updateInternalIndexes call.
0842         // Now the mapping for E -> 4 needs to be updated so that it's a mapping for J -> 5.
0843 
0844         Q_ASSERT(!m_mapping.isEmpty());
0845         static const int column = 0;
0846         const QModelIndex oldIndex = q->sourceModel()->index(rowCount - 1 - difference, column, parent);
0847         Q_ASSERT(m_mapping.leftContains(oldIndex));
0848 
0849         const QModelIndex newIndex = q->sourceModel()->index(rowCount - 1, column, parent);
0850 
0851         QModelIndex indexAbove = oldIndex;
0852 
0853         if (start > 0) {
0854             // If we have something like this:
0855             //
0856             // - A
0857             // - - B
0858             // - - C
0859             //
0860             // and we then insert D as a sibling of A below it, we need to remove the mapping for A,
0861             // and the row number used for D must take into account the descendants of A.
0862 
0863             while (q->isSourceIndexExpanded(indexAbove) && q->sourceModel()->hasChildren(indexAbove)) {
0864                 Q_ASSERT(q->sourceModel()->rowCount(indexAbove) > 0);
0865                 indexAbove = q->sourceModel()->index(q->sourceModel()->rowCount(indexAbove) - 1, column, indexAbove);
0866             }
0867             Q_ASSERT(!q->isSourceIndexExpanded(indexAbove) || q->sourceModel()->rowCount(indexAbove) == 0);
0868         }
0869 
0870         Q_ASSERT(m_mapping.leftContains(indexAbove));
0871 
0872         const int newProxyRow = m_mapping.leftToRight(indexAbove) + difference;
0873 
0874         // oldIndex is E in the source. proxyRow is 4.
0875         m_mapping.removeLeft(oldIndex);
0876 
0877         // newIndex is J. (proxyRow + difference) is 5.
0878         m_mapping.insert(newIndex, newProxyRow);
0879     }
0880 
0881     for (int row = start; row <= end; ++row) {
0882         static const int column = 0;
0883         const QModelIndex idx = q->sourceModel()->index(row, column, parent);
0884         Q_ASSERT(idx.isValid());
0885 
0886         if (q->isSourceIndexExpanded(idx) && q->sourceModel()->hasChildren(idx) && q->sourceModel()->rowCount(idx) > 0) {
0887             m_pendingParents.append(idx);
0888         }
0889     }
0890 
0891     m_rowCount += difference;
0892 
0893     q->endInsertRows();
0894     scheduleProcessPendingParents();
0895     if (parent.isValid()) {
0896         const QModelIndex index = q->mapFromSource(parent);
0897         Q_EMIT q->dataChanged(index,
0898                               index,
0899                               {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole, KDescendantsProxyModel::HasSiblingsRole});
0900     }
0901 
0902     if (start > 0) {
0903         notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent));
0904     }
0905 }
0906 
0907 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
0908 {
0909     Q_Q(KDescendantsProxyModel);
0910 
0911     if (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent)) {
0912         return;
0913     }
0914 
0915     const int proxyStart = q->mapFromSource(q->sourceModel()->index(start, 0, parent)).row();
0916 
0917     static const int column = 0;
0918     QModelIndex idx = q->sourceModel()->index(end, column, parent);
0919     while (q->sourceModel()->hasChildren(idx) && q->sourceModel()->rowCount(idx) > 0) {
0920         idx = q->sourceModel()->index(q->sourceModel()->rowCount(idx) - 1, column, idx);
0921     }
0922     const int proxyEnd = q->mapFromSource(idx).row();
0923 
0924     for (int i = start; i <= end; ++i) {
0925         QModelIndex idx = q->sourceModel()->index(i, column, parent);
0926         m_expandedSourceIndexes.remove(QPersistentModelIndex(idx));
0927     }
0928 
0929     m_removePair = qMakePair(proxyStart, proxyEnd);
0930 
0931     q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd);
0932 }
0933 
0934 static QModelIndex getFirstDeepest(QAbstractItemModel *model, const QModelIndex &parent, int *count)
0935 {
0936     static const int column = 0;
0937     Q_ASSERT(model->hasChildren(parent));
0938     Q_ASSERT(model->rowCount(parent) > 0);
0939     for (int row = 0; row < model->rowCount(parent); ++row) {
0940         (*count)++;
0941         const QModelIndex child = model->index(row, column, parent);
0942         Q_ASSERT(child.isValid());
0943         if (model->hasChildren(child)) {
0944             return getFirstDeepest(model, child, count);
0945         }
0946     }
0947     return model->index(model->rowCount(parent) - 1, column, parent);
0948 }
0949 
0950 void KDescendantsProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
0951 {
0952     Q_Q(KDescendantsProxyModel);
0953     Q_UNUSED(end)
0954 
0955     if (!q->isSourceIndexExpanded(parent) || !q->isSourceIndexVisible(parent)) {
0956         if (parent.isValid()) {
0957             const QModelIndex index = q->mapFromSource(parent);
0958             Q_EMIT q->dataChanged(index, index, {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole});
0959         }
0960         return;
0961     }
0962 
0963     const int rowCount = q->sourceModel()->rowCount(parent);
0964 
0965     const int proxyStart = m_removePair.first;
0966     const int proxyEnd = m_removePair.second;
0967 
0968     const int difference = proxyEnd - proxyStart + 1;
0969     {
0970         Mapping::right_iterator it = m_mapping.rightLowerBound(proxyStart);
0971         const Mapping::right_iterator endIt = m_mapping.rightUpperBound(proxyEnd);
0972 
0973         if (endIt != m_mapping.rightEnd()) {
0974             while (it != endIt) {
0975                 it = m_mapping.eraseRight(it);
0976             }
0977         } else {
0978             while (it != m_mapping.rightUpperBound(proxyEnd)) {
0979                 it = m_mapping.eraseRight(it);
0980             }
0981         }
0982     }
0983 
0984     m_removePair = qMakePair(-1, -1);
0985     m_rowCount -= difference;
0986     Q_ASSERT(m_rowCount >= 0);
0987 
0988     updateInternalIndexes(proxyStart, -1 * difference);
0989 
0990     if (rowCount != start || rowCount == 0) {
0991         q->endRemoveRows();
0992         if (parent.isValid()) {
0993             const QModelIndex index = q->mapFromSource(parent);
0994             Q_EMIT q->dataChanged(index, index, {KDescendantsProxyModel::ExpandableRole, KDescendantsProxyModel::ExpandedRole});
0995         }
0996         if (start > 0) {
0997             notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent));
0998         }
0999         return;
1000     }
1001 
1002     static const int column = 0;
1003     const QModelIndex newEnd = q->sourceModel()->index(rowCount - 1, column, parent);
1004     Q_ASSERT(newEnd.isValid());
1005 
1006     if (m_mapping.isEmpty()) {
1007         m_mapping.insert(newEnd, newEnd.row());
1008         q->endRemoveRows();
1009         if (start > 0) {
1010             notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent));
1011         }
1012         return;
1013     }
1014     if (q->sourceModel()->hasChildren(newEnd)) {
1015         int count = 0;
1016         const QModelIndex firstDeepest = getFirstDeepest(q->sourceModel(), newEnd, &count);
1017         Q_ASSERT(firstDeepest.isValid());
1018         const int firstDeepestProxy = m_mapping.leftToRight(firstDeepest);
1019 
1020         m_mapping.insert(newEnd, firstDeepestProxy - count);
1021         q->endRemoveRows();
1022         if (start > 0) {
1023             notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent));
1024         }
1025         return;
1026     }
1027     Mapping::right_iterator lowerBound = m_mapping.rightLowerBound(proxyStart);
1028     if (lowerBound == m_mapping.rightEnd()) {
1029         int proxyRow = std::prev(lowerBound).key();
1030 
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)) {
1034                 ++proxyRow;
1035             } else {
1036                 break;
1037             }
1038         }
1039         m_mapping.insert(newEnd, proxyRow);
1040         q->endRemoveRows();
1041         if (start > 0) {
1042             notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent));
1043         }
1044         return;
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();
1051         }
1052         m_mapping.insert(newEnd, proxyRow);
1053         q->endRemoveRows();
1054         if (start > 0) {
1055             notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent));
1056         }
1057         return;
1058     }
1059     const Mapping::right_iterator boundAbove = std::prev(lowerBound);
1060 
1061     QList<QModelIndex> targetParents;
1062     targetParents.push_back(parent);
1063     {
1064         QModelIndex target = parent;
1065         int count = 0;
1066         while (target.isValid()) {
1067             if (target == boundAbove.value()) {
1068                 m_mapping.insert(newEnd, count + boundAbove.key() + newEnd.row() + 1);
1069                 q->endRemoveRows();
1070                 if (start > 0) {
1071                     notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent));
1072                 }
1073                 return;
1074             }
1075             count += (target.row() + 1);
1076             target = target.parent();
1077             if (target.isValid()) {
1078                 targetParents.push_back(target);
1079             }
1080         }
1081     }
1082 
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();
1089 
1090         if (targetParents.contains(prevParent)) {
1091             break;
1092         }
1093 
1094         if (!m_mapping.leftContains(prevParent)) {
1095             break;
1096         }
1097 
1098         if (m_mapping.leftToRight(prevParent) > boundAbove.key()) {
1099             break;
1100         }
1101     }
1102 
1103     QModelIndex trackedParent = parent;
1104 
1105     int proxyRow = boundAbove.key();
1106 
1107     Q_ASSERT(prevParent.isValid());
1108     proxyRow -= prevParent.row();
1109     while (trackedParent != boundParent) {
1110         proxyRow += (trackedParent.row() + 1);
1111         trackedParent = trackedParent.parent();
1112     }
1113     m_mapping.insert(newEnd, proxyRow + newEnd.row());
1114     q->endRemoveRows();
1115 
1116     if (parent.isValid()) {
1117         const QModelIndex oindex = q->mapFromSource(parent);
1118         QList<int> rolesChanged({KDescendantsProxyModel::ExpandableRole});
1119 
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});
1125         }
1126 
1127         Q_EMIT q->dataChanged(oindex, oindex, rolesChanged);
1128     }
1129 
1130     if (start > 0) {
1131         notifyhasSiblings(q->sourceModel()->index(start - 1, 0, parent));
1132     }
1133 }
1134 
1135 void KDescendantsProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &srcParent,
1136                                                              int srcStart,
1137                                                              int srcEnd,
1138                                                              const QModelIndex &destParent,
1139                                                              int destStart)
1140 {
1141     Q_Q(KDescendantsProxyModel);
1142 
1143     Q_UNUSED(destStart)
1144 
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);
1150 
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;
1155 
1156         q->beginInsertRows(QModelIndex(), proxyParentRow + destStart, proxyParentRow + destStart + (srcEnd - srcStart));
1157     }
1158 
1159     sourceLayoutAboutToBeChanged();
1160 }
1161 
1162 void KDescendantsProxyModelPrivate::sourceRowsMoved(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destStart)
1163 {
1164     Q_Q(KDescendantsProxyModel);
1165 
1166     Q_UNUSED(srcParent)
1167     Q_UNUSED(srcStart)
1168     Q_UNUSED(srcEnd)
1169     Q_UNUSED(destParent)
1170     Q_UNUSED(destStart)
1171 
1172     if (q->isSourceIndexExpanded(srcParent) && q->isSourceIndexVisible(srcParent)
1173         && (!q->isSourceIndexExpanded(destParent) || !q->isSourceIndexVisible(destParent))) {
1174         q->endRemoveRows();
1175     } else if (!q->isSourceIndexExpanded(srcParent) && q->isSourceIndexExpanded(destParent)) {
1176         q->endInsertRows();
1177     }
1178 
1179     sourceLayoutChanged();
1180 
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});
1188         }
1189     }
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});
1192 
1193     if (srcStart > 0) {
1194         notifyhasSiblings(q->sourceModel()->index(srcStart - 1, 0, srcParent));
1195     }
1196     if (destStart > 0) {
1197         notifyhasSiblings(q->sourceModel()->index(destStart - 1, 0, destParent));
1198     }
1199 }
1200 
1201 void KDescendantsProxyModelPrivate::sourceModelAboutToBeReset()
1202 {
1203     Q_Q(KDescendantsProxyModel);
1204     q->beginResetModel();
1205 }
1206 
1207 void KDescendantsProxyModelPrivate::sourceModelReset()
1208 {
1209     Q_Q(KDescendantsProxyModel);
1210     resetInternalData();
1211     if (q->sourceModel()->hasChildren() && q->sourceModel()->rowCount() > 0) {
1212         m_pendingParents.append(QModelIndex());
1213         scheduleProcessPendingParents();
1214     }
1215     q->endResetModel();
1216 }
1217 
1218 void KDescendantsProxyModelPrivate::sourceLayoutAboutToBeChanged()
1219 {
1220     Q_Q(KDescendantsProxyModel);
1221 
1222     if (m_ignoreNextLayoutChanged) {
1223         m_ignoreNextLayoutChanged = false;
1224         return;
1225     }
1226 
1227     if (m_mapping.isEmpty()) {
1228         return;
1229     }
1230 
1231     Q_EMIT q->layoutAboutToBeChanged();
1232 
1233     QPersistentModelIndex srcPersistentIndex;
1234     const auto lst = q->persistentIndexList();
1235     for (const QModelIndex &proxyPersistentIndex : lst) {
1236         m_proxyIndexes << proxyPersistentIndex;
1237         Q_ASSERT(proxyPersistentIndex.isValid());
1238         srcPersistentIndex = q->mapToSource(proxyPersistentIndex);
1239         Q_ASSERT(srcPersistentIndex.isValid());
1240         m_layoutChangePersistentIndexes << srcPersistentIndex;
1241     }
1242 }
1243 
1244 void KDescendantsProxyModelPrivate::sourceLayoutChanged()
1245 {
1246     Q_Q(KDescendantsProxyModel);
1247 
1248     if (m_ignoreNextLayoutAboutToBeChanged) {
1249         m_ignoreNextLayoutAboutToBeChanged = false;
1250         return;
1251     }
1252 
1253     if (m_mapping.isEmpty()) {
1254         return;
1255     }
1256 
1257     m_rowCount = 0;
1258 
1259     synchronousMappingRefresh();
1260 
1261     for (int i = 0; i < m_proxyIndexes.size(); ++i) {
1262         q->changePersistentIndex(m_proxyIndexes.at(i), q->mapFromSource(m_layoutChangePersistentIndexes.at(i)));
1263     }
1264 
1265     m_layoutChangePersistentIndexes.clear();
1266     m_proxyIndexes.clear();
1267 
1268     Q_EMIT q->layoutChanged();
1269 }
1270 
1271 void KDescendantsProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
1272 {
1273     Q_Q(KDescendantsProxyModel);
1274     // It is actually possible in a real world scenario that the source model emits dataChanged
1275     // with invalid indexes when the source model is a QSortFilterProxyModel
1276     // because QSortFilterProxyModel doesn't check for mapped index validity when its
1277     // source model emitted dataChanged on a column QSortFilterProxyModel doesn't accept.
1278     // See https://bugreports.qt.io/browse/QTBUG-86850
1279     if (!topLeft.isValid() || !bottomRight.isValid()) {
1280         return;
1281     }
1282     Q_ASSERT(topLeft.model() == q->sourceModel());
1283     Q_ASSERT(bottomRight.model() == q->sourceModel());
1284 
1285     if (!q->isSourceIndexExpanded(topLeft.parent()) || !q->isSourceIndexVisible(topLeft.parent())) {
1286         return;
1287     }
1288 
1289     const int topRow = topLeft.row();
1290     const int bottomRow = bottomRight.row();
1291 
1292     for (int i = topRow; i <= bottomRow; ++i) {
1293         const QModelIndex sourceTopLeft = q->sourceModel()->index(i, topLeft.column(), topLeft.parent());
1294 
1295         Q_ASSERT(sourceTopLeft.isValid());
1296         const QModelIndex proxyTopLeft = q->mapFromSource(sourceTopLeft);
1297         // TODO. If an index does not have any descendants, then we can emit in blocks of rows.
1298         // As it is we emit once for each row.
1299         const QModelIndex sourceBottomRight = q->sourceModel()->index(i, bottomRight.column(), bottomRight.parent());
1300         const QModelIndex proxyBottomRight = q->mapFromSource(sourceBottomRight);
1301         Q_ASSERT(proxyTopLeft.isValid());
1302         Q_ASSERT(proxyBottomRight.isValid());
1303         Q_EMIT q->dataChanged(proxyTopLeft, proxyBottomRight);
1304     }
1305 }
1306 
1307 void KDescendantsProxyModelPrivate::sourceModelDestroyed()
1308 {
1309     resetInternalData();
1310 }
1311 
1312 QMimeData *KDescendantsProxyModel::mimeData(const QModelIndexList &indexes) const
1313 {
1314     if (!sourceModel()) {
1315         return QAbstractProxyModel::mimeData(indexes);
1316     }
1317     Q_ASSERT(sourceModel());
1318     QModelIndexList sourceIndexes;
1319     for (const QModelIndex &index : indexes) {
1320         sourceIndexes << mapToSource(index);
1321     }
1322     return sourceModel()->mimeData(sourceIndexes);
1323 }
1324 
1325 QStringList KDescendantsProxyModel::mimeTypes() const
1326 {
1327     if (!sourceModel()) {
1328         return QAbstractProxyModel::mimeTypes();
1329     }
1330     Q_ASSERT(sourceModel());
1331     return sourceModel()->mimeTypes();
1332 }
1333 
1334 Qt::DropActions KDescendantsProxyModel::supportedDropActions() const
1335 {
1336     if (!sourceModel()) {
1337         return QAbstractProxyModel::supportedDropActions();
1338     }
1339     return sourceModel()->supportedDropActions();
1340 }
1341 
1342 #include "moc_kdescendantsproxymodel.cpp"