diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp index 4a446e468d..6f8df29538 100644 --- a/src/quick/accessible/qaccessiblequickitem.cpp +++ b/src/quick/accessible/qaccessiblequickitem.cpp @@ -456,7 +456,7 @@ QAccessible::Role QAccessibleQuickItem::role() const QAccessible::Role role = QAccessible::NoRole; if (item()) - role = QQuickItemPrivate::get(item())->accessibleRole(); + role = QQuickItemPrivate::get(item())->effectiveAccessibleRole(); if (role == QAccessible::NoRole) { if (qobject_cast(const_cast(item()))) role = QAccessible::StaticText; diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index d53a190b5f..2e645a918d 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2376,7 +2376,7 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item) return true; #if QT_CONFIG(accessibility) - QAccessible::Role role = QQuickItemPrivate::get(item)->accessibleRole(); + QAccessible::Role role = QQuickItemPrivate::get(item)->effectiveAccessibleRole(); if (role == QAccessible::EditableText || role == QAccessible::Table || role == QAccessible::List) { return true; } else if (role == QAccessible::ComboBox || role == QAccessible::SpinBox) { @@ -9731,13 +9731,20 @@ QQuickItemPrivate::ExtraData::ExtraData() #if QT_CONFIG(accessibility) -QAccessible::Role QQuickItemPrivate::accessibleRole() const +QAccessible::Role QQuickItemPrivate::effectiveAccessibleRole() const { Q_Q(const QQuickItem); - QQuickAccessibleAttached *accessibleAttached = qobject_cast(qmlAttachedPropertiesObject(q, false)); - if (accessibleAttached) - return accessibleAttached->role(); + auto *attached = qmlAttachedPropertiesObject(q, false); + auto role = QAccessible::NoRole; + if (auto *accessibleAttached = qobject_cast(attached)) + role = accessibleAttached->role(); + if (role == QAccessible::NoRole) + role = accessibleRole(); + return role; +} +QAccessible::Role QQuickItemPrivate::accessibleRole() const +{ return QAccessible::NoRole; } #endif diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index e1e909d1a2..df6ec900ce 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -601,7 +601,10 @@ public: virtual void implicitHeightChanged(); #if QT_CONFIG(accessibility) + QAccessible::Role effectiveAccessibleRole() const; +private: virtual QAccessible::Role accessibleRole() const; +public: #endif void setImplicitAntialiasing(bool antialiasing); diff --git a/src/quicktemplates/qquickcontrol.cpp b/src/quicktemplates/qquickcontrol.cpp index ace34c9d63..7af4b29523 100644 --- a/src/quicktemplates/qquickcontrol.cpp +++ b/src/quicktemplates/qquickcontrol.cpp @@ -2185,12 +2185,13 @@ QAccessible::Role QQuickControl::accessibleRole() const void QQuickControl::accessibilityActiveChanged(bool active) { + Q_D(QQuickControl); if (!active) return; QQuickAccessibleAttached *accessibleAttached = qobject_cast(qmlAttachedPropertiesObject(this, true)); Q_ASSERT(accessibleAttached); - accessibleAttached->setRole(accessibleRole()); + accessibleAttached->setRole(d->effectiveAccessibleRole()); } #endif diff --git a/src/quicktemplates/qquicklabel.cpp b/src/quicktemplates/qquicklabel.cpp index 39ad6b88c3..ee8723d755 100644 --- a/src/quicktemplates/qquicklabel.cpp +++ b/src/quicktemplates/qquicklabel.cpp @@ -190,7 +190,7 @@ void QQuickLabelPrivate::accessibilityActiveChanged(bool active) Q_Q(QQuickLabel); QQuickAccessibleAttached *accessibleAttached = qobject_cast(qmlAttachedPropertiesObject(q, true)); Q_ASSERT(accessibleAttached); - accessibleAttached->setRole(accessibleRole()); + accessibleAttached->setRole(effectiveAccessibleRole()); maybeSetAccessibleName(text); } diff --git a/src/quicktemplates/qquickpopup.cpp b/src/quicktemplates/qquickpopup.cpp index 5b26789951..63999c23a5 100644 --- a/src/quicktemplates/qquickpopup.cpp +++ b/src/quicktemplates/qquickpopup.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -2769,6 +2770,19 @@ QFont QQuickPopup::defaultFont() const } #if QT_CONFIG(accessibility) +QAccessible::Role QQuickPopup::effectiveAccessibleRole() const +{ + auto *attached = qmlAttachedPropertiesObject(this, false); + + auto role = QAccessible::NoRole; + if (auto *accessibleAttached = qobject_cast(attached)) + role = accessibleAttached->role(); + if (role == QAccessible::NoRole) + role = accessibleRole(); + + return role; +} + QAccessible::Role QQuickPopup::accessibleRole() const { return QAccessible::Dialog; diff --git a/src/quicktemplates/qquickpopup_p.h b/src/quicktemplates/qquickpopup_p.h index ee9003d627..7552b549bd 100644 --- a/src/quicktemplates/qquickpopup_p.h +++ b/src/quicktemplates/qquickpopup_p.h @@ -419,7 +419,10 @@ protected: virtual QFont defaultFont() const; #if QT_CONFIG(accessibility) + QAccessible::Role effectiveAccessibleRole() const; +private: virtual QAccessible::Role accessibleRole() const; +protected: virtual void accessibilityActiveChanged(bool active); #endif diff --git a/src/quicktemplates/qquickpopupitem.cpp b/src/quicktemplates/qquickpopupitem.cpp index 43fc1bdc50..6a494626d4 100644 --- a/src/quicktemplates/qquickpopupitem.cpp +++ b/src/quicktemplates/qquickpopupitem.cpp @@ -308,7 +308,7 @@ QFont QQuickPopupItem::defaultFont() const QAccessible::Role QQuickPopupItem::accessibleRole() const { Q_D(const QQuickPopupItem); - return d->popup->accessibleRole(); + return d->popup->effectiveAccessibleRole(); } void QQuickPopupItem::accessibilityActiveChanged(bool active) diff --git a/src/quicktemplates/qquicktextarea.cpp b/src/quicktemplates/qquicktextarea.cpp index f16b88c07f..dd4a908f5a 100644 --- a/src/quicktemplates/qquicktextarea.cpp +++ b/src/quicktemplates/qquicktextarea.cpp @@ -438,7 +438,7 @@ void QQuickTextAreaPrivate::accessibilityActiveChanged(bool active) Q_Q(QQuickTextArea); QQuickAccessibleAttached *accessibleAttached = qobject_cast(qmlAttachedPropertiesObject(q, true)); Q_ASSERT(accessibleAttached); - accessibleAttached->setRole(accessibleRole()); + accessibleAttached->setRole(effectiveAccessibleRole()); accessibleAttached->set_readOnly(q->isReadOnly()); accessibleAttached->setDescription(placeholder); } diff --git a/src/quicktemplates/qquicktextfield.cpp b/src/quicktemplates/qquicktextfield.cpp index 15a6276465..b7c2e03265 100644 --- a/src/quicktemplates/qquicktextfield.cpp +++ b/src/quicktemplates/qquicktextfield.cpp @@ -288,7 +288,7 @@ void QQuickTextFieldPrivate::accessibilityActiveChanged(bool active) Q_Q(QQuickTextField); QQuickAccessibleAttached *accessibleAttached = qobject_cast(qmlAttachedPropertiesObject(q, true)); Q_ASSERT(accessibleAttached); - accessibleAttached->setRole(accessibleRole()); + accessibleAttached->setRole(effectiveAccessibleRole()); accessibleAttached->set_readOnly(m_readOnly); accessibleAttached->set_passwordEdit((m_echoMode == QQuickTextField::Password || m_echoMode == QQuickTextField::PasswordEchoOnEdit) ? true : false); accessibleAttached->setDescription(placeholder); diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp index e7da38a5ce..f51e7e8710 100644 --- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp +++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp @@ -56,6 +56,7 @@ private slots: void commonTests(); void quickAttachedProperties(); + void attachedWins(); void basicPropertiesTest(); void hitTest(); void checkableTest(); @@ -322,6 +323,31 @@ void tst_QQuickAccessible::quickAttachedProperties() QTestAccessibility::clearEvents(); } +// Verify that a role can be explicitly set, and that the values from the +// attached object are used even if the item has a default role - QTBUG-110114 +void tst_QQuickAccessible::attachedWins() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData(R"( + import QtQuick + import QtQuick.Controls + Button { + text: "Button" + objectName: "button" + Accessible.role: Accessible.RadioButton + Accessible.description: "Radio Button" + })", QUrl()); + auto button = std::unique_ptr(component.create()); + QVERIFY(button); + + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(button.get()); + QVERIFY(iface); + + QCOMPARE(iface->role(), QAccessible::RadioButton); + QTestAccessibility::clearEvents(); +} + void tst_QQuickAccessible::basicPropertiesTest() {