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();
206 void checkableTest();
209 tst_QDeclarativeAccessibility::tst_QDeclarativeAccessibility()
214 tst_QDeclarativeAccessibility::~tst_QDeclarativeAccessibility()
219 void tst_QDeclarativeAccessibility::commonTests_data()
221 QTest::addColumn<QString>("accessibleRoleFileName");
223 QTest::newRow("StaticText") << SRCDIR "/data/statictext.qml";
224 QTest::newRow("PushButton") << SRCDIR "/data/pushbutton.qml";
227 void tst_QDeclarativeAccessibility::commonTests()
229 QFETCH(QString, accessibleRoleFileName);
231 qDebug() << "testing" << accessibleRoleFileName;
233 QQuickView *view = new QQuickView();
234 // view->setFixedSize(240,320);
235 view->setSource(QUrl::fromLocalFile(accessibleRoleFileName));
238 QVERIFY(view->rootObject() != 0);
240 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(view);
249 QString eventName(const int ev)
252 case 0x0001: return "SoundPlayed";
253 case 0x0002: return "Alert";
254 case 0x0003: return "ForegroundChanged";
255 case 0x0004: return "MenuStart";
256 case 0x0005: return "MenuEnd";
257 case 0x0006: return "PopupMenuStart";
258 case 0x0007: return "PopupMenuEnd";
259 case 0x000C: return "ContextHelpStart";
260 case 0x000D: return "ContextHelpEnd";
261 case 0x000E: return "DragDropStart";
262 case 0x000F: return "DragDropEnd";
263 case 0x0010: return "DialogStart";
264 case 0x0011: return "DialogEnd";
265 case 0x0012: return "ScrollingStart";
266 case 0x0013: return "ScrollingEnd";
267 case 0x0018: return "MenuCommand";
268 case 0x8000: return "ObjectCreated";
269 case 0x8001: return "ObjectDestroyed";
270 case 0x8002: return "ObjectShow";
271 case 0x8003: return "ObjectHide";
272 case 0x8004: return "ObjectReorder";
273 case 0x8005: return "Focus";
274 case 0x8006: return "Selection";
275 case 0x8007: return "SelectionAdd";
276 case 0x8008: return "SelectionRemove";
277 case 0x8009: return "SelectionWithin";
278 case 0x800A: return "StateChanged";
279 case 0x800B: return "LocationChanged";
280 case 0x800C: return "NameChanged";
281 case 0x800D: return "DescriptionChanged";
282 case 0x800E: return "ValueChanged";
283 case 0x800F: return "ParentChanged";
284 case 0x80A0: return "HelpChanged";
285 case 0x80B0: return "DefaultActionChanged";
286 case 0x80C0: return "AcceleratorChanged";
287 default: return "Unknown Event";
291 void tst_QDeclarativeAccessibility::declarativeAttachedProperties()
294 QDeclarativeEngine engine;
295 QDeclarativeComponent component(&engine);
296 component.setData("import QtQuick 1.1\nItem {\n"
298 QObject *object = component.create();
299 QVERIFY(object != 0);
301 QObject *attachedObject = QDeclarativeAccessibleAttached::attachedProperties(object);
302 QCOMPARE(attachedObject, static_cast<QObject*>(0));
309 QDeclarativeAccessibleAttached *attachedObj = new QDeclarativeAccessibleAttached(&parent);
313 QVariant pp = attachedObj->property("name");
314 QDeclarativeEngine engine;
315 QDeclarativeComponent component(&engine);
316 component.setData("import QtQuick 1.1\nItem {\n"
317 "Accessible.role: Accessible.Button\n"
319 QObject *object = component.create();
320 QVERIFY(object != 0);
322 QObject *attachedObject = QDeclarativeAccessibleAttached::attachedProperties(object);
323 QVERIFY(attachedObject);
324 if (attachedObject) {
325 QVariant p = attachedObject->property("role");
326 QCOMPARE(p.isNull(), false);
327 QCOMPARE(p.toInt(), int(QAccessible::PushButton));
328 p = attachedObject->property("name");
329 QCOMPARE(p.isNull(), true);
330 p = attachedObject->property("description");
331 QCOMPARE(p.isNull(), true);
338 QDeclarativeEngine engine;
339 QDeclarativeComponent component(&engine);
340 component.setData("import QtQuick 1.1\nItem {\n"
341 "Accessible.role: Accessible.Button\n"
342 "Accessible.name: \"Donald\"\n"
343 "Accessible.description: \"Duck\"\n"
345 QObject *object = component.create();
346 QVERIFY(object != 0);
348 QObject *attachedObject = QDeclarativeAccessibleAttached::attachedProperties(object);
349 QVERIFY(attachedObject);
350 if (attachedObject) {
351 QVariant p = attachedObject->property("role");
352 QCOMPARE(p.isNull(), false);
353 QCOMPARE(p.toInt(), int(QAccessible::PushButton));
354 p = attachedObject->property("name");
355 QCOMPARE(p.isNull(), false);
356 QCOMPARE(p.toString(), QLatin1String("Donald"));
357 p = attachedObject->property("description");
358 QCOMPARE(p.isNull(), false);
359 QCOMPARE(p.toString(), QLatin1String("Duck"));
366 void tst_QDeclarativeAccessibility::basicPropertiesTest()
368 QAI app = QAI(QAccessible::queryAccessibleInterface(qApp));
369 QCOMPARE(app->childCount(), 0);
371 QQuickView *canvas = new QQuickView();
372 canvas->setSource(testFileUrl("statictext.qml"));
374 QCOMPARE(app->childCount(), 1);
376 QAI iface = QAI(QAccessible::queryAccessibleInterface(canvas));
377 QVERIFY(iface.data());
378 QCOMPARE(iface->childCount(), 1);
380 QAI item = QAI(iface->child(0));
381 QVERIFY(item.data());
382 QCOMPARE(item->childCount(), 2);
383 QCOMPARE(item->rect().size(), QSize(400, 400));
384 QCOMPARE(item->role(), QAccessible::Pane);
385 QCOMPARE(iface->indexOfChild(item.data()), 0);
387 QAI text = QAI(item->child(0));
388 QVERIFY(text.data());
389 QCOMPARE(text->childCount(), 0);
391 QCOMPARE(text->text(QAccessible::Name), QLatin1String("Hello Accessibility"));
392 QCOMPARE(text->rect().size(), QSize(200, 50));
393 QCOMPARE(text->rect().x(), item->rect().x() + 100);
394 QCOMPARE(text->rect().y(), item->rect().y() + 20);
395 QCOMPARE(text->role(), QAccessible::StaticText);
396 QCOMPARE(item->indexOfChild(text.data()), 0);
398 QAI text2 = QAI(item->child(1));
399 QVERIFY(text2.data());
400 QCOMPARE(text2->childCount(), 0);
402 QCOMPARE(text2->text(QAccessible::Name), QLatin1String("The Hello 2 accessible text"));
403 QCOMPARE(text2->rect().size(), QSize(100, 40));
404 QCOMPARE(text2->rect().x(), item->rect().x() + 100);
405 QCOMPARE(text2->rect().y(), item->rect().y() + 40);
406 QCOMPARE(text2->role(), QAccessible::StaticText);
407 QCOMPARE(item->indexOfChild(text2.data()), 1);
409 QCOMPARE(iface->indexOfChild(text2.data()), -1);
410 QCOMPARE(text2->indexOfChild(item.data()), -1);
415 QAI topLevelChildAt(QAccessibleInterface *iface, int x, int y)
417 QAI child = QAI(iface->childAt(x, y));
422 while (childOfChild = QAI(child->childAt(x, y))) {
423 child = childOfChild;
428 void tst_QDeclarativeAccessibility::hitTest()
430 QQuickView *canvas = new QQuickView;
431 canvas->setSource(testFileUrl("hittest.qml"));
434 QAI iface = QAI(QAccessible::queryAccessibleInterface(canvas));
435 QVERIFY(iface.data());
436 QAI rootItem = QAI(iface->child(0));
437 QRect rootRect = rootItem->rect();
440 QAI itemHit(iface->childAt(rootRect.x() + 200, rootRect.y() + 50));
442 QCOMPARE(rootRect, itemHit->rect());
445 QAI rect1(rootItem->child(1));
446 QRect rect1Rect = rect1->rect();
447 itemHit = QAI(rootItem->childAt(rect1Rect.x() + 10, rect1Rect.y() + 10));
449 QCOMPARE(rect1Rect, itemHit->rect());
450 QCOMPARE(itemHit->text(QAccessible::Name), QLatin1String("rect1"));
452 // should also work from top level (app)
453 QAI app(QAccessible::queryAccessibleInterface(qApp));
454 QAI itemHit2(topLevelChildAt(app.data(), rect1Rect.x() + 10, rect1Rect.y() + 10));
456 QCOMPARE(itemHit2->rect(), rect1Rect);
457 QCOMPARE(itemHit2->text(QAccessible::Name), QLatin1String("rect1"));
460 QAI rect2(rootItem->child(2));
461 QAI rect20(rect2->child(1));
462 QAI rect201(rect20->child(2));
465 QRect rect201Rect = rect201->rect();
466 itemHit = QAI(iface->childAt(rect201Rect.x() + 20, rect201Rect.y() + 20));
468 QCOMPARE(itemHit->rect(), rect201Rect);
469 QCOMPARE(itemHit->text(QAccessible::Name), QLatin1String("rect201"));
474 void tst_QDeclarativeAccessibility::checkableTest()
476 QQuickView *canvas = new QQuickView();
477 canvas->setSource(testFileUrl("checkbuttons.qml"));
480 QAI iface = QAI(QAccessible::queryAccessibleInterface(canvas));
481 QVERIFY(iface.data());
482 QAI root = QAI(iface->child(0));
484 QAI button1 = QAI(root->child(0));
485 QCOMPARE(button1->role(), QAccessible::Button);
486 QVERIFY(!(button1->state().checked));
487 QAI button2 = QAI(root->child(1));
488 QVERIFY(!(button2->state().checked));
489 QAI button3 = QAI(root->child(2));
490 QVERIFY(button3->state().checked);
492 QAI checkBox1 = QAI(root->child(3));
493 QCOMPARE(checkBox1->role(), QAccessible::CheckBox);
494 QVERIFY((checkBox1->state().checked));
495 QAI checkBox2 = QAI(root->child(4));
496 QVERIFY(!(checkBox2->state().checked));
499 QTEST_MAIN(tst_QDeclarativeAccessibility)
501 #include "tst_qdeclarativeaccessibility.moc"