Accessibility: Improve interface handling in Quick
authorFrederik Gladhorn <frederik.gladhorn@digia.com>
Sun, 4 Nov 2012 11:54:30 +0000 (12:54 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Wed, 19 Dec 2012 13:59:06 +0000 (14:59 +0100)
This changes how interfaces are handled:
the QAccessibleQuickItem will simply subclass
all interfaces and dynamically return 0 or the
appropriate interface_cast.

This makes our implementation a lot more flexible.
To make use of the value interface, only a value
property is needed (together with a corresponding role).

Since the implementation of the interfaces became simpler,
the value interface and some text interface improvements
go along with the change.

Change-Id: I003ec3016d48d730a4acac467bce322167842f4d
Reviewed-by: Jan Arve Sæther <jan-arve.saether@digia.com>

src/plugins/accessible/quick/main.cpp
src/plugins/accessible/quick/qaccessiblequickitem.cpp
src/plugins/accessible/quick/qaccessiblequickitem.h
src/quick/items/qquickaccessibleattached_p.h
src/quick/items/qquickitem.cpp
src/quick/items/qquicktextinput.cpp

index 882cbcd..cac5d7e 100644 (file)
@@ -92,22 +92,7 @@ QAccessibleInterface *AccessibleQuickFactory::create(const QString &classname, Q
         QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
         if (!itemPrivate->isAccessible)
             return 0;
-
-        QVariant v = QQuickAccessibleAttached::property(item, "role");
-        bool ok;
-        QAccessible::Role role = (QAccessible::Role)v.toInt(&ok);
-        if (!ok)    // Not sure if this check is needed.
-            return new QAccessibleQuickItem(item);
-
-        switch (role) {
-        case QAccessible::Slider:
-        case QAccessible::SpinBox:
-        case QAccessible::Dial:
-        case QAccessible::ScrollBar:
-            return new QAccessibleQuickItemValueInterface(item);
-        default:
-            return new QAccessibleQuickItem(item);
-        }
+        return new QAccessibleQuickItem(item);
     }
 
     return 0;
index 2d41379..8d36834 100644 (file)
@@ -228,7 +228,7 @@ QString QAccessibleQuickItem::text(QAccessible::Text textType) const
         break;
     }
 
-    // the following blocks handles item-specific behavior
+    // the following block handles item-specific behavior
     if (role() == QAccessible::EditableText) {
         if (textType == QAccessible::Value) {
             QVariant text = object()->property("text");
@@ -241,34 +241,44 @@ QString QAccessibleQuickItem::text(QAccessible::Text textType) const
     return QString();
 }
 
-void *QAccessibleQuickItemValueInterface::interface_cast(QAccessible::InterfaceType t)
+void *QAccessibleQuickItem::interface_cast(QAccessible::InterfaceType t)
 {
-    if (t == QAccessible::ValueInterface)
+    QAccessible::Role r = role();
+    if (t == QAccessible::ValueInterface &&
+           (r == QAccessible::Slider ||
+            r == QAccessible::SpinBox ||
+            r == QAccessible::Dial ||
+            r == QAccessible::ScrollBar))
        return static_cast<QAccessibleValueInterface*>(this);
-    return QAccessibleQuickItem::interface_cast(t);
+
+    if (t == QAccessible::TextInterface &&
+            (r == QAccessible::EditableText))
+        return static_cast<QAccessibleTextInterface*>(this);
+
+    return QQmlAccessible::interface_cast(t);
 }
 
-QVariant QAccessibleQuickItemValueInterface::currentValue() const
+QVariant QAccessibleQuickItem::currentValue() const
 {
     return item()->property("value");
 }
 
-void QAccessibleQuickItemValueInterface::setCurrentValue(const QVariant &value)
+void QAccessibleQuickItem::setCurrentValue(const QVariant &value)
 {
     item()->setProperty("value", value);
 }
 
-QVariant QAccessibleQuickItemValueInterface::maximumValue() const
+QVariant QAccessibleQuickItem::maximumValue() const
 {
     return item()->property("maximumValue");
 }
 
-QVariant QAccessibleQuickItemValueInterface::minimumValue() const
+QVariant QAccessibleQuickItem::minimumValue() const
 {
     return item()->property("minimumValue");
 }
 
-QVariant QAccessibleQuickItemValueInterface::minimumStepSize() const
+QVariant QAccessibleQuickItem::minimumStepSize() const
 {
     return item()->property("stepSize");
 }
index 0d31749..46f573c 100644 (file)
@@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE
 
 #ifndef QT_NO_ACCESSIBILITY
 
-class QAccessibleQuickItem : public QQmlAccessible
+class QAccessibleQuickItem : public QQmlAccessible, public QAccessibleValueInterface, public QAccessibleTextInterface
 {
 public:
     QAccessibleQuickItem(QQuickItem *item);
@@ -72,28 +72,51 @@ public:
 
     bool isAccessible() const;
 
-protected:
-    QQuickItem *item() const { return static_cast<QQuickItem*>(object()); }
-};
-
-QRect itemScreenRect(QQuickItem *item);
-
-
-class QAccessibleQuickItemValueInterface: public QAccessibleQuickItem, public QAccessibleValueInterface
-{
-public:
-    QAccessibleQuickItemValueInterface(QQuickItem *item) : QAccessibleQuickItem(item)
-    {}
-
-    void *interface_cast(QAccessible::InterfaceType t);
-
+    // Value Interface
     QVariant currentValue() const;
     void setCurrentValue(const QVariant &value);
     QVariant maximumValue() const;
     QVariant minimumValue() const;
     QVariant minimumStepSize() const;
+
+
+    // Text Interface
+    // selection (ignored for now)
+    void selection(int selectionIndex, int *startOffset, int *endOffset) const { *startOffset = 0; *endOffset = 0; }
+    int selectionCount() const { return 0; }
+    void addSelection(int startOffset, int endOffset) {}
+    void removeSelection(int selectionIndex) {}
+    void setSelection(int selectionIndex, int startOffset, int endOffset) {}
+
+    // cursor
+    int cursorPosition() const { return 0; }
+    void setCursorPosition(int position) {}
+
+    // text
+    QString text(int startOffset, int endOffset) const { return text(QAccessible::Name).mid(startOffset, endOffset - startOffset); }
+//    QString textBeforeOffset(int offset, QAccessible2::BoundaryType boundaryType,
+//                                     int *startOffset, int *endOffset) const;
+//    QString textAfterOffset(int offset, QAccessible2::BoundaryType boundaryType,
+//                                    int *startOffset, int *endOffset) const;
+//    QString textAtOffset(int offset, QAccessible2::BoundaryType boundaryType,
+//                                 int *startOffset, int *endOffset) const;
+    int characterCount() const { return text(QAccessible::Name).count(); }
+
+    // character <-> geometry
+    QRect characterRect(int offset) const { return QRect(); }
+    int offsetAtPoint(const QPoint &point) const { return -1; }
+
+    void scrollToSubstring(int startIndex, int endIndex) {}
+    QString attributes(int offset, int *startOffset, int *endOffset) const { return QString(); }
+
+protected:
+    QQuickItem *item() const { return static_cast<QQuickItem*>(object()); }
+    void *interface_cast(QAccessible::InterfaceType t);
 };
 
+QRect itemScreenRect(QQuickItem *item);
+
+
 #endif // QT_NO_ACCESSIBILITY
 
 QT_END_NAMESPACE
index 74f486a..a11f40c 100644 (file)
@@ -127,6 +127,18 @@ public:
         return obj->setProperty(propertyName, value);
     }
 
+    static QObject *findAccessible(QObject *object, QAccessible::Role role = QAccessible::NoRole)
+    {
+        while (object) {
+            QObject *att = QQuickAccessibleAttached::attachedProperties(object);
+            if (att && (role == QAccessible::NoRole || att->property("role").toInt() == role)) {
+                break;
+            }
+            object = object->parent();
+        }
+        return object;
+    }
+
 
 Q_SIGNALS:
     void roleChanged();
index 2340da9..b23ff68 100644 (file)
@@ -3129,8 +3129,12 @@ void QQuickItem::inputMethodEvent(QInputMethodEvent *event)
 void QQuickItem::focusInEvent(QFocusEvent * /*event*/)
 {
 #ifndef QT_NO_ACCESSIBILITY
-    QAccessibleEvent ev(this, QAccessible::Focus);
-    QAccessible::updateAccessibility(&ev);
+    if (QAccessible::isActive()) {
+        if (QObject *acc = QQuickAccessibleAttached::findAccessible(this)) {
+            QAccessibleEvent ev(acc, QAccessible::Focus);
+            QAccessible::updateAccessibility(&ev);
+        }
+    }
 #endif
 }
 
@@ -5274,7 +5278,7 @@ void QQuickItem::setFlags(Flags flags)
         }
     }
 
-    if ((flags & ItemClipsChildrenToShape ) != (d->flags & ItemClipsChildrenToShape))
+    if ((flags & ItemClipsChildrenToShape) != (d->flags & ItemClipsChildrenToShape))
         d->dirty(QQuickItemPrivate::Clip);
 
     d->flags = flags;
index fee4959..6dd8fb1 100644 (file)
@@ -59,6 +59,7 @@
 
 #ifndef QT_NO_ACCESSIBILITY
 #include "qaccessible.h"
+#include "qquickaccessibleattached_p.h"
 #endif
 
 QT_BEGIN_NAMESPACE
@@ -3374,9 +3375,11 @@ void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool e
 #ifdef QT_NO_ACCESSIBILITY
     Q_UNUSED(changed)
 #else
-    if (changed) {
-        QAccessibleTextUpdateEvent ev(q, 0, oldText, m_text);
-        QAccessible::updateAccessibility(&ev);
+    if (changed && QAccessible::isActive()) {
+        if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
+            QAccessibleTextUpdateEvent ev(acc, 0, oldText, m_text);
+            QAccessible::updateAccessibility(&ev);
+        }
     }
 #endif
 }
@@ -4025,8 +4028,12 @@ bool QQuickTextInputPrivate::emitCursorPositionChanged()
         }
 
 #ifndef QT_NO_ACCESSIBILITY
-        QAccessibleTextCursorEvent ev(q, m_cursor);
-        QAccessible::updateAccessibility(&ev);
+        if (QAccessible::isActive()) {
+            if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
+                QAccessibleTextCursorEvent ev(acc, m_cursor);
+                QAccessible::updateAccessibility(&ev);
+            }
+        }
 #endif
 
         return true;