From 7854ad75d3f81ff1793b064cb55f22756391db46 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Mon, 28 Mar 2016 07:09:50 +0200 Subject: [PATCH] KSPM: Simplify deselection logic Iterate over the m_rootIndexList and remove things from it based on the deselection, rather than looping over the deselection and trying to figure out how it applies to the m_rootIndexList. --- src/kselectionproxymodel.cpp | 192 +++++++++++++++-------------------- 1 file changed, 80 insertions(+), 112 deletions(-) diff --git a/src/kselectionproxymodel.cpp b/src/kselectionproxymodel.cpp index 35d6acc..5bfe3b5 100644 --- a/src/kselectionproxymodel.cpp +++ b/src/kselectionproxymodel.cpp @@ -584,13 +584,15 @@ public: void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); void removeSelectionFromProxy(const QItemSelection &selection); - void removeRangeFromProxy(const QItemSelectionRange &range); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); void sourceModelDestroyed(); void resetInternalData(); + bool rootWillBeRemoved(const QItemSelection &selection, + const QModelIndex &root); + /** When items are inserted or removed in the m_startWithChildTrees configuration, this method helps find the startRow for use emitting the signals from the proxy. @@ -1108,6 +1110,41 @@ void KSelectionProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, m_pendingSelectionChanges.clear(); } +static bool rootWillBeRemovedFrom(const QModelIndex &ancestor, int start, int end, + const QModelIndex &root) +{ + Q_ASSERT(root.isValid()); + + auto parent = root; + while (parent.isValid()) { + auto prev = parent; + parent = parent.parent(); + if (parent == ancestor) { + return (prev.row() <= end && prev.row() >= start); + } + } + return false; +} + +bool KSelectionProxyModelPrivate::rootWillBeRemoved(const QItemSelection &selection, + const QModelIndex &root) +{ + Q_ASSERT(root.isValid()); + + for (auto r : selection) { + if (m_includeAllSelected) { + if (r.parent() == root.parent() && root.row() <= r.bottom() && root.row() >= r.top()) { + return true; + } + } else { + if (rootWillBeRemovedFrom(r.parent(), r.top(), r.bottom(), root)) { + return true; + } + } + } + return false; +} + QPair KSelectionProxyModelPrivate::beginRemoveRows(const QModelIndex &parent, int start, int end) const { Q_Q(const KSelectionProxyModel); @@ -1725,131 +1762,62 @@ void KSelectionProxyModelPrivate::removeSelectionFromProxy(const QItemSelection return; } - q->rootSelectionAboutToBeRemoved(selection); + QList::iterator rootIt = m_rootIndexList.begin(); + const QList::iterator rootEnd = m_rootIndexList.end(); + int proxyStartRemove = 0; - Q_FOREACH (const QItemSelectionRange &range, selection) { - removeRangeFromProxy(range); + for (; rootIt != rootEnd; ++rootIt) { + if (rootWillBeRemoved(selection, *rootIt)) { + break; + } else { + if (m_startWithChildTrees) { + auto rc = q->sourceModel()->rowCount(*rootIt); + proxyStartRemove += rc; + } else { + ++proxyStartRemove; + } + } } -} -void KSelectionProxyModelPrivate::removeRangeFromProxy(const QItemSelectionRange &range) -{ - Q_Q(KSelectionProxyModel); - - Q_ASSERT(range.model() == q->sourceModel()); - - const QModelIndex sourceTopLeft = range.topLeft(); - const QModelIndex proxyTopLeft = mapFromSource(sourceTopLeft); - const QModelIndex sourceBottomLeft = range.bottomRight().sibling(range.bottom(), 0); - const QModelIndex proxyParent = proxyTopLeft.parent(); - const QModelIndex sourceParent = sourceTopLeft.parent(); + if (rootIt == rootEnd) { + return; + } - if (m_startWithChildTrees) { - Q_ASSERT(sourceTopLeft.isValid()); - Q_ASSERT(sourceBottomLeft.isValid()); - const int startRootIdx = m_rootIndexList.indexOf(sourceTopLeft); - int endRootIdx = m_rootIndexList.indexOf(sourceBottomLeft); - QItemSelection extraRanges; - if (m_includeAllSelected) { - // It can happen that indexes of descendants get in between indexes which make up a range. - // We handle only the first contiguous block here and handle the rest later. - int idx = startRootIdx; - const int bottomIdx = endRootIdx; - const int rootListSize = m_rootIndexList.size(); - int next = idx + 1; - while (next <= bottomIdx) { - if (next < rootListSize && m_rootIndexList.at(next).parent() == sourceParent) { - idx = next; - ++next; - } else { - break; - } - } - endRootIdx = idx; - ++idx; - while (idx <= bottomIdx) { - const QModelIndex index = m_rootIndexList.at(idx); - if (m_rootIndexList.at(idx).parent() == sourceParent) { - extraRanges << QItemSelectionRange(index, index); - } - ++idx; - } - } - Q_ASSERT(endRootIdx != -1); - int childrenCount = q->sourceModel()->rowCount(sourceTopLeft); - for (int rootIdx = startRootIdx + 1; rootIdx <= endRootIdx; ++rootIdx) { - childrenCount += q->sourceModel()->rowCount(m_rootIndexList.at(rootIdx)); - } - if (childrenCount == 0) { - for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; --endRootIdx) { - const QModelIndex idx = m_rootIndexList.at(rootIdx); - q->rootIndexAboutToBeRemoved(idx); - m_rootIndexList.removeOne(idx); - } - return; - } - if (!m_includeAllSelected) { - ++endRootIdx; - for (; endRootIdx < m_rootIndexList.size(); ++endRootIdx) { - const QModelIndex idx = m_rootIndexList.at(endRootIdx); - if (isDescendantOf(sourceBottomLeft, idx)) { - childrenCount += q->sourceModel()->rowCount(idx); - } else { - break; - } - } - --endRootIdx; - } - const int proxyStart = getTargetRow(startRootIdx); - int proxyEnd = proxyStart + childrenCount - 1; - q->beginRemoveRows(QModelIndex(), proxyStart, proxyEnd); + int proxyEndRemove = proxyStartRemove; - for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; ++rootIdx) { - q->rootIndexAboutToBeRemoved(m_rootIndexList.at(rootIdx)); - } + QList::iterator rootRemoveStart = rootIt; - removeParentMappings(QModelIndex(), proxyStart, proxyEnd); - removeFirstChildMappings(proxyStart, proxyEnd); - int numRemovedChildren = 0; - for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; --endRootIdx) { - const QModelIndex idx = m_rootIndexList.at(rootIdx); - const int childCount = q->sourceModel()->rowCount(idx); - m_rootIndexList.removeAt(rootIdx); - numRemovedChildren += childCount; - } - updateInternalTopIndexes(proxyEnd + 1, -1 * numRemovedChildren); - q->endRemoveRows(); - if (m_includeAllSelected) { - removeSelectionFromProxy(kNormalizeSelection(extraRanges)); + for (; rootIt != rootEnd; ++rootIt) { + if (!rootWillBeRemoved(selection, *rootIt)) { + break; } - } else { - if (!proxyTopLeft.isValid()) { - return; + q->rootIndexAboutToBeRemoved(*rootIt); + if (m_startWithChildTrees) { + auto rc = q->sourceModel()->rowCount(*rootIt); + proxyEndRemove += rc; + } else { + ++proxyEndRemove; } - const int height = range.height(); - q->beginRemoveRows(proxyParent, proxyTopLeft.row(), proxyTopLeft.row() + height - 1); + } - // TODO: Do this conditionally if the signal is connected to anything. - for (int i = 0; i < height; ++i) { - const QModelIndex idx = sourceTopLeft.sibling(range.top() + i, sourceTopLeft.column()); - q->rootIndexAboutToBeRemoved(idx); - } + --proxyEndRemove; + if (proxyEndRemove >= 0) { + q->beginRemoveRows(QModelIndex(), proxyStartRemove, proxyEndRemove); - removeParentMappings(proxyParent, proxyTopLeft.row(), proxyTopLeft.row() + height - 1); - updateInternalIndexes(proxyParent, proxyTopLeft.row() + height, -1 * height); + rootIt = m_rootIndexList.erase(rootRemoveStart, rootIt); - for (int i = 0; i < height; ++i) { - const QModelIndex idx = sourceTopLeft.sibling(range.top() + i, sourceTopLeft.column()); - Q_ASSERT(idx.isValid()); - const bool b = m_rootIndexList.removeOne(idx); - Q_UNUSED(b) - if (!b) { - qDebug() << idx; - } - Q_ASSERT(b); + removeParentMappings(QModelIndex(), proxyStartRemove, proxyEndRemove); + if (m_startWithChildTrees) { + removeFirstChildMappings(proxyStartRemove, proxyEndRemove); } + updateInternalTopIndexes(proxyEndRemove + 1, -1 * (proxyEndRemove - proxyStartRemove + 1)); q->endRemoveRows(); + } else { + rootIt = m_rootIndexList.erase(rootRemoveStart, rootIt); + } + if (rootIt != rootEnd) { + removeSelectionFromProxy(selection); } }