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 sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
void removeSelectionFromProxy(const QItemSelection &selection); void removeSelectionFromProxy(const QItemSelection &selection);
void removeRangeFromProxy(const QItemSelectionRange &range);
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void sourceModelDestroyed(); void sourceModelDestroyed();
void resetInternalData(); void resetInternalData();
bool rootWillBeRemoved(const QItemSelection &selection,
const QModelIndex &root);
/** /**
When items are inserted or removed in the m_startWithChildTrees configuration, 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. 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(); 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 QPair<int, int> KSelectionProxyModelPrivate::beginRemoveRows(const QModelIndex &parent, int start, int end) const
{ {
Q_Q(const KSelectionProxyModel); Q_Q(const KSelectionProxyModel);
@ -1725,131 +1762,62 @@ void KSelectionProxyModelPrivate::removeSelectionFromProxy(const QItemSelection
return; 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) { for (; rootIt != rootEnd; ++rootIt) {
removeRangeFromProxy(range); 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) if (rootIt == rootEnd) {
{ return;
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 (m_startWithChildTrees) { int proxyEndRemove = proxyStartRemove;
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);
for (int rootIdx = startRootIdx; rootIdx <= endRootIdx; ++rootIdx) { QList<QPersistentModelIndex>::iterator rootRemoveStart = rootIt;
q->rootIndexAboutToBeRemoved(m_rootIndexList.at(rootIdx));
}
removeParentMappings(QModelIndex(), proxyStart, proxyEnd); for (; rootIt != rootEnd; ++rootIt) {
removeFirstChildMappings(proxyStart, proxyEnd); if (!rootWillBeRemoved(selection, *rootIt)) {
int numRemovedChildren = 0; break;
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));
} }
} else { q->rootIndexAboutToBeRemoved(*rootIt);
if (!proxyTopLeft.isValid()) { if (m_startWithChildTrees) {
return; 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. --proxyEndRemove;
for (int i = 0; i < height; ++i) { if (proxyEndRemove >= 0) {
const QModelIndex idx = sourceTopLeft.sibling(range.top() + i, sourceTopLeft.column()); q->beginRemoveRows(QModelIndex(), proxyStartRemove, proxyEndRemove);
q->rootIndexAboutToBeRemoved(idx);
}
removeParentMappings(proxyParent, proxyTopLeft.row(), proxyTopLeft.row() + height - 1); rootIt = m_rootIndexList.erase(rootRemoveStart, rootIt);
updateInternalIndexes(proxyParent, proxyTopLeft.row() + height, -1 * height);
for (int i = 0; i < height; ++i) { removeParentMappings(QModelIndex(), proxyStartRemove, proxyEndRemove);
const QModelIndex idx = sourceTopLeft.sibling(range.top() + i, sourceTopLeft.column()); if (m_startWithChildTrees) {
Q_ASSERT(idx.isValid()); removeFirstChildMappings(proxyStartRemove, proxyEndRemove);
const bool b = m_rootIndexList.removeOne(idx);
Q_UNUSED(b)
if (!b) {
qDebug() << idx;
}
Q_ASSERT(b);
} }
updateInternalTopIndexes(proxyEndRemove + 1, -1 * (proxyEndRemove - proxyStartRemove + 1));
q->endRemoveRows(); q->endRemoveRows();
} else {
rootIt = m_rootIndexList.erase(rootRemoveStart, rootIt);
}
if (rootIt != rootEnd) {
removeSelectionFromProxy(selection);
} }
} }

Loading…
Cancel
Save