diff --git a/doc/src/declarative/declarativeui.qdoc b/doc/src/declarative/declarativeui.qdoc index 054717941f67a2060958ff222ca41d0578afbad8..3554cf556c62f08304c00bbad0a65c58753c1018 100644 --- a/doc/src/declarative/declarativeui.qdoc +++ b/doc/src/declarative/declarativeui.qdoc @@ -78,6 +78,7 @@ Qt applications. \o \l{Dynamic Object Management in QML}{Dynamic Object Management} \o \l{Network Transparency}{Loading Resources in QML} \o \l{QML Internationalization}{Internationalization} +\o \l{Accessible}{Accessibility} \endlist \section1 QML Add-Ons diff --git a/doc/src/declarative/elements.qdoc b/doc/src/declarative/elements.qdoc index 174b762391caad3498472c579f985c0efc2e9379..5cacd86ccd951668f0cfcf2be30a1a936ca7de4b 100644 --- a/doc/src/declarative/elements.qdoc +++ b/doc/src/declarative/elements.qdoc @@ -179,6 +179,11 @@ Elements that animate properties based on data types \o The \l{QtQuick.Particles 2} module provides a set of Particle System elements for QtQuick 2 \endlist +\section1 Accessibility +\list +\o \l {Accessible} - Attached property to make components accessible +\endlist + */ diff --git a/examples/declarative/accessibility/accessibility.qml b/examples/declarative/accessibility/accessibility.qml new file mode 100644 index 0000000000000000000000000000000000000000..dff08e52ede29003c23ccf8702504db5b0c636ab --- /dev/null +++ b/examples/declarative/accessibility/accessibility.qml @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Window 2.0 +import "widgets" + +Rectangle { + id: window + + width: 360; height: 300 + color: "white" + + Column { + id: column + spacing: 6 + anchors.fill: parent + width: parent.width + Row { + spacing: 6 + width: column.width + Button { width: 100; height: column.h + 20; text: "Send" } + Button { width: 100; height: column.h + 20; text: "Discard" } + } + + Row { + spacing: 6 + width: column.width + height: column.h + Text { + id: subjectLabel + Accessible.role: Accessible.StaticText + Accessible.name: text + text: "Subject:" + width: 50 + } + Rectangle { + id: subjectBorder + Accessible.role: Accessible.EditableText + Accessible.name: subjectEdit.text + border.width: 1 + border.color: "black" + height: subjectEdit.height + width: 304 + TextInput { + id: subjectEdit + text: "Vacation plans" + } + } + } + Rectangle { + id: textBorder + Accessible.role: Accessible.EditableText + property alias text : textEdit.text + border.width: 1 + border.color: "black" + width: parent.width + height: textEdit.height + TextEdit { + id: textEdit + text: "Hi, we're going to the Dolomites this summer. Weren't you also going to northern Italy? \n\nbest wishes, your friend Luke" + width: parent.width + wrapMode: TextEdit.WordWrap + } + } + } +} diff --git a/examples/declarative/accessibility/widgets/Button.qml b/examples/declarative/accessibility/widgets/Button.qml new file mode 100644 index 0000000000000000000000000000000000000000..2ce5629a6aa883d851fc9f93e75f6c0d06ed41d7 --- /dev/null +++ b/examples/declarative/accessibility/widgets/Button.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: button + + property alias text : buttonText.text + Accessible.name: text + Accessible.description: "This button does " + text + Accessible.role: Accessible.Button + + signal clicked + + width: buttonText.width + 20 + height: 30 + gradient: Gradient { + GradientStop { position: 0.0; color: "lightsteelblue" } + GradientStop { position: 1.0; color: "blue" } + } + border.width: 2 + border.color: "black"; + radius: 10 + + Text { + id: buttonText + text: parent.description + anchors.centerIn: parent + font.pixelSize: parent.height * .5 + style: Text.Sunken; color: "white"; styleColor: "black"; smooth: true + } + + MouseArea { + id: mouseArea + anchors.fill: parent + onClicked: { + checked = !checked; + } + } +} diff --git a/examples/declarative/calculator/Core/Button.qml b/examples/declarative/calculator/Core/Button.qml index 9080c2472e93d0f5d66db8b7979a6bb98438b34a..6222ac09c42bbfe65bcc58347f5eebd73c01e3d1 100644 --- a/examples/declarative/calculator/Core/Button.qml +++ b/examples/declarative/calculator/Core/Button.qml @@ -47,6 +47,10 @@ BorderImage { property alias operation: buttonText.text property string color: "" + Accessible.name: operation + Accessible.description: "This button does " + operation + Accessible.role: Accessible.Button + signal clicked source: "images/button-" + color + ".png"; clip: true diff --git a/src/plugins/accessible/accessible.pro b/src/plugins/accessible/accessible.pro new file mode 100644 index 0000000000000000000000000000000000000000..71165af784107c32dee5200e9083bc7add021dae --- /dev/null +++ b/src/plugins/accessible/accessible.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS += quick +SUBDIRS += qtquick1 diff --git a/src/plugins/accessible/qtquick1/main.cpp b/src/plugins/accessible/qtquick1/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5ace1a78a10e9b44ffdef9a848f4b73074f90f11 --- /dev/null +++ b/src/plugins/accessible/qtquick1/main.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeaccessible.h" +#include "qaccessibledeclarativeview.h" +#include "qaccessibledeclarativeitem.h" + +#include <QtQuick1/qdeclarativeitem.h> +#include <QtWidgets/qgraphicsview.h> + +#include <qaccessibleplugin.h> +#include <qplugin.h> +#include <qvariant.h> +#include <qaccessible.h> + +#ifndef QT_NO_ACCESSIBILITY + +QT_BEGIN_NAMESPACE + +class AccessibleQtQuick1Factory : public QAccessiblePlugin +{ +public: + AccessibleQtQuick1Factory(); + + QStringList keys() const; + QAccessibleInterface *create(const QString &classname, QObject *object); +}; + +AccessibleQtQuick1Factory::AccessibleQtQuick1Factory() +{ +} + +QStringList AccessibleQtQuick1Factory::keys() const +{ + QStringList list; + list << QLatin1String("QDeclarativeView"); + list << QLatin1String("QDeclarativeItem"); + return list; +} + +QAccessibleInterface *AccessibleQtQuick1Factory::create(const QString &classname, QObject *object) +{ + if (classname == QLatin1String("QDeclarativeView")) { + QWidget *widget = qobject_cast<QWidget*>(object); + if (qobject_cast<QDeclarativeView *>(widget) != 0) + return new QAccessibleDeclarativeView(widget); + } else if (classname == QLatin1String("QDeclarativeItem")) { + QDeclarativeItem *item = qobject_cast<QDeclarativeItem *>(object); + if (!item->scene()) + return 0; + + QList<QGraphicsView *> views = item->scene()->views(); + if (views.isEmpty()) + return 0; + QGraphicsView *view = views.at(0); // Accessibility support for the first view only. + // (Not a problem for QDeclarative) + return new QAccessibleDeclarativeItem(item, view); + } + + return 0; +} + +Q_EXPORT_STATIC_PLUGIN(AccessibleQtQuick1Factory) +Q_EXPORT_PLUGIN2(qtaccessibleqtquick1, AccessibleQtQuick1Factory) + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/qtquick1/qaccessibledeclarativeitem.cpp b/src/plugins/accessible/qtquick1/qaccessibledeclarativeitem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..202023990b12435681f0de5925ba976e7a9b407b --- /dev/null +++ b/src/plugins/accessible/qtquick1/qaccessibledeclarativeitem.cpp @@ -0,0 +1,290 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaccessibledeclarativeitem.h" + +#include <QtQuick1/qdeclarativeitem.h> +#include <QtQuick1/private/qdeclarativeaccessibleattached_p.h> + +QT_BEGIN_NAMESPACE + +QAccessibleDeclarativeItem::QAccessibleDeclarativeItem(QGraphicsObject *item, QGraphicsView *view) + :QDeclarativeAccessible(item) + ,m_item(item) + ,m_view(view) +{ + +} + +int QAccessibleDeclarativeItem::childCount() const +{ + QList<QGraphicsItem *> children = m_item->childItems(); + return children.count(); +} + +QRect QAccessibleDeclarativeItem::rect() const +{ + QRectF sceneRect = m_item->sceneTransform().mapRect(m_item->boundingRect()); + QPoint pos = m_view->mapFromScene(m_view->mapToGlobal(sceneRect.topLeft().toPoint())); + QSize size = sceneRect.size().toSize(); + return QRect(pos, size); +} + +QRect QAccessibleDeclarativeItem::viewRect() const +{ + QPoint screenPos = m_view->mapToGlobal(m_view->pos()); + return QRect(screenPos, m_view->size()); +} + +bool QAccessibleDeclarativeItem::clipsChildren() const +{ + return static_cast<QDeclarativeItem *>(m_item)->clip(); +} + +static inline bool isAncestor(const QObject *ancestorCandidate, const QObject *child) +{ + while (child) { + if (child == ancestorCandidate) + return true; + child = child->parent(); + } + return false; +} + + +QAccessibleInterface *QAccessibleDeclarativeItem::parent() const +{ + QGraphicsItem *parent = m_item->parentItem(); + QGraphicsObject *parentObj = parent ? parent->toGraphicsObject() : 0; + if (parent && !parentObj) + qWarning("Can not make QGraphicsItems accessible"); + QAccessibleInterface *ancestor = (parentObj + ? new QAccessibleDeclarativeItem(parentObj, m_view) + : QAccessible::queryAccessibleInterface(m_view)); + return ancestor; +} + +QAccessibleInterface *QAccessibleDeclarativeItem::child(int index) const +{ + QList<QGraphicsItem *> children = m_item->childItems(); + + if (index >= children.count()) + return 0; + + QGraphicsItem *child = children.at(index); + QGraphicsObject *childObject = qobject_cast<QGraphicsObject *>(child); + if (!childObject) + return 0; + + return new QAccessibleDeclarativeItem(childObject, m_view); +} + +int QAccessibleDeclarativeItem::navigate(QAccessible::RelationFlag rel, int entry, QAccessibleInterface **target) const +{ + //qDebug() << "QAccessibleDeclarativeItem navigate" << rel << entry; + Q_ASSERT(entry >= 0); + + *target = 0; + if (entry == 0) { + *target = new QAccessibleDeclarativeItem(m_item->toGraphicsObject(), m_view); + return 0; + } + + switch (rel) { + case QAccessible::Child: { + QList<QGraphicsItem *> children = m_item->childItems(); + const int childIndex = entry - 1; + + if (childIndex >= children.count()) + return -1; + + QGraphicsItem *child = children.at(childIndex); + QGraphicsObject *childObject = qobject_cast<QGraphicsObject *>(child); + if (!childObject) + return -1; + + *target = new QAccessibleDeclarativeItem(childObject, m_view); + return 0; + break;} + case QAccessible::Ancestor: { + Q_ASSERT(entry >= 1); + QGraphicsItem *parent = m_item->parentItem(); + QGraphicsObject *parentObj = parent ? parent->toGraphicsObject() : 0; + if (parent && !parentObj) + qWarning("Can not make QGraphicsItems accessible"); + QAccessibleInterface *ancestor = (parentObj + ? new QAccessibleDeclarativeItem(parentObj, m_view) + : QAccessible::queryAccessibleInterface(m_view)); + if (entry == 1) { + *target = ancestor; + return 0; + } else if (entry > 1) { + int ret = ancestor->navigate(QAccessible::Ancestor, entry - 1, target); + delete ancestor; + return ret; + } + break;} + case QAccessible::Sibling: { + QAccessibleInterface *iface = 0; + if (navigate(QAccessible::Ancestor, 1, &iface) == 0) { + if (iface) { + int ret = iface->navigate(QAccessible::Child, entry, target); + delete iface; + return ret; + } + } + return -1; + break;} + case QAccessible::FocusChild: { + QGraphicsObject *focusObject = 0; + if (m_item->hasFocus()) { + focusObject = m_item->toGraphicsObject(); + } else { + if (QGraphicsItem *focusItem = m_view->scene()->focusItem()) { + if (m_item->isAncestorOf(focusItem)) { + focusObject = focusItem->toGraphicsObject(); + } + } + } + //qDebug() << "QAccessibleDeclarativeItem navigate QAccessible::FocusChild" << rel << entry; + if (focusObject) { + *target = new QAccessibleDeclarativeItem(focusObject, m_view); + return 0; + } + } + default: break; + } + + return -1; + +} + +int QAccessibleDeclarativeItem::indexOfChild(const QAccessibleInterface *iface) const +{ + // ### No QAccessibleInterfaces are created with a QGraphicsItem. + // However, we want to support QML, not QGraphicsView in general. + // And since the UI is written in QML, this means we can assume that *all* + // QGraphicsItems are actually QGraphicsObjects + + const QGraphicsObject *childObj = static_cast<QGraphicsObject*>(iface->object()); + if (m_item == childObj) + return 0; + + QList<QGraphicsItem*> kids = m_item->childItems(); + int index = kids.indexOf(const_cast<QGraphicsItem*>(static_cast<const QGraphicsItem*>(childObj))); + if (index != -1) { + ++index; + } + return index; +} + +QFlags<QAccessible::StateFlag> QAccessibleDeclarativeItem::state() const +{ + QAccessible::State state = QAccessible::Normal; + + if (m_item->hasFocus()) { + state |= QAccessible::Focused; + } + return state; +} + +QAccessible::Role QAccessibleDeclarativeItem::role() const +{ + // ### Workaround for setAccessibleRole() not working. + // Text items are special since they are defined + // entirely from C++ (setting the role from QML works.) +// if (qobject_cast<QDeclarative1Text*>(m_item)) +// return QAccessible::StaticText; + + QVariant v = QDeclarativeAccessibleAttached::property(m_item, "role"); + bool ok; + QAccessible::Role role = (QAccessible::Role)v.toInt(&ok); + if (!ok) // Not sure if this check is needed. + role = QAccessible::Pane; + return role; +} + +bool QAccessibleDeclarativeItem::isAccessible() const +{ + return true; +} + +QString QAccessibleDeclarativeItem::text(QAccessible::Text textType) const +{ + // handles generic behaviour not specific to an item + switch (textType) { + case QAccessible::Name: { + QVariant accessibleName = QDeclarativeAccessibleAttached::property(object(), "name"); + if (!accessibleName.isNull()) + return accessibleName.toString(); + break;} + case QAccessible::Description: { + QVariant accessibleDecription = QDeclarativeAccessibleAttached::property(object(), "description"); + if (!accessibleDecription.isNull()) + return accessibleDecription.toString(); + break;} + case QAccessible::Value: + case QAccessible::Help: + case QAccessible::Accelerator: + default: + break; + } + + // the following blocks handles item-specific behaviour + if (role() == QAccessible::EditableText) { + if (textType == QAccessible::Value) { + QVariant text = object()->property("text"); + return text.toString(); + } else if (textType == QAccessible::Name) { + return object()->objectName(); + } + } else { + if (textType == QAccessible::Name) { + QVariant text = object()->property("text"); + return text.toString(); + } + } + + + return QString(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/accessible/qtquick1/qaccessibledeclarativeitem.h b/src/plugins/accessible/qtquick1/qaccessibledeclarativeitem.h new file mode 100644 index 0000000000000000000000000000000000000000..5582672aaeb55ad8cb890819c2f70fabbc1a07f3 --- /dev/null +++ b/src/plugins/accessible/qtquick1/qaccessibledeclarativeitem.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACCESSIBLEDECLARATIVEITEM_H +#define QACCESSIBLEDECLARATIVEITEM_H + +#include "qdeclarativeaccessible.h" + +#include <QtWidgets/qgraphicsview.h> +#include <QtWidgets/qgraphicsitem.h> + +QT_BEGIN_NAMESPACE + +class QAccessibleDeclarativeItem : public QDeclarativeAccessible +{ +public: + QAccessibleDeclarativeItem(QGraphicsObject *item, QGraphicsView *view); + + QRect rect() const; + QRect viewRect() const; + + bool clipsChildren() const; + + QAccessibleInterface *parent() const; + QAccessibleInterface *child(int index) const; + int childCount() const; + int navigate(QAccessible::RelationFlag rel, int entry, QAccessibleInterface **target) const; + int indexOfChild(const QAccessibleInterface *iface) const; + + QFlags<QAccessible::StateFlag> state() const; + QAccessible::Role role() const; + QString text(QAccessible::Text) const; + + virtual bool isAccessible() const; +private: + QGraphicsObject *m_item; + QGraphicsView *m_view; +}; + +QT_END_NAMESPACE + +#endif // QACCESSIBLEGRAPHICSVIEWIMPLEMENTATION_H diff --git a/src/plugins/accessible/qtquick1/qaccessibledeclarativeview.cpp b/src/plugins/accessible/qtquick1/qaccessibledeclarativeview.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1aa4bef992cd5dd051520458cbc1f2c12837a9b4 --- /dev/null +++ b/src/plugins/accessible/qtquick1/qaccessibledeclarativeview.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaccessibledeclarativeview.h" +#include "qdeclarativeaccessible.h" +#include "qaccessibledeclarativeitem.h" + + +#ifndef QT_NO_ACCESSIBILITY + +QT_BEGIN_NAMESPACE + +QAccessibleDeclarativeView::QAccessibleDeclarativeView(QWidget *widget) + :QAccessibleWidget(widget) +{ + m_view = static_cast<QDeclarativeView *>(widget); +} + +int QAccessibleDeclarativeView::childCount() const +{ + return 1; +} + +QAccessibleInterface *QAccessibleDeclarativeView::child(int index) const +{ + if (index == 0) { + QDeclarativeItem *declarativeRoot = m_view->accessibleRootItem(); + return new QAccessibleDeclarativeItem(declarativeRoot, m_view); + } + return 0; +} + +int QAccessibleDeclarativeView::navigate(QAccessible::RelationFlag rel, int entry, QAccessibleInterface **target) const +{ + if (rel == QAccessible::Child) { + *target = child(entry - 1); + return *target ? 0 : -1; + } + return QAccessibleWidget::navigate(rel, entry, target); +} + +QAccessibleInterface *QAccessibleDeclarativeView::childAt(int x, int y) const +{ + return child(0); // return the top-level QML item +} + +int QAccessibleDeclarativeView::indexOfChild(const QAccessibleInterface *iface) const +{ + if (iface) { + QDeclarativeItem *declarativeRoot = m_view->accessibleRootItem(); + if (declarativeRoot == iface->object()) + return 1; + } + return -1; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/qtquick1/qaccessibledeclarativeview.h b/src/plugins/accessible/qtquick1/qaccessibledeclarativeview.h new file mode 100644 index 0000000000000000000000000000000000000000..48833f932caebbd29421e7a29a1eb0c762ae6276 --- /dev/null +++ b/src/plugins/accessible/qtquick1/qaccessibledeclarativeview.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACCESSIBLEDECLARATIVEVIEW_H +#define QACCESSIBLEDECLARATIVEVIEW_H + +#include <QtGui/qaccessible2.h> +#include <QtWidgets/qaccessiblewidget.h> + +#include <QtQuick1/qdeclarativeview.h> +#include <QtQuick1/qdeclarativeitem.h> +#include <QtWidgets/qwidget.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_ACCESSIBILITY + +class QAccessibleDeclarativeView: public QAccessibleWidget +{ +public: + explicit QAccessibleDeclarativeView(QWidget *widget); + + QAccessibleInterface *child(int index) const; + int childCount() const; + int navigate(QAccessible::RelationFlag rel, int entry, QAccessibleInterface **target) const; + QAccessibleInterface *childAt(int x, int y) const; + int indexOfChild(const QAccessibleInterface *iface) const; + +private: + QDeclarativeView *m_view; +}; + +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE + +#endif // QACCESSIBLEDECLARATIVEVIEW_H diff --git a/src/plugins/accessible/qtquick1/qtquick1.pro b/src/plugins/accessible/qtquick1/qtquick1.pro new file mode 100644 index 0000000000000000000000000000000000000000..f4602e4420b3517f301ddf3abae82b356e4a5342 --- /dev/null +++ b/src/plugins/accessible/qtquick1/qtquick1.pro @@ -0,0 +1,22 @@ +contains(QT_CONFIG, accessibility) { + +TARGET = qtaccessibleqtquick1 +load(qt_plugin) +include ($$PWD/../shared/qaccessiblebase.pri) + +QT += core-private gui-private widgets-private v8-private declarative-private qtquick1-private +DESTDIR = $$QT.gui.plugins/accessible + +QTDIR_build:REQUIRES += "contains(QT_CONFIG, accessibility)" + +DEFINES+=Q_ACCESSIBLE_QUICK_ITEM_ENABLE_DEBUG_DESCRIPTION + +SOURCES += \ + main.cpp \ + qaccessibledeclarativeview.cpp \ + qaccessibledeclarativeitem.cpp + +HEADERS += \ + qaccessibledeclarativeview.h \ + qaccessibledeclarativeitem.h +} diff --git a/src/plugins/accessible/quick/main.cpp b/src/plugins/accessible/quick/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8b8285e45067cf5e3bfbdb1885e6174f69a2914d --- /dev/null +++ b/src/plugins/accessible/quick/main.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qdeclarativeaccessible.h" +#include "qaccessiblequickview.h" +#include "qaccessiblequickitem.h" + +#include <QtQuick/QQuickView> +#include <QtQuick/QQuickItem> + +#include <qaccessibleplugin.h> +#include <qvariant.h> +#include <qplugin.h> +#include <qaccessible.h> + +#ifndef QT_NO_ACCESSIBILITY + +QT_BEGIN_NAMESPACE + +class AccessibleQuickFactory : public QAccessiblePlugin +{ +public: + AccessibleQuickFactory(); + + QStringList keys() const; + QAccessibleInterface *create(const QString &classname, QObject *object); +}; + +AccessibleQuickFactory::AccessibleQuickFactory() +{ +} + +QStringList AccessibleQuickFactory::keys() const +{ + QStringList list; + list << QLatin1String("QQuickView"); + list << QLatin1String("QQuickItem"); + return list; +} + +QAccessibleInterface *AccessibleQuickFactory::create(const QString &classname, QObject *object) +{ + if (classname == QLatin1String("QQuickView")) { + return new QAccessibleQuickView(qobject_cast<QQuickView *>(object)); // FIXME + } else if (classname == QLatin1String("QQuickItem")) { + QQuickItem * item = qobject_cast<QQuickItem *>(object); + Q_ASSERT(item); + return new QAccessibleQuickItem(item); + } + + return 0; +} + +Q_EXPORT_STATIC_PLUGIN(AccessibleQuickFactory) +Q_EXPORT_PLUGIN2(qtaccessiblequick, AccessibleQuickFactory) + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/quick/qaccessiblequickitem.cpp b/src/plugins/accessible/quick/qaccessiblequickitem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7131e110d8d3b7e7e108df3831910ed9f4f8ecc3 --- /dev/null +++ b/src/plugins/accessible/quick/qaccessiblequickitem.cpp @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaccessiblequickitem.h" +#include "QtQuick/private/qquickitem_p.h" +#include "QtQuick/private/qquicktext_p.h" +#include "QtQuick/private/qquickaccessibleattached_p.h" + +QT_BEGIN_NAMESPACE + +QAccessibleQuickItem::QAccessibleQuickItem(QQuickItem *item) + : QDeclarativeAccessible(item) + , m_item(item) +{ +} + +int QAccessibleQuickItem::childCount() const +{ + return childItems().count(); +} + +QRect QAccessibleQuickItem::rect() const +{ + // ### no canvas in some cases. + // ### Should we really check for 0 opacity? + if (!m_item->canvas() ||!m_item->isVisible() || qFuzzyIsNull(m_item->opacity())) { + return QRect(); + } + + QSizeF size = QSizeF(m_item->width(), m_item->height()); + // ### If the bounding rect fails, we first try the implicit size, then we go for the + // parent size. WE MIGHT HAVE TO REVISIT THESE FALLBACKS. + if (size.isEmpty()) { + size = QSizeF(m_item->implicitWidth(), m_item->implicitHeight()); + if (size.isEmpty()) + // ### Seems that the above fallback is not enough, fallback to use the parent size... + size = QSizeF(m_item->parentItem()->width(), m_item->parentItem()->height()); + } + + QRectF sceneRect = m_item->mapRectToScene(QRectF(QPointF(0, 0), size)); + QPoint screenPos = m_item->canvas()->mapToGlobal(sceneRect.topLeft().toPoint()); + + QRect r = QRect(screenPos, sceneRect.size().toSize()); + + if (!r.isValid()) { + qWarning() << m_item->metaObject()->className() << m_item->property("accessibleText") << r; + } + return r; +} + +QRect QAccessibleQuickItem::viewRect() const +{ + // ### no canvas in some cases. + if (!m_item->canvas()) { + return QRect(); + } + + QQuickCanvas *canvas = m_item->canvas(); + QPoint screenPos = canvas->mapToGlobal(QPoint(0,0)); + return QRect(screenPos, canvas->size()); +} + + +bool QAccessibleQuickItem::clipsChildren() const +{ + return static_cast<QQuickItem *>(m_item)->clip(); +} + + +QAccessibleInterface *QAccessibleQuickItem::parent() const +{ + QQuickItem *parent = m_item->parentItem(); + if (parent) { + QQuickCanvas *canvas = m_item->canvas(); + // Jump out to the scene widget if the parent is the root item. + // There are two root items, QQuickCanvas::rootItem and + // QQuickView::declarativeRoot. The former is the true root item, + // but is not a part of the accessibility tree. Check if we hit + // it here and return an interface for the scene instead. + if (parent == canvas->rootItem()) { + return QAccessible::queryAccessibleInterface(canvas); + } else { + QDeclarativeAccessible *ancestor = new QAccessibleQuickItem(parent); + return ancestor; + } + } + return 0; +} + +QAccessibleInterface *QAccessibleQuickItem::child(int index) const +{ + QList<QQuickItem *> children = childItems(); + + if (index < 0 || index >= children.count()) + return 0; + + QQuickItem *child = children.at(index); + if (!child) // FIXME can this happen? + return 0; + + return new QAccessibleQuickItem(child); +} + +int QAccessibleQuickItem::navigate(QAccessible::RelationFlag rel, int entry, QAccessibleInterface **target) const +{ + *target = 0; + if (entry == 0) { + *target = new QAccessibleQuickItem(m_item); + return 0; + } + + switch (rel) { + case QAccessible::Child: { // FIMXE + QList<QQuickItem *> children = childItems(); + const int childIndex = entry - 1; + + if (childIndex >= children.count()) + return -1; + + QQuickItem *child = children.at(childIndex); + if (!child) + return -1; + + *target = new QAccessibleQuickItem(child); + return 0; + break;} + case QAccessible::Ancestor: { // FIMXE + QQuickItem *parent = m_item->parentItem(); + if (parent) { + QDeclarativeAccessible *ancestor = new QAccessibleQuickItem(parent); + if (entry == 1) { + QQuickCanvas *canvas = m_item->canvas(); + // Jump out to the scene widget if the parent is the root item. + // There are two root items, QQuickCanvas::rootItem and + // QQuickView::declarativeRoot. The former is the true root item, + // but is not a part of the accessibility tree. Check if we hit + // it here and return an interface for the scene instead. + if (parent == canvas->rootItem()) { + *target = QAccessible::queryAccessibleInterface(canvas); + } else { + *target = ancestor; + } + return 0; + } else if (entry > 1) { + int ret = ancestor->navigate(QAccessible::Ancestor, entry - 1, target); + delete ancestor; + return ret; + } + } + return -1; + break;} + default: break; + } + + return -1; +} + +int QAccessibleQuickItem::indexOfChild(const QAccessibleInterface *iface) const +{ + QList<QQuickItem*> kids = childItems(); + int idx = kids.indexOf(static_cast<QQuickItem*>(iface->object())); + if (idx != -1) + ++idx; + return idx; +} + +QList<QQuickItem *> QAccessibleQuickItem::childItems() const +{ + if (role() == QAccessible::Button) + return QList<QQuickItem *>(); + return m_item->childItems(); +} + +QFlags<QAccessible::StateFlag> QAccessibleQuickItem::state() const +{ + QAccessible::State state = QAccessible::Normal; + + if (m_item->hasActiveFocus()) { + state |= QAccessible::Focused; + } + return state; +} + + +QAccessible::Role QAccessibleQuickItem::role() const +{ + // Workaround for setAccessibleRole() not working for + // Text items. Text items are special since they are defined + // entirely from C++ (setting the role from QML works.) + if (qobject_cast<QQuickText*>(const_cast<QQuickItem *>(m_item))) + return QAccessible::StaticText; + + QVariant v = QQuickAccessibleAttached::property(m_item, "role"); + bool ok; + QAccessible::Role role = (QAccessible::Role)v.toInt(&ok); + if (!ok) // Not sure if this check is needed. + role = QAccessible::Pane; + return role; +} + +bool QAccessibleQuickItem::isAccessible() const +{ + return m_item->d_func()->isAccessible; +} + +QString QAccessibleQuickItem::text(QAccessible::Text textType) const +{ + // handles generic behavior not specific to an item + switch (textType) { + case QAccessible::Name: { + QVariant accessibleName = QQuickAccessibleAttached::property(object(), "name"); + if (!accessibleName.isNull()) + return accessibleName.toString(); + break;} + case QAccessible::Description: { + QVariant accessibleDecription = QQuickAccessibleAttached::property(object(), "description"); + if (!accessibleDecription.isNull()) + return accessibleDecription.toString(); + break;} +#ifdef Q_ACCESSIBLE_QUICK_ITEM_ENABLE_DEBUG_DESCRIPTION + case QAccessible::DebugDescription: { + QString debugString; + debugString = QString::fromAscii(object()->metaObject()->className()) + QLatin1Char(' '); + debugString += isAccessible() ? QLatin1String("enabled") : QLatin1String("disabled"); + return debugString; + break; } +#endif + case QAccessible::Value: + case QAccessible::Help: + case QAccessible::Accelerator: + default: + break; + } + + // the following blocks handles item-specific behavior + if (role() == QAccessible::EditableText) { + if (textType == QAccessible::Value) { + QVariant text = object()->property("text"); + return text.toString(); + } else if (textType == QAccessible::Name) { + return object()->objectName(); + } + } else { + if (textType == QAccessible::Name) { + QVariant text = object()->property("text"); + return text.toString(); + } + } + + + return QString(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/accessible/quick/qaccessiblequickitem.h b/src/plugins/accessible/quick/qaccessiblequickitem.h new file mode 100644 index 0000000000000000000000000000000000000000..9782f6773179f1c61b79535c5aaaf2eeb5320495 --- /dev/null +++ b/src/plugins/accessible/quick/qaccessiblequickitem.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACCESSIBLEQUICKITEM_H +#define QACCESSIBLEQUICKITEM_H + +#include <QtQuick/QQuickItem> +#include <QtQuick/QQuickView> +#include "qdeclarativeaccessible.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_ACCESSIBILITY + +class QAccessibleQuickItem : public QDeclarativeAccessible +{ +public: + QAccessibleQuickItem(QQuickItem *item); + + QRect rect() const; + QRect viewRect() const; + + bool clipsChildren() const; + + QAccessibleInterface *parent() const; + QAccessibleInterface *child(int index) const; + int childCount() const; + int navigate(QAccessible::RelationFlag rel, int entry, QAccessibleInterface **target) const; + int indexOfChild(const QAccessibleInterface *iface) const; + QList<QQuickItem *> childItems() const; + + QFlags<QAccessible::StateFlag> state() const; + QAccessible::Role role() const; + QString text(QAccessible::Text) const; + + bool isAccessible() const; +private: + QQuickItem *m_item; +}; + +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE + +#endif // QACCESSIBLEQUICKITEM_H diff --git a/src/plugins/accessible/quick/qaccessiblequickview.cpp b/src/plugins/accessible/quick/qaccessiblequickview.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd4b4937ec351567e10119086037c4a818dce856 --- /dev/null +++ b/src/plugins/accessible/quick/qaccessiblequickview.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaccessiblequickview.h" + +#include <QtQuick/qquickitem.h> + +#include "qaccessiblequickitem.h" +#include "qdeclarativeaccessible.h" + +#ifndef QT_NO_ACCESSIBILITY + +QT_BEGIN_NAMESPACE + +QAccessibleQuickView::QAccessibleQuickView(QQuickView *object) + :QAccessibleObject(object) +{ + m_view = static_cast<QQuickView *>(object); +} + +int QAccessibleQuickView::childCount() const +{ + return m_view->rootItem() ? 1 : 0; +} + +QAccessibleInterface *QAccessibleQuickView::parent() const +{ + // FIXME: for now we assume to be a top level window... + return QAccessible::queryAccessibleInterface(qApp); +} + +QAccessibleInterface *QAccessibleQuickView::child(int index) const +{ + if (index == 0) { + QQuickItem *declarativeRoot = m_view->rootObject(); + return new QAccessibleQuickItem(declarativeRoot); + } + return 0; +} + +QAccessible::Role QAccessibleQuickView::role() const +{ + return QAccessible::Window; // FIXME +} + +QAccessible::State QAccessibleQuickView::state() const +{ + return QAccessible::Normal; // FIXME +} + +QRect QAccessibleQuickView::rect() const +{ + return QRect(m_view->x(), m_view->y(), m_view->width(), m_view->height()); +} + +int QAccessibleQuickView::navigate(QAccessible::RelationFlag rel, int entry, QAccessibleInterface **target) const +{ + switch (rel) { + case QAccessible::Child: + *target = child(entry - 1); + case QAccessible::Ancestor: + *target = parent(); + default: + *target = 0; + } + return *target ? 0 : -1; +} + +QString QAccessibleQuickView::text(QAccessible::Text text) const +{ +#ifdef Q_ACCESSIBLE_QUICK_ITEM_ENABLE_DEBUG_DESCRIPTION + if (text == QAccessible::DebugDescription) { + return QString::fromAscii(object()->metaObject()->className()) ; + } +#endif + return m_view->windowTitle(); +} + +QAccessibleInterface *QAccessibleQuickView::childAt(int x, int y) const +{ + Q_UNUSED(x); + Q_UNUSED(y); + return child(0); // return the top-level QML item +} + +int QAccessibleQuickView::indexOfChild(const QAccessibleInterface *iface) const +{ + if (iface) { + QQuickItem *declarativeRoot = m_view->rootObject(); + if (declarativeRoot == iface->object()) + return 1; + } + return -1; + +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/quick/qaccessiblequickview.h b/src/plugins/accessible/quick/qaccessiblequickview.h new file mode 100644 index 0000000000000000000000000000000000000000..0b9b5d1f8049d8f68d3c8db265fb51fe09542f29 --- /dev/null +++ b/src/plugins/accessible/quick/qaccessiblequickview.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QAccessibleQuickView_H +#define QAccessibleQuickView_H + +#include <QtGui/qaccessible2.h> +#include <QtGui/qaccessibleobject.h> +#include <QtQuick/qquickview.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_ACCESSIBILITY + +class QAccessibleQuickView : public QAccessibleObject +{ +public: + QAccessibleQuickView(QQuickView *object); + + QAccessibleInterface *parent() const; + QAccessibleInterface *child(int index) const; + + QAccessible::Role role() const; + QAccessible::State state() const; + QRect rect() const; + + int childCount() const; + int navigate(QAccessible::RelationFlag rel, int entry, QAccessibleInterface **target) const; + int indexOfChild(const QAccessibleInterface *iface) const; + QString text(QAccessible::Text text) const; + QAccessibleInterface *childAt(int x, int y) const; +private: + QQuickView *m_view; +}; + +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE + +#endif // QAccessibleQuickView_H diff --git a/src/plugins/accessible/quick/quick.pro b/src/plugins/accessible/quick/quick.pro new file mode 100644 index 0000000000000000000000000000000000000000..97a1d5009819b2f0eb45c327e60e5209b2d0647b --- /dev/null +++ b/src/plugins/accessible/quick/quick.pro @@ -0,0 +1,23 @@ +contains(QT_CONFIG, accessibility) { + +TARGET = qtaccessiblequick +load(qt_plugin) +include ($$PWD/../shared/qaccessiblebase.pri) + +QT += core-private gui-private v8-private declarative-private quick-private +DESTDIR = $$QT.gui.plugins/accessible + +QTDIR_build:REQUIRES += "contains(QT_CONFIG, accessibility)" + +#DEFINES+=Q_ACCESSIBLE_QUICK_ITEM_ENABLE_DEBUG_DESCRIPTION + +SOURCES += \ + main.cpp \ + qaccessiblequickview.cpp \ + qaccessiblequickitem.cpp + +HEADERS += \ + qaccessiblequickview.h \ + qaccessiblequickitem.h +} + diff --git a/src/plugins/accessible/shared/qaccessiblebase.pri b/src/plugins/accessible/shared/qaccessiblebase.pri new file mode 100644 index 0000000000000000000000000000000000000000..8c82705443556e6f34a14078cf33cc8bab4bc53c --- /dev/null +++ b/src/plugins/accessible/shared/qaccessiblebase.pri @@ -0,0 +1,7 @@ +target.path += $$[QT_INSTALL_PLUGINS]/accessible +INSTALLS += target + +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +SOURCES += $$PWD/qdeclarativeaccessible.cpp +HEADERS += $$PWD/qdeclarativeaccessible.h diff --git a/src/plugins/accessible/shared/qdeclarativeaccessible.cpp b/src/plugins/accessible/shared/qdeclarativeaccessible.cpp new file mode 100644 index 0000000000000000000000000000000000000000..abe73f24ea3de83e08e0efd0d9162c9dc9c00dfc --- /dev/null +++ b/src/plugins/accessible/shared/qdeclarativeaccessible.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qnamespace.h> +#include "qdeclarativeaccessible.h" + +#ifndef QT_NO_ACCESSIBILITY + +QT_BEGIN_NAMESPACE + + +QString Q_GUI_EXPORT qTextBeforeOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType, + int *startOffset, int *endOffset, const QString& text); +QString Q_GUI_EXPORT qTextAtOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType, + int *startOffset, int *endOffset, const QString& text); +QString Q_GUI_EXPORT qTextAfterOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType, + int *startOffset, int *endOffset, const QString& text); + +QDeclarativeAccessible::QDeclarativeAccessible(QObject *object) + :QAccessibleObject(object) +{ +} + +QDeclarativeAccessible::~QDeclarativeAccessible() +{ +} + +QFlags<QAccessible::RelationFlag> QDeclarativeAccessible::relationTo(const QAccessibleInterface *) const +{ + return QAccessible::Unrelated; +} + +QAccessibleInterface *QDeclarativeAccessible::childAt(int x, int y) const +{ + // Look for children first. + // Start with the last child first, because children are ordered in paint order + // (which is opposite of hit test order) + + // If the item clips its children, we can return early if the coordinate is outside its rect + if (clipsChildren()) { + if (!rect().contains(x, y)) + return 0; + } + + for (int i = childCount() - 1; i >= 0; --i) { + QAccessibleInterface *childIface = child(i); + if (childIface && !(childIface->state() & QAccessible::Invisible)) { + if (childIface->rect().contains(x, y)) + return childIface; + } + } + return 0; +} + +QFlags<QAccessible::StateFlag> QDeclarativeAccessible::state() const +{ + QAccessible::State state;// = state(); + + //QRect viewRect(QPoint(0, 0), m_implementation->size()); + //QRect itemRect(m_item->scenePos().toPoint(), m_item->boundingRect().size().toSize()); + + QRect viewRect_ = viewRect(); + QRect itemRect = rect(); + + // qDebug() << "viewRect" << viewRect << "itemRect" << itemRect; + // error case: + if (viewRect_.isNull() || itemRect.isNull()) { + state |= QAccessible::Invisible; + } + + if (!viewRect_.intersects(itemRect)) { + state |= QAccessible::Offscreen; + // state |= QAccessible::Invisible; // no set at this point to ease development + } + + if (!object()->property("visible").toBool() || qFuzzyIsNull(object()->property("opacity").toDouble())) { + state |= QAccessible::Invisible; + } + + if ((role() == QAccessible::CheckBox || role() == QAccessible::RadioButton) && object()->property("checked").toBool()) { + state |= QAccessible::Checked; + } + + if (role() == QAccessible::EditableText) + state |= QAccessible::Focusable; + + //qDebug() << "state?" << m_item->property("state").toString() << m_item->property("status").toString() << m_item->property("visible").toString(); + + return state; +} + +QStringList QDeclarativeAccessible::actionNames() const +{ + QStringList actions; + switch (role()) { + case QAccessible::PushButton: + actions << QAccessibleActionInterface::pressAction(); + break; + case QAccessible::RadioButton: + case QAccessible::CheckBox: + actions << QAccessibleActionInterface::checkAction(); + break; + default: + break; + } + return actions; +} + +void QDeclarativeAccessible::doAction(const QString &actionName) +{ + if (role() == QAccessible::PushButton && actionName == QAccessibleActionInterface::pressAction()) { + QMetaObject::invokeMethod(object(), "accessibleAction"); + } + if ((role() == QAccessible::CheckBox || role() == QAccessible::RadioButton) && actionName == QAccessibleActionInterface::checkAction()) { + bool checked = object()->property("checked").toBool(); + object()->setProperty("checked", QVariant(!checked)); + } +} + +QStringList QDeclarativeAccessible::keyBindingsForAction(const QString &actionName) const +{ + Q_UNUSED(actionName) + return QStringList(); +} + +QVariant QDeclarativeAccessible::invokeMethod(QAccessible::Method method, const QVariantList&) +{ + Q_UNUSED(method) + return QVariant(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/shared/qdeclarativeaccessible.h b/src/plugins/accessible/shared/qdeclarativeaccessible.h new file mode 100644 index 0000000000000000000000000000000000000000..16b61508c019f3c2bb5fc4f6ec484a9eb3acd3c6 --- /dev/null +++ b/src/plugins/accessible/shared/qdeclarativeaccessible.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEACCESSIBLE_H +#define QDECLARATIVEACCESSIBLE_H + +#include <QtGui/qaccessibleobject.h> +#include <QtGui/qaccessible2.h> +//#include <QtQuick1/qdeclarativeview.h> +//#include <QtQuick1/qdeclarativeitem.h> +#include <QtDeclarative/qdeclarativeproperty.h> + +//#include <private/qdeclarativeaccessible_p.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_ACCESSIBILITY + +/* + -- Declarative Accessibility Overview. -- + + * Item interface classes: + QAccessibleDeclarativeItem for QtQuick1 + QAccessibleQuickItem for for QtQuick2 + Common base class: QDeclarativeAccessible + + * View interface classes. + + These are the root of the QML accessible tree and connects it to the widget hierarchy. + + QAccessbileDeclarativeView is the root for the QGraphicsView implementation + QAccessbileQuickView is the root for the SceneGraph implementation + +*/ +class QDeclarativeAccessible: public QAccessibleObject, public QAccessibleActionInterface +{ +public: + ~QDeclarativeAccessible(); + + virtual QRect viewRect() const = 0; + QFlags<QAccessible::RelationFlag> relationTo(const QAccessibleInterface*) const; + QAccessibleInterface *childAt(int, int) const; + QFlags<QAccessible::StateFlag> state() const; + QVariant invokeMethod(QAccessible::Method, const QVariantList &); + + QStringList actionNames() const; + void doAction(const QString &actionName); + QStringList keyBindingsForAction(const QString &actionName) const; + +protected: + virtual bool clipsChildren() const = 0; + // For subclasses, use instantiateObject factory method outside the class. + QDeclarativeAccessible(QObject *object); +}; + +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE + +#endif // QDECLARATIVEACCESSIBLE_H diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 664a45760800c386e4e4c78fdee835ccfe7e41ac..ae42ba1ba4d5ed803990e709b803b0bafedea9e3 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -1,2 +1,3 @@ TEMPLATE = subdirs SUBDIRS += qmltooling +SUBDIRS += accessible diff --git a/src/qtquick1/graphicsitems/graphicsitems.pri b/src/qtquick1/graphicsitems/graphicsitems.pri index 9904274023c7cde4eeaf3e98eb66fefce3243210..d3125d0b66e99091c38c251e54e802bc7f9c1432 100644 --- a/src/qtquick1/graphicsitems/graphicsitems.pri +++ b/src/qtquick1/graphicsitems/graphicsitems.pri @@ -2,6 +2,7 @@ INCLUDEPATH += $$PWD HEADERS += \ $$PWD/qdeclarativeitemsmodule_p.h \ + $$PWD/qdeclarativeaccessibleattached_p.h \ $$PWD/qdeclarativeanchors_p.h \ $$PWD/qdeclarativeanchors_p_p.h \ $$PWD/qdeclarativeevents_p_p.h \ @@ -59,6 +60,7 @@ HEADERS += \ SOURCES += \ $$PWD/qdeclarativeitemsmodule.cpp \ + $$PWD/qdeclarativeaccessibleattached.cpp \ $$PWD/qdeclarativeanchors.cpp \ $$PWD/qdeclarativeevents.cpp \ $$PWD/qdeclarativeflickable.cpp \ diff --git a/src/qtquick1/graphicsitems/qdeclarativeaccessibleattached.cpp b/src/qtquick1/graphicsitems/qdeclarativeaccessibleattached.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c9d0645b01dfbcd809ff4ed0a93c0b57b3456956 --- /dev/null +++ b/src/qtquick1/graphicsitems/qdeclarativeaccessibleattached.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeaccessibleattached_p.h" + +#ifndef QT_NO_ACCESSIBILITY + +#include "private/qdeclarativeitem_p.h" + +QT_BEGIN_NAMESPACE + + +QDeclarativeAccessibleAttached::QDeclarativeAccessibleAttached(QObject *parent) + : QObject(parent) +{ + Q_ASSERT(parent); + QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent); + if (!item) + return; + + // Enable accessibility for items with accessible content. This also + // enables accessibility for the ancestors of such items. + item->d_func()->setAccessibleFlagAndListener(); + QAccessible::updateAccessibility(item, 0, QAccessible::ObjectCreated); +} + +QDeclarativeAccessibleAttached::~QDeclarativeAccessibleAttached() +{ +} + +QDeclarativeAccessibleAttached *QDeclarativeAccessibleAttached::qmlAttachedProperties(QObject *obj) +{ + return new QDeclarativeAccessibleAttached(obj); +} + +QT_END_NAMESPACE + +#endif diff --git a/src/qtquick1/graphicsitems/qdeclarativeaccessibleattached_p.h b/src/qtquick1/graphicsitems/qdeclarativeaccessibleattached_p.h new file mode 100644 index 0000000000000000000000000000000000000000..8671c671b7c73d2b1292d206a3ec29c283c651e0 --- /dev/null +++ b/src/qtquick1/graphicsitems/qdeclarativeaccessibleattached_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICK1ACCESSIBLEATTACHED_H +#define QQUICK1ACCESSIBLEATTACHED_H + +#include <qdeclarativeitem.h> + +#include <QtCore/qobject.h> +#include <QtCore/qstring.h> + +#ifndef QT_NO_ACCESSIBILITY + +#include <private/qdeclarativeglobal_p.h> +#include <QtGui/qaccessible.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_QTQUICK1_EXPORT QDeclarativeAccessibleAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(QAccessible::Role role READ role WRITE setRole NOTIFY roleChanged) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged) + +public: + Q_ENUMS(QAccessible::Role QAccessible::Event QAccessible::State) + + QDeclarativeAccessibleAttached(QObject *parent); + ~QDeclarativeAccessibleAttached(); + + QAccessible::Role role() const { return m_role; } + void setRole(QAccessible::Role role) + { + m_role = role; + emit roleChanged(); + // There is no way to signify role changes at the moment. + // QAccessible::updateAccessibility(parent(), 0, QAccessible::); + } + QString name() const { return m_name; } + void setName(const QString &name) + { + m_name = name; + emit nameChanged(); + QAccessible::updateAccessibility(parent(), 0, QAccessible::NameChanged); + } + + QString description() const { return m_description; } + void setDescription(const QString &description) + { + m_description = description; + emit descriptionChanged(); + QAccessible::updateAccessibility(parent(), 0, QAccessible::DescriptionChanged); + } + + // Factory function + static QDeclarativeAccessibleAttached *qmlAttachedProperties(QObject *); + + // Property getter + static QObject *attachedProperties(const QObject *obj) + { + return qmlAttachedPropertiesObject<QDeclarativeAccessibleAttached>(obj, false); + } + + static QVariant property(const QObject *object, const char *propertyName) + { + if (QObject *attachedObject = QDeclarativeAccessibleAttached::attachedProperties(object)) + return attachedObject->property(propertyName); + return QVariant(); + } + + static bool setProperty(QObject *object, const char *propertyName, const QVariant &value) + { + QObject *obj = qmlAttachedPropertiesObject<QDeclarativeAccessibleAttached>(object, true); + if (!obj) { + qWarning("cannot set property Accessible.%s of QObject %s", propertyName, object->metaObject()->className()); + return false; + } + return obj->setProperty(propertyName, value); + } + + +Q_SIGNALS: + void roleChanged(); + void nameChanged(); + void descriptionChanged(); +private: + QAccessible::Role m_role; + QString m_name; + QString m_description; +public: + using QObject::property; +}; + + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeAccessibleAttached) +QML_DECLARE_TYPEINFO(QDeclarativeAccessibleAttached, QML_HAS_ATTACHED_PROPERTIES) + +QT_END_HEADER + +#endif // QT_NO_ACCESSIBILITY + +#endif + diff --git a/src/qtquick1/graphicsitems/qdeclarativeitem.cpp b/src/qtquick1/graphicsitems/qdeclarativeitem.cpp index 1f57d53b7e1708c91d6676451b0a08b1e6ccc923..016dc94408fef1014563e4b8477fdee2739ac3e7 100644 --- a/src/qtquick1/graphicsitems/qdeclarativeitem.cpp +++ b/src/qtquick1/graphicsitems/qdeclarativeitem.cpp @@ -53,6 +53,8 @@ #include <QtQuick1/private/qdeclarativestategroup_p.h> #include <QtDeclarative/qdeclarativecomponent.h> #include <QtDeclarative/qdeclarativeinfo.h> +// ### Due to the workaround mentioned in accessibleRole() +#include <QtQuick1/private/qdeclarativetext_p.h> #include <QDebug> #include <QPen> @@ -64,6 +66,8 @@ #include <private/qv8engine_p.h> #include <QtWidgets/qgraphicstransform.h> #include <private/qlistmodelinterface_p.h> +#include <QAccessible> +#include <QtQuick1/private/qdeclarativeaccessibleattached_p.h> #include <float.h> @@ -1779,7 +1783,11 @@ QDeclarativeItem::~QDeclarativeItem() */ void QDeclarativeItem::setParentItem(QDeclarativeItem *parent) { + Q_D(QDeclarativeItem); QGraphicsObject::setParentItem(parent); + if (d->isAccessible && parentItem()) { + parentItem()->d_func()->setAccessibleFlagAndListener(); + } } /*! @@ -3022,6 +3030,25 @@ QDeclarativeItemPrivate::AnchorLines::AnchorLines(QGraphicsObject *q) baseline.anchorLine = QDeclarative1AnchorLine::Baseline; } +void QDeclarativeItemPrivate::setAccessibleFlagAndListener() +{ + Q_Q(QDeclarativeItem); + QDeclarativeItem *item = q; + while (item) { + if (item->d_func()->isAccessible) + break; // already set - grandparents should have the flag set as well. + +// if (qmlEngine(item) != 0) { +// item->d_func()->addItemChangeListener(QDeclarativeEnginePrivate::getAccessibilityUpdateManager(qmlEngine(item)), +// QDeclarativeItemPrivate::Geometry | QDeclarativeItemPrivate::Visibility | +// QDeclarativeItemPrivate::Opacity | QDeclarativeItemPrivate::Destroyed); +// } + + item->d_func()->isAccessible = true; + item = item->parentItem(); + } +} + QPointF QDeclarativeItemPrivate::computeTransformOrigin() const { Q_Q(const QDeclarativeItem); diff --git a/src/qtquick1/graphicsitems/qdeclarativeitem.h b/src/qtquick1/graphicsitems/qdeclarativeitem.h index c56b59125b322b7ea9e0e4b655c74aaa337293b6..80c5e35ce4b88da3c26b7aab26c15dbd29455d26 100644 --- a/src/qtquick1/graphicsitems/qdeclarativeitem.h +++ b/src/qtquick1/graphicsitems/qdeclarativeitem.h @@ -50,6 +50,7 @@ #include <QtGui/qfont.h> #include <QtWidgets/qgraphicsitem.h> #include <QtWidgets/qgraphicstransform.h> +#include <QtGui/qaccessible.h> #include <QtWidgets/qaction.h> QT_BEGIN_HEADER @@ -198,6 +199,8 @@ protected: private: Q_DISABLE_COPY(QDeclarativeItem) Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeItem) + + friend class QDeclarativeAccessibleAttached; }; template<typename T> diff --git a/src/qtquick1/graphicsitems/qdeclarativeitem_p.h b/src/qtquick1/graphicsitems/qdeclarativeitem_p.h index 1dcafe55f418f47d6a030a21d2f8d67cb83ac149..b884c38b6ac0a22535ad34b44b62d6d40d06328b 100644 --- a/src/qtquick1/graphicsitems/qdeclarativeitem_p.h +++ b/src/qtquick1/graphicsitems/qdeclarativeitem_p.h @@ -71,6 +71,7 @@ #include <QtCore/qlist.h> #include <QtCore/qrect.h> #include <QtCore/qdebug.h> +#include <QtGui/qaccessible.h> #include <QtWidgets/private/qgraphicsitem_p.h> @@ -287,6 +288,7 @@ public: bool isMirrorImplicit:1; bool inheritMirrorFromParent:1; bool inheritMirrorFromItem:1; + bool isAccessible:1; QDeclarativeItemKeyFilter *keyHandler; @@ -298,6 +300,7 @@ public: QDeclarative1LayoutMirroringAttached* attachedLayoutDirection; bool hadSubFocusItem; + void setAccessibleFlagAndListener(); QPointF computeTransformOrigin() const; @@ -617,6 +620,7 @@ private: static const SigMap sigMap[]; }; + Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeItemPrivate::ChangeTypes); QT_END_NAMESPACE diff --git a/src/qtquick1/graphicsitems/qdeclarativeitemsmodule.cpp b/src/qtquick1/graphicsitems/qdeclarativeitemsmodule.cpp index 0a20b949b87b1ec5b0d4d428bca0221a506c009b..24ab4df4e2f212c0e933e7d4b29f355379d3f673 100644 --- a/src/qtquick1/graphicsitems/qdeclarativeitemsmodule.cpp +++ b/src/qtquick1/graphicsitems/qdeclarativeitemsmodule.cpp @@ -76,6 +76,7 @@ #include "QtQuick1/private/qdeclarativegraphicswidget_p.h" #include "QtQuick1/private/qdeclarativeanchors_p.h" #include "QtQuick1/private/qdeclarativepincharea_p.h" +#include "QtQuick1/private/qdeclarativeaccessibleattached_p.h" static QDeclarativePrivate::AutoParentResult qgraphicsobject_autoParent(QObject *obj, QObject *parent) { @@ -199,6 +200,11 @@ void QDeclarative1ItemModule::defineModule(QDeclarativeQtQuick1Module::Module mo qmlRegisterRevision<QDeclarative1ImplicitSizePaintedItem,0>("QtQuick",1,0); qmlRegisterRevision<QDeclarative1ImplicitSizePaintedItem,1>("QtQuick",1,1); qmlRegisterUncreatableType<QDeclarative1LayoutMirroringAttached>("QtQuick",1,1,"LayoutMirroring", QDeclarative1LayoutMirroringAttached::tr("LayoutMirroring is only available via attached properties")); +#ifndef QT_NO_ACCESSIBILITY + qmlRegisterUncreatableType<QDeclarativeAccessibleAttached>("QtQuick",1,0,"Accessible",QDeclarativeAccessibleAttached::tr("Accessible is only available via attached properties")); + qmlRegisterUncreatableType<QDeclarativeAccessibleAttached>("QtQuick",1,1,"Accessible",QDeclarativeAccessibleAttached::tr("Accessible is only available via attached properties")); +#endif + } else if (module == QDeclarativeQtQuick1Module::Qt47) { #ifdef QT_NO_MOVIE qmlRegisterTypeNotAvailable("Qt",4,7,"AnimatedImage", diff --git a/src/qtquick1/util/qdeclarativeview.cpp b/src/qtquick1/util/qdeclarativeview.cpp index 8581947c06aabc9534936a4874106812b2677825..55b8a772faab65359b79d05b3246f8d8304fa570 100644 --- a/src/qtquick1/util/qdeclarativeview.cpp +++ b/src/qtquick1/util/qdeclarativeview.cpp @@ -743,4 +743,10 @@ void QDeclarativeView::paintEvent(QPaintEvent *event) } +QDeclarativeItem * QDeclarativeView::accessibleRootItem() const +{ + Q_D(const QDeclarativeView); + return d->declarativeItemRoot; +} + QT_END_NAMESPACE diff --git a/src/qtquick1/util/qdeclarativeview.h b/src/qtquick1/util/qdeclarativeview.h index 4249d26980e7515d3f6ad38b0f7f9a5269c3c5f2..9780d7a4134f2d25af6356eb2653e589ba92f298 100644 --- a/src/qtquick1/util/qdeclarativeview.h +++ b/src/qtquick1/util/qdeclarativeview.h @@ -57,6 +57,7 @@ class QGraphicsObject; class QDeclarativeEngine; class QDeclarativeContext; class QDeclarativeError; +class QDeclarativeItem; QT_MODULE(Declarative) @@ -113,6 +114,9 @@ protected: private: Q_DISABLE_COPY(QDeclarativeView) Q_DECLARE_PRIVATE(QDeclarativeView) +// Accessibility support: + friend class QAccessibleDeclarativeView; + QDeclarativeItem *accessibleRootItem() const; }; QT_END_NAMESPACE diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri index 28a32fcc4810b188639797529916e804088ebf65..f02c769c3a4d93154c92578defe9e1b32567b7f4 100644 --- a/src/quick/items/items.pri +++ b/src/quick/items/items.pri @@ -1,10 +1,11 @@ HEADERS += \ $$PWD/qquickevents_p_p.h \ - $$PWD/qquickitemchangelistener_p.h \ $$PWD/qquickanchors_p.h \ $$PWD/qquickanchors_p_p.h \ + $$PWD/qquickaccessibleattached_p.h \ $$PWD/qquickitem.h \ $$PWD/qquickitem_p.h \ + $$PWD/qquickitemchangelistener_p.h \ $$PWD/qquickrectangle_p.h \ $$PWD/qquickrectangle_p_p.h \ $$PWD/qquickcanvas.h \ @@ -116,6 +117,7 @@ SOURCES += \ $$PWD/qquickspriteengine.cpp \ $$PWD/qquicksprite.cpp \ $$PWD/qquickspriteimage.cpp \ + $$PWD/qquickaccessibleattached.cpp \ $$PWD/qquickdrag.cpp \ $$PWD/qquickdroparea.cpp \ $$PWD/qquickmultipointtoucharea.cpp \ diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4fa3b87bf068ede22ff943cc458b860d048f7064 --- /dev/null +++ b/src/quick/items/qquickaccessibleattached.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickaccessibleattached_p.h" + +#ifndef QT_NO_ACCESSIBILITY + +#include "private/qquickitem_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmlclass Accessible QQuickAccessibleAttached + \inqmlmodule QtQuick 2 + \ingroup qml-basic-interaction-elements + \brief Attached property to enable accessibility of QML items. + + Items the user interacts with or that give information to the user + need to expose their information in a semantic way. + Then assistive tools can make use of that information to enable + users to interact with the application in various ways. + + This enables Qt Quick applications to be used with screen-readers for example. + + The most important properties to set are \l name and \l role. + + \sa Accessibility +*/ + +/*! + \qmlproperty string QtQuick2::Accessible::name + + This property sets an accessible name. + For a button for example, this should have a binding to its text. + In general this property should be set to a simple and concise + but human readable name. Do not include the type of control + you want to represent but just the name. +*/ + +/*! + \qmlproperty string QtQuick2::Accessible::description + + This property sets an accessible description. + Similar to the name it describes the item. The description + can be a little more verbose and tell what the item does, + for example the functionallity of the button it describes. +*/ + +/*! + \qmlproperty enumeration QtQuick2::Accessible::role + + This flags sets the semantic type of the widget. + A button for example would have "Button" as type. + The value must be one of \l QAccessible::Role . + Example: + \qml + Item { + id: myButton + Text { + id: label + // ... + } + Accessible.name: label.text + Accessible.role: Accessible.Button + } + \endqml +*/ + +QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent) + : QObject(parent) +{ + Q_ASSERT(parent); + QQuickItem *item = qobject_cast<QQuickItem*>(parent); + if (!item) + return; + + // Enable accessibility for items with accessible content. This also + // enables accessibility for the ancestors of souch items. + item->d_func()->setAccessibleFlagAndListener(); + QAccessible::updateAccessibility(item, 0, QAccessible::ObjectCreated); +} + +QQuickAccessibleAttached::~QQuickAccessibleAttached() +{ +} + +QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObject *obj) +{ + return new QQuickAccessibleAttached(obj); +} + +QT_END_NAMESPACE + +#endif diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h new file mode 100644 index 0000000000000000000000000000000000000000..184dc2116dd914157ff0c48cc2803d586969077d --- /dev/null +++ b/src/quick/items/qquickaccessibleattached_p.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKACCESSIBLEATTACHED_H +#define QQUICKACCESSIBLEATTACHED_H + +#include <QtQuick/qquickitem.h> + +#include <QtCore/qobject.h> +#include <QtCore/qstring.h> + +#ifndef QT_NO_ACCESSIBILITY + +#include <QtGui/qaccessible.h> +#include <private/qtquickglobal_p.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_QUICK_PRIVATE_EXPORT QQuickAccessibleAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(QAccessible::Role role READ role WRITE setRole NOTIFY roleChanged) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged) + +public: + Q_ENUMS(QAccessible::Role QAccessible::Event QAccessible::State) + + QQuickAccessibleAttached(QObject *parent); + ~QQuickAccessibleAttached(); + + QAccessible::Role role() const { return m_role; } + void setRole(QAccessible::Role role) + { + if (role != m_role) { + m_role = role; + emit roleChanged(); + // There is no way to signify role changes at the moment. + // QAccessible::updateAccessibility(parent(), 0, QAccessible::); + } + } + QString name() const { return m_name; } + void setName(const QString &name) { + if (name != m_name) { + m_name = name; + emit nameChanged(); + QAccessible::updateAccessibility(parent(), 0, QAccessible::NameChanged); + } + } + + QString description() const { return m_description; } + void setDescription(const QString &description) + { + if (m_description != description) { + m_description = description; + emit descriptionChanged(); + QAccessible::updateAccessibility(parent(), 0, QAccessible::DescriptionChanged); + } + } + + // Factory function + static QQuickAccessibleAttached *qmlAttachedProperties(QObject *obj); + + // Property getter + static QObject *attachedProperties(const QObject *obj) + { + return qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj, false); + } + + static QVariant property(const QObject *object, const char *propertyName) + { + if (QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object)) + return attachedObject->property(propertyName); + return QVariant(); + } + + static bool setProperty(QObject *object, const char *propertyName, const QVariant &value) + { + QObject *obj = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(object, true); + if (!obj) { + qWarning("cannot set property Accessible.%s of QObject %s", propertyName, object->metaObject()->className()); + return false; + } + return obj->setProperty(propertyName, value); + } + + +Q_SIGNALS: + void roleChanged(); + void nameChanged(); + void descriptionChanged(); +private: + QAccessible::Role m_role; + QString m_name; + QString m_description; + +public: + using QObject::property; +}; + + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickAccessibleAttached) +QML_DECLARE_TYPEINFO(QQuickAccessibleAttached, QML_HAS_ATTACHED_PROPERTIES) + +QT_END_HEADER + +#endif // QT_NO_ACCESSIBILITY + +#endif diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp index c827bfbb523aedcc230920edae7966fab73e7ef7..eab6292f22cfbfc4c9aede6aa0fe00c2b0ab67cd 100644 --- a/src/quick/items/qquickcanvas.cpp +++ b/src/quick/items/qquickcanvas.cpp @@ -116,6 +116,10 @@ private: bool m_eventSent; }; +QAccessibleInterface *QQuickCanvas::accessibleRoot() const +{ + return QAccessible::queryAccessibleInterface(const_cast<QQuickCanvas*>(this)); +} /* diff --git a/src/quick/items/qquickcanvas.h b/src/quick/items/qquickcanvas.h index d38ed97028edffc80e94df255b6d55152a955681..de82e8386e2c848f763638734d7f798f551db1c0 100644 --- a/src/quick/items/qquickcanvas.h +++ b/src/quick/items/qquickcanvas.h @@ -97,6 +97,8 @@ public: QDeclarativeIncubationController *incubationController() const; + virtual QAccessibleInterface *accessibleRoot() const; + // Scene graph specific functions QSGTexture *createTextureFromImage(const QImage &image) const; QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption(0)) const; diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index c95ae1a9c3b5305403cd9881b50c860aa9e33907..e9dc737e8a497265080bd9e212c496e3c6d652e0 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -66,6 +66,7 @@ #include <private/qlistmodelinterface_p.h> #include <private/qquickitem_p.h> #include <private/qdeclarativeaccessors_p.h> +#include <QtQuick/private/qquickaccessibleattached_p.h> #include <float.h> @@ -1603,6 +1604,22 @@ void QQuickItemPrivate::setLayoutMirror(bool mirror) } } +void QQuickItemPrivate::setAccessibleFlagAndListener() +{ + Q_Q(QQuickItem); + QQuickItem *item = q; + while (item) { + if (item->d_func()->isAccessible) + break; // already set - grandparents should have the flag set as well. + + if (item->canvas() && item->canvas()->rootItem() == item) + break; // don't add a listener to the canvas root item + + item->d_func()->isAccessible = true; + item = item->d_func()->parentItem; + } +} + /*! \class QQuickItem \brief The QQuickItem class provides the most basic of all visual items in QML. @@ -1804,6 +1821,7 @@ QQuickItem::~QQuickItem() if (change.types & QQuickItemPrivate::Destroyed) change.listener->itemDestroyed(this); } + d->changeListeners.clear(); delete d->_anchorLines; d->_anchorLines = 0; delete d->_anchors; d->_anchors = 0; @@ -1913,6 +1931,10 @@ void QQuickItem::setParentItem(QQuickItem *parentItem) d->itemChange(ItemParentHasChanged, d->parentItem); d->parentNotifier.notify(); + if (d->isAccessible && d->parentItem) { + d->parentItem->d_func()->setAccessibleFlagAndListener(); + } + emit parentChanged(d->parentItem); } @@ -2251,6 +2273,7 @@ QQuickItemPrivate::QQuickItemPrivate() inheritedLayoutMirror(false), effectiveLayoutMirror(false), isMirrorImplicit(true), inheritMirrorFromParent(false), inheritMirrorFromItem(false), childrenDoNotOverlap(false), staticSubtreeGeometry(false), + isAccessible(false), canvas(0), parentItem(0), sortedChildItems(&childItems), @@ -2886,6 +2909,11 @@ void QQuickItem::updatePolish() { } +void QQuickItem::sendAccessibilityUpdate() +{ + Q_D(QQuickItem); +} + void QQuickItemPrivate::removeItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types) { ChangeListener change(listener, types); @@ -2931,6 +2959,7 @@ void QQuickItem::inputMethodEvent(QInputMethodEvent *event) void QQuickItem::focusInEvent(QFocusEvent *) { + QAccessible::updateAccessibility(this, 0, QAccessible::Focus); } void QQuickItem::focusOutEvent(QFocusEvent *) @@ -3895,6 +3924,9 @@ void QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible) change.listener->itemVisibilityChanged(q); } + if (isAccessible) + QAccessible::updateAccessibility(q, 0, effectiveVisible ? QAccessible::ObjectShow : QAccessible::ObjectHide ); + emit q->visibleChanged(); } diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index ffc10171057dde61ed5029163df6740e24a50fde..763fc59ac4dd5537e133fa738bc434211e4b4b78 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -51,6 +51,7 @@ #include <QtCore/QList> #include <QtGui/qevent.h> #include <QtGui/qfont.h> +#include <QtGui/qaccessible.h> QT_BEGIN_HEADER @@ -393,6 +394,9 @@ protected: virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); virtual void updatePolish(); +protected Q_SLOTS: + void sendAccessibilityUpdate(); + protected: QQuickItem(QQuickItemPrivate &dd, QQuickItem *parent = 0); @@ -400,6 +404,8 @@ private: friend class QQuickCanvas; friend class QQuickCanvasPrivate; friend class QSGRenderer; + friend class QAccessibleQuickItem; + friend class QQuickAccessibleAttached; Q_DISABLE_COPY(QQuickItem) Q_DECLARE_PRIVATE(QQuickItem) }; diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 6ed4a694a7aa76ee703cd498d66c849d87a8d222..1a23ab17324c2b5c61c662480a7f419f12b82ede 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -280,6 +280,7 @@ public: bool inheritMirrorFromItem:1; bool childrenDoNotOverlap:1; bool staticSubtreeGeometry:1; + bool isAccessible:1; QQuickCanvas *canvas; QSGContext *sceneGraphContext() const { Q_ASSERT(canvas); return static_cast<QQuickCanvasPrivate *>(QObjectPrivate::get(canvas))->context; } @@ -337,6 +338,8 @@ public: Qt::MouseButtons acceptedMouseButtons; Qt::InputMethodHints imHints; + void setAccessibleFlagAndListener(); + QPointF transformOriginPoint; virtual qreal getImplicitWidth() const; diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 69b9caf940b3b38aad0a32a44e05301eebf80a3e..b5eb611e78485f5dd2d1190abe768e28c6c72956 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -82,6 +82,7 @@ #include "qquickdroparea_p.h" #include "qquickmultipointtoucharea_p.h" #include <private/qdeclarativemetatype_p.h> +#include <QtQuick/private/qquickaccessibleattached_p.h> static QDeclarativePrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject *parent) { @@ -215,6 +216,10 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickMultiPointTouchArea>("QtQuick", 2, 0, "MultiPointTouchArea"); qmlRegisterType<QQuickTouchPoint>("QtQuick", 2, 0, "TouchPoint"); qmlRegisterType<QQuickGrabGestureEvent>(); + +#ifndef QT_NO_ACCESSIBILITY + qmlRegisterUncreatableType<QQuickAccessibleAttached>("QtQuick", 2, 0, "Accessible",QQuickAccessibleAttached::tr("Accessible is only available via attached properties")); +#endif } void QQuickItemsModule::defineModule() diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 2a6be05851698089ff63abfa37342a4e2ff129f6..5072bf1a58b29a0a1ad01ea8aabca7582ed78190 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -1920,6 +1920,9 @@ void QQuickText::componentComplete() QQuickItem::componentComplete(); if (d->updateOnComponentComplete) d->updateLayout(); + + // Enable accessibility for text items. + d->setAccessibleFlagAndListener(); } diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index 6780a87f55bd175f73b4ce4457f4b1dd3fa73eec..f5ff636f254bb5bc70c46e1e2f863e5aa41bfa1c 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -27,6 +27,7 @@ PUBLICTESTS += \ qmlplugindump PRIVATETESTS += \ + qdeclarativeaccessibility \ qdeclarativebinding \ qdeclarativechangeset \ qdeclarativeconnection \ diff --git a/tests/auto/declarative/qdeclarativeaccessibility/data/pushbutton.qml b/tests/auto/declarative/qdeclarativeaccessibility/data/pushbutton.qml new file mode 100644 index 0000000000000000000000000000000000000000..df19231703bd03e11ace0fb6bbb04c34032288f2 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeaccessibility/data/pushbutton.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +Rectangle { + Accessible.role : Accessible.Button + property string text : "test" + + Text { + anchors.fill : parent + text : parent.text + } + + MouseArea { + anchors.fill : parent + } +} diff --git a/tests/auto/declarative/qdeclarativeaccessibility/data/statictext.qml b/tests/auto/declarative/qdeclarativeaccessibility/data/statictext.qml new file mode 100644 index 0000000000000000000000000000000000000000..a0821cfc4d79030a8fbce15067af20bc0b434ed3 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeaccessibility/data/statictext.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +Item { + width: 400 + height: 400 + + Text { + x: 100 + y: 20 + width: 200 + height: 50 + text : "Hello Accessibility" + } + + Text { + x: 100 + y: 40 + width: 100 + height: 40 + text : "Hello 2" + Accessible.role: Accessible.StaticText + Accessible.name: "The Hello 2 accessible text" + Accessible.description: "A text description" + } +} diff --git a/tests/auto/declarative/qdeclarativeaccessibility/qdeclarativeaccessibility.pro b/tests/auto/declarative/qdeclarativeaccessibility/qdeclarativeaccessibility.pro new file mode 100644 index 0000000000000000000000000000000000000000..8b5165687b66d00149c318d73d693308e31d3d41 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeaccessibility/qdeclarativeaccessibility.pro @@ -0,0 +1,32 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative-private gui network qtquick1-private +macx:CONFIG -= app_bundle + +HEADERS += ../../shared/util.h + +SOURCES += tst_qdeclarativeaccessibility.cpp \ + ../../shared/util.cpp + + +OTHER_FILES += data/pushbutton.qml +OTHER_FILES += data/statictext.qml + +symbian: { + importFiles.files = data + importFiles.path = . + DEPLOYMENT += importFiles +} else { + DEFINES += SRCDIR=\\\"$$PWD\\\" +} + +CONFIG += parallel_test + +wince*: { + accessneeded.files = $$QT_BUILD_TREE\\plugins\\accessible\\*.dll + accessneeded.path = accessible + DEPLOYMENT += accessneeded +} + + + + diff --git a/tests/auto/declarative/qdeclarativeaccessibility/tst_qdeclarativeaccessibility.cpp b/tests/auto/declarative/qdeclarativeaccessibility/tst_qdeclarativeaccessibility.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c34daa4c0771e3715b722e17d552da16a3fe2a8 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeaccessibility/tst_qdeclarativeaccessibility.cpp @@ -0,0 +1,497 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include "QtTest/qtestaccessible.h" + +#include <QtGui/qaccessible.h> + +#include <QtQuick1/qdeclarativeview.h> +#include <QtQuick/qquickview.h> +#include <QtQuick/qquickitem.h> + +#include <QtDeclarative/qdeclarativeengine.h> +#include <QtDeclarative/qdeclarativeproperty.h> +#include <private/qdeclarativeaccessibleattached_p.h> + +#include "../../shared/util.h" + + +typedef QSharedPointer<QAccessibleInterface> QAI; + + +static inline bool verifyChild(QWidget *child, QAccessibleInterface *iface, + int index, const QRect &domain) +{ + if (!child) { + qWarning("tst_QAccessibility::verifyChild: null pointer to child."); + return false; + } + + if (!iface) { + qWarning("tst_QAccessibility::verifyChild: null pointer to interface."); + return false; + } + + // Verify that we get a valid QAccessibleInterface for the child. + QAccessibleInterface *childInterface = QAccessible::queryAccessibleInterface(child); + if (!childInterface) { + qWarning("tst_QAccessibility::verifyChild: Failed to retrieve interface for child."); + return false; + } + + // QAccessibleInterface::indexOfChild(): + // Verify that indexOfChild() returns an index equal to the index passed in + int indexFromIndexOfChild = iface->indexOfChild(childInterface); + delete childInterface; + if (indexFromIndexOfChild != index) { + qWarning("tst_QAccessibility::verifyChild (indexOfChild()):"); + qWarning() << "Expected:" << index; + qWarning() << "Actual: " << indexFromIndexOfChild; + return false; + } + + // Navigate to child, compare its object and role with the interface from queryAccessibleInterface(child). + QAccessibleInterface *navigatedChildInterface = iface->child(index - 1); + if (navigatedChildInterface == 0) + return false; + + const QRect rectFromInterface = navigatedChildInterface->rect(); + delete navigatedChildInterface; + + // QAccessibleInterface::childAt(): + // Calculate global child position and check that the interface + // returns the correct index for that position. + QPoint globalChildPos = child->mapToGlobal(QPoint(0, 0)); + QAccessibleInterface *childAtInterface = iface->childAt(globalChildPos.x(), globalChildPos.y()); + if (!childAtInterface) { + qWarning("tst_QAccessibility::verifyChild (childAt()):"); + qWarning() << "Expected:" << childInterface; + qWarning() << "Actual: no child"; + return false; + } + if (childAtInterface->object() != childInterface->object()) { + qWarning("tst_QAccessibility::verifyChild (childAt()):"); + qWarning() << "Expected:" << childInterface; + qWarning() << "Actual: " << childAtInterface; + return false; + } + delete childInterface; + delete childAtInterface; + + // Verify that the child is within its domain. + if (!domain.contains(rectFromInterface)) { + qWarning("tst_QAccessibility::verifyChild: Child is not within its domain."); + return false; + } + + return true; +} + +static inline int indexOfChild(QAccessibleInterface *parentInterface, QWidget *childWidget) +{ + if (!parentInterface || !childWidget) + return -1; + QAccessibleInterface *childInterface = QAccessible::queryAccessibleInterface(childWidget); + if (!childInterface) + return -1; + int index = parentInterface->indexOfChild(childInterface); + delete childInterface; + return index; +} + +#define EXPECT(cond) \ + do { \ + if (!errorAt && !(cond)) { \ + errorAt = __LINE__; \ + qWarning("level: %d, middle: %d, role: %d (%s)", treelevel, middle, iface->role(), #cond); \ + } \ + } while (0) + +static int verifyHierarchy(QAccessibleInterface *iface) +{ + int errorAt = 0; + static int treelevel = 0; // for error diagnostics + QAccessibleInterface *middleChild, *if2; + middleChild = 0; + ++treelevel; + int middle = iface->childCount()/2 + 1; + if (iface->childCount() >= 2) { + middleChild = iface->child(middle - 1); + } + for (int i = 0; i < iface->childCount() && !errorAt; ++i) { + if2 = iface->child(i); + EXPECT(if2 != 0); + // navigate Ancestor... + QAccessibleInterface *parent = if2->parent(); + EXPECT(iface->object() == parent->object()); + delete parent; + + // navigate Sibling... +// if (middleChild) { +// entry = if2->navigate(QAccessible::Sibling, middle, &if3); +// EXPECT(entry == 0 && if3->object() == middleChild->object()); +// if (entry == 0) +// delete if3; +// EXPECT(iface->indexOfChild(middleChild) == middle); +// } + + // verify children... + if (!errorAt) + errorAt = verifyHierarchy(if2); + delete if2; + } + delete middleChild; + + --treelevel; + return errorAt; +} + + +//TESTED_FILES= + +class tst_QDeclarativeAccessibility : public QDeclarativeDataTest +{ + Q_OBJECT +public: + tst_QDeclarativeAccessibility(); + virtual ~tst_QDeclarativeAccessibility(); + +private slots: + void commonTests_data(); + void commonTests(); + + void declarativeAttachedProperties(); + void basicPropertiesTest(); + void hitTest(); +}; + +tst_QDeclarativeAccessibility::tst_QDeclarativeAccessibility() +{ + +} + +tst_QDeclarativeAccessibility::~tst_QDeclarativeAccessibility() +{ + +} + +void tst_QDeclarativeAccessibility::commonTests_data() +{ + QTest::addColumn<QString>("accessibleRoleFileName"); + + QTest::newRow("StaticText") << SRCDIR "/data/statictext.qml"; + QTest::newRow("PushButton") << SRCDIR "/data/pushbutton.qml"; +} + +void tst_QDeclarativeAccessibility::commonTests() +{ + QFETCH(QString, accessibleRoleFileName); + + qDebug() << "testing" << accessibleRoleFileName; + + QQuickView *view = new QQuickView(); +// view->setFixedSize(240,320); + view->setSource(QUrl::fromLocalFile(accessibleRoleFileName)); + view->show(); +// view->setFocus(); + QVERIFY(view->rootObject() != 0); + + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(view); + QVERIFY(iface); + + delete iface; + delete view; +} + + + +QString eventName(const int ev) +{ + switch (ev) { + case 0x0001: return "SoundPlayed"; + case 0x0002: return "Alert"; + case 0x0003: return "ForegroundChanged"; + case 0x0004: return "MenuStart"; + case 0x0005: return "MenuEnd"; + case 0x0006: return "PopupMenuStart"; + case 0x0007: return "PopupMenuEnd"; + case 0x000C: return "ContextHelpStart"; + case 0x000D: return "ContextHelpEnd"; + case 0x000E: return "DragDropStart"; + case 0x000F: return "DragDropEnd"; + case 0x0010: return "DialogStart"; + case 0x0011: return "DialogEnd"; + case 0x0012: return "ScrollingStart"; + case 0x0013: return "ScrollingEnd"; + case 0x0018: return "MenuCommand"; + case 0x8000: return "ObjectCreated"; + case 0x8001: return "ObjectDestroyed"; + case 0x8002: return "ObjectShow"; + case 0x8003: return "ObjectHide"; + case 0x8004: return "ObjectReorder"; + case 0x8005: return "Focus"; + case 0x8006: return "Selection"; + case 0x8007: return "SelectionAdd"; + case 0x8008: return "SelectionRemove"; + case 0x8009: return "SelectionWithin"; + case 0x800A: return "StateChanged"; + case 0x800B: return "LocationChanged"; + case 0x800C: return "NameChanged"; + case 0x800D: return "DescriptionChanged"; + case 0x800E: return "ValueChanged"; + case 0x800F: return "ParentChanged"; + case 0x80A0: return "HelpChanged"; + case 0x80B0: return "DefaultActionChanged"; + case 0x80C0: return "AcceleratorChanged"; + default: return "Unknown Event"; + } +} + +static QString stateNames(int state) +{ + QString stateString; + if (state == 0x00000000) stateString += " Normal"; + if (state & 0x00000001) stateString += " Unavailable"; + if (state & 0x00000002) stateString += " Selected"; + if (state & 0x00000004) stateString += " Focused"; + if (state & 0x00000008) stateString += " Pressed"; + if (state & 0x00000010) stateString += " Checked"; + if (state & 0x00000020) stateString += " Mixed"; + if (state & 0x00000040) stateString += " ReadOnly"; + if (state & 0x00000080) stateString += " HotTracked"; + if (state & 0x00000100) stateString += " DefaultButton"; + if (state & 0x00000200) stateString += " Expanded"; + if (state & 0x00000400) stateString += " Collapsed"; + if (state & 0x00000800) stateString += " Busy"; + if (state & 0x00001000) stateString += " Floating"; + if (state & 0x00002000) stateString += " Marqueed"; + if (state & 0x00004000) stateString += " Animated"; + if (state & 0x00008000) stateString += " Invisible"; + if (state & 0x00010000) stateString += " Offscreen"; + if (state & 0x00020000) stateString += " Sizeable"; + if (state & 0x00040000) stateString += " Moveable"; + if (state & 0x00080000) stateString += " SelfVoicing"; + if (state & 0x00100000) stateString += " Focusable"; + if (state & 0x00200000) stateString += " Selectable"; + if (state & 0x00400000) stateString += " Linked"; + if (state & 0x00800000) stateString += " Traversed"; + if (state & 0x01000000) stateString += " MultiSelectable"; + if (state & 0x02000000) stateString += " ExtSelectable"; + if (state & 0x04000000) stateString += " AlertLow"; + if (state & 0x08000000) stateString += " AlertMedium"; + if (state & 0x10000000) stateString += " AlertHigh"; + if (state & 0x20000000) stateString += " Protected"; + if (state & 0x3fffffff) stateString += " Valid"; + + if (stateString.isEmpty()) + stateString = "Unknown state " + QString::number(state); + + return stateString; +} + +void tst_QDeclarativeAccessibility::declarativeAttachedProperties() +{ + { + QDeclarativeEngine engine; + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 1.1\nItem {\n" + "}", QUrl()); + QObject *object = component.create(); + QVERIFY(object != 0); + + QObject *attachedObject = QDeclarativeAccessibleAttached::attachedProperties(object); + QCOMPARE(attachedObject, static_cast<QObject*>(0)); + delete object; + } + + // Attached property + { + QObject parent; + QDeclarativeAccessibleAttached *attachedObj = new QDeclarativeAccessibleAttached(&parent); + + attachedObj->name(); + + QVariant pp = attachedObj->property("name"); + QDeclarativeEngine engine; + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 1.1\nItem {\n" + "Accessible.role: Accessible.Button\n" + "}", QUrl()); + QObject *object = component.create(); + QVERIFY(object != 0); + + QObject *attachedObject = QDeclarativeAccessibleAttached::attachedProperties(object); + QVERIFY(attachedObject); + if (attachedObject) { + QVariant p = attachedObject->property("role"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toInt(), int(QAccessible::PushButton)); + p = attachedObject->property("name"); + QCOMPARE(p.isNull(), true); + p = attachedObject->property("description"); + QCOMPARE(p.isNull(), true); + } + delete object; + } + + // Attached property + { + QDeclarativeEngine engine; + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 1.1\nItem {\n" + "Accessible.role: Accessible.Button\n" + "Accessible.name: \"Donald\"\n" + "Accessible.description: \"Duck\"\n" + "}", QUrl()); + QObject *object = component.create(); + QVERIFY(object != 0); + + QObject *attachedObject = QDeclarativeAccessibleAttached::attachedProperties(object); + QVERIFY(attachedObject); + if (attachedObject) { + QVariant p = attachedObject->property("role"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toInt(), int(QAccessible::PushButton)); + p = attachedObject->property("name"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("Donald")); + p = attachedObject->property("description"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("Duck")); + } + delete object; + } +} + + +void tst_QDeclarativeAccessibility::basicPropertiesTest() +{ + QAI app = QAI(QAccessible::queryAccessibleInterface(qApp)); + QCOMPARE(app->childCount(), 0); + + QQuickView *canvas = new QQuickView(); + canvas->setSource(testFileUrl("statictext.qml")); + canvas->show(); + QCOMPARE(app->childCount(), 1); + + QAI iface = QAI(QAccessible::queryAccessibleInterface(canvas)); + QVERIFY(iface.data()); + QCOMPARE(iface->childCount(), 1); + + QAI item = QAI(iface->child(0)); + QVERIFY(item.data()); + QCOMPARE(item->childCount(), 2); + QCOMPARE(item->rect().size(), QSize(400, 400)); + QCOMPARE(item->role(), QAccessible::Pane); + + QAI text = QAI(item->child(0)); + QVERIFY(text.data()); + QCOMPARE(text->childCount(), 0); + + QCOMPARE(text->text(QAccessible::Name), QLatin1String("Hello Accessibility")); + QCOMPARE(text->rect().size(), QSize(200, 50)); + QCOMPARE(text->rect().x(), item->rect().x() + 100); + QCOMPARE(text->rect().y(), item->rect().y() + 20); + QCOMPARE(text->role(), QAccessible::StaticText); + + QAI text2 = QAI(item->child(1)); + QVERIFY(text2.data()); + QCOMPARE(text2->childCount(), 0); + + QCOMPARE(text2->text(QAccessible::Name), QLatin1String("The Hello 2 accessible text")); + QCOMPARE(text2->rect().size(), QSize(100, 40)); + QCOMPARE(text2->rect().x(), item->rect().x() + 100); + QCOMPARE(text2->rect().y(), item->rect().y() + 40); + QCOMPARE(text2->role(), QAccessible::StaticText); + + delete canvas; +} + +QAI topLevelChildAt(QAccessibleInterface *iface, int x, int y) +{ + QAI child = QAI(iface->childAt(x, y)); + if (!child) + return QAI(); + + QAI childOfChild; + while (childOfChild = QAI(child->childAt(x, y))) { + child = childOfChild; + } + return child; +} + +void tst_QDeclarativeAccessibility::hitTest() +{ + QQuickView *canvas = new QQuickView(); + canvas->setSource(testFileUrl("statictext.qml")); + canvas->show(); + + QAI iface = QAI(QAccessible::queryAccessibleInterface(canvas)); + QVERIFY(iface.data()); + QAI item = QAI(iface->child(0)); + QRect itemRect = item->rect(); + + // hit the root item + QAI itemHit = QAI(iface->childAt(itemRect.x() + 5, itemRect.y() + 5)); + QVERIFY(itemHit); + QCOMPARE(itemRect, itemHit->rect()); + + // hit a text element + QAI textChild = QAI(item->child(0)); + QAI textChildHit = topLevelChildAt(iface.data(), itemRect.x() + 105, itemRect.y() + 25); + QVERIFY(textChildHit); + QCOMPARE(textChild->rect(), textChildHit->rect()); + QCOMPARE(textChildHit->text(QAccessible::Name), QLatin1String("Hello Accessibility")); + + // should also work from top level (app) + QAI app = QAI(QAccessible::queryAccessibleInterface(qApp)); + QAI textChildHit2 = topLevelChildAt(app.data(), itemRect.x() + 105, itemRect.y() + 25); + QVERIFY(textChildHit2); + QCOMPARE(textChild->rect(), textChildHit2->rect()); + QCOMPARE(textChildHit2->text(QAccessible::Name), QLatin1String("Hello Accessibility")); + + delete canvas; +} +QTEST_MAIN(tst_QDeclarativeAccessibility) + +#include "tst_qdeclarativeaccessibility.moc" diff --git a/tests/manual/accessibility/animation.qml b/tests/manual/accessibility/animation.qml new file mode 100644 index 0000000000000000000000000000000000000000..21e0072466a1037258b08d10d7da2559a45cf6d4 --- /dev/null +++ b/tests/manual/accessibility/animation.qml @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: scene + width: 800; height: 600 + + Rectangle { + id: behavior + x : 50 + y : 100 + width: 100; height: 100 + color: "red" + + Text { + text : "Behavior" + } + + Behavior on x { + NumberAnimation { duration: 1000 } + } + + MouseArea { + anchors.fill: parent + onClicked: behavior.x += 50 + } + } + + Rectangle { + id: transition + x : 400 + y : 100 + width: 100; height: 100 + color: "red" + + MouseArea { + id: mouseArea + anchors.fill: parent + } + + Text { + text : "Transition" + } + + states: State { + name: "moved"; when: mouseArea.pressed + PropertyChanges { target: transition; x: 500; y: 200 } + } + + transitions: Transition { + NumberAnimation { properties: "x,y"; easing.type: Easing.InOutQuad; duration: 1000 } + } + } + + Rectangle { + id : animatee + width: 100; height: 100 + x : 50 + y : 300 + color: "blue" + opacity: 0.5 + Text { + anchors.centerIn: parent + text : "NumberAnimation" + } + + MouseArea { + anchors.fill: parent + onClicked: { + animatePosition.start() + } + } + + NumberAnimation { + id: animatePosition + target: animatee + properties: "x" + from: animatee.x + to: animatee.x + 50 + loops: 1 + easing {type: Easing.Linear;} + } + } + + ListView { + id : content + x : 400 + y : 300 + width: 300 + height: 200 + + model : 200 + delegate : Text { text : "Flickable" + index; height : 50 } + } +} diff --git a/tests/manual/accessibility/behavior.qml b/tests/manual/accessibility/behavior.qml new file mode 100644 index 0000000000000000000000000000000000000000..889b88029b575a143fe4d0518b1629a0690170e3 --- /dev/null +++ b/tests/manual/accessibility/behavior.qml @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: scene + width: 400; height: 400 + + Rectangle { + id: rect + y : 100 + width: 100; height: 100 + color: "red" + + Text { + text : "Behavior animation" + } + + Behavior on x { + NumberAnimation { duration: 1000 } + } + + MouseArea { + anchors.fill: parent + onClicked: rect.x += 50 + } + } + } diff --git a/tests/manual/accessibility/flickable.qml b/tests/manual/accessibility/flickable.qml new file mode 100644 index 0000000000000000000000000000000000000000..741777a18c6bd547220395713e876579e99b17c3 --- /dev/null +++ b/tests/manual/accessibility/flickable.qml @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + + + ListView { + id : content + width: 300 + height: 200 +// KeyNavigation.up: gridMenu; KeyNavigation.left: contextMenu; KeyNavigation.right: list2 + + model : 200 + delegate : Text { text : "foo" + index; height : 50 } + } diff --git a/tests/manual/accessibility/hittest.qml b/tests/manual/accessibility/hittest.qml new file mode 100644 index 0000000000000000000000000000000000000000..522ed649b3dd0835b216eb354c43e164873fee30 --- /dev/null +++ b/tests/manual/accessibility/hittest.qml @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +import QtQuick 2.0 +Rectangle { + id: page + width: 640 + height: 480 + color: "white" + Rectangle { + id: header + color: "#c0c0c0" + height: usage.height + chkClip.height + anchors.left: parent.left + anchors.right: parent.right + Text { + id: usage + text: "Use an a11y inspect tool to see if all visible rectangles can be found with hit testing." + } + Rectangle { + id: chkClip + property bool checked: true + + color: (checked ? "#f0f0f0" : "#c0c0c0") + height: label.height + width: label.width + anchors.left: parent.left + anchors.bottom: parent.bottom + + MouseArea { + anchors.fill: parent + onClicked: chkClip.checked = !chkClip.checked + } + Text { + id: label + text: "Click here to toggle clipping" + } + } + } + Rectangle { + clip: chkClip.checked + z: 2 + Accessible.role: Accessible.Button + id: rect1 + width: 100 + height: 100 + color: "#ffc0c0" + anchors.top: header.bottom + Rectangle { + id: rect2 + width: 100 + height: 100 + x: 50 + y: 50 + color: "#ffa0a0" + Rectangle { + id: rect31 + width: 100 + height: 100 + x: 80 + y: 80 + color: "#ff8080" + } + Rectangle { + id: rect32 + x: 100 + y: 70 + z: 3 + width: 100 + height: 100 + color: "#e06060" + } + Rectangle { + id: rect33 + width: 100 + height: 100 + x: 150 + y: 60 + color: "#c04040" + } + } + } + + Rectangle { + x: 0 + y: 50 + id: recta1 + width: 100 + height: 100 + color: "#c0c0ff" + Rectangle { + id: recta2 + width: 100 + height: 100 + x: 50 + y: 50 + color: "#a0a0ff" + Rectangle { + id: recta31 + width: 100 + height: 100 + x: 80 + y: 80 + color: "#8080ff" + } + Rectangle { + id: recta32 + x: 100 + y: 70 + z: 100 + width: 100 + height: 100 + color: "#6060e0" + } + Rectangle { + id: recta33 + width: 100 + height: 100 + x: 150 + y: 60 + color: "#4040c0" + } + } + } + +} diff --git a/tests/manual/accessibility/numberanimation.qml b/tests/manual/accessibility/numberanimation.qml new file mode 100644 index 0000000000000000000000000000000000000000..425491bcd565a4368df6e8374535e26abfd7afc4 --- /dev/null +++ b/tests/manual/accessibility/numberanimation.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: flashingblob + width: 300; height: 300 + + MouseArea { + anchors.fill: parent + onClicked: { + animatePosition.start() + } + } + + Rectangle { + id : animatee + width: 100; height: 100 + y : 100 + color: "blue" + opacity: 0.5 + Text { + anchors.centerIn: parent + text : "Be Well" + } + } + + NumberAnimation { + id: animatePosition + target: animatee + properties: "x" + from: animatee.x + to: animatee.x + 50 + loops: 1 + easing {type: Easing.Linear;} + } +} diff --git a/tests/manual/accessibility/qmltestfiles.qmlproject b/tests/manual/accessibility/qmltestfiles.qmlproject new file mode 100644 index 0000000000000000000000000000000000000000..9062c6a412588e40ed5c04f09ce4ef18d0a358c3 --- /dev/null +++ b/tests/manual/accessibility/qmltestfiles.qmlproject @@ -0,0 +1,16 @@ +import QmlProject 1.0 + +Project { + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "." + } + JavaScriptFiles { + directory: "." + } + ImageFiles { + directory: "." + } + /* List of plugin directories passed to QML runtime */ + // importPaths: [ "../exampleplugin" ] +} diff --git a/tests/manual/accessibility/textandbuttons.qml b/tests/manual/accessibility/textandbuttons.qml new file mode 100644 index 0000000000000000000000000000000000000000..c646275815fd59b12d4407db18f9ba1117e202d6 --- /dev/null +++ b/tests/manual/accessibility/textandbuttons.qml @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id : rect + width: 300 + height: 200 + + Rectangle { + width : 200 + height : 20 + + id: button + anchors.top : rect.top + anchors.topMargin: 30 + property string text : "Click to activate" + property int counter : 0 + + Accessible.role : Accessible.Button + + function accessibleAction(action) { + if (action == Qt.Press) + buttonAction() + } + + function buttonAction() { + ++counter + text = "clicked " + counter + + text2.x += 20 + } + + Text { + id : text1 + anchors.fill: parent + text : parent.text + } + + MouseArea { + id : mouseArea + anchors.fill: parent + onClicked: parent.buttonAction() + } + } + + Text { + id : text2 + anchors.top: button.bottom + anchors.topMargin: 50 + text : "Hello World " + x + + Behavior on x { PropertyAnimation { duration: 500 } } + } +} diff --git a/tests/manual/accessibility/transition.qml b/tests/manual/accessibility/transition.qml new file mode 100644 index 0000000000000000000000000000000000000000..640b00663eca1bf81f74402ef237e7a120db3c80 --- /dev/null +++ b/tests/manual/accessibility/transition.qml @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: scene + width: 300; height: 300 + + Rectangle { + id: rect + x : 100 + y : 100 + width: 100; height: 100 + color: "red" + + MouseArea { + id: mouseArea + anchors.fill: parent + } + + Text { + text : "Transition" + } + + states: State { + name: "moved"; when: mouseArea.pressed + PropertyChanges { target: rect; x: 150; y: 150 } + } + + transitions: Transition { + NumberAnimation { properties: "x,y"; easing.type: Easing.InOutQuad; duration: 1000 } + } + } +}