1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
43 #include <QtCore/qglobal.h>
45 # include <QtCore/qt_windows.h>
47 # include <servprov.h>
50 # include <Accessible2.h>
51 # include <AccessibleAction.h>
52 # include <AccessibleComponent.h>
55 #include <QtTest/QtTest>
60 #if defined(Q_OS_WIN) && defined(interface)
65 #include "QtTest/qtestaccessible.h"
67 #if defined(Q_OS_WINCE)
68 extern "C" bool SystemParametersInfo(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
69 #define SPI_GETPLATFORMTYPE 257
70 inline bool IsValidCEPlatform() {
71 wchar_t tszPlatform[64];
72 if (SystemParametersInfo(SPI_GETPLATFORMTYPE, sizeof(tszPlatform) / sizeof(*tszPlatform), tszPlatform, 0)) {
73 QString platform = QString::fromWCharArray(tszPlatform);
74 if ((platform == QLatin1String("PocketPC")) || (platform == QLatin1String("Smartphone")))
81 typedef QSharedPointer<QAccessibleInterface> QAIPtr;
83 static inline bool verifyChild(QWidget *child, QAccessibleInterface *interface,
84 int index, const QRect &domain)
87 qWarning("tst_QAccessibility::verifyChild: null pointer to child.");
92 qWarning("tst_QAccessibility::verifyChild: null pointer to interface.");
96 // Verify that we get a valid QAccessibleInterface for the child.
97 QAccessibleInterface *childInterface = QAccessible::queryAccessibleInterface(child);
98 if (!childInterface) {
99 qWarning("tst_QAccessibility::verifyChild: Failed to retrieve interface for child.");
103 // QAccessibleInterface::indexOfChild():
104 // Verify that indexOfChild() returns an index equal to the index passed in
105 int indexFromIndexOfChild = interface->indexOfChild(childInterface);
106 if (indexFromIndexOfChild != index) {
107 qWarning("tst_QAccessibility::verifyChild (indexOfChild()):");
108 qWarning() << "Expected:" << index;
109 qWarning() << "Actual: " << indexFromIndexOfChild;
113 // Navigate to child, compare its object and role with the interface from queryAccessibleInterface(child).
114 QAccessibleInterface *navigatedChildInterface = interface->child(index);
115 if (navigatedChildInterface == 0)
118 const QRect rectFromInterface = navigatedChildInterface->rect();
119 delete navigatedChildInterface;
121 // QAccessibleInterface::childAt():
122 // Calculate global child position and check that the interface
123 // returns the correct index for that position.
124 QPoint globalChildPos = child->mapToGlobal(QPoint(0, 0));
125 QAccessibleInterface *childAtInterface = interface->childAt(globalChildPos.x(), globalChildPos.y());
126 if (!childAtInterface) {
127 qWarning("tst_QAccessibility::verifyChild (childAt()):");
128 qWarning() << "Expected:" << childInterface;
129 qWarning() << "Actual: no child";
132 if (childAtInterface->object() != childInterface->object()) {
133 qWarning("tst_QAccessibility::verifyChild (childAt()):");
134 qWarning() << "Expected:" << childInterface;
135 qWarning() << "Actual: " << childAtInterface;
138 delete childInterface;
139 delete childAtInterface;
141 // QAccessibleInterface::rect():
142 // Calculate global child geometry and check that the interface
143 // returns a QRect which is equal to the calculated QRect.
144 const QRect expectedGlobalRect = QRect(globalChildPos, child->size());
145 if (expectedGlobalRect != rectFromInterface) {
146 qWarning("tst_QAccessibility::verifyChild (rect()):");
147 qWarning() << "Expected:" << expectedGlobalRect;
148 qWarning() << "Actual: " << rectFromInterface;
152 // Verify that the child is within its domain.
153 if (!domain.contains(rectFromInterface)) {
154 qWarning("tst_QAccessibility::verifyChild: Child is not within its domain.");
161 static inline int indexOfChild(QAccessibleInterface *parentInterface, QWidget *childWidget)
163 if (!parentInterface || !childWidget)
165 QAccessibleInterface *childInterface = QAccessible::queryAccessibleInterface(childWidget);
168 int index = parentInterface->indexOfChild(childInterface);
169 delete childInterface;
173 #define EXPECT(cond) \
175 if (!errorAt && !(cond)) { \
176 errorAt = __LINE__; \
177 qWarning("level: %d, middle: %d, role: %d (%s)", treelevel, middle, iface->role(), #cond); \
181 static int verifyHierarchy(QAccessibleInterface *iface)
184 static int treelevel = 0; // for error diagnostics
185 QAccessibleInterface *middleChild, *if2;
188 int middle = iface->childCount()/2 + 1;
189 if (iface->childCount() >= 2) {
190 middleChild = iface->child(middle - 1);
192 for (int i = 0; i < iface->childCount() && !errorAt; ++i) {
193 if2 = iface->child(i);
195 // navigate Ancestor...
196 QAccessibleInterface *parent = if2->parent();
197 EXPECT(iface->object() == parent->object());
200 // navigate Sibling...
201 // if (middleChild) {
202 // entry = if2->navigate(QAccessible::Sibling, middle, &if3);
203 // EXPECT(entry == 0 && if3->object() == middleChild->object());
206 // EXPECT(iface->indexOfChild(middleChild) == middle);
209 // verify children...
211 errorAt = verifyHierarchy(if2);
220 QRect childRect(QAccessibleInterface *iface, int index = 0)
222 QAccessibleInterface *child = iface->child(index);
223 QRect rect = child->rect();
228 class tst_QAccessibility : public QObject
232 tst_QAccessibility();
233 virtual ~tst_QAccessibility();
237 void cleanupTestCase();
243 void deletedWidget();
245 void statesStructTest();
246 void navigateHierarchy();
248 void textAttributes();
253 void applicationTest();
254 void mainWindowTest();
256 void scrollBarTest();
258 void tabWidgetTest();
261 void doubleSpinBoxTest();
263 void textBrowserTest();
265 void mdiSubWindowTest();
268 void dialogButtonBoxTest();
270 void rubberBandTest();
271 void abstractScrollAreaTest();
272 void scrollAreaTest();
278 void calendarWidgetTest();
279 void dockWidgetTest();
281 void accessibleName();
292 const double Q_PI = 3.14159265358979323846;
294 QAccessible::State state(QWidget * const widget)
296 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(widget);
298 qWarning() << "Cannot get QAccessibleInterface for widget";
299 QAccessible::State state = (iface ? iface->state() : QAccessible::State());
304 class QtTestAccessibleWidget: public QWidget
308 QtTestAccessibleWidget(QWidget *parent, const char *name): QWidget(parent)
312 pal.setColor(backgroundRole(), Qt::black);//black is beautiful
318 class QtTestAccessibleWidgetIface: public QAccessibleWidget
321 QtTestAccessibleWidgetIface(QtTestAccessibleWidget *w): QAccessibleWidget(w) {}
322 QString text(QAccessible::Text t) const
324 if (t == QAccessible::Help)
325 return QString::fromLatin1("Help yourself");
326 return QAccessibleWidget::text(t);
328 static QAccessibleInterface *ifaceFactory(const QString &key, QObject *o)
330 if (key == "QtTestAccessibleWidget")
331 return new QtTestAccessibleWidgetIface(static_cast<QtTestAccessibleWidget*>(o));
336 tst_QAccessibility::tst_QAccessibility()
341 tst_QAccessibility::~tst_QAccessibility()
345 void tst_QAccessibility::onClicked()
350 void tst_QAccessibility::initTestCase()
352 QTestAccessibility::initialize();
353 QAccessible::installFactory(QtTestAccessibleWidgetIface::ifaceFactory);
356 void tst_QAccessibility::cleanupTestCase()
358 QTestAccessibility::cleanup();
361 void tst_QAccessibility::init()
363 QTestAccessibility::clearEvents();
366 void tst_QAccessibility::cleanup()
368 const EventList list = QTestAccessibility::events();
369 if (!list.isEmpty()) {
370 qWarning("%d accessibility event(s) were not handled in testfunction '%s':", list.count(),
371 QString(QTest::currentTestFunction()).toAscii().constData());
372 for (int i = 0; i < list.count(); ++i)
373 qWarning(" %d: Object: %p Event: '%s' Child: %d", i + 1, list.at(i)->object(),
374 qAccessibleEventString(list.at(i)->type()), list.at(i)->child());
376 QTestAccessibility::clearEvents();
379 void tst_QAccessibility::eventTest()
381 QPushButton* button = new QPushButton(0);
382 button->setObjectName(QString("Olaf"));
385 QAccessibleEvent showEvent(button, QAccessible::ObjectShow);
386 QVERIFY_EVENT(&showEvent);
387 button->setFocus(Qt::MouseFocusReason);
388 QTestAccessibility::clearEvents();
389 QTest::mouseClick(button, Qt::LeftButton, 0);
391 button->setAccessibleName("Olaf the second");
392 QAccessibleEvent nameEvent(button, QAccessible::NameChanged);
393 QVERIFY_EVENT(&nameEvent);
394 button->setAccessibleDescription("This is a button labeled Olaf");
395 QAccessibleEvent descEvent(button, QAccessible::DescriptionChanged);
396 QVERIFY_EVENT(&descEvent);
399 QAccessibleEvent hideEvent(button, QAccessible::ObjectHide);
400 QVERIFY_EVENT(&hideEvent);
405 void tst_QAccessibility::customWidget()
407 QtTestAccessibleWidget* widget = new QtTestAccessibleWidget(0, "Heinz");
409 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(widget);
411 QVERIFY(iface->isValid());
412 QCOMPARE(iface->object(), (QObject*)widget);
413 QCOMPARE(iface->object()->objectName(), QString("Heinz"));
414 QCOMPARE(iface->text(QAccessible::Help), QString("Help yourself"));
420 void tst_QAccessibility::deletedWidget()
422 QtTestAccessibleWidget *widget = new QtTestAccessibleWidget(0, "Ralf");
423 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(widget);
425 QVERIFY(iface->isValid());
426 QCOMPARE(iface->object(), (QObject*)widget);
430 QVERIFY(!iface->isValid());
434 void tst_QAccessibility::statesStructTest()
436 QAccessible::State s1;
437 QVERIFY(s1.disabled == 0);
438 QVERIFY(s1.focusable == 0);
439 QVERIFY(s1.modal == 0);
441 QAccessible::State s2;
444 QVERIFY(!(s2 == s1));
447 s1 = QAccessible::State();
448 QVERIFY(!(s2 == s1));
451 QVERIFY(s1.busy == 1);
454 void tst_QAccessibility::sliderTest()
457 QSlider *slider = new QSlider(0);
458 slider->setObjectName(QString("Slidy"));
460 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(slider);
462 QVERIFY(iface->isValid());
464 QCOMPARE(iface->childCount(), 0);
465 QCOMPARE(iface->role(), QAccessible::Slider);
467 QAccessibleValueInterface *valueIface = iface->valueInterface();
468 QVERIFY(valueIface != 0);
469 QCOMPARE(valueIface->minimumValue().toInt(), slider->minimum());
470 QCOMPARE(valueIface->maximumValue().toInt(), slider->maximum());
471 slider->setValue(50);
472 QCOMPARE(valueIface->currentValue().toInt(), slider->value());
474 QCOMPARE(valueIface->currentValue().toInt(), slider->value());
475 slider->setValue(100);
476 QCOMPARE(valueIface->currentValue().toInt(), slider->value());
477 valueIface->setCurrentValue(77);
478 QCOMPARE(77, slider->value());
483 QTestAccessibility::clearEvents();
486 void tst_QAccessibility::navigateHierarchy()
489 QWidget *w = new QWidget(0);
490 w->setObjectName(QString("Hans"));
492 QWidget *w1 = new QWidget(w);
493 w1->setObjectName(QString("1"));
495 QWidget *w2 = new QWidget(w);
496 w2->setObjectName(QString("2"));
498 QWidget *w3 = new QWidget(w);
499 w3->setObjectName(QString("3"));
501 QWidget *w31 = new QWidget(w3);
502 w31->setObjectName(QString("31"));
505 QAccessibleInterface *target = 0;
506 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(w);
508 QVERIFY(iface->isValid());
510 target = iface->child(14);
511 QVERIFY(target == 0);
512 target = iface->child(-1);
513 QVERIFY(target == 0);
514 target = iface->child(0);
515 QAccessibleInterface *interfaceW1 = iface->child(0);
517 QVERIFY(target->isValid());
518 QCOMPARE(target->object(), (QObject*)w1);
519 QVERIFY(interfaceW1 != 0);
520 QVERIFY(interfaceW1->isValid());
521 QCOMPARE(interfaceW1->object(), (QObject*)w1);
523 delete iface; iface = 0;
525 iface = QAccessible::queryAccessibleInterface(w);
526 target = iface->child(2);
527 QVERIFY(target != 0);
528 QVERIFY(target->isValid());
529 QCOMPARE(target->object(), (QObject*)w3);
530 delete iface; iface = 0;
533 iface = target->child(1);
534 QCOMPARE(iface, (QAccessibleInterface*)0);
535 iface = target->child(0);
537 QVERIFY(iface->isValid());
538 QCOMPARE(iface->object(), (QObject*)w31);
540 iface = QAccessible::queryAccessibleInterface(w);
541 QAccessibleInterface *acc3 = iface->child(2);
542 target = acc3->child(0);
545 QCOMPARE(target->object(), (QObject*)w31);
547 iface = target->parent();
549 QVERIFY(iface->isValid());
550 QCOMPARE(iface->object(), (QObject*)w3);
551 delete iface; iface = 0;
552 delete target; target = 0;
556 QTestAccessibility::clearEvents();
559 #define QSETCOMPARE(thetypename, elements, otherelements) \
560 QCOMPARE((QSet<thetypename>() << elements), (QSet<thetypename>() << otherelements))
562 static QWidget *createWidgets()
564 QWidget *w = new QWidget();
566 QHBoxLayout *box = new QHBoxLayout(w);
569 box->addWidget(new QComboBox(w));
570 box->addWidget(new QPushButton(QString::fromAscii("widget text %1").arg(i++), w));
571 box->addWidget(new QHeaderView(Qt::Vertical, w));
572 box->addWidget(new QTreeView(w));
573 box->addWidget(new QTreeWidget(w));
574 box->addWidget(new QListView(w));
575 box->addWidget(new QListWidget(w));
576 box->addWidget(new QTableView(w));
577 box->addWidget(new QTableWidget(w));
578 box->addWidget(new QCalendarWidget(w));
579 box->addWidget(new QDialogButtonBox(w));
580 box->addWidget(new QGroupBox(QString::fromAscii("widget text %1").arg(i++), w));
581 box->addWidget(new QFrame(w));
582 box->addWidget(new QLineEdit(QString::fromAscii("widget text %1").arg(i++), w));
583 box->addWidget(new QProgressBar(w));
584 box->addWidget(new QTabWidget(w));
585 box->addWidget(new QCheckBox(QString::fromAscii("widget text %1").arg(i++), w));
586 box->addWidget(new QRadioButton(QString::fromAscii("widget text %1").arg(i++), w));
587 box->addWidget(new QDial(w));
588 box->addWidget(new QScrollBar(w));
589 box->addWidget(new QSlider(w));
590 box->addWidget(new QDateTimeEdit(w));
591 box->addWidget(new QDoubleSpinBox(w));
592 box->addWidget(new QSpinBox(w));
593 box->addWidget(new QLabel(QString::fromAscii("widget text %1").arg(i++), w));
594 box->addWidget(new QLCDNumber(w));
595 box->addWidget(new QStackedWidget(w));
596 box->addWidget(new QToolBox(w));
597 box->addWidget(new QLabel(QString::fromAscii("widget text %1").arg(i++), w));
598 box->addWidget(new QTextEdit(QString::fromAscii("widget text %1").arg(i++), w));
601 * QAbstractItemView, QGraphicsView, QScrollArea,
602 * QToolButton, QDockWidget, QFocusFrame, QMainWindow, QMenu, QMenuBar, QSizeGrip, QSplashScreen, QSplitterHandle,
603 * QStatusBar, QSvgWidget, QTabBar, QToolBar, QSplitter
608 void tst_QAccessibility::accessibleName()
610 QWidget *toplevel = createWidgets();
612 #if defined(Q_OS_UNIX)
613 QCoreApplication::processEvents();
616 QLayout *lout = toplevel->layout();
617 for (int i = 0; i < lout->count(); i++) {
618 QLayoutItem *item = lout->itemAt(i);
619 QWidget *child = item->widget();
621 QString name = tr("Widget Name %1").arg(i);
622 child->setAccessibleName(name);
623 QAccessibleInterface *acc = QAccessible::queryAccessibleInterface(child);
624 QCOMPARE(acc->text(QAccessible::Name), name);
626 QString desc = tr("Widget Description %1").arg(i);
627 child->setAccessibleDescription(desc);
628 QCOMPARE(acc->text(QAccessible::Description), desc);
633 QTestAccessibility::clearEvents();
636 void tst_QAccessibility::textAttributes()
642 QString text("<html><head></head><body>"
643 "Hello, <b>this</b> is an <i><b>example</b> text</i>."
644 "<span style=\"font-family: monospace\">Multiple fonts are used.</span>"
645 "Multiple <span style=\"font-size: 8pt\">text sizes</span> are used."
646 "Let's give some color to <span style=\"color:#f0f1f2; background-color:#14f01e\">Qt</span>."
649 textEdit.setText(text);
650 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&textEdit);
652 QAccessibleTextInterface *textInterface=interface->textInterface();
654 QVERIFY(textInterface);
655 QCOMPARE(textInterface->characterCount(), 112);
657 attributes = textInterface->attributes(10, &startOffset, &endOffset);
658 QCOMPARE(startOffset, 7);
659 QCOMPARE(endOffset, 11);
660 attributes.prepend(';');
661 QVERIFY(attributes.contains(QLatin1String(";font-weight:bold;")));
663 attributes = textInterface->attributes(18, &startOffset, &endOffset);
664 QCOMPARE(startOffset, 18);
665 QCOMPARE(endOffset, 25);
666 attributes.prepend(';');
667 QVERIFY(attributes.contains(QLatin1String(";font-weight:bold;")));
668 QVERIFY(attributes.contains(QLatin1String(";font-style:italic;")));
670 attributes = textInterface->attributes(34, &startOffset, &endOffset);
671 QCOMPARE(startOffset, 31);
672 QCOMPARE(endOffset, 55);
673 attributes.prepend(';');
674 QVERIFY(attributes.contains(QLatin1String(";font-family:\"monospace\";")));
676 attributes = textInterface->attributes(65, &startOffset, &endOffset);
677 QCOMPARE(startOffset, 64);
678 QCOMPARE(endOffset, 74);
679 attributes.prepend(';');
680 QVERIFY(attributes.contains(QLatin1String(";font-size:8pt;")));
682 attributes = textInterface->attributes(110, &startOffset, &endOffset);
683 QCOMPARE(startOffset, 109);
684 QCOMPARE(endOffset, 111);
685 attributes.prepend(';');
686 QVERIFY(attributes.contains(QLatin1String(";background-color:rgb(20,240,30);")));
687 QVERIFY(attributes.contains(QLatin1String(";color:rgb(240,241,242);")));
690 void tst_QAccessibility::hideShowTest()
692 QWidget * const window = new QWidget();
693 QWidget * const child = new QWidget(window);
695 QVERIFY(state(window).invisible);
696 QVERIFY(state(child).invisible);
698 QTestAccessibility::clearEvents();
700 // show() and veryfy that both window and child are not invisible and get ObjectShow events.
702 QVERIFY(!state(window).invisible);
703 QVERIFY(!state(child).invisible);
705 QAccessibleEvent show(window, QAccessible::ObjectShow);
706 QVERIFY(QTestAccessibility::containsEvent(&show));
707 QAccessibleEvent showChild(child, QAccessible::ObjectShow);
708 QVERIFY(QTestAccessibility::containsEvent(&showChild));
709 QTestAccessibility::clearEvents();
711 // hide() and veryfy that both window and child are invisible and get ObjectHide events.
713 QVERIFY(state(window).invisible);
714 QVERIFY(state(child).invisible);
715 QAccessibleEvent hide(window, QAccessible::ObjectHide);
716 QVERIFY(QTestAccessibility::containsEvent(&hide));
717 QAccessibleEvent hideChild(child, QAccessible::ObjectHide);
718 QVERIFY(QTestAccessibility::containsEvent(&hideChild));
719 QTestAccessibility::clearEvents();
722 QTestAccessibility::clearEvents();
726 void tst_QAccessibility::actionTest()
729 QCOMPARE(QAccessibleActionInterface::pressAction(), QString(QStringLiteral("Press")));
731 QWidget *widget = new QWidget;
732 widget->setFocusPolicy(Qt::NoFocus);
735 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(widget);
737 QVERIFY(interface->isValid());
738 QAccessibleActionInterface *actions = interface->actionInterface();
741 // no actions by default, except when focusable
742 QCOMPARE(actions->actionNames(), QStringList());
743 widget->setFocusPolicy(Qt::StrongFocus);
744 QCOMPARE(actions->actionNames(), QStringList(QAccessibleActionInterface::setFocusAction()));
749 QTestAccessibility::clearEvents();
752 QPushButton *button = new QPushButton;
754 QTest::qWaitForWindowShown(button);
755 button->clearFocus();
756 QCOMPARE(button->hasFocus(), false);
757 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(button);
758 QAccessibleActionInterface *actions = interface->actionInterface();
761 // Make sure the "primary action" press comes first!
762 QCOMPARE(actions->actionNames(), QStringList() << QAccessibleActionInterface::pressAction() << QAccessibleActionInterface::setFocusAction());
764 actions->doAction(QAccessibleActionInterface::setFocusAction());
766 QCOMPARE(button->hasFocus(), true);
768 connect(button, SIGNAL(clicked()), this, SLOT(onClicked()));
769 QCOMPARE(click_count, 0);
770 actions->doAction(QAccessibleActionInterface::pressAction());
772 QCOMPARE(click_count, 1);
777 QTestAccessibility::clearEvents();
780 void tst_QAccessibility::applicationTest()
782 QLatin1String name = QLatin1String("My Name");
783 qApp->setApplicationName(name);
784 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(qApp);
785 QCOMPARE(interface->text(QAccessible::Name), name);
786 QCOMPARE(interface->role(), QAccessible::Application);
790 void tst_QAccessibility::mainWindowTest()
793 QMainWindow *mw = new QMainWindow;
794 mw->resize(300, 200);
795 mw->show(); // triggers layout
797 QLatin1String name = QLatin1String("I am the main window");
798 mw->setWindowTitle(name);
799 QTest::qWaitForWindowShown(mw);
800 QAccessibleEvent show(mw, QAccessible::ObjectShow);
801 QVERIFY_EVENT(&show);
803 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(mw);
804 QCOMPARE(iface->text(QAccessible::Name), name);
805 QCOMPARE(iface->role(), QAccessible::Window);
806 QVERIFY(iface->state().active);
808 QAccessible::State activeState;
809 activeState.active = true;
810 QAccessibleStateChangeEvent active(mw, activeState);
811 QVERIFY_EVENT(&active);
816 QTestAccessibility::clearEvents();
820 window.setGeometry(80, 80, 40, 40);
822 QTRY_VERIFY(QGuiApplication::focusWindow() == &window);
824 // We currently don't have an accessible interface for QWindow
825 // the active state is either in the QMainWindow or QQuickView
826 // QAIPtr windowIface(QAccessible::queryAccessibleInterface(&window));
827 // QVERIFY(windowIface->state().active);
829 QAccessible::State activeState;
830 activeState.active = true;
831 QAccessibleStateChangeEvent active(&window, activeState);
832 QVERIFY_EVENT(&active);
835 child.setParent(&window);
836 child.setGeometry(10, 10, 20, 20);
839 child.requestActivateWindow();
840 QTRY_VERIFY(QGuiApplication::focusWindow() == &child);
842 QAccessibleStateChangeEvent deactivate(&window, activeState);
843 QVERIFY_EVENT(&deactivate); // deactivation of parent
845 QAccessibleStateChangeEvent activeChild(&child, activeState);
846 QVERIFY_EVENT(&activeChild);
850 class CounterButton : public QPushButton {
853 CounterButton(const QString& name, QWidget* parent)
854 : QPushButton(name, parent), clickCount(0)
856 connect(this, SIGNAL(clicked(bool)), SLOT(incClickCount()));
860 void incClickCount() {
865 static QAccessibleInterface *relatedInterface(QAccessibleInterface *iface, QAccessible::RelationFlag flag)
867 typedef QPair<QAccessibleInterface *, QAccessible::Relation> RelationPair;
868 QVector<RelationPair> rels = iface->relations(flag);
870 for (int i = 1; i < rels.count(); ++i)
871 delete rels.at(i).first;
873 return rels.value(0).first;
876 void tst_QAccessibility::buttonTest()
879 window.setLayout(new QVBoxLayout);
881 // Standard push button
882 CounterButton pushButton("Ok", &window);
885 QPushButton toggleButton("Toggle", &window);
886 toggleButton.setCheckable(true);
889 QCheckBox checkBox("Check me!", &window);
892 QCheckBox tristate("Tristate!", &window);
893 tristate.setTristate(true);
896 QRadioButton radio("Radio me!", &window);
898 // standard toolbutton
899 QToolButton toolbutton(&window);
900 toolbutton.setText("Tool");
901 toolbutton.setMinimumSize(20,20);
903 // standard toolbutton
904 QToolButton toggletool(&window);
905 toggletool.setCheckable(true);
906 toggletool.setText("Toggle");
907 toggletool.setMinimumSize(20,20);
909 // test Controller/Controlled relations
911 QCheckBox toggler("Toggle me!", &window);
912 bool ok = connect(&pushButton, SIGNAL(clicked()), &toggler, SLOT(toggle()));
914 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&toggler);
916 QCOMPARE(iface->role(), QAccessible::CheckBox);
917 QAccessibleInterface *buttonIFace = relatedInterface(iface, QAccessible::Controller);
918 QVERIFY(buttonIFace);
919 QCOMPARE(buttonIFace->role(), QAccessible::Button);
920 QCOMPARE(buttonIFace->object(), &pushButton);
924 buttonIFace = QAccessible::queryAccessibleInterface(&pushButton);
925 QVERIFY(buttonIFace);
926 QCOMPARE(buttonIFace->role(), QAccessible::Button);
927 iface = relatedInterface(buttonIFace, QAccessible::Controlled);
929 QCOMPARE(iface->object(), &toggler);
934 QAccessibleInterface* interface = QAccessible::queryAccessibleInterface(&pushButton);
935 QAccessibleActionInterface* actionInterface = interface->actionInterface();
936 QVERIFY(actionInterface != 0);
937 QCOMPARE(interface->role(), QAccessible::PushButton);
939 // buttons only have a click action
940 QCOMPARE(actionInterface->actionNames().size(), 2);
941 QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::pressAction() << QAccessibleActionInterface::setFocusAction());
942 QCOMPARE(pushButton.clickCount, 0);
943 actionInterface->doAction(QAccessibleActionInterface::pressAction());
945 QCOMPARE(pushButton.clickCount, 1);
948 // test toggle button
949 interface = QAccessible::queryAccessibleInterface(&toggleButton);
950 actionInterface = interface->actionInterface();
951 QCOMPARE(interface->role(), QAccessible::CheckBox);
952 QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::checkAction() << QAccessibleActionInterface::setFocusAction());
953 QCOMPARE(actionInterface->localizedActionDescription(QAccessibleActionInterface::checkAction()), QString("Checks the checkbox"));
954 QVERIFY(!toggleButton.isChecked());
955 QVERIFY(!interface->state().checked);
956 actionInterface->doAction(QAccessibleActionInterface::checkAction());
958 QVERIFY(toggleButton.isChecked());
959 QCOMPARE(actionInterface->actionNames().at(0), QAccessibleActionInterface::uncheckAction());
960 QVERIFY(interface->state().checked);
964 // test menu push button
965 QAction *foo = new QAction("Foo", 0);
966 foo->setShortcut(QKeySequence("Ctrl+F"));
967 QMenu *menu = new QMenu();
968 menu->addAction(foo);
969 QPushButton menuButton;
970 menuButton.setMenu(menu);
972 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&menuButton);
973 QCOMPARE(interface->role(), QAccessible::ButtonMenu);
974 QVERIFY(interface->state().hasPopup);
975 QCOMPARE(interface->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::showMenuAction() << QAccessibleActionInterface::setFocusAction());
976 // showing the menu enters a new event loop...
977 // interface->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
978 // QTest::qWait(500);
984 QTestAccessibility::clearEvents();
987 interface = QAccessible::queryAccessibleInterface(&checkBox);
988 actionInterface = interface->actionInterface();
989 QCOMPARE(interface->role(), QAccessible::CheckBox);
990 QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::checkAction() << QAccessibleActionInterface::setFocusAction());
991 QVERIFY(!interface->state().checked);
992 actionInterface->doAction(QAccessibleActionInterface::checkAction());
995 QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::uncheckAction() << QAccessibleActionInterface::setFocusAction());
996 QVERIFY(interface->state().checked);
997 QVERIFY(checkBox.isChecked());
998 QAccessible::State st;
1000 QAccessibleStateChangeEvent ev(&checkBox, st);
1002 checkBox.setChecked(false);
1009 interface = QAccessible::queryAccessibleInterface(&radio);
1010 actionInterface = interface->actionInterface();
1011 QCOMPARE(interface->role(), QAccessible::RadioButton);
1012 QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::checkAction() << QAccessibleActionInterface::setFocusAction());
1013 QVERIFY(!interface->state().checked);
1014 actionInterface->doAction(QAccessibleActionInterface::checkAction());
1016 QCOMPARE(actionInterface->actionNames(), QStringList() << QAccessibleActionInterface::checkAction() << QAccessibleActionInterface::setFocusAction());
1017 QVERIFY(interface->state().checked);
1018 QVERIFY(radio.isChecked());
1019 QAccessible::State st;
1021 QAccessibleStateChangeEvent ev(&radio, st);
1026 // // test standard toolbutton
1027 // QVERIFY(QAccessible::queryAccessibleInterface(&toolbutton, &test));
1028 // QCOMPARE(test->role(), QAccessible::PushButton);
1029 // QCOMPARE(test->defaultAction(0), QAccessible::Press);
1030 // QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press"));
1031 // QCOMPARE(test->state(), (int)QAccessible::Normal);
1034 // // toggle tool button
1035 // QVERIFY(QAccessible::queryAccessibleInterface(&toggletool, &test));
1036 // QCOMPARE(test->role(), QAccessible::CheckBox);
1037 // QCOMPARE(test->defaultAction(0), QAccessible::Press);
1038 // QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check"));
1039 // QCOMPARE(test->state(), (int)QAccessible::Normal);
1040 // QVERIFY(test->doAction(QAccessible::Press, 0));
1041 // QTest::qWait(500);
1042 // QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck"));
1043 // QCOMPARE(test->state(), (int)QAccessible::Checked);
1046 // // test menu toolbutton
1047 // QVERIFY(QAccessible::queryAccessibleInterface(&menuToolButton, &test));
1048 // QCOMPARE(test->role(), QAccessible::ButtonMenu);
1049 // QCOMPARE(test->defaultAction(0), 1);
1050 // QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Open"));
1051 // QCOMPARE(test->state(), (int)QAccessible::HasPopup);
1052 // QCOMPARE(test->actionCount(0), 1);
1053 // QCOMPARE(test->actionText(QAccessible::Press, QAccessible::Name, 0), QString("Press"));
1056 // // test split menu toolbutton
1057 // QVERIFY(QAccessible::queryAccessibleInterface(&splitToolButton, &test));
1058 // QCOMPARE(test->childCount(), 2);
1059 // QCOMPARE(test->role(), QAccessible::ButtonDropDown);
1060 // QCOMPARE(test->role(1), QAccessible::PushButton);
1061 // QCOMPARE(test->role(2), QAccessible::ButtonMenu);
1062 // QCOMPARE(test->defaultAction(0), QAccessible::Press);
1063 // QCOMPARE(test->defaultAction(1), QAccessible::Press);
1064 // QCOMPARE(test->defaultAction(2), QAccessible::Press);
1065 // QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press"));
1066 // QCOMPARE(test->state(), (int)QAccessible::HasPopup);
1067 // QCOMPARE(test->actionCount(0), 1);
1068 // QCOMPARE(test->actionText(1, QAccessible::Name, 0), QString("Open"));
1069 // QCOMPARE(test->actionText(test->defaultAction(1), QAccessible::Name, 1), QString("Press"));
1070 // QCOMPARE(test->state(1), (int)QAccessible::Normal);
1071 // QCOMPARE(test->actionText(test->defaultAction(2), QAccessible::Name, 2), QString("Open"));
1072 // QCOMPARE(test->state(2), (int)QAccessible::HasPopup);
1076 void tst_QAccessibility::scrollBarTest()
1078 QScrollBar *scrollBar = new QScrollBar(Qt::Horizontal);
1079 QAccessibleInterface * const scrollBarInterface = QAccessible::queryAccessibleInterface(scrollBar);
1080 QVERIFY(scrollBarInterface);
1081 QVERIFY(scrollBarInterface->state().invisible);
1082 scrollBar->resize(200, 50);
1084 QVERIFY(!scrollBarInterface->state().invisible);
1085 QAccessibleEvent show(scrollBar, QAccessible::ObjectShow);
1086 QVERIFY(QTestAccessibility::containsEvent(&show));
1087 QTestAccessibility::clearEvents();
1090 QVERIFY(scrollBarInterface->state().invisible);
1091 QAccessibleEvent hide(scrollBar, QAccessible::ObjectHide);
1092 QVERIFY(QTestAccessibility::containsEvent(&hide));
1093 QTestAccessibility::clearEvents();
1095 // Test that the left/right subcontrols are set to unavailable when the scrollBar is at the minimum/maximum.
1097 scrollBar->setMinimum(11);
1098 scrollBar->setMaximum(111);
1100 QAccessibleValueInterface *valueIface = scrollBarInterface->valueInterface();
1101 QVERIFY(valueIface != 0);
1102 QCOMPARE(valueIface->minimumValue().toInt(), scrollBar->minimum());
1103 QCOMPARE(valueIface->maximumValue().toInt(), scrollBar->maximum());
1104 scrollBar->setValue(50);
1105 QCOMPARE(valueIface->currentValue().toInt(), scrollBar->value());
1106 scrollBar->setValue(0);
1107 QCOMPARE(valueIface->currentValue().toInt(), scrollBar->value());
1108 scrollBar->setValue(100);
1109 QCOMPARE(valueIface->currentValue().toInt(), scrollBar->value());
1110 valueIface->setCurrentValue(77);
1111 QCOMPARE(77, scrollBar->value());
1113 const QRect scrollBarRect = scrollBarInterface->rect();
1114 QVERIFY(scrollBarRect.isValid());
1116 delete scrollBarInterface;
1119 QTestAccessibility::clearEvents();
1122 void tst_QAccessibility::tabTest()
1124 QTabBar *tabBar = new QTabBar();
1127 QAccessibleInterface * const interface = QAccessible::queryAccessibleInterface(tabBar);
1129 QCOMPARE(interface->childCount(), 2);
1131 // Test that the Invisible bit for the navigation buttons gets set
1132 // and cleared correctly.
1133 QAccessibleInterface *leftButton = interface->child(0);
1134 QCOMPARE(leftButton->role(), QAccessible::PushButton);
1135 QVERIFY(leftButton->state().invisible);
1139 for (int i = 0; i < lots; ++i)
1140 tabBar->addTab("Foo");
1142 QAccessibleInterface *child1 = interface->child(0);
1143 QAccessibleInterface *child2 = interface->child(1);
1145 QCOMPARE(child1->role(), QAccessible::PageTab);
1147 QCOMPARE(child2->role(), QAccessible::PageTab);
1149 QVERIFY((child1->state().invisible) == false);
1152 QCoreApplication::processEvents();
1155 QVERIFY(child1->state().invisible);
1158 tabBar->setCurrentIndex(0);
1160 // Test that sending a focus action to a tab does not select it.
1161 // child2->doAction(QAccessible::Focus, 2, QVariantList());
1162 QCOMPARE(tabBar->currentIndex(), 0);
1164 // Test that sending a press action to a tab selects it.
1165 QVERIFY(child2->actionInterface());
1166 QCOMPARE(child2->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::pressAction());
1167 QCOMPARE(tabBar->currentIndex(), 0);
1168 child2->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
1169 QCOMPARE(tabBar->currentIndex(), 1);
1175 QTestAccessibility::clearEvents();
1178 void tst_QAccessibility::tabWidgetTest()
1180 QTabWidget *tabWidget = new QTabWidget();
1183 // the interface for the tab is just a container for tabbar and stacked widget
1184 QAccessibleInterface * const interface = QAccessible::queryAccessibleInterface(tabWidget);
1186 QCOMPARE(interface->childCount(), 2);
1187 QCOMPARE(interface->role(), QAccessible::Client);
1189 // Create pages, check navigation
1190 QLabel *label1 = new QLabel("Page 1", tabWidget);
1191 tabWidget->addTab(label1, "Tab 1");
1192 QLabel *label2 = new QLabel("Page 2", tabWidget);
1193 tabWidget->addTab(label2, "Tab 2");
1195 QCOMPARE(interface->childCount(), 2);
1197 QAccessibleInterface* tabBarInterface = 0;
1198 // there is no special logic to sort the children, so the contents will be 1, the tab bar 2
1199 tabBarInterface = interface->child(1);
1200 QVERIFY(tabBarInterface);
1201 QCOMPARE(tabBarInterface->childCount(), 4);
1202 QCOMPARE(tabBarInterface->role(), QAccessible::PageTabList);
1204 QAccessibleInterface* tabButton1Interface = tabBarInterface->child(0);
1205 QVERIFY(tabButton1Interface);
1206 QCOMPARE(tabButton1Interface->role(), QAccessible::PageTab);
1207 QCOMPARE(tabButton1Interface->text(QAccessible::Name), QLatin1String("Tab 1"));
1209 QAccessibleInterface* tabButton2Interface = tabBarInterface->child(1);
1210 QVERIFY(tabButton1Interface);
1211 QCOMPARE(tabButton2Interface->role(), QAccessible::PageTab);
1212 QCOMPARE(tabButton2Interface->text(QAccessible::Name), QLatin1String("Tab 2"));
1214 QAccessibleInterface* tabButtonLeft = tabBarInterface->child(2);
1215 QVERIFY(tabButtonLeft);
1216 QCOMPARE(tabButtonLeft->role(), QAccessible::PushButton);
1217 QCOMPARE(tabButtonLeft->text(QAccessible::Name), QLatin1String("Scroll Left"));
1219 QAccessibleInterface* tabButtonRight = tabBarInterface->child(3);
1220 QVERIFY(tabButtonRight);
1221 QCOMPARE(tabButtonRight->role(), QAccessible::PushButton);
1222 QCOMPARE(tabButtonRight->text(QAccessible::Name), QLatin1String("Scroll Right"));
1223 delete tabButton1Interface;
1224 delete tabButton2Interface;
1225 delete tabButtonLeft;
1226 delete tabButtonRight;
1228 QAccessibleInterface* stackWidgetInterface = interface->child(0);
1229 QVERIFY(stackWidgetInterface);
1230 QCOMPARE(stackWidgetInterface->childCount(), 2);
1231 QCOMPARE(stackWidgetInterface->role(), QAccessible::LayeredPane);
1233 QAccessibleInterface* stackChild1Interface = stackWidgetInterface->child(0);
1234 QVERIFY(stackChild1Interface);
1236 QCOMPARE(stackChild1Interface->childCount(), 0);
1238 QCOMPARE(stackChild1Interface->role(), QAccessible::StaticText);
1239 QCOMPARE(stackChild1Interface->text(QAccessible::Name), QLatin1String("Page 1"));
1240 QCOMPARE(label1, stackChild1Interface->object());
1242 // Navigation in stack widgets should be consistent
1243 QAccessibleInterface* parent = stackChild1Interface->parent();
1246 QCOMPARE(parent->childCount(), 2);
1248 QCOMPARE(parent->role(), QAccessible::LayeredPane);
1251 QAccessibleInterface* stackChild2Interface = stackWidgetInterface->child(1);
1252 QVERIFY(stackChild2Interface);
1253 QCOMPARE(stackChild2Interface->childCount(), 0);
1254 QCOMPARE(stackChild2Interface->role(), QAccessible::StaticText);
1255 QCOMPARE(label2, stackChild2Interface->object());
1256 QCOMPARE(label2->text(), stackChild2Interface->text(QAccessible::Name));
1258 parent = stackChild2Interface->parent();
1261 QCOMPARE(parent->childCount(), 2);
1263 QCOMPARE(parent->role(), QAccessible::LayeredPane);
1266 delete tabBarInterface;
1267 delete stackChild1Interface;
1268 delete stackChild2Interface;
1269 delete stackWidgetInterface;
1272 QTestAccessibility::clearEvents();
1275 void tst_QAccessibility::menuTest()
1279 mw.resize(300, 200);
1280 QMenu *file = mw.menuBar()->addMenu("&File");
1281 QMenu *fileNew = file->addMenu("&New...");
1282 fileNew->menuAction()->setShortcut(tr("Ctrl+N"));
1283 fileNew->addAction("Text file");
1284 fileNew->addAction("Image file");
1285 file->addAction("&Open")->setShortcut(tr("Ctrl+O"));
1286 file->addAction("&Save")->setShortcut(tr("Ctrl+S"));
1287 file->addSeparator();
1288 file->addAction("E&xit")->setShortcut(tr("Alt+F4"));
1290 QMenu *edit = mw.menuBar()->addMenu("&Edit");
1291 edit->addAction("&Undo")->setShortcut(tr("Ctrl+Z"));
1292 edit->addAction("&Redo")->setShortcut(tr("Ctrl+Y"));
1293 edit->addSeparator();
1294 edit->addAction("Cu&t")->setShortcut(tr("Ctrl+X"));
1295 edit->addAction("&Copy")->setShortcut(tr("Ctrl+C"));
1296 edit->addAction("&Paste")->setShortcut(tr("Ctrl+V"));
1297 edit->addAction("&Delete")->setShortcut(tr("Del"));
1298 edit->addSeparator();
1299 edit->addAction("Pr&operties");
1301 mw.menuBar()->addSeparator();
1303 QMenu *help = mw.menuBar()->addMenu("&Help");
1304 help->addAction("&Contents");
1305 help->addAction("&About");
1307 mw.menuBar()->addAction("Action!");
1309 mw.show(); // triggers layout
1312 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(mw.menuBar());
1313 QCOMPARE(verifyHierarchy(interface), 0);
1316 QCOMPARE(interface->childCount(), 5);
1317 QCOMPARE(interface->role(), QAccessible::MenuBar);
1319 QAccessibleInterface *iFile = interface->child(0);
1320 QAccessibleInterface *iEdit = interface->child(1);
1321 QAccessibleInterface *iSeparator = interface->child(2);
1322 QAccessibleInterface *iHelp = interface->child(3);
1323 QAccessibleInterface *iAction = interface->child(4);
1325 QCOMPARE(iFile->role(), QAccessible::MenuItem);
1326 QCOMPARE(iEdit->role(), QAccessible::MenuItem);
1327 QCOMPARE(iSeparator->role(), QAccessible::Separator);
1328 QCOMPARE(iHelp->role(), QAccessible::MenuItem);
1329 QCOMPARE(iAction->role(), QAccessible::MenuItem);
1332 if (!IsValidCEPlatform())
1333 QSKIP("Tests do not work on Mobile platforms due to native menus");
1335 QCOMPARE(mw.mapFromGlobal(interface->rect().topLeft()), mw.menuBar()->geometry().topLeft());
1336 QCOMPARE(interface->rect().size(), mw.menuBar()->size());
1338 QVERIFY(interface->rect().contains(iFile->rect()));
1339 QVERIFY(interface->rect().contains(iEdit->rect()));
1340 // QVERIFY(interface->rect().contains(childSeparator->rect())); //separator might be invisible
1341 QVERIFY(interface->rect().contains(iHelp->rect()));
1342 QVERIFY(interface->rect().contains(iAction->rect()));
1345 QCOMPARE(iFile->text(QAccessible::Name), QString("File"));
1346 QCOMPARE(iEdit->text(QAccessible::Name), QString("Edit"));
1347 QCOMPARE(iSeparator->text(QAccessible::Name), QString());
1348 QCOMPARE(iHelp->text(QAccessible::Name), QString("Help"));
1349 QCOMPARE(iAction->text(QAccessible::Name), QString("Action!"));
1351 // TODO: Currently not working, task to fix is #100019.
1353 QCOMPARE(iFile->text(QAccessible::Accelerator), tr("Alt+F"));
1354 QCOMPARE(iEdit->text(QAccessible::Accelerator), tr("Alt+E"));
1355 QCOMPARE(iSeparator->text(QAccessible::Accelerator), QString());
1356 QCOMPARE(iHelp->text(QAccessible::Accelerator), tr("Alt+H"));
1357 QCOMPARE(iAction->text(QAccessible::Accelerator), QString());
1360 QVERIFY(iFile->actionInterface());
1362 QCOMPARE(iFile->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::showMenuAction());
1363 QCOMPARE(iSeparator->actionInterface()->actionNames(), QStringList());
1364 QCOMPARE(iHelp->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::showMenuAction());
1365 QCOMPARE(iAction->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::pressAction());
1367 bool menuFade = qApp->isEffectEnabled(Qt::UI_FadeMenu);
1368 int menuFadeDelay = 300;
1369 iFile->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1371 QTest::qWait(menuFadeDelay);
1372 QVERIFY(file->isVisible() && !edit->isVisible() && !help->isVisible());
1373 iEdit->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1375 QTest::qWait(menuFadeDelay);
1376 QVERIFY(!file->isVisible() && edit->isVisible() && !help->isVisible());
1377 iHelp->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1379 QTest::qWait(menuFadeDelay);
1380 QVERIFY(!file->isVisible() && !edit->isVisible() && help->isVisible());
1381 iAction->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1383 QTest::qWait(menuFadeDelay);
1384 QVERIFY(!file->isVisible() && !edit->isVisible() && !help->isVisible());
1386 QVERIFY(interface->actionInterface());
1387 QCOMPARE(interface->actionInterface()->actionNames(), QStringList());
1389 interface = QAccessible::queryAccessibleInterface(file);
1390 QCOMPARE(interface->childCount(), 5);
1391 QCOMPARE(interface->role(), QAccessible::PopupMenu);
1393 QAccessibleInterface *iFileNew = interface->child(0);
1394 QAccessibleInterface *iFileOpen = interface->child(1);
1395 QAccessibleInterface *iFileSave = interface->child(2);
1396 QAccessibleInterface *iFileSeparator = interface->child(3);
1397 QAccessibleInterface *iFileExit = interface->child(4);
1399 QCOMPARE(iFileNew->role(), QAccessible::MenuItem);
1400 QCOMPARE(iFileOpen->role(), QAccessible::MenuItem);
1401 QCOMPARE(iFileSave->role(), QAccessible::MenuItem);
1402 QCOMPARE(iFileSeparator->role(), QAccessible::Separator);
1403 QCOMPARE(iFileExit->role(), QAccessible::MenuItem);
1404 QCOMPARE(iFileNew->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::showMenuAction());
1405 QCOMPARE(iFileOpen->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::pressAction());
1406 QCOMPARE(iFileSave->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::pressAction());
1407 QCOMPARE(iFileSeparator->actionInterface()->actionNames(), QStringList());
1408 QCOMPARE(iFileExit->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::pressAction());
1410 QAccessibleInterface *iface = 0;
1411 QAccessibleInterface *iface2 = 0;
1413 // traverse siblings with navigate(Sibling, ...)
1414 iface = interface->child(0);
1416 QCOMPARE(iface->role(), QAccessible::MenuItem);
1418 QAccessible::Role fileRoles[5] = {
1419 QAccessible::MenuItem,
1420 QAccessible::MenuItem,
1421 QAccessible::MenuItem,
1422 QAccessible::Separator,
1423 QAccessible::MenuItem
1425 for (int child = 0; child < 5; ++child) {
1426 iface2 = interface->child(child);
1428 QCOMPARE(iface2->role(), fileRoles[child]);
1434 iface = interface->child(0);
1436 QCOMPARE(iface->role(), QAccessible::MenuItem);
1439 iface2 = iface->child(0);
1443 QCOMPARE(iface->role(), QAccessible::PopupMenu);
1445 // "Text file" menu item
1446 iface2 = iface->child(0);
1450 QCOMPARE(iface->role(), QAccessible::MenuItem);
1454 // move mouse pointer away, since that might influence the
1456 QTest::mouseMove(&mw, QPoint(-1, -1));
1459 QTest::qWait(menuFadeDelay);
1461 iFile->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1462 iFileNew->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
1464 QVERIFY(file->isVisible());
1465 QVERIFY(fileNew->isVisible());
1466 QVERIFY(!edit->isVisible());
1467 QVERIFY(!help->isVisible());
1469 QTestAccessibility::clearEvents();
1476 delete iFileSeparator;
1479 // Do not crash if the menu don't have a parent
1480 QMenu *menu = new QMenu;
1481 menu->addAction(QLatin1String("one"));
1482 menu->addAction(QLatin1String("two"));
1483 menu->addAction(QLatin1String("three"));
1484 iface = QAccessible::queryAccessibleInterface(menu);
1485 iface2 = iface->parent();
1487 QCOMPARE(iface2->role(), QAccessible::Application);
1495 QTestAccessibility::clearEvents();
1498 void tst_QAccessibility::spinBoxTest()
1500 QSpinBox * const spinBox = new QSpinBox();
1501 spinBox->setValue(3);
1504 QAccessibleInterface * const interface = QAccessible::queryAccessibleInterface(spinBox);
1506 QCOMPARE(interface->role(), QAccessible::SpinBox);
1508 const QRect widgetRect = spinBox->geometry();
1509 const QRect accessibleRect = interface->rect();
1510 QCOMPARE(accessibleRect, widgetRect);
1511 QCOMPARE(interface->text(QAccessible::Value), QLatin1String("3"));
1513 // one child, the line edit
1514 const int numChildren = interface->childCount();
1515 QCOMPARE(numChildren, 1);
1516 QAccessibleInterface *lineEdit = interface->child(0);
1518 QCOMPARE(lineEdit->role(), QAccessible::EditableText);
1519 QCOMPARE(lineEdit->text(QAccessible::Value), QLatin1String("3"));
1522 QVERIFY(interface->valueInterface());
1523 QCOMPARE(interface->valueInterface()->currentValue().toInt(), 3);
1524 interface->valueInterface()->setCurrentValue(23);
1525 QCOMPARE(interface->valueInterface()->currentValue().toInt(), 23);
1526 QCOMPARE(spinBox->value(), 23);
1528 spinBox->setFocus();
1529 QTestAccessibility::clearEvents();
1530 QTest::keyPress(spinBox, Qt::Key_Up);
1532 QAccessibleValueChangeEvent expectedEvent(spinBox, spinBox->value());
1533 QVERIFY(QTestAccessibility::containsEvent(&expectedEvent));
1535 QTestAccessibility::clearEvents();
1538 void tst_QAccessibility::doubleSpinBoxTest()
1540 QDoubleSpinBox *doubleSpinBox = new QDoubleSpinBox;
1541 doubleSpinBox->show();
1543 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(doubleSpinBox);
1546 const QRect widgetRect = doubleSpinBox->geometry();
1547 const QRect accessibleRect = interface->rect();
1548 QCOMPARE(accessibleRect, widgetRect);
1550 // Test that we get valid rects for all the spinbox child interfaces.
1551 const int numChildren = interface->childCount();
1552 for (int i = 0; i < numChildren; ++i) {
1553 QAccessibleInterface *childIface = interface->child(i);
1554 const QRect childRect = childIface->rect();
1555 QVERIFY(childRect.isValid());
1559 delete doubleSpinBox;
1560 QTestAccessibility::clearEvents();
1563 void tst_QAccessibility::textEditTest()
1569 QString text = "hello world\nhow are you today?\n";
1573 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&edit);
1574 QCOMPARE(iface->text(QAccessible::Value), text);
1575 QCOMPARE(iface->textInterface()->textAtOffset(8, QAccessible2::WordBoundary, &startOffset, &endOffset), QString("world"));
1576 QCOMPARE(startOffset, 6);
1577 QCOMPARE(endOffset, 11);
1578 QCOMPARE(iface->textInterface()->textAtOffset(14, QAccessible2::LineBoundary, &startOffset, &endOffset), QString("how are you today?"));
1579 QCOMPARE(startOffset, 12);
1580 QCOMPARE(endOffset, 30);
1581 QCOMPARE(iface->textInterface()->characterCount(), 31);
1582 QFontMetrics fm(edit.font());
1583 QCOMPARE(iface->textInterface()->characterRect(0).size(), QSize(fm.width("h"), fm.height()));
1584 QCOMPARE(iface->textInterface()->characterRect(5).size(), QSize(fm.width(" "), fm.height()));
1585 QCOMPARE(iface->textInterface()->characterRect(6).size(), QSize(fm.width("w"), fm.height()));
1587 iface->editableTextInterface()->copyText(6, 11);
1588 QCOMPARE(QApplication::clipboard()->text(), QLatin1String("world"));
1589 iface->editableTextInterface()->cutText(12, 16);
1590 QCOMPARE(QApplication::clipboard()->text(), QLatin1String("how "));
1591 QCOMPARE(iface->textInterface()->text(12, 15), QLatin1String("are"));
1593 QTestAccessibility::clearEvents();
1596 QTextCursor c = edit.textCursor();
1598 c.setPosition(4, QTextCursor::KeepAnchor);
1599 edit.setTextCursor(c);
1600 QAccessibleTextSelectionEvent sel(&edit, 2, 4);
1601 QVERIFY_EVENT(&sel);
1604 int end = edit.textCursor().position();
1605 sel.setCursorPosition(end);
1606 sel.setSelection(0, end);
1607 QVERIFY_EVENT(&sel);
1609 QTestAccessibility::clearEvents();
1612 void tst_QAccessibility::textBrowserTest()
1615 QTextBrowser textBrowser;
1616 QString text = QLatin1String("Hello world\nhow are you today?\n");
1617 textBrowser.setText(text);
1620 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&textBrowser);
1622 QCOMPARE(iface->role(), QAccessible::StaticText);
1623 QCOMPARE(iface->text(QAccessible::Value), text);
1626 QCOMPARE(iface->textInterface()->textAtOffset(8, QAccessible2::WordBoundary, &startOffset, &endOffset), QString("world"));
1627 QCOMPARE(startOffset, 6);
1628 QCOMPARE(endOffset, 11);
1629 QCOMPARE(iface->textInterface()->textAtOffset(14, QAccessible2::LineBoundary, &startOffset, &endOffset), QString("how are you today?"));
1630 QCOMPARE(startOffset, 12);
1631 QCOMPARE(endOffset, 30);
1632 QCOMPARE(iface->textInterface()->characterCount(), 31);
1634 QTestAccessibility::clearEvents();
1637 void tst_QAccessibility::mdiAreaTest()
1641 mdiArea.resize(400,300);
1643 const int subWindowCount = 3;
1644 for (int i = 0; i < subWindowCount; ++i)
1645 mdiArea.addSubWindow(new QWidget, Qt::Dialog)->show();
1647 QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
1648 QCOMPARE(subWindows.count(), subWindowCount);
1650 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&mdiArea);
1652 QCOMPARE(interface->childCount(), subWindowCount);
1655 QTestAccessibility::clearEvents();
1658 void tst_QAccessibility::mdiSubWindowTest()
1663 qApp->setActiveWindow(&mdiArea);
1664 #if defined(Q_OS_UNIX)
1665 QCoreApplication::processEvents();
1669 const int subWindowCount = 5;
1670 for (int i = 0; i < subWindowCount; ++i) {
1671 QMdiSubWindow *window = mdiArea.addSubWindow(new QPushButton("QAccessibilityTest"));
1673 // Parts of this test requires that the sub windows are placed next
1674 // to each other. In order to achieve that QMdiArea must have
1675 // a width which is larger than subWindow->width() * subWindowCount.
1677 int minimumWidth = window->width() * subWindowCount + 20;
1678 mdiArea.resize(mdiArea.size().expandedTo(QSize(minimumWidth, 0)));
1679 #if defined(Q_OS_UNIX)
1680 QCoreApplication::processEvents();
1686 QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
1687 QCOMPARE(subWindows.count(), subWindowCount);
1689 QMdiSubWindow *testWindow = subWindows.at(3);
1690 QVERIFY(testWindow);
1691 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(testWindow);
1695 QCOMPARE(interface->childCount(), 1);
1698 QCOMPARE(interface->text(QAccessible::Name), QString());
1699 testWindow->setWindowTitle(QLatin1String("ReplaceMe"));
1700 QCOMPARE(interface->text(QAccessible::Name), QLatin1String("ReplaceMe"));
1701 interface->setText(QAccessible::Name, QLatin1String("TitleSetOnWindow"));
1702 QCOMPARE(interface->text(QAccessible::Name), QLatin1String("TitleSetOnWindow"));
1704 mdiArea.setActiveSubWindow(testWindow);
1707 QAccessible::State state;
1708 state.focusable = true;
1709 state.focused = true;
1710 state.movable = true;
1711 state.sizeable = true;
1713 QCOMPARE(interface->state(), state);
1714 const QRect originalGeometry = testWindow->geometry();
1715 testWindow->showMaximized();
1716 state.sizeable = false;
1717 state.movable = false;
1718 QCOMPARE(interface->state(), state);
1719 testWindow->showNormal();
1720 testWindow->move(-10, 0);
1721 QVERIFY(interface->state().offscreen);
1722 testWindow->setVisible(false);
1723 QVERIFY(interface->state().invisible);
1724 testWindow->setVisible(true);
1725 testWindow->setEnabled(false);
1726 QVERIFY(interface->state().disabled);
1727 testWindow->setEnabled(true);
1728 qApp->setActiveWindow(&mdiArea);
1729 mdiArea.setActiveSubWindow(testWindow);
1730 testWindow->setFocus();
1731 QVERIFY(testWindow->isAncestorOf(qApp->focusWidget()));
1732 QVERIFY(interface->state().focused);
1733 testWindow->setGeometry(originalGeometry);
1736 const QPoint globalPos = testWindow->mapToGlobal(QPoint(0, 0));
1737 QCOMPARE(interface->rect(), QRect(globalPos, testWindow->size()));
1739 QCOMPARE(interface->rect(), QRect());
1740 QCOMPARE(childRect(interface), QRect());
1741 testWindow->showMinimized();
1742 QCOMPARE(childRect(interface), QRect());
1743 testWindow->showNormal();
1744 testWindow->widget()->hide();
1745 QCOMPARE(childRect(interface), QRect());
1746 testWindow->widget()->show();
1747 const QRect widgetGeometry = testWindow->contentsRect();
1748 const QPoint globalWidgetPos = QPoint(globalPos.x() + widgetGeometry.x(),
1749 globalPos.y() + widgetGeometry.y());
1750 QCOMPARE(childRect(interface), QRect(globalWidgetPos, widgetGeometry.size()));
1753 QCOMPARE(interface->childAt(-10, 0), static_cast<QAccessibleInterface*>(0));
1754 QCOMPARE(interface->childAt(globalPos.x(), globalPos.y()), static_cast<QAccessibleInterface*>(0));
1755 QAccessibleInterface *child = interface->childAt(globalWidgetPos.x(), globalWidgetPos.y());
1756 QCOMPARE(child->role(), QAccessible::PushButton);
1757 QCOMPARE(child->text(QAccessible::Name), QString("QAccessibilityTest"));
1759 testWindow->widget()->hide();
1760 QCOMPARE(interface->childAt(globalWidgetPos.x(), globalWidgetPos.y()), static_cast<QAccessibleInterface*>(0));
1763 QTestAccessibility::clearEvents();
1766 void tst_QAccessibility::lineEditTest()
1768 QWidget *toplevel = new QWidget;
1770 QLineEdit *le = new QLineEdit;
1771 QAIPtr iface(QAccessible::queryAccessibleInterface(le));
1775 QApplication::processEvents();
1776 QCOMPARE(iface->childCount(), 0);
1777 QVERIFY(iface->state().sizeable);
1778 QVERIFY(iface->state().movable);
1779 QVERIFY(iface->state().focusable);
1780 QVERIFY(iface->state().selectable);
1781 QVERIFY(iface->state().hasPopup);
1782 QCOMPARE(bool(iface->state().focused), le->hasFocus());
1784 QString secret(QLatin1String("secret"));
1785 le->setText(secret);
1786 le->setEchoMode(QLineEdit::Normal);
1787 QVERIFY(!(iface->state().passwordEdit));
1788 QCOMPARE(iface->text(QAccessible::Value), secret);
1789 le->setEchoMode(QLineEdit::NoEcho);
1790 QVERIFY(iface->state().passwordEdit);
1791 QVERIFY(iface->text(QAccessible::Value).isEmpty());
1792 le->setEchoMode(QLineEdit::Password);
1793 QVERIFY(iface->state().passwordEdit);
1794 QVERIFY(iface->text(QAccessible::Value).isEmpty());
1795 le->setEchoMode(QLineEdit::PasswordEchoOnEdit);
1796 QVERIFY(iface->state().passwordEdit);
1797 QVERIFY(iface->text(QAccessible::Value).isEmpty());
1798 le->setEchoMode(QLineEdit::Normal);
1799 QVERIFY(!(iface->state().passwordEdit));
1800 QCOMPARE(iface->text(QAccessible::Value), secret);
1802 le->setParent(toplevel);
1804 QApplication::processEvents();
1805 QVERIFY(!(iface->state().sizeable));
1806 QVERIFY(!(iface->state().movable));
1807 QVERIFY(iface->state().focusable);
1808 QVERIFY(iface->state().selectable);
1809 QVERIFY(iface->state().hasPopup);
1810 QCOMPARE(bool(iface->state().focused), le->hasFocus());
1812 QLineEdit *le2 = new QLineEdit(toplevel);
1815 le2->activateWindow();
1817 le->setFocus(Qt::TabFocusReason);
1818 QTestAccessibility::clearEvents();
1819 le2->setFocus(Qt::TabFocusReason);
1820 QAccessibleEvent ev(le2, QAccessible::Focus);
1821 QTRY_VERIFY(QTestAccessibility::containsEvent(&ev));
1823 le->setText(QLatin1String("500"));
1824 le->setValidator(new QIntValidator());
1825 iface->setText(QAccessible::Value, QLatin1String("This text is not a number"));
1826 QCOMPARE(le->text(), QLatin1String("500"));
1833 // Text interface to get the current text
1834 QString cite = "I always pass on good advice. It is the only thing to do with it. It is never of any use to oneself. --Oscar Wilde";
1835 QLineEdit *le3 = new QLineEdit(cite, toplevel);
1837 QAIPtr iface(QAccessible::queryAccessibleInterface(le3));
1838 QAccessibleTextInterface* textIface = iface->textInterface();
1840 QTestAccessibility::clearEvents();
1841 le3->setCursorPosition(3);
1842 QCOMPARE(textIface->cursorPosition(), 3);
1844 QAccessibleTextCursorEvent caretEvent(le3, 3);
1845 QTRY_VERIFY(QTestAccessibility::containsEvent(&caretEvent));
1846 QCOMPARE(textIface->selectionCount(), 0);
1847 QTestAccessibility::clearEvents();
1850 QCOMPARE(textIface->text(0, 8), QString::fromLatin1("I always"));
1851 QCOMPARE(textIface->textAtOffset(0, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1("I"));
1854 QCOMPARE(textIface->textBeforeOffset(0, QAccessible2::CharBoundary,&start,&end), QString());
1855 QCOMPARE(textIface->textAfterOffset(0, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1(" "));
1859 QCOMPARE(textIface->textAtOffset(5, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1("a"));
1862 QCOMPARE(textIface->textBeforeOffset(5, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1("w"));
1863 QCOMPARE(textIface->textAfterOffset(5, QAccessible2::CharBoundary,&start,&end), QString::fromLatin1("y"));
1865 QCOMPARE(textIface->textAtOffset(5, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1("always"));
1869 QCOMPARE(textIface->textAtOffset(2, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1("always"));
1870 QCOMPARE(textIface->textAtOffset(7, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1("always"));
1871 QCOMPARE(textIface->textAtOffset(8, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1(" "));
1872 QCOMPARE(textIface->textAtOffset(25, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1("advice"));
1873 QCOMPARE(textIface->textAtOffset(92, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1("oneself"));
1875 QCOMPARE(textIface->textBeforeOffset(5, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1(" "));
1876 QCOMPARE(textIface->textAfterOffset(5, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1(" "));
1877 QCOMPARE(textIface->textAtOffset(5, QAccessible2::SentenceBoundary,&start,&end), QString::fromLatin1("I always pass on good advice. "));
1881 QCOMPARE(textIface->textBeforeOffset(40, QAccessible2::SentenceBoundary,&start,&end), QString::fromLatin1("I always pass on good advice. "));
1882 QCOMPARE(textIface->textAfterOffset(5, QAccessible2::SentenceBoundary,&start,&end), QString::fromLatin1("It is the only thing to do with it. "));
1884 QCOMPARE(textIface->textAtOffset(5, QAccessible2::ParagraphBoundary,&start,&end), cite);
1886 QCOMPARE(end, cite.length());
1887 QCOMPARE(textIface->textAtOffset(5, QAccessible2::LineBoundary,&start,&end), cite);
1888 QCOMPARE(textIface->textAtOffset(5, QAccessible2::NoBoundary,&start,&end), cite);
1890 QTestAccessibility::clearEvents();
1894 // Test events: cursor movement, selection, text changes
1895 QString text = "Hello, world";
1896 QLineEdit *lineEdit = new QLineEdit(text, toplevel);
1898 QTestAccessibility::clearEvents();
1900 lineEdit->setCursorPosition(5);
1901 QAccessibleTextCursorEvent cursorEvent(lineEdit, 5);
1902 QVERIFY_EVENT(&cursorEvent);
1903 lineEdit->setCursorPosition(0);
1904 cursorEvent.setCursorPosition(0);
1905 QVERIFY_EVENT(&cursorEvent);
1908 lineEdit->setSelection(2, 4);
1910 QAccessibleTextSelectionEvent sel(lineEdit, 2, 2+4);
1911 QVERIFY_EVENT(&sel);
1913 lineEdit->selectAll();
1914 sel.setSelection(0, lineEdit->text().length());
1915 sel.setCursorPosition(lineEdit->text().length());
1916 QVERIFY_EVENT(&sel);
1918 lineEdit->setSelection(10, -4);
1919 QCOMPARE(lineEdit->cursorPosition(), 6);
1920 QAccessibleTextSelectionEvent sel2(lineEdit, 6, 10);
1921 sel2.setCursorPosition(6);
1922 QVERIFY_EVENT(&sel2);
1924 lineEdit->deselect();
1925 QAccessibleTextSelectionEvent sel3(lineEdit, -1, -1);
1926 sel3.setCursorPosition(6);
1927 QVERIFY_EVENT(&sel3);
1931 // FIXME: improve redundant updates
1932 QAccessibleTextRemoveEvent remove(lineEdit, 0, text);
1933 QVERIFY_EVENT(&remove);
1935 QAccessibleTextSelectionEvent noSel(lineEdit, -1, -1);
1936 QVERIFY_EVENT(&noSel);
1937 QAccessibleTextCursorEvent cursor(lineEdit, 0);
1938 QVERIFY_EVENT(&cursor);
1940 lineEdit->setText("foo");
1941 cursorEvent.setCursorPosition(3);
1942 QVERIFY_EVENT(&cursorEvent);
1944 QAccessibleTextInsertEvent e(lineEdit, 0, "foo");
1945 QVERIFY(QTestAccessibility::containsEvent(&e));
1947 lineEdit->setText("bar");
1948 QAccessibleTextUpdateEvent update(lineEdit, 0, "foo", "bar");
1949 QVERIFY(QTestAccessibility::containsEvent(&update));
1951 // FIXME check what extra events are around and get rid of them
1952 QTestAccessibility::clearEvents();
1954 QTestEventList keys;
1955 keys.addKeyClick('D');
1956 keys.simulate(lineEdit);
1958 QAccessibleTextInsertEvent insertD(lineEdit, 3, "D");
1959 QVERIFY_EVENT(&insertD);
1961 keys.addKeyClick('E');
1962 keys.simulate(lineEdit);
1964 QAccessibleTextInsertEvent insertE(lineEdit, 4, "E");
1965 QVERIFY(QTestAccessibility::containsEvent(&insertE));
1967 keys.addKeyClick(Qt::Key_Left);
1968 keys.addKeyClick(Qt::Key_Left);
1969 keys.simulate(lineEdit);
1970 cursorEvent.setCursorPosition(4);
1971 QVERIFY(QTestAccessibility::containsEvent(&cursorEvent));
1972 cursorEvent.setCursorPosition(3);
1973 QVERIFY(QTestAccessibility::containsEvent(&cursorEvent));
1976 keys.addKeyClick('C');
1977 keys.simulate(lineEdit);
1979 QAccessibleTextInsertEvent insertC(lineEdit, 3, "C");
1980 QVERIFY(QTestAccessibility::containsEvent(&insertC));
1983 keys.addKeyClick('O');
1984 keys.simulate(lineEdit);
1985 QAccessibleTextInsertEvent insertO(lineEdit, 4, "O");
1986 QVERIFY(QTestAccessibility::containsEvent(&insertO));
1989 QTestAccessibility::clearEvents();
1992 void tst_QAccessibility::groupBoxTest()
1995 QGroupBox *groupBox = new QGroupBox();
1996 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(groupBox);
1998 groupBox->setTitle(QLatin1String("Test QGroupBox"));
2000 QAccessibleEvent ev(groupBox, QAccessible::NameChanged);
2003 groupBox->setToolTip(QLatin1String("This group box will be used to test accessibility"));
2004 QVBoxLayout *layout = new QVBoxLayout();
2005 QRadioButton *rbutton = new QRadioButton();
2006 layout->addWidget(rbutton);
2007 groupBox->setLayout(layout);
2008 QAccessibleInterface *rButtonIface = QAccessible::queryAccessibleInterface(rbutton);
2010 QCOMPARE(iface->childCount(), 1);
2011 QCOMPARE(iface->role(), QAccessible::Grouping);
2012 QCOMPARE(iface->text(QAccessible::Name), QLatin1String("Test QGroupBox"));
2013 QCOMPARE(iface->text(QAccessible::Description), QLatin1String("This group box will be used to test accessibility"));
2014 QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > relations = rButtonIface->relations();
2015 QVERIFY(relations.size() == 1);
2016 QPair<QAccessibleInterface*, QAccessible::Relation> relation = relations.first();
2017 QCOMPARE(relation.first->object(), groupBox);
2018 QCOMPARE(relation.second, QAccessible::Label);
2020 delete relation.first;
2022 delete rButtonIface;
2028 QGroupBox *groupBox = new QGroupBox();
2029 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(groupBox);
2030 QVERIFY(!iface->state().checkable);
2031 groupBox->setCheckable(true);
2033 groupBox->setChecked(false);
2034 QAccessible::State st;
2036 QAccessibleStateChangeEvent ev(groupBox, st);
2039 QCOMPARE(iface->role(), QAccessible::CheckBox);
2040 QAccessibleActionInterface *actionIface = iface->actionInterface();
2041 QVERIFY(actionIface);
2042 QAccessible::State state = iface->state();
2043 QVERIFY(state.checkable);
2044 QVERIFY(!state.checked);
2045 QVERIFY(actionIface->actionNames().contains(QAccessibleActionInterface::checkAction()));
2046 actionIface->doAction(QAccessibleActionInterface::checkAction());
2047 QVERIFY(groupBox->isChecked());
2048 state = iface->state();
2049 QVERIFY(state.checked);
2050 QAccessibleStateChangeEvent ev2(groupBox, st);
2051 QVERIFY_EVENT(&ev2);
2058 bool accessibleInterfaceLeftOf(const QAccessibleInterface *a1, const QAccessibleInterface *a2)
2060 return a1->rect().x() < a2->rect().x();
2063 bool accessibleInterfaceAbove(const QAccessibleInterface *a1, const QAccessibleInterface *a2)
2065 return a1->rect().y() < a2->rect().y();
2068 void tst_QAccessibility::dialogButtonBoxTest()
2071 QDialogButtonBox box(QDialogButtonBox::Reset |
2072 QDialogButtonBox::Help |
2073 QDialogButtonBox::Ok, Qt::Horizontal);
2076 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&box);
2079 #if defined(Q_OS_UNIX)
2080 QCoreApplication::processEvents();
2084 QApplication::processEvents();
2085 QCOMPARE(iface->childCount(), 3);
2086 QCOMPARE(iface->role(), QAccessible::Grouping);
2087 QStringList actualOrder;
2088 QAccessibleInterface *child;
2089 child = iface->child(0);
2090 QCOMPARE(child->role(), QAccessible::PushButton);
2092 QVector<QAccessibleInterface *> buttons;
2093 for (int i = 0; i < iface->childCount(); ++i)
2094 buttons << iface->child(i);
2096 qSort(buttons.begin(), buttons.end(), accessibleInterfaceLeftOf);
2098 for (int i = 0; i < buttons.count(); ++i)
2099 actualOrder << buttons.at(i)->text(QAccessible::Name);
2101 QStringList expectedOrder;
2102 QDialogButtonBox::ButtonLayout btnlout =
2103 QDialogButtonBox::ButtonLayout(QApplication::style()->styleHint(QStyle::SH_DialogButtonLayout));
2105 case QDialogButtonBox::WinLayout:
2106 expectedOrder << QDialogButtonBox::tr("Reset")
2107 << QDialogButtonBox::tr("OK")
2108 << QDialogButtonBox::tr("Help");
2110 case QDialogButtonBox::GnomeLayout:
2111 case QDialogButtonBox::KdeLayout:
2112 case QDialogButtonBox::MacLayout:
2113 expectedOrder << QDialogButtonBox::tr("Help")
2114 << QDialogButtonBox::tr("Reset")
2115 << QDialogButtonBox::tr("OK");
2118 QCOMPARE(actualOrder, expectedOrder);
2120 QApplication::processEvents();
2121 QTestAccessibility::clearEvents();
2125 QDialogButtonBox box(QDialogButtonBox::Reset |
2126 QDialogButtonBox::Help |
2127 QDialogButtonBox::Ok, Qt::Horizontal);
2130 // Test up and down navigation
2131 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&box);
2133 box.setOrientation(Qt::Vertical);
2135 #if defined(Q_OS_UNIX)
2136 QCoreApplication::processEvents();
2140 QApplication::processEvents();
2141 QStringList actualOrder;
2143 QVector<QAccessibleInterface *> buttons;
2144 for (int i = 0; i < iface->childCount(); ++i)
2145 buttons << iface->child(i);
2147 qSort(buttons.begin(), buttons.end(), accessibleInterfaceAbove);
2149 for (int i = 0; i < buttons.count(); ++i)
2150 actualOrder << buttons.at(i)->text(QAccessible::Name);
2152 QStringList expectedOrder;
2153 expectedOrder << QDialogButtonBox::tr("OK")
2154 << QDialogButtonBox::tr("Reset")
2155 << QDialogButtonBox::tr("Help");
2157 QCOMPARE(actualOrder, expectedOrder);
2159 QApplication::processEvents();
2162 QTestAccessibility::clearEvents();
2165 void tst_QAccessibility::dialTest()
2169 dial.setMinimum(23);
2170 dial.setMaximum(121);
2172 QCOMPARE(dial.value(), 42);
2175 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&dial);
2177 QCOMPARE(interface->childCount(), 0);
2179 QCOMPARE(interface->text(QAccessible::Value), QString::number(dial.value()));
2180 QCOMPARE(interface->rect(), dial.geometry());
2182 QAccessibleValueInterface *valueIface = interface->valueInterface();
2183 QVERIFY(valueIface != 0);
2184 QCOMPARE(valueIface->minimumValue().toInt(), dial.minimum());
2185 QCOMPARE(valueIface->maximumValue().toInt(), dial.maximum());
2186 QCOMPARE(valueIface->currentValue().toInt(), 42);
2188 QCOMPARE(valueIface->currentValue().toInt(), dial.value());
2190 QCOMPARE(valueIface->currentValue().toInt(), dial.value());
2192 QCOMPARE(valueIface->currentValue().toInt(), dial.value());
2193 valueIface->setCurrentValue(77);
2194 QCOMPARE(77, dial.value());
2196 QTestAccessibility::clearEvents();
2199 void tst_QAccessibility::rubberBandTest()
2201 QRubberBand rubberBand(QRubberBand::Rectangle);
2202 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&rubberBand);
2204 QCOMPARE(interface->role(), QAccessible::Border);
2206 QTestAccessibility::clearEvents();
2209 void tst_QAccessibility::abstractScrollAreaTest()
2212 QAbstractScrollArea abstractScrollArea;
2214 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&abstractScrollArea);
2216 QVERIFY(!interface->rect().isValid());
2217 QCOMPARE(interface->childAt(200, 200), static_cast<QAccessibleInterface*>(0));
2219 abstractScrollArea.resize(400, 400);
2220 abstractScrollArea.show();
2221 #if defined(Q_OS_UNIX)
2222 QCoreApplication::processEvents();
2225 const QRect globalGeometry = QRect(abstractScrollArea.mapToGlobal(QPoint(0, 0)),
2226 abstractScrollArea.size());
2229 QCOMPARE(interface->childCount(), 1);
2230 QWidget *viewport = abstractScrollArea.viewport();
2232 QVERIFY(verifyChild(viewport, interface, 0, globalGeometry));
2234 // Horizontal scrollBar.
2235 abstractScrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
2236 QCOMPARE(interface->childCount(), 2);
2237 QWidget *horizontalScrollBar = abstractScrollArea.horizontalScrollBar();
2238 QWidget *horizontalScrollBarContainer = horizontalScrollBar->parentWidget();
2239 QVERIFY(verifyChild(horizontalScrollBarContainer, interface, 1, globalGeometry));
2241 // Horizontal scrollBar widgets.
2242 QLabel *secondLeftLabel = new QLabel(QLatin1String("L2"));
2243 abstractScrollArea.addScrollBarWidget(secondLeftLabel, Qt::AlignLeft);
2244 QCOMPARE(interface->childCount(), 2);
2246 QLabel *firstLeftLabel = new QLabel(QLatin1String("L1"));
2247 abstractScrollArea.addScrollBarWidget(firstLeftLabel, Qt::AlignLeft);
2248 QCOMPARE(interface->childCount(), 2);
2250 QLabel *secondRightLabel = new QLabel(QLatin1String("R2"));
2251 abstractScrollArea.addScrollBarWidget(secondRightLabel, Qt::AlignRight);
2252 QCOMPARE(interface->childCount(), 2);
2254 QLabel *firstRightLabel = new QLabel(QLatin1String("R1"));
2255 abstractScrollArea.addScrollBarWidget(firstRightLabel, Qt::AlignRight);
2256 QCOMPARE(interface->childCount(), 2);
2258 // Vertical scrollBar.
2259 abstractScrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
2260 QCOMPARE(interface->childCount(), 3);
2261 QWidget *verticalScrollBar = abstractScrollArea.verticalScrollBar();
2262 QWidget *verticalScrollBarContainer = verticalScrollBar->parentWidget();
2263 QVERIFY(verifyChild(verticalScrollBarContainer, interface, 2, globalGeometry));
2265 // Vertical scrollBar widgets.
2266 QLabel *secondTopLabel = new QLabel(QLatin1String("T2"));
2267 abstractScrollArea.addScrollBarWidget(secondTopLabel, Qt::AlignTop);
2268 QCOMPARE(interface->childCount(), 3);
2270 QLabel *firstTopLabel = new QLabel(QLatin1String("T1"));
2271 abstractScrollArea.addScrollBarWidget(firstTopLabel, Qt::AlignTop);
2272 QCOMPARE(interface->childCount(), 3);
2274 QLabel *secondBottomLabel = new QLabel(QLatin1String("B2"));
2275 abstractScrollArea.addScrollBarWidget(secondBottomLabel, Qt::AlignBottom);
2276 QCOMPARE(interface->childCount(), 3);
2278 QLabel *firstBottomLabel = new QLabel(QLatin1String("B1"));
2279 abstractScrollArea.addScrollBarWidget(firstBottomLabel, Qt::AlignBottom);
2280 QCOMPARE(interface->childCount(), 3);
2283 abstractScrollArea.setCornerWidget(new QLabel(QLatin1String("C")));
2284 QCOMPARE(interface->childCount(), 4);
2285 QWidget *cornerWidget = abstractScrollArea.cornerWidget();
2286 QVERIFY(verifyChild(cornerWidget, interface, 3, globalGeometry));
2288 QCOMPARE(verifyHierarchy(interface), 0);
2293 QTestAccessibility::clearEvents();
2296 void tst_QAccessibility::scrollAreaTest()
2299 QScrollArea scrollArea;
2301 #if defined(Q_OS_UNIX)
2302 QCoreApplication::processEvents();
2305 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&scrollArea);
2307 QCOMPARE(interface->childCount(), 1); // The viewport.
2310 QTestAccessibility::clearEvents();
2313 void tst_QAccessibility::listTest()
2316 QListWidget *listView = new QListWidget;
2317 listView->addItem("Oslo");
2318 listView->addItem("Berlin");
2319 listView->addItem("Brisbane");
2320 listView->resize(400,400);
2322 QTest::qWait(1); // Need this for indexOfchild to work.
2323 QCoreApplication::processEvents();
2326 QAIPtr iface = QAIPtr(QAccessible::queryAccessibleInterface(listView));
2327 QCOMPARE(verifyHierarchy(iface.data()), 0);
2329 QCOMPARE((int)iface->role(), (int)QAccessible::List);
2330 QCOMPARE(iface->childCount(), 3);
2333 QAIPtr child1 = QAIPtr(iface->child(0));
2335 QCOMPARE(iface->indexOfChild(child1.data()), 0);
2336 QCOMPARE(child1->text(QAccessible::Name), QString("Oslo"));
2337 QCOMPARE(child1->role(), QAccessible::ListItem);
2339 QAIPtr child2 = QAIPtr(iface->child(1));
2341 QCOMPARE(iface->indexOfChild(child2.data()), 1);
2342 QCOMPARE(child2->text(QAccessible::Name), QString("Berlin"));
2344 QAIPtr child3 = QAIPtr(iface->child(2));
2346 QCOMPARE(iface->indexOfChild(child3.data()), 2);
2347 QCOMPARE(child3->text(QAccessible::Name), QString("Brisbane"));
2349 QTestAccessibility::clearEvents();
2352 QTest::mouseClick(listView->viewport(), Qt::LeftButton, 0, listView->visualItemRect(listView->item(1)).center());
2353 QAccessibleEvent selectionEvent(listView, QAccessible::Selection);
2354 selectionEvent.setChild(2);
2355 QAccessibleEvent focusEvent(listView, QAccessible::Focus);
2356 focusEvent.setChild(2);
2357 QVERIFY(QTestAccessibility::containsEvent(&selectionEvent));
2358 QVERIFY(QTestAccessibility::containsEvent(&focusEvent));
2359 QTest::mouseClick(listView->viewport(), Qt::LeftButton, 0, listView->visualItemRect(listView->item(2)).center());
2361 QAccessibleEvent selectionEvent2(listView, QAccessible::Selection);
2362 selectionEvent2.setChild(3);
2363 QAccessibleEvent focusEvent2(listView, QAccessible::Focus);
2364 focusEvent2.setChild(3);
2365 QVERIFY(QTestAccessibility::containsEvent(&selectionEvent2));
2366 QVERIFY(QTestAccessibility::containsEvent(&focusEvent2));
2368 listView->addItem("Munich");
2369 QCOMPARE(iface->childCount(), 4);
2372 QAccessibleTableInterface *table2 = iface->tableInterface();
2374 QCOMPARE(table2->columnCount(), 1);
2375 QCOMPARE(table2->rowCount(), 4);
2376 QAIPtr cell1 = QAIPtr(table2->cellAt(0,0));
2378 QCOMPARE(cell1->text(QAccessible::Name), QString("Oslo"));
2380 QAIPtr cell4 = QAIPtr(table2->cellAt(3,0));
2382 QCOMPARE(cell4->text(QAccessible::Name), QString("Munich"));
2383 QCOMPARE(cell4->role(), QAccessible::ListItem);
2385 QAccessibleTableCellInterface *cellInterface = cell4->tableCellInterface();
2386 QVERIFY(cellInterface);
2387 QCOMPARE(cellInterface->rowIndex(), 3);
2388 QCOMPARE(cellInterface->columnIndex(), 0);
2389 QCOMPARE(cellInterface->rowExtent(), 1);
2390 QCOMPARE(cellInterface->columnExtent(), 1);
2391 QCOMPARE(cellInterface->rowHeaderCells(), QList<QAccessibleInterface*>());
2392 QCOMPARE(cellInterface->columnHeaderCells(), QList<QAccessibleInterface*>());
2394 QCOMPARE(QAIPtr(cellInterface->table())->object(), listView);
2396 listView->clearSelection();
2397 QVERIFY(!(cell4->state().expandable));
2398 QVERIFY( (cell4->state().selectable));
2399 QVERIFY(!(cell4->state().selected));
2400 table2->selectRow(3);
2401 QCOMPARE(listView->selectedItems().size(), 1);
2402 QCOMPARE(listView->selectedItems().at(0)->text(), QLatin1String("Munich"));
2403 QVERIFY(cell4->state().selected);
2404 QVERIFY(cellInterface->isSelected());
2406 QVERIFY(table2->cellAt(-1, 0) == 0);
2407 QVERIFY(table2->cellAt(0, -1) == 0);
2408 QVERIFY(table2->cellAt(0, 1) == 0);
2409 QVERIFY(table2->cellAt(4, 0) == 0);
2413 QTestAccessibility::clearEvents();
2416 void tst_QAccessibility::treeTest()
2418 QTreeWidget *treeView = new QTreeWidget;
2419 treeView->setColumnCount(2);
2420 QTreeWidgetItem *header = new QTreeWidgetItem;
2421 header->setText(0, "Artist");
2422 header->setText(1, "Work");
2423 treeView->setHeaderItem(header);
2425 QTreeWidgetItem *root1 = new QTreeWidgetItem;
2426 root1->setText(0, "Spain");
2427 treeView->addTopLevelItem(root1);
2429 QTreeWidgetItem *item1 = new QTreeWidgetItem;
2430 item1->setText(0, "Picasso");
2431 item1->setText(1, "Guernica");
2432 root1->addChild(item1);
2434 QTreeWidgetItem *item2 = new QTreeWidgetItem;
2435 item2->setText(0, "Tapies");
2436 item2->setText(1, "Ambrosia");
2437 root1->addChild(item2);
2439 QTreeWidgetItem *root2 = new QTreeWidgetItem;
2440 root2->setText(0, "Austria");
2441 treeView->addTopLevelItem(root2);
2443 QTreeWidgetItem *item3 = new QTreeWidgetItem;
2444 item3->setText(0, "Klimt");
2445 item3->setText(1, "The Kiss");
2446 root2->addChild(item3);
2448 treeView->resize(400,400);
2451 QCoreApplication::processEvents();
2454 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(treeView);
2455 QCOMPARE(verifyHierarchy(iface), 0);
2457 QCOMPARE((int)iface->role(), (int)QAccessible::Tree);
2458 // header and 2 rows (the others are not expanded, thus not visible)
2459 QCOMPARE(iface->childCount(), 6);
2461 QAccessibleInterface *header1 = 0;
2462 header1 = iface->child(0);
2464 QCOMPARE(iface->indexOfChild(header1), 0);
2465 QCOMPARE(header1->text(QAccessible::Name), QString("Artist"));
2466 QCOMPARE(header1->role(), QAccessible::ColumnHeader);
2469 QAccessibleInterface *child1 = 0;
2470 child1 = iface->child(2);
2472 QCOMPARE(iface->indexOfChild(child1), 2);
2473 QCOMPARE(child1->text(QAccessible::Name), QString("Spain"));
2474 QCOMPARE(child1->role(), QAccessible::TreeItem);
2475 QVERIFY(!(child1->state().expanded));
2478 QAccessibleInterface *child2 = 0;
2479 child2 = iface->child(4);
2481 QCOMPARE(iface->indexOfChild(child2), 4);
2482 QCOMPARE(child2->text(QAccessible::Name), QString("Austria"));
2485 QTestAccessibility::clearEvents();
2488 QAccessibleTableInterface *table2 = iface->tableInterface();
2490 QCOMPARE(table2->columnCount(), 2);
2491 QCOMPARE(table2->rowCount(), 2);
2492 QAccessibleInterface *cell1;
2493 QVERIFY(cell1 = table2->cellAt(0,0));
2494 QCOMPARE(cell1->text(QAccessible::Name), QString("Spain"));
2495 QAccessibleInterface *cell2;
2496 QVERIFY(cell2 = table2->cellAt(1,0));
2497 QCOMPARE(cell2->text(QAccessible::Name), QString("Austria"));
2498 QCOMPARE(cell2->role(), QAccessible::TreeItem);
2499 QCOMPARE(cell2->tableCellInterface()->rowIndex(), 1);
2500 QCOMPARE(cell2->tableCellInterface()->columnIndex(), 0);
2501 QVERIFY(cell2->state().expandable);
2502 QCOMPARE(iface->indexOfChild(cell2), 4);
2503 QVERIFY(!(cell2->state().expanded));
2504 QCOMPARE(table2->columnDescription(1), QString("Work"));
2508 treeView->expandAll();
2510 // Need this for indexOfchild to work.
2511 QCoreApplication::processEvents();
2514 QCOMPARE(table2->columnCount(), 2);
2515 QCOMPARE(table2->rowCount(), 5);
2516 cell1 = table2->cellAt(1,0);
2517 QCOMPARE(cell1->text(QAccessible::Name), QString("Picasso"));
2518 QCOMPARE(iface->indexOfChild(cell1), 4); // 2 header + 2 for root item
2520 cell2 = table2->cellAt(4,0);
2521 QCOMPARE(cell2->text(QAccessible::Name), QString("Klimt"));
2522 QCOMPARE(cell2->role(), QAccessible::TreeItem);
2523 QCOMPARE(cell2->tableCellInterface()->rowIndex(), 4);
2524 QCOMPARE(cell2->tableCellInterface()->columnIndex(), 0);
2525 QVERIFY(!(cell2->state().expandable));
2526 QCOMPARE(iface->indexOfChild(cell2), 10);
2528 QCOMPARE(table2->columnDescription(0), QString("Artist"));
2529 QCOMPARE(table2->columnDescription(1), QString("Work"));
2532 QTestAccessibility::clearEvents();
2535 void tst_QAccessibility::tableTest()
2537 QTableWidget *tableView = new QTableWidget(3, 3);
2538 tableView->setColumnCount(3);
2539 QStringList hHeader;
2540 hHeader << "h1" << "h2" << "h3";
2541 tableView->setHorizontalHeaderLabels(hHeader);
2543 QStringList vHeader;
2544 vHeader << "v1" << "v2" << "v3";
2545 tableView->setVerticalHeaderLabels(vHeader);
2547 for (int i = 0; i<9; ++i) {
2548 QTableWidgetItem *item = new QTableWidgetItem;
2549 item->setText(QString::number(i/3) + QString(".") + QString::number(i%3));
2550 tableView->setItem(i/3, i%3, item);
2553 tableView->resize(600,600);
2555 QTest::qWait(1); // Need this for indexOfchild to work.
2556 QCoreApplication::processEvents();
2559 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(tableView);
2560 QCOMPARE(verifyHierarchy(iface), 0);
2562 QCOMPARE((int)iface->role(), (int)QAccessible::Table);
2563 // header and 2 rows (the others are not expanded, thus not visible)
2564 QCOMPARE(iface->childCount(), 9+3+3+1); // cell+headers+topleft button
2566 QAccessibleInterface *cornerButton = iface->child(0);
2567 QVERIFY(cornerButton);
2568 QCOMPARE(iface->indexOfChild(cornerButton), 0);
2569 QCOMPARE(cornerButton->role(), QAccessible::Pane);
2570 delete cornerButton;
2572 QAccessibleInterface *child1 = iface->child(2);
2574 QCOMPARE(iface->indexOfChild(child1), 2);
2575 QCOMPARE(child1->text(QAccessible::Name), QString("h2"));
2576 QCOMPARE(child1->role(), QAccessible::ColumnHeader);
2577 QVERIFY(!(child1->state().expanded));
2580 QAccessibleInterface *child2 = iface->child(10);
2582 QCOMPARE(iface->indexOfChild(child2), 10);
2583 QCOMPARE(child2->text(QAccessible::Name), QString("1.1"));
2584 QAccessibleTableCellInterface *cell2Iface = child2->tableCellInterface();
2585 QCOMPARE(cell2Iface->rowIndex(), 1);
2586 QCOMPARE(cell2Iface->columnIndex(), 1);
2589 QAccessibleInterface *child3 = iface->child(11);
2590 QCOMPARE(iface->indexOfChild(child3), 11);
2591 QCOMPARE(child3->text(QAccessible::Name), QString("1.2"));
2594 QTestAccessibility::clearEvents();
2597 QAccessibleTableInterface *table2 = iface->tableInterface();
2599 QCOMPARE(table2->columnCount(), 3);
2600 QCOMPARE(table2->rowCount(), 3);
2601 QAccessibleInterface *cell1;
2602 QVERIFY(cell1 = table2->cellAt(0,0));
2603 QCOMPARE(cell1->text(QAccessible::Name), QString("0.0"));
2604 QCOMPARE(iface->indexOfChild(cell1), 5);
2606 QAccessibleInterface *cell2;
2607 QVERIFY(cell2 = table2->cellAt(0,1));
2608 QCOMPARE(cell2->text(QAccessible::Name), QString("0.1"));
2609 QCOMPARE(cell2->role(), QAccessible::Cell);
2610 QCOMPARE(cell2->tableCellInterface()->rowIndex(), 0);
2611 QCOMPARE(cell2->tableCellInterface()->columnIndex(), 1);
2612 QCOMPARE(iface->indexOfChild(cell2), 6);
2615 QAccessibleInterface *cell3;
2616 QVERIFY(cell3 = table2->cellAt(1,2));
2617 QCOMPARE(cell3->text(QAccessible::Name), QString("1.2"));
2618 QCOMPARE(cell3->role(), QAccessible::Cell);
2619 QCOMPARE(cell3->tableCellInterface()->rowIndex(), 1);
2620 QCOMPARE(cell3->tableCellInterface()->columnIndex(), 2);
2621 QCOMPARE(iface->indexOfChild(cell3), 11);
2624 QCOMPARE(table2->columnDescription(0), QString("h1"));
2625 QCOMPARE(table2->columnDescription(1), QString("h2"));
2626 QCOMPARE(table2->columnDescription(2), QString("h3"));
2627 QCOMPARE(table2->rowDescription(0), QString("v1"));
2628 QCOMPARE(table2->rowDescription(1), QString("v2"));
2629 QCOMPARE(table2->rowDescription(2), QString("v3"));
2635 QTestAccessibility::clearEvents();
2638 void tst_QAccessibility::calendarWidgetTest()
2640 #ifndef QT_NO_CALENDARWIDGET
2642 QCalendarWidget calendarWidget;
2644 QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&calendarWidget);
2646 QCOMPARE(interface->role(), QAccessible::Table);
2647 QVERIFY(!interface->rect().isValid());
2648 QCOMPARE(interface->childAt(200, 200), static_cast<QAccessibleInterface*>(0));
2650 calendarWidget.resize(400, 300);
2651 calendarWidget.show();
2652 #if defined(Q_OS_UNIX)
2653 QCoreApplication::processEvents();
2657 // 1 = navigationBar, 2 = view.
2658 QCOMPARE(interface->childCount(), 2);
2660 const QRect globalGeometry = QRect(calendarWidget.mapToGlobal(QPoint(0, 0)),
2661 calendarWidget.size());
2662 QCOMPARE(interface->rect(), globalGeometry);
2664 QWidget *navigationBar = 0;
2665 foreach (QObject *child, calendarWidget.children()) {
2666 if (child->objectName() == QLatin1String("qt_calendar_navigationbar")) {
2667 navigationBar = static_cast<QWidget *>(child);
2671 QVERIFY(navigationBar);
2672 QVERIFY(verifyChild(navigationBar, interface, 0, globalGeometry));
2674 QAbstractItemView *calendarView = 0;
2675 foreach (QObject *child, calendarWidget.children()) {
2676 if (child->objectName() == QLatin1String("qt_calendar_calendarview")) {
2677 calendarView = static_cast<QAbstractItemView *>(child);
2681 QVERIFY(calendarView);
2682 QVERIFY(verifyChild(calendarView, interface, 1, globalGeometry));
2684 // Hide navigation bar.
2685 calendarWidget.setNavigationBarVisible(false);
2686 QCOMPARE(interface->childCount(), 1);
2687 QVERIFY(!navigationBar->isVisible());
2689 QVERIFY(verifyChild(calendarView, interface, 0, globalGeometry));
2691 // Show navigation bar.
2692 calendarWidget.setNavigationBarVisible(true);
2693 QCOMPARE(interface->childCount(), 2);
2694 QVERIFY(navigationBar->isVisible());
2696 // Navigate to the navigation bar via Child.
2697 QAccessibleInterface *navigationBarInterface = interface->child(0);
2698 QVERIFY(navigationBarInterface);
2699 QCOMPARE(navigationBarInterface->object(), (QObject*)navigationBar);
2701 // Navigate to the view via Child.
2702 QAccessibleInterface *calendarViewInterface = interface->child(1);
2703 QVERIFY(calendarViewInterface);
2704 QCOMPARE(calendarViewInterface->object(), (QObject*)calendarView);
2706 QVERIFY(!interface->child(-1));
2708 // In order for geometric navigation to work they must share the same parent
2709 QCOMPARE(navigationBarInterface->parent()->object(), calendarViewInterface->parent()->object());
2710 QVERIFY(navigationBarInterface->rect().bottom() < calendarViewInterface->rect().top());
2711 delete calendarViewInterface;
2712 calendarViewInterface = 0;
2713 delete navigationBarInterface;
2714 navigationBarInterface = 0;
2717 QTestAccessibility::clearEvents();
2718 #endif // QT_NO_CALENDARWIDGET
2721 void tst_QAccessibility::dockWidgetTest()
2723 #ifndef QT_NO_DOCKWIDGET
2724 // Set up a proper main window with two dock widgets
2725 QMainWindow *mw = new QMainWindow();
2726 QFrame *central = new QFrame(mw);
2727 mw->setCentralWidget(central);
2728 QMenuBar *mb = new QMenuBar(mw);
2729 mb->addAction(tr("&File"));
2732 QDockWidget *dock1 = new QDockWidget(mw);
2733 mw->addDockWidget(Qt::LeftDockWidgetArea, dock1);
2734 QPushButton *pb1 = new QPushButton(tr("Push me"), dock1);
2735 dock1->setWidget(pb1);
2737 QDockWidget *dock2 = new QDockWidget(mw);
2738 mw->addDockWidget(Qt::BottomDockWidgetArea, dock2);
2739 QPushButton *pb2 = new QPushButton(tr("Push me"), dock2);
2740 dock2->setWidget(pb2);
2742 mw->resize(600,400);
2744 #if defined(Q_OS_UNIX)
2745 QCoreApplication::processEvents();
2749 QAccessibleInterface *accMainWindow = QAccessible::queryAccessibleInterface(mw);
2750 // 4 children: menu bar, dock1, dock2, and central widget
2751 QCOMPARE(accMainWindow->childCount(), 4);
2752 QAccessibleInterface *accDock1 = 0;
2753 for (int i = 0; i < 4; ++i) {
2754 accDock1 = accMainWindow->child(i);
2755 if (accMainWindow->role() == QAccessible::Window) {
2756 if (accDock1 && qobject_cast<QDockWidget*>(accDock1->object()) == dock1) {
2764 QCOMPARE(accDock1->role(), QAccessible::Window);
2766 QAccessibleInterface *dock1TitleBar = accDock1->child(0);
2767 QCOMPARE(dock1TitleBar->role(), QAccessible::TitleBar);
2768 QVERIFY(accDock1->rect().contains(dock1TitleBar->rect()));
2769 delete dock1TitleBar;
2771 QPoint globalPos = dock1->mapToGlobal(QPoint(0,0));
2772 globalPos.rx()+=5; //### query style
2774 QAccessibleInterface *childAt = accDock1->childAt(globalPos.x(), globalPos.y()); //###
2775 QCOMPARE(childAt->role(), QAccessible::TitleBar);
2776 int index = accDock1->indexOfChild(childAt);
2778 QAccessibleInterface *accTitleBar = accDock1->child(index);
2780 QCOMPARE(accTitleBar->role(), QAccessible::TitleBar);
2781 QCOMPARE(accDock1->indexOfChild(accTitleBar), 0);
2782 QAccessibleInterface *acc;
2783 acc = accTitleBar->parent();
2785 QCOMPARE(acc->role(), QAccessible::Window);
2795 QTestAccessibility::clearEvents();
2796 #endif // QT_NO_DOCKWIDGET
2799 void tst_QAccessibility::comboBoxTest()
2801 #if defined(Q_OS_WINCE)
2802 if (!IsValidCEPlatform())
2803 QSKIP("Test skipped on Windows Mobile test hardware");
2805 { // not editable combobox
2807 combo.addItems(QStringList() << "one" << "two" << "three");
2809 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&combo);
2810 QCOMPARE(verifyHierarchy(iface), 0);
2812 QCOMPARE(iface->role(), QAccessible::ComboBox);
2813 QCOMPARE(iface->childCount(), 1);
2816 QCOMPARE(iface->text(QAccessible::Name), QLatin1String("one"));
2818 QCOMPARE(iface->text(QAccessible::Value), QLatin1String("one"));
2819 combo.setCurrentIndex(2);
2821 QCOMPARE(iface->text(QAccessible::Name), QLatin1String("three"));
2823 QCOMPARE(iface->text(QAccessible::Value), QLatin1String("three"));
2825 QAccessibleInterface *listIface = iface->child(0);
2826 QCOMPARE(listIface->role(), QAccessible::List);
2827 QCOMPARE(listIface->childCount(), 3);
2829 QVERIFY(!combo.view()->isVisible());
2830 QVERIFY(iface->actionInterface());
2831 QCOMPARE(iface->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::showMenuAction());
2832 iface->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction());
2833 QVERIFY(combo.view()->isVisible());
2838 { // editable combobox
2839 QComboBox editableCombo;
2840 editableCombo.show();
2841 editableCombo.setEditable(true);
2842 editableCombo.addItems(QStringList() << "foo" << "bar" << "baz");
2844 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&editableCombo);
2845 QCOMPARE(verifyHierarchy(iface), 0);
2847 QCOMPARE(iface->role(), QAccessible::ComboBox);
2848 QCOMPARE(iface->childCount(), 2);
2850 QAccessibleInterface *listIface = iface->child(0);
2851 QCOMPARE(listIface->role(), QAccessible::List);
2852 QAccessibleInterface *editIface = iface->child(1);
2853 QCOMPARE(editIface->role(), QAccessible::EditableText);
2860 QTestAccessibility::clearEvents();
2863 void tst_QAccessibility::labelTest()
2865 QString text = "Hello World";
2866 QLabel *label = new QLabel(text);
2869 #if defined(Q_OS_UNIX)
2870 QCoreApplication::processEvents();
2874 QAccessibleInterface *acc_label = QAccessible::queryAccessibleInterface(label);
2877 QCOMPARE(acc_label->text(QAccessible::Name), text);
2881 QTestAccessibility::clearEvents();
2883 QPixmap testPixmap(50, 50);
2887 imageLabel.setPixmap(testPixmap);
2888 imageLabel.setToolTip("Test Description");
2890 acc_label = QAccessible::queryAccessibleInterface(&imageLabel);
2893 QAccessibleImageInterface *imageInterface = acc_label->imageInterface();
2894 QVERIFY(imageInterface);
2896 QCOMPARE(imageInterface->imageSize(), testPixmap.size());
2897 QCOMPARE(imageInterface->imageDescription(), QString::fromLatin1("Test Description"));
2898 const QPoint labelPos = imageLabel.mapToGlobal(QPoint(0,0));
2899 QCOMPARE(imageInterface->imagePosition().topLeft(), labelPos);
2903 QTestAccessibility::clearEvents();
2906 void tst_QAccessibility::accelerators()
2908 QWidget *window = new QWidget;
2909 QHBoxLayout *lay = new QHBoxLayout(window);
2910 QLabel *label = new QLabel(tr("&Line edit"), window);
2911 QLineEdit *le = new QLineEdit(window);
2912 lay->addWidget(label);
2914 label->setBuddy(le);
2918 QAccessibleInterface *accLineEdit = QAccessible::queryAccessibleInterface(le);
2919 QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QKeySequence(Qt::ALT).toString(QKeySequence::NativeText) + QLatin1String("L"));
2920 QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QKeySequence(Qt::ALT).toString(QKeySequence::NativeText) + QLatin1String("L"));
2921 label->setText(tr("Q &"));
2922 QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QString());
2923 label->setText(tr("Q &&"));
2924 QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QString());
2925 label->setText(tr("Q && A"));
2926 QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QString());
2927 label->setText(tr("Q &&&A"));
2928 QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QKeySequence(Qt::ALT).toString(QKeySequence::NativeText) + QLatin1String("A"));
2929 label->setText(tr("Q &&A"));
2930 QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QString());
2932 #if !defined(QT_NO_DEBUG) && !defined(Q_OS_MAC)
2933 QTest::ignoreMessage(QtWarningMsg, "QKeySequence::mnemonic: \"Q &A&B\" contains multiple occurrences of '&'");
2935 label->setText(tr("Q &A&B"));
2936 QCOMPARE(accLineEdit->text(QAccessible::Accelerator), QKeySequence(Qt::ALT).toString(QKeySequence::NativeText) + QLatin1String("A"));
2938 #if defined(Q_OS_UNIX)
2939 QCoreApplication::processEvents();
2943 QTestAccessibility::clearEvents();
2946 void tst_QAccessibility::bridgeTest()
2948 // For now this is a simple test to see if the bridge is working at all.
2949 // Ideally it should be extended to test all aspects of the bridge.
2951 // First, test MSAA part of bridge
2952 QWidget *window = new QWidget;
2953 QVBoxLayout *lay = new QVBoxLayout(window);
2954 QPushButton *button = new QPushButton(tr("Push me"), window);
2955 QLineEdit *le = new QLineEdit(window);
2956 lay->addWidget(button);
2960 QTest::qWaitForWindowShown(window);
2962 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(button);
2963 QPoint buttonPos = button->mapToGlobal(QPoint(0,0));
2964 QRect buttonRect = iface->rect();
2965 QCOMPARE(buttonRect.topLeft(), buttonPos);
2968 // All set, now test the bridge.
2970 pt.x = buttonRect.center().x();
2971 pt.y = buttonRect.center().y();
2975 HRESULT hr = ::AccessibleObjectFromPoint(pt, &iacc, &varChild);
2976 QVERIFY(SUCCEEDED(hr));
2981 // **** Test get_accRole ****
2983 hr = iacc->get_accRole(varSELF, &varRole);
2984 QVERIFY(SUCCEEDED(hr));
2986 QCOMPARE(varRole.vt, (VARTYPE)VT_I4);
2987 QCOMPARE(varRole.lVal, (LONG)ROLE_SYSTEM_PUSHBUTTON);
2989 // **** Test accLocation ****
2991 hr = iacc->accLocation(&x, &y, &w, &h, varSELF);
2992 QCOMPARE(buttonRect, QRect(x, y, w, h));
2995 // Test IAccessible2 part of bridge
2996 IServiceProvider *pService = 0;
2997 hr = iacc->QueryInterface(IID_IServiceProvider, (void **)&pService);
2998 if (SUCCEEDED(hr)) {
2999 IAccessible2 *pIA2 = 0;
3000 hr = pService->QueryService(IID_IAccessible, IID_IAccessible2, (void**)&pIA2);
3001 if (SUCCEEDED(hr) && pIA2) {
3002 // The control supports IAccessible2.
3003 // pIA2 is the reference to the accessible object's IAccessible2 interface.
3005 /***** Test IAccessibleComponent *****/
3006 IAccessibleComponent *ia2Component = 0;
3007 hr = pIA2->QueryInterface(IID_IAccessibleComponent, (void**)&ia2Component);
3008 QVERIFY(SUCCEEDED(hr));
3010 hr = ia2Component->get_locationInParent(&x, &y);
3011 QVERIFY(SUCCEEDED(hr));
3012 QCOMPARE(button->pos(), QPoint(x, y));
3013 ia2Component->Release();
3015 /***** Test IAccessibleAction *****/
3016 IAccessibleAction *ia2Action = 0;
3017 hr = pIA2->QueryInterface(IID_IAccessibleAction, (void**)&ia2Action);
3018 QVERIFY(SUCCEEDED(hr));
3021 ia2Action->nActions(&nActions);
3022 QVERIFY(nActions >= 1); // "Press" and "SetFocus"
3024 ia2Action->get_name(0, &actionName);
3025 QString name((QChar*)actionName);
3026 QCOMPARE(name, QAccessibleActionInterface::pressAction());
3027 ia2Action->Release();
3032 pService->Release();
3037 QTestAccessibility::clearEvents();
3041 QTEST_MAIN(tst_QAccessibility)
3042 #include "tst_qaccessibility.moc"