From ff2886db6a3308c1f4ee0879af497a5d43c33133 Mon Sep 17 00:00:00 2001 From: Jan-Arve Saether Date: Thu, 9 Feb 2012 11:20:34 +0100 Subject: Move all usages of Relation enum values to QAccessible::relations() Next step is to remove navigate(), but that has to be done in qtdeclarative first. Change-Id: I01ea1386c092446be04cc19d0f70adf53f094adc Reviewed-by: Frederik Gladhorn --- src/gui/accessible/qaccessible.cpp | 6 +- src/gui/accessible/qaccessible.h | 5 +- src/plugins/accessible/widgets/simplewidgets.cpp | 61 +++---- src/plugins/accessible/widgets/simplewidgets.h | 3 +- .../platforms/windows/qwindowsaccessibility.cpp | 23 +++ src/widgets/accessible/qaccessiblewidget.cpp | 177 ++++++++------------- src/widgets/accessible/qaccessiblewidget.h | 3 +- .../other/qaccessibility/tst_qaccessibility.cpp | 35 ++++ 8 files changed, 152 insertions(+), 161 deletions(-) diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp index dd0468d9f9..6664e5d312 100644 --- a/src/gui/accessible/qaccessible.cpp +++ b/src/gui/accessible/qaccessible.cpp @@ -894,17 +894,19 @@ QAccessibleInterface *QAccessibleEvent::accessibleInterface() const */ QAccessible::Relation QAccessibleInterface::relationTo(const QAccessibleInterface *) const { - return QAccessible::Unrelated; + return QAccessible::Relation(); } /*! Returns the meaningful relations to other widgets. Usually this will not return parent/child relations, unless they are handled in a specific way such as in tree views. It will typically return the labelled-by and label relations. + It should never return itself. \sa relationTo(), navigate() */ -QVector > QAccessibleInterface::relations() const +QVector > +QAccessibleInterface::relations(QAccessible::Relation /*match = QAccessible::AllRelations*/) const { return QVector >(); } diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h index 214ec20f9c..9fc13a827b 100644 --- a/src/gui/accessible/qaccessible.h +++ b/src/gui/accessible/qaccessible.h @@ -306,12 +306,11 @@ public: }; enum RelationFlag { - Unrelated = 0x00000000, Label = 0x00020000, Labelled = 0x00040000, Controller = 0x00080000, Controlled = 0x00100000, - LogicalMask = 0x00ff0000 + AllRelations = 0xffffffff }; Q_DECLARE_FLAGS(Relation, RelationFlag) @@ -380,7 +379,7 @@ public: // relations virtual QAccessible::Relation relationTo(const QAccessibleInterface *other) const; - virtual QVector > relations() const; + virtual QVector > relations(QAccessible::Relation match = QAccessible::AllRelations) const; virtual QAccessibleInterface *focusChild() const; virtual QAccessibleInterface *childAt(int x, int y) const = 0; diff --git a/src/plugins/accessible/widgets/simplewidgets.cpp b/src/plugins/accessible/widgets/simplewidgets.cpp index 652150f392..0fdd4490f7 100644 --- a/src/plugins/accessible/widgets/simplewidgets.cpp +++ b/src/plugins/accessible/widgets/simplewidgets.cpp @@ -54,6 +54,7 @@ #include #include #include +#include #ifdef Q_OS_MAC #include @@ -427,52 +428,36 @@ QString QAccessibleDisplay::text(QAccessible::Text t) const return qt_accStripAmp(str); } -QAccessible::Relation QAccessibleDisplay::relationTo(const QAccessibleInterface *other) const +/*! \reimp */ +QVector > +QAccessibleDisplay::relations(QAccessible::Relation match /*= QAccessible::AllRelations*/) const { - QAccessible::Relation relation = QAccessibleWidget::relationTo(other); + QVector > rels = QAccessibleWidget::relations(match); + if (match & QAccessible::Labelled) { + QVarLengthArray relatedObjects; - QObject *o = other->object(); - QLabel *label = qobject_cast(object()); - if (label) { #ifndef QT_NO_SHORTCUT - if (o == label->buddy()) - relation |= QAccessible::Label; + if (QLabel *label = qobject_cast(object())) { + relatedObjects.append(label->buddy()); #endif #ifndef QT_NO_GROUPBOX - } else { - QGroupBox *groupbox = qobject_cast(object()); - if (groupbox && !groupbox->title().isEmpty()) - if (groupbox->children().contains(o)) - relation |= QAccessible::Label; -#endif - } - return relation; -} - -int QAccessibleDisplay::navigate(QAccessible::RelationFlag rel, int entry, QAccessibleInterface **target) const -{ - *target = 0; - if (rel == QAccessible::Labelled) { - QObject *targetObject = 0; - QLabel *label = qobject_cast(object()); - if (label) { -#ifndef QT_NO_SHORTCUT - if (entry == 1) - targetObject = label->buddy(); -#endif -#ifndef QT_NO_GROUPBOX - } else { - QGroupBox *groupbox = qobject_cast(object()); - if (groupbox && !groupbox->title().isEmpty()) - *target = child(entry - 1); + } else if (QGroupBox *groupbox = qobject_cast(object())) { + if (!groupbox->title().isEmpty()) { + const QList kids = childWidgets(widget()); + for (int i = 0; i < kids.count(); ++i) { + relatedObjects.append(kids.at(i)); + } + } #endif } - if (targetObject) - *target = QAccessible::queryAccessibleInterface(targetObject); - if (*target) - return 0; + for (int i = 0; i < relatedObjects.count(); ++i) { + const QAccessible::Relation rel = QAccessible::Labelled; + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(relatedObjects.at(i)); + if (iface) + rels.append(qMakePair(iface, rel)); + } } - return QAccessibleWidget::navigate(rel, entry, target); + return rels; } void *QAccessibleDisplay::interface_cast(QAccessible::InterfaceType t) diff --git a/src/plugins/accessible/widgets/simplewidgets.h b/src/plugins/accessible/widgets/simplewidgets.h index bbdececadf..c228775421 100644 --- a/src/plugins/accessible/widgets/simplewidgets.h +++ b/src/plugins/accessible/widgets/simplewidgets.h @@ -104,8 +104,7 @@ public: QString text(QAccessible::Text t) const; QAccessible::Role role() const; - QAccessible::Relation relationTo(const QAccessibleInterface *other) const; - int navigate(QAccessible::RelationFlag, int entry, QAccessibleInterface **target) const; + QVector >relations(QAccessible::Relation match = QAccessible::AllRelations) const; void *interface_cast(QAccessible::InterfaceType t); // QAccessibleImageInterface diff --git a/src/plugins/platforms/windows/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/qwindowsaccessibility.cpp index 2c49d8614d..e36e255947 100644 --- a/src/plugins/platforms/windows/qwindowsaccessibility.cpp +++ b/src/plugins/platforms/windows/qwindowsaccessibility.cpp @@ -988,6 +988,17 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accKeyboardShortcut(VARIANT va return *pszKeyboardShortcut ? S_OK : S_FALSE; } +static QAccessibleInterface *relatedInterface(QAccessibleInterface *iface, QAccessible::RelationFlag flag) +{ + typedef QPair RelationPair; + QVector rels = iface->relations(flag); + + for (int i = 1; i < rels.count(); ++i) + delete rels.at(i).first; + + return rels.value(0).first; +} + // moz: [important] HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accName(VARIANT varID, BSTR* pszName) { @@ -1001,8 +1012,20 @@ HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accName(VARIANT varID, BSTR* p if (!child) return E_FAIL; name = child->text(QAccessible::Name); + if (name.isEmpty()) { + if (QAccessibleInterface *labelInterface = relatedInterface(child.data(), QAccessible::Label)) { + name = labelInterface->text(QAccessible::Name); + delete labelInterface; + } + } } else { name = accessible->text(QAccessible::Name); + if (name.isEmpty()) { + if (QAccessibleInterface *labelInterface = relatedInterface(accessible, QAccessible::Label)) { + name = labelInterface->text(QAccessible::Name); + delete labelInterface; + } + } } if (name.size()) { *pszName = QStringToBSTR(name); diff --git a/src/widgets/accessible/qaccessiblewidget.cpp b/src/widgets/accessible/qaccessiblewidget.cpp index 56ba990382..feac42780d 100644 --- a/src/widgets/accessible/qaccessiblewidget.cpp +++ b/src/widgets/accessible/qaccessiblewidget.cpp @@ -327,37 +327,76 @@ static inline bool isAncestor(const QObject *obj, const QObject *child) return false; } - /*! \reimp */ -QAccessible::Relation QAccessibleWidget::relationTo(const QAccessibleInterface *other) const +QVector > +QAccessibleWidget::relations(QAccessible::Relation match /*= QAccessible::AllRelations*/) const { - QAccessible::Relation relation = QAccessible::Unrelated; - if (d->asking == this) // recursive call - return relation; - - QObject *o = other ? other->object() : 0; - if (!o) - return relation; + QVector > rels; + if (match & QAccessible::Label) { + const QAccessible::Relation rel = QAccessible::Label; + if (QWidget *parent = widget()->parentWidget()) { +#ifndef QT_NO_SHORTCUT + // first check for all siblings that are labels to us + // ideally we would go through all objects and check, but that + // will be too expensive + const QList kids = childWidgets(parent); + for (int i = 0; i < kids.count(); ++i) { + if (QLabel *labelSibling = qobject_cast(kids.at(i))) { + if (labelSibling->buddy() == widget()) { + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(labelSibling); + rels.append(qMakePair(iface, rel)); + } + } + } +#endif +#ifndef QT_NO_GROUPBOX + QGroupBox *groupbox = qobject_cast(parent); + if (groupbox && !groupbox->title().isEmpty()) { + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(groupbox); + rels.append(qMakePair(iface, rel)); + } +#endif + } + } - QACConnectionObject *connectionObject = (QACConnectionObject*)object(); - for (int sig = 0; sig < d->primarySignals.count(); ++sig) { - if (connectionObject->isSender(o, d->primarySignals.at(sig).toAscii())) { - relation |= QAccessible::Controller; - break; + if (match & QAccessible::Controller) { + const QAccessible::Relation rel = QAccessible::Controller; + QACConnectionObject *connectionObject = (QACConnectionObject*)object(); + const QObjectList senderList = connectionObject->senderList(); + for (int s = 0; s < senderList.count(); ++s) { + QObject *sender = senderList.at(s); + if (sender->isWidgetType() && sender != object()) { + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(sender); + QACConnectionObject *connectionSender = (QACConnectionObject*)sender; + QStringList senderPrimarySignals = static_cast(iface)->d->primarySignals; + for (int sig = 0; sig < senderPrimarySignals.count(); ++sig) { + const QByteArray strSignal = senderPrimarySignals.at(sig).toAscii(); + if (connectionSender->isSender(object(), strSignal.constData())) + rels.append(qMakePair(iface, rel)); + } + } } } - // test for passive relationships. - // d->asking protects from endless recursion. - d->asking = this; - int inverse = other->relationTo(this); - d->asking = 0; - if (inverse & QAccessible::Controller) - relation |= QAccessible::Controlled; - if (inverse & QAccessible::Label) - relation |= QAccessible::Labelled; + if (match & QAccessible::Controlled) { + QObjectList allReceivers; + QACConnectionObject *connectionObject = (QACConnectionObject*)object(); + for (int sig = 0; sig < d->primarySignals.count(); ++sig) { + const QObjectList receivers = connectionObject->receiverList(d->primarySignals.at(sig).toAscii()); + allReceivers += receivers; + } + + allReceivers.removeAll(object()); //### The object might connect to itself internally - return relation; + for (int i = 0; i < allReceivers.count(); ++i) { + const QAccessible::Relation rel = QAccessible::Controlled; + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(allReceivers.at(i)); + if (iface) + rels.append(qMakePair(iface, rel)); + } + } + + return rels; } /*! \reimp */ @@ -393,96 +432,6 @@ QAccessibleInterface *QAccessibleWidget::focusChild() const return 0; } -/*! \reimp */ -int QAccessibleWidget::navigate(QAccessible::RelationFlag relation, int entry, - QAccessibleInterface **target) const -{ - if (!target) - return -1; - - *target = 0; - QObject *targetObject = 0; - - switch (relation) { - // Logical - case QAccessible::Label: - if (entry > 0) { - QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject()); - if (!pIface) - return -1; - - // first check for all siblings that are labels to us - // ideally we would go through all objects and check, but that - // will be too expensive - int sibCount = pIface->childCount(); - QAccessibleInterface *candidate = 0; - for (int i = 0; i < sibCount && entry; ++i) { - candidate = pIface->child(i); - Q_ASSERT(candidate); - if (candidate->relationTo(this) & QAccessible::Label) - --entry; - if (!entry) - break; - - delete candidate; - candidate = 0; - } - if (!candidate) { - if (pIface->relationTo(this) & QAccessible::Label) - --entry; - if (!entry) - candidate = pIface; - } - if (pIface != candidate) - delete pIface; - - *target = candidate; - if (*target) - return 0; - } - break; - case QAccessible::Labelled: // only implemented in subclasses - break; - case QAccessible::Controller: - if (entry > 0) { - // check all senders we are connected to, - // and figure out which one are controllers to us - QACConnectionObject *connectionObject = (QACConnectionObject*)object(); - QObjectList allSenders = connectionObject->senderList(); - QObjectList senders; - for (int s = 0; s < allSenders.size(); ++s) { - QObject *sender = allSenders.at(s); - QAccessibleInterface *candidate = QAccessible::queryAccessibleInterface(sender); - if (!candidate) - continue; - if (candidate->relationTo(this) & QAccessible::Controller) - senders << sender; - delete candidate; - } - if (entry <= senders.size()) - targetObject = senders.at(entry-1); - } - break; - case QAccessible::Controlled: - if (entry > 0) { - QObjectList allReceivers; - QACConnectionObject *connectionObject = (QACConnectionObject*)object(); - for (int sig = 0; sig < d->primarySignals.count(); ++sig) { - QObjectList receivers = connectionObject->receiverList(d->primarySignals.at(sig).toAscii()); - allReceivers += receivers; - } - if (entry <= allReceivers.size()) - targetObject = allReceivers.at(entry-1); - } - break; - default: - break; - } - - *target = QAccessible::queryAccessibleInterface(targetObject); - return *target ? 0 : -1; -} - /*! \reimp */ int QAccessibleWidget::childCount() const { diff --git a/src/widgets/accessible/qaccessiblewidget.h b/src/widgets/accessible/qaccessiblewidget.h index d34d852e27..4b480ca0ee 100644 --- a/src/widgets/accessible/qaccessiblewidget.h +++ b/src/widgets/accessible/qaccessiblewidget.h @@ -61,14 +61,13 @@ public: QWindow *window() const; int childCount() const; int indexOfChild(const QAccessibleInterface *child) const; - QAccessible::Relation relationTo(const QAccessibleInterface *other) const; + QVector > relations(QAccessible::Relation match = QAccessible::AllRelations) const; QAccessibleInterface *focusChild() const; QRect rect() const; QAccessibleInterface *parent() const; QAccessibleInterface *child(int index) const; - int navigate(QAccessible::RelationFlag rel, int entry, QAccessibleInterface **target) const; QString text(QAccessible::Text t) const; QAccessible::Role role() const; diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp index 63770f14cb..b2a4b1cca2 100644 --- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp @@ -846,6 +846,17 @@ public Q_SLOTS: } }; +static QAccessibleInterface *relatedInterface(QAccessibleInterface *iface, QAccessible::RelationFlag flag) +{ + typedef QPair RelationPair; + QVector rels = iface->relations(flag); + + for (int i = 1; i < rels.count(); ++i) + delete rels.at(i).first; + + return rels.value(0).first; +} + void tst_QAccessibility::buttonTest() { QWidget window; @@ -879,6 +890,30 @@ void tst_QAccessibility::buttonTest() toggletool.setText("Toggle"); toggletool.setMinimumSize(20,20); + // test Controller/Controlled relations + { + QCheckBox toggler("Toggle me!", &window); + bool ok = connect(&pushButton, SIGNAL(clicked()), &toggler, SLOT(toggle())); + QCOMPARE(ok, true); + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&toggler); + QVERIFY(iface); + QCOMPARE(iface->role(), QAccessible::CheckBox); + QAccessibleInterface *buttonIFace = relatedInterface(iface, QAccessible::Controller); + QVERIFY(buttonIFace); + QCOMPARE(buttonIFace->role(), QAccessible::Button); + QCOMPARE(buttonIFace->object(), &pushButton); + delete buttonIFace; + delete iface; + + buttonIFace = QAccessible::queryAccessibleInterface(&pushButton); + QVERIFY(buttonIFace); + QCOMPARE(buttonIFace->role(), QAccessible::Button); + iface = relatedInterface(buttonIFace, QAccessible::Controlled); + QVERIFY(iface); + QCOMPARE(iface->object(), &toggler); + + } + // test push button QAccessibleInterface* interface = QAccessible::queryAccessibleInterface(&pushButton); QAccessibleActionInterface* actionInterface = interface->actionInterface(); -- cgit v1.2.3