diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-08-29 11:47:05 +0200 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-09-01 18:03:29 +0200 |
commit | c59b34b8cf1c2a087e361d4235990803d89d34ec (patch) | |
tree | 9bd0e09474bc0d0179a7ad0b3363c6997eea1608 | |
parent | b770b0f8b98a280034b70bfd7e51e29f94ca93b6 (diff) |
QAccessible: consistently respect rootIndex of item views
Accessibility implementations rely on correct information about the
model dimensions when operating on item views. An item view that has a
root index set needs to report it's size based on the root index, rather
than for the view's model directly.
Pass the rootIndex to all calls to QAbstractItemModel::column/rowCount.
Refactor the code to avoid excessive dereferencing of a QPointer, apply
const and fix/improve coding style in touched lines.
Emit a ModelReset notification when the root index changes, or (in the
case of QListView) when the model column changes.
Split long Q_ASSERTs into multiple lines to be able to better trace the
exact reason for an assertion, and replace the assert with an early
return of nil when it's plausible that a cached cell is no longer part
of the view (i.e. because the root index changed).
Add a test case that verifies that changing the root index changes the
dimension of the view as reported through the accessibility interface.
Pick-to: 6.6 6.5
Fixes: QTBUG-114423
Change-Id: I7897b79b2e1d10c789cc866b7f5c5dabdabe6770
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm | 10 | ||||
-rw-r--r-- | src/widgets/accessible/itemviews.cpp | 224 | ||||
-rw-r--r-- | src/widgets/itemviews/qabstractitemview.cpp | 6 | ||||
-rw-r--r-- | src/widgets/itemviews/qlistview.cpp | 6 | ||||
-rw-r--r-- | tests/auto/other/qaccessibility/tst_qaccessibility.cpp | 47 |
5 files changed, 207 insertions, 86 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 7a1bab7351..85c395e2bf 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -130,7 +130,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of if (tableInterface) { auto *tableElement = [QMacAccessibilityElement elementWithInterface:table]; Q_ASSERT(tableElement); - Q_ASSERT(tableElement->rows && int(tableElement->rows.count) > m_rowIndex); + Q_ASSERT(tableElement->rows); + Q_ASSERT(int(tableElement->rows.count) > m_rowIndex); auto *rowElement = tableElement->rows[m_rowIndex]; if (!rowElement->columns) { rowElement->columns = [rowElement populateTableRow:rowElement->columns @@ -490,7 +491,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of // a synthetic cell without interface - shortcut to the row QMacAccessibilityElement *tableElement = [QMacAccessibilityElement elementWithId:axid]; - Q_ASSERT(tableElement && tableElement->rows && int(tableElement->rows.count) > m_rowIndex); + Q_ASSERT(tableElement && tableElement->rows); + Q_ASSERT(int(tableElement->rows.count) > m_rowIndex); QMacAccessibilityElement *rowElement = tableElement->rows[m_rowIndex]; return rowElement; } @@ -520,7 +522,9 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of rowIndex = m_rowIndex; else if (QAccessibleTableCellInterface *cell = iface->tableCellInterface()) rowIndex = cell->rowIndex(); - Q_ASSERT(tableElement->rows && int([tableElement->rows count]) > rowIndex); + Q_ASSERT(tableElement->rows); + if (rowIndex > int([tableElement->rows count])) + return nil; QMacAccessibilityElement *rowElement = tableElement->rows[rowIndex]; return NSAccessibilityUnignoredAncestor(rowElement); } diff --git a/src/widgets/accessible/itemviews.cpp b/src/widgets/accessible/itemviews.cpp index e640194a2e..b960cd70e2 100644 --- a/src/widgets/accessible/itemviews.cpp +++ b/src/widgets/accessible/itemviews.cpp @@ -39,11 +39,16 @@ QAbstractItemView *QAccessibleTable::view() const int QAccessibleTable::logicalIndex(const QModelIndex &index) const { - if (!view()->model() || !index.isValid()) + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = index.model(); + if (!theModel || !index.isValid()) return -1; - int vHeader = verticalHeader() ? 1 : 0; - int hHeader = horizontalHeader() ? 1 : 0; - return (index.row() + hHeader)*(index.model()->columnCount() + vHeader) + (index.column() + vHeader); + + const QModelIndex rootIndex = theView->rootIndex(); + const int vHeader = verticalHeader() ? 1 : 0; + const int hHeader = horizontalHeader() ? 1 : 0; + return (index.row() + hHeader) * (theModel->columnCount(rootIndex) + vHeader) + + (index.column() + vHeader); } QAccessibleTable::QAccessibleTable(QWidget *w) @@ -113,12 +118,14 @@ QHeaderView *QAccessibleTable::verticalHeader() const QAccessibleInterface *QAccessibleTable::cellAt(int row, int column) const { - if (!view()->model()) + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + if (!theModel) return nullptr; Q_ASSERT(role() != QAccessible::Tree); - QModelIndex index = view()->model()->index(row, column, view()->rootIndex()); + QModelIndex index = theModel->index(row, column, theView->rootIndex()); if (Q_UNLIKELY(!index.isValid())) { - qWarning() << "QAccessibleTable::cellAt: invalid index: " << index << " for " << view(); + qWarning() << "QAccessibleTable::cellAt: invalid index: " << index << " for " << theView; return nullptr; } return child(logicalIndex(index)); @@ -131,23 +138,29 @@ QAccessibleInterface *QAccessibleTable::caption() const QString QAccessibleTable::columnDescription(int column) const { - if (!view()->model()) + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + if (!theModel) return QString(); - return view()->model()->headerData(column, Qt::Horizontal).toString(); + return theModel->headerData(column, Qt::Horizontal).toString(); } int QAccessibleTable::columnCount() const { - if (!view()->model()) + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + if (!theModel) return 0; - return view()->model()->columnCount(); + return theModel->columnCount(theView->rootIndex()); } int QAccessibleTable::rowCount() const { - if (!view()->model()) + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + if (!theModel) return 0; - return view()->model()->rowCount(); + return theModel->rowCount(theView->rootIndex()); } int QAccessibleTable::selectedCellCount() const @@ -173,9 +186,11 @@ int QAccessibleTable::selectedRowCount() const QString QAccessibleTable::rowDescription(int row) const { - if (!view()->model()) + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + if (!theModel) return QString(); - return view()->model()->headerData(row, Qt::Vertical).toString(); + return theModel->headerData(row, Qt::Vertical).toString(); } QList<QAccessibleInterface *> QAccessibleTable::selectedCells() const @@ -237,9 +252,13 @@ bool QAccessibleTable::isRowSelected(int row) const bool QAccessibleTable::selectRow(int row) { - if (!view()->model() || !view()->selectionModel()) + QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + if (!theModel || !view()->selectionModel()) return false; - QModelIndex index = view()->model()->index(row, 0, view()->rootIndex()); + + const QModelIndex rootIndex = theView->rootIndex(); + const QModelIndex index = theModel->index(row, 0, rootIndex); if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectColumns) return false; @@ -253,9 +272,10 @@ bool QAccessibleTable::selectRow(int row) view()->clearSelection(); break; case QAbstractItemView::ContiguousSelection: - if ((!row || !view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex())) - && !view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex())) - view()->clearSelection(); + if ((!row || !theView->selectionModel()->isRowSelected(row - 1, rootIndex)) + && !theView->selectionModel()->isRowSelected(row + 1, rootIndex)) { + theView->clearSelection(); + } break; default: break; @@ -267,45 +287,55 @@ bool QAccessibleTable::selectRow(int row) bool QAccessibleTable::selectColumn(int column) { - if (!view()->model() || !view()->selectionModel()) + QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + auto *selectionModel = theView->selectionModel(); + if (!theModel || !selectionModel) return false; - QModelIndex index = view()->model()->index(0, column, view()->rootIndex()); + + const QModelIndex rootIndex = theView->rootIndex(); + const QModelIndex index = theModel->index(0, column, rootIndex); if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectRows) return false; - switch (view()->selectionMode()) { + switch (theView->selectionMode()) { case QAbstractItemView::NoSelection: return false; case QAbstractItemView::SingleSelection: - if (view()->selectionBehavior() != QAbstractItemView::SelectColumns && rowCount() > 1) + if (theView->selectionBehavior() != QAbstractItemView::SelectColumns && rowCount() > 1) return false; Q_FALLTHROUGH(); case QAbstractItemView::ContiguousSelection: - if ((!column || !view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex())) - && !view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex())) - view()->clearSelection(); + if ((!column || !selectionModel->isColumnSelected(column - 1, rootIndex)) + && !selectionModel->isColumnSelected(column + 1, rootIndex)) { + theView->clearSelection(); + } break; default: break; } - view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Columns); + selectionModel->select(index, QItemSelectionModel::Select | QItemSelectionModel::Columns); return true; } bool QAccessibleTable::unselectRow(int row) { - if (!view()->model() || !view()->selectionModel()) + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + auto *selectionModel = theView->selectionModel(); + if (!theModel || !selectionModel) return false; - QModelIndex index = view()->model()->index(row, 0, view()->rootIndex()); + const QModelIndex rootIndex = theView->rootIndex(); + const QModelIndex index = view()->model()->index(row, 0, rootIndex); if (!index.isValid()) return false; QItemSelection selection(index, index); - switch (view()->selectionMode()) { + switch (theView->selectionMode()) { case QAbstractItemView::SingleSelection: //In SingleSelection and ContiguousSelection once an item //is selected, there's no way for the user to unselect all items @@ -316,26 +346,30 @@ bool QAccessibleTable::unselectRow(int row) if (selectedRowCount() == 1) return false; - if ((!row || view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex())) - && view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex())) { + if ((!row || selectionModel->isRowSelected(row - 1, rootIndex)) + && selectionModel->isRowSelected(row + 1, rootIndex)) { //If there are rows selected both up the current row and down the current rown, //the ones which are down the current row will be deselected - selection = QItemSelection(index, view()->model()->index(rowCount() - 1, 0, view()->rootIndex())); + selection = QItemSelection(index, theModel->index(rowCount() - 1, 0, rootIndex)); } default: break; } - view()->selectionModel()->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Rows); + selectionModel->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Rows); return true; } bool QAccessibleTable::unselectColumn(int column) { - if (!view()->model() || !view()->selectionModel()) + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + auto *selectionModel = theView->selectionModel(); + if (!theModel || !selectionModel) return false; - QModelIndex index = view()->model()->index(0, column, view()->rootIndex()); + const QModelIndex rootIndex = theView->rootIndex(); + const QModelIndex index = view()->model()->index(0, column, rootIndex); if (!index.isValid()) return false; @@ -352,17 +386,17 @@ bool QAccessibleTable::unselectColumn(int column) if (selectedColumnCount() == 1) return false; - if ((!column || view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex())) - && view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex())) { + if ((!column || selectionModel->isColumnSelected(column - 1, rootIndex)) + && selectionModel->isColumnSelected(column + 1, rootIndex)) { //If there are columns selected both at the left of the current row and at the right //of the current rown, the ones which are at the right will be deselected - selection = QItemSelection(index, view()->model()->index(0, columnCount() - 1, view()->rootIndex())); + selection = QItemSelection(index, theModel->index(0, columnCount() - 1, rootIndex)); } default: break; } - view()->selectionModel()->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Columns); + selectionModel->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Columns); return true; } @@ -481,10 +515,9 @@ QAccessibleInterface *QAccessibleTable::childAt(int x, int y) const QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset); // FIXME: if indexPosition < 0 in one coordinate, return header - QModelIndex index = view()->indexAt(indexPosition); - if (index.isValid()) { + const QModelIndex index = view()->indexAt(indexPosition); + if (index.isValid()) return child(logicalIndex(index)); - } return nullptr; } @@ -499,21 +532,27 @@ QAccessibleInterface *QAccessibleTable::focusChild() const int QAccessibleTable::childCount() const { - if (!view()->model()) + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + if (!theModel) return 0; + const QModelIndex rootIndex = theView->rootIndex(); int vHeader = verticalHeader() ? 1 : 0; int hHeader = horizontalHeader() ? 1 : 0; - return (view()->model()->rowCount()+hHeader) * (view()->model()->columnCount()+vHeader); + return (theModel->rowCount(rootIndex) + hHeader) * (theModel->columnCount(rootIndex) + vHeader); } int QAccessibleTable::indexOfChild(const QAccessibleInterface *iface) const { - if (!view()->model()) + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + if (!theModel) return -1; QAccessibleInterface *parent = iface->parent(); - if (parent->object() != view()) + if (parent->object() != theView) return -1; + const QModelIndex rootIndex = theView->rootIndex(); Q_ASSERT(iface->role() != QAccessible::TreeItem); // should be handled by tree class if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) { const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(iface); @@ -523,7 +562,7 @@ int QAccessibleTable::indexOfChild(const QAccessibleInterface *iface) const return cell->index + (verticalHeader() ? 1 : 0); } else if (iface->role() == QAccessible::RowHeader){ const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface); - return (cell->index + 1) * (view()->model()->columnCount() + 1); + return (cell->index + 1) * (theModel->columnCount(rootIndex) + 1); } else if (iface->role() == QAccessible::Pane) { return 0; // corner button } else { @@ -562,9 +601,12 @@ QAccessibleInterface *QAccessibleTable::parent() const QAccessibleInterface *QAccessibleTable::child(int logicalIndex) const { - if (!view()->model()) + QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + if (!theModel) return nullptr; + const QModelIndex rootIndex = theView->rootIndex(); auto id = childToId.constFind(logicalIndex); if (id != childToId.constEnd()) return QAccessible::accessibleInterface(id.value()); @@ -572,7 +614,7 @@ QAccessibleInterface *QAccessibleTable::child(int logicalIndex) const int vHeader = verticalHeader() ? 1 : 0; int hHeader = horizontalHeader() ? 1 : 0; - int columns = view()->model()->columnCount() + vHeader; + int columns = theModel->columnCount(rootIndex) + vHeader; int row = logicalIndex / columns; int column = logicalIndex % columns; @@ -582,27 +624,27 @@ QAccessibleInterface *QAccessibleTable::child(int logicalIndex) const if (vHeader) { if (column == 0) { if (hHeader && row == 0) { - iface = new QAccessibleTableCornerButton(view()); + iface = new QAccessibleTableCornerButton(theView); } else { - iface = new QAccessibleTableHeaderCell(view(), row - hHeader, Qt::Vertical); + iface = new QAccessibleTableHeaderCell(theView, row - hHeader, Qt::Vertical); } } --column; } if (!iface && hHeader) { if (row == 0) { - iface = new QAccessibleTableHeaderCell(view(), column, Qt::Horizontal); + iface = new QAccessibleTableHeaderCell(theView, column, Qt::Horizontal); } --row; } if (!iface) { - QModelIndex index = view()->model()->index(row, column, view()->rootIndex()); + QModelIndex index = theModel->index(row, column, rootIndex); if (Q_UNLIKELY(!index.isValid())) { qWarning("QAccessibleTable::child: Invalid index at: %d %d", row, column); return nullptr; } - iface = new QAccessibleTableCell(view(), index, cellRole()); + iface = new QAccessibleTableCell(theView, index, cellRole()); } QAccessible::registerAccessibleInterface(iface); @@ -749,34 +791,39 @@ QModelIndex QAccessibleTree::indexFromLogical(int row, int column) const QAccessibleInterface *QAccessibleTree::childAt(int x, int y) const { - if (!view()->model()) + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + if (!theModel) return nullptr; - QPoint viewportOffset = view()->viewport()->mapTo(view(), QPoint(0,0)); - QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset); - QModelIndex index = view()->indexAt(indexPosition); + const QPoint viewportOffset = theView->viewport()->mapTo(view(), QPoint(0, 0)); + const QPoint indexPosition = theView->mapFromGlobal(QPoint(x, y) - viewportOffset); + + const QModelIndex index = theView->indexAt(indexPosition); if (!index.isValid()) return nullptr; - const QTreeView *treeView = qobject_cast<const QTreeView*>(view()); + const QTreeView *treeView = qobject_cast<const QTreeView *>(theView); int row = treeView->d_func()->viewIndex(index) + (horizontalHeader() ? 1 : 0); int column = index.column(); - int i = row * view()->model()->columnCount() + column; + int i = row * theModel->columnCount(theView->rootIndex()) + column; return child(i); } QAccessibleInterface *QAccessibleTree::focusChild() const { - QModelIndex index = view()->currentIndex(); + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + const QModelIndex index = theView->currentIndex(); if (!index.isValid()) return nullptr; - const QTreeView *treeView = qobject_cast<const QTreeView*>(view()); - int row = treeView->d_func()->viewIndex(index) + (horizontalHeader() ? 1 : 0); - int column = index.column(); + const QTreeView *treeView = qobject_cast<const QTreeView *>(theView); + const int row = treeView->d_func()->viewIndex(index) + (horizontalHeader() ? 1 : 0); + const int column = index.column(); - int i = row * view()->model()->columnCount() + column; + int i = row * theModel->columnCount(theView->rootIndex()) + column; return child(i); } @@ -784,33 +831,37 @@ int QAccessibleTree::childCount() const { const QTreeView *treeView = qobject_cast<const QTreeView*>(view()); Q_ASSERT(treeView); - if (!view()->model()) + const QAbstractItemModel *theModel = treeView->model(); + if (!theModel) return 0; int hHeader = horizontalHeader() ? 1 : 0; - return (treeView->d_func()->viewItems.size() + hHeader)* view()->model()->columnCount(); + return (treeView->d_func()->viewItems.size() + hHeader) + * theModel->columnCount(treeView->rootIndex()); } QAccessibleInterface *QAccessibleTree::child(int logicalIndex) const { - if (logicalIndex < 0 || !view()->model() || !view()->model()->columnCount()) + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + const QModelIndex rootIndex = theView->rootIndex(); + if (logicalIndex < 0 || !theModel || !theModel->columnCount(rootIndex)) return nullptr; QAccessibleInterface *iface = nullptr; int index = logicalIndex; if (horizontalHeader()) { - if (index < view()->model()->columnCount()) { + if (index < theModel->columnCount(rootIndex)) iface = new QAccessibleTableHeaderCell(view(), index, Qt::Horizontal); - } else { - index -= view()->model()->columnCount(); - } + else + index -= theModel->columnCount(rootIndex); } if (!iface) { - int row = index / view()->model()->columnCount(); - int column = index % view()->model()->columnCount(); - QModelIndex modelIndex = indexFromLogical(row, column); + const int row = index / theModel->columnCount(rootIndex); + const int column = index % theModel->columnCount(rootIndex); + const QModelIndex modelIndex = indexFromLogical(row, column); if (!modelIndex.isValid()) return nullptr; iface = new QAccessibleTableCell(view(), modelIndex, cellRole()); @@ -829,7 +880,9 @@ int QAccessibleTree::rowCount() const int QAccessibleTree::indexOfChild(const QAccessibleInterface *iface) const { - if (!view()->model()) + const QAbstractItemView *theView = view(); + const QAbstractItemModel *theModel = theView->model(); + if (!theModel) return -1; QAccessibleInterface *parent = iface->parent(); if (parent->object() != view()) @@ -837,12 +890,12 @@ int QAccessibleTree::indexOfChild(const QAccessibleInterface *iface) const if (iface->role() == QAccessible::TreeItem) { const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(iface); - const QTreeView *treeView = qobject_cast<const QTreeView*>(view()); + const QTreeView *treeView = qobject_cast<const QTreeView *>(theView); Q_ASSERT(treeView); int row = treeView->d_func()->viewIndex(cell->m_index) + (horizontalHeader() ? 1 : 0); int column = cell->m_index.column(); - int index = row * view()->model()->columnCount() + column; + int index = row * theModel->columnCount(theView->rootIndex()) + column; return index; } else if (iface->role() == QAccessible::ColumnHeader){ const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface); @@ -1299,9 +1352,14 @@ void QAccessibleTableHeaderCell::setText(QAccessible::Text, const QString &) bool QAccessibleTableHeaderCell::isValid() const { - return view && !qt_widget_private(view)->data.in_destructor - && view->model() && (index >= 0) - && ((orientation == Qt::Horizontal) ? (index < view->model()->columnCount()) : (index < view->model()->rowCount())); + const QAbstractItemModel *theModel = view && !qt_widget_private(view)->data.in_destructor + ? view->model() : nullptr; + if (!theModel) + return false; + const QModelIndex rootIndex = view->rootIndex(); + return (index >= 0) && ((orientation == Qt::Horizontal) + ? (index < theModel->columnCount(rootIndex)) + : (index < theModel->rowCount(rootIndex))); } QAccessibleInterface *QAccessibleTableHeaderCell::parent() const diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index 41aba6297c..5c2e59915f 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -1159,6 +1159,12 @@ void QAbstractItemView::setRootIndex(const QModelIndex &index) return; } d->root = index; +#if QT_CONFIG(accessibility) + if (QAccessible::isActive()) { + QAccessibleTableModelChangeEvent accessibleEvent(this, QAccessibleTableModelChangeEvent::ModelReset); + QAccessible::updateAccessibility(&accessibleEvent); + } +#endif d->doDelayedItemsLayout(); d->updateGeometry(); } diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp index 89fccfc2ba..a4cb4c76fb 100644 --- a/src/widgets/itemviews/qlistview.cpp +++ b/src/widgets/itemviews/qlistview.cpp @@ -1622,6 +1622,12 @@ void QListView::setModelColumn(int column) return; d->column = column; d->doDelayedItemsLayout(); +#if QT_CONFIG(accessibility) + if (QAccessible::isActive()) { + QAccessibleTableModelChangeEvent event(this, QAccessibleTableModelChangeEvent::ModelReset); + QAccessible::updateAccessibility(&event); + } +#endif } int QListView::modelColumn() const diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp index 3580e3c844..d63a2dfe08 100644 --- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp @@ -39,6 +39,7 @@ #include <QtTest/private/qtesthelpers_p.h> using namespace QTestPrivate; +using namespace Qt::StringLiterals; static inline bool verifyChild(QWidget *child, QAccessibleInterface *interface, int index, const QRect &domain) @@ -213,6 +214,7 @@ private slots: void listTest(); void treeTest(); void tableTest(); + void rootIndexView(); void uniqueIdTest(); void calendarWidgetTest(); @@ -3405,6 +3407,51 @@ void tst_QAccessibility::tableTest() QTestAccessibility::clearEvents(); } +void tst_QAccessibility::rootIndexView() +{ + QStandardItemModel model; + for (int i = 0; i < 2; ++i) { + QStandardItem *item = new QStandardItem(u"root %1"_s.arg(i)); + for (int j = 0; j < 5 * (i + 1); ++j) { + switch (i) { + case 0: + item->appendRow(new QStandardItem(u"child0/%1"_s.arg(j))); + break; + case 1: + item->appendRow({new QStandardItem(u"column0 1/%1"_s.arg(j)), + new QStandardItem(u"column1 1/%1"_s.arg(j)) + }); + break; + } + } + model.appendRow(item); + } + + QListView view; + view.setModel(&model); + QTestAccessibility::clearEvents(); + + QAccessibleInterface *accView = QAccessible::queryAccessibleInterface(&view); + QVERIFY(accView); + QAccessibleTableInterface *accTable = accView->tableInterface(); + QVERIFY(accTable); + QCOMPARE(accTable->rowCount(), 2); + QCOMPARE(accTable->columnCount(), 1); + + view.setRootIndex(model.index(0, 0)); + QAccessibleTableModelChangeEvent resetEvent(&view, QAccessibleTableModelChangeEvent::ModelReset); + QVERIFY(QTestAccessibility::containsEvent(&resetEvent)); + + QCOMPARE(accTable->rowCount(), 5); + QCOMPARE(accTable->columnCount(), 1); + + view.setRootIndex(model.index(1, 0)); + QCOMPARE(accTable->rowCount(), 10); + QCOMPARE(accTable->columnCount(), 2); + + QTestAccessibility::clearEvents(); +} + void tst_QAccessibility::uniqueIdTest() { // Test that an ID isn't reassigned to another interface right away when an accessible interface |