src/gui/accessible/qaccessiblewidget.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/accessible/qaccessiblewidget.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1031 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaccessiblewidget.h"
+
+#ifndef QT_NO_ACCESSIBILITY
+
+#include "qaction.h"
+#include "qapplication.h"
+#include "qgroupbox.h"
+#include "qlabel.h"
+#include "qtooltip.h"
+#include "qwhatsthis.h"
+#include "qwidget.h"
+#include "qdebug.h"
+#include <qmath.h>
+#include <QRubberBand>
+#include <QtGui/QFocusFrame>
+#include <QtGui/QMenu>
+
+QT_BEGIN_NAMESPACE
+
+static QList<QWidget*> childWidgets(const QWidget *widget)
+{
+    QList<QObject*> list = widget->children();
+    QList<QWidget*> widgets;
+    for (int i = 0; i < list.size(); ++i) {
+        QWidget *w = qobject_cast<QWidget *>(list.at(i));
+        if (w && !w->isWindow() 
+            && !qobject_cast<QFocusFrame*>(w)
+#if !defined(QT_NO_MENU)
+            && !qobject_cast<QMenu*>(w)
+#endif
+            && w->objectName() != QLatin1String("qt_rubberband"))
+            widgets.append(w);
+    }
+    return widgets;
+}
+
+static QString buddyString(const QWidget *widget)
+{
+    if (!widget)
+        return QString();
+    QWidget *parent = widget->parentWidget();
+    if (!parent)
+        return QString();
+#ifndef QT_NO_SHORTCUT
+    QObjectList ol = parent->children();
+    for (int i = 0; i < ol.size(); ++i) {
+        QLabel *label = qobject_cast<QLabel*>(ol.at(i));
+        if (label && label->buddy() == widget)
+            return label->text();
+    }
+#endif
+
+#ifndef QT_NO_GROUPBOX
+    QGroupBox *groupbox = qobject_cast<QGroupBox*>(parent);
+    if (groupbox)
+        return groupbox->title();
+#endif
+
+    return QString();
+}
+
+QString Q_GUI_EXPORT qt_accStripAmp(const QString &text)
+{
+    return QString(text).remove(QLatin1Char('&'));
+}
+
+QString Q_GUI_EXPORT qt_accHotKey(const QString &text)
+{
+#ifndef QT_NO_SHORTCUT
+    if (text.isEmpty())
+        return text;
+
+    int fa = 0;
+    QChar ac;
+    while ((fa = text.indexOf(QLatin1Char('&'), fa)) != -1) {
+        ++fa;
+        if (fa < text.length()) {
+            // ignore "&&"
+            if (text.at(fa) == QLatin1Char('&')) {
+                ++fa;
+                continue;
+            } else {
+                ac = text.at(fa);
+                break;
+            }
+        }
+    }
+    if (ac.isNull())
+        return QString();
+    return (QString)QKeySequence(Qt::ALT) + ac.toUpper();
+#else
+    Q_UNUSED(text);
+    return QString();
+#endif
+}
+
+class QAccessibleWidgetPrivate : public QAccessible
+{
+public:
+    QAccessibleWidgetPrivate()
+        :role(Client)
+    {}
+
+    Role role;
+    QString name;
+    QString description;
+    QString value;
+    QString help;
+    QString accelerator;
+    QStringList primarySignals;
+    const QAccessibleInterface *asking;
+};
+
+/*!
+    \class QAccessibleWidget
+    \brief The QAccessibleWidget class implements the QAccessibleInterface for QWidgets.
+
+    \ingroup accessibility
+
+    This class is convenient to use as a base class for custom
+    implementations of QAccessibleInterfaces that provide information
+    about widget objects.
+
+    The class provides functions to retrieve the parentObject() (the
+    widget's parent widget), and the associated widget(). Controlling
+    signals can be added with addControllingSignal(), and setters are
+    provided for various aspects of the interface implementation, for
+    example setValue(), setDescription(), setAccelerator(), and
+    setHelp().
+
+    \sa QAccessible, QAccessibleObject
+*/
+
+/*!
+    Creates a QAccessibleWidget object for widget \a w.
+    \a role and \a name are optional parameters that set the object's
+    role and name properties.
+*/
+QAccessibleWidget::QAccessibleWidget(QWidget *w, Role role, const QString &name)
+: QAccessibleObject(w)
+{
+    Q_ASSERT(widget());
+    d = new QAccessibleWidgetPrivate();
+    d->role = role;
+    d->name = name;
+    d->asking = 0;
+}
+
+/*!
+    Destroys this object.
+*/
+QAccessibleWidget::~QAccessibleWidget()
+{
+    delete d;
+}
+
+/*!
+    Returns the associated widget.
+*/
+QWidget *QAccessibleWidget::widget() const
+{
+    return qobject_cast<QWidget*>(object());
+}
+
+/*!
+    Returns the associated widget's parent object, which is either the
+    parent widget, or qApp for top-level widgets.
+*/
+QObject *QAccessibleWidget::parentObject() const
+{
+    QObject *parent = object()->parent();
+    if (!parent)
+        parent = qApp;
+    return parent;
+}
+
+/*! \reimp */
+int QAccessibleWidget::childAt(int x, int y) const
+{
+    QWidget *w = widget();
+    if (!w->isVisible())
+        return -1;
+    QPoint gp = w->mapToGlobal(QPoint(0, 0));
+    if (!QRect(gp.x(), gp.y(), w->width(), w->height()).contains(x, y))
+        return -1;
+
+    QWidgetList list = childWidgets(w);
+    int ccount = childCount();
+
+    // a complex child
+    if (list.size() < ccount) {
+        for (int i = 1; i <= ccount; ++i) {
+            if (rect(i).contains(x, y))
+                return i;
+        }
+        return 0;
+    }
+
+    QPoint rp = w->mapFromGlobal(QPoint(x, y));
+    for (int i = 0; i<list.size(); ++i) {
+        QWidget *child = list.at(i);
+        if (!child->isWindow() && !child->isHidden() && child->geometry().contains(rp)) {
+            return i + 1;
+        }
+    }
+    return 0;
+}
+
+/*! \reimp */
+QRect QAccessibleWidget::rect(int child) const
+{
+    if (child) {
+        qWarning("QAccessibleWidget::rect: This implementation does not support subelements! "
+                 "(ID %d unknown for %s)", child, widget()->metaObject()->className());
+    }
+
+    QWidget *w = widget();
+    if (!w->isVisible())
+        return QRect();
+    QPoint wpos = w->mapToGlobal(QPoint(0, 0));
+
+    return QRect(wpos.x(), wpos.y(), w->width(), w->height());
+}
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <private/qobject_p.h>
+QT_END_INCLUDE_NAMESPACE
+
+class QACConnectionObject : public QObject
+{
+    Q_DECLARE_PRIVATE(QObject)
+public:
+    inline bool isSender(const QObject *receiver, const char *signal) const
+    { return d_func()->isSender(receiver, signal); }
+    inline QObjectList receiverList(const char *signal) const
+    { return d_func()->receiverList(signal); }
+    inline QObjectList senderList() const
+    { return d_func()->senderList(); }
+};
+
+/*!
+    Registers \a signal as a controlling signal.
+
+    An object is a Controller to any other object connected to a
+    controlling signal.
+*/
+void QAccessibleWidget::addControllingSignal(const QString &signal)
+{
+    QByteArray s = QMetaObject::normalizedSignature(signal.toAscii());
+    if (object()->metaObject()->indexOfSignal(s) < 0)
+        qWarning("Signal %s unknown in %s", s.constData(), object()->metaObject()->className());
+    d->primarySignals << QLatin1String(s);
+}
+
+/*!
+    Sets the value of this interface implementation to \a value.
+
+    The default implementation of text() returns the set value for
+    the Value text.
+
+    Note that the object wrapped by this interface is not modified.
+*/
+void QAccessibleWidget::setValue(const QString &value)
+{
+    d->value = value;
+}
+
+/*!
+    Sets the description of this interface implementation to \a desc.
+
+    The default implementation of text() returns the set value for
+    the Description text.
+
+    Note that the object wrapped by this interface is not modified.
+*/
+void QAccessibleWidget::setDescription(const QString &desc)
+{
+    d->description = desc;
+}
+
+/*!
+    Sets the help of this interface implementation to \a help.
+
+    The default implementation of text() returns the set value for
+    the Help text.
+
+    Note that the object wrapped by this interface is not modified.
+*/
+void QAccessibleWidget::setHelp(const QString &help)
+{
+    d->help = help;
+}
+
+/*!
+    Sets the accelerator of this interface implementation to \a accel.
+
+    The default implementation of text() returns the set value for
+    the Accelerator text.
+
+    Note that the object wrapped by this interface is not modified.
+*/
+void QAccessibleWidget::setAccelerator(const QString &accel)
+{
+    d->accelerator = accel;
+}
+
+static inline bool isAncestor(const QObject *obj, const QObject *child)
+{
+    while (child) {
+        if (child == obj)
+            return true;
+        child = child->parent();
+    }
+    return false;
+}
+
+
+/*! \reimp */
+QAccessible::Relation QAccessibleWidget::relationTo(int child,
+            const QAccessibleInterface *other, int otherChild) const
+{
+    Relation relation = Unrelated;
+    if (d->asking == this) // recursive call
+        return relation;
+
+    QObject *o = other ? other->object() : 0;
+    if (!o)
+        return relation;
+
+    QWidget *focus = widget()->focusWidget();
+    if (object() == focus && isAncestor(o, focus))
+        relation |= FocusChild;
+
+    QACConnectionObject *connectionObject = (QACConnectionObject*)object();
+    for (int sig = 0; sig < d->primarySignals.count(); ++sig) {
+        if (connectionObject->isSender(o, d->primarySignals.at(sig).toAscii())) {
+            relation |= Controller;
+            break;
+        }
+    }
+    // test for passive relationships.
+    // d->asking protects from endless recursion.
+    d->asking = this;
+    int inverse = other->relationTo(otherChild, this, child);
+    d->asking = 0;
+
+    if (inverse & Controller)
+        relation |= Controlled;
+    if (inverse & Label)
+        relation |= Labelled;
+
+    if(o == object()) {
+        if (child && !otherChild)
+            return relation | Child;
+        if (!child && otherChild)
+            return relation | Ancestor;
+        if (!child && !otherChild)
+            return relation | Self;
+    }
+
+    QObject *parent = object()->parent();
+    if (o == parent)
+        return relation | Child;
+
+    if (o->parent() == parent) {
+        relation |= Sibling;
+        QAccessibleInterface *sibIface = QAccessible::queryAccessibleInterface(o);
+        Q_ASSERT(sibIface);
+        QRect wg = rect(0);
+        QRect sg = sibIface->rect(0);
+        if (wg.intersects(sg)) {
+            QAccessibleInterface *pIface = 0;
+            sibIface->navigate(Ancestor, 1, &pIface);
+            if (pIface && !((sibIface->state(0) | state(0)) & Invisible)) {
+                int wi = pIface->indexOfChild(this);
+                int si = pIface->indexOfChild(sibIface);
+
+                if (wi > si)
+                    relation |= QAccessible::Covers;
+                else
+                    relation |= QAccessible::Covered;
+            }
+            delete pIface;
+        } else {
+            QPoint wc = wg.center();
+            QPoint sc = sg.center();
+            if (wc.x() < sc.x())
+                relation |= QAccessible::Left;
+            else if(wc.x() > sc.x())
+                relation |= QAccessible::Right;
+            if (wc.y() < sc.y())
+                relation |= QAccessible::Up;
+            else if (wc.y() > sc.y())
+                relation |= QAccessible::Down;
+        }
+        delete sibIface;
+
+        return relation;
+    }
+
+    if (isAncestor(o, object()))
+        return relation | Descendent;
+    if (isAncestor(object(), o))
+        return relation | Ancestor;
+
+    return relation;
+}
+
+/*! \reimp */
+int QAccessibleWidget::navigate(RelationFlag relation, int entry,
+                                QAccessibleInterface **target) const
+{
+    if (!target)
+        return -1;
+
+    *target = 0;
+    QObject *targetObject = 0;
+
+    QWidgetList childList = childWidgets(widget());
+    bool complexWidget = childList.size() < childCount();
+
+    switch (relation) {
+    // Hierarchical
+    case Self:
+        targetObject = object();
+        break;
+    case Child:
+        if (complexWidget) {
+            if (entry > 0 && entry <= childCount())
+                return entry;
+            return -1;
+        }else {
+            if (entry > 0 && childList.size() >= entry)
+                targetObject = childList.at(entry - 1);
+        }
+        break;
+    case Ancestor:
+        {
+            if (entry <= 0)
+                return -1;
+            targetObject = widget()->parentWidget();
+            int i;
+            for (i = entry; i > 1 && targetObject; --i)
+                targetObject = targetObject->parent();
+            if (!targetObject && i == 1)
+                targetObject = qApp;
+        }
+        break;
+    case Sibling:
+        {
+            QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(parentObject());
+            if (!iface)
+                return -1;
+
+            iface->navigate(Child, entry, target);
+            delete iface;
+            if (*target)
+                return 0;
+        }
+        break;
+
+    // Geometrical
+    case QAccessible::Left:
+        if (complexWidget && entry) {
+            if (entry < 2 || widget()->height() > widget()->width() + 20) // looks vertical
+                return -1;
+            return entry - 1;
+        }
+        // fall through
+    case QAccessible::Right:
+        if (complexWidget && entry) {
+            if (entry >= childCount() || widget()->height() > widget()->width() + 20) // looks vertical
+                return -1;
+            return entry + 1;
+        }
+        // fall through
+    case QAccessible::Up:
+        if (complexWidget && entry) {
+            if (entry < 2 || widget()->width() > widget()->height() + 20) // looks horizontal
+                return - 1;
+            return entry - 1;
+        }
+        // fall through
+    case QAccessible::Down:
+        if (complexWidget && entry) {
+            if (entry >= childCount() || widget()->width() > widget()->height()  + 20) // looks horizontal
+                return - 1;
+            return entry + 1;
+        } else {
+            QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
+            if (!pIface)
+                return -1;
+
+            QRect startg = rect(0);
+            QPoint startc = startg.center();
+            QAccessibleInterface *candidate = 0;
+            int mindist = 100000;
+            int sibCount = pIface->childCount();
+            for (int i = 0; i < sibCount; ++i) {
+                QAccessibleInterface *sibling = 0;
+                pIface->navigate(Child, i+1, &sibling);
+                Q_ASSERT(sibling);
+                if ((relationTo(0, sibling, 0) & Self) || (sibling->state(0) & QAccessible::Invisible)) {
+                    //ignore ourself and invisible siblings
+                    delete sibling;
+                    continue;
+                }
+
+                QRect sibg = sibling->rect(0);
+                QPoint sibc = sibg.center();
+                QPoint sibp;
+                QPoint startp;
+                QPoint distp;
+                switch (relation) {
+                case QAccessible::Left:
+                    startp = QPoint(startg.left(), startg.top() + startg.height() / 2);
+                    sibp = QPoint(sibg.right(), sibg.top() + sibg.height() / 2);
+                    if (QPoint(sibc - startc).x() >= 0) {
+                        delete sibling;
+                        continue;
+                    }
+                    distp = sibp - startp;
+                    break;
+                case QAccessible::Right:
+                    startp = QPoint(startg.right(), startg.top() + startg.height() / 2);
+                    sibp = QPoint(sibg.left(), sibg.top() + sibg.height() / 2);
+                    if (QPoint(sibc - startc).x() <= 0) {
+                        delete sibling;
+                        continue;
+                    }
+                    distp = sibp - startp;
+                    break;
+                case QAccessible::Up:
+                    startp = QPoint(startg.left() + startg.width() / 2, startg.top());
+                    sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.bottom());
+                    if (QPoint(sibc - startc).y() >= 0) {
+                        delete sibling;
+                        continue;
+                    }
+                    distp = sibp - startp;
+                    break;
+                case QAccessible::Down:
+                    startp = QPoint(startg.left() + startg.width() / 2, startg.bottom());
+                    sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.top());
+                    if (QPoint(sibc - startc).y() <= 0) {
+                        delete sibling;
+                        continue;
+                    }
+                    distp = sibp - startp;
+                    break;
+		default:
+		    break;
+                }
+
+                int dist = (int)qSqrt((qreal)distp.x() * distp.x() + distp.y() * distp.y());
+                if (dist < mindist) {
+                    delete candidate;
+                    candidate = sibling;
+                    mindist = dist;
+                } else {
+                    delete sibling;
+                }
+            }
+            delete pIface;
+            *target = candidate;
+            if (*target)
+                return 0;
+        }
+        break;
+    case Covers:
+        if (entry > 0) {
+            QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
+            if (!pIface)
+                return -1;
+
+            QRect r = rect(0);
+            int sibCount = pIface->childCount();
+            QAccessibleInterface *sibling = 0;
+            for (int i = pIface->indexOfChild(this) + 1; i <= sibCount && entry; ++i) {
+                pIface->navigate(Child, i, &sibling);
+                if (!sibling || (sibling->state(0) & Invisible)) {
+                    delete sibling;
+                    sibling = 0;
+                    continue;
+                }
+                if (sibling->rect(0).intersects(r))
+                    --entry;
+                if (!entry)
+                    break;
+                delete sibling;
+                sibling = 0;
+            }
+            delete pIface;
+            *target = sibling;
+            if (*target)
+                return 0;
+        }
+        break;
+    case Covered:
+        if (entry > 0) {
+            QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
+            if (!pIface)
+                return -1;
+
+            QRect r = rect(0);
+            int index = pIface->indexOfChild(this);
+            QAccessibleInterface *sibling = 0;
+            for (int i = 1; i < index && entry; ++i) {
+                pIface->navigate(Child, i, &sibling);
+                Q_ASSERT(sibling);
+                if (!sibling || (sibling->state(0) & Invisible)) {
+                    delete sibling;
+                    sibling = 0;
+                    continue;
+                }
+                if (sibling->rect(0).intersects(r))
+                    --entry;
+                if (!entry)
+                    break;
+                delete sibling;
+                sibling = 0;
+            }
+            delete pIface;
+            *target = sibling;
+            if (*target)
+                return 0;
+        }
+        break;
+
+    // Logical
+    case FocusChild:
+        {
+            if (widget()->hasFocus()) {
+                targetObject = object();
+                break;
+            }
+
+            QWidget *fw = widget()->focusWidget();
+            if (!fw)
+                return -1;
+
+            if (isAncestor(widget(), fw) || fw == widget())
+                targetObject = fw;
+            /* ###
+            QWidget *parent = fw;
+            while (parent && !targetObject) {
+                parent = parent->parentWidget();
+                if (parent == widget())
+                    targetObject = fw;
+            }
+            */
+        }
+        break;
+    case 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) {
+                pIface->navigate(Child, i+1, &candidate);
+                Q_ASSERT(candidate);
+                if (candidate->relationTo(0, this, 0) & Label)
+                    --entry;
+                if (!entry)
+                    break;
+                delete candidate;
+                candidate = 0;
+            }
+            if (!candidate) {
+                if (pIface->relationTo(0, this, 0) & Label)
+                    --entry;
+                if (!entry)
+                    candidate = pIface;
+            }
+            if (pIface != candidate)
+                delete pIface;
+
+            *target = candidate;
+            if (*target)
+                return 0;
+        }
+        break;
+    case Labelled: // only implemented in subclasses
+        break;
+    case 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(0, this, 0)&Controller)
+                    senders << sender;
+                delete candidate;
+            }
+            if (entry <= senders.size())
+                targetObject = senders.at(entry-1);
+        }
+        break;
+    case 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());
+    return cl.size();
+}
+
+/*! \reimp */
+int QAccessibleWidget::indexOfChild(const QAccessibleInterface *child) const
+{
+    QWidgetList cl = childWidgets(widget());
+    int index = cl.indexOf(qobject_cast<QWidget *>(child->object()));
+    if (index != -1)
+        ++index;
+    return index;
+}
+
+// from qwidget.cpp
+extern QString qt_setWindowTitle_helperHelper(const QString &, const QWidget*);
+
+/*! \reimp */
+QString QAccessibleWidget::text(Text t, int child) const
+{
+    QString str;
+
+    switch (t) {
+    case Name:
+        if (!d->name.isEmpty()) {
+            str = d->name;
+        } else if (!widget()->accessibleName().isEmpty()) {
+            str = widget()->accessibleName();
+        } else if (!child && widget()->isWindow()) {
+            if (widget()->isMinimized())
+                str = qt_setWindowTitle_helperHelper(widget()->windowIconText(), widget());
+            else
+                str = qt_setWindowTitle_helperHelper(widget()->windowTitle(), widget());
+        } else {
+            str = qt_accStripAmp(buddyString(widget()));
+        }
+        break;
+    case Description:
+        if (!d->description.isEmpty())
+            str = d->description;
+        else if (!widget()->accessibleDescription().isEmpty())
+            str = widget()->accessibleDescription();
+#ifndef QT_NO_TOOLTIP
+        else
+            str = widget()->toolTip();
+#endif
+        break;
+    case Help:
+        if (!d->help.isEmpty())
+            str = d->help;
+#ifndef QT_NO_WHATSTHIS
+        else
+            str = widget()->whatsThis();
+#endif
+        break;
+    case Accelerator:
+        if (!d->accelerator.isEmpty())
+            str = d->accelerator;
+        else
+            str = qt_accHotKey(buddyString(widget()));
+        break;
+    case Value:
+        str = d->value;
+        break;
+    default:
+        break;
+    }
+    return str;
+}
+
+#ifndef QT_NO_ACTION
+
+/*! \reimp */
+int QAccessibleWidget::userActionCount(int child) const
+{
+    if (child)
+        return 0;
+    return widget()->actions().count();
+}
+
+/*! \reimp */
+QString QAccessibleWidget::actionText(int action, Text t, int child) const
+{
+    if (action == DefaultAction)
+        action = SetFocus;
+
+    if (action > 0 && !child) {
+        QAction *act = widget()->actions().value(action - 1);
+        if (act) {
+            switch (t) {
+            case Name:
+                return act->text();
+            case Description:
+                return act->toolTip();
+#ifndef QT_NO_SHORTCUT
+            case Accelerator:
+                return act->shortcut().toString();
+#endif
+            default:
+                break;
+            }
+        }
+    }
+
+    return QAccessibleObject::actionText(action, t, child);
+}
+
+/*! \reimp */
+bool QAccessibleWidget::doAction(int action, int child, const QVariantList &params)
+{
+    if (action == SetFocus || action == DefaultAction) {
+        if (child || !widget()->isEnabled())
+            return false;
+        if (widget()->focusPolicy() != Qt::NoFocus)
+            widget()->setFocus();
+        else if (widget()->isWindow())
+            widget()->activateWindow();
+        else
+            return false;
+        return true;
+    } else if (action > 0) {
+        if (QAction *act = widget()->actions().value(action - 1)) {
+            act->trigger();
+            return true;
+        }
+    }
+    return QAccessibleObject::doAction(action, child, params);
+}
+
+#endif // QT_NO_ACTION
+
+/*! \reimp */
+QAccessible::Role QAccessibleWidget::role(int child) const
+{
+    if (!child)
+        return d->role;
+
+    QWidgetList childList = childWidgets(widget());
+    if (childList.count() > 0 && child <= childList.count()) {
+        QWidget *targetWidget = childList.at(child - 1);
+        QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(targetWidget);
+        if (iface) {
+            QAccessible::Role role = iface->role(0);
+            delete iface;
+            return role;
+        }
+    }
+
+    return NoRole;
+}
+
+/*! \reimp */
+QAccessible::State QAccessibleWidget::state(int child) const
+{
+    if (child)
+        return Normal;
+
+    QAccessible::State state = Normal;
+
+    QWidget *w = widget();
+    if (w->testAttribute(Qt::WA_WState_Visible) == false)
+        state |= Invisible;
+    if (w->focusPolicy() != Qt::NoFocus && w->isActiveWindow())
+        state |= Focusable;
+    if (w->hasFocus())
+        state |= Focused;
+    if (!w->isEnabled())
+        state |= Unavailable;
+    if (w->isWindow()) {
+        if (w->windowFlags() & Qt::WindowSystemMenuHint)
+            state |= Movable;
+        if (w->minimumSize() != w->maximumSize())
+            state |= Sizeable;
+    }
+
+    return state;
+}
+
+// ### Qt 5: remove me - binary compatibility hack
+QAccessibleWidgetEx::QAccessibleWidgetEx(QWidget *o, Role role, const QString& name)
+    : QAccessibleObjectEx(o)
+{
+    Q_ASSERT(widget());
+    d = new QAccessibleWidgetPrivate();
+    d->role = role;
+    d->name = name;
+    d->asking = 0;
+}
+
+int QAccessibleWidgetEx::childCount() const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::childCount(); }
+int QAccessibleWidgetEx::indexOfChild(const QAccessibleInterface *child) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::indexOfChild(child); }
+QAccessible::Relation QAccessibleWidgetEx::relationTo(int child, const QAccessibleInterface *other, int otherChild) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::relationTo(child, other, otherChild); }
+
+int QAccessibleWidgetEx::childAt(int x, int y) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::childAt(x, y); }
+QRect QAccessibleWidgetEx::rect(int child) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::rect(child); }
+int QAccessibleWidgetEx::navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::navigate(rel, entry, target); }
+
+QString QAccessibleWidgetEx::text(Text t, int child) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::text(t, child); }
+QAccessible::Role QAccessibleWidgetEx::role(int child) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::role(child); }
+QAccessible::State QAccessibleWidgetEx::state(int child) const
+{ return (reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::state(child))
+    | HasInvokeExtension; }
+
+QString QAccessibleWidgetEx::actionText(int action, Text t, int child) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::actionText(action, t, child); }
+bool QAccessibleWidgetEx::doAction(int action, int child, const QVariantList &params)
+{ return reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::doAction(action, child, params); }
+
+QAccessibleWidgetEx::~QAccessibleWidgetEx()
+{ delete d; }
+QWidget *QAccessibleWidgetEx::widget() const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::widget(); }
+QObject *QAccessibleWidgetEx::parentObject() const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::parentObject(); }
+
+void QAccessibleWidgetEx::addControllingSignal(const QString &signal)
+{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::addControllingSignal(signal); }
+void QAccessibleWidgetEx::setValue(const QString &value)
+{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::setValue(value); }
+void QAccessibleWidgetEx::setDescription(const QString &desc)
+{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::setDescription(desc); }
+void QAccessibleWidgetEx::setHelp(const QString &help)
+{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::setHelp(help); }
+void QAccessibleWidgetEx::setAccelerator(const QString &accel)
+{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::setAccelerator(accel); }
+
+QVariant QAccessibleWidgetEx::invokeMethodEx(Method method, int child, const QVariantList & /*params*/)
+{
+    if (child)
+        return QVariant();
+
+    switch (method) {
+    case ListSupportedMethods: {
+        QSet<QAccessible::Method> set;
+        set << ListSupportedMethods << ForegroundColor << BackgroundColor;
+        return qVariantFromValue(set);
+    }
+    case ForegroundColor:
+        return widget()->palette().color(widget()->foregroundRole());
+    case BackgroundColor:
+        return widget()->palette().color(widget()->backgroundRole());
+    default:
+        return QVariant();
+    }
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ACCESSIBILITY