Merge "Merge remote-tracking branch 'origin/api_changes'" into refs/staging/master
[profile/ivi/qtbase.git] / tests / auto / other / qaccessibility / tst_qaccessibility.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtCore/qglobal.h>
44 #ifdef Q_OS_WIN
45 # include <QtCore/qt_windows.h>
46 # include <oleacc.h>
47 # include <servprov.h>
48 # include <winuser.h>
49 # ifndef Q_CC_MINGW
50 #  include <Accessible2.h>
51 #  include <AccessibleAction.h>
52 #  include <AccessibleComponent.h>
53 # endif
54 #endif
55 #include <QtTest/QtTest>
56 #include <QtGui>
57 #include <QtWidgets>
58 #include <math.h>
59
60 #if defined(Q_OS_WIN) && defined(interface)
61 #   undef interface
62 #endif
63
64
65 #include "QtTest/qtestaccessible.h"
66
67 #if defined(Q_OS_WINCE)
68 extern "C" bool SystemParametersInfo(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
69 #define SPI_GETPLATFORMTYPE 257
70 inline bool IsValidCEPlatform() {
71     wchar_t tszPlatform[64];
72     if (SystemParametersInfo(SPI_GETPLATFORMTYPE, sizeof(tszPlatform) / sizeof(*tszPlatform), tszPlatform, 0)) {
73         QString platform = QString::fromWCharArray(tszPlatform);
74         if ((platform == QLatin1String("PocketPC")) || (platform == QLatin1String("Smartphone")))
75             return false;
76     }
77     return true;
78 }
79 #endif
80
81 typedef QSharedPointer<QAccessibleInterface> QAIPtr;
82
83 static inline bool verifyChild(QWidget *child, QAccessibleInterface *interface,
84                                int index, const QRect &domain)
85 {
86     if (!child) {
87         qWarning("tst_QAccessibility::verifyChild: null pointer to child.");
88         return false;
89     }
90
91     if (!interface) {
92         qWarning("tst_QAccessibility::verifyChild: null pointer to interface.");
93         return false;
94     }
95
96     // Verify that we get a valid QAccessibleInterface for the child.
97     QAccessibleInterface *childInterface = QAccessible::queryAccessibleInterface(child);
98     if (!childInterface) {
99         qWarning("tst_QAccessibility::verifyChild: Failed to retrieve interface for child.");
100         return false;
101     }
102
103     // QAccessibleInterface::indexOfChild():
104     // Verify that indexOfChild() returns an index equal to the index passed in
105     int indexFromIndexOfChild = interface->indexOfChild(childInterface);
106     if (indexFromIndexOfChild != index) {
107         qWarning("tst_QAccessibility::verifyChild (indexOfChild()):");
108         qWarning() << "Expected:" << index;
109         qWarning() << "Actual:  " << indexFromIndexOfChild;
110         return false;
111     }
112
113     // Navigate to child, compare its object and role with the interface from queryAccessibleInterface(child).
114     QAccessibleInterface *navigatedChildInterface = interface->child(index);
115     if (navigatedChildInterface == 0)
116         return false;
117
118     const QRect rectFromInterface = navigatedChildInterface->rect();
119     delete navigatedChildInterface;
120
121     // QAccessibleInterface::childAt():
122     // Calculate global child position and check that the interface
123     // returns the correct index for that position.
124     QPoint globalChildPos = child->mapToGlobal(QPoint(0, 0));
125     QAccessibleInterface *childAtInterface = interface->childAt(globalChildPos.x(), globalChildPos.y());
126     if (!childAtInterface) {
127         qWarning("tst_QAccessibility::verifyChild (childAt()):");
128         qWarning() << "Expected:" << childInterface;
129         qWarning() << "Actual:  no child";
130         return false;
131     }
132     if (childAtInterface->object() != childInterface->object()) {
133         qWarning("tst_QAccessibility::verifyChild (childAt()):");
134         qWarning() << "Expected:" << childInterface;
135         qWarning() << "Actual:  " << childAtInterface;
136         return false;
137     }
138     delete childInterface;
139     delete childAtInterface;
140
141     // QAccessibleInterface::rect():
142     // Calculate global child geometry and check that the interface
143     // returns a QRect which is equal to the calculated QRect.
144     const QRect expectedGlobalRect = QRect(globalChildPos, child->size());
145     if (expectedGlobalRect != rectFromInterface) {
146         qWarning("tst_QAccessibility::verifyChild (rect()):");
147         qWarning() << "Expected:" << expectedGlobalRect;
148         qWarning() << "Actual:  " << rectFromInterface;
149         return false;
150     }
151
152     // Verify that the child is within its domain.
153     if (!domain.contains(rectFromInterface)) {
154         qWarning("tst_QAccessibility::verifyChild: Child is not within its domain.");
155         return false;
156     }
157
158     return true;
159 }
160
161 static inline int indexOfChild(QAccessibleInterface *parentInterface, QWidget *childWidget)
162 {
163     if (!parentInterface || !childWidget)
164         return -1;
165     QAccessibleInterface *childInterface = QAccessible::queryAccessibleInterface(childWidget);
166     if (!childInterface)
167         return -1;
168     int index = parentInterface->indexOfChild(childInterface);
169     delete childInterface;
170     return index;
171 }
172
173 #define EXPECT(cond) \
174     do { \
175         if (!errorAt && !(cond)) { \
176             errorAt = __LINE__; \
177             qWarning("level: %d, middle: %d, role: %d (%s)", treelevel, middle, iface->role(), #cond); \
178         } \
179     } while (0)
180
181 static int verifyHierarchy(QAccessibleInterface *iface)
182 {
183     int errorAt = 0;
184     static int treelevel = 0;   // for error diagnostics
185     QAccessibleInterface *middleChild, *if2;
186     middleChild = 0;
187     ++treelevel;
188     int middle = iface->childCount()/2 + 1;
189     if (iface->childCount() >= 2) {
190         middleChild = iface->child(middle - 1);
191     }
192     for (int i = 0; i < iface->childCount() && !errorAt; ++i) {
193         if2 = iface->child(i);
194         EXPECT(if2 != 0);
195         // navigate Ancestor...
196         QAccessibleInterface *parent = if2->parent();
197         EXPECT(iface->object() == parent->object());
198         delete parent;
199
200             // navigate Sibling...
201 //            if (middleChild) {
202 //                entry = if2->navigate(QAccessible::Sibling, middle, &if3);
203 //                EXPECT(entry == 0 && if3->object() == middleChild->object());
204 //                if (entry == 0)
205 //                    delete if3;
206 //                EXPECT(iface->indexOfChild(middleChild) == middle);
207 //            }
208
209         // verify children...
210         if (!errorAt)
211             errorAt = verifyHierarchy(if2);
212         delete if2;
213     }
214     delete middleChild;
215
216     --treelevel;
217     return errorAt;
218 }
219
220 QRect childRect(QAccessibleInterface *iface, int index = 0)
221 {
222     QAccessibleInterface *child = iface->child(index);
223     QRect rect = child->rect();
224     delete child;
225     return rect;
226 }
227
228 class tst_QAccessibility : public QObject
229 {
230     Q_OBJECT
231 public:
232     tst_QAccessibility();
233     virtual ~tst_QAccessibility();
234
235 public slots:
236     void initTestCase();
237     void cleanupTestCase();
238     void init();
239     void cleanup();
240 private slots:
241     void eventTest();
242     void customWidget();
243     void deletedWidget();
244
245     void statesStructTest();
246     void navigateHierarchy();
247     void sliderTest();
248     void textAttributes();
249     void hideShowTest();
250
251     void actionTest();
252
253     void applicationTest();
254     void mainWindowTest();
255     void buttonTest();
256     void scrollBarTest();
257     void tabTest();
258     void tabWidgetTest();
259     void menuTest();
260     void spinBoxTest();
261     void doubleSpinBoxTest();
262     void textEditTest();
263     void textBrowserTest();
264     void mdiAreaTest();
265     void mdiSubWindowTest();
266     void lineEditTest();
267     void groupBoxTest();
268     void dialogButtonBoxTest();
269     void dialTest();
270     void rubberBandTest();
271     void abstractScrollAreaTest();
272     void scrollAreaTest();
273
274     void listTest();
275     void treeTest();
276     void tableTest();
277
278     void calendarWidgetTest();
279     void dockWidgetTest();
280     void comboBoxTest();
281     void accessibleName();
282     void labelTest();
283     void accelerators();
284     void bridgeTest();
285
286 protected slots:
287     void onClicked();
288 private:
289     int click_count;
290 };
291
292 const double Q_PI = 3.14159265358979323846;
293
294 QAccessible::State state(QWidget * const widget)
295 {
296     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(widget);
297     if (!iface)
298         qWarning() << "Cannot get QAccessibleInterface for widget";
299     QAccessible::State state = (iface ? iface->state() : QAccessible::State());
300     delete iface;
301     return state;
302 }
303
304 class QtTestAccessibleWidget: public QWidget
305 {
306     Q_OBJECT
307 public:
308     QtTestAccessibleWidget(QWidget *parent, const char *name): QWidget(parent)
309     {
310         setObjectName(name);
311         QPalette pal;
312         pal.setColor(backgroundRole(), Qt::black);//black is beautiful
313         setPalette(pal);
314         setFixedSize(5, 5);
315     }
316 };
317
318 class QtTestAccessibleWidgetIface: public QAccessibleWidget
319 {
320 public:
321     QtTestAccessibleWidgetIface(QtTestAccessibleWidget *w): QAccessibleWidget(w) {}
322     QString text(QAccessible::Text t) const
323     {
324         if (t == QAccessible::Help)
325             return QString::fromLatin1("Help yourself");
326         return QAccessibleWidget::text(t);
327     }
328     static QAccessibleInterface *ifaceFactory(const QString &key, QObject *o)
329     {
330         if (key == "QtTestAccessibleWidget")
331             return new QtTestAccessibleWidgetIface(static_cast<QtTestAccessibleWidget*>(o));
332         return 0;
333     }
334 };
335
336 tst_QAccessibility::tst_QAccessibility()
337 {
338     click_count = 0;
339 }
340
341 tst_QAccessibility::~tst_QAccessibility()
342 {
343 }
344
345 void tst_QAccessibility::onClicked()
346 {
347     click_count++;
348 }
349
350 void tst_QAccessibility::initTestCase()
351 {
352     QTestAccessibility::initialize();
353     QAccessible::installFactory(QtTestAccessibleWidgetIface::ifaceFactory);
354 }
355
356 void tst_QAccessibility::cleanupTestCase()
357 {
358     QTestAccessibility::cleanup();
359 }
360
361 void tst_QAccessibility::init()
362 {
363     QTestAccessibility::clearEvents();
364 }
365
366 void tst_QAccessibility::cleanup()
367 {
368     const EventList list = QTestAccessibility::events();
369     if (!list.isEmpty()) {
370         qWarning("%d accessibility event(s) were not handled in testfunction '%s':", list.count(),
371                  QString(QTest::currentTestFunction()).toAscii().constData());
372         for (int i = 0; i < list.count(); ++i)
373             qWarning(" %d: Object: %p Event: '%s' Child: %d", i + 1, list.at(i)->object(),
374                      qAccessibleEventString(list.at(i)->type()), list.at(i)->child());
375     }
376     QTestAccessibility::clearEvents();
377 }
378
379 void tst_QAccessibility::eventTest()
380 {
381     QPushButton* button = new QPushButton(0);
382     button->setObjectName(QString("Olaf"));
383
384     button->show();
385     QAccessibleEvent showEvent(button, QAccessible::ObjectShow);
386     QVERIFY_EVENT(&showEvent);
387     button->setFocus(Qt::MouseFocusReason);
388     QTestAccessibility::clearEvents();
389     QTest::mouseClick(button, Qt::LeftButton, 0);
390
391     button->setAccessibleName("Olaf the second");
392     QAccessibleEvent nameEvent(button, QAccessible::NameChanged);
393     QVERIFY_EVENT(&nameEvent);
394     button->setAccessibleDescription("This is a button labeled Olaf");
395     QAccessibleEvent descEvent(button, QAccessible::DescriptionChanged);
396     QVERIFY_EVENT(&descEvent);
397
398     button->hide();
399     QAccessibleEvent hideEvent(button, QAccessible::ObjectHide);
400     QVERIFY_EVENT(&hideEvent);
401
402     delete button;
403 }
404
405 void tst_QAccessibility::customWidget()
406 {
407     QtTestAccessibleWidget* widget = new QtTestAccessibleWidget(0, "Heinz");
408
409     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(widget);
410     QVERIFY(iface != 0);
411     QVERIFY(iface->isValid());
412     QCOMPARE(iface->object(), (QObject*)widget);
413     QCOMPARE(iface->object()->objectName(), QString("Heinz"));
414     QCOMPARE(iface->text(QAccessible::Help), QString("Help yourself"));
415
416     delete iface;
417     delete widget;
418 }
419
420 void tst_QAccessibility::deletedWidget()
421 {
422     QtTestAccessibleWidget *widget = new QtTestAccessibleWidget(0, "Ralf");
423     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(widget);
424     QVERIFY(iface != 0);
425     QVERIFY(iface->isValid());
426     QCOMPARE(iface->object(), (QObject*)widget);
427
428     delete widget;
429     widget = 0;
430     QVERIFY(!iface->isValid());
431     delete iface;
432 }
433
434 void tst_QAccessibility::statesStructTest()
435 {
436     QAccessible::State s1;
437     QVERIFY(s1.disabled == 0);
438     QVERIFY(s1.focusable == 0);
439     QVERIFY(s1.modal == 0);
440
441     QAccessible::State s2;
442     QVERIFY(s2 == s1);
443     s2.busy = true;
444     QVERIFY(!(s2 == s1));
445     s1.busy = true;
446     QVERIFY(s2 == s1);
447     s1 = QAccessible::State();
448     QVERIFY(!(s2 == s1));
449     s1 = s2;
450     QVERIFY(s2 == s1);
451     QVERIFY(s1.busy == 1);
452 }
453
454 void tst_QAccessibility::sliderTest()
455 {
456     {
457     QSlider *slider = new QSlider(0);
458     slider->setObjectName(QString("Slidy"));
459     slider->show();
460     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(slider);
461     QVERIFY(iface != 0);
462     QVERIFY(iface->isValid());
463
464     QCOMPARE(iface->childCount(), 0);
465     QCOMPARE(iface->role(), QAccessible::Slider);
466
467     QAccessibleValueInterface *valueIface = iface->valueInterface();
468     QVERIFY(valueIface != 0);
469     QCOMPARE(valueIface->minimumValue().toInt(), slider->minimum());
470     QCOMPARE(valueIface->maximumValue().toInt(), slider->maximum());
471     slider->setValue(50);
472     QCOMPARE(valueIface->currentValue().toInt(), slider->value());
473     slider->setValue(0);
474     QCOMPARE(valueIface->currentValue().toInt(), slider->value());
475     slider->setValue(100);
476     QCOMPARE(valueIface->currentValue().toInt(), slider->value());
477     valueIface->setCurrentValue(77);
478     QCOMPARE(77, slider->value());
479
480     delete iface;
481     delete slider;
482     }
483     QTestAccessibility::clearEvents();
484 }
485
486 void tst_QAccessibility::navigateHierarchy()
487 {
488     {
489     QWidget *w = new QWidget(0);
490     w->setObjectName(QString("Hans"));
491     w->show();
492     QWidget *w1 = new QWidget(w);
493     w1->setObjectName(QString("1"));
494     w1->show();
495     QWidget *w2 = new QWidget(w);
496     w2->setObjectName(QString("2"));
497     w2->show();
498     QWidget *w3 = new QWidget(w);
499     w3->setObjectName(QString("3"));
500     w3->show();
501     QWidget *w31 = new QWidget(w3);
502     w31->setObjectName(QString("31"));
503     w31->show();
504
505     QAccessibleInterface *target = 0;
506     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(w);
507     QVERIFY(iface != 0);
508     QVERIFY(iface->isValid());
509
510     target = iface->child(14);
511     QVERIFY(target == 0);
512     target = iface->child(-1);
513     QVERIFY(target == 0);
514     target = iface->child(0);
515     QAccessibleInterface *interfaceW1 = iface->child(0);
516     QVERIFY(target);
517     QVERIFY(target->isValid());
518     QCOMPARE(target->object(), (QObject*)w1);
519     QVERIFY(interfaceW1 != 0);
520     QVERIFY(interfaceW1->isValid());
521     QCOMPARE(interfaceW1->object(), (QObject*)w1);
522     delete interfaceW1;
523     delete iface; iface = 0;
524
525     iface = QAccessible::queryAccessibleInterface(w);
526     target = iface->child(2);
527     QVERIFY(target != 0);
528     QVERIFY(target->isValid());
529     QCOMPARE(target->object(), (QObject*)w3);
530     delete iface; iface = 0;
531
532
533     iface = target->child(1);
534     QCOMPARE(iface, (QAccessibleInterface*)0);
535     iface = target->child(0);
536     QVERIFY(iface != 0);
537     QVERIFY(iface->isValid());
538     QCOMPARE(iface->object(), (QObject*)w31);
539
540     iface = QAccessible::queryAccessibleInterface(w);
541     QAccessibleInterface *acc3 = iface->child(2);
542     target = acc3->child(0);
543     delete acc3;
544     delete iface;
545     QCOMPARE(target->object(), (QObject*)w31);
546
547     iface = target->parent();
548     QVERIFY(iface != 0);
549     QVERIFY(iface->isValid());
550     QCOMPARE(iface->object(), (QObject*)w3);
551     delete iface; iface = 0;
552     delete target; target = 0;
553
554     delete w;
555     }
556     QTestAccessibility::clearEvents();
557 }
558
559 #define QSETCOMPARE(thetypename, elements, otherelements) \
560     QCOMPARE((QSet<thetypename>() << elements), (QSet<thetypename>() << otherelements))
561
562 static QWidget *createWidgets()
563 {
564     QWidget *w = new QWidget();
565
566     QHBoxLayout *box = new QHBoxLayout(w);
567
568     int i = 0;
569     box->addWidget(new QComboBox(w));
570     box->addWidget(new QPushButton(QString::fromAscii("widget text %1").arg(i++), w));
571     box->addWidget(new QHeaderView(Qt::Vertical, w));
572     box->addWidget(new QTreeView(w));
573     box->addWidget(new QTreeWidget(w));
574     box->addWidget(new QListView(w));
575     box->addWidget(new QListWidget(w));
576     box->addWidget(new QTableView(w));
577     box->addWidget(new QTableWidget(w));
578     box->addWidget(new QCalendarWidget(w));
579     box->addWidget(new QDialogButtonBox(w));
580     box->addWidget(new QGroupBox(QString::fromAscii("widget text %1").arg(i++), w));
581     box->addWidget(new QFrame(w));
582     box->addWidget(new QLineEdit(QString::fromAscii("widget text %1").arg(i++), w));
583     box->addWidget(new QProgressBar(w));
584     box->addWidget(new QTabWidget(w));
585     box->addWidget(new QCheckBox(QString::fromAscii("widget text %1").arg(i++), w));
586     box->addWidget(new QRadioButton(QString::fromAscii("widget text %1").arg(i++), w));
587     box->addWidget(new QDial(w));
588     box->addWidget(new QScrollBar(w));
589     box->addWidget(new QSlider(w));
590     box->addWidget(new QDateTimeEdit(w));
591     box->addWidget(new QDoubleSpinBox(w));
592     box->addWidget(new QSpinBox(w));
593     box->addWidget(new QLabel(QString::fromAscii("widget text %1").arg(i++), w));
594     box->addWidget(new QLCDNumber(w));
595     box->addWidget(new QStackedWidget(w));
596     box->addWidget(new QToolBox(w));
597     box->addWidget(new QLabel(QString::fromAscii("widget text %1").arg(i++), w));
598     box->addWidget(new QTextEdit(QString::fromAscii("widget text %1").arg(i++), w));
599
600     /* Not in the list
601      * QAbstractItemView, QGraphicsView, QScrollArea,
602      * QToolButton, QDockWidget, QFocusFrame, QMainWindow, QMenu, QMenuBar, QSizeGrip, QSplashScreen, QSplitterHandle,
603      * QStatusBar, QSvgWidget, QTabBar, QToolBar, QSplitter
604      */
605     return w;
606 }
607
608 void tst_QAccessibility::accessibleName()
609 {
610     QWidget *toplevel = createWidgets();
611     toplevel->show();
612 #if defined(Q_OS_UNIX)
613     QCoreApplication::processEvents();
614     QTest::qWait(100);
615 #endif
616     QLayout *lout = toplevel->layout();
617     for (int i = 0; i < lout->count(); i++) {
618         QLayoutItem *item = lout->itemAt(i);
619         QWidget *child = item->widget();
620
621         QString name = tr("Widget Name %1").arg(i);
622         child->setAccessibleName(name);
623         QAccessibleInterface *acc = QAccessible::queryAccessibleInterface(child);
624         QCOMPARE(acc->text(QAccessible::Name), name);
625
626         QString desc = tr("Widget Description %1").arg(i);
627         child->setAccessibleDescription(desc);
628         QCOMPARE(acc->text(QAccessible::Description), desc);
629
630     }
631
632     delete toplevel;
633     QTestAccessibility::clearEvents();
634 }
635
636 void tst_QAccessibility::textAttributes()
637 {
638     QTextEdit textEdit;
639     int startOffset;
640     int endOffset;
641     QString attributes;
642     QString text("<html><head></head><body>"
643                  "Hello, <b>this</b> is an <i><b>example</b> text</i>."
644                  "<span style=\"font-family: monospace\">Multiple fonts are used.</span>"
645                  "Multiple <span style=\"font-size: 8pt\">text sizes</span> are used."
646                  "Let's give some color to <span style=\"color:#f0f1f2; background-color:#14f01e\">Qt</span>."
647                  "</body></html>");
648
649     textEdit.setText(text);
650     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&textEdit);
651
652     QAccessibleTextInterface *textInterface=interface->textInterface();
653
654     QVERIFY(textInterface);
655     QCOMPARE(textInterface->characterCount(), 112);
656
657     attributes = textInterface->attributes(10, &startOffset, &endOffset);
658     QCOMPARE(startOffset, 7);
659     QCOMPARE(endOffset, 11);
660     attributes.prepend(';');
661     QVERIFY(attributes.contains(QLatin1String(";font-weight:bold;")));
662
663     attributes = textInterface->attributes(18, &startOffset, &endOffset);
664     QCOMPARE(startOffset, 18);
665     QCOMPARE(endOffset, 25);
666     attributes.prepend(';');
667     QVERIFY(attributes.contains(QLatin1String(";font-weight:bold;")));
668     QVERIFY(attributes.contains(QLatin1String(";font-style:italic;")));
669
670     attributes = textInterface->attributes(34, &startOffset, &endOffset);
671     QCOMPARE(startOffset, 31);
672     QCOMPARE(endOffset, 55);
673     attributes.prepend(';');
674     QVERIFY(attributes.contains(QLatin1String(";font-family:\"monospace\";")));
675
676     attributes = textInterface->attributes(65, &startOffset, &endOffset);
677     QCOMPARE(startOffset, 64);
678     QCOMPARE(endOffset, 74);
679     attributes.prepend(';');
680     QVERIFY(attributes.contains(QLatin1String(";font-size:8pt;")));
681
682     attributes = textInterface->attributes(110, &startOffset, &endOffset);
683     QCOMPARE(startOffset, 109);
684     QCOMPARE(endOffset, 111);
685     attributes.prepend(';');
686     QVERIFY(attributes.contains(QLatin1String(";background-color:rgb(20,240,30);")));
687     QVERIFY(attributes.contains(QLatin1String(";color:rgb(240,241,242);")));
688 }
689
690 void tst_QAccessibility::hideShowTest()
691 {
692     QWidget * const window = new QWidget();
693     QWidget * const child = new QWidget(window);
694
695     QVERIFY(state(window).invisible);
696     QVERIFY(state(child).invisible);
697
698     QTestAccessibility::clearEvents();
699
700     // show() and veryfy that both window and child are not invisible and get ObjectShow events.
701     window->show();
702     QVERIFY(!state(window).invisible);
703     QVERIFY(!state(child).invisible);
704
705     QAccessibleEvent show(window, QAccessible::ObjectShow);
706     QVERIFY(QTestAccessibility::containsEvent(&show));
707     QAccessibleEvent showChild(child, QAccessible::ObjectShow);
708     QVERIFY(QTestAccessibility::containsEvent(&showChild));
709     QTestAccessibility::clearEvents();
710
711     // hide() and veryfy that both window and child are invisible and get ObjectHide events.
712     window->hide();
713     QVERIFY(state(window).invisible);
714     QVERIFY(state(child).invisible);
715     QAccessibleEvent hide(window, QAccessible::ObjectHide);
716     QVERIFY(QTestAccessibility::containsEvent(&hide));
717     QAccessibleEvent hideChild(child, QAccessible::ObjectHide);
718     QVERIFY(QTestAccessibility::containsEvent(&hideChild));
719     QTestAccessibility::clearEvents();
720
721     delete window;
722     QTestAccessibility::clearEvents();
723 }
724
725
726 void tst_QAccessibility::actionTest()
727 {
728     {
729     QCOMPARE(QAccessibleActionInterface::pressAction(), QString(QStringLiteral("Press")));
730
731     QWidget *widget = new QWidget;
732     widget->setFocusPolicy(Qt::NoFocus);
733     widget->show();
734
735     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(widget);
736     QVERIFY(interface);
737     QVERIFY(interface->isValid());
738     QAccessibleActionInterface *actions = interface->actionInterface();
739     QVERIFY(actions);
740
741     // no actions by default, except when focusable
742     QCOMPARE(actions->actionNames(), QStringList());
743     widget->setFocusPolicy(Qt::StrongFocus);
744     QCOMPARE(actions->actionNames(), QStringList(QAccessibleActionInterface::setFocusAction()));
745
746     delete interface;
747     delete widget;
748     }
749     QTestAccessibility::clearEvents();
750
751     {
752     QPushButton *button = new QPushButton;
753     button->show();
754     QTest::qWaitForWindowShown(button);
755     button->clearFocus();
756     QCOMPARE(button->hasFocus(), false);
757     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(button);
758     QAccessibleActionInterface *actions = interface->actionInterface();
759     QVERIFY(actions);
760
761     // Make sure the "primary action" press comes first!
762     QCOMPARE(actions->actionNames(), QStringList() << QAccessibleActionInterface::pressAction() << QAccessibleActionInterface::setFocusAction());
763
764     actions->doAction(QAccessibleActionInterface::setFocusAction());
765     QTest::qWait(500);
766     QCOMPARE(button->hasFocus(), true);
767
768     connect(button, SIGNAL(clicked()), this, SLOT(onClicked()));
769     QCOMPARE(click_count, 0);
770     actions->doAction(QAccessibleActionInterface::pressAction());
771     QTest::qWait(500);
772     QCOMPARE(click_count, 1);
773
774     delete interface;
775     delete button;
776     }
777     QTestAccessibility::clearEvents();
778 }
779
780 void tst_QAccessibility::applicationTest()
781 {
782     QLatin1String name = QLatin1String("My Name");
783     qApp->setApplicationName(name);
784     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(qApp);
785     QCOMPARE(interface->text(QAccessible::Name), name);
786     QCOMPARE(interface->role(), QAccessible::Application);
787     delete interface;
788 }
789
790 void tst_QAccessibility::mainWindowTest()
791 {
792     {
793     QMainWindow *mw = new QMainWindow;
794     mw->resize(300, 200);
795     mw->show(); // triggers layout
796
797     QLatin1String name = QLatin1String("I am the main window");
798     mw->setWindowTitle(name);
799     QTest::qWaitForWindowShown(mw);
800     QAccessibleEvent show(mw, QAccessible::ObjectShow);
801     QVERIFY_EVENT(&show);
802
803     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(mw);
804     QCOMPARE(iface->text(QAccessible::Name), name);
805     QCOMPARE(iface->role(), QAccessible::Window);
806     QVERIFY(iface->state().active);
807
808     QAccessible::State activeState;
809     activeState.active = true;
810     QAccessibleStateChangeEvent active(mw, activeState);
811     QVERIFY_EVENT(&active);
812
813     delete iface;
814     delete mw;
815     }
816     QTestAccessibility::clearEvents();
817
818     {
819     QWindow window;
820     window.setGeometry(80, 80, 40, 40);
821     window.show();
822     QTRY_VERIFY(QGuiApplication::focusWindow() == &window);
823
824 //    We currently don't have an accessible interface for QWindow
825 //    the active state is either in the QMainWindow or QQuickView
826 //    QAIPtr windowIface(QAccessible::queryAccessibleInterface(&window));
827 //    QVERIFY(windowIface->state().active);
828
829     QAccessible::State activeState;
830     activeState.active = true;
831     QAccessibleStateChangeEvent active(&window, activeState);
832     QVERIFY_EVENT(&active);
833
834     QWindow child;
835     child.setParent(&window);
836     child.setGeometry(10, 10, 20, 20);
837     child.show();
838
839     child.requestActivateWindow();
840     QTRY_VERIFY(QGuiApplication::focusWindow() == &child);
841
842     QAccessibleStateChangeEvent deactivate(&window, activeState);
843     QVERIFY_EVENT(&deactivate); // deactivation of parent
844
845     QAccessibleStateChangeEvent activeChild(&child, activeState);
846     QVERIFY_EVENT(&activeChild);
847     }
848 }
849
850 class CounterButton : public QPushButton {
851     Q_OBJECT
852 public:
853     CounterButton(const QString& name, QWidget* parent)
854         : QPushButton(name, parent), clickCount(0)
855     {
856         connect(this, SIGNAL(clicked(bool)), SLOT(incClickCount()));
857     }
858     int clickCount;
859 public Q_SLOTS:
860     void incClickCount() {
861         ++clickCount;
862     }
863 };
864
865 static QAccessibleInterface *relatedInterface(QAccessibleInterface *iface, QAccessible::RelationFlag flag)
866 {
867     typedef QPair<QAccessibleInterface *, QAccessible::Relation> RelationPair;
868     QVector<RelationPair> rels = iface->relations(flag);
869
870     for (int i = 1; i < rels.count(); ++i)
871         delete rels.at(i).first;
872
873     return rels.value(0).first;
874 }
875
876 void tst_QAccessibility::buttonTest()
877 {
878     QWidget window;
879     window.setLayout(new QVBoxLayout);
880
881     // Standard push button
882     CounterButton pushButton("Ok", &window);
883
884     // toggle button
885     QPushButton toggleButton("Toggle", &window);
886     toggleButton.setCheckable(true);
887
888     // standard checkbox
889     QCheckBox checkBox("Check me!", &window);
890
891     // tristate checkbox
892     QCheckBox tristate("Tristate!", &window);
893     tristate.setTristate(true);
894
895     // radiobutton
896     QRadioButton radio("Radio me!", &window);
897
898     // standard toolbutton
899     QToolButton toolbutton(&window);
900     toolbutton.setText("Tool");
901     toolbutton.setMinimumSize(20,20);
902
903     // standard toolbutton
904     QToolButton toggletool(&window);
905     toggletool.setCheckable(true);
906     toggletool.setText("Toggle");
907     toggletool.setMinimumSize(20,20);
908
909     // test Controller/Controlled relations
910     {
911     QCheckBox toggler("Toggle me!", &window);
912     bool ok = connect(&pushButton, SIGNAL(clicked()), &toggler, SLOT(toggle()));
913     QCOMPARE(ok, true);
914     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&toggler);
915     QVERIFY(iface);
916     QCOMPARE(iface->role(), QAccessible::CheckBox);
917     QAccessibleInterface *buttonIFace = relatedInterface(iface, QAccessible::Controller);
918     QVERIFY(buttonIFace);
919     QCOMPARE(buttonIFace->role(), QAccessible::Button);
920     QCOMPARE(buttonIFace->object(), &pushButton);
921     delete buttonIFace;
922     delete iface;
923
924     buttonIFace = QAccessible::queryAccessibleInterface(&pushButton);
925     QVERIFY(buttonIFace);
926     QCOMPARE(buttonIFace->role(), QAccessible::Button);
927     iface = relatedInterface(buttonIFace, QAccessible::Controlled);
928     QVERIFY(iface);
929     QCOMPARE(iface->object(), &toggler);
930
931     }
932
933     // test push button
934     QAccessibleInterface* interface = QAccessible::queryAccessibleInterface(&pushButton);
935     QAccessibleActionInterface* actionInterface = interface->actionInterface();
936     QVERIFY(actionInterface != 0);
937     QCOMPARE(interface->role(), QAccessible::PushButton);
938
939     // buttons only have a click action
940     QCOMPARE(actionInterface->actionNames().size(), 2);
941     QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::pressAction() << QAccessibleActionInterface::setFocusAction());
942     QCOMPARE(pushButton.clickCount, 0);
943     actionInterface->doAction(QAccessibleActionInterface::pressAction());
944     QTest::qWait(500);
945     QCOMPARE(pushButton.clickCount, 1);
946     delete interface;
947
948     // test toggle button
949     interface = QAccessible::queryAccessibleInterface(&toggleButton);
950     actionInterface = interface->actionInterface();
951     QCOMPARE(interface->role(), QAccessible::CheckBox);
952     QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::checkAction() << QAccessibleActionInterface::setFocusAction());
953     QCOMPARE(actionInterface->localizedActionDescription(QAccessibleActionInterface::checkAction()), QString("Checks the checkbox"));
954     QVERIFY(!toggleButton.isChecked());
955     QVERIFY(!interface->state().checked);
956     actionInterface->doAction(QAccessibleActionInterface::checkAction());
957     QTest::qWait(500);
958     QVERIFY(toggleButton.isChecked());
959     QCOMPARE(actionInterface->actionNames().at(0), QAccessibleActionInterface::uncheckAction());
960     QVERIFY(interface->state().checked);
961     delete interface;
962
963     {
964     // test menu push button
965     QAction *foo = new QAction("Foo", 0);
966     foo->setShortcut(QKeySequence("Ctrl+F"));
967     QMenu *menu = new QMenu();
968     menu->addAction(foo);
969     QPushButton menuButton;
970     menuButton.setMenu(menu);
971     menuButton.show();
972     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&menuButton);
973     QCOMPARE(interface->role(), QAccessible::ButtonMenu);
974     QVERIFY(interface->state().hasPopup);
975     QCOMPARE(interface->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::showMenuAction() << QAccessibleActionInterface::setFocusAction());
976     // showing the menu enters a new event loop...
977 //    interface->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
978 //    QTest::qWait(500);
979     delete interface;
980     delete menu;
981     }
982
983
984     QTestAccessibility::clearEvents();
985     {
986     // test check box
987     interface = QAccessible::queryAccessibleInterface(&checkBox);
988     actionInterface = interface->actionInterface();
989     QCOMPARE(interface->role(), QAccessible::CheckBox);
990     QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::checkAction() << QAccessibleActionInterface::setFocusAction());
991     QVERIFY(!interface->state().checked);
992     actionInterface->doAction(QAccessibleActionInterface::checkAction());
993
994     QTest::qWait(500);
995     QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::uncheckAction() << QAccessibleActionInterface::setFocusAction());
996     QVERIFY(interface->state().checked);
997     QVERIFY(checkBox.isChecked());
998     QAccessible::State st;
999     st.checked = true;
1000     QAccessibleStateChangeEvent ev(&checkBox, st);
1001     QVERIFY_EVENT(&ev);
1002     checkBox.setChecked(false);
1003     QVERIFY_EVENT(&ev);
1004     delete interface;
1005     }
1006
1007     {
1008     // test radiobutton
1009     interface = QAccessible::queryAccessibleInterface(&radio);
1010     actionInterface = interface->actionInterface();
1011     QCOMPARE(interface->role(), QAccessible::RadioButton);
1012     QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::checkAction() << QAccessibleActionInterface::setFocusAction());
1013     QVERIFY(!interface->state().checked);
1014     actionInterface->doAction(QAccessibleActionInterface::checkAction());
1015     QTest::qWait(500);
1016     QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::checkAction() << QAccessibleActionInterface::setFocusAction());
1017     QVERIFY(interface->state().checked);
1018     QVERIFY(radio.isChecked());
1019     QAccessible::State st;
1020     st.checked = true;
1021     QAccessibleStateChangeEvent ev(&radio, st);
1022     QVERIFY_EVENT(&ev);
1023     delete interface;
1024     }
1025
1026 //    // test standard toolbutton
1027 //    QVERIFY(QAccessible::queryAccessibleInterface(&toolbutton, &test));
1028 //    QCOMPARE(test->role(), QAccessible::PushButton);
1029 //    QCOMPARE(test->defaultAction(0), QAccessible::Press);
1030 //    QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press"));
1031 //    QCOMPARE(test->state(), (int)QAccessible::Normal);
1032 //    test->release();
1033
1034 //    // toggle tool button
1035 //    QVERIFY(QAccessible::queryAccessibleInterface(&toggletool, &test));
1036 //    QCOMPARE(test->role(), QAccessible::CheckBox);
1037 //    QCOMPARE(test->defaultAction(0), QAccessible::Press);
1038 //    QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check"));
1039 //    QCOMPARE(test->state(), (int)QAccessible::Normal);
1040 //    QVERIFY(test->doAction(QAccessible::Press, 0));
1041 //    QTest::qWait(500);
1042 //    QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck"));
1043 //    QCOMPARE(test->state(), (int)QAccessible::Checked);
1044 //    test->release();
1045
1046 //    // test menu toolbutton
1047 //    QVERIFY(QAccessible::queryAccessibleInterface(&menuToolButton, &test));
1048 //    QCOMPARE(test->role(), QAccessible::ButtonMenu);
1049 //    QCOMPARE(test->defaultAction(0), 1);
1050 //    QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Open"));
1051 //    QCOMPARE(test->state(), (int)QAccessible::HasPopup);
1052 //    QCOMPARE(test->actionCount(0), 1);
1053 //    QCOMPARE(test->actionText(QAccessible::Press, QAccessible::Name, 0), QString("Press"));
1054 //    test->release();
1055
1056 //    // test split menu toolbutton
1057 //    QVERIFY(QAccessible::queryAccessibleInterface(&splitToolButton, &test));
1058 //    QCOMPARE(test->childCount(), 2);
1059 //    QCOMPARE(test->role(), QAccessible::ButtonDropDown);
1060 //    QCOMPARE(test->role(1), QAccessible::PushButton);
1061 //    QCOMPARE(test->role(2), QAccessible::ButtonMenu);
1062 //    QCOMPARE(test->defaultAction(0), QAccessible::Press);
1063 //    QCOMPARE(test->defaultAction(1), QAccessible::Press);
1064 //    QCOMPARE(test->defaultAction(2), QAccessible::Press);
1065 //    QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press"));
1066 //    QCOMPARE(test->state(), (int)QAccessible::HasPopup);
1067 //    QCOMPARE(test->actionCount(0), 1);
1068 //    QCOMPARE(test->actionText(1, QAccessible::Name, 0), QString("Open"));
1069 //    QCOMPARE(test->actionText(test->defaultAction(1), QAccessible::Name, 1), QString("Press"));
1070 //    QCOMPARE(test->state(1), (int)QAccessible::Normal);
1071 //    QCOMPARE(test->actionText(test->defaultAction(2), QAccessible::Name, 2), QString("Open"));
1072 //    QCOMPARE(test->state(2), (int)QAccessible::HasPopup);
1073 //    test->release();
1074 }
1075
1076 void tst_QAccessibility::scrollBarTest()
1077 {
1078     QScrollBar *scrollBar  = new QScrollBar(Qt::Horizontal);
1079     QAccessibleInterface * const scrollBarInterface = QAccessible::queryAccessibleInterface(scrollBar);
1080     QVERIFY(scrollBarInterface);
1081     QVERIFY(scrollBarInterface->state().invisible);
1082     scrollBar->resize(200, 50);
1083     scrollBar->show();
1084     QVERIFY(!scrollBarInterface->state().invisible);
1085     QAccessibleEvent show(scrollBar, QAccessible::ObjectShow);
1086     QVERIFY(QTestAccessibility::containsEvent(&show));
1087     QTestAccessibility::clearEvents();
1088
1089     scrollBar->hide();
1090     QVERIFY(scrollBarInterface->state().invisible);
1091     QAccessibleEvent hide(scrollBar, QAccessible::ObjectHide);
1092     QVERIFY(QTestAccessibility::containsEvent(&hide));
1093     QTestAccessibility::clearEvents();
1094
1095     // Test that the left/right subcontrols are set to unavailable when the scrollBar is at the minimum/maximum.
1096     scrollBar->show();
1097     scrollBar->setMinimum(11);
1098     scrollBar->setMaximum(111);
1099
1100     QAccessibleValueInterface *valueIface = scrollBarInterface->valueInterface();
1101     QVERIFY(valueIface != 0);
1102     QCOMPARE(valueIface->minimumValue().toInt(), scrollBar->minimum());
1103     QCOMPARE(valueIface->maximumValue().toInt(), scrollBar->maximum());
1104     scrollBar->setValue(50);
1105     QCOMPARE(valueIface->currentValue().toInt(), scrollBar->value());
1106     scrollBar->setValue(0);
1107     QCOMPARE(valueIface->currentValue().toInt(), scrollBar->value());
1108     scrollBar->setValue(100);
1109     QCOMPARE(valueIface->currentValue().toInt(), scrollBar->value());
1110     valueIface->setCurrentValue(77);
1111     QCOMPARE(77, scrollBar->value());
1112
1113     const QRect scrollBarRect = scrollBarInterface->rect();
1114     QVERIFY(scrollBarRect.isValid());
1115
1116     delete scrollBarInterface;
1117     delete scrollBar;
1118
1119     QTestAccessibility::clearEvents();
1120 }
1121
1122 void tst_QAccessibility::tabTest()
1123 {
1124     QTabBar *tabBar = new QTabBar();
1125     tabBar->show();
1126
1127     QAccessibleInterface * const interface = QAccessible::queryAccessibleInterface(tabBar);
1128     QVERIFY(interface);
1129     QCOMPARE(interface->childCount(), 2);
1130
1131     // Test that the Invisible bit for the navigation buttons gets set
1132     // and cleared correctly.
1133     QAccessibleInterface *leftButton = interface->child(0);
1134     QCOMPARE(leftButton->role(), QAccessible::PushButton);
1135     QVERIFY(leftButton->state().invisible);
1136     delete leftButton;
1137
1138     const int lots = 5;
1139     for (int i = 0; i < lots; ++i)
1140         tabBar->addTab("Foo");
1141
1142     QAccessibleInterface *child1 = interface->child(0);
1143     QAccessibleInterface *child2 = interface->child(1);
1144     QVERIFY(child1);
1145     QCOMPARE(child1->role(), QAccessible::PageTab);
1146     QVERIFY(child2);
1147     QCOMPARE(child2->role(), QAccessible::PageTab);
1148
1149     QVERIFY((child1->state().invisible) == false);
1150     tabBar->hide();
1151
1152     QCoreApplication::processEvents();
1153     QTest::qWait(100);
1154
1155     QVERIFY(child1->state().invisible);
1156
1157     tabBar->show();
1158     tabBar->setCurrentIndex(0);
1159
1160     // Test that sending a focus action to a tab does not select it.
1161 //    child2->doAction(QAccessible::Focus, 2, QVariantList());
1162     QCOMPARE(tabBar->currentIndex(), 0);
1163
1164     // Test that sending a press action to a tab selects it.
1165     QVERIFY(child2->actionInterface());
1166     QCOMPARE(child2->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::pressAction());
1167     QCOMPARE(tabBar->currentIndex(), 0);
1168     child2->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
1169     QCOMPARE(tabBar->currentIndex(), 1);
1170
1171     delete tabBar;
1172     delete interface;
1173     delete child1;
1174     delete child2;
1175     QTestAccessibility::clearEvents();
1176 }
1177
1178 void tst_QAccessibility::tabWidgetTest()
1179 {
1180     QTabWidget *tabWidget = new QTabWidget();
1181     tabWidget->show();
1182
1183     // the interface for the tab is just a container for tabbar and stacked widget
1184     QAccessibleInterface * const interface = QAccessible::queryAccessibleInterface(tabWidget);
1185     QVERIFY(interface);
1186     QCOMPARE(interface->childCount(), 2);
1187     QCOMPARE(interface->role(), QAccessible::Client);
1188
1189     // Create pages, check navigation
1190     QLabel *label1 = new QLabel("Page 1", tabWidget);
1191     tabWidget->addTab(label1, "Tab 1");
1192     QLabel *label2 = new QLabel("Page 2", tabWidget);
1193     tabWidget->addTab(label2, "Tab 2");
1194
1195     QCOMPARE(interface->childCount(), 2);
1196
1197     QAccessibleInterface* tabBarInterface = 0;
1198     // there is no special logic to sort the children, so the contents will be 1, the tab bar 2
1199     tabBarInterface = interface->child(1);
1200     QVERIFY(tabBarInterface);
1201     QCOMPARE(tabBarInterface->childCount(), 4);
1202     QCOMPARE(tabBarInterface->role(), QAccessible::PageTabList);
1203
1204     QAccessibleInterface* tabButton1Interface = tabBarInterface->child(0);
1205     QVERIFY(tabButton1Interface);
1206     QCOMPARE(tabButton1Interface->role(), QAccessible::PageTab);
1207     QCOMPARE(tabButton1Interface->text(QAccessible::Name), QLatin1String("Tab 1"));
1208
1209     QAccessibleInterface* tabButton2Interface = tabBarInterface->child(1);
1210     QVERIFY(tabButton1Interface);
1211     QCOMPARE(tabButton2Interface->role(), QAccessible::PageTab);
1212     QCOMPARE(tabButton2Interface->text(QAccessible::Name), QLatin1String("Tab 2"));
1213
1214     QAccessibleInterface* tabButtonLeft = tabBarInterface->child(2);
1215     QVERIFY(tabButtonLeft);
1216     QCOMPARE(tabButtonLeft->role(), QAccessible::PushButton);
1217     QCOMPARE(tabButtonLeft->text(QAccessible::Name), QLatin1String("Scroll Left"));
1218
1219     QAccessibleInterface* tabButtonRight = tabBarInterface->child(3);
1220     QVERIFY(tabButtonRight);
1221     QCOMPARE(tabButtonRight->role(), QAccessible::PushButton);
1222     QCOMPARE(tabButtonRight->text(QAccessible::Name), QLatin1String("Scroll Right"));
1223     delete tabButton1Interface;
1224     delete tabButton2Interface;
1225     delete tabButtonLeft;
1226     delete tabButtonRight;
1227
1228     QAccessibleInterface* stackWidgetInterface = interface->child(0);
1229     QVERIFY(stackWidgetInterface);
1230     QCOMPARE(stackWidgetInterface->childCount(), 2);
1231     QCOMPARE(stackWidgetInterface->role(), QAccessible::LayeredPane);
1232
1233     QAccessibleInterface* stackChild1Interface = stackWidgetInterface->child(0);
1234     QVERIFY(stackChild1Interface);
1235 #ifndef Q_CC_INTEL
1236     QCOMPARE(stackChild1Interface->childCount(), 0);
1237 #endif
1238     QCOMPARE(stackChild1Interface->role(), QAccessible::StaticText);
1239     QCOMPARE(stackChild1Interface->text(QAccessible::Name), QLatin1String("Page 1"));
1240     QCOMPARE(label1, stackChild1Interface->object());
1241
1242     // Navigation in stack widgets should be consistent
1243     QAccessibleInterface* parent = stackChild1Interface->parent();
1244     QVERIFY(parent);
1245 #ifndef Q_CC_INTEL
1246     QCOMPARE(parent->childCount(), 2);
1247 #endif
1248     QCOMPARE(parent->role(), QAccessible::LayeredPane);
1249     delete parent;
1250
1251     QAccessibleInterface* stackChild2Interface = stackWidgetInterface->child(1);
1252     QVERIFY(stackChild2Interface);
1253     QCOMPARE(stackChild2Interface->childCount(), 0);
1254     QCOMPARE(stackChild2Interface->role(), QAccessible::StaticText);
1255     QCOMPARE(label2, stackChild2Interface->object());
1256     QCOMPARE(label2->text(), stackChild2Interface->text(QAccessible::Name));
1257
1258     parent = stackChild2Interface->parent();
1259     QVERIFY(parent);
1260 #ifndef Q_CC_INTEL
1261     QCOMPARE(parent->childCount(), 2);
1262 #endif
1263     QCOMPARE(parent->role(), QAccessible::LayeredPane);
1264     delete parent;
1265
1266     delete tabBarInterface;
1267     delete stackChild1Interface;
1268     delete stackChild2Interface;
1269     delete stackWidgetInterface;
1270     delete interface;
1271     delete tabWidget;
1272     QTestAccessibility::clearEvents();
1273 }
1274
1275 void tst_QAccessibility::menuTest()
1276 {
1277     {
1278     QMainWindow mw;
1279     mw.resize(300, 200);
1280     QMenu *file = mw.menuBar()->addMenu("&File");
1281     QMenu *fileNew = file->addMenu("&New...");
1282     fileNew->menuAction()->setShortcut(tr("Ctrl+N"));
1283     fileNew->addAction("Text file");
1284     fileNew->addAction("Image file");
1285     file->addAction("&Open")->setShortcut(tr("Ctrl+O"));
1286     file->addAction("&Save")->setShortcut(tr("Ctrl+S"));
1287     file->addSeparator();
1288     file->addAction("E&xit")->setShortcut(tr("Alt+F4"));
1289
1290     QMenu *edit = mw.menuBar()->addMenu("&Edit");
1291     edit->addAction("&Undo")->setShortcut(tr("Ctrl+Z"));
1292     edit->addAction("&Redo")->setShortcut(tr("Ctrl+Y"));
1293     edit->addSeparator();
1294     edit->addAction("Cu&t")->setShortcut(tr("Ctrl+X"));
1295     edit->addAction("&Copy")->setShortcut(tr("Ctrl+C"));
1296     edit->addAction("&Paste")->setShortcut(tr("Ctrl+V"));
1297     edit->addAction("&Delete")->setShortcut(tr("Del"));
1298     edit->addSeparator();
1299     edit->addAction("Pr&operties");
1300
1301     mw.menuBar()->addSeparator();
1302
1303     QMenu *help = mw.menuBar()->addMenu("&Help");
1304     help->addAction("&Contents");
1305     help->addAction("&About");
1306
1307     mw.menuBar()->addAction("Action!");
1308
1309     mw.show(); // triggers layout
1310     QTest::qWait(100);
1311
1312     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(mw.menuBar());
1313     QCOMPARE(verifyHierarchy(interface),  0);
1314
1315     QVERIFY(interface);
1316     QCOMPARE(interface->childCount(), 5);
1317     QCOMPARE(interface->role(), QAccessible::MenuBar);
1318
1319     QAccessibleInterface *iFile = interface->child(0);
1320     QAccessibleInterface *iEdit = interface->child(1);
1321     QAccessibleInterface *iSeparator = interface->child(2);
1322     QAccessibleInterface *iHelp = interface->child(3);
1323     QAccessibleInterface *iAction = interface->child(4);
1324
1325     QCOMPARE(iFile->role(), QAccessible::MenuItem);
1326     QCOMPARE(iEdit->role(), QAccessible::MenuItem);
1327     QCOMPARE(iSeparator->role(), QAccessible::Separator);
1328     QCOMPARE(iHelp->role(), QAccessible::MenuItem);
1329     QCOMPARE(iAction->role(), QAccessible::MenuItem);
1330 #ifndef Q_OS_MAC
1331 #ifdef Q_OS_WINCE
1332     if (!IsValidCEPlatform())
1333         QSKIP("Tests do not work on Mobile platforms due to native menus");
1334 #endif
1335     QCOMPARE(mw.mapFromGlobal(interface->rect().topLeft()), mw.menuBar()->geometry().topLeft());
1336     QCOMPARE(interface->rect().size(), mw.menuBar()->size());
1337
1338     QVERIFY(interface->rect().contains(iFile->rect()));
1339     QVERIFY(interface->rect().contains(iEdit->rect()));
1340     // QVERIFY(interface->rect().contains(childSeparator->rect())); //separator might be invisible
1341     QVERIFY(interface->rect().contains(iHelp->rect()));
1342     QVERIFY(interface->rect().contains(iAction->rect()));
1343 #endif
1344
1345     QCOMPARE(iFile->text(QAccessible::Name), QString("File"));
1346     QCOMPARE(iEdit->text(QAccessible::Name), QString("Edit"));
1347     QCOMPARE(iSeparator->text(QAccessible::Name), QString());
1348     QCOMPARE(iHelp->text(QAccessible::Name), QString("Help"));
1349     QCOMPARE(iAction->text(QAccessible::Name), QString("Action!"));
1350
1351 // TODO: Currently not working, task to fix is #100019.
1352 #ifndef Q_OS_MAC
1353     QCOMPARE(iFile->text(QAccessible::Accelerator), tr("Alt+F"));
1354     QCOMPARE(iEdit->text(QAccessible::Accelerator), tr("Alt+E"));
1355     QCOMPARE(iSeparator->text(QAccessible::Accelerator), QString());
1356     QCOMPARE(iHelp->text(QAccessible::Accelerator), tr("Alt+H"));
1357     QCOMPARE(iAction->text(QAccessible::Accelerator), QString());
1358 #endif
1359
1360     QVERIFY(iFile->actionInterface());
1361
1362     QCOMPARE(iFile->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::showMenuAction());
1363     QCOMPARE(iSeparator->actionInterface()->actionNames(), QStringList());
1364     QCOMPARE(iHelp->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::showMenuAction());
1365     QCOMPARE(iAction->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::pressAction());
1366
1367     bool menuFade = qApp->isEffectEnabled(Qt::UI_FadeMenu);
1368     int menuFadeDelay = 300;
1369     iFile->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1370     if(menuFade)
1371         QTest::qWait(menuFadeDelay);
1372     QVERIFY(file->isVisible() && !edit->isVisible() && !help->isVisible());
1373     iEdit->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1374     if(menuFade)
1375         QTest::qWait(menuFadeDelay);
1376     QVERIFY(!file->isVisible() && edit->isVisible() && !help->isVisible());
1377     iHelp->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1378     if(menuFade)
1379         QTest::qWait(menuFadeDelay);
1380     QVERIFY(!file->isVisible() && !edit->isVisible() && help->isVisible());
1381     iAction->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1382     if(menuFade)
1383         QTest::qWait(menuFadeDelay);
1384     QVERIFY(!file->isVisible() && !edit->isVisible() && !help->isVisible());
1385
1386     QVERIFY(interface->actionInterface());
1387     QCOMPARE(interface->actionInterface()->actionNames(), QStringList());
1388     delete interface;
1389     interface = QAccessible::queryAccessibleInterface(file);
1390     QCOMPARE(interface->childCount(), 5);
1391     QCOMPARE(interface->role(), QAccessible::PopupMenu);
1392
1393     QAccessibleInterface *iFileNew = interface->child(0);
1394     QAccessibleInterface *iFileOpen = interface->child(1);
1395     QAccessibleInterface *iFileSave = interface->child(2);
1396     QAccessibleInterface *iFileSeparator = interface->child(3);
1397     QAccessibleInterface *iFileExit = interface->child(4);
1398
1399     QCOMPARE(iFileNew->role(), QAccessible::MenuItem);
1400     QCOMPARE(iFileOpen->role(), QAccessible::MenuItem);
1401     QCOMPARE(iFileSave->role(), QAccessible::MenuItem);
1402     QCOMPARE(iFileSeparator->role(), QAccessible::Separator);
1403     QCOMPARE(iFileExit->role(), QAccessible::MenuItem);
1404     QCOMPARE(iFileNew->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::showMenuAction());
1405     QCOMPARE(iFileOpen->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::pressAction());
1406     QCOMPARE(iFileSave->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::pressAction());
1407     QCOMPARE(iFileSeparator->actionInterface()->actionNames(), QStringList());
1408     QCOMPARE(iFileExit->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::pressAction());
1409
1410     QAccessibleInterface *iface = 0;
1411     QAccessibleInterface *iface2 = 0;
1412
1413     // traverse siblings with navigate(Sibling, ...)
1414     iface = interface->child(0);
1415     QVERIFY(iface);
1416     QCOMPARE(iface->role(), QAccessible::MenuItem);
1417
1418     QAccessible::Role fileRoles[5] = {
1419         QAccessible::MenuItem,
1420         QAccessible::MenuItem,
1421         QAccessible::MenuItem,
1422         QAccessible::Separator,
1423         QAccessible::MenuItem
1424     };
1425     for (int child = 0; child < 5; ++child) {
1426         iface2 = interface->child(child);
1427         QVERIFY(iface2);
1428         QCOMPARE(iface2->role(), fileRoles[child]);
1429         delete iface2;
1430     }
1431     delete iface;
1432
1433     // "New" item
1434     iface = interface->child(0);
1435     QVERIFY(iface);
1436     QCOMPARE(iface->role(), QAccessible::MenuItem);
1437
1438     // "New" menu
1439     iface2 = iface->child(0);
1440     delete iface;
1441     iface = iface2;
1442     QVERIFY(iface);
1443     QCOMPARE(iface->role(), QAccessible::PopupMenu);
1444
1445     // "Text file" menu item
1446     iface2 = iface->child(0);
1447     delete iface;
1448     iface = iface2;
1449     QVERIFY(iface);
1450     QCOMPARE(iface->role(), QAccessible::MenuItem);
1451
1452     delete iface;
1453
1454     // move mouse pointer away, since that might influence the
1455     // subsequent tests
1456     QTest::mouseMove(&mw, QPoint(-1, -1));
1457     QTest::qWait(100);
1458     if (menuFade)
1459         QTest::qWait(menuFadeDelay);
1460
1461     iFile->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1462     iFileNew->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1463
1464     QVERIFY(file->isVisible());
1465     QVERIFY(fileNew->isVisible());
1466     QVERIFY(!edit->isVisible());
1467     QVERIFY(!help->isVisible());
1468
1469     QTestAccessibility::clearEvents();
1470     mw.hide();
1471
1472     delete iFile;
1473     delete iFileNew;
1474     delete iFileOpen;
1475     delete iFileSave;
1476     delete iFileSeparator;
1477     delete iFileExit;
1478
1479     // Do not crash if the menu don't have a parent
1480     QMenu *menu = new QMenu;
1481     menu->addAction(QLatin1String("one"));
1482     menu->addAction(QLatin1String("two"));
1483     menu->addAction(QLatin1String("three"));
1484     iface = QAccessible::queryAccessibleInterface(menu);
1485     iface2 = iface->parent();
1486     QVERIFY(iface2);
1487     QCOMPARE(iface2->role(), QAccessible::Application);
1488     // caused a *crash*
1489     iface2->state();
1490     delete iface2;
1491     delete iface;
1492     delete menu;
1493
1494     }
1495     QTestAccessibility::clearEvents();
1496 }
1497
1498 void tst_QAccessibility::spinBoxTest()
1499 {
1500     QSpinBox * const spinBox = new QSpinBox();
1501     spinBox->setValue(3);
1502     spinBox->show();
1503
1504     QAccessibleInterface * const interface = QAccessible::queryAccessibleInterface(spinBox);
1505     QVERIFY(interface);
1506     QCOMPARE(interface->role(), QAccessible::SpinBox);
1507
1508     const QRect widgetRect = spinBox->geometry();
1509     const QRect accessibleRect = interface->rect();
1510     QCOMPARE(accessibleRect, widgetRect);
1511     QCOMPARE(interface->text(QAccessible::Value), QLatin1String("3"));
1512
1513     // one child, the line edit
1514     const int numChildren = interface->childCount();
1515     QCOMPARE(numChildren, 1);
1516     QAccessibleInterface *lineEdit = interface->child(0);
1517
1518     QCOMPARE(lineEdit->role(), QAccessible::EditableText);
1519     QCOMPARE(lineEdit->text(QAccessible::Value), QLatin1String("3"));
1520     delete lineEdit;
1521
1522     QVERIFY(interface->valueInterface());
1523     QCOMPARE(interface->valueInterface()->currentValue().toInt(), 3);
1524     interface->valueInterface()->setCurrentValue(23);
1525     QCOMPARE(interface->valueInterface()->currentValue().toInt(), 23);
1526     QCOMPARE(spinBox->value(), 23);
1527
1528     spinBox->setFocus();
1529     QTestAccessibility::clearEvents();
1530     QTest::keyPress(spinBox, Qt::Key_Up);
1531     QTest::qWait(200);
1532     QAccessibleValueChangeEvent expectedEvent(spinBox, spinBox->value());
1533     QVERIFY(QTestAccessibility::containsEvent(&expectedEvent));
1534     delete spinBox;
1535     QTestAccessibility::clearEvents();
1536 }
1537
1538 void tst_QAccessibility::doubleSpinBoxTest()
1539 {
1540     QDoubleSpinBox *doubleSpinBox = new QDoubleSpinBox;
1541     doubleSpinBox->show();
1542
1543     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(doubleSpinBox);
1544     QVERIFY(interface);
1545
1546     const QRect widgetRect = doubleSpinBox->geometry();
1547     const QRect accessibleRect = interface->rect();
1548     QCOMPARE(accessibleRect, widgetRect);
1549
1550     // Test that we get valid rects for all the spinbox child interfaces.
1551     const int numChildren = interface->childCount();
1552     for (int i = 0; i < numChildren; ++i) {
1553         QAccessibleInterface *childIface = interface->child(i);
1554         const QRect childRect = childIface->rect();
1555         QVERIFY(childRect.isValid());
1556         delete childIface;
1557     }
1558
1559     delete doubleSpinBox;
1560     QTestAccessibility::clearEvents();
1561 }
1562
1563 void tst_QAccessibility::textEditTest()
1564 {
1565     {
1566     QTextEdit edit;
1567     int startOffset;
1568     int endOffset;
1569     QString text = "hello world\nhow are you today?\n";
1570     edit.setText(text);
1571     edit.show();
1572
1573     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&edit);
1574     QCOMPARE(iface->text(QAccessible::Value), text);
1575     QCOMPARE(iface->textInterface()->textAtOffset(8, QAccessible2::WordBoundary, &startOffset, &endOffset), QString("world"));
1576     QCOMPARE(startOffset, 6);
1577     QCOMPARE(endOffset, 11);
1578     QCOMPARE(iface->textInterface()->textAtOffset(14, QAccessible2::LineBoundary, &startOffset, &endOffset), QString("how are you today?"));
1579     QCOMPARE(startOffset, 12);
1580     QCOMPARE(endOffset, 30);
1581     QCOMPARE(iface->textInterface()->characterCount(), 31);
1582     QFontMetrics fm(edit.font());
1583     QCOMPARE(iface->textInterface()->characterRect(0).size(), QSize(fm.width("h"), fm.height()));
1584     QCOMPARE(iface->textInterface()->characterRect(5).size(), QSize(fm.width(" "), fm.height()));
1585     QCOMPARE(iface->textInterface()->characterRect(6).size(), QSize(fm.width("w"), fm.height()));
1586
1587     iface->editableTextInterface()->copyText(6, 11);
1588     QCOMPARE(QApplication::clipboard()->text(), QLatin1String("world"));
1589     iface->editableTextInterface()->cutText(12, 16);
1590     QCOMPARE(QApplication::clipboard()->text(), QLatin1String("how "));
1591     QCOMPARE(iface->textInterface()->text(12, 15), QLatin1String("are"));
1592
1593     QTestAccessibility::clearEvents();
1594
1595     // select text
1596     QTextCursor c = edit.textCursor();
1597     c.setPosition(2);
1598     c.setPosition(4, QTextCursor::KeepAnchor);
1599     edit.setTextCursor(c);
1600     QAccessibleTextSelectionEvent sel(&edit, 2, 4);
1601     QVERIFY_EVENT(&sel);
1602
1603     edit.selectAll();
1604     int end = edit.textCursor().position();
1605     sel.setCursorPosition(end);
1606     sel.setSelection(0, end);
1607     QVERIFY_EVENT(&sel);
1608     }
1609     QTestAccessibility::clearEvents();
1610 }
1611
1612 void tst_QAccessibility::textBrowserTest()
1613 {
1614     {
1615     QTextBrowser textBrowser;
1616     QString text = QLatin1String("Hello world\nhow are you today?\n");
1617     textBrowser.setText(text);
1618     textBrowser.show();
1619
1620     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&textBrowser);
1621     QVERIFY(iface);
1622     QCOMPARE(iface->role(), QAccessible::StaticText);
1623     QCOMPARE(iface->text(QAccessible::Value), text);
1624     int startOffset;
1625     int endOffset;
1626     QCOMPARE(iface->textInterface()->textAtOffset(8, QAccessible2::WordBoundary, &startOffset, &endOffset), QString("world"));
1627     QCOMPARE(startOffset, 6);
1628     QCOMPARE(endOffset, 11);
1629     QCOMPARE(iface->textInterface()->textAtOffset(14, QAccessible2::LineBoundary, &startOffset, &endOffset), QString("how are you today?"));
1630     QCOMPARE(startOffset, 12);
1631     QCOMPARE(endOffset, 30);
1632     QCOMPARE(iface->textInterface()->characterCount(), 31);
1633     }
1634     QTestAccessibility::clearEvents();
1635 }
1636
1637 void tst_QAccessibility::mdiAreaTest()
1638 {
1639     {
1640     QMdiArea mdiArea;
1641     mdiArea.resize(400,300);
1642     mdiArea.show();
1643     const int subWindowCount = 3;
1644     for (int i = 0; i < subWindowCount; ++i)
1645         mdiArea.addSubWindow(new QWidget, Qt::Dialog)->show();
1646
1647     QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
1648     QCOMPARE(subWindows.count(), subWindowCount);
1649
1650     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&mdiArea);
1651     QVERIFY(interface);
1652     QCOMPARE(interface->childCount(), subWindowCount);
1653
1654     }
1655     QTestAccessibility::clearEvents();
1656 }
1657
1658 void tst_QAccessibility::mdiSubWindowTest()
1659 {
1660     {
1661     QMdiArea mdiArea;
1662     mdiArea.show();
1663     qApp->setActiveWindow(&mdiArea);
1664 #if defined(Q_OS_UNIX)
1665     QCoreApplication::processEvents();
1666     QTest::qWait(150);
1667 #endif
1668
1669     const int subWindowCount =  5;
1670     for (int i = 0; i < subWindowCount; ++i) {
1671         QMdiSubWindow *window = mdiArea.addSubWindow(new QPushButton("QAccessibilityTest"));
1672         window->show();
1673         // Parts of this test requires that the sub windows are placed next
1674         // to each other. In order to achieve that QMdiArea must have
1675         // a width which is larger than subWindow->width() * subWindowCount.
1676         if (i == 0) {
1677             int minimumWidth = window->width() * subWindowCount + 20;
1678             mdiArea.resize(mdiArea.size().expandedTo(QSize(minimumWidth, 0)));
1679 #if defined(Q_OS_UNIX)
1680             QCoreApplication::processEvents();
1681             QTest::qWait(100);
1682 #endif
1683         }
1684     }
1685
1686     QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
1687     QCOMPARE(subWindows.count(), subWindowCount);
1688
1689     QMdiSubWindow *testWindow = subWindows.at(3);
1690     QVERIFY(testWindow);
1691     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(testWindow);
1692
1693     // childCount
1694     QVERIFY(interface);
1695     QCOMPARE(interface->childCount(), 1);
1696
1697     // setText / text
1698     QCOMPARE(interface->text(QAccessible::Name), QString());
1699     testWindow->setWindowTitle(QLatin1String("ReplaceMe"));
1700     QCOMPARE(interface->text(QAccessible::Name), QLatin1String("ReplaceMe"));
1701     interface->setText(QAccessible::Name, QLatin1String("TitleSetOnWindow"));
1702     QCOMPARE(interface->text(QAccessible::Name), QLatin1String("TitleSetOnWindow"));
1703
1704     mdiArea.setActiveSubWindow(testWindow);
1705
1706     // state
1707     QAccessible::State state;
1708     state.focusable = true;
1709     state.focused = true;
1710     state.movable = true;
1711     state.sizeable = true;
1712
1713     QCOMPARE(interface->state(), state);
1714     const QRect originalGeometry = testWindow->geometry();
1715     testWindow->showMaximized();
1716     state.sizeable = false;
1717     state.movable = false;
1718     QCOMPARE(interface->state(), state);
1719     testWindow->showNormal();
1720     testWindow->move(-10, 0);
1721     QVERIFY(interface->state().offscreen);
1722     testWindow->setVisible(false);
1723     QVERIFY(interface->state().invisible);
1724     testWindow->setVisible(true);
1725     testWindow->setEnabled(false);
1726     QVERIFY(interface->state().disabled);
1727     testWindow->setEnabled(true);
1728     qApp->setActiveWindow(&mdiArea);
1729     mdiArea.setActiveSubWindow(testWindow);
1730     testWindow->setFocus();
1731     QVERIFY(testWindow->isAncestorOf(qApp->focusWidget()));
1732     QVERIFY(interface->state().focused);
1733     testWindow->setGeometry(originalGeometry);
1734
1735     // rect
1736     const QPoint globalPos = testWindow->mapToGlobal(QPoint(0, 0));
1737     QCOMPARE(interface->rect(), QRect(globalPos, testWindow->size()));
1738     testWindow->hide();
1739     QCOMPARE(interface->rect(), QRect());
1740     QCOMPARE(childRect(interface), QRect());
1741     testWindow->showMinimized();
1742     QCOMPARE(childRect(interface), QRect());
1743     testWindow->showNormal();
1744     testWindow->widget()->hide();
1745     QCOMPARE(childRect(interface), QRect());
1746     testWindow->widget()->show();
1747     const QRect widgetGeometry = testWindow->contentsRect();
1748     const QPoint globalWidgetPos = QPoint(globalPos.x() + widgetGeometry.x(),
1749                                           globalPos.y() + widgetGeometry.y());
1750     QCOMPARE(childRect(interface), QRect(globalWidgetPos, widgetGeometry.size()));
1751
1752     // childAt
1753     QCOMPARE(interface->childAt(-10, 0), static_cast<QAccessibleInterface*>(0));
1754     QCOMPARE(interface->childAt(globalPos.x(), globalPos.y()), static_cast<QAccessibleInterface*>(0));
1755     QAccessibleInterface *child = interface->childAt(globalWidgetPos.x(), globalWidgetPos.y());
1756     QCOMPARE(child->role(), QAccessible::PushButton);
1757     QCOMPARE(child->text(QAccessible::Name), QString("QAccessibilityTest"));
1758     delete child;
1759     testWindow->widget()->hide();
1760     QCOMPARE(interface->childAt(globalWidgetPos.x(), globalWidgetPos.y()), static_cast<QAccessibleInterface*>(0));
1761
1762     }
1763     QTestAccessibility::clearEvents();
1764 }
1765
1766 void tst_QAccessibility::lineEditTest()
1767 {
1768     QWidget *toplevel = new QWidget;
1769     {
1770     QLineEdit *le = new QLineEdit;
1771     QAIPtr iface(QAccessible::queryAccessibleInterface(le));
1772     QVERIFY(iface);
1773     le->show();
1774
1775     QApplication::processEvents();
1776     QCOMPARE(iface->childCount(), 0);
1777     QVERIFY(iface->state().sizeable);
1778     QVERIFY(iface->state().movable);
1779     QVERIFY(iface->state().focusable);
1780     QVERIFY(iface->state().selectable);
1781     QVERIFY(iface->state().hasPopup);
1782     QCOMPARE(bool(iface->state().focused), le->hasFocus());
1783
1784     QString secret(QLatin1String("secret"));
1785     le->setText(secret);
1786     le->setEchoMode(QLineEdit::Normal);
1787     QVERIFY(!(iface->state().passwordEdit));
1788     QCOMPARE(iface->text(QAccessible::Value), secret);
1789     le->setEchoMode(QLineEdit::NoEcho);
1790     QVERIFY(iface->state().passwordEdit);
1791     QVERIFY(iface->text(QAccessible::Value).isEmpty());
1792     le->setEchoMode(QLineEdit::Password);
1793     QVERIFY(iface->state().passwordEdit);
1794     QVERIFY(iface->text(QAccessible::Value).isEmpty());
1795     le->setEchoMode(QLineEdit::PasswordEchoOnEdit);
1796     QVERIFY(iface->state().passwordEdit);
1797     QVERIFY(iface->text(QAccessible::Value).isEmpty());
1798     le->setEchoMode(QLineEdit::Normal);
1799     QVERIFY(!(iface->state().passwordEdit));
1800     QCOMPARE(iface->text(QAccessible::Value), secret);
1801
1802     le->setParent(toplevel);
1803     toplevel->show();
1804     QApplication::processEvents();
1805     QVERIFY(!(iface->state().sizeable));
1806     QVERIFY(!(iface->state().movable));
1807     QVERIFY(iface->state().focusable);
1808     QVERIFY(iface->state().selectable);
1809     QVERIFY(iface->state().hasPopup);
1810     QCOMPARE(bool(iface->state().focused), le->hasFocus());
1811
1812     QLineEdit *le2 = new QLineEdit(toplevel);
1813     le2->show();
1814     QTest::qWait(100);
1815     le2->activateWindow();
1816     QTest::qWait(100);
1817     le->setFocus(Qt::TabFocusReason);
1818     QTestAccessibility::clearEvents();
1819     le2->setFocus(Qt::TabFocusReason);
1820     QAccessibleEvent ev(le2, QAccessible::Focus);
1821     QTRY_VERIFY(QTestAccessibility::containsEvent(&ev));
1822
1823     le->setText(QLatin1String("500"));
1824     le->setValidator(new QIntValidator());
1825     iface->setText(QAccessible::Value, QLatin1String("This text is not a number"));
1826     QCOMPARE(le->text(), QLatin1String("500"));
1827
1828     delete le;
1829     delete le2;
1830     }
1831
1832     {
1833     // Text interface to get the current text
1834     QString cite = "I always pass on good advice. It is the only thing to do with it. It is never of any use to oneself. --Oscar Wilde";
1835     QLineEdit *le3 = new QLineEdit(cite, toplevel);
1836     le3->show();
1837     QAIPtr iface(QAccessible::queryAccessibleInterface(le3));
1838     QAccessibleTextInterface* textIface = iface->textInterface();
1839     le3->deselect();
1840     QTestAccessibility::clearEvents();
1841     le3->setCursorPosition(3);
1842     QCOMPARE(textIface->cursorPosition(), 3);
1843
1844     QAccessibleTextCursorEvent caretEvent(le3, 3);
1845     QTRY_VERIFY(QTestAccessibility::containsEvent(&caretEvent));
1846     QCOMPARE(textIface->selectionCount(), 0);
1847     QTestAccessibility::clearEvents();
1848
1849     int start, end;
1850     QCOMPARE(textIface->text(0, 8), QString::fromLatin1("I always"));
1851     QCOMPARE(textIface->textAtOffset(0, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1("I"));
1852     QCOMPARE(start, 0);
1853     QCOMPARE(end, 1);
1854     QCOMPARE(textIface->textBeforeOffset(0, QAccessible2::CharBoundary,&start,&end), QString());
1855     QCOMPARE(textIface->textAfterOffset(0, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1(" "));
1856     QCOMPARE(start, 1);
1857     QCOMPARE(end, 2);
1858
1859     QCOMPARE(textIface->textAtOffset(5, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1("a"));
1860     QCOMPARE(start, 5);
1861     QCOMPARE(end, 6);
1862     QCOMPARE(textIface->textBeforeOffset(5, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1("w"));
1863     QCOMPARE(textIface->textAfterOffset(5, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1("y"));
1864
1865     QCOMPARE(textIface->textAtOffset(5, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1("always"));
1866     QCOMPARE(start, 2);
1867     QCOMPARE(end, 8);
1868
1869     QCOMPARE(textIface->textAtOffset(2, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1("always"));
1870     QCOMPARE(textIface->textAtOffset(7, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1("always"));
1871     QCOMPARE(textIface->textAtOffset(8, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1(" "));
1872     QCOMPARE(textIface->textAtOffset(25, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1("advice"));
1873     QCOMPARE(textIface->textAtOffset(92, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1("oneself"));
1874
1875     QCOMPARE(textIface->textBeforeOffset(5, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1(" "));
1876     QCOMPARE(textIface->textAfterOffset(5, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1(" "));
1877     QCOMPARE(textIface->textAtOffset(5, QAccessible2::SentenceBoundary,&start,&end), QString::fromLatin1("I always pass on good advice. "));
1878     QCOMPARE(start, 0);
1879     QCOMPARE(end, 30);
1880
1881     QCOMPARE(textIface->textBeforeOffset(40, QAccessible2::SentenceBoundary,&start,&end), QString::fromLatin1("I always pass on good advice. "));
1882     QCOMPARE(textIface->textAfterOffset(5, QAccessible2::SentenceBoundary,&start,&end), QString::fromLatin1("It is the only thing to do with it. "));
1883
1884     QCOMPARE(textIface->textAtOffset(5, QAccessible2::ParagraphBoundary,&start,&end), cite);
1885     QCOMPARE(start, 0);
1886     QCOMPARE(end, cite.length());
1887     QCOMPARE(textIface->textAtOffset(5, QAccessible2::LineBoundary,&start,&end), cite);
1888     QCOMPARE(textIface->textAtOffset(5, QAccessible2::NoBoundary,&start,&end), cite);
1889
1890     QTestAccessibility::clearEvents();
1891     }
1892
1893     {
1894     // Test events: cursor movement, selection, text changes
1895     QString text = "Hello, world";
1896     QLineEdit *lineEdit = new QLineEdit(text, toplevel);
1897     lineEdit->show();
1898     QTestAccessibility::clearEvents();
1899     // cursor
1900     lineEdit->setCursorPosition(5);
1901     QAccessibleTextCursorEvent cursorEvent(lineEdit, 5);
1902     QVERIFY_EVENT(&cursorEvent);
1903     lineEdit->setCursorPosition(0);
1904     cursorEvent.setCursorPosition(0);
1905     QVERIFY_EVENT(&cursorEvent);
1906
1907     // selection
1908     lineEdit->setSelection(2, 4);
1909
1910     QAccessibleTextSelectionEvent sel(lineEdit, 2, 2+4);
1911     QVERIFY_EVENT(&sel);
1912
1913     lineEdit->selectAll();
1914     sel.setSelection(0, lineEdit->text().length());
1915     sel.setCursorPosition(lineEdit->text().length());
1916     QVERIFY_EVENT(&sel);
1917
1918     lineEdit->setSelection(10, -4);
1919     QCOMPARE(lineEdit->cursorPosition(), 6);
1920     QAccessibleTextSelectionEvent sel2(lineEdit, 6, 10);
1921     sel2.setCursorPosition(6);
1922     QVERIFY_EVENT(&sel2);
1923
1924     lineEdit->deselect();
1925     QAccessibleTextSelectionEvent sel3(lineEdit, -1, -1);
1926     sel3.setCursorPosition(6);
1927     QVERIFY_EVENT(&sel3);
1928
1929     // editing
1930     lineEdit->clear();
1931     // FIXME: improve redundant updates
1932     QAccessibleTextRemoveEvent remove(lineEdit, 0, text);
1933     QVERIFY_EVENT(&remove);
1934
1935     QAccessibleTextSelectionEvent noSel(lineEdit, -1, -1);
1936     QVERIFY_EVENT(&noSel);
1937     QAccessibleTextCursorEvent cursor(lineEdit, 0);
1938     QVERIFY_EVENT(&cursor);
1939
1940     lineEdit->setText("foo");
1941     cursorEvent.setCursorPosition(3);
1942     QVERIFY_EVENT(&cursorEvent);
1943
1944     QAccessibleTextInsertEvent e(lineEdit, 0, "foo");
1945     QVERIFY(QTestAccessibility::containsEvent(&e));
1946
1947     lineEdit->setText("bar");
1948     QAccessibleTextUpdateEvent update(lineEdit, 0, "foo", "bar");
1949     QVERIFY(QTestAccessibility::containsEvent(&update));
1950
1951     // FIXME check what extra events are around and get rid of them
1952     QTestAccessibility::clearEvents();
1953
1954     QTestEventList keys;
1955     keys.addKeyClick('D');
1956     keys.simulate(lineEdit);
1957
1958     QAccessibleTextInsertEvent insertD(lineEdit, 3, "D");
1959     QVERIFY_EVENT(&insertD);
1960     keys.clear();
1961     keys.addKeyClick('E');
1962     keys.simulate(lineEdit);
1963
1964     QAccessibleTextInsertEvent insertE(lineEdit, 4, "E");
1965     QVERIFY(QTestAccessibility::containsEvent(&insertE));
1966     keys.clear();
1967     keys.addKeyClick(Qt::Key_Left);
1968     keys.addKeyClick(Qt::Key_Left);
1969     keys.simulate(lineEdit);
1970     cursorEvent.setCursorPosition(4);
1971     QVERIFY(QTestAccessibility::containsEvent(&cursorEvent));
1972     cursorEvent.setCursorPosition(3);
1973     QVERIFY(QTestAccessibility::containsEvent(&cursorEvent));
1974
1975     keys.clear();
1976     keys.addKeyClick('C');
1977     keys.simulate(lineEdit);
1978
1979     QAccessibleTextInsertEvent insertC(lineEdit, 3, "C");
1980     QVERIFY(QTestAccessibility::containsEvent(&insertC));
1981
1982     keys.clear();
1983     keys.addKeyClick('O');
1984     keys.simulate(lineEdit);
1985     QAccessibleTextInsertEvent insertO(lineEdit, 4, "O");
1986     QVERIFY(QTestAccessibility::containsEvent(&insertO));
1987     }
1988     delete toplevel;
1989     QTestAccessibility::clearEvents();
1990 }
1991
1992 void tst_QAccessibility::groupBoxTest()
1993 {
1994     {
1995     QGroupBox *groupBox = new QGroupBox();
1996     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(groupBox);
1997
1998     groupBox->setTitle(QLatin1String("Test QGroupBox"));
1999
2000     QAccessibleEvent ev(groupBox, QAccessible::NameChanged);
2001     QVERIFY_EVENT(&ev);
2002
2003     groupBox->setToolTip(QLatin1String("This group box will be used to test accessibility"));
2004     QVBoxLayout *layout = new QVBoxLayout();
2005     QRadioButton *rbutton = new QRadioButton();
2006     layout->addWidget(rbutton);
2007     groupBox->setLayout(layout);
2008     QAccessibleInterface *rButtonIface = QAccessible::queryAccessibleInterface(rbutton);
2009
2010     QCOMPARE(iface->childCount(), 1);
2011     QCOMPARE(iface->role(), QAccessible::Grouping);
2012     QCOMPARE(iface->text(QAccessible::Name), QLatin1String("Test QGroupBox"));
2013     QCOMPARE(iface->text(QAccessible::Description), QLatin1String("This group box will be used to test accessibility"));
2014     QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > relations = rButtonIface->relations();
2015     QVERIFY(relations.size() == 1);
2016     QPair<QAccessibleInterface*, QAccessible::Relation> relation = relations.first();
2017     QCOMPARE(relation.first->object(), groupBox);
2018     QCOMPARE(relation.second, QAccessible::Label);
2019
2020     delete relation.first;
2021
2022     delete rButtonIface;
2023     delete iface;
2024     delete groupBox;
2025     }
2026
2027     {
2028     QGroupBox *groupBox = new QGroupBox();
2029     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(groupBox);
2030     QVERIFY(!iface->state().checkable);
2031     groupBox->setCheckable(true);
2032
2033     groupBox->setChecked(false);
2034     QAccessible::State st;
2035     st.checked = true;
2036     QAccessibleStateChangeEvent ev(groupBox, st);
2037     QVERIFY_EVENT(&ev);
2038
2039     QCOMPARE(iface->role(), QAccessible::CheckBox);
2040     QAccessibleActionInterface *actionIface = iface->actionInterface();
2041     QVERIFY(actionIface);
2042     QAccessible::State state = iface->state();
2043     QVERIFY(state.checkable);
2044     QVERIFY(!state.checked);
2045     QVERIFY(actionIface->actionNames().contains(QAccessibleActionInterface::checkAction()));
2046     actionIface->doAction(QAccessibleActionInterface::checkAction());
2047     QVERIFY(groupBox->isChecked());
2048     state = iface->state();
2049     QVERIFY(state.checked);
2050     QAccessibleStateChangeEvent ev2(groupBox, st);
2051     QVERIFY_EVENT(&ev2);
2052
2053     delete iface;
2054     delete groupBox;
2055     }
2056 }
2057
2058 bool accessibleInterfaceLeftOf(const QAccessibleInterface *a1, const QAccessibleInterface *a2)
2059 {
2060     return a1->rect().x() < a2->rect().x();
2061 }
2062
2063 bool accessibleInterfaceAbove(const QAccessibleInterface *a1, const QAccessibleInterface *a2)
2064 {
2065     return a1->rect().y() < a2->rect().y();
2066 }
2067
2068 void tst_QAccessibility::dialogButtonBoxTest()
2069 {
2070     {
2071     QDialogButtonBox box(QDialogButtonBox::Reset |
2072                          QDialogButtonBox::Help |
2073                          QDialogButtonBox::Ok, Qt::Horizontal);
2074
2075
2076     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&box);
2077     QVERIFY(iface);
2078     box.show();
2079 #if defined(Q_OS_UNIX)
2080     QCoreApplication::processEvents();
2081     QTest::qWait(100);
2082 #endif
2083
2084     QApplication::processEvents();
2085     QCOMPARE(iface->childCount(), 3);
2086     QCOMPARE(iface->role(), QAccessible::Grouping);
2087     QStringList actualOrder;
2088     QAccessibleInterface *child;
2089     child = iface->child(0);
2090     QCOMPARE(child->role(), QAccessible::PushButton);
2091
2092     QVector<QAccessibleInterface *> buttons;
2093     for (int i = 0; i < iface->childCount(); ++i)
2094         buttons <<  iface->child(i);
2095
2096     qSort(buttons.begin(), buttons.end(), accessibleInterfaceLeftOf);
2097
2098     for (int i = 0; i < buttons.count(); ++i)
2099         actualOrder << buttons.at(i)->text(QAccessible::Name);
2100
2101     QStringList expectedOrder;
2102     QDialogButtonBox::ButtonLayout btnlout =
2103         QDialogButtonBox::ButtonLayout(QApplication::style()->styleHint(QStyle::SH_DialogButtonLayout));
2104     switch (btnlout) {
2105     case QDialogButtonBox::WinLayout:
2106         expectedOrder << QDialogButtonBox::tr("Reset")
2107                       << QDialogButtonBox::tr("OK")
2108                       << QDialogButtonBox::tr("Help");
2109         break;
2110     case QDialogButtonBox::GnomeLayout:
2111     case QDialogButtonBox::KdeLayout:
2112     case QDialogButtonBox::MacLayout:
2113         expectedOrder << QDialogButtonBox::tr("Help")
2114                       << QDialogButtonBox::tr("Reset")
2115                       << QDialogButtonBox::tr("OK");
2116         break;
2117     }
2118     QCOMPARE(actualOrder, expectedOrder);
2119     delete iface;
2120     QApplication::processEvents();
2121     QTestAccessibility::clearEvents();
2122     }
2123
2124     {
2125     QDialogButtonBox box(QDialogButtonBox::Reset |
2126                          QDialogButtonBox::Help |
2127                          QDialogButtonBox::Ok, Qt::Horizontal);
2128
2129
2130     // Test up and down navigation
2131     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&box);
2132     QVERIFY(iface);
2133     box.setOrientation(Qt::Vertical);
2134     box.show();
2135 #if defined(Q_OS_UNIX)
2136     QCoreApplication::processEvents();
2137     QTest::qWait(100);
2138 #endif
2139
2140     QApplication::processEvents();
2141     QStringList actualOrder;
2142
2143     QVector<QAccessibleInterface *> buttons;
2144     for (int i = 0; i < iface->childCount(); ++i)
2145         buttons <<  iface->child(i);
2146
2147     qSort(buttons.begin(), buttons.end(), accessibleInterfaceAbove);
2148
2149     for (int i = 0; i < buttons.count(); ++i)
2150         actualOrder << buttons.at(i)->text(QAccessible::Name);
2151
2152     QStringList expectedOrder;
2153     expectedOrder << QDialogButtonBox::tr("OK")
2154                   << QDialogButtonBox::tr("Reset")
2155                   << QDialogButtonBox::tr("Help");
2156
2157     QCOMPARE(actualOrder, expectedOrder);
2158     delete iface;
2159     QApplication::processEvents();
2160
2161     }
2162     QTestAccessibility::clearEvents();
2163 }
2164
2165 void tst_QAccessibility::dialTest()
2166 {
2167     {
2168     QDial dial;
2169     dial.setMinimum(23);
2170     dial.setMaximum(121);
2171     dial.setValue(42);
2172     QCOMPARE(dial.value(), 42);
2173     dial.show();
2174
2175     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&dial);
2176     QVERIFY(interface);
2177     QCOMPARE(interface->childCount(), 0);
2178
2179     QCOMPARE(interface->text(QAccessible::Value), QString::number(dial.value()));
2180     QCOMPARE(interface->rect(), dial.geometry());
2181
2182     QAccessibleValueInterface *valueIface = interface->valueInterface();
2183     QVERIFY(valueIface != 0);
2184     QCOMPARE(valueIface->minimumValue().toInt(), dial.minimum());
2185     QCOMPARE(valueIface->maximumValue().toInt(), dial.maximum());
2186     QCOMPARE(valueIface->currentValue().toInt(), 42);
2187     dial.setValue(50);
2188     QCOMPARE(valueIface->currentValue().toInt(), dial.value());
2189     dial.setValue(0);
2190     QCOMPARE(valueIface->currentValue().toInt(), dial.value());
2191     dial.setValue(100);
2192     QCOMPARE(valueIface->currentValue().toInt(), dial.value());
2193     valueIface->setCurrentValue(77);
2194     QCOMPARE(77, dial.value());
2195     }
2196     QTestAccessibility::clearEvents();
2197 }
2198
2199 void tst_QAccessibility::rubberBandTest()
2200 {
2201     QRubberBand rubberBand(QRubberBand::Rectangle);
2202     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&rubberBand);
2203     QVERIFY(interface);
2204     QCOMPARE(interface->role(), QAccessible::Border);
2205     delete interface;
2206     QTestAccessibility::clearEvents();
2207 }
2208
2209 void tst_QAccessibility::abstractScrollAreaTest()
2210 {
2211     {
2212     QAbstractScrollArea abstractScrollArea;
2213
2214     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&abstractScrollArea);
2215     QVERIFY(interface);
2216     QVERIFY(!interface->rect().isValid());
2217     QCOMPARE(interface->childAt(200, 200), static_cast<QAccessibleInterface*>(0));
2218
2219     abstractScrollArea.resize(400, 400);
2220     abstractScrollArea.show();
2221 #if defined(Q_OS_UNIX)
2222     QCoreApplication::processEvents();
2223     QTest::qWait(100);
2224 #endif
2225     const QRect globalGeometry = QRect(abstractScrollArea.mapToGlobal(QPoint(0, 0)),
2226                                        abstractScrollArea.size());
2227
2228     // Viewport.
2229     QCOMPARE(interface->childCount(), 1);
2230     QWidget *viewport = abstractScrollArea.viewport();
2231     QVERIFY(viewport);
2232     QVERIFY(verifyChild(viewport, interface, 0, globalGeometry));
2233
2234     // Horizontal scrollBar.
2235     abstractScrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
2236     QCOMPARE(interface->childCount(), 2);
2237     QWidget *horizontalScrollBar = abstractScrollArea.horizontalScrollBar();
2238     QWidget *horizontalScrollBarContainer = horizontalScrollBar->parentWidget();
2239     QVERIFY(verifyChild(horizontalScrollBarContainer, interface, 1, globalGeometry));
2240
2241     // Horizontal scrollBar widgets.
2242     QLabel *secondLeftLabel = new QLabel(QLatin1String("L2"));
2243     abstractScrollArea.addScrollBarWidget(secondLeftLabel, Qt::AlignLeft);
2244     QCOMPARE(interface->childCount(), 2);
2245
2246     QLabel *firstLeftLabel = new QLabel(QLatin1String("L1"));
2247     abstractScrollArea.addScrollBarWidget(firstLeftLabel, Qt::AlignLeft);
2248     QCOMPARE(interface->childCount(), 2);
2249
2250     QLabel *secondRightLabel = new QLabel(QLatin1String("R2"));
2251     abstractScrollArea.addScrollBarWidget(secondRightLabel, Qt::AlignRight);
2252     QCOMPARE(interface->childCount(), 2);
2253
2254     QLabel *firstRightLabel = new QLabel(QLatin1String("R1"));
2255     abstractScrollArea.addScrollBarWidget(firstRightLabel, Qt::AlignRight);
2256     QCOMPARE(interface->childCount(), 2);
2257
2258     // Vertical scrollBar.
2259     abstractScrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
2260     QCOMPARE(interface->childCount(), 3);
2261     QWidget *verticalScrollBar = abstractScrollArea.verticalScrollBar();
2262     QWidget *verticalScrollBarContainer = verticalScrollBar->parentWidget();
2263     QVERIFY(verifyChild(verticalScrollBarContainer, interface, 2, globalGeometry));
2264
2265     // Vertical scrollBar widgets.
2266     QLabel *secondTopLabel = new QLabel(QLatin1String("T2"));
2267     abstractScrollArea.addScrollBarWidget(secondTopLabel, Qt::AlignTop);
2268     QCOMPARE(interface->childCount(), 3);
2269
2270     QLabel *firstTopLabel = new QLabel(QLatin1String("T1"));
2271     abstractScrollArea.addScrollBarWidget(firstTopLabel, Qt::AlignTop);
2272     QCOMPARE(interface->childCount(), 3);
2273
2274     QLabel *secondBottomLabel = new QLabel(QLatin1String("B2"));
2275     abstractScrollArea.addScrollBarWidget(secondBottomLabel, Qt::AlignBottom);
2276     QCOMPARE(interface->childCount(), 3);
2277
2278     QLabel *firstBottomLabel = new QLabel(QLatin1String("B1"));
2279     abstractScrollArea.addScrollBarWidget(firstBottomLabel, Qt::AlignBottom);
2280     QCOMPARE(interface->childCount(), 3);
2281
2282     // CornerWidget.
2283     abstractScrollArea.setCornerWidget(new QLabel(QLatin1String("C")));
2284     QCOMPARE(interface->childCount(), 4);
2285     QWidget *cornerWidget = abstractScrollArea.cornerWidget();
2286     QVERIFY(verifyChild(cornerWidget, interface, 3, globalGeometry));
2287
2288     QCOMPARE(verifyHierarchy(interface), 0);
2289
2290     delete interface;
2291     }
2292
2293     QTestAccessibility::clearEvents();
2294 }
2295
2296 void tst_QAccessibility::scrollAreaTest()
2297 {
2298     {
2299     QScrollArea scrollArea;
2300     scrollArea.show();
2301 #if defined(Q_OS_UNIX)
2302     QCoreApplication::processEvents();
2303     QTest::qWait(100);
2304 #endif
2305     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&scrollArea);
2306     QVERIFY(interface);
2307     QCOMPARE(interface->childCount(), 1); // The viewport.
2308     delete interface;
2309     }
2310     QTestAccessibility::clearEvents();
2311 }
2312
2313 void tst_QAccessibility::listTest()
2314 {
2315     {
2316     QListWidget *listView = new QListWidget;
2317     listView->addItem("Oslo");
2318     listView->addItem("Berlin");
2319     listView->addItem("Brisbane");
2320     listView->resize(400,400);
2321     listView->show();
2322     QTest::qWait(1); // Need this for indexOfchild to work.
2323     QCoreApplication::processEvents();
2324     QTest::qWait(100);
2325
2326     QAIPtr iface = QAIPtr(QAccessible::queryAccessibleInterface(listView));
2327     QCOMPARE(verifyHierarchy(iface.data()), 0);
2328
2329     QCOMPARE((int)iface->role(), (int)QAccessible::List);
2330     QCOMPARE(iface->childCount(), 3);
2331
2332     {
2333     QAIPtr child1 = QAIPtr(iface->child(0));
2334     QVERIFY(child1);
2335     QCOMPARE(iface->indexOfChild(child1.data()), 0);
2336     QCOMPARE(child1->text(QAccessible::Name), QString("Oslo"));
2337     QCOMPARE(child1->role(), QAccessible::ListItem);
2338
2339     QAIPtr child2 = QAIPtr(iface->child(1));
2340     QVERIFY(child2);
2341     QCOMPARE(iface->indexOfChild(child2.data()), 1);
2342     QCOMPARE(child2->text(QAccessible::Name), QString("Berlin"));
2343
2344     QAIPtr child3 = QAIPtr(iface->child(2));
2345     QVERIFY(child3);
2346     QCOMPARE(iface->indexOfChild(child3.data()), 2);
2347     QCOMPARE(child3->text(QAccessible::Name), QString("Brisbane"));
2348     }
2349     QTestAccessibility::clearEvents();
2350
2351     // Check for events
2352     QTest::mouseClick(listView->viewport(), Qt::LeftButton, 0, listView->visualItemRect(listView->item(1)).center());
2353     QAccessibleEvent selectionEvent(listView, QAccessible::Selection);
2354     selectionEvent.setChild(2);
2355     QAccessibleEvent focusEvent(listView, QAccessible::Focus);
2356     focusEvent.setChild(2);
2357     QVERIFY(QTestAccessibility::containsEvent(&selectionEvent));
2358     QVERIFY(QTestAccessibility::containsEvent(&focusEvent));
2359     QTest::mouseClick(listView->viewport(), Qt::LeftButton, 0, listView->visualItemRect(listView->item(2)).center());
2360
2361     QAccessibleEvent selectionEvent2(listView, QAccessible::Selection);
2362     selectionEvent2.setChild(3);
2363     QAccessibleEvent focusEvent2(listView, QAccessible::Focus);
2364     focusEvent2.setChild(3);
2365     QVERIFY(QTestAccessibility::containsEvent(&selectionEvent2));
2366     QVERIFY(QTestAccessibility::containsEvent(&focusEvent2));
2367
2368     listView->addItem("Munich");
2369     QCOMPARE(iface->childCount(), 4);
2370
2371     // table 2
2372     QAccessibleTableInterface *table2 = iface->tableInterface();
2373     QVERIFY(table2);
2374     QCOMPARE(table2->columnCount(), 1);
2375     QCOMPARE(table2->rowCount(), 4);
2376     QAIPtr cell1 = QAIPtr(table2->cellAt(0,0));
2377     QVERIFY(cell1);
2378     QCOMPARE(cell1->text(QAccessible::Name), QString("Oslo"));
2379
2380     QAIPtr cell4 = QAIPtr(table2->cellAt(3,0));
2381     QVERIFY(cell4);
2382     QCOMPARE(cell4->text(QAccessible::Name), QString("Munich"));
2383     QCOMPARE(cell4->role(), QAccessible::ListItem);
2384
2385     QAccessibleTableCellInterface *cellInterface = cell4->tableCellInterface();
2386     QVERIFY(cellInterface);
2387     QCOMPARE(cellInterface->rowIndex(), 3);
2388     QCOMPARE(cellInterface->columnIndex(), 0);
2389     QCOMPARE(cellInterface->rowExtent(), 1);
2390     QCOMPARE(cellInterface->columnExtent(), 1);
2391     QCOMPARE(cellInterface->rowHeaderCells(), QList<QAccessibleInterface*>());
2392     QCOMPARE(cellInterface->columnHeaderCells(), QList<QAccessibleInterface*>());
2393
2394     QCOMPARE(QAIPtr(cellInterface->table())->object(), listView);
2395
2396     listView->clearSelection();
2397     QVERIFY(!(cell4->state().expandable));
2398     QVERIFY( (cell4->state().selectable));
2399     QVERIFY(!(cell4->state().selected));
2400     table2->selectRow(3);
2401     QCOMPARE(listView->selectedItems().size(), 1);
2402     QCOMPARE(listView->selectedItems().at(0)->text(), QLatin1String("Munich"));
2403     QVERIFY(cell4->state().selected);
2404     QVERIFY(cellInterface->isSelected());
2405
2406     QVERIFY(table2->cellAt(-1, 0) == 0);
2407     QVERIFY(table2->cellAt(0, -1) == 0);
2408     QVERIFY(table2->cellAt(0, 1) == 0);
2409     QVERIFY(table2->cellAt(4, 0) == 0);
2410
2411     delete listView;
2412     }
2413     QTestAccessibility::clearEvents();
2414 }
2415
2416 void tst_QAccessibility::treeTest()
2417 {
2418     QTreeWidget *treeView = new QTreeWidget;
2419     treeView->setColumnCount(2);
2420     QTreeWidgetItem *header = new QTreeWidgetItem;
2421     header->setText(0, "Artist");
2422     header->setText(1, "Work");
2423     treeView->setHeaderItem(header);
2424
2425     QTreeWidgetItem *root1 = new QTreeWidgetItem;
2426     root1->setText(0, "Spain");
2427     treeView->addTopLevelItem(root1);
2428
2429     QTreeWidgetItem *item1 = new QTreeWidgetItem;
2430     item1->setText(0, "Picasso");
2431     item1->setText(1, "Guernica");
2432     root1->addChild(item1);
2433
2434     QTreeWidgetItem *item2 = new QTreeWidgetItem;
2435     item2->setText(0, "Tapies");
2436     item2->setText(1, "Ambrosia");
2437     root1->addChild(item2);
2438
2439     QTreeWidgetItem *root2 = new QTreeWidgetItem;
2440     root2->setText(0, "Austria");
2441     treeView->addTopLevelItem(root2);
2442
2443     QTreeWidgetItem *item3 = new QTreeWidgetItem;
2444     item3->setText(0, "Klimt");
2445     item3->setText(1, "The Kiss");
2446     root2->addChild(item3);
2447
2448     treeView->resize(400,400);
2449     treeView->show();
2450
2451     QCoreApplication::processEvents();
2452     QTest::qWait(100);
2453
2454     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(treeView);
2455     QCOMPARE(verifyHierarchy(iface), 0);
2456
2457     QCOMPARE((int)iface->role(), (int)QAccessible::Tree);
2458     // header and 2 rows (the others are not expanded, thus not visible)
2459     QCOMPARE(iface->childCount(), 6);
2460
2461     QAccessibleInterface *header1 = 0;
2462     header1 = iface->child(0);
2463     QVERIFY(header1);
2464     QCOMPARE(iface->indexOfChild(header1), 0);
2465     QCOMPARE(header1->text(QAccessible::Name), QString("Artist"));
2466     QCOMPARE(header1->role(), QAccessible::ColumnHeader);
2467     delete header1;
2468
2469     QAccessibleInterface *child1 = 0;
2470     child1 = iface->child(2);
2471     QVERIFY(child1);
2472     QCOMPARE(iface->indexOfChild(child1), 2);
2473     QCOMPARE(child1->text(QAccessible::Name), QString("Spain"));
2474     QCOMPARE(child1->role(), QAccessible::TreeItem);
2475     QVERIFY(!(child1->state().expanded));
2476     delete child1;
2477
2478     QAccessibleInterface *child2 = 0;
2479     child2 = iface->child(4);
2480     QVERIFY(child2);
2481     QCOMPARE(iface->indexOfChild(child2), 4);
2482     QCOMPARE(child2->text(QAccessible::Name), QString("Austria"));
2483     delete child2;
2484
2485     QTestAccessibility::clearEvents();
2486
2487     // table 2
2488     QAccessibleTableInterface *table2 = iface->tableInterface();
2489     QVERIFY(table2);
2490     QCOMPARE(table2->columnCount(), 2);
2491     QCOMPARE(table2->rowCount(), 2);
2492     QAccessibleInterface *cell1;
2493     QVERIFY(cell1 = table2->cellAt(0,0));
2494     QCOMPARE(cell1->text(QAccessible::Name), QString("Spain"));
2495     QAccessibleInterface *cell2;
2496     QVERIFY(cell2 = table2->cellAt(1,0));
2497     QCOMPARE(cell2->text(QAccessible::Name), QString("Austria"));
2498     QCOMPARE(cell2->role(), QAccessible::TreeItem);
2499     QCOMPARE(cell2->tableCellInterface()->rowIndex(), 1);
2500     QCOMPARE(cell2->tableCellInterface()->columnIndex(), 0);
2501     QVERIFY(cell2->state().expandable);
2502     QCOMPARE(iface->indexOfChild(cell2), 4);
2503     QVERIFY(!(cell2->state().expanded));
2504     QCOMPARE(table2->columnDescription(1), QString("Work"));
2505     delete cell2;
2506     delete cell1;
2507
2508     treeView->expandAll();
2509
2510     // Need this for indexOfchild to work.
2511     QCoreApplication::processEvents();
2512     QTest::qWait(100);
2513
2514     QCOMPARE(table2->columnCount(), 2);
2515     QCOMPARE(table2->rowCount(), 5);
2516     cell1 = table2->cellAt(1,0);
2517     QCOMPARE(cell1->text(QAccessible::Name), QString("Picasso"));
2518     QCOMPARE(iface->indexOfChild(cell1), 4); // 2 header + 2 for root item
2519
2520     cell2 = table2->cellAt(4,0);
2521     QCOMPARE(cell2->text(QAccessible::Name), QString("Klimt"));
2522     QCOMPARE(cell2->role(), QAccessible::TreeItem);
2523     QCOMPARE(cell2->tableCellInterface()->rowIndex(), 4);
2524     QCOMPARE(cell2->tableCellInterface()->columnIndex(), 0);
2525     QVERIFY(!(cell2->state().expandable));
2526     QCOMPARE(iface->indexOfChild(cell2), 10);
2527
2528     QCOMPARE(table2->columnDescription(0), QString("Artist"));
2529     QCOMPARE(table2->columnDescription(1), QString("Work"));
2530
2531     delete iface;
2532     QTestAccessibility::clearEvents();
2533 }
2534
2535 void tst_QAccessibility::tableTest()
2536 {
2537     QTableWidget *tableView = new QTableWidget(3, 3);
2538     tableView->setColumnCount(3);
2539     QStringList hHeader;
2540     hHeader << "h1" << "h2" << "h3";
2541     tableView->setHorizontalHeaderLabels(hHeader);
2542
2543     QStringList vHeader;
2544     vHeader << "v1" << "v2" << "v3";
2545     tableView->setVerticalHeaderLabels(vHeader);
2546
2547     for (int i = 0; i<9; ++i) {
2548         QTableWidgetItem *item = new QTableWidgetItem;
2549         item->setText(QString::number(i/3) + QString(".") + QString::number(i%3));
2550         tableView->setItem(i/3, i%3, item);
2551     }
2552
2553     tableView->resize(600,600);
2554     tableView->show();
2555     QTest::qWait(1); // Need this for indexOfchild to work.
2556     QCoreApplication::processEvents();
2557     QTest::qWait(100);
2558
2559     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(tableView);
2560     QCOMPARE(verifyHierarchy(iface), 0);
2561
2562     QCOMPARE((int)iface->role(), (int)QAccessible::Table);
2563     // header and 2 rows (the others are not expanded, thus not visible)
2564     QCOMPARE(iface->childCount(), 9+3+3+1); // cell+headers+topleft button
2565
2566     QAccessibleInterface *cornerButton = iface->child(0);
2567     QVERIFY(cornerButton);
2568     QCOMPARE(iface->indexOfChild(cornerButton), 0);
2569     QCOMPARE(cornerButton->role(), QAccessible::Pane);
2570     delete cornerButton;
2571
2572     QAccessibleInterface *child1 = iface->child(2);
2573     QVERIFY(child1);
2574     QCOMPARE(iface->indexOfChild(child1), 2);
2575     QCOMPARE(child1->text(QAccessible::Name), QString("h2"));
2576     QCOMPARE(child1->role(), QAccessible::ColumnHeader);
2577     QVERIFY(!(child1->state().expanded));
2578     delete child1;
2579
2580     QAccessibleInterface *child2 = iface->child(10);
2581     QVERIFY(child2);
2582     QCOMPARE(iface->indexOfChild(child2), 10);
2583     QCOMPARE(child2->text(QAccessible::Name), QString("1.1"));
2584     QAccessibleTableCellInterface *cell2Iface = child2->tableCellInterface();
2585     QCOMPARE(cell2Iface->rowIndex(), 1);
2586     QCOMPARE(cell2Iface->columnIndex(), 1);
2587     delete child2;
2588
2589     QAccessibleInterface *child3 = iface->child(11);
2590     QCOMPARE(iface->indexOfChild(child3), 11);
2591     QCOMPARE(child3->text(QAccessible::Name), QString("1.2"));
2592     delete child3;
2593
2594     QTestAccessibility::clearEvents();
2595
2596     // table 2
2597     QAccessibleTableInterface *table2 = iface->tableInterface();
2598     QVERIFY(table2);
2599     QCOMPARE(table2->columnCount(), 3);
2600     QCOMPARE(table2->rowCount(), 3);
2601     QAccessibleInterface *cell1;
2602     QVERIFY(cell1 = table2->cellAt(0,0));
2603     QCOMPARE(cell1->text(QAccessible::Name), QString("0.0"));
2604     QCOMPARE(iface->indexOfChild(cell1), 5);
2605
2606     QAccessibleInterface *cell2;
2607     QVERIFY(cell2 = table2->cellAt(0,1));
2608     QCOMPARE(cell2->text(QAccessible::Name), QString("0.1"));
2609     QCOMPARE(cell2->role(), QAccessible::Cell);
2610     QCOMPARE(cell2->tableCellInterface()->rowIndex(), 0);
2611     QCOMPARE(cell2->tableCellInterface()->columnIndex(), 1);
2612     QCOMPARE(iface->indexOfChild(cell2), 6);
2613     delete cell2;
2614
2615     QAccessibleInterface *cell3;
2616     QVERIFY(cell3 = table2->cellAt(1,2));
2617     QCOMPARE(cell3->text(QAccessible::Name), QString("1.2"));
2618     QCOMPARE(cell3->role(), QAccessible::Cell);
2619     QCOMPARE(cell3->tableCellInterface()->rowIndex(), 1);
2620     QCOMPARE(cell3->tableCellInterface()->columnIndex(), 2);
2621     QCOMPARE(iface->indexOfChild(cell3), 11);
2622     delete cell3;
2623
2624     QCOMPARE(table2->columnDescription(0), QString("h1"));
2625     QCOMPARE(table2->columnDescription(1), QString("h2"));
2626     QCOMPARE(table2->columnDescription(2), QString("h3"));
2627     QCOMPARE(table2->rowDescription(0), QString("v1"));
2628     QCOMPARE(table2->rowDescription(1), QString("v2"));
2629     QCOMPARE(table2->rowDescription(2), QString("v3"));
2630
2631     delete iface;
2632
2633     delete tableView;
2634
2635     QTestAccessibility::clearEvents();
2636 }
2637
2638 void tst_QAccessibility::calendarWidgetTest()
2639 {
2640 #ifndef QT_NO_CALENDARWIDGET
2641     {
2642     QCalendarWidget calendarWidget;
2643
2644     QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&calendarWidget);
2645     QVERIFY(interface);
2646     QCOMPARE(interface->role(), QAccessible::Table);
2647     QVERIFY(!interface->rect().isValid());
2648     QCOMPARE(interface->childAt(200, 200), static_cast<QAccessibleInterface*>(0));
2649
2650     calendarWidget.resize(400, 300);
2651     calendarWidget.show();
2652 #if defined(Q_OS_UNIX)
2653     QCoreApplication::processEvents();
2654     QTest::qWait(100);
2655 #endif
2656
2657     // 1 = navigationBar, 2 = view.
2658     QCOMPARE(interface->childCount(), 2);
2659
2660     const QRect globalGeometry = QRect(calendarWidget.mapToGlobal(QPoint(0, 0)),
2661                                        calendarWidget.size());
2662     QCOMPARE(interface->rect(), globalGeometry);
2663
2664     QWidget *navigationBar = 0;
2665     foreach (QObject *child, calendarWidget.children()) {
2666         if (child->objectName() == QLatin1String("qt_calendar_navigationbar")) {
2667             navigationBar = static_cast<QWidget *>(child);
2668             break;
2669         }
2670     }
2671     QVERIFY(navigationBar);
2672     QVERIFY(verifyChild(navigationBar, interface, 0, globalGeometry));
2673
2674     QAbstractItemView *calendarView = 0;
2675     foreach (QObject *child, calendarWidget.children()) {
2676         if (child->objectName() == QLatin1String("qt_calendar_calendarview")) {
2677             calendarView = static_cast<QAbstractItemView *>(child);
2678             break;
2679         }
2680     }
2681     QVERIFY(calendarView);
2682     QVERIFY(verifyChild(calendarView, interface, 1, globalGeometry));
2683
2684     // Hide navigation bar.
2685     calendarWidget.setNavigationBarVisible(false);
2686     QCOMPARE(interface->childCount(), 1);
2687     QVERIFY(!navigationBar->isVisible());
2688
2689     QVERIFY(verifyChild(calendarView, interface, 0, globalGeometry));
2690
2691     // Show navigation bar.
2692     calendarWidget.setNavigationBarVisible(true);
2693     QCOMPARE(interface->childCount(), 2);
2694     QVERIFY(navigationBar->isVisible());
2695
2696     // Navigate to the navigation bar via Child.
2697     QAccessibleInterface *navigationBarInterface = interface->child(0);
2698     QVERIFY(navigationBarInterface);
2699     QCOMPARE(navigationBarInterface->object(), (QObject*)navigationBar);
2700
2701     // Navigate to the view via Child.
2702     QAccessibleInterface *calendarViewInterface = interface->child(1);
2703     QVERIFY(calendarViewInterface);
2704     QCOMPARE(calendarViewInterface->object(), (QObject*)calendarView);
2705
2706     QVERIFY(!interface->child(-1));
2707
2708     // In order for geometric navigation to work they must share the same parent
2709     QCOMPARE(navigationBarInterface->parent()->object(), calendarViewInterface->parent()->object());
2710     QVERIFY(navigationBarInterface->rect().bottom() < calendarViewInterface->rect().top());
2711     delete calendarViewInterface;
2712     calendarViewInterface = 0;
2713     delete navigationBarInterface;
2714     navigationBarInterface = 0;
2715
2716     }
2717     QTestAccessibility::clearEvents();
2718 #endif // QT_NO_CALENDARWIDGET
2719 }
2720
2721 void tst_QAccessibility::dockWidgetTest()
2722 {
2723 #ifndef QT_NO_DOCKWIDGET
2724     // Set up a proper main window with two dock widgets
2725     QMainWindow *mw = new QMainWindow();
2726     QFrame *central = new QFrame(mw);
2727     mw->setCentralWidget(central);
2728     QMenuBar *mb = new QMenuBar(mw);
2729     mb->addAction(tr("&File"));
2730     mw->setMenuBar(mb);
2731
2732     QDockWidget *dock1 = new QDockWidget(mw);
2733     mw->addDockWidget(Qt::LeftDockWidgetArea, dock1);
2734     QPushButton *pb1 = new QPushButton(tr("Push me"), dock1);
2735     dock1->setWidget(pb1);
2736
2737     QDockWidget *dock2 = new QDockWidget(mw);
2738     mw->addDockWidget(Qt::BottomDockWidgetArea, dock2);
2739     QPushButton *pb2 = new QPushButton(tr("Push me"), dock2);
2740     dock2->setWidget(pb2);
2741
2742     mw->resize(600,400);
2743     mw->show();
2744 #if defined(Q_OS_UNIX)
2745     QCoreApplication::processEvents();
2746     QTest::qWait(100);
2747 #endif
2748
2749     QAccessibleInterface *accMainWindow = QAccessible::queryAccessibleInterface(mw);
2750     // 4 children: menu bar, dock1, dock2, and central widget
2751     QCOMPARE(accMainWindow->childCount(), 4);
2752     QAccessibleInterface *accDock1 = 0;
2753     for (int i = 0; i < 4; ++i) {
2754         accDock1 = accMainWindow->child(i);
2755         if (accMainWindow->role() == QAccessible::Window) {
2756             if (accDock1 && qobject_cast<QDockWidget*>(accDock1->object()) == dock1) {
2757                 break;
2758             } else {
2759                 delete accDock1;
2760             }
2761         }
2762     }
2763     QVERIFY(accDock1);
2764     QCOMPARE(accDock1->role(), QAccessible::Window);
2765
2766     QAccessibleInterface *dock1TitleBar = accDock1->child(0);
2767     QCOMPARE(dock1TitleBar->role(), QAccessible::TitleBar);
2768     QVERIFY(accDock1->rect().contains(dock1TitleBar->rect()));
2769     delete dock1TitleBar;
2770
2771     QPoint globalPos = dock1->mapToGlobal(QPoint(0,0));
2772     globalPos.rx()+=5;  //### query style
2773     globalPos.ry()+=5;
2774     QAccessibleInterface *childAt = accDock1->childAt(globalPos.x(), globalPos.y());    //###
2775     QCOMPARE(childAt->role(), QAccessible::TitleBar);
2776     int index = accDock1->indexOfChild(childAt);
2777     delete childAt;
2778     QAccessibleInterface *accTitleBar = accDock1->child(index);
2779
2780     QCOMPARE(accTitleBar->role(), QAccessible::TitleBar);
2781     QCOMPARE(accDock1->indexOfChild(accTitleBar), 0);
2782     QAccessibleInterface *acc;
2783     acc = accTitleBar->parent();
2784     QVERIFY(acc);
2785     QCOMPARE(acc->role(), QAccessible::Window);
2786
2787
2788     delete accTitleBar;
2789     delete accDock1;
2790     delete pb1;
2791     delete pb2;
2792     delete dock1;
2793     delete dock2;
2794     delete mw;
2795     QTestAccessibility::clearEvents();
2796 #endif // QT_NO_DOCKWIDGET
2797 }
2798
2799 void tst_QAccessibility::comboBoxTest()
2800 {
2801 #if defined(Q_OS_WINCE)
2802     if (!IsValidCEPlatform())
2803         QSKIP("Test skipped on Windows Mobile test hardware");
2804 #endif
2805     { // not editable combobox
2806     QComboBox combo;
2807     combo.addItems(QStringList() << "one" << "two" << "three");
2808     combo.show();
2809     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&combo);
2810     QCOMPARE(verifyHierarchy(iface), 0);
2811
2812     QCOMPARE(iface->role(), QAccessible::ComboBox);
2813     QCOMPARE(iface->childCount(), 1);
2814
2815 #ifdef Q_OS_UNIX
2816     QCOMPARE(iface->text(QAccessible::Name), QLatin1String("one"));
2817 #endif
2818     QCOMPARE(iface->text(QAccessible::Value), QLatin1String("one"));
2819     combo.setCurrentIndex(2);
2820 #ifdef Q_OS_UNIX
2821     QCOMPARE(iface->text(QAccessible::Name), QLatin1String("three"));
2822 #endif
2823     QCOMPARE(iface->text(QAccessible::Value), QLatin1String("three"));
2824
2825     QAccessibleInterface *listIface = iface->child(0);
2826     QCOMPARE(listIface->role(), QAccessible::List);
2827     QCOMPARE(listIface->childCount(), 3);
2828
2829     QVERIFY(!combo.view()->isVisible());
2830     QVERIFY(iface->actionInterface());
2831     QCOMPARE(iface->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::showMenuAction());
2832     iface->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
2833     QVERIFY(combo.view()->isVisible());
2834
2835     delete iface;
2836     }
2837
2838     { // editable combobox
2839     QComboBox editableCombo;
2840     editableCombo.show();
2841     editableCombo.setEditable(true);
2842     editableCombo.addItems(QStringList() << "foo" << "bar" << "baz");
2843
2844     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&editableCombo);
2845     QCOMPARE(verifyHierarchy(iface), 0);
2846
2847     QCOMPARE(iface->role(), QAccessible::ComboBox);
2848     QCOMPARE(iface->childCount(), 2);
2849
2850     QAccessibleInterface *listIface = iface->child(0);
2851     QCOMPARE(listIface->role(), QAccessible::List);
2852     QAccessibleInterface *editIface = iface->child(1);
2853     QCOMPARE(editIface->role(), QAccessible::EditableText);
2854
2855     delete listIface;
2856     delete editIface;
2857     delete iface;
2858     }
2859
2860     QTestAccessibility::clearEvents();
2861 }
2862
2863 void tst_QAccessibility::labelTest()
2864 {
2865     QString text = "Hello World";
2866     QLabel *label = new QLabel(text);
2867     label->show();
2868
2869 #if defined(Q_OS_UNIX)
2870     QCoreApplication::processEvents();
2871 #endif
2872     QTest::qWait(100);
2873
2874     QAccessibleInterface *acc_label = QAccessible::queryAccessibleInterface(label);
2875     QVERIFY(acc_label);
2876
2877     QCOMPARE(acc_label->text(QAccessible::Name), text);
2878
2879     delete acc_label;
2880     delete label;
2881     QTestAccessibility::clearEvents();
2882
2883     QPixmap testPixmap(50, 50);
2884     testPixmap.fill();
2885
2886     QLabel imageLabel;
2887     imageLabel.setPixmap(testPixmap);
2888     imageLabel.setToolTip("Test Description");
2889
2890     acc_label = QAccessible::queryAccessibleInterface(&imageLabel);
2891     QVERIFY(acc_label);
2892
2893     QAccessibleImageInterface *imageInterface = acc_label->imageInterface();
2894     QVERIFY(imageInterface);
2895
2896     QCOMPARE(imageInterface->imageSize(), testPixmap.size());
2897     QCOMPARE(imageInterface->imageDescription(), QString::fromLatin1("Test Description"));
2898     const QPoint labelPos = imageLabel.mapToGlobal(QPoint(0,0));
2899     QCOMPARE(imageInterface->imagePosition().topLeft(), labelPos);
2900
2901     delete acc_label;
2902
2903     QTestAccessibility::clearEvents();
2904 }
2905
2906 void tst_QAccessibility::accelerators()
2907 {
2908     QWidget *window = new QWidget;
2909     QHBoxLayout *lay = new QHBoxLayout(window);
2910     QLabel *label = new QLabel(tr("&Line edit"), window);
2911     QLineEdit *le = new QLineEdit(window);
2912     lay->addWidget(label);
2913     lay->addWidget(le);
2914     label->setBuddy(le);
2915
2916     window->show();
2917
2918     QAccessibleInterface *accLineEdit = QAccessible::queryAccessibleInterface(le);
2919     QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QKeySequence(Qt::ALT).toString(QKeySequence::NativeText) + QLatin1String("L"));
2920     QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QKeySequence(Qt::ALT).toString(QKeySequence::NativeText) + QLatin1String("L"));
2921     label->setText(tr("Q &"));
2922     QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QString());
2923     label->setText(tr("Q &&"));
2924     QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QString());
2925     label->setText(tr("Q && A"));
2926     QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QString());
2927     label->setText(tr("Q &&&A"));
2928     QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QKeySequence(Qt::ALT).toString(QKeySequence::NativeText) + QLatin1String("A"));
2929     label->setText(tr("Q &&A"));
2930     QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QString());
2931
2932 #if !defined(QT_NO_DEBUG) && !defined(Q_OS_MAC)
2933     QTest::ignoreMessage(QtWarningMsg, "QKeySequence::mnemonic: \"Q &A&B\" contains multiple occurrences of '&'");
2934 #endif
2935     label->setText(tr("Q &A&B"));
2936     QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QKeySequence(Qt::ALT).toString(QKeySequence::NativeText) + QLatin1String("A"));
2937
2938 #if defined(Q_OS_UNIX)
2939     QCoreApplication::processEvents();
2940 #endif
2941     QTest::qWait(100);
2942     delete window;
2943     QTestAccessibility::clearEvents();
2944 }
2945
2946 void tst_QAccessibility::bridgeTest()
2947 {
2948     // For now this is a simple test to see if the bridge is working at all.
2949     // Ideally it should be extended to test all aspects of the bridge.
2950 #ifdef Q_OS_WIN
2951     // First, test MSAA part of bridge
2952     QWidget *window = new QWidget;
2953     QVBoxLayout *lay = new QVBoxLayout(window);
2954     QPushButton *button = new QPushButton(tr("Push me"), window);
2955     QLineEdit *le = new QLineEdit(window);
2956     lay->addWidget(button);
2957     lay->addWidget(le);
2958
2959     window->show();
2960     QTest::qWaitForWindowShown(window);
2961
2962     QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(button);
2963     QPoint buttonPos = button->mapToGlobal(QPoint(0,0));
2964     QRect buttonRect = iface->rect();
2965     QCOMPARE(buttonRect.topLeft(), buttonPos);
2966
2967
2968     // All set, now test the bridge.
2969     POINT pt;
2970     pt.x = buttonRect.center().x();
2971     pt.y = buttonRect.center().y();
2972     IAccessible *iacc;
2973
2974     VARIANT varChild;
2975     HRESULT hr = ::AccessibleObjectFromPoint(pt, &iacc, &varChild);
2976     QVERIFY(SUCCEEDED(hr));
2977     VARIANT varSELF;
2978     varSELF.vt = VT_I4;
2979     varSELF.lVal = 0;
2980
2981     // **** Test get_accRole ****
2982     VARIANT varRole;
2983     hr = iacc->get_accRole(varSELF, &varRole);
2984     QVERIFY(SUCCEEDED(hr));
2985
2986     QCOMPARE(varRole.vt, (VARTYPE)VT_I4);
2987     QCOMPARE(varRole.lVal, (LONG)ROLE_SYSTEM_PUSHBUTTON);
2988
2989     // **** Test accLocation ****
2990     long x, y, w, h;
2991     hr = iacc->accLocation(&x, &y, &w, &h, varSELF);
2992     QCOMPARE(buttonRect, QRect(x, y, w, h));
2993
2994 #ifndef Q_CC_MINGW
2995     // Test IAccessible2 part of bridge
2996     IServiceProvider *pService = 0;
2997     hr = iacc->QueryInterface(IID_IServiceProvider, (void **)&pService);
2998     if (SUCCEEDED(hr)) {
2999         IAccessible2 *pIA2 = 0;
3000         hr = pService->QueryService(IID_IAccessible, IID_IAccessible2, (void**)&pIA2);
3001         if (SUCCEEDED(hr) && pIA2) {
3002             // The control supports IAccessible2.
3003             // pIA2 is the reference to the accessible object's IAccessible2 interface.
3004
3005             /***** Test IAccessibleComponent *****/
3006             IAccessibleComponent *ia2Component = 0;
3007             hr = pIA2->QueryInterface(IID_IAccessibleComponent, (void**)&ia2Component);
3008             QVERIFY(SUCCEEDED(hr));
3009             long x, y;
3010             hr = ia2Component->get_locationInParent(&x, &y);
3011             QVERIFY(SUCCEEDED(hr));
3012             QCOMPARE(button->pos(), QPoint(x, y));
3013             ia2Component->Release();
3014
3015             /***** Test IAccessibleAction *****/
3016             IAccessibleAction *ia2Action = 0;
3017             hr = pIA2->QueryInterface(IID_IAccessibleAction, (void**)&ia2Action);
3018             QVERIFY(SUCCEEDED(hr));
3019             QVERIFY(ia2Action);
3020             long nActions;
3021             ia2Action->nActions(&nActions);
3022             QVERIFY(nActions >= 1); // "Press" and "SetFocus"
3023             BSTR actionName;
3024             ia2Action->get_name(0, &actionName);
3025             QString name((QChar*)actionName);
3026             QCOMPARE(name, QAccessibleActionInterface::pressAction());
3027             ia2Action->Release();
3028
3029             // Done testing
3030             pIA2->Release();
3031         }
3032         pService->Release();
3033     }
3034 #endif
3035     iacc->Release();
3036
3037     QTestAccessibility::clearEvents();
3038 #endif
3039 }
3040
3041 QTEST_MAIN(tst_QAccessibility)
3042 #include "tst_qaccessibility.moc"