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.
wilder
Stephen Kelly 10 years ago
parent 0cf75268b0
commit 7854ad75d3
  1. 192
      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<int, int> 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<QPersistentModelIndex>::iterator rootIt = m_rootIndexList.begin();
const QList<QPersistentModelIndex>::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<QPersistentModelIndex>::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);
}
}

Loading…
Cancel
Save