1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the test suite of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
43 #include <QtCore/qglobal.h>
45 # include <QtCore/qt_windows.h>
47 # include <servprov.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>
57 #include <QtTest/QtTest>
61 #include <qpa/qplatformnativeinterface.h>
63 #if defined(Q_OS_WIN) && defined(interface)
68 #include "QtTest/qtestaccessible.h"
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")))
84 typedef QSharedPointer<QAccessibleInterface> QAIPtr;
86 static inline bool verifyChild(QWidget *child, QAccessibleInterface *interface,
87 int index, const QRect &domain)
90 qWarning("tst_QAccessibility::verifyChild: null pointer to child.");
95 qWarning("tst_QAccessibility::verifyChild: null pointer to interface.");
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.");
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;
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)
121 const QRect rectFromInterface = navigatedChildInterface->rect();
122 delete navigatedChildInterface;
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";
135 if (childAtInterface->object() != childInterface->object()) {
136 qWarning("tst_QAccessibility::verifyChild (childAt()):");
137 qWarning() << "Expected:" << childInterface;
138 qWarning() << "Actual: " << childAtInterface;
141 delete childInterface;
142 delete childAtInterface;
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;
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.");
164 static inline int indexOfChild(QAccessibleInterface *parentInterface, QWidget *childWidget)
166 if (!parentInterface || !childWidget)
168 QAccessibleInterface *childInterface = QAccessible::queryAccessibleInterface(childWidget);
171 int index = parentInterface->indexOfChild(childInterface);
172 delete childInterface;
176 #define EXPECT(cond) \
178 if (!errorAt && !(cond)) { \
179 errorAt = __LINE__; \
180 qWarning("level: %d, middle: %d, role: %d (%s)", treelevel, middle, iface->role(), #cond); \
184 static int verifyHierarchy(QAccessibleInterface *iface)
187 static int treelevel = 0; // for error diagnostics
188 QAccessibleInterface *middleChild, *if2;
191 int middle = iface->childCount()/2 + 1;
192 if (iface->childCount() >= 2) {
193 middleChild = iface->child(middle - 1);
195 for (int i = 0; i < iface->childCount() && !errorAt; ++i) {
196 if2 = iface->child(i);
198 // navigate Ancestor...
199 QAccessibleInterface *parent = if2->parent();
200 EXPECT(iface->object() == parent->object());
203 // navigate Sibling...
204 // if (middleChild) {
205 // entry = if2->navigate(QAccessible::Sibling, middle, &if3);
206 // EXPECT(entry == 0 && if3->object() == middleChild->object());
209 // EXPECT(iface->indexOfChild(middleChild) == middle);
212 // verify children...
214 errorAt = verifyHierarchy(if2);
223 QRect childRect(QAccessibleInterface *iface, int index = 0)
225 QAccessibleInterface *child = iface->child(index);
226 QRect rect = child->rect();
231 class tst_QAccessibility : public QObject
235 tst_QAccessibility();
236 virtual ~tst_QAccessibility();
240 void cleanupTestCase();
246 void deletedWidget();
248 void statesStructTest();
249 void navigateHierarchy();
251 void textAttributes();
256 void applicationTest();
257 void mainWindowTest();
259 void scrollBarTest();
261 void tabWidgetTest();
264 void doubleSpinBoxTest();
266 void textBrowserTest();
268 void mdiSubWindowTest();
271 void dialogButtonBoxTest();
273 void rubberBandTest();
274 void abstractScrollAreaTest();
275 void scrollAreaTest();
281 void calendarWidgetTest();
282 void dockWidgetTest();
284 void accessibleName();
295 const double Q_PI = 3.14159265358979323846;
297 QAccessible::State state(QWidget * const widget)
299 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(widget);
301 qWarning() << "Cannot get QAccessibleInterface for widget";
302 QAccessible::State state = (iface ? iface->state() : QAccessible::State());
307 class QtTestAccessibleWidget: public QWidget
311 QtTestAccessibleWidget(QWidget *parent, const char *name): QWidget(parent)
315 pal.setColor(backgroundRole(), Qt::black);//black is beautiful
321 class QtTestAccessibleWidgetIface: public QAccessibleWidget
324 QtTestAccessibleWidgetIface(QtTestAccessibleWidget *w): QAccessibleWidget(w) {}
325 QString text(QAccessible::Text t) const
327 if (t == QAccessible::Help)
328 return QString::fromLatin1("Help yourself");
329 return QAccessibleWidget::text(t);
331 static QAccessibleInterface *ifaceFactory(const QString &key, QObject *o)
333 if (key == "QtTestAccessibleWidget")
334 return new QtTestAccessibleWidgetIface(static_cast<QtTestAccessibleWidget*>(o));
339 tst_QAccessibility::tst_QAccessibility()
344 tst_QAccessibility::~tst_QAccessibility()
348 void tst_QAccessibility::onClicked()
353 void tst_QAccessibility::initTestCase()
355 QTestAccessibility::initialize();
356 QAccessible::installFactory(QtTestAccessibleWidgetIface::ifaceFactory);
359 void tst_QAccessibility::cleanupTestCase()
361 QTestAccessibility::cleanup();
364 void tst_QAccessibility::init()
366 QTestAccessibility::clearEvents();
369 void tst_QAccessibility::cleanup()
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());
379 QTestAccessibility::clearEvents();
382 void tst_QAccessibility::eventTest()
384 QPushButton* button = new QPushButton(0);
385 button->setObjectName(QString("Olaf"));
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);
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);
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));
410 void tst_QAccessibility::customWidget()
412 QtTestAccessibleWidget* widget = new QtTestAccessibleWidget(0, "Heinz");
414 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(widget);
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"));
425 void tst_QAccessibility::deletedWidget()
427 QtTestAccessibleWidget *widget = new QtTestAccessibleWidget(0, "Ralf");
428 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(widget);
430 QVERIFY(iface->isValid());
431 QCOMPARE(iface->object(), (QObject*)widget);
435 QVERIFY(!iface->isValid());
439 void tst_QAccessibility::statesStructTest()
441 QAccessible::State s1;
442 QVERIFY(s1.disabled == 0);
443 QVERIFY(s1.focusable == 0);
444 QVERIFY(s1.modal == 0);
446 QAccessible::State s2;
449 QVERIFY(!(s2 == s1));
452 s1 = QAccessible::State();
453 QVERIFY(!(s2 == s1));
456 QVERIFY(s1.busy == 1);
459 void tst_QAccessibility::sliderTest()
462 QSlider *slider = new QSlider(0);
463 slider->setObjectName(QString("Slidy"));
465 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(slider);
467 QVERIFY(iface->isValid());
469 QCOMPARE(iface->childCount(), 0);
470 QCOMPARE(iface->role(), QAccessible::Slider);
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());
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());
488 QTestAccessibility::clearEvents();
491 void tst_QAccessibility::navigateHierarchy()
494 QWidget *w = new QWidget(0);
495 w->setObjectName(QString("Hans"));
497 QWidget *w1 = new QWidget(w);
498 w1->setObjectName(QString("1"));
500 QWidget *w2 = new QWidget(w);
501 w2->setObjectName(QString("2"));
503 QWidget *w3 = new QWidget(w);
504 w3->setObjectName(QString("3"));
506 QWidget *w31 = new QWidget(w3);
507 w31->setObjectName(QString("31"));
510 QAccessibleInterface *target = 0;
511 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(w);
513 QVERIFY(iface->isValid());
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);
522 QVERIFY(target->isValid());
523 QCOMPARE(target->object(), (QObject*)w1);
524 QVERIFY(interfaceW1 != 0);
525 QVERIFY(interfaceW1->isValid());
526 QCOMPARE(interfaceW1->object(), (QObject*)w1);
528 delete iface; iface = 0;
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;
538 iface = target->child(1);
539 QCOMPARE(iface, (QAccessibleInterface*)0);
540 iface = target->child(0);
542 QVERIFY(iface->isValid());
543 QCOMPARE(iface->object(), (QObject*)w31);
545 iface = QAccessible::queryAccessibleInterface(w);
546 QAccessibleInterface *acc3 = iface->child(2);
547 target = acc3->child(0);
550 QCOMPARE(target->object(), (QObject*)w31);
552 iface = target->parent();
554 QVERIFY(iface->isValid());
555 QCOMPARE(iface->object(), (QObject*)w3);
556 delete iface; iface = 0;
557 delete target; target = 0;
561 QTestAccessibility::clearEvents();
564 #define QSETCOMPARE(thetypename, elements, otherelements) \
565 QCOMPARE((QSet<thetypename>() << elements), (QSet<thetypename>() << otherelements))
567 static QWidget *createWidgets()
569 QWidget *w = new QWidget();
571 QHBoxLayout *box = new QHBoxLayout(w);
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));
606 * QAbstractItemView, QGraphicsView, QScrollArea,
607 * QToolButton, QDockWidget, QFocusFrame, QMainWindow, QMenu, QMenuBar, QSizeGrip, QSplashScreen, QSplitterHandle,
608 * QStatusBar, QSvgWidget, QTabBar, QToolBar, QSplitter
613 void tst_QAccessibility::accessibleName()
615 QWidget *toplevel = createWidgets();
617 #if defined(Q_OS_UNIX)
618 QCoreApplication::processEvents();
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();
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);
631 QString desc = tr("Widget Description %1").arg(i);
632 child->setAccessibleDescription(desc);
633 QCOMPARE(acc->text(QAccessible::Description), desc);
638 QTestAccessibility::clearEvents();
641 void tst_QAccessibility::textAttributes()
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>."
654 textEdit.setText(text);
655 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&textEdit);
657 QAccessibleTextInterface *textInterface=interface->textInterface();
659 QVERIFY(textInterface);
660 QCOMPARE(textInterface->characterCount(), 112);
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;")));
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;")));
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\";")));
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;")));
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);")));
695 void tst_QAccessibility::hideShowTest()
697 QWidget * const window = new QWidget();
698 QWidget * const child = new QWidget(window);
700 QVERIFY(state(window).invisible);
701 QVERIFY(state(child).invisible);
703 QTestAccessibility::clearEvents();
705 // show() and veryfy that both window and child are not invisible and get ObjectShow events.
707 QVERIFY(!state(window).invisible);
708 QVERIFY(!state(child).invisible);
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();
716 // hide() and veryfy that both window and child are invisible and get ObjectHide events.
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();
727 QTestAccessibility::clearEvents();
731 void tst_QAccessibility::actionTest()
734 QCOMPARE(QAccessibleActionInterface::pressAction(), QString(QStringLiteral("Press")));
736 QWidget *widget = new QWidget;
737 widget->setFocusPolicy(Qt::NoFocus);
740 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(widget);
742 QVERIFY(interface->isValid());
743 QAccessibleActionInterface *actions = interface->actionInterface();
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()));
754 QTestAccessibility::clearEvents();
757 QPushButton *button = new QPushButton;
759 QVERIFY(QTest::qWaitForWindowExposed(button));
760 button->clearFocus();
761 QCOMPARE(button->hasFocus(), false);
762 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(button);
763 QAccessibleActionInterface *actions = interface->actionInterface();
766 // Make sure the "primary action" press comes first!
767 QCOMPARE(actions->actionNames(), QStringList() << QAccessibleActionInterface::pressAction() << QAccessibleActionInterface::setFocusAction());
769 actions->doAction(QAccessibleActionInterface::setFocusAction());
771 QCOMPARE(button->hasFocus(), true);
773 connect(button, SIGNAL(clicked()), this, SLOT(onClicked()));
774 QCOMPARE(click_count, 0);
775 actions->doAction(QAccessibleActionInterface::pressAction());
777 QCOMPARE(click_count, 1);
782 QTestAccessibility::clearEvents();
785 void tst_QAccessibility::applicationTest()
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);
795 void tst_QAccessibility::mainWindowTest()
798 QMainWindow *mw = new QMainWindow;
799 mw->resize(300, 200);
800 mw->show(); // triggers layout
801 qApp->setActiveWindow(mw);
803 QLatin1String name = QLatin1String("I am the main window");
804 mw->setWindowTitle(name);
805 QVERIFY(QTest::qWaitForWindowActive(mw));
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));
815 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(mw);
816 QCOMPARE(iface->text(QAccessible::Name), name);
817 QCOMPARE(iface->role(), QAccessible::Window);
818 QVERIFY(iface->state().active);
824 QTestAccessibility::clearEvents();
828 window.setGeometry(80, 80, 40, 40);
830 QTRY_VERIFY(QGuiApplication::focusWindow() == &window);
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);
837 QAccessible::State activeState;
838 activeState.active = true;
839 QAccessibleStateChangeEvent active(&window, activeState);
840 QVERIFY_EVENT(&active);
843 child.setParent(&window);
844 child.setGeometry(10, 10, 20, 20);
847 child.requestActivateWindow();
848 QTRY_VERIFY(QGuiApplication::focusWindow() == &child);
850 QAccessibleStateChangeEvent deactivate(&window, activeState);
851 QVERIFY_EVENT(&deactivate); // deactivation of parent
853 QAccessibleStateChangeEvent activeChild(&child, activeState);
854 QVERIFY_EVENT(&activeChild);
858 class CounterButton : public QPushButton {
861 CounterButton(const QString& name, QWidget* parent)
862 : QPushButton(name, parent), clickCount(0)
864 connect(this, SIGNAL(clicked(bool)), SLOT(incClickCount()));
868 void incClickCount() {
873 void tst_QAccessibility::buttonTest()
876 window.setLayout(new QVBoxLayout);
878 // Standard push button
879 CounterButton pushButton("Ok", &window);
882 QPushButton toggleButton("Toggle", &window);
883 toggleButton.setCheckable(true);
886 QCheckBox checkBox("Check me!", &window);
889 QCheckBox tristate("Tristate!", &window);
890 tristate.setTristate(true);
893 QRadioButton radio("Radio me!", &window);
895 // standard toolbutton
896 QToolButton toolbutton(&window);
897 toolbutton.setText("Tool");
898 toolbutton.setMinimumSize(20,20);
900 // standard toolbutton
901 QToolButton toggletool(&window);
902 toggletool.setCheckable(true);
903 toggletool.setText("Toggle");
904 toggletool.setMinimumSize(20,20);
907 QAccessibleInterface* interface = QAccessible::queryAccessibleInterface(&pushButton);
908 QAccessibleActionInterface* actionInterface = interface->actionInterface();
909 QVERIFY(actionInterface != 0);
910 QCOMPARE(interface->role(), QAccessible::PushButton);
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());
918 QCOMPARE(pushButton.clickCount, 1);
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());
931 QVERIFY(toggleButton.isChecked());
932 QCOMPARE(actionInterface->actionNames().at(0), QAccessibleActionInterface::toggleAction());
933 QVERIFY(interface->state().checked);
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);
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);
957 QTestAccessibility::clearEvents();
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());
968 QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::toggleAction() << QAccessibleActionInterface::setFocusAction());
969 QVERIFY(interface->state().checked);
970 QVERIFY(checkBox.isChecked());
971 QAccessible::State st;
973 QAccessibleStateChangeEvent ev(&checkBox, st);
975 checkBox.setChecked(false);
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());
989 QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::toggleAction() << QAccessibleActionInterface::setFocusAction());
990 QVERIFY(interface->state().checked);
991 QVERIFY(radio.isChecked());
992 QAccessible::State st;
994 QAccessibleStateChangeEvent ev(&radio, st);
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);
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);
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"));
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);
1049 void tst_QAccessibility::scrollBarTest()
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);
1057 QVERIFY(!scrollBarInterface->state().invisible);
1058 QAccessibleEvent show(scrollBar, QAccessible::ObjectShow);
1059 QVERIFY(QTestAccessibility::containsEvent(&show));
1060 QTestAccessibility::clearEvents();
1063 QVERIFY(scrollBarInterface->state().invisible);
1064 QAccessibleEvent hide(scrollBar, QAccessible::ObjectHide);
1065 QVERIFY(QTestAccessibility::containsEvent(&hide));
1066 QTestAccessibility::clearEvents();
1068 // Test that the left/right subcontrols are set to unavailable when the scrollBar is at the minimum/maximum.
1070 scrollBar->setMinimum(11);
1071 scrollBar->setMaximum(111);
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());
1086 const QRect scrollBarRect = scrollBarInterface->rect();
1087 QVERIFY(scrollBarRect.isValid());
1089 delete scrollBarInterface;
1092 QTestAccessibility::clearEvents();
1095 void tst_QAccessibility::tabTest()
1097 QTabBar *tabBar = new QTabBar();
1100 QAccessibleInterface * const interface = QAccessible::queryAccessibleInterface(tabBar);
1102 QCOMPARE(interface->childCount(), 2);
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);
1112 for (int i = 0; i < lots; ++i)
1113 tabBar->addTab("Foo");
1115 QAccessibleInterface *child1 = interface->child(0);
1116 QAccessibleInterface *child2 = interface->child(1);
1118 QCOMPARE(child1->role(), QAccessible::PageTab);
1120 QCOMPARE(child2->role(), QAccessible::PageTab);
1122 QVERIFY((child1->state().invisible) == false);
1125 QCoreApplication::processEvents();
1128 QVERIFY(child1->state().invisible);
1131 tabBar->setCurrentIndex(0);
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);
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);
1148 QTestAccessibility::clearEvents();
1151 void tst_QAccessibility::tabWidgetTest()
1153 QTabWidget *tabWidget = new QTabWidget();
1156 // the interface for the tab is just a container for tabbar and stacked widget
1157 QAccessibleInterface * const interface = QAccessible::queryAccessibleInterface(tabWidget);
1159 QCOMPARE(interface->childCount(), 2);
1160 QCOMPARE(interface->role(), QAccessible::Client);
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");
1168 QCOMPARE(interface->childCount(), 2);
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);
1177 QAccessibleInterface* tabButton1Interface = tabBarInterface->child(0);
1178 QVERIFY(tabButton1Interface);
1179 QCOMPARE(tabButton1Interface->role(), QAccessible::PageTab);
1180 QCOMPARE(tabButton1Interface->text(QAccessible::Name), QLatin1String("Tab 1"));
1182 QAccessibleInterface* tabButton2Interface = tabBarInterface->child(1);
1183 QVERIFY(tabButton1Interface);
1184 QCOMPARE(tabButton2Interface->role(), QAccessible::PageTab);
1185 QCOMPARE(tabButton2Interface->text(QAccessible::Name), QLatin1String("Tab 2"));
1187 QAccessibleInterface* tabButtonLeft = tabBarInterface->child(2);
1188 QVERIFY(tabButtonLeft);
1189 QCOMPARE(tabButtonLeft->role(), QAccessible::PushButton);
1190 QCOMPARE(tabButtonLeft->text(QAccessible::Name), QLatin1String("Scroll Left"));
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;
1201 QAccessibleInterface* stackWidgetInterface = interface->child(0);
1202 QVERIFY(stackWidgetInterface);
1203 QCOMPARE(stackWidgetInterface->childCount(), 2);
1204 QCOMPARE(stackWidgetInterface->role(), QAccessible::LayeredPane);
1206 QAccessibleInterface* stackChild1Interface = stackWidgetInterface->child(0);
1207 QVERIFY(stackChild1Interface);
1209 QCOMPARE(stackChild1Interface->childCount(), 0);
1211 QCOMPARE(stackChild1Interface->role(), QAccessible::StaticText);
1212 QCOMPARE(stackChild1Interface->text(QAccessible::Name), QLatin1String("Page 1"));
1213 QCOMPARE(label1, stackChild1Interface->object());
1215 // Navigation in stack widgets should be consistent
1216 QAccessibleInterface* parent = stackChild1Interface->parent();
1219 QCOMPARE(parent->childCount(), 2);
1221 QCOMPARE(parent->role(), QAccessible::LayeredPane);
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));
1231 parent = stackChild2Interface->parent();
1234 QCOMPARE(parent->childCount(), 2);
1236 QCOMPARE(parent->role(), QAccessible::LayeredPane);
1239 delete tabBarInterface;
1240 delete stackChild1Interface;
1241 delete stackChild2Interface;
1242 delete stackWidgetInterface;
1245 QTestAccessibility::clearEvents();
1248 void tst_QAccessibility::menuTest()
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"));
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");
1274 mw.menuBar()->addSeparator();
1276 QMenu *help = mw.menuBar()->addMenu("&Help");
1277 help->addAction("&Contents");
1278 help->addAction("&About");
1280 mw.menuBar()->addAction("Action!");
1282 mw.show(); // triggers layout
1285 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(mw.menuBar());
1286 QCOMPARE(verifyHierarchy(interface), 0);
1289 QCOMPARE(interface->childCount(), 5);
1290 QCOMPARE(interface->role(), QAccessible::MenuBar);
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);
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);
1305 if (!IsValidCEPlatform())
1306 QSKIP("Tests do not work on Mobile platforms due to native menus");
1308 QCOMPARE(mw.mapFromGlobal(interface->rect().topLeft()), mw.menuBar()->geometry().topLeft());
1309 QCOMPARE(interface->rect().size(), mw.menuBar()->size());
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()));
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!"));
1324 // TODO: Currently not working, task to fix is #100019.
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());
1333 QVERIFY(iFile->actionInterface());
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());
1340 bool menuFade = qApp->isEffectEnabled(Qt::UI_FadeMenu);
1341 int menuFadeDelay = 300;
1342 iFile->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1344 QTest::qWait(menuFadeDelay);
1345 QVERIFY(file->isVisible() && !edit->isVisible() && !help->isVisible());
1346 iEdit->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1348 QTest::qWait(menuFadeDelay);
1349 QVERIFY(!file->isVisible() && edit->isVisible() && !help->isVisible());
1350 iHelp->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1352 QTest::qWait(menuFadeDelay);
1353 QVERIFY(!file->isVisible() && !edit->isVisible() && help->isVisible());
1354 iAction->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1356 QTest::qWait(menuFadeDelay);
1357 QVERIFY(!file->isVisible() && !edit->isVisible() && !help->isVisible());
1359 QVERIFY(interface->actionInterface());
1360 QCOMPARE(interface->actionInterface()->actionNames(), QStringList());
1362 interface = QAccessible::queryAccessibleInterface(file);
1363 QCOMPARE(interface->childCount(), 5);
1364 QCOMPARE(interface->role(), QAccessible::PopupMenu);
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);
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());
1383 QAccessibleInterface *iface = 0;
1384 QAccessibleInterface *iface2 = 0;
1386 // traverse siblings with navigate(Sibling, ...)
1387 iface = interface->child(0);
1389 QCOMPARE(iface->role(), QAccessible::MenuItem);
1391 QAccessible::Role fileRoles[5] = {
1392 QAccessible::MenuItem,
1393 QAccessible::MenuItem,
1394 QAccessible::MenuItem,
1395 QAccessible::Separator,
1396 QAccessible::MenuItem
1398 for (int child = 0; child < 5; ++child) {
1399 iface2 = interface->child(child);
1401 QCOMPARE(iface2->role(), fileRoles[child]);
1407 iface = interface->child(0);
1409 QCOMPARE(iface->role(), QAccessible::MenuItem);
1412 iface2 = iface->child(0);
1416 QCOMPARE(iface->role(), QAccessible::PopupMenu);
1418 // "Text file" menu item
1419 iface2 = iface->child(0);
1423 QCOMPARE(iface->role(), QAccessible::MenuItem);
1427 // move mouse pointer away, since that might influence the
1429 QTest::mouseMove(&mw, QPoint(-1, -1));
1432 QTest::qWait(menuFadeDelay);
1434 iFile->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1435 iFileNew->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1437 QVERIFY(file->isVisible());
1438 QVERIFY(fileNew->isVisible());
1439 QVERIFY(!edit->isVisible());
1440 QVERIFY(!help->isVisible());
1442 QTestAccessibility::clearEvents();
1449 delete iFileSeparator;
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();
1460 QCOMPARE(iface2->role(), QAccessible::Application);
1468 QTestAccessibility::clearEvents();
1471 void tst_QAccessibility::spinBoxTest()
1473 QSpinBox * const spinBox = new QSpinBox();
1474 spinBox->setValue(3);
1477 QAccessibleInterface * const interface = QAccessible::queryAccessibleInterface(spinBox);
1479 QCOMPARE(interface->role(), QAccessible::SpinBox);
1481 QVERIFY(QTest::qWaitForWindowExposed(spinBox));
1483 const QRect widgetRect = spinBox->geometry();
1484 const QRect accessibleRect = interface->rect();
1485 QCOMPARE(accessibleRect, widgetRect);
1486 QCOMPARE(interface->text(QAccessible::Value), QLatin1String("3"));
1488 // one child, the line edit
1489 const int numChildren = interface->childCount();
1490 QCOMPARE(numChildren, 1);
1491 QAccessibleInterface *lineEdit = interface->child(0);
1493 QCOMPARE(lineEdit->role(), QAccessible::EditableText);
1494 QCOMPARE(lineEdit->text(QAccessible::Value), QLatin1String("3"));
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);
1503 spinBox->setFocus();
1504 QTestAccessibility::clearEvents();
1505 QTest::keyPress(spinBox, Qt::Key_Up);
1507 QAccessibleValueChangeEvent expectedEvent(spinBox, spinBox->value());
1508 QVERIFY(QTestAccessibility::containsEvent(&expectedEvent));
1510 QTestAccessibility::clearEvents();
1513 void tst_QAccessibility::doubleSpinBoxTest()
1515 QDoubleSpinBox *doubleSpinBox = new QDoubleSpinBox;
1516 doubleSpinBox->show();
1518 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(doubleSpinBox);
1521 QVERIFY(QTest::qWaitForWindowExposed(doubleSpinBox));
1523 const QRect widgetRect = doubleSpinBox->geometry();
1524 const QRect accessibleRect = interface->rect();
1525 QCOMPARE(accessibleRect, widgetRect);
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());
1536 delete doubleSpinBox;
1537 QTestAccessibility::clearEvents();
1540 static QRect characterRect(const QTextEdit &edit, int offset)
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();
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()));
1559 void tst_QAccessibility::textEditTest()
1561 for (int pass = 0; pass < 2; ++pass) {
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>";
1570 QFont font("Helvetica");
1571 font.setPointSizeF(12.5);
1572 font.setWordSpacing(1.1);
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()));
1593 QCOMPARE(iface->textInterface()->text(offset, offset + 1), QStringLiteral("d"));
1594 QCOMPARE(iface->textInterface()->characterRect(offset), characterRect(edit, offset));
1596 QCOMPARE(iface->textInterface()->text(offset, offset + 1), QStringLiteral("H"));
1597 QCOMPARE(iface->textInterface()->characterRect(offset), characterRect(edit, offset));
1599 QCOMPARE(iface->textInterface()->text(offset, offset + 1), QStringLiteral("y"));
1600 QCOMPARE(iface->textInterface()->characterRect(offset), characterRect(edit, offset));
1602 QCOMPARE(iface->textInterface()->text(offset, offset + 1), QStringLiteral("I"));
1603 QCOMPARE(iface->textInterface()->characterRect(offset), characterRect(edit, offset));
1605 QTestAccessibility::clearEvents();
1608 QTextCursor c = edit.textCursor();
1610 c.setPosition(4, QTextCursor::KeepAnchor);
1611 edit.setTextCursor(c);
1612 QAccessibleTextSelectionEvent sel(&edit, 2, 4);
1613 QVERIFY_EVENT(&sel);
1616 int end = edit.textCursor().position();
1617 sel.setCursorPosition(end);
1618 sel.setSelection(0, end);
1619 QVERIFY_EVENT(&sel);
1621 QTestAccessibility::clearEvents();
1625 void tst_QAccessibility::textBrowserTest()
1628 QTextBrowser textBrowser;
1629 QString text = QLatin1String("Hello world\nhow are you today?\n");
1630 textBrowser.setText(text);
1633 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&textBrowser);
1635 QCOMPARE(iface->role(), QAccessible::StaticText);
1636 QCOMPARE(iface->text(QAccessible::Value), text);
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);
1647 QTestAccessibility::clearEvents();
1650 void tst_QAccessibility::mdiAreaTest()
1654 mdiArea.resize(400,300);
1656 const int subWindowCount = 3;
1657 for (int i = 0; i < subWindowCount; ++i)
1658 mdiArea.addSubWindow(new QWidget, Qt::Dialog)->show();
1660 QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
1661 QCOMPARE(subWindows.count(), subWindowCount);
1663 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&mdiArea);
1665 QCOMPARE(interface->childCount(), subWindowCount);
1668 QTestAccessibility::clearEvents();
1671 void tst_QAccessibility::mdiSubWindowTest()
1676 qApp->setActiveWindow(&mdiArea);
1677 QVERIFY(QTest::qWaitForWindowActive(&mdiArea));
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);
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.
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();
1698 QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
1699 QCOMPARE(subWindows.count(), subWindowCount);
1701 QMdiSubWindow *testWindow = subWindows.at(3);
1702 QVERIFY(testWindow);
1703 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(testWindow);
1707 QCOMPARE(interface->childCount(), 1);
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"));
1716 mdiArea.setActiveSubWindow(testWindow);
1719 QAccessible::State state;
1720 state.focusable = true;
1721 state.focused = true;
1722 state.movable = true;
1723 state.sizeable = true;
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);
1748 const QPoint globalPos = testWindow->mapToGlobal(QPoint(0, 0));
1749 QCOMPARE(interface->rect(), QRect(globalPos, testWindow->size()));
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());
1763 QSKIP("QTBUG-22812");
1765 QCOMPARE(childRect(interface), QRect(globalWidgetPos, widgetGeometry.size()));
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"));
1774 testWindow->widget()->hide();
1775 QCOMPARE(interface->childAt(globalWidgetPos.x(), globalWidgetPos.y()), static_cast<QAccessibleInterface*>(0));
1778 QTestAccessibility::clearEvents();
1781 void tst_QAccessibility::lineEditTest()
1783 QWidget *toplevel = new QWidget;
1785 QLineEdit *le = new QLineEdit;
1786 QAIPtr iface(QAccessible::queryAccessibleInterface(le));
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());
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);
1817 le->setParent(toplevel);
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());
1827 QLineEdit *le2 = new QLineEdit(toplevel);
1830 le2->activateWindow();
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));
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"));
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);
1852 QAIPtr iface(QAccessible::queryAccessibleInterface(le3));
1853 QAccessibleTextInterface* textIface = iface->textInterface();
1855 QTestAccessibility::clearEvents();
1856 le3->setCursorPosition(3);
1857 QCOMPARE(textIface->cursorPosition(), 3);
1859 QAccessibleTextCursorEvent caretEvent(le3, 3);
1860 QTRY_VERIFY(QTestAccessibility::containsEvent(&caretEvent));
1861 QCOMPARE(textIface->selectionCount(), 0);
1862 QTestAccessibility::clearEvents();
1865 QCOMPARE(textIface->text(0, 8), QString::fromLatin1("I always"));
1866 QCOMPARE(textIface->textAtOffset(0, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1("I"));
1869 QCOMPARE(textIface->textBeforeOffset(0, QAccessible2::CharBoundary,&start,&end), QString());
1870 QCOMPARE(textIface->textAfterOffset(0, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1(" "));
1874 QCOMPARE(textIface->textAtOffset(5, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1("a"));
1877 QCOMPARE(textIface->textBeforeOffset(5, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1("w"));
1878 QCOMPARE(textIface->textAfterOffset(5, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1("y"));
1880 QCOMPARE(textIface->textAtOffset(5, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1("always"));
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(". --"));
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. "));
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. "));
1900 QCOMPARE(textIface->textAtOffset(5, QAccessible2::ParagraphBoundary,&start,&end), cite);
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);
1906 QTestAccessibility::clearEvents();
1910 // Test events: cursor movement, selection, text changes
1911 QString text = "Hello, world";
1912 QLineEdit *lineEdit = new QLineEdit(text, toplevel);
1914 QTestAccessibility::clearEvents();
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);
1924 lineEdit->setSelection(2, 4);
1926 QAccessibleTextSelectionEvent sel(lineEdit, 2, 2+4);
1927 QVERIFY_EVENT(&sel);
1929 lineEdit->selectAll();
1930 sel.setSelection(0, lineEdit->text().length());
1931 sel.setCursorPosition(lineEdit->text().length());
1932 QVERIFY_EVENT(&sel);
1934 lineEdit->setSelection(10, -4);
1935 QCOMPARE(lineEdit->cursorPosition(), 6);
1936 QAccessibleTextSelectionEvent sel2(lineEdit, 6, 10);
1937 sel2.setCursorPosition(6);
1938 QVERIFY_EVENT(&sel2);
1940 lineEdit->deselect();
1941 QAccessibleTextSelectionEvent sel3(lineEdit, -1, -1);
1942 sel3.setCursorPosition(6);
1943 QVERIFY_EVENT(&sel3);
1947 // FIXME: improve redundant updates
1948 QAccessibleTextRemoveEvent remove(lineEdit, 0, text);
1949 QVERIFY_EVENT(&remove);
1951 QAccessibleTextSelectionEvent noSel(lineEdit, -1, -1);
1952 QVERIFY_EVENT(&noSel);
1953 QAccessibleTextCursorEvent cursor(lineEdit, 0);
1954 QVERIFY_EVENT(&cursor);
1956 lineEdit->setText("foo");
1957 cursorEvent.setCursorPosition(3);
1958 QVERIFY_EVENT(&cursorEvent);
1960 QAccessibleTextInsertEvent e(lineEdit, 0, "foo");
1961 QVERIFY(QTestAccessibility::containsEvent(&e));
1963 lineEdit->setText("bar");
1964 QAccessibleTextUpdateEvent update(lineEdit, 0, "foo", "bar");
1965 QVERIFY(QTestAccessibility::containsEvent(&update));
1967 // FIXME check what extra events are around and get rid of them
1968 QTestAccessibility::clearEvents();
1970 QTestEventList keys;
1971 keys.addKeyClick('D');
1972 keys.simulate(lineEdit);
1974 QAccessibleTextInsertEvent insertD(lineEdit, 3, "D");
1975 QVERIFY_EVENT(&insertD);
1977 keys.addKeyClick('E');
1978 keys.simulate(lineEdit);
1980 QAccessibleTextInsertEvent insertE(lineEdit, 4, "E");
1981 QVERIFY(QTestAccessibility::containsEvent(&insertE));
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));
1992 keys.addKeyClick('C');
1993 keys.simulate(lineEdit);
1995 QAccessibleTextInsertEvent insertC(lineEdit, 3, "C");
1996 QVERIFY(QTestAccessibility::containsEvent(&insertC));
1999 keys.addKeyClick('O');
2000 keys.simulate(lineEdit);
2001 QAccessibleTextInsertEvent insertO(lineEdit, 4, "O");
2002 QVERIFY(QTestAccessibility::containsEvent(&insertO));
2005 QTestAccessibility::clearEvents();
2008 void tst_QAccessibility::groupBoxTest()
2011 QGroupBox *groupBox = new QGroupBox();
2012 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(groupBox);
2014 groupBox->setTitle(QLatin1String("Test QGroupBox"));
2016 QAccessibleEvent ev(groupBox, QAccessible::NameChanged);
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);
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);
2036 delete relation.first;
2038 delete rButtonIface;
2044 QGroupBox *groupBox = new QGroupBox();
2045 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(groupBox);
2046 QVERIFY(!iface->state().checkable);
2047 groupBox->setCheckable(true);
2049 groupBox->setChecked(false);
2050 QAccessible::State st;
2052 QAccessibleStateChangeEvent ev(groupBox, st);
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);
2074 bool accessibleInterfaceLeftOf(const QAccessibleInterface *a1, const QAccessibleInterface *a2)
2076 return a1->rect().x() < a2->rect().x();
2079 bool accessibleInterfaceAbove(const QAccessibleInterface *a1, const QAccessibleInterface *a2)
2081 return a1->rect().y() < a2->rect().y();
2084 void tst_QAccessibility::dialogButtonBoxTest()
2087 QDialogButtonBox box(QDialogButtonBox::Reset |
2088 QDialogButtonBox::Help |
2089 QDialogButtonBox::Ok, Qt::Horizontal);
2092 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&box);
2095 #if defined(Q_OS_UNIX)
2096 QCoreApplication::processEvents();
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);
2108 QVector<QAccessibleInterface *> buttons;
2109 for (int i = 0; i < iface->childCount(); ++i)
2110 buttons << iface->child(i);
2112 qSort(buttons.begin(), buttons.end(), accessibleInterfaceLeftOf);
2114 for (int i = 0; i < buttons.count(); ++i)
2115 actualOrder << buttons.at(i)->text(QAccessible::Name);
2117 QStringList expectedOrder;
2118 QDialogButtonBox::ButtonLayout btnlout =
2119 QDialogButtonBox::ButtonLayout(QApplication::style()->styleHint(QStyle::SH_DialogButtonLayout));
2121 case QDialogButtonBox::WinLayout:
2122 expectedOrder << QDialogButtonBox::tr("Reset")
2123 << QDialogButtonBox::tr("OK")
2124 << QDialogButtonBox::tr("Help");
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");
2134 QCOMPARE(actualOrder, expectedOrder);
2136 QApplication::processEvents();
2137 QTestAccessibility::clearEvents();
2141 QDialogButtonBox box(QDialogButtonBox::Reset |
2142 QDialogButtonBox::Help |
2143 QDialogButtonBox::Ok, Qt::Horizontal);
2146 // Test up and down navigation
2147 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&box);
2149 box.setOrientation(Qt::Vertical);
2151 #if defined(Q_OS_UNIX)
2152 QCoreApplication::processEvents();
2156 QApplication::processEvents();
2157 QStringList actualOrder;
2159 QVector<QAccessibleInterface *> buttons;
2160 for (int i = 0; i < iface->childCount(); ++i)
2161 buttons << iface->child(i);
2163 qSort(buttons.begin(), buttons.end(), accessibleInterfaceAbove);
2165 for (int i = 0; i < buttons.count(); ++i)
2166 actualOrder << buttons.at(i)->text(QAccessible::Name);
2168 QStringList expectedOrder;
2169 expectedOrder << QDialogButtonBox::tr("OK")
2170 << QDialogButtonBox::tr("Reset")
2171 << QDialogButtonBox::tr("Help");
2173 QCOMPARE(actualOrder, expectedOrder);
2175 QApplication::processEvents();
2178 QTestAccessibility::clearEvents();
2181 void tst_QAccessibility::dialTest()
2185 dial.setMinimum(23);
2186 dial.setMaximum(121);
2188 QCOMPARE(dial.value(), 42);
2191 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&dial);
2193 QCOMPARE(interface->childCount(), 0);
2195 QVERIFY(QTest::qWaitForWindowExposed(&dial));
2197 QCOMPARE(interface->text(QAccessible::Value), QString::number(dial.value()));
2198 QCOMPARE(interface->rect(), dial.geometry());
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);
2206 QCOMPARE(valueIface->currentValue().toInt(), dial.value());
2208 QCOMPARE(valueIface->currentValue().toInt(), dial.value());
2210 QCOMPARE(valueIface->currentValue().toInt(), dial.value());
2211 valueIface->setCurrentValue(77);
2212 QCOMPARE(77, dial.value());
2214 QTestAccessibility::clearEvents();
2217 void tst_QAccessibility::rubberBandTest()
2219 QRubberBand rubberBand(QRubberBand::Rectangle);
2220 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&rubberBand);
2222 QCOMPARE(interface->role(), QAccessible::Border);
2224 QTestAccessibility::clearEvents();
2227 void tst_QAccessibility::abstractScrollAreaTest()
2230 QAbstractScrollArea abstractScrollArea;
2232 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&abstractScrollArea);
2234 QVERIFY(!interface->rect().isValid());
2235 QCOMPARE(interface->childAt(200, 200), static_cast<QAccessibleInterface*>(0));
2237 abstractScrollArea.resize(400, 400);
2238 abstractScrollArea.show();
2239 #if defined(Q_OS_UNIX)
2240 QCoreApplication::processEvents();
2243 const QRect globalGeometry = QRect(abstractScrollArea.mapToGlobal(QPoint(0, 0)),
2244 abstractScrollArea.size());
2247 QCOMPARE(interface->childCount(), 1);
2248 QWidget *viewport = abstractScrollArea.viewport();
2250 QVERIFY(verifyChild(viewport, interface, 0, globalGeometry));
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));
2259 // Horizontal scrollBar widgets.
2260 QLabel *secondLeftLabel = new QLabel(QLatin1String("L2"));
2261 abstractScrollArea.addScrollBarWidget(secondLeftLabel, Qt::AlignLeft);
2262 QCOMPARE(interface->childCount(), 2);
2264 QLabel *firstLeftLabel = new QLabel(QLatin1String("L1"));
2265 abstractScrollArea.addScrollBarWidget(firstLeftLabel, Qt::AlignLeft);
2266 QCOMPARE(interface->childCount(), 2);
2268 QLabel *secondRightLabel = new QLabel(QLatin1String("R2"));
2269 abstractScrollArea.addScrollBarWidget(secondRightLabel, Qt::AlignRight);
2270 QCOMPARE(interface->childCount(), 2);
2272 QLabel *firstRightLabel = new QLabel(QLatin1String("R1"));
2273 abstractScrollArea.addScrollBarWidget(firstRightLabel, Qt::AlignRight);
2274 QCOMPARE(interface->childCount(), 2);
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));
2283 // Vertical scrollBar widgets.
2284 QLabel *secondTopLabel = new QLabel(QLatin1String("T2"));
2285 abstractScrollArea.addScrollBarWidget(secondTopLabel, Qt::AlignTop);
2286 QCOMPARE(interface->childCount(), 3);
2288 QLabel *firstTopLabel = new QLabel(QLatin1String("T1"));
2289 abstractScrollArea.addScrollBarWidget(firstTopLabel, Qt::AlignTop);
2290 QCOMPARE(interface->childCount(), 3);
2292 QLabel *secondBottomLabel = new QLabel(QLatin1String("B2"));
2293 abstractScrollArea.addScrollBarWidget(secondBottomLabel, Qt::AlignBottom);
2294 QCOMPARE(interface->childCount(), 3);
2296 QLabel *firstBottomLabel = new QLabel(QLatin1String("B1"));
2297 abstractScrollArea.addScrollBarWidget(firstBottomLabel, Qt::AlignBottom);
2298 QCOMPARE(interface->childCount(), 3);
2301 abstractScrollArea.setCornerWidget(new QLabel(QLatin1String("C")));
2302 QCOMPARE(interface->childCount(), 4);
2303 QWidget *cornerWidget = abstractScrollArea.cornerWidget();
2304 QVERIFY(verifyChild(cornerWidget, interface, 3, globalGeometry));
2306 QCOMPARE(verifyHierarchy(interface), 0);
2311 QTestAccessibility::clearEvents();
2314 void tst_QAccessibility::scrollAreaTest()
2317 QScrollArea scrollArea;
2319 #if defined(Q_OS_UNIX)
2320 QCoreApplication::processEvents();
2323 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&scrollArea);
2325 QCOMPARE(interface->childCount(), 1); // The viewport.
2328 QTestAccessibility::clearEvents();
2331 void tst_QAccessibility::listTest()
2334 QListWidget *listView = new QListWidget;
2335 listView->addItem("Oslo");
2336 listView->addItem("Berlin");
2337 listView->addItem("Brisbane");
2338 listView->resize(400,400);
2340 QTest::qWait(1); // Need this for indexOfchild to work.
2341 QCoreApplication::processEvents();
2344 QAIPtr iface = QAIPtr(QAccessible::queryAccessibleInterface(listView));
2345 QCOMPARE(verifyHierarchy(iface.data()), 0);
2347 QCOMPARE((int)iface->role(), (int)QAccessible::List);
2348 QCOMPARE(iface->childCount(), 3);
2351 QAIPtr child1 = QAIPtr(iface->child(0));
2353 QCOMPARE(iface->indexOfChild(child1.data()), 0);
2354 QCOMPARE(child1->text(QAccessible::Name), QString("Oslo"));
2355 QCOMPARE(child1->role(), QAccessible::ListItem);
2357 QAIPtr child2 = QAIPtr(iface->child(1));
2359 QCOMPARE(iface->indexOfChild(child2.data()), 1);
2360 QCOMPARE(child2->text(QAccessible::Name), QString("Berlin"));
2362 QAIPtr child3 = QAIPtr(iface->child(2));
2364 QCOMPARE(iface->indexOfChild(child3.data()), 2);
2365 QCOMPARE(child3->text(QAccessible::Name), QString("Brisbane"));
2367 QTestAccessibility::clearEvents();
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());
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));
2386 listView->addItem("Munich");
2387 QCOMPARE(iface->childCount(), 4);
2390 QAccessibleTableInterface *table2 = iface->tableInterface();
2392 QCOMPARE(table2->columnCount(), 1);
2393 QCOMPARE(table2->rowCount(), 4);
2394 QAIPtr cell1 = QAIPtr(table2->cellAt(0,0));
2396 QCOMPARE(cell1->text(QAccessible::Name), QString("Oslo"));
2398 QAIPtr cell4 = QAIPtr(table2->cellAt(3,0));
2400 QCOMPARE(cell4->text(QAccessible::Name), QString("Munich"));
2401 QCOMPARE(cell4->role(), QAccessible::ListItem);
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*>());
2412 QCOMPARE(QAIPtr(cellInterface->table())->object(), listView);
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());
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);
2431 QTestAccessibility::clearEvents();
2434 void tst_QAccessibility::treeTest()
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);
2443 QTreeWidgetItem *root1 = new QTreeWidgetItem;
2444 root1->setText(0, "Spain");
2445 treeView->addTopLevelItem(root1);
2447 QTreeWidgetItem *item1 = new QTreeWidgetItem;
2448 item1->setText(0, "Picasso");
2449 item1->setText(1, "Guernica");
2450 root1->addChild(item1);
2452 QTreeWidgetItem *item2 = new QTreeWidgetItem;
2453 item2->setText(0, "Tapies");
2454 item2->setText(1, "Ambrosia");
2455 root1->addChild(item2);
2457 QTreeWidgetItem *root2 = new QTreeWidgetItem;
2458 root2->setText(0, "Austria");
2459 treeView->addTopLevelItem(root2);
2461 QTreeWidgetItem *item3 = new QTreeWidgetItem;
2462 item3->setText(0, "Klimt");
2463 item3->setText(1, "The Kiss");
2464 root2->addChild(item3);
2466 treeView->resize(400,400);
2469 QCoreApplication::processEvents();
2472 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(treeView);
2473 QCOMPARE(verifyHierarchy(iface), 0);
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);
2479 QAccessibleInterface *header1 = 0;
2480 header1 = iface->child(0);
2482 QCOMPARE(iface->indexOfChild(header1), 0);
2483 QCOMPARE(header1->text(QAccessible::Name), QString("Artist"));
2484 QCOMPARE(header1->role(), QAccessible::ColumnHeader);
2487 QAccessibleInterface *child1 = 0;
2488 child1 = iface->child(2);
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));
2496 QAccessibleInterface *child2 = 0;
2497 child2 = iface->child(4);
2499 QCOMPARE(iface->indexOfChild(child2), 4);
2500 QCOMPARE(child2->text(QAccessible::Name), QString("Austria"));
2503 QTestAccessibility::clearEvents();
2506 QAccessibleTableInterface *table2 = iface->tableInterface();
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"));
2526 treeView->expandAll();
2528 // Need this for indexOfchild to work.
2529 QCoreApplication::processEvents();
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
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);
2546 QCOMPARE(table2->columnDescription(0), QString("Artist"));
2547 QCOMPARE(table2->columnDescription(1), QString("Work"));
2550 QTestAccessibility::clearEvents();
2553 void tst_QAccessibility::tableTest()
2555 QTableWidget *tableView = new QTableWidget(3, 3);
2556 tableView->setColumnCount(3);
2557 QStringList hHeader;
2558 hHeader << "h1" << "h2" << "h3";
2559 tableView->setHorizontalHeaderLabels(hHeader);
2561 QStringList vHeader;
2562 vHeader << "v1" << "v2" << "v3";
2563 tableView->setVerticalHeaderLabels(vHeader);
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);
2571 tableView->resize(600,600);
2573 QTest::qWait(1); // Need this for indexOfchild to work.
2574 QCoreApplication::processEvents();
2577 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(tableView);
2578 QCOMPARE(verifyHierarchy(iface), 0);
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
2584 QAccessibleInterface *cornerButton = iface->child(0);
2585 QVERIFY(cornerButton);
2586 QCOMPARE(iface->indexOfChild(cornerButton), 0);
2587 QCOMPARE(cornerButton->role(), QAccessible::Pane);
2588 delete cornerButton;
2590 QAccessibleInterface *child1 = iface->child(2);
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));
2598 QAccessibleInterface *child2 = iface->child(10);
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);
2607 QAccessibleInterface *child3 = iface->child(11);
2608 QCOMPARE(iface->indexOfChild(child3), 11);
2609 QCOMPARE(child3->text(QAccessible::Name), QString("1.2"));
2612 QTestAccessibility::clearEvents();
2615 QAccessibleTableInterface *table2 = iface->tableInterface();
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);
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);
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);
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"));
2653 QTestAccessibility::clearEvents();
2656 void tst_QAccessibility::calendarWidgetTest()
2658 #ifndef QT_NO_CALENDARWIDGET
2660 QCalendarWidget calendarWidget;
2662 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&calendarWidget);
2664 QCOMPARE(interface->role(), QAccessible::Table);
2665 QVERIFY(!interface->rect().isValid());
2666 QCOMPARE(interface->childAt(200, 200), static_cast<QAccessibleInterface*>(0));
2668 calendarWidget.resize(400, 300);
2669 calendarWidget.show();
2670 #if defined(Q_OS_UNIX)
2671 QCoreApplication::processEvents();
2675 // 1 = navigationBar, 2 = view.
2676 QCOMPARE(interface->childCount(), 2);
2678 const QRect globalGeometry = QRect(calendarWidget.mapToGlobal(QPoint(0, 0)),
2679 calendarWidget.size());
2680 QCOMPARE(interface->rect(), globalGeometry);
2682 QWidget *navigationBar = 0;
2683 foreach (QObject *child, calendarWidget.children()) {
2684 if (child->objectName() == QLatin1String("qt_calendar_navigationbar")) {
2685 navigationBar = static_cast<QWidget *>(child);
2689 QVERIFY(navigationBar);
2690 QVERIFY(verifyChild(navigationBar, interface, 0, globalGeometry));
2692 QAbstractItemView *calendarView = 0;
2693 foreach (QObject *child, calendarWidget.children()) {
2694 if (child->objectName() == QLatin1String("qt_calendar_calendarview")) {
2695 calendarView = static_cast<QAbstractItemView *>(child);
2699 QVERIFY(calendarView);
2700 QVERIFY(verifyChild(calendarView, interface, 1, globalGeometry));
2702 // Hide navigation bar.
2703 calendarWidget.setNavigationBarVisible(false);
2704 QCOMPARE(interface->childCount(), 1);
2705 QVERIFY(!navigationBar->isVisible());
2707 QVERIFY(verifyChild(calendarView, interface, 0, globalGeometry));
2709 // Show navigation bar.
2710 calendarWidget.setNavigationBarVisible(true);
2711 QCOMPARE(interface->childCount(), 2);
2712 QVERIFY(navigationBar->isVisible());
2714 // Navigate to the navigation bar via Child.
2715 QAccessibleInterface *navigationBarInterface = interface->child(0);
2716 QVERIFY(navigationBarInterface);
2717 QCOMPARE(navigationBarInterface->object(), (QObject*)navigationBar);
2719 // Navigate to the view via Child.
2720 QAccessibleInterface *calendarViewInterface = interface->child(1);
2721 QVERIFY(calendarViewInterface);
2722 QCOMPARE(calendarViewInterface->object(), (QObject*)calendarView);
2724 QVERIFY(!interface->child(-1));
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;
2735 QTestAccessibility::clearEvents();
2736 #endif // QT_NO_CALENDARWIDGET
2739 void tst_QAccessibility::dockWidgetTest()
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"));
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);
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);
2760 mw->resize(600,400);
2762 #if defined(Q_OS_UNIX)
2763 QCoreApplication::processEvents();
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) {
2782 QCOMPARE(accDock1->role(), QAccessible::Window);
2784 QAccessibleInterface *dock1TitleBar = accDock1->child(0);
2785 QCOMPARE(dock1TitleBar->role(), QAccessible::TitleBar);
2786 QVERIFY(accDock1->rect().contains(dock1TitleBar->rect()));
2787 delete dock1TitleBar;
2789 QPoint globalPos = dock1->mapToGlobal(QPoint(0,0));
2790 globalPos.rx()+=5; //### query style
2792 QAccessibleInterface *childAt = accDock1->childAt(globalPos.x(), globalPos.y()); //###
2793 QCOMPARE(childAt->role(), QAccessible::TitleBar);
2794 int index = accDock1->indexOfChild(childAt);
2796 QAccessibleInterface *accTitleBar = accDock1->child(index);
2798 QCOMPARE(accTitleBar->role(), QAccessible::TitleBar);
2799 QCOMPARE(accDock1->indexOfChild(accTitleBar), 0);
2800 QAccessibleInterface *acc;
2801 acc = accTitleBar->parent();
2803 QCOMPARE(acc->role(), QAccessible::Window);
2813 QTestAccessibility::clearEvents();
2814 #endif // QT_NO_DOCKWIDGET
2817 void tst_QAccessibility::comboBoxTest()
2819 #if defined(Q_OS_WINCE)
2820 if (!IsValidCEPlatform())
2821 QSKIP("Test skipped on Windows Mobile test hardware");
2823 { // not editable combobox
2825 combo.addItems(QStringList() << "one" << "two" << "three");
2826 // Fully decorated windows have a minimum width of 160 on Windows.
2827 combo.setMinimumWidth(200);
2829 QVERIFY(QTest::qWaitForWindowShown(&combo));
2831 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&combo);
2832 QCOMPARE(verifyHierarchy(iface), 0);
2834 QCOMPARE(iface->role(), QAccessible::ComboBox);
2835 QCOMPARE(iface->childCount(), 1);
2838 QCOMPARE(iface->text(QAccessible::Name), QLatin1String("one"));
2840 QCOMPARE(iface->text(QAccessible::Value), QLatin1String("one"));
2841 combo.setCurrentIndex(2);
2843 QCOMPARE(iface->text(QAccessible::Name), QLatin1String("three"));
2845 QCOMPARE(iface->text(QAccessible::Value), QLatin1String("three"));
2847 QAccessibleInterface *listIface = iface->child(0);
2848 QCOMPARE(listIface->role(), QAccessible::List);
2849 QCOMPARE(listIface->childCount(), 3);
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());
2860 { // editable combobox
2861 QComboBox editableCombo;
2862 editableCombo.setMinimumWidth(200);
2863 editableCombo.show();
2864 editableCombo.setEditable(true);
2865 editableCombo.addItems(QStringList() << "foo" << "bar" << "baz");
2867 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&editableCombo);
2868 QCOMPARE(verifyHierarchy(iface), 0);
2870 QCOMPARE(iface->role(), QAccessible::ComboBox);
2871 QCOMPARE(iface->childCount(), 2);
2873 QAccessibleInterface *listIface = iface->child(0);
2874 QCOMPARE(listIface->role(), QAccessible::List);
2875 QAccessibleInterface *editIface = iface->child(1);
2876 QCOMPARE(editIface->role(), QAccessible::EditableText);
2883 QTestAccessibility::clearEvents();
2886 void tst_QAccessibility::labelTest()
2888 QString text = "Hello World";
2889 QLabel *label = new QLabel(text);
2892 #if defined(Q_OS_UNIX)
2893 QCoreApplication::processEvents();
2897 QAccessibleInterface *acc_label = QAccessible::queryAccessibleInterface(label);
2900 QCOMPARE(acc_label->text(QAccessible::Name), text);
2904 QTestAccessibility::clearEvents();
2906 QPixmap testPixmap(50, 50);
2910 imageLabel.setPixmap(testPixmap);
2911 imageLabel.setToolTip("Test Description");
2913 acc_label = QAccessible::queryAccessibleInterface(&imageLabel);
2916 QAccessibleImageInterface *imageInterface = acc_label->imageInterface();
2917 QVERIFY(imageInterface);
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);
2926 QTestAccessibility::clearEvents();
2929 void tst_QAccessibility::accelerators()
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);
2937 label->setBuddy(le);
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());
2955 #if !defined(QT_NO_DEBUG) && !defined(Q_OS_MAC)
2956 QTest::ignoreMessage(QtWarningMsg, "QKeySequence::mnemonic: \"Q &A&B\" contains multiple occurrences of '&'");
2958 label->setText(tr("Q &A&B"));
2959 QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QKeySequence(Qt::ALT).toString(QKeySequence::NativeText) + QLatin1String("A"));
2961 #if defined(Q_OS_UNIX)
2962 QCoreApplication::processEvents();
2966 QTestAccessibility::clearEvents();
2969 #ifdef QT_SUPPORTS_IACCESSIBLE2
2970 static IUnknown *queryIA2(IAccessible *acc, const IID &iid)
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);
2984 // The control supports IAccessible2.
2985 pService->Release();
2987 return resultInterface;
2991 void tst_QAccessibility::bridgeTest()
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.
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);
3006 QVERIFY(QTest::qWaitForWindowExposed(window));
3009 /**************************************************
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);
3017 // All set, now test the bridge.
3019 pt.x = buttonRect.center().x();
3020 pt.y = buttonRect.center().y();
3021 IAccessible *iaccButton;
3024 HRESULT hr = ::AccessibleObjectFromPoint(pt, &iaccButton, &varChild);
3025 QVERIFY(SUCCEEDED(hr));
3030 // **** Test get_accRole ****
3032 hr = iaccButton->get_accRole(varSELF, &varRole);
3033 QVERIFY(SUCCEEDED(hr));
3035 QCOMPARE(varRole.vt, (VARTYPE)VT_I4);
3036 QCOMPARE(varRole.lVal, (LONG)ROLE_SYSTEM_PUSHBUTTON);
3038 // **** Test accLocation ****
3040 hr = iaccButton->accLocation(&x, &y, &w, &h, varSELF);
3041 QCOMPARE(buttonRect, QRect(x, y, w, h));
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.
3049 /***** Test IAccessibleComponent *****/
3050 IAccessibleComponent *ia2Component = 0;
3051 hr = ia2Button->QueryInterface(IID_IAccessibleComponent, (void**)&ia2Component);
3052 QVERIFY(SUCCEEDED(hr));
3054 hr = ia2Component->get_locationInParent(&x, &y);
3055 QVERIFY(SUCCEEDED(hr));
3056 QCOMPARE(button->pos(), QPoint(x, y));
3057 ia2Component->Release();
3059 /***** Test IAccessibleAction *****/
3060 IAccessibleAction *ia2Action = 0;
3061 hr = ia2Button->QueryInterface(IID_IAccessibleAction, (void**)&ia2Action);
3062 QVERIFY(SUCCEEDED(hr));
3065 ia2Action->nActions(&nActions);
3066 QVERIFY(nActions >= 1); // "Press" and "SetFocus"
3068 ia2Action->get_name(0, &actionName);
3069 QString name((QChar*)actionName);
3070 QCOMPARE(name, QAccessibleActionInterface::pressAction());
3071 ia2Action->Release();
3075 ia2Button->Release();
3078 iaccButton->Release();
3080 /**************************************************
3082 **************************************************/
3083 QWindow *windowHandle = window->windowHandle();
3084 QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
3085 HWND hWnd = (HWND)platform->nativeResourceForWindow("handle", windowHandle);
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));
3093 QCOMPARE(varRole.vt, (VARTYPE)VT_I4);
3094 QCOMPARE(varRole.lVal, (LONG)ROLE_SYSTEM_CLIENT);
3097 hr = iaccWindow->get_accChildCount(&nChildren);
3098 QVERIFY(SUCCEEDED(hr));
3099 QCOMPARE(nChildren, (long)2);
3101 /**************************************************
3103 **************************************************/
3104 // Get the second child (the accessible interface for the text edit)
3105 varChild.vt = VT_I4;
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));
3115 QCOMPARE(varRole.vt, (VARTYPE)VT_I4);
3116 QCOMPARE(varRole.lVal, (LONG)ROLE_SYSTEM_TEXT);
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();
3128 if (IAccessibleText *ia2Text = (IAccessibleText*)queryIA2(iaccTextEdit, IID_IAccessibleText)) {
3130 hr = ia2Text->get_text(12, 15, &txt);
3131 QVERIFY(SUCCEEDED(hr));
3132 QCOMPARE(QString((QChar*)txt), QLatin1String("are"));
3136 iaccTextEdit->Release();
3139 iaccWindow->Release();
3140 QTestAccessibility::clearEvents();
3144 QTEST_MAIN(tst_QAccessibility)
3145 #include "tst_qaccessibility.moc"