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>
This commit is contained in:
Volker Hilsheimer 2023-08-29 11:47:05 +02:00
parent b770b0f8b9
commit c59b34b8cf
5 changed files with 207 additions and 86 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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