Windows QPA: Implement Selection UIA pattern for QTabBar

Adding Selection pattern for tab bars and SelectionItem pattern for
tab items, which are required for accessibility compliance.

Fixes: QTBUG-104740
Change-Id: I0e3b1cfbf4838d8bc8b5bc2e2d7c9d372ac8b99d
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
(cherry picked from commit 083ff27518a735e39563d1bae9c40ffbc7c1d527)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
André de la Rocha 2022-07-06 03:22:53 +02:00 committed by Qt Cherry-pick Bot
parent 4ef77e81b3
commit c9c3f57883
3 changed files with 37 additions and 23 deletions

View File

@ -295,14 +295,16 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow
break; break;
case UIA_SelectionPatternId: case UIA_SelectionPatternId:
// Lists of items. // Lists of items.
if (accessible->role() == QAccessible::List) { if (accessible->role() == QAccessible::List
|| accessible->role() == QAccessible::PageTabList) {
*pRetVal = new QWindowsUiaSelectionProvider(id()); *pRetVal = new QWindowsUiaSelectionProvider(id());
} }
break; break;
case UIA_SelectionItemPatternId: case UIA_SelectionItemPatternId:
// Items within a list and radio buttons. // Items within a list and radio buttons.
if ((accessible->role() == QAccessible::RadioButton) if ((accessible->role() == QAccessible::RadioButton)
|| (accessible->role() == QAccessible::ListItem)) { || (accessible->role() == QAccessible::ListItem)
|| (accessible->role() == QAccessible::PageTab)) {
*pRetVal = new QWindowsUiaSelectionItemProvider(id()); *pRetVal = new QWindowsUiaSelectionItemProvider(id());
} }
break; break;

View File

@ -40,8 +40,8 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::Select()
if (!actionInterface) if (!actionInterface)
return UIA_E_ELEMENTNOTAVAILABLE; return UIA_E_ELEMENTNOTAVAILABLE;
if (accessible->role() == QAccessible::RadioButton) { if (accessible->role() == QAccessible::RadioButton || accessible->role() == QAccessible::PageTab) {
// For radio buttons we just invoke the selection action; others are automatically deselected. // For radio buttons/tabs we just invoke the selection action; others are automatically deselected.
actionInterface->doAction(QAccessibleActionInterface::pressAction()); actionInterface->doAction(QAccessibleActionInterface::pressAction());
} else { } else {
// Toggle list item if not already selected. It must be done first to support all selection modes. // Toggle list item if not already selected. It must be done first to support all selection modes.
@ -77,8 +77,8 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::AddToSelection()
if (!actionInterface) if (!actionInterface)
return UIA_E_ELEMENTNOTAVAILABLE; return UIA_E_ELEMENTNOTAVAILABLE;
if (accessible->role() == QAccessible::RadioButton) { if (accessible->role() == QAccessible::RadioButton || accessible->role() == QAccessible::PageTab) {
// For radio buttons we invoke the selection action. // For radio buttons and tabs we invoke the selection action.
actionInterface->doAction(QAccessibleActionInterface::pressAction()); actionInterface->doAction(QAccessibleActionInterface::pressAction());
} else { } else {
// Toggle list item if not already selected. // Toggle list item if not already selected.
@ -102,7 +102,7 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::RemoveFromSelection(
if (!actionInterface) if (!actionInterface)
return UIA_E_ELEMENTNOTAVAILABLE; return UIA_E_ELEMENTNOTAVAILABLE;
if (accessible->role() != QAccessible::RadioButton) { if (accessible->role() != QAccessible::RadioButton && accessible->role() != QAccessible::PageTab) {
if (accessible->state().selected) { if (accessible->state().selected) {
actionInterface->doAction(QAccessibleActionInterface::toggleAction()); actionInterface->doAction(QAccessibleActionInterface::toggleAction());
} }
@ -126,6 +126,8 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::get_IsSelected(BOOL
if (accessible->role() == QAccessible::RadioButton) if (accessible->role() == QAccessible::RadioButton)
*pRetVal = accessible->state().checked; *pRetVal = accessible->state().checked;
else if (accessible->role() == QAccessible::PageTab)
*pRetVal = accessible->state().focused;
else else
*pRetVal = accessible->state().selected; *pRetVal = accessible->state().selected;
return S_OK; return S_OK;
@ -149,13 +151,12 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::get_SelectionContain
return UIA_E_ELEMENTNOTAVAILABLE; return UIA_E_ELEMENTNOTAVAILABLE;
// Radio buttons do not require a container. // Radio buttons do not require a container.
if (accessible->role() == QAccessible::ListItem) {
if (QAccessibleInterface *parent = accessible->parent()) { if (QAccessibleInterface *parent = accessible->parent()) {
if (parent->role() == QAccessible::List) { if ((accessible->role() == QAccessible::ListItem && parent->role() == QAccessible::List)
|| (accessible->role() == QAccessible::PageTab && parent->role() == QAccessible::PageTabList)) {
*pRetVal = QWindowsUiaMainProvider::providerForAccessible(parent); *pRetVal = QWindowsUiaMainProvider::providerForAccessible(parent);
} }
} }
}
return S_OK; return S_OK;
} }

View File

@ -45,11 +45,17 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::GetSelection(SAFEARRAY *
QList<QAccessibleInterface *> selectedList; QList<QAccessibleInterface *> selectedList;
for (int i = 0; i < accessible->childCount(); ++i) { for (int i = 0; i < accessible->childCount(); ++i) {
if (QAccessibleInterface *child = accessible->child(i)) { if (QAccessibleInterface *child = accessible->child(i)) {
if (accessible->role() == QAccessible::PageTabList) {
if (child->role() == QAccessible::PageTab && child->state().focused) {
selectedList.append(child);
}
} else {
if (child->state().selected) { if (child->state().selected) {
selectedList.append(child); selectedList.append(child);
} }
} }
} }
}
if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, selectedList.size()))) { if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, selectedList.size()))) {
for (LONG i = 0; i < selectedList.size(); ++i) { for (LONG i = 0; i < selectedList.size(); ++i) {
@ -90,6 +96,10 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_IsSelectionRequired(
if (!accessible) if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE; return UIA_E_ELEMENTNOTAVAILABLE;
if (accessible->role() == QAccessible::PageTabList) {
*pRetVal = TRUE;
} else {
// Initially returns false if none are selected. After the first selection, it may be required. // Initially returns false if none are selected. After the first selection, it may be required.
bool anySelected = false; bool anySelected = false;
for (int i = 0; i < accessible->childCount(); ++i) { for (int i = 0; i < accessible->childCount(); ++i) {
@ -102,6 +112,7 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_IsSelectionRequired(
} }
*pRetVal = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable; *pRetVal = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable;
}
return S_OK; return S_OK;
} }