Skip to content

Commit

Permalink
QTreeView: fix performance regression from accessibility updates
Browse files Browse the repository at this point in the history
When expanding items in a tree view, the model as seen by accessibility
changes size and structure, and needs to be reset. This was done in
6a4afeb by emitting a ModelReset update
at the end of QTreeViewPrivate::layout when laying out the items had
changed the number of visible items.

However, QTreeViewPrivate::layout is called both recursively, and in a
loop when expanding all items, or expanding items to a certain depth,
resulting in a heavy performance hit when each recursion or iteration
causes the accessibility bridge to rebuild its representation from
scratch.

Instead, we now only store a flag that the model has to be reset in
QTreeViewPrivate::layout, and then trigger the reset in the function
that call layout, after the laying out is complete.

Fixes: QTBUG-122054
Pick-to: 6.7 6.6
Change-Id: Icb8384b56a4727c8c5050a1d501aebb55f48aafe
Reviewed-by: Oliver Eftevaag <oliver.eftevaag@qt.io>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
  • Loading branch information
vohi committed Feb 9, 2024
1 parent 16c27a8 commit a86321c
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 5 deletions.
26 changes: 21 additions & 5 deletions src/widgets/itemviews/qtreeview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2145,6 +2145,7 @@ void QTreeView::doItemsLayout()
}
QAbstractItemView::doItemsLayout();
d->header->doItemsLayout();
d->updateAccessibility();
}

/*!
Expand Down Expand Up @@ -2708,6 +2709,7 @@ void QTreeView::expandAll()
d->layout(-1, true);
updateGeometries();
d->viewport->update();
d->updateAccessibility();
}

/*!
Expand Down Expand Up @@ -2831,6 +2833,7 @@ void QTreeView::expandToDepth(int depth)

updateGeometries();
d->viewport->update();
d->updateAccessibility();
}

/*!
Expand Down Expand Up @@ -3142,6 +3145,7 @@ void QTreeViewPrivate::expand(int item, bool emitSignal)
beginAnimatedOperation();
#endif // animation
}
updateAccessibility();
}

void QTreeViewPrivate::insertViewItems(int pos, int count, const QTreeViewItem &viewItem)
Expand Down Expand Up @@ -3350,6 +3354,21 @@ void QTreeViewPrivate::columnsRemoved(const QModelIndex &parent, int start, int
QAbstractItemViewPrivate::columnsRemoved(parent, start, end);
}

void QTreeViewPrivate::updateAccessibility()
{
#if QT_CONFIG(accessibility)
Q_Q(QTreeView);
if (pendingAccessibilityUpdate) {
pendingAccessibilityUpdate = false;
if (QAccessible::isActive()) {
QAccessibleTableModelChangeEvent event(q, QAccessibleTableModelChangeEvent::ModelReset);
QAccessible::updateAccessibility(&event);
}
}
#endif
}


/** \internal
creates and initialize the viewItem structure of the children of the element \li
Expand All @@ -3374,11 +3393,8 @@ void QTreeViewPrivate::layout(int i, bool recursiveExpanding, bool afterIsUninit
// QAccessibleTree's rowCount implementation uses viewItems.size(), so
// we need to invalidate any cached accessibility data structures if
// that value changes during the run of this function.
const auto resetModelIfNeeded = qScopeGuard([oldViewItemsSize = viewItems.size(), this, q]{
if (oldViewItemsSize != viewItems.size() && QAccessible::isActive()) {
QAccessibleTableModelChangeEvent event(q, QAccessibleTableModelChangeEvent::ModelReset);
QAccessible::updateAccessibility(&event);
}
const auto resetModelIfNeeded = qScopeGuard([oldViewItemsSize = viewItems.size(), this]{
pendingAccessibilityUpdate |= oldViewItemsSize != viewItems.size();
});
#endif

Expand Down
6 changes: 6 additions & 0 deletions src/widgets/itemviews/qtreeview_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,12 @@ class Q_WIDGETS_EXPORT QTreeViewPrivate : public QAbstractItemViewPrivate
// tree position
int treePosition;

// pending accessibility update
#if QT_CONFIG(accessibility)
bool pendingAccessibilityUpdate = false;
#endif
void updateAccessibility();

QMetaObject::Connection animationConnection;
QMetaObject::Connection selectionmodelConnection;
std::array<QMetaObject::Connection, 2> modelConnections;
Expand Down

0 comments on commit a86321c

Please sign in to comment.