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;
case UIA_SelectionPatternId:
// Lists of items.
if (accessible->role() == QAccessible::List) {
if (accessible->role() == QAccessible::List
|| accessible->role() == QAccessible::PageTabList) {
*pRetVal = new QWindowsUiaSelectionProvider(id());
}
break;
case UIA_SelectionItemPatternId:
// Items within a list and radio buttons.
if ((accessible->role() == QAccessible::RadioButton)
|| (accessible->role() == QAccessible::ListItem)) {
|| (accessible->role() == QAccessible::ListItem)
|| (accessible->role() == QAccessible::PageTab)) {
*pRetVal = new QWindowsUiaSelectionItemProvider(id());
}
break;

View File

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

View File

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