1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include <QtTest/qtest.h>
38#include <QtQml/qqmlengine.h>
39#include <QtQml/qqmlcomponent.h>
40#include <QtQml/qqmlcontext.h>
41#include <QtQuick/private/qquickitem_p.h>
42#include <QtQuickTemplates2/private/qquickpopup_p.h>
43#include "../shared/util.h"
44
45#if QT_CONFIG(accessibility)
46#include <QtGui/private/qguiapplication_p.h>
47#include <QtGui/qpa/qplatformintegration.h>
48#include <QtGui/qpa/qplatformaccessibility.h>
49#include <QtQuick/private/qquickaccessibleattached_p.h>
50#endif
51
52class tst_accessibility : public QQmlDataTest
53{
54 Q_OBJECT
55
56private slots:
57 void a11y_data();
58 void a11y();
59
60 void override_data();
61 void override();
62
63 void ordering();
64private:
65 QQmlEngine engine;
66};
67
68#if QT_CONFIG(accessibility)
69static QPlatformAccessibility *platformAccessibility()
70{
71 QPlatformIntegration *pfIntegration = QGuiApplicationPrivate::platformIntegration();
72 return pfIntegration ? pfIntegration->accessibility() : nullptr;
73}
74#endif
75
76QString adjustFileBaseName(const QString &fileBaseName)
77{
78#if !QT_CONFIG(accessibility)
79 if (fileBaseName == QLatin1Literal("dayofweekrow")
80 || fileBaseName == QLatin1Literal("monthgrid")
81 || fileBaseName == QLatin1Literal("weeknumbercolumn"))
82 return fileBaseName += QLatin1Literal("-2");
83#else
84 return fileBaseName;
85#endif
86}
87
88QQuickItem *findItem(QObject *object)
89{
90 QQuickItem *item = qobject_cast<QQuickItem *>(object);
91 if (!item) {
92 QQuickPopup *popup = qobject_cast<QQuickPopup *>(object);
93 if (popup)
94 item = popup->popupItem();
95 }
96 return item;
97}
98
99void tst_accessibility::a11y_data()
100{
101 QTest::addColumn<QString>(name: "fileBaseName");
102 QTest::addColumn<QAccessible::Role>(name: "role");
103 QTest::addColumn<QString>(name: "text");
104
105 QTest::newRow(dataTag: "AbstractButton") << "abstractbutton" << QAccessible::Button << "AbstractButton";
106 QTest::newRow(dataTag: "BusyIndicator") << "busyindicator" << QAccessible::Indicator << "";
107 QTest::newRow(dataTag: "Button") << "button" << QAccessible::Button << "Button";
108 QTest::newRow(dataTag: "CheckBox") << "checkbox" << QAccessible::CheckBox << "CheckBox";
109 QTest::newRow(dataTag: "CheckDelegate") << "checkdelegate" << QAccessible::CheckBox << "CheckDelegate";
110 QTest::newRow(dataTag: "ComboBox") << "combobox" << QAccessible::ComboBox << "ComboBox";
111 QTest::newRow(dataTag: "Container") << "container" << QAccessible::NoRole << "";
112 QTest::newRow(dataTag: "Control") << "control" << QAccessible::NoRole << "";
113 QTest::newRow(dataTag: "Dial") << "dial" << QAccessible::Dial << "";
114 QTest::newRow(dataTag: "Dialog") << "dialog" << QAccessible::Dialog << "Dialog";
115 QTest::newRow(dataTag: "Drawer") << "drawer" << QAccessible::Dialog << "";
116 QTest::newRow(dataTag: "Frame") << "frame" << QAccessible::Border << "";
117 QTest::newRow(dataTag: "GroupBox") << "groupbox" << QAccessible::Grouping << "GroupBox";
118 QTest::newRow(dataTag: "ItemDelegate") << "itemdelegate" << QAccessible::ListItem << "ItemDelegate";
119 QTest::newRow(dataTag: "Label") << "label" << QAccessible::StaticText << "Label";
120 QTest::newRow(dataTag: "Menu") << "menu" << QAccessible::PopupMenu << "";
121 QTest::newRow(dataTag: "MenuItem") << "menuitem" << QAccessible::MenuItem << "MenuItem";
122 QTest::newRow(dataTag: "Page") << "page" << QAccessible::PageTab << "Page";
123 QTest::newRow(dataTag: "PageIndicator") << "pageindicator" << QAccessible::Indicator << "";
124 QTest::newRow(dataTag: "Pane") << "pane" << QAccessible::Pane << "";
125 QTest::newRow(dataTag: "Popup") << "popup" << QAccessible::Dialog << "";
126 QTest::newRow(dataTag: "ProgressBar") << "progressbar" << QAccessible::ProgressBar << "";
127 QTest::newRow(dataTag: "RadioButton") << "radiobutton" << QAccessible::RadioButton << "RadioButton";
128 QTest::newRow(dataTag: "RadioDelegate") << "radiodelegate" << QAccessible::RadioButton << "RadioDelegate";
129 QTest::newRow(dataTag: "RangeSlider") << "rangeslider" << QAccessible::Slider << "";
130 QTest::newRow(dataTag: "RoundButton") << "roundbutton" << QAccessible::Button << "RoundButton";
131 QTest::newRow(dataTag: "ScrollBar") << "scrollbar" << QAccessible::ScrollBar << "";
132 QTest::newRow(dataTag: "ScrollIndicator") << "scrollindicator" << QAccessible::Indicator << "";
133 QTest::newRow(dataTag: "Slider") << "slider" << QAccessible::Slider << "";
134 QTest::newRow(dataTag: "SpinBox") << "spinbox" << QAccessible::SpinBox << "";
135 QTest::newRow(dataTag: "StackView") << "stackview" << QAccessible::LayeredPane << "";
136 QTest::newRow(dataTag: "SwipeDelegate") << "swipedelegate" << QAccessible::ListItem << "SwipeDelegate";
137 QTest::newRow(dataTag: "SwipeView") << "swipeview" << QAccessible::PageTabList << "";
138 QTest::newRow(dataTag: "Switch") << "switch" << QAccessible::CheckBox << "Switch";
139 QTest::newRow(dataTag: "SwitchDelegate") << "switchdelegate" << QAccessible::ListItem << "SwitchDelegate";
140 QTest::newRow(dataTag: "TabBar") << "tabbar" << QAccessible::PageTabList << "";
141 QTest::newRow(dataTag: "TabButton") << "tabbutton" << QAccessible::PageTab << "TabButton";
142 QTest::newRow(dataTag: "TextArea") << "textarea" << QAccessible::EditableText << "";
143 QTest::newRow(dataTag: "TextField") << "textfield" << QAccessible::EditableText << "";
144 QTest::newRow(dataTag: "ToolBar") << "toolbar" << QAccessible::ToolBar << "";
145 QTest::newRow(dataTag: "ToolButton") << "toolbutton" << QAccessible::Button << "ToolButton";
146 QTest::newRow(dataTag: "ToolTip") << "tooltip" << QAccessible::ToolTip << "ToolTip";
147 QTest::newRow(dataTag: "Tumbler") << "tumbler" << QAccessible::NoRole << ""; // TODO
148
149 QTest::newRow(dataTag: "DayOfWeekRow") << "dayofweekrow" << QAccessible::NoRole << "DayOfWeekRow";
150 QTest::newRow(dataTag: "MonthGrid") << "monthgrid" << QAccessible::NoRole << "MonthGrid";
151 QTest::newRow(dataTag: "WeekNumberColumn") << "weeknumbercolumn" << QAccessible::NoRole << "WeekNumberColumn";
152}
153
154void tst_accessibility::a11y()
155{
156 QFETCH(QString, fileBaseName);
157 QFETCH(QAccessible::Role, role);
158 QFETCH(QString, text);
159
160 QQmlComponent component(&engine);
161 component.loadUrl(url: testFileUrl(fileName: "defaults/" + adjustFileBaseName(fileBaseName) + ".qml"));
162
163 QScopedPointer<QObject> object(component.create());
164 QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
165
166 QQuickItem *item = findItem(object: object.data());
167 QVERIFY(item);
168
169#if QT_CONFIG(accessibility)
170 QQuickAccessibleAttached *attached = QQuickAccessibleAttached::attachedProperties(obj: item);
171 if (fileBaseName != QLatin1String("dayofweekrow")
172 && fileBaseName != QLatin1String("monthgrid")
173 && fileBaseName != QLatin1String("weeknumbercolumn")) {
174 if (QAccessible::isActive()) {
175 QVERIFY(attached);
176 } else {
177 QVERIFY(!attached);
178 QPlatformAccessibility *accessibility = platformAccessibility();
179 if (!accessibility)
180 QSKIP("No QPlatformAccessibility available.");
181 accessibility->setActive(true);
182 attached = QQuickAccessibleAttached::attachedProperties(obj: item);
183 }
184 }
185 QVERIFY(attached);
186 QCOMPARE(attached->role(), role);
187 QCOMPARE(attached->name(), text);
188#else
189 Q_UNUSED(role)
190 Q_UNUSED(text)
191#endif
192}
193
194void tst_accessibility::override_data()
195{
196 QTest::addColumn<QAccessible::Role>(name: "role");
197
198 QTest::newRow(dataTag: "AbstractButton") << QAccessible::Button;
199 QTest::newRow(dataTag: "BusyIndicator") << QAccessible::Indicator;
200 QTest::newRow(dataTag: "Button") << QAccessible::Button;
201 QTest::newRow(dataTag: "CheckBox") << QAccessible::CheckBox;
202 QTest::newRow(dataTag: "CheckDelegate") << QAccessible::CheckBox;
203 QTest::newRow(dataTag: "ComboBox") << QAccessible::ComboBox;
204 QTest::newRow(dataTag: "Container") << QAccessible::NoRole;
205 QTest::newRow(dataTag: "Control") << QAccessible::NoRole;
206 QTest::newRow(dataTag: "Dial") << QAccessible::Dial;
207 QTest::newRow(dataTag: "Dialog") << QAccessible::Dialog;
208 QTest::newRow(dataTag: "Drawer") << QAccessible::Dialog;
209 QTest::newRow(dataTag: "Frame") << QAccessible::Border;
210 QTest::newRow(dataTag: "GroupBox") << QAccessible::Grouping;
211 QTest::newRow(dataTag: "ItemDelegate") << QAccessible::ListItem;
212 QTest::newRow(dataTag: "Label") << QAccessible::StaticText;
213 QTest::newRow(dataTag: "Menu") << QAccessible::PopupMenu;
214 QTest::newRow(dataTag: "MenuItem") << QAccessible::MenuItem;
215 QTest::newRow(dataTag: "Page") << QAccessible::PageTab;
216 QTest::newRow(dataTag: "PageIndicator") << QAccessible::Indicator;
217 QTest::newRow(dataTag: "Pane") << QAccessible::Pane;
218 QTest::newRow(dataTag: "Popup") << QAccessible::Dialog;
219 QTest::newRow(dataTag: "ProgressBar") << QAccessible::ProgressBar;
220 QTest::newRow(dataTag: "RadioButton") << QAccessible::RadioButton;
221 QTest::newRow(dataTag: "RadioDelegate") << QAccessible::RadioButton;
222 QTest::newRow(dataTag: "RangeSlider") << QAccessible::Slider;
223 QTest::newRow(dataTag: "RoundButton") << QAccessible::Button;
224 QTest::newRow(dataTag: "ScrollBar") << QAccessible::ScrollBar;
225 QTest::newRow(dataTag: "ScrollIndicator") << QAccessible::Indicator;
226 QTest::newRow(dataTag: "Slider") << QAccessible::Slider;
227 QTest::newRow(dataTag: "SpinBox") << QAccessible::SpinBox;
228 QTest::newRow(dataTag: "StackView") << QAccessible::LayeredPane;
229 QTest::newRow(dataTag: "SwipeDelegate") << QAccessible::ListItem;
230 QTest::newRow(dataTag: "SwipeView") << QAccessible::PageTabList;
231 QTest::newRow(dataTag: "Switch") << QAccessible::CheckBox;
232 QTest::newRow(dataTag: "SwitchDelegate") << QAccessible::ListItem;
233 QTest::newRow(dataTag: "TabBar") << QAccessible::PageTabList;
234 QTest::newRow(dataTag: "TabButton") << QAccessible::PageTab;
235 QTest::newRow(dataTag: "TextArea") << QAccessible::EditableText;
236 QTest::newRow(dataTag: "TextField") << QAccessible::EditableText;
237 QTest::newRow(dataTag: "ToolBar") << QAccessible::ToolBar;
238 QTest::newRow(dataTag: "ToolButton") << QAccessible::Button;
239 QTest::newRow(dataTag: "ToolTip") << QAccessible::ToolTip;
240 QTest::newRow(dataTag: "Tumbler") << QAccessible::NoRole;
241
242 QTest::newRow(dataTag: "DayOfWeekRow") << QAccessible::NoRole;
243 QTest::newRow(dataTag: "MonthGrid") << QAccessible::NoRole;
244 QTest::newRow(dataTag: "WeekNumberColumn") << QAccessible::NoRole;
245}
246
247void tst_accessibility::override()
248{
249 QFETCH(QAccessible::Role, role);
250
251 const QString name = QTest::currentDataTag();
252 const QString fileBaseName = name.toLower();
253
254 QQmlComponent component(&engine);
255 component.loadUrl(url: testFileUrl(fileName: "override/" + adjustFileBaseName(fileBaseName) + ".qml"));
256
257 QScopedPointer<QObject> object(component.create());
258 QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
259
260 QQuickItem *item = findItem(object: object.data());
261 QVERIFY(item);
262
263#if QT_CONFIG(accessibility)
264 QQuickAccessibleAttached *attached = QQuickAccessibleAttached::attachedProperties(obj: item);
265 if (fileBaseName != QLatin1String("dayofweekrow")
266 && fileBaseName != QLatin1String("monthgrid")
267 && fileBaseName != QLatin1String("weeknumbercolumn")) {
268 if (QAccessible::isActive()) {
269 QVERIFY(attached);
270 } else {
271 QPlatformAccessibility *accessibility = platformAccessibility();
272 if (!accessibility)
273 QSKIP("No QPlatformAccessibility available.");
274 accessibility->setActive(true);
275 if (!attached)
276 attached = QQuickAccessibleAttached::attachedProperties(obj: item);
277 }
278 }
279
280 QVERIFY(attached);
281 QCOMPARE(attached->role(), role);
282 QCOMPARE(attached->name(), name + "Override");
283#else
284 Q_UNUSED(role)
285 Q_UNUSED(text)
286#endif
287}
288template <typename Predicate>
289void a11yDescendants(QAccessibleInterface *iface, Predicate pred)
290{
291 for (int i = 0; i < iface->childCount(); ++i) {
292 if (QAccessibleInterface *child = iface->child(index: i)) {
293 pred(child);
294 a11yDescendants(child, pred);
295 }
296 }
297}
298
299void tst_accessibility::ordering()
300{
301 QQmlComponent component(&engine);
302 component.loadUrl(url: testFileUrl(fileName: "ordering/page.qml"));
303
304 QScopedPointer<QObject> object(component.create());
305 QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
306
307#if QT_CONFIG(accessibility)
308 QQuickItem *item = findItem(object: object.data());
309 QVERIFY(item);
310 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(item);
311 QVERIFY(iface);
312 QStringList strings;
313 a11yDescendants(iface, pred: [&](QAccessibleInterface *iface) {strings << iface->text(t: QAccessible::Name);});
314 QCOMPARE(strings.join(QLatin1String(", ")), "Header, Content item 1, Content item 2, Footer");
315#endif
316}
317
318QTEST_MAIN(tst_accessibility)
319
320#include "tst_accessibility.moc"
321

source code of qtquickcontrols2/tests/auto/accessibility/tst_accessibility.cpp