*/
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<QPair<QAccessibleInterface*, QAccessible::Relation> > QAccessibleInterface::relations() const
+QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >
+QAccessibleInterface::relations(QAccessible::Relation /*match = QAccessible::AllRelations*/) const
{
return QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >();
}
};
enum RelationFlag {
- Unrelated = 0x00000000,
Label = 0x00020000,
Labelled = 0x00040000,
Controller = 0x00080000,
Controlled = 0x00100000,
- LogicalMask = 0x00ff0000
+ AllRelations = 0xffffffff
};
Q_DECLARE_FLAGS(Relation, RelationFlag)
// relations
virtual QAccessible::Relation relationTo(const QAccessibleInterface *other) const;
- virtual QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > relations() const;
+ virtual QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > relations(QAccessible::Relation match = QAccessible::AllRelations) const;
virtual QAccessibleInterface *focusChild() const;
virtual QAccessibleInterface *childAt(int x, int y) const = 0;
#include <qlineedit.h>
#include <qstyle.h>
#include <qstyleoption.h>
+#include <QtCore/qvarlengtharray.h>
#ifdef Q_OS_MAC
#include <qfocusframe.h>
return qt_accStripAmp(str);
}
-QAccessible::Relation QAccessibleDisplay::relationTo(const QAccessibleInterface *other) const
+/*! \reimp */
+QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >
+QAccessibleDisplay::relations(QAccessible::Relation match /*= QAccessible::AllRelations*/) const
{
- QAccessible::Relation relation = QAccessibleWidget::relationTo(other);
+ QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > rels = QAccessibleWidget::relations(match);
+ if (match & QAccessible::Labelled) {
+ QVarLengthArray<QObject *, 4> relatedObjects;
- QObject *o = other->object();
- QLabel *label = qobject_cast<QLabel*>(object());
- if (label) {
#ifndef QT_NO_SHORTCUT
- if (o == label->buddy())
- relation |= QAccessible::Label;
+ if (QLabel *label = qobject_cast<QLabel*>(object())) {
+ relatedObjects.append(label->buddy());
#endif
#ifndef QT_NO_GROUPBOX
- } else {
- QGroupBox *groupbox = qobject_cast<QGroupBox*>(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<QLabel*>(object());
- if (label) {
-#ifndef QT_NO_SHORTCUT
- if (entry == 1)
- targetObject = label->buddy();
-#endif
-#ifndef QT_NO_GROUPBOX
- } else {
- QGroupBox *groupbox = qobject_cast<QGroupBox*>(object());
- if (groupbox && !groupbox->title().isEmpty())
- *target = child(entry - 1);
+ } else if (QGroupBox *groupbox = qobject_cast<QGroupBox*>(object())) {
+ if (!groupbox->title().isEmpty()) {
+ const QList<QWidget*> 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)
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<QPair<QAccessibleInterface*, QAccessible::Relation> >relations(QAccessible::Relation match = QAccessible::AllRelations) const;
void *interface_cast(QAccessible::InterfaceType t);
// QAccessibleImageInterface
return *pszKeyboardShortcut ? S_OK : S_FALSE;
}
+static QAccessibleInterface *relatedInterface(QAccessibleInterface *iface, QAccessible::RelationFlag flag)
+{
+ typedef QPair<QAccessibleInterface *, QAccessible::Relation> RelationPair;
+ QVector<RelationPair> 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)
{
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);
return false;
}
-
/*! \reimp */
-QAccessible::Relation QAccessibleWidget::relationTo(const QAccessibleInterface *other) const
+QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >
+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<QPair<QAccessibleInterface*, QAccessible::Relation> > 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<QWidget*> kids = childWidgets(parent);
+ for (int i = 0; i < kids.count(); ++i) {
+ if (QLabel *labelSibling = qobject_cast<QLabel*>(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<QGroupBox*>(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<QAccessibleWidget*>(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 */
}
/*! \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
{
QWidgetList cl = childWidgets(widget());
QWindow *window() const;
int childCount() const;
int indexOfChild(const QAccessibleInterface *child) const;
- QAccessible::Relation relationTo(const QAccessibleInterface *other) const;
+ QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > 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;
}
};
+static QAccessibleInterface *relatedInterface(QAccessibleInterface *iface, QAccessible::RelationFlag flag)
+{
+ typedef QPair<QAccessibleInterface *, QAccessible::Relation> RelationPair;
+ QVector<RelationPair> 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;
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();