QComboBox: inform accessibility about model change before selecting

QComboBox implicitly selects the first item that gets inserted into the
model. This happens in response to the model's rowInserted signal, at
which point the item view might not have handled the rowInserted signal
yet. Because of that, the view couldn't update the accessibility bridge,
so informing accessibility about a row being selected that doens't exist
in the bridge's representation of the table yet will result in data
being out of sync, and depending on the bridge implementation trigger
asserts.

Fix this by explicitly updating the accessibility bridge before
implicitly selecting the first row.

Fixes: QTBUG-119526
Fixes: QTBUG-118585
Pick-to: 6.6 6.5
Change-Id: I2830c00751b3f18feb5d9252b23823c80229fed1
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
This commit is contained in:
Volker Hilsheimer 2023-12-08 16:53:51 +01:00
parent e28a664ae1
commit ecef704624
2 changed files with 22 additions and 0 deletions

View File

@ -9,12 +9,15 @@
#include "qcocoawindow.h" #include "qcocoawindow.h"
#include "qcocoascreen.h" #include "qcocoascreen.h"
#include <QtCore/qlogging.h>
#include <QtGui/private/qaccessiblecache_p.h> #include <QtGui/private/qaccessiblecache_p.h>
#include <QtGui/private/qaccessiblebridgeutils_p.h> #include <QtGui/private/qaccessiblebridgeutils_p.h>
#include <QtGui/qaccessible.h> #include <QtGui/qaccessible.h>
QT_USE_NAMESPACE QT_USE_NAMESPACE
Q_LOGGING_CATEGORY(lcAccessibilityTable, "qt.accessibility.table")
using namespace Qt::Literals::StringLiterals; using namespace Qt::Literals::StringLiterals;
#if QT_CONFIG(accessibility) #if QT_CONFIG(accessibility)
@ -133,6 +136,12 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
auto *tableElement = [QMacAccessibilityElement elementWithInterface:table]; auto *tableElement = [QMacAccessibilityElement elementWithInterface:table];
Q_ASSERT(tableElement); Q_ASSERT(tableElement);
Q_ASSERT(tableElement->rows); Q_ASSERT(tableElement->rows);
qCDebug(lcAccessibilityTable) << "Creating cell representation for"
<< m_rowIndex << m_columnIndex
<< "in table with"
<< tableElement->rows.count << "rows";
Q_ASSERT(int(tableElement->rows.count) > m_rowIndex); Q_ASSERT(int(tableElement->rows.count) > m_rowIndex);
auto *rowElement = tableElement->rows[m_rowIndex]; auto *rowElement = tableElement->rows[m_rowIndex];
if (!rowElement->columns) { if (!rowElement->columns) {
@ -275,6 +284,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
if (QAccessibleInterface *iface = self.qtInterface) { if (QAccessibleInterface *iface = self.qtInterface) {
if (QAccessibleTableInterface *table = iface->tableInterface()) { if (QAccessibleTableInterface *table = iface->tableInterface()) {
Q_ASSERT(!self.isManagedByParent); Q_ASSERT(!self.isManagedByParent);
qCDebug(lcAccessibilityTable) << "Updating table representation with"
<< table->rowCount() << table->columnCount();
rows = [self populateTableArray:rows role:NSAccessibilityRowRole count:table->rowCount()]; rows = [self populateTableArray:rows role:NSAccessibilityRowRole count:table->rowCount()];
columns = [self populateTableArray:columns role:NSAccessibilityColumnRole count:table->columnCount()]; columns = [self populateTableArray:columns role:NSAccessibilityColumnRole count:table->columnCount()];
} }

View File

@ -1128,6 +1128,17 @@ void QComboBoxPrivate::rowsInserted(const QModelIndex &parent, int start, int en
// set current index if combo was previously empty and there is no placeholderText // set current index if combo was previously empty and there is no placeholderText
if (start == 0 && (end - start + 1) == q->count() && !currentIndex.isValid() && if (start == 0 && (end - start + 1) == q->count() && !currentIndex.isValid() &&
placeholderText.isEmpty()) { placeholderText.isEmpty()) {
#if QT_CONFIG(accessibility)
// This might have been called by the model emitting rowInserted(), at which
// point the view won't have updated the accessibility bridge yet about its new
// dimensions. Do it now so that the change of the selection matches the row
// indexes of the accessibility bridge's representation.
if (container && container->itemView()) {
QAccessibleTableModelChangeEvent event(container->itemView(),
QAccessibleTableModelChangeEvent::ModelReset);
QAccessible::updateAccessibility(&event);
}
#endif
q->setCurrentIndex(0); q->setCurrentIndex(0);
// need to emit changed if model updated index "silently" // need to emit changed if model updated index "silently"
} else if (currentIndex.row() != indexBeforeChange) { } else if (currentIndex.row() != indexBeforeChange) {