Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-21 10:12:23

0001 // Copyright (C) 2016 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 
0004 #ifndef QTESTACCESSIBLE_H
0005 #define QTESTACCESSIBLE_H
0006 
0007 #if 0
0008 // inform syncqt
0009 #pragma qt_no_master_include
0010 #endif
0011 
0012 #include <QtCore/qglobal.h>
0013 
0014 #define QVERIFY_EVENT(event) \
0015     QVERIFY(QTestAccessibility::verifyEvent(event))
0016 
0017 #include <QtCore/qlist.h>
0018 #include <QtCore/qdebug.h>
0019 #include <QtGui/qaccessible.h>
0020 #include <QtGui/qguiapplication.h>
0021 #include <QtTest/qttestglobal.h>
0022 #include <QtTest/qtestsystem.h>
0023 
0024 #if QT_CONFIG(accessibility)
0025 
0026 QT_BEGIN_NAMESPACE
0027 
0028 
0029 class QObject;
0030 
0031 // Use pointers since we subclass QAccessibleEvent
0032 using EventList = QList<QAccessibleEvent*>;
0033 
0034 bool operator==(const QAccessibleEvent &l, const QAccessibleEvent &r)
0035 {
0036     if (l.type() != r.type()) {
0037 //        qDebug() << "QAccessibleEvent with wrong type: " << qAccessibleEventString(l.type()) << " and " << qAccessibleEventString(r.type());
0038         return false;
0039     }
0040     if (l.object() != r.object() ||
0041             l.child() != r.child()) {
0042 //        qDebug() << "QAccessibleEvent for wrong object: " << l.object() << " and " << r.object() << " child: " << l.child() << " and " << r.child();
0043         return false;
0044     }
0045 
0046     if (l.type() == QAccessible::StateChanged) {
0047         return static_cast<const QAccessibleStateChangeEvent*>(&l)->changedStates()
0048                 == static_cast<const QAccessibleStateChangeEvent*>(&r)->changedStates();
0049     } else if (l.type() == QAccessible::TextCaretMoved) {
0050         return static_cast<const QAccessibleTextCursorEvent*>(&l)->cursorPosition()
0051                 == static_cast<const QAccessibleTextCursorEvent*>(&r)->cursorPosition();
0052     } else if (l.type() == QAccessible::TextSelectionChanged) {
0053         const QAccessibleTextSelectionEvent *le = static_cast<const QAccessibleTextSelectionEvent*>(&l);
0054         const QAccessibleTextSelectionEvent *re = static_cast<const QAccessibleTextSelectionEvent*>(&r);
0055         return  le->cursorPosition() == re->cursorPosition() &&
0056                 le->selectionStart() == re->selectionStart() &&
0057                 le->selectionEnd() == re->selectionEnd();
0058     } else if (l.type() == QAccessible::TextInserted) {
0059         const QAccessibleTextInsertEvent *le = static_cast<const QAccessibleTextInsertEvent*>(&l);
0060         const QAccessibleTextInsertEvent *re = static_cast<const QAccessibleTextInsertEvent*>(&r);
0061         return  le->cursorPosition() == re->cursorPosition() &&
0062                 le->changePosition() == re->changePosition() &&
0063                 le->textInserted() == re->textInserted();
0064     } else if (l.type() == QAccessible::TextRemoved) {
0065         const QAccessibleTextRemoveEvent *le = static_cast<const QAccessibleTextRemoveEvent*>(&l);
0066         const QAccessibleTextRemoveEvent *re = static_cast<const QAccessibleTextRemoveEvent*>(&r);
0067         return  le->cursorPosition() == re->cursorPosition() &&
0068                 le->changePosition() == re->changePosition() &&
0069                 le->textRemoved() == re->textRemoved();
0070     } else if (l.type() == QAccessible::TextUpdated) {
0071         const QAccessibleTextUpdateEvent *le = static_cast<const QAccessibleTextUpdateEvent*>(&l);
0072         const QAccessibleTextUpdateEvent *re = static_cast<const QAccessibleTextUpdateEvent*>(&r);
0073         return  le->cursorPosition() == re->cursorPosition() &&
0074                 le->changePosition() == re->changePosition() &&
0075                 le->textInserted() == re->textInserted() &&
0076                 le->textRemoved() == re->textRemoved();
0077     } else if (l.type() == QAccessible::ValueChanged) {
0078         const QAccessibleValueChangeEvent *le = static_cast<const QAccessibleValueChangeEvent*>(&l);
0079         const QAccessibleValueChangeEvent *re = static_cast<const QAccessibleValueChangeEvent*>(&r);
0080         return le->value() == re->value();
0081     }
0082     return true;
0083 }
0084 
0085 class QTestAccessibility
0086 {
0087 public:
0088     static void initialize()
0089     {
0090         if (!instance()) {
0091             instance() = new QTestAccessibility;
0092             qAddPostRoutine(cleanup);
0093         }
0094     }
0095 
0096     static void cleanup()
0097     {
0098         delete instance();
0099         instance() = nullptr;
0100     }
0101     static void clearEvents() { eventList().clear(); }
0102     static EventList events() { return eventList(); }
0103     static bool verifyEvent(QAccessibleEvent *ev)
0104     {
0105         for (int i = 0; eventList().isEmpty() && i < 5; ++i)
0106             QTest::qWait(50);
0107         if (eventList().isEmpty()) {
0108             qWarning("Timeout waiting for accessibility event.");
0109             return false;
0110         }
0111         const bool res = *eventList().constFirst() == *ev;
0112         if (!res)
0113             qWarning("%s", qPrintable(msgAccessibilityEventListMismatch(eventList(), ev)));
0114         delete eventList().takeFirst();
0115         return res;
0116     }
0117     static bool containsEvent(QAccessibleEvent *event) {
0118         for (const QAccessibleEvent *ev : std::as_const(eventList())) {
0119             if (*ev == *event)
0120                 return true;
0121         }
0122         return false;
0123     }
0124 
0125 private:
0126     QTestAccessibility()
0127     {
0128         QAccessible::installUpdateHandler(updateHandler);
0129         QAccessible::installRootObjectHandler(rootObjectHandler);
0130     }
0131 
0132     ~QTestAccessibility()
0133     {
0134         QAccessible::installUpdateHandler(nullptr);
0135         QAccessible::installRootObjectHandler(nullptr);
0136     }
0137 
0138     static void rootObjectHandler(QObject *object)
0139     {
0140         //    qDebug("rootObjectHandler called %p", object);
0141         if (object) {
0142             QGuiApplication* app = qobject_cast<QGuiApplication*>(object);
0143             if ( !app )
0144                 qWarning("root Object is not a QGuiApplication!");
0145         } else {
0146             qWarning("root Object called with 0 pointer");
0147         }
0148     }
0149 
0150     static void updateHandler(QAccessibleEvent *event)
0151     {
0152         auto ev = copyEvent(event);
0153         if (auto obj = ev->object()) {
0154             QObject::connect(obj, &QObject::destroyed, obj, [&, ev](){
0155                 auto index= eventList().indexOf(ev);
0156                 if (index == -1)
0157                     return;
0158                 eventList().at(index)->m_object = nullptr;
0159             });
0160         }
0161         eventList().append(ev);
0162     }
0163     static QAccessibleEvent *copyEvent(QAccessibleEvent *event)
0164     {
0165         QAccessibleEvent *ev;
0166         if (event->type() == QAccessible::StateChanged) {
0167             if (event->object())
0168                 ev = new QAccessibleStateChangeEvent(event->object(),
0169                         static_cast<QAccessibleStateChangeEvent*>(event)->changedStates());
0170             else
0171                 ev = new QAccessibleStateChangeEvent(event->accessibleInterface(),
0172                         static_cast<QAccessibleStateChangeEvent*>(event)->changedStates());
0173         } else if (event->type() == QAccessible::TextCaretMoved) {
0174             if (event->object())
0175                 ev = new QAccessibleTextCursorEvent(event->object(), static_cast<QAccessibleTextCursorEvent*>(event)->cursorPosition());
0176             else
0177                 ev = new QAccessibleTextCursorEvent(event->accessibleInterface(), static_cast<QAccessibleTextCursorEvent*>(event)->cursorPosition());
0178         } else if (event->type() == QAccessible::TextSelectionChanged) {
0179             const QAccessibleTextSelectionEvent *original = static_cast<QAccessibleTextSelectionEvent*>(event);
0180             QAccessibleTextSelectionEvent *sel;
0181             if (event->object())
0182                 sel = new QAccessibleTextSelectionEvent(event->object(), original->selectionStart(), original->selectionEnd());
0183             else
0184                 sel = new QAccessibleTextSelectionEvent(event->accessibleInterface(), original->selectionStart(), original->selectionEnd());
0185             sel->setCursorPosition(original->cursorPosition());
0186             ev = sel;
0187         } else if (event->type() == QAccessible::TextInserted) {
0188             const QAccessibleTextInsertEvent *original = static_cast<QAccessibleTextInsertEvent*>(event);
0189             QAccessibleTextInsertEvent *ins;
0190             if (original->object())
0191                 ins = new QAccessibleTextInsertEvent(event->object(), original->changePosition(), original->textInserted());
0192             else
0193                 ins = new QAccessibleTextInsertEvent(event->accessibleInterface(), original->changePosition(), original->textInserted());
0194             ins->setCursorPosition(original->cursorPosition());
0195             ev = ins;
0196         } else if (event->type() == QAccessible::TextRemoved) {
0197             const QAccessibleTextRemoveEvent *original = static_cast<QAccessibleTextRemoveEvent*>(event);
0198             QAccessibleTextRemoveEvent *rem;
0199             if (event->object())
0200                 rem = new QAccessibleTextRemoveEvent(event->object(), original->changePosition(), original->textRemoved());
0201             else
0202                 rem = new QAccessibleTextRemoveEvent(event->accessibleInterface(), original->changePosition(), original->textRemoved());
0203             rem->setCursorPosition(original->cursorPosition());
0204             ev = rem;
0205         } else if (event->type() == QAccessible::TextUpdated) {
0206             const QAccessibleTextUpdateEvent *original = static_cast<QAccessibleTextUpdateEvent*>(event);
0207             QAccessibleTextUpdateEvent *upd;
0208             if (event->object())
0209                 upd = new QAccessibleTextUpdateEvent(event->object(), original->changePosition(), original->textRemoved(), original->textInserted());
0210             else
0211                 upd = new QAccessibleTextUpdateEvent(event->accessibleInterface(), original->changePosition(), original->textRemoved(), original->textInserted());
0212             upd->setCursorPosition(original->cursorPosition());
0213             ev = upd;
0214         } else if (event->type() == QAccessible::ValueChanged) {
0215             if (event->object())
0216                 ev = new QAccessibleValueChangeEvent(event->object(), static_cast<QAccessibleValueChangeEvent*>(event)->value());
0217             else
0218                 ev = new QAccessibleValueChangeEvent(event->accessibleInterface(), static_cast<QAccessibleValueChangeEvent*>(event)->value());
0219         } else if (event->type() == QAccessible::TableModelChanged) {
0220             QAccessibleTableModelChangeEvent *oldEvent = static_cast<QAccessibleTableModelChangeEvent*>(event);
0221             QAccessibleTableModelChangeEvent *newEvent;
0222             if (event->object())
0223                 newEvent = new QAccessibleTableModelChangeEvent(event->object(), oldEvent->modelChangeType());
0224             else
0225                 newEvent = new QAccessibleTableModelChangeEvent(event->accessibleInterface(), oldEvent->modelChangeType());
0226             newEvent->setFirstRow(oldEvent->firstRow());
0227             newEvent->setFirstColumn(oldEvent->firstColumn());
0228             newEvent->setLastRow(oldEvent->lastRow());
0229             newEvent->setLastColumn(oldEvent->lastColumn());
0230             ev = newEvent;
0231         } else {
0232             if (event->object())
0233                 ev = new QAccessibleEvent(event->object(), event->type());
0234             else
0235                 ev = new QAccessibleEvent(event->accessibleInterface(), event->type());
0236         }
0237         ev->setChild(event->child());
0238         return ev;
0239     }
0240 
0241     static EventList &eventList()
0242     {
0243         static EventList list;
0244         return list;
0245     }
0246 
0247     static QTestAccessibility *&instance()
0248     {
0249         static QTestAccessibility *ta = nullptr;
0250         return ta;
0251     }
0252 
0253 private:
0254     static QString msgAccessibilityEventListMismatch(const EventList &haystack,
0255                                                      const QAccessibleEvent *needle)
0256     {
0257         QString rc;
0258         QDebug str = QDebug(&rc).nospace();
0259         str << "Event " << *needle
0260             <<  " not found at head of event list of size " << haystack.size() << " :";
0261         for (const QAccessibleEvent *e : haystack)
0262             str << ' ' << *e;
0263         return rc;
0264     }
0265 
0266 };
0267 
0268 QT_END_NAMESPACE
0269 
0270 #endif // QT_CONFIG(accessibility)
0271 #endif // QTESTACCESSIBLE_H