Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qtestaccessible.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QTESTACCESSIBLE_H
5#define QTESTACCESSIBLE_H
6
7#if 0
8// inform syncqt
9#pragma qt_no_master_include
10#endif
11
12#include <QtCore/qglobal.h>
13
14#define QVERIFY_EVENT(event) \
15 QVERIFY(QTestAccessibility::verifyEvent(event))
16
17#include <QtCore/qlist.h>
18#include <QtCore/qdebug.h>
19#include <QtGui/qaccessible.h>
20#include <QtGui/qguiapplication.h>
21#include <QtTest/qttestglobal.h>
22#include <QtTest/qtestsystem.h>
23
24#if QT_CONFIG(accessibility)
25
27
28
29class QObject;
30
31// Use pointers since we subclass QAccessibleEvent
32using EventList = QList<QAccessibleEvent*>;
33
34bool operator==(const QAccessibleEvent &l, const QAccessibleEvent &r)
35{
36 if (l.type() != r.type()) {
37// qDebug() << "QAccessibleEvent with wrong type: " << qAccessibleEventString(l.type()) << " and " << qAccessibleEventString(r.type());
38 return false;
39 }
40 if (l.object() != r.object() ||
41 l.child() != r.child()) {
42// qDebug() << "QAccessibleEvent for wrong object: " << l.object() << " and " << r.object() << " child: " << l.child() << " and " << r.child();
43 return false;
44 }
45
46 if (l.type() == QAccessible::StateChanged) {
47 return static_cast<const QAccessibleStateChangeEvent*>(&l)->changedStates()
48 == static_cast<const QAccessibleStateChangeEvent*>(&r)->changedStates();
49 } else if (l.type() == QAccessible::TextCaretMoved) {
50 return static_cast<const QAccessibleTextCursorEvent*>(&l)->cursorPosition()
51 == static_cast<const QAccessibleTextCursorEvent*>(&r)->cursorPosition();
52 } else if (l.type() == QAccessible::TextSelectionChanged) {
53 const QAccessibleTextSelectionEvent *le = static_cast<const QAccessibleTextSelectionEvent*>(&l);
54 const QAccessibleTextSelectionEvent *re = static_cast<const QAccessibleTextSelectionEvent*>(&r);
55 return le->cursorPosition() == re->cursorPosition() &&
56 le->selectionStart() == re->selectionStart() &&
57 le->selectionEnd() == re->selectionEnd();
58 } else if (l.type() == QAccessible::TextInserted) {
59 const QAccessibleTextInsertEvent *le = static_cast<const QAccessibleTextInsertEvent*>(&l);
60 const QAccessibleTextInsertEvent *re = static_cast<const QAccessibleTextInsertEvent*>(&r);
61 return le->cursorPosition() == re->cursorPosition() &&
62 le->changePosition() == re->changePosition() &&
63 le->textInserted() == re->textInserted();
64 } else if (l.type() == QAccessible::TextRemoved) {
65 const QAccessibleTextRemoveEvent *le = static_cast<const QAccessibleTextRemoveEvent*>(&l);
66 const QAccessibleTextRemoveEvent *re = static_cast<const QAccessibleTextRemoveEvent*>(&r);
67 return le->cursorPosition() == re->cursorPosition() &&
68 le->changePosition() == re->changePosition() &&
69 le->textRemoved() == re->textRemoved();
70 } else if (l.type() == QAccessible::TextUpdated) {
71 const QAccessibleTextUpdateEvent *le = static_cast<const QAccessibleTextUpdateEvent*>(&l);
72 const QAccessibleTextUpdateEvent *re = static_cast<const QAccessibleTextUpdateEvent*>(&r);
73 return le->cursorPosition() == re->cursorPosition() &&
74 le->changePosition() == re->changePosition() &&
75 le->textInserted() == re->textInserted() &&
76 le->textRemoved() == re->textRemoved();
77 } else if (l.type() == QAccessible::ValueChanged) {
78 const QAccessibleValueChangeEvent *le = static_cast<const QAccessibleValueChangeEvent*>(&l);
79 const QAccessibleValueChangeEvent *re = static_cast<const QAccessibleValueChangeEvent*>(&r);
80 return le->value() == re->value();
81 }
82 return true;
83}
84
85class QTestAccessibility
86{
87public:
88 static void initialize()
89 {
90 if (!instance()) {
91 instance() = new QTestAccessibility;
92 qAddPostRoutine(cleanup);
93 }
94 }
95
96 static void cleanup()
97 {
98 delete instance();
99 instance() = nullptr;
100 }
101 static void clearEvents() { eventList().clear(); }
102 static EventList events() { return eventList(); }
103 static bool verifyEvent(QAccessibleEvent *ev)
104 {
105 for (int i = 0; eventList().isEmpty() && i < 5; ++i)
106 QTest::qWait(50);
107 if (eventList().isEmpty()) {
108 qWarning("Timeout waiting for accessibility event.");
109 return false;
110 }
111 const bool res = *eventList().constFirst() == *ev;
112 if (!res)
113 qWarning("%s", qPrintable(msgAccessibilityEventListMismatch(eventList(), ev)));
114 delete eventList().takeFirst();
115 return res;
116 }
117 static bool containsEvent(QAccessibleEvent *event) {
118 for (const QAccessibleEvent *ev : std::as_const(eventList())) {
119 if (*ev == *event)
120 return true;
121 }
122 return false;
123 }
124
125private:
126 QTestAccessibility()
127 {
128 QAccessible::installUpdateHandler(updateHandler);
129 QAccessible::installRootObjectHandler(rootObjectHandler);
130 }
131
132 ~QTestAccessibility()
133 {
134 QAccessible::installUpdateHandler(nullptr);
135 QAccessible::installRootObjectHandler(nullptr);
136 }
137
138 static void rootObjectHandler(QObject *object)
139 {
140 // qDebug("rootObjectHandler called %p", object);
141 if (object) {
142 QGuiApplication* app = qobject_cast<QGuiApplication*>(object);
143 if ( !app )
144 qWarning("root Object is not a QGuiApplication!");
145 } else {
146 qWarning("root Object called with 0 pointer");
147 }
148 }
149
150 static void updateHandler(QAccessibleEvent *event)
151 {
152 auto ev = copyEvent(event);
153 if (auto obj = ev->object()) {
155 auto index= eventList().indexOf(ev);
156 if (index == -1)
157 return;
158 eventList().at(index)->m_object = nullptr;
159 });
160 }
161 eventList().append(ev);
162 }
163 static QAccessibleEvent *copyEvent(QAccessibleEvent *event)
164 {
165 QAccessibleEvent *ev;
166 if (event->type() == QAccessible::StateChanged) {
167 if (event->object())
168 ev = new QAccessibleStateChangeEvent(event->object(),
169 static_cast<QAccessibleStateChangeEvent*>(event)->changedStates());
170 else
171 ev = new QAccessibleStateChangeEvent(event->accessibleInterface(),
172 static_cast<QAccessibleStateChangeEvent*>(event)->changedStates());
173 } else if (event->type() == QAccessible::TextCaretMoved) {
174 if (event->object())
175 ev = new QAccessibleTextCursorEvent(event->object(), static_cast<QAccessibleTextCursorEvent*>(event)->cursorPosition());
176 else
177 ev = new QAccessibleTextCursorEvent(event->accessibleInterface(), static_cast<QAccessibleTextCursorEvent*>(event)->cursorPosition());
178 } else if (event->type() == QAccessible::TextSelectionChanged) {
179 const QAccessibleTextSelectionEvent *original = static_cast<QAccessibleTextSelectionEvent*>(event);
180 QAccessibleTextSelectionEvent *sel;
181 if (event->object())
182 sel = new QAccessibleTextSelectionEvent(event->object(), original->selectionStart(), original->selectionEnd());
183 else
184 sel = new QAccessibleTextSelectionEvent(event->accessibleInterface(), original->selectionStart(), original->selectionEnd());
185 sel->setCursorPosition(original->cursorPosition());
186 ev = sel;
187 } else if (event->type() == QAccessible::TextInserted) {
188 const QAccessibleTextInsertEvent *original = static_cast<QAccessibleTextInsertEvent*>(event);
189 QAccessibleTextInsertEvent *ins;
190 if (original->object())
191 ins = new QAccessibleTextInsertEvent(event->object(), original->changePosition(), original->textInserted());
192 else
193 ins = new QAccessibleTextInsertEvent(event->accessibleInterface(), original->changePosition(), original->textInserted());
194 ins->setCursorPosition(original->cursorPosition());
195 ev = ins;
196 } else if (event->type() == QAccessible::TextRemoved) {
197 const QAccessibleTextRemoveEvent *original = static_cast<QAccessibleTextRemoveEvent*>(event);
198 QAccessibleTextRemoveEvent *rem;
199 if (event->object())
200 rem = new QAccessibleTextRemoveEvent(event->object(), original->changePosition(), original->textRemoved());
201 else
202 rem = new QAccessibleTextRemoveEvent(event->accessibleInterface(), original->changePosition(), original->textRemoved());
203 rem->setCursorPosition(original->cursorPosition());
204 ev = rem;
205 } else if (event->type() == QAccessible::TextUpdated) {
206 const QAccessibleTextUpdateEvent *original = static_cast<QAccessibleTextUpdateEvent*>(event);
207 QAccessibleTextUpdateEvent *upd;
208 if (event->object())
209 upd = new QAccessibleTextUpdateEvent(event->object(), original->changePosition(), original->textRemoved(), original->textInserted());
210 else
211 upd = new QAccessibleTextUpdateEvent(event->accessibleInterface(), original->changePosition(), original->textRemoved(), original->textInserted());
212 upd->setCursorPosition(original->cursorPosition());
213 ev = upd;
214 } else if (event->type() == QAccessible::ValueChanged) {
215 if (event->object())
216 ev = new QAccessibleValueChangeEvent(event->object(), static_cast<QAccessibleValueChangeEvent*>(event)->value());
217 else
218 ev = new QAccessibleValueChangeEvent(event->accessibleInterface(), static_cast<QAccessibleValueChangeEvent*>(event)->value());
219 } else if (event->type() == QAccessible::TableModelChanged) {
220 QAccessibleTableModelChangeEvent *oldEvent = static_cast<QAccessibleTableModelChangeEvent*>(event);
221 QAccessibleTableModelChangeEvent *newEvent;
222 if (event->object())
223 newEvent = new QAccessibleTableModelChangeEvent(event->object(), oldEvent->modelChangeType());
224 else
225 newEvent = new QAccessibleTableModelChangeEvent(event->accessibleInterface(), oldEvent->modelChangeType());
226 newEvent->setFirstRow(oldEvent->firstRow());
227 newEvent->setFirstColumn(oldEvent->firstColumn());
228 newEvent->setLastRow(oldEvent->lastRow());
229 newEvent->setLastColumn(oldEvent->lastColumn());
230 ev = newEvent;
231 } else {
232 if (event->object())
233 ev = new QAccessibleEvent(event->object(), event->type());
234 else
235 ev = new QAccessibleEvent(event->accessibleInterface(), event->type());
236 }
237 ev->setChild(event->child());
238 return ev;
239 }
240
241 static EventList &eventList()
242 {
243 static EventList list;
244 return list;
245 }
246
247 static QTestAccessibility *&instance()
248 {
249 static QTestAccessibility *ta = nullptr;
250 return ta;
251 }
252
253private:
254 static QString msgAccessibilityEventListMismatch(const EventList &haystack,
255 const QAccessibleEvent *needle)
256 {
257 QString rc;
258 QDebug str = QDebug(&rc).nospace();
259 str << "Event " << *needle
260 << " not found at head of event list of size " << haystack.size() << " :";
261 for (const QAccessibleEvent *e : haystack)
262 str << ' ' << *e;
263 return rc;
264 }
265
266};
267
269
270#endif // QT_CONFIG(accessibility)
271#endif // QTESTACCESSIBLE_H
\inmodule QtCore
\macro qGuiApp
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
QString str
[2]
Combined button and popup list for selecting options.
Q_CORE_EXPORT void qWait(int ms)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void qAddPostRoutine(QtCleanUpFunction p)
static bool initialize()
Definition qctf.cpp:94
#define qWarning
Definition qlogging.h:166
GLuint index
[2]
GLboolean r
[2]
struct _cl_event * event
GLhandleARB obj
[2]
GLuint res
bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
Definition qrandom.cpp:1220
#define qPrintable(string)
Definition qstring.h:1531
QList< int > list
[14]
QApplication app(argc, argv)
[0]
QPointer< QLineEdit > le