1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
43 #include <QtTest/QtTest>
44 #include "QtTest/qtestaccessible.h"
46 #include <QtGui/qaccessible.h>
48 #include <QtQuick1/qdeclarativeview.h>
49 #include <QtQuick/qquickview.h>
50 #include <QtQuick/qquickitem.h>
52 #include <QtDeclarative/qdeclarativeengine.h>
53 #include <QtDeclarative/qdeclarativeproperty.h>
54 #include <private/qdeclarativeaccessibleattached_p.h>
56 #include "../../shared/util.h"
59 typedef QSharedPointer<QAccessibleInterface> QAI;
62 static inline bool verifyChild(QWidget *child, QAccessibleInterface *iface,
63 int index, const QRect &domain)
66 qWarning("tst_QAccessibility::verifyChild: null pointer to child.");
71 qWarning("tst_QAccessibility::verifyChild: null pointer to interface.");
75 // Verify that we get a valid QAccessibleInterface for the child.
76 QAccessibleInterface *childInterface = QAccessible::queryAccessibleInterface(child);
77 if (!childInterface) {
78 qWarning("tst_QAccessibility::verifyChild: Failed to retrieve interface for child.");
82 // QAccessibleInterface::indexOfChild():
83 // Verify that indexOfChild() returns an index equal to the index passed in
84 int indexFromIndexOfChild = iface->indexOfChild(childInterface);
85 delete childInterface;
86 if (indexFromIndexOfChild != index) {
87 qWarning("tst_QAccessibility::verifyChild (indexOfChild()):");
88 qWarning() << "Expected:" << index;
89 qWarning() << "Actual: " << indexFromIndexOfChild;
93 // Navigate to child, compare its object and role with the interface from queryAccessibleInterface(child).
94 QAccessibleInterface *navigatedChildInterface = iface->child(index - 1);
95 if (navigatedChildInterface == 0)
98 const QRect rectFromInterface = navigatedChildInterface->rect();
99 delete navigatedChildInterface;
101 // QAccessibleInterface::childAt():
102 // Calculate global child position and check that the interface
103 // returns the correct index for that position.
104 QPoint globalChildPos = child->mapToGlobal(QPoint(0, 0));
105 QAccessibleInterface *childAtInterface = iface->childAt(globalChildPos.x(), globalChildPos.y());
106 if (!childAtInterface) {
107 qWarning("tst_QAccessibility::verifyChild (childAt()):");
108 qWarning() << "Expected:" << childInterface;
109 qWarning() << "Actual: no child";
112 if (childAtInterface->object() != childInterface->object()) {
113 qWarning("tst_QAccessibility::verifyChild (childAt()):");
114 qWarning() << "Expected:" << childInterface;
115 qWarning() << "Actual: " << childAtInterface;
118 delete childInterface;
119 delete childAtInterface;
121 // Verify that the child is within its domain.
122 if (!domain.contains(rectFromInterface)) {
123 qWarning("tst_QAccessibility::verifyChild: Child is not within its domain.");
130 static inline int indexOfChild(QAccessibleInterface *parentInterface, QWidget *childWidget)
132 if (!parentInterface || !childWidget)
134 QAccessibleInterface *childInterface = QAccessible::queryAccessibleInterface(childWidget);
137 int index = parentInterface->indexOfChild(childInterface);
138 delete childInterface;
142 #define EXPECT(cond) \
144 if (!errorAt && !(cond)) { \
145 errorAt = __LINE__; \
146 qWarning("level: %d, middle: %d, role: %d (%s)", treelevel, middle, iface->role(), #cond); \
150 static int verifyHierarchy(QAccessibleInterface *iface)
153 static int treelevel = 0; // for error diagnostics
154 QAccessibleInterface *middleChild, *if2;
157 int middle = iface->childCount()/2 + 1;
158 if (iface->childCount() >= 2) {
159 middleChild = iface->child(middle - 1);
161 for (int i = 0; i < iface->childCount() && !errorAt; ++i) {
162 if2 = iface->child(i);
164 // navigate Ancestor...
165 QAccessibleInterface *parent = if2->parent();
166 EXPECT(iface->object() == parent->object());
169 // navigate Sibling...
170 // if (middleChild) {
171 // entry = if2->navigate(QAccessible::Sibling, middle, &if3);
172 // EXPECT(entry == 0 && if3->object() == middleChild->object());
175 // EXPECT(iface->indexOfChild(middleChild) == middle);
178 // verify children...
180 errorAt = verifyHierarchy(if2);
192 class tst_QDeclarativeAccessibility : public QDeclarativeDataTest
196 tst_QDeclarativeAccessibility();
197 virtual ~tst_QDeclarativeAccessibility();
200 void commonTests_data();
203 void declarativeAttachedProperties();
204 void basicPropertiesTest();
208 tst_QDeclarativeAccessibility::tst_QDeclarativeAccessibility()
213 tst_QDeclarativeAccessibility::~tst_QDeclarativeAccessibility()
218 void tst_QDeclarativeAccessibility::commonTests_data()
220 QTest::addColumn<QString>("accessibleRoleFileName");
222 QTest::newRow("StaticText") << SRCDIR "/data/statictext.qml";
223 QTest::newRow("PushButton") << SRCDIR "/data/pushbutton.qml";
226 void tst_QDeclarativeAccessibility::commonTests()
228 QFETCH(QString, accessibleRoleFileName);
230 qDebug() << "testing" << accessibleRoleFileName;
232 QQuickView *view = new QQuickView();
233 // view->setFixedSize(240,320);
234 view->setSource(QUrl::fromLocalFile(accessibleRoleFileName));
237 QVERIFY(view->rootObject() != 0);
239 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(view);
248 QString eventName(const int ev)
251 case 0x0001: return "SoundPlayed";
252 case 0x0002: return "Alert";
253 case 0x0003: return "ForegroundChanged";
254 case 0x0004: return "MenuStart";
255 case 0x0005: return "MenuEnd";
256 case 0x0006: return "PopupMenuStart";
257 case 0x0007: return "PopupMenuEnd";
258 case 0x000C: return "ContextHelpStart";
259 case 0x000D: return "ContextHelpEnd";
260 case 0x000E: return "DragDropStart";
261 case 0x000F: return "DragDropEnd";
262 case 0x0010: return "DialogStart";
263 case 0x0011: return "DialogEnd";
264 case 0x0012: return "ScrollingStart";
265 case 0x0013: return "ScrollingEnd";
266 case 0x0018: return "MenuCommand";
267 case 0x8000: return "ObjectCreated";
268 case 0x8001: return "ObjectDestroyed";
269 case 0x8002: return "ObjectShow";
270 case 0x8003: return "ObjectHide";
271 case 0x8004: return "ObjectReorder";
272 case 0x8005: return "Focus";
273 case 0x8006: return "Selection";
274 case 0x8007: return "SelectionAdd";
275 case 0x8008: return "SelectionRemove";
276 case 0x8009: return "SelectionWithin";
277 case 0x800A: return "StateChanged";
278 case 0x800B: return "LocationChanged";
279 case 0x800C: return "NameChanged";
280 case 0x800D: return "DescriptionChanged";
281 case 0x800E: return "ValueChanged";
282 case 0x800F: return "ParentChanged";
283 case 0x80A0: return "HelpChanged";
284 case 0x80B0: return "DefaultActionChanged";
285 case 0x80C0: return "AcceleratorChanged";
286 default: return "Unknown Event";
290 static QString stateNames(int state)
293 if (state == 0x00000000) stateString += " Normal";
294 if (state & 0x00000001) stateString += " Unavailable";
295 if (state & 0x00000002) stateString += " Selected";
296 if (state & 0x00000004) stateString += " Focused";
297 if (state & 0x00000008) stateString += " Pressed";
298 if (state & 0x00000010) stateString += " Checked";
299 if (state & 0x00000020) stateString += " Mixed";
300 if (state & 0x00000040) stateString += " ReadOnly";
301 if (state & 0x00000080) stateString += " HotTracked";
302 if (state & 0x00000100) stateString += " DefaultButton";
303 if (state & 0x00000200) stateString += " Expanded";
304 if (state & 0x00000400) stateString += " Collapsed";
305 if (state & 0x00000800) stateString += " Busy";
306 if (state & 0x00001000) stateString += " Floating";
307 if (state & 0x00002000) stateString += " Marqueed";
308 if (state & 0x00004000) stateString += " Animated";
309 if (state & 0x00008000) stateString += " Invisible";
310 if (state & 0x00010000) stateString += " Offscreen";
311 if (state & 0x00020000) stateString += " Sizeable";
312 if (state & 0x00040000) stateString += " Moveable";
313 if (state & 0x00080000) stateString += " SelfVoicing";
314 if (state & 0x00100000) stateString += " Focusable";
315 if (state & 0x00200000) stateString += " Selectable";
316 if (state & 0x00400000) stateString += " Linked";
317 if (state & 0x00800000) stateString += " Traversed";
318 if (state & 0x01000000) stateString += " MultiSelectable";
319 if (state & 0x02000000) stateString += " ExtSelectable";
320 if (state & 0x04000000) stateString += " AlertLow";
321 if (state & 0x08000000) stateString += " AlertMedium";
322 if (state & 0x10000000) stateString += " AlertHigh";
323 if (state & 0x20000000) stateString += " Protected";
324 if (state & 0x3fffffff) stateString += " Valid";
326 if (stateString.isEmpty())
327 stateString = "Unknown state " + QString::number(state);
332 void tst_QDeclarativeAccessibility::declarativeAttachedProperties()
335 QDeclarativeEngine engine;
336 QDeclarativeComponent component(&engine);
337 component.setData("import QtQuick 1.1\nItem {\n"
339 QObject *object = component.create();
340 QVERIFY(object != 0);
342 QObject *attachedObject = QDeclarativeAccessibleAttached::attachedProperties(object);
343 QCOMPARE(attachedObject, static_cast<QObject*>(0));
350 QDeclarativeAccessibleAttached *attachedObj = new QDeclarativeAccessibleAttached(&parent);
354 QVariant pp = attachedObj->property("name");
355 QDeclarativeEngine engine;
356 QDeclarativeComponent component(&engine);
357 component.setData("import QtQuick 1.1\nItem {\n"
358 "Accessible.role: Accessible.Button\n"
360 QObject *object = component.create();
361 QVERIFY(object != 0);
363 QObject *attachedObject = QDeclarativeAccessibleAttached::attachedProperties(object);
364 QVERIFY(attachedObject);
365 if (attachedObject) {
366 QVariant p = attachedObject->property("role");
367 QCOMPARE(p.isNull(), false);
368 QCOMPARE(p.toInt(), int(QAccessible::PushButton));
369 p = attachedObject->property("name");
370 QCOMPARE(p.isNull(), true);
371 p = attachedObject->property("description");
372 QCOMPARE(p.isNull(), true);
379 QDeclarativeEngine engine;
380 QDeclarativeComponent component(&engine);
381 component.setData("import QtQuick 1.1\nItem {\n"
382 "Accessible.role: Accessible.Button\n"
383 "Accessible.name: \"Donald\"\n"
384 "Accessible.description: \"Duck\"\n"
386 QObject *object = component.create();
387 QVERIFY(object != 0);
389 QObject *attachedObject = QDeclarativeAccessibleAttached::attachedProperties(object);
390 QVERIFY(attachedObject);
391 if (attachedObject) {
392 QVariant p = attachedObject->property("role");
393 QCOMPARE(p.isNull(), false);
394 QCOMPARE(p.toInt(), int(QAccessible::PushButton));
395 p = attachedObject->property("name");
396 QCOMPARE(p.isNull(), false);
397 QCOMPARE(p.toString(), QLatin1String("Donald"));
398 p = attachedObject->property("description");
399 QCOMPARE(p.isNull(), false);
400 QCOMPARE(p.toString(), QLatin1String("Duck"));
407 void tst_QDeclarativeAccessibility::basicPropertiesTest()
409 QAI app = QAI(QAccessible::queryAccessibleInterface(qApp));
410 QCOMPARE(app->childCount(), 0);
412 QQuickView *canvas = new QQuickView();
413 canvas->setSource(testFileUrl("statictext.qml"));
415 QCOMPARE(app->childCount(), 1);
417 QAI iface = QAI(QAccessible::queryAccessibleInterface(canvas));
418 QVERIFY(iface.data());
419 QCOMPARE(iface->childCount(), 1);
421 QAI item = QAI(iface->child(0));
422 QVERIFY(item.data());
423 QCOMPARE(item->childCount(), 2);
424 QCOMPARE(item->rect().size(), QSize(400, 400));
425 QCOMPARE(item->role(), QAccessible::Pane);
427 QAI text = QAI(item->child(0));
428 QVERIFY(text.data());
429 QCOMPARE(text->childCount(), 0);
431 QCOMPARE(text->text(QAccessible::Name), QLatin1String("Hello Accessibility"));
432 QCOMPARE(text->rect().size(), QSize(200, 50));
433 QCOMPARE(text->rect().x(), item->rect().x() + 100);
434 QCOMPARE(text->rect().y(), item->rect().y() + 20);
435 QCOMPARE(text->role(), QAccessible::StaticText);
437 QAI text2 = QAI(item->child(1));
438 QVERIFY(text2.data());
439 QCOMPARE(text2->childCount(), 0);
441 QCOMPARE(text2->text(QAccessible::Name), QLatin1String("The Hello 2 accessible text"));
442 QCOMPARE(text2->rect().size(), QSize(100, 40));
443 QCOMPARE(text2->rect().x(), item->rect().x() + 100);
444 QCOMPARE(text2->rect().y(), item->rect().y() + 40);
445 QCOMPARE(text2->role(), QAccessible::StaticText);
450 QAI topLevelChildAt(QAccessibleInterface *iface, int x, int y)
452 QAI child = QAI(iface->childAt(x, y));
457 while (childOfChild = QAI(child->childAt(x, y))) {
458 child = childOfChild;
463 void tst_QDeclarativeAccessibility::hitTest()
465 QQuickView *canvas = new QQuickView();
466 canvas->setSource(testFileUrl("statictext.qml"));
469 QAI iface = QAI(QAccessible::queryAccessibleInterface(canvas));
470 QVERIFY(iface.data());
471 QAI item = QAI(iface->child(0));
472 QRect itemRect = item->rect();
475 QAI itemHit = QAI(iface->childAt(itemRect.x() + 5, itemRect.y() + 5));
477 QCOMPARE(itemRect, itemHit->rect());
479 // hit a text element
480 QAI textChild = QAI(item->child(0));
481 QAI textChildHit = topLevelChildAt(iface.data(), itemRect.x() + 105, itemRect.y() + 25);
482 QVERIFY(textChildHit);
483 QCOMPARE(textChild->rect(), textChildHit->rect());
484 QCOMPARE(textChildHit->text(QAccessible::Name), QLatin1String("Hello Accessibility"));
486 // should also work from top level (app)
487 QAI app = QAI(QAccessible::queryAccessibleInterface(qApp));
488 QAI textChildHit2 = topLevelChildAt(app.data(), itemRect.x() + 105, itemRect.y() + 25);
489 QVERIFY(textChildHit2);
490 QCOMPARE(textChild->rect(), textChildHit2->rect());
491 QCOMPARE(textChildHit2->text(QAccessible::Name), QLatin1String("Hello Accessibility"));
495 QTEST_MAIN(tst_QDeclarativeAccessibility)
497 #include "tst_qdeclarativeaccessibility.moc"