summaryrefslogtreecommitdiffstats
path: root/src/testlib/qtestaccessible.h
blob: 29f69bd81925a81ba6ba176c3d6f4b67d3484271 (plain)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
// Copyright (C) 2016 The Qt Company Ltd.// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#ifndef QTESTACCESSIBLE_H#define QTESTACCESSIBLE_H#if 0// inform syncqt#pragma qt_no_master_include#endif#include <QtCore/qglobal.h>#define QVERIFY_EVENT(event) \ QVERIFY(QTestAccessibility::verifyEvent(event))#include <QtCore/qlist.h>#include <QtCore/qdebug.h>#include <QtGui/qaccessible.h>#include <QtGui/qguiapplication.h>#include <QtTest/qttestglobal.h>#include <QtTest/qtestsystem.h>#if QT_CONFIG(accessibility) QT_BEGIN_NAMESPACE class QObject;// Use pointers since we subclass QAccessibleEventusing EventList = QList<QAccessibleEvent*>;booloperator==(const QAccessibleEvent &l,const QAccessibleEvent &r){if(l.type() != r.type()) {// qDebug() << "QAccessibleEvent with wrong type: " << qAccessibleEventString(l.type()) << " and " << qAccessibleEventString(r.type());return false;}if(l.object() != r.object() || l.child() != r.child()) {// qDebug() << "QAccessibleEvent for wrong object: " << l.object() << " and " << r.object() << " child: " << l.child() << " and " << r.child();return false;}if(l.type() ==QAccessible::StateChanged) {return static_cast<const QAccessibleStateChangeEvent*>(&l)->changedStates()==static_cast<const QAccessibleStateChangeEvent*>(&r)->changedStates();}else if(l.type() ==QAccessible::TextCaretMoved) {return static_cast<const QAccessibleTextCursorEvent*>(&l)->cursorPosition()==static_cast<const QAccessibleTextCursorEvent*>(&r)->cursorPosition();}else if(l.type() ==QAccessible::TextSelectionChanged) {const QAccessibleTextSelectionEvent *le =static_cast<const QAccessibleTextSelectionEvent*>(&l);const QAccessibleTextSelectionEvent *re =static_cast<const QAccessibleTextSelectionEvent*>(&r);return le->cursorPosition() == re->cursorPosition() && le->selectionStart() == re->selectionStart() && le->selectionEnd() == re->selectionEnd();}else if(l.type() ==QAccessible::TextInserted) {const QAccessibleTextInsertEvent *le =static_cast<const QAccessibleTextInsertEvent*>(&l);const QAccessibleTextInsertEvent *re =static_cast<const QAccessibleTextInsertEvent*>(&r);return le->cursorPosition() == re->cursorPosition() && le->changePosition() == re->changePosition() && le->textInserted() == re->textInserted();}else if(l.type() ==QAccessible::TextRemoved) {const QAccessibleTextRemoveEvent *le =static_cast<const QAccessibleTextRemoveEvent*>(&l);const QAccessibleTextRemoveEvent *re =static_cast<const QAccessibleTextRemoveEvent*>(&r);return le->cursorPosition() == re->cursorPosition() && le->changePosition() == re->changePosition() && le->textRemoved() == re->textRemoved();}else if(l.type() ==QAccessible::TextUpdated) {const QAccessibleTextUpdateEvent *le =static_cast<const QAccessibleTextUpdateEvent*>(&l);const QAccessibleTextUpdateEvent *re =static_cast<const QAccessibleTextUpdateEvent*>(&r);return le->cursorPosition() == re->cursorPosition() && le->changePosition() == re->changePosition() && le->textInserted() == re->textInserted() && le->textRemoved() == re->textRemoved();}else if(l.type() ==QAccessible::ValueChanged) {const QAccessibleValueChangeEvent *le =static_cast<const QAccessibleValueChangeEvent*>(&l);const QAccessibleValueChangeEvent *re =static_cast<const QAccessibleValueChangeEvent*>(&r);return le->value() == re->value();}return true;}class QTestAccessibility {public:static voidinitialize(){if(!instance()) {instance() =new QTestAccessibility;qAddPostRoutine(cleanup);}}static voidcleanup(){deleteinstance();instance() =nullptr;}static voidclearEvents() {eventList().clear(); }static EventList events() {returneventList(); }static boolverifyEvent(QAccessibleEvent *ev){for(int i =0;eventList().isEmpty() && i <5; ++i)QTest::qWait(50);if(eventList().isEmpty()) {qWarning("Timeout waiting for accessibility event.");return false;}const bool res = *eventList().constFirst() == *ev;if(!res)qWarning("%s",qPrintable(msgAccessibilityEventListMismatch(eventList(), ev)));deleteeventList().takeFirst();return res;}static boolcontainsEvent(QAccessibleEvent *event) {for(const QAccessibleEvent *ev :std::as_const(eventList())) {if(*ev == *event)return true;}return false;}private:QTestAccessibility(){QAccessible::installUpdateHandler(updateHandler);QAccessible::installRootObjectHandler(rootObjectHandler);}~QTestAccessibility(){QAccessible::installUpdateHandler(nullptr);QAccessible::installRootObjectHandler(nullptr);}static voidrootObjectHandler(QObject *object){// qDebug("rootObjectHandler called %p", object);if(object) { QGuiApplication* app = qobject_cast<QGuiApplication*>(object);if( !app )qWarning("root Object is not a QGuiApplication!");}else{qWarning("root Object called with 0 pointer");}}static voidupdateHandler(QAccessibleEvent *event){auto ev =copyEvent(event);if(auto obj = ev->object()) {QObject::connect(obj, &QObject::destroyed, obj, [&, ev](){auto index=eventList().indexOf(ev);if(index == -1)return;eventList().at(index)->m_object =nullptr;});}eventList().append(ev);}static QAccessibleEvent *copyEvent(QAccessibleEvent *event){ QAccessibleEvent *ev;if(event->type() ==QAccessible::StateChanged) {if(event->object()) ev =newQAccessibleStateChangeEvent(event->object(),static_cast<QAccessibleStateChangeEvent*>(event)->changedStates());else ev =newQAccessibleStateChangeEvent(event->accessibleInterface(),static_cast<QAccessibleStateChangeEvent*>(event)->changedStates());}else if(event->type() ==QAccessible::TextCaretMoved) {if(event->object()) ev =newQAccessibleTextCursorEvent(event->object(),static_cast<QAccessibleTextCursorEvent*>(event)->cursorPosition());else ev =newQAccessibleTextCursorEvent(event->accessibleInterface(),static_cast<QAccessibleTextCursorEvent*>(event)->cursorPosition());}else if(event->type() ==QAccessible::TextSelectionChanged) {const QAccessibleTextSelectionEvent *original =static_cast<QAccessibleTextSelectionEvent*>(event); QAccessibleTextSelectionEvent *sel;if(event->object()) sel =newQAccessibleTextSelectionEvent(event->object(), original->selectionStart(), original->selectionEnd());else sel =newQAccessibleTextSelectionEvent(event->accessibleInterface(), original->selectionStart(), original->selectionEnd()); sel->setCursorPosition(original->cursorPosition()); ev = sel;}else if(event->type() ==QAccessible::TextInserted) {const QAccessibleTextInsertEvent *original =static_cast<QAccessibleTextInsertEvent*>(event); QAccessibleTextInsertEvent *ins;if(original->object()) ins =newQAccessibleTextInsertEvent(event->object(), original->changePosition(), original->textInserted());else ins =newQAccessibleTextInsertEvent(event->accessibleInterface(), original->changePosition(), original->textInserted()); ins->setCursorPosition(original->cursorPosition()); ev = ins;}else if(event->type() ==QAccessible::TextRemoved) {const QAccessibleTextRemoveEvent *original =static_cast<QAccessibleTextRemoveEvent*>(event); QAccessibleTextRemoveEvent *rem;if(event->object()) rem =newQAccessibleTextRemoveEvent(event->object(), original->changePosition(), original->textRemoved());else rem =newQAccessibleTextRemoveEvent(event->accessibleInterface(), original->changePosition(), original->textRemoved()); rem->setCursorPosition(original->cursorPosition()); ev = rem;}else if(event->type() ==QAccessible::TextUpdated) {const QAccessibleTextUpdateEvent *original =static_cast<QAccessibleTextUpdateEvent*>(event); QAccessibleTextUpdateEvent *upd;if(event->object()) upd =newQAccessibleTextUpdateEvent(event->object(), original->changePosition(), original->textRemoved(), original->textInserted());else upd =newQAccessibleTextUpdateEvent(event->accessibleInterface(), original->changePosition(), original->textRemoved(), original->textInserted()); upd->setCursorPosition(original->cursorPosition()); ev = upd;}else if(event->type() ==QAccessible::ValueChanged) {if(event->object()) ev =newQAccessibleValueChangeEvent(event->object(),static_cast<QAccessibleValueChangeEvent*>(event)->value());else ev =newQAccessibleValueChangeEvent(event->accessibleInterface(),static_cast<QAccessibleValueChangeEvent*>(event)->value());}else if(event->type() ==QAccessible::TableModelChanged) { QAccessibleTableModelChangeEvent *oldEvent =static_cast<QAccessibleTableModelChangeEvent*>(event); QAccessibleTableModelChangeEvent *newEvent;if(event->object()) newEvent =newQAccessibleTableModelChangeEvent(event->object(), oldEvent->modelChangeType());else newEvent =newQAccessibleTableModelChangeEvent(event->accessibleInterface(), oldEvent->modelChangeType()); newEvent->setFirstRow(oldEvent->firstRow()); newEvent->setFirstColumn(oldEvent->firstColumn()); newEvent->setLastRow(oldEvent->lastRow()); newEvent->setLastColumn(oldEvent->lastColumn()); ev = newEvent;}else if(event->type() ==QAccessible::Announcement) { QAccessibleAnnouncementEvent *oldEvent =static_cast<QAccessibleAnnouncementEvent *>(event); QAccessibleAnnouncementEvent *newEvent;if(event->object()) newEvent =newQAccessibleAnnouncementEvent(event->object(), oldEvent->message());else newEvent =newQAccessibleAnnouncementEvent(event->accessibleInterface(), oldEvent->message()); newEvent->setPoliteness(oldEvent->politeness()); ev = newEvent;}else{if(event->object()) ev =newQAccessibleEvent(event->object(), event->type());else ev =newQAccessibleEvent(event->accessibleInterface(), event->type());} ev->setChild(event->child());return ev;}static EventList &eventList(){static EventList list;return list;}static QTestAccessibility *&instance(){static QTestAccessibility *ta =nullptr;return ta;}private:static QString msgAccessibilityEventListMismatch(const EventList &haystack,const QAccessibleEvent *needle){ QString rc; QDebug str =QDebug(&rc).nospace(); str <<"Event "<< *needle <<" not found at head of event list of size "<< haystack.size() <<" :";for(const QAccessibleEvent *e : haystack) str <<' '<< *e;return rc;}}; QT_END_NAMESPACE #endif// QT_CONFIG(accessibility)#endif// QTESTACCESSIBLE_H
close