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