Added QAccessibleGroupBox
authorFrederik Gladhorn <frederik.gladhorn@nokia.com>
Mon, 13 Feb 2012 13:05:51 +0000 (14:05 +0100)
committerQt by Nokia <qt-info@nokia.com>
Sat, 24 Mar 2012 14:10:00 +0000 (15:10 +0100)
Added a new accessible interface for QGroupBox, as QAccessibleDisplay
is not good enough when the QGroupBox is checkable.
AccessibleFactory was modified to return a QAccessibleGroupBox when
the accessible interface of a QGroupBox is requested.

Created tst_QAccessibility::groupBoxTest

Port to Qt5 of the patch by José Millán Soto <fid@gpul.org>

Change-Id: I6c23dcf5562b3ea269b04102e78463b65827188a
Reviewed-by: Jan-Arve Sæther <jan-arve.saether@nokia.com>
(cherry picked from commit c03ceb203c65d9e3485fad848bfc0c4b6ee3e9aa)

src/plugins/accessible/widgets/main.cpp
src/plugins/accessible/widgets/simplewidgets.cpp
src/plugins/accessible/widgets/simplewidgets.h
src/widgets/widgets/qgroupbox.cpp
tests/auto/other/qaccessibility/tst_qaccessibility.cpp

index ca8bf81..4709069 100644 (file)
@@ -236,8 +236,10 @@ QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObjec
 #endif
     } else if (classname == QLatin1String("QLabel") || classname == QLatin1String("QLCDNumber")) {
         iface = new QAccessibleDisplay(widget);
+#ifndef QT_NO_GROUPBOX
     } else if (classname == QLatin1String("QGroupBox")) {
-        iface = new QAccessibleDisplay(widget, QAccessible::Grouping);
+        iface = new QAccessibleGroupBox(widget);
+#endif
     } else if (classname == QLatin1String("QStatusBar")) {
         iface = new QAccessibleWidget(widget, QAccessible::StatusBar);
 #ifndef QT_NO_PROGRESSBAR
index 4e1fe34..af0c211 100644 (file)
@@ -399,10 +399,6 @@ QString QAccessibleDisplay::text(QAccessible::Text t) const
         if (str.isEmpty()) {
             if (qobject_cast<QLabel*>(object())) {
                 str = qobject_cast<QLabel*>(object())->text();
-#ifndef QT_NO_GROUPBOX
-            } else if (qobject_cast<QGroupBox*>(object())) {
-                str = qobject_cast<QGroupBox*>(object())->title();
-#endif
 #ifndef QT_NO_LCDNUMBER
             } else if (qobject_cast<QLCDNumber*>(object())) {
                 QLCDNumber *l = qobject_cast<QLCDNumber*>(object());
@@ -440,15 +436,6 @@ QAccessibleDisplay::relations(QAccessible::Relation match /*= QAccessible::AllRe
         if (QLabel *label = qobject_cast<QLabel*>(object())) {
             relatedObjects.append(label->buddy());
 #endif
-#ifndef QT_NO_GROUPBOX
-        } 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
         }
         for (int i = 0; i < relatedObjects.count(); ++i) {
             const QAccessible::Relation rel = QAccessible::Labelled;
@@ -502,6 +489,87 @@ QRect QAccessibleDisplay::imagePosition() const
     return QRect(label->mapToGlobal(label->pos()), label->size());
 }
 
+#ifndef QT_NO_GROUPBOX
+QAccessibleGroupBox::QAccessibleGroupBox(QWidget *w)
+: QAccessibleWidget(w)
+{
+}
+
+QGroupBox* QAccessibleGroupBox::groupBox() const
+{
+    return static_cast<QGroupBox *>(widget());
+}
+
+QString QAccessibleGroupBox::text(QAccessible::Text t) const
+{
+    QString txt = QAccessibleWidget::text(t);
+
+    if (txt.isEmpty()) {
+        switch (t) {
+        case QAccessible::Name:
+            txt = qt_accStripAmp(groupBox()->title());
+        case QAccessible::Description:
+            txt = qt_accStripAmp(groupBox()->title());
+        default:
+            break;
+        }
+    }
+
+    return txt;
+}
+
+QAccessible::State QAccessibleGroupBox::state() const
+{
+    QAccessible::State st = QAccessibleWidget::state();
+    st.checkable = groupBox()->isCheckable();
+    st.checked = groupBox()->isChecked();
+    return st;
+}
+
+QAccessible::Role QAccessibleGroupBox::role() const
+{
+    return groupBox()->isCheckable() ? QAccessible::CheckBox : QAccessible::Grouping;
+}
+
+QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >
+QAccessibleGroupBox::relations(QAccessible::Relation match /*= QAccessible::AllRelations*/) const
+{
+    QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > rels = QAccessibleWidget::relations(match);
+
+    if ((match & QAccessible::Labelled) && (!groupBox()->title().isEmpty())) {
+        const QList<QWidget*> kids = childWidgets(widget());
+        for (int i = 0; i < kids.count(); ++i) {
+            QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(kids.at(i));
+            if (iface)
+                rels.append(qMakePair(iface, QAccessible::Relation(QAccessible::Labelled)));
+        }
+    }
+    return rels;
+}
+
+QStringList QAccessibleGroupBox::actionNames() const
+{
+    QStringList actions = QAccessibleWidget::actionNames();
+
+    if (groupBox()->isCheckable()) {
+        actions.prepend(QAccessibleActionInterface::checkAction());
+    }
+    return actions;
+}
+
+void QAccessibleGroupBox::doAction(const QString &actionName)
+{
+    if (actionName == QAccessibleActionInterface::checkAction())
+        groupBox()->setChecked(!groupBox()->isChecked());
+}
+
+QStringList QAccessibleGroupBox::keyBindingsForAction(const QString &) const
+{
+    return QStringList();
+}
+
+#endif
+
 #ifndef QT_NO_LINEEDIT
 /*!
   \class QAccessibleLineEdit
index e2847dd..74c1da4 100644 (file)
@@ -53,6 +53,7 @@ QT_BEGIN_NAMESPACE
 class QAbstractButton;
 class QLineEdit;
 class QToolButton;
+class QGroupBox;
 class QProgressBar;
 
 class QAccessibleButton : public QAccessibleWidget
@@ -113,6 +114,28 @@ public:
     QRect imagePosition() const;
 };
 
+#ifndef QT_NO_GROUPBOX
+class QAccessibleGroupBox : public QAccessibleWidget
+{
+public:
+    explicit QAccessibleGroupBox(QWidget *w);
+
+    QAccessible::State state() const;
+    QAccessible::Role role() const;
+    QString text(QAccessible::Text t) const;
+
+    QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >relations(QAccessible::Relation match = QAccessible::AllRelations) const;
+
+    //QAccessibleActionInterface
+    QStringList actionNames() const;
+    void doAction(const QString &actionName);
+    QStringList keyBindingsForAction(const QString &) const;
+
+private:
+    QGroupBox *groupBox() const;
+};
+#endif
+
 #ifndef QT_NO_LINEEDIT
 class QAccessibleLineEdit : public QAccessibleWidget, public QAccessibleTextInterface,
                             public QAccessibleSimpleEditableTextInterface
index e9edea2..d8ad04c 100644 (file)
@@ -643,6 +643,12 @@ void QGroupBox::setChecked(bool b)
         update();
         d->checked = b;
         d->_q_setChildrenEnabled(b);
+#ifndef QT_NO_ACCESSIBILITY
+        QAccessible::State st;
+        st.checked = true;
+        QAccessibleStateChangeEvent *ev = new QAccessibleStateChangeEvent(this, st);
+        QAccessible::updateAccessibility(ev);
+#endif
         emit toggled(b);
     }
 }
index 4d46ae4..be7cb7d 100644 (file)
@@ -252,6 +252,7 @@ private slots:
     void mdiAreaTest();
     void mdiSubWindowTest();
     void lineEditTest();
+    void groupBoxTest();
     void workspaceTest();
     void dialogButtonBoxTest();
     void dialTest();
@@ -1894,6 +1895,72 @@ void tst_QAccessibility::lineEditTest()
     QTestAccessibility::clearEvents();
 }
 
+void tst_QAccessibility::groupBoxTest()
+{
+    {
+    QGroupBox *groupBox = new QGroupBox();
+    QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(groupBox);
+
+    groupBox->setTitle(QLatin1String("Test QGroupBox"));
+
+    QAccessibleEvent ev(groupBox, QAccessible::NameChanged);
+    QVERIFY_EVENT(&ev);
+
+    groupBox->setToolTip(QLatin1String("This group box will be used to test accessibility"));
+    QVBoxLayout *layout = new QVBoxLayout();
+    QRadioButton *rbutton = new QRadioButton();
+    layout->addWidget(rbutton);
+    groupBox->setLayout(layout);
+    QAccessibleInterface *rButtonIface = QAccessible::queryAccessibleInterface(rbutton);
+
+    QCOMPARE(iface->childCount(), 1);
+    QCOMPARE(iface->role(), QAccessible::Grouping);
+    QCOMPARE(iface->text(QAccessible::Name), QLatin1String("Test QGroupBox"));
+    QCOMPARE(iface->text(QAccessible::Description), QLatin1String("This group box will be used to test accessibility"));
+    QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > relations = rButtonIface->relations();
+    QVERIFY(relations.size() == 1);
+    QPair<QAccessibleInterface*, QAccessible::Relation> relation = relations.first();
+    QCOMPARE(relation.first->object(), groupBox);
+    QCOMPARE(relation.second, QAccessible::Label);
+
+    delete relation.first;
+
+    delete rButtonIface;
+    delete iface;
+    delete groupBox;
+    }
+
+    {
+    QGroupBox *groupBox = new QGroupBox();
+    QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(groupBox);
+    QVERIFY(!iface->state().checkable);
+    groupBox->setCheckable(true);
+
+    groupBox->setChecked(false);
+    QAccessible::State st;
+    st.checked = true;
+    QAccessibleStateChangeEvent ev(groupBox, st);
+    QVERIFY_EVENT(&ev);
+
+    QCOMPARE(iface->role(), QAccessible::CheckBox);
+    QAccessibleActionInterface *actionIface = iface->actionInterface();
+    QVERIFY(actionIface);
+    QAccessible::State state = iface->state();
+    QVERIFY(state.checkable);
+    QVERIFY(!state.checked);
+    QVERIFY(actionIface->actionNames().contains(QAccessibleActionInterface::checkAction()));
+    actionIface->doAction(QAccessibleActionInterface::checkAction());
+    QVERIFY(groupBox->isChecked());
+    state = iface->state();
+    QVERIFY(state.checked);
+    QAccessibleStateChangeEvent ev2(groupBox, st);
+    QVERIFY_EVENT(&ev2);
+
+    delete iface;
+    delete groupBox;
+    }
+}
+
 void tst_QAccessibility::workspaceTest()
 {
     {