QTreeView: optimize Private::intersectedRect()

The implementation for QTreeViewPrivate::intersectedRect() calculated
the view rect for every single index which is not needed:
 - when the row is spanned, the first item spans the complete viewport
 - the x-position of an index in the same column but different row is
   the same so no need to re-calculate the boundaries again (similar to
   the implementation in QTableView)

This reduces the visualRect() call count from n*m to n+m

Task-number: QTBUG-124173
Change-Id: I651b2ff9b6d4e68a82f32b3f5c3c0e746f88ce5e
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
This commit is contained in:
Christian Ehrlicher 2024-04-12 20:28:46 +02:00
parent 64b6a2aa70
commit 2f9c72028d

View File

@ -1412,13 +1412,48 @@ QRect QTreeViewPrivate::intersectedRect(const QRect rect, const QModelIndex &top
const auto parentIdx = topLeft.parent();
executePostedLayout();
QRect updateRect;
for (int r = topLeft.row(); r <= bottomRight.row(); ++r) {
if (isRowHidden(model->index(r, 0, parentIdx)))
int left = std::numeric_limits<int>::max();
int right = std::numeric_limits<int>::min();
for (int row = topLeft.row(); row <= bottomRight.row(); ++row) {
const auto idxCol0 = model->index(row, 0, parentIdx);
if (isRowHidden(idxCol0))
continue;
for (int c = topLeft.column(); c <= bottomRight.column(); ++c) {
const QModelIndex idx(model->index(r, c, parentIdx));
updateRect |= visualRect(idx, SingleSection);
QRect rowRect;
if (left != std::numeric_limits<int>::max()) {
// we already know left and right boundary of the rect to update
rowRect = visualRect(idxCol0, FullRow);
if (!rowRect.intersects(rect))
continue;
rowRect = QRect(left, rowRect.top(), right, rowRect.bottom());
} else if (!spanningIndexes.isEmpty() && spanningIndexes.contains(idxCol0)) {
// isFirstColumnSpanned re-creates the child index so take a shortcut here
// spans the whole row, therefore ask for FullRow instead for every cell
rowRect = visualRect(idxCol0, FullRow);
if (!rowRect.intersects(rect))
continue;
} else {
for (int col = topLeft.column(); col <= bottomRight.column(); ++col) {
if (header->isSectionHidden(col))
continue;
const QModelIndex idx(model->index(row, col, parentIdx));
const QRect idxRect = visualRect(idx, SingleSection);
if (idxRect.isNull())
continue;
// early exit when complete row is out of viewport
if (idxRect.top() > rect.bottom() && idxRect.bottom() < rect.top())
break;
if (!idxRect.intersects(rect))
continue;
rowRect = rowRect.united(idxRect);
if (rowRect.left() < rect.left() && rowRect.right() > rect.right())
break;
}
left = std::min(left, rowRect.left());
right = std::max(right, rowRect.right());
}
updateRect = updateRect.united(rowRect);
if (updateRect.contains(rect)) // already full rect covered?
break;
}
return rect.intersected(updateRect);
}