Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qaccessiblebridgeutils.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4#include <QtCore/qmath.h>
5#include <QtGui/qwindow.h>
6
8
10
11static bool performAction(QAccessibleInterface *iface, const QString &actionName)
12{
13 if (QAccessibleActionInterface *actionIface = iface->actionInterface()) {
14 if (actionIface->actionNames().contains(actionName)) {
15 actionIface->doAction(actionName);
16 return true;
17 }
18 }
19 return false;
20}
21
22QStringList effectiveActionNames(QAccessibleInterface *iface)
23{
24 QStringList actions;
25 if (QAccessibleActionInterface *actionIface = iface->actionInterface())
26 actions = actionIface->actionNames();
27
28 if (iface->valueInterface()) {
29 if (!actions.contains(QAccessibleActionInterface::increaseAction()))
30 actions << QAccessibleActionInterface::increaseAction();
31 if (!actions.contains(QAccessibleActionInterface::decreaseAction()))
32 actions << QAccessibleActionInterface::decreaseAction();
33 }
34 return actions;
35}
36
37bool performEffectiveAction(QAccessibleInterface *iface, const QString &actionName)
38{
39 if (!iface)
40 return false;
41 if (performAction(iface, actionName))
42 return true;
43 if (actionName != QAccessibleActionInterface::increaseAction()
44 && actionName != QAccessibleActionInterface::decreaseAction())
45 return false;
46
47 QAccessibleValueInterface *valueIface = iface->valueInterface();
48 if (!valueIface)
49 return false;
50 bool success;
51 const QVariant currentVariant = valueIface->currentValue();
52 double stepSize = valueIface->minimumStepSize().toDouble(&success);
53 if (!success || qFuzzyIsNull(stepSize)) {
54 const double min = valueIface->minimumValue().toDouble(&success);
55 if (!success)
56 return false;
57 const double max = valueIface->maximumValue().toDouble(&success);
58 if (!success)
59 return false;
60 stepSize = (max - min) / 10; // this is pretty arbitrary, we just need to provide something
61 const int typ = currentVariant.userType();
62 if (typ != QMetaType::Float && typ != QMetaType::Double) {
63 // currentValue is an integer. Round it up to ensure stepping in case it was below 1
64 stepSize = qCeil(stepSize);
65 }
66 }
67 const double current = currentVariant.toDouble(&success);
68 if (!success)
69 return false;
70 if (actionName == QAccessibleActionInterface::decreaseAction())
71 stepSize = -stepSize;
72 valueIface->setCurrentValue(current + stepSize);
73 return true;
74}
75
76QString accessibleId(QAccessibleInterface *accessible) {
77 QString result;
78 if (!accessible)
79 return result;
80 result = accessible->text(QAccessible::Identifier);
81 if (!result.isEmpty())
82 return result;
83 while (accessible) {
84 if (!result.isEmpty())
85 result.prepend(u'.');
86 if (auto obj = accessible->object()) {
87 const QString name = obj->objectName();
88 if (!name.isEmpty())
89 result.prepend(name);
90 else
91 result.prepend(QString::fromUtf8(obj->metaObject()->className()));
92 }
93 accessible = accessible->parent();
94 }
95 return result;
96}
97
98/*
99 Returns the window whose native handle is responsible for \a iface.
100
101 Not every interface implements window(), so we walk up the ancestors until
102 one does, as the documentation asks of the backend. The first ancestor to
103 answer gives the closest window, since a window's root interface sits on this
104 chain and reports its own window.
105
106 A caller that already knows the window of an ancestor passes the ancestor as
107 \a ancestorInterface and its window as \a ancestorWindow. The walk then stops
108 at that ancestor and answers with \a ancestorWindow. The full walk ends up at
109 the same window, so the two arguments only skip the part the caller has
110 already walked.
111
112 The two arguments also let us reject an answer that can not be true. An
113 interface below \a ancestorInterface can not live in a window that contains
114 \a ancestorWindow. A bridge that substituted the native view of such a window
115 would hand back a view that contains \a ancestorWindow's own view, and the
116 native accessibility tree would loop. An interface that answers window() with
117 the top level instead of the window containing it gives such an answer, so we
118 discard it and keep walking.
119
120 We do however accept a window that is not a descendant of \a ancestorWindow. A
121 QWindowContainer inside a child QWindow hands its contained window to the top
122 level, and the two windows are then siblings. Move the container further down
123 the QWindow hierarchy and \a ancestorWindow becomes a descendant of a sibling
124 of the window we return.
125
126 Callers that have specific demands on the accepted window hierarchy beyond
127 the loop detection must handle those cases at the call site.
128*/
129QWindow *windowFor(const QAccessibleInterface *iface,
130 const QAccessibleInterface *ancestorInterface,
131 QWindow *ancestorWindow)
132{
133 Q_ASSERT(bool(ancestorInterface) == bool(ancestorWindow));
134
135 for (const auto *candidate = iface; candidate && candidate != ancestorInterface;
136 candidate = candidate->parent()) {
137 QWindow *window = candidate->window();
138 if (!window)
139 continue;
140
141 // We found a window before reaching ancestorInterface. It can only
142 // represent the interface if it does not contain ancestorWindow,
143 // as otherwise the native accessibility tree would loop.
144 if (ancestorWindow && window->isAncestorOf(ancestorWindow, QWindow::ExcludeTransients))
145 continue;
146
147 return window;
148 }
149
150 return ancestorWindow;
151}
152
153} //namespace
154
155QT_END_NAMESPACE
bool performEffectiveAction(QAccessibleInterface *iface, const QString &actionName)
QStringList effectiveActionNames(QAccessibleInterface *iface)
QString accessibleId(QAccessibleInterface *accessible)
QWindow * windowFor(const QAccessibleInterface *iface, const QAccessibleInterface *ancestorInterface, QWindow *ancestorWindow)
static bool performAction(QAccessibleInterface *iface, const QString &actionName)
Combined button and popup list for selecting options.