aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Arve Sæther <jan-arve.saether@qt.io>2021-01-14 18:46:17 +0100
committerJan Arve Sæther <jan-arve.saether@qt.io>2021-01-29 11:05:52 +0100
commit4b1acb290dc8869d0d2d1250dc1ed415d6b6e202 (patch)
treeb542f3cd93d6ea07b0843c853bd38c2498ba4724
parentf9813dfa243d109dd027a40b5ca505fdee79e877 (diff)
a11y: Fix ordering on header, content item and footer in Page
Because of the previous behavior, the footer could be read aloud by the screen reader before the content item. And even worse, the footer could be read aloud even before the header in some cases. This made it hard for visually impaired people to use the application. The Page type was used by the Dialog type, so it also affected that. Fixes: QTBUG-75042 Pick-to: 5.15 6.0 Change-Id: Ic3e8ec3f7dcf18af9262b1d35c986835c8da6900 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r--src/imports/templates/qtquicktemplates2plugin.cpp3
-rw-r--r--src/quicktemplates2/CMakeLists.txt3
-rw-r--r--src/quicktemplates2/accessible/accessible.pri4
-rw-r--r--src/quicktemplates2/accessible/qaccessiblequickpage.cpp81
-rw-r--r--src/quicktemplates2/accessible/qaccessiblequickpage_p.h70
-rw-r--r--src/quicktemplates2/qtquicktemplates2global.cpp63
-rw-r--r--src/quicktemplates2/qtquicktemplates2global_p.h4
-rw-r--r--src/quicktemplates2/quicktemplates2.pro4
-rw-r--r--tests/auto/accessibility/accessibility.pro4
-rw-r--r--tests/auto/accessibility/data/ordering/page.qml23
-rw-r--r--tests/auto/accessibility/tst_accessibility.cpp30
11 files changed, 286 insertions, 3 deletions
diff --git a/src/imports/templates/qtquicktemplates2plugin.cpp b/src/imports/templates/qtquicktemplates2plugin.cpp
index e2a15213..732cb3f8 100644
--- a/src/imports/templates/qtquicktemplates2plugin.cpp
+++ b/src/imports/templates/qtquicktemplates2plugin.cpp
@@ -71,7 +71,10 @@ QtQuickTemplates2Plugin::QtQuickTemplates2Plugin(QObject *parent)
: QQmlExtensionPlugin(parent), registered(false)
{
volatile auto registration = &qml_register_types_QtQuick_Templates;
+ volatile auto initialization = &QQuickTemplates_initializeModule;
+
Q_UNUSED(registration)
+ Q_UNUSED(initialization)
}
QtQuickTemplates2Plugin::~QtQuickTemplates2Plugin()
diff --git a/src/quicktemplates2/CMakeLists.txt b/src/quicktemplates2/CMakeLists.txt
index ff9fdb5c..1493c52b 100644
--- a/src/quicktemplates2/CMakeLists.txt
+++ b/src/quicktemplates2/CMakeLists.txt
@@ -7,6 +7,7 @@
qt_internal_add_module(QuickTemplates2
GENERATE_METATYPES
SOURCES
+ accessible/qaccessiblequickpage.cpp accessible/qaccessiblequickpage_p.h
qquickabstractbutton.cpp qquickabstractbutton_p.h
qquickabstractbutton_p_p.h
qquickaction.cpp qquickaction_p.h
@@ -112,7 +113,7 @@ qt_internal_add_module(QuickTemplates2
qquicktooltip.cpp qquicktooltip_p.h
qquickvelocitycalculator.cpp
qquickvelocitycalculator_p_p.h
- qtquicktemplates2global_p.h
+ qtquicktemplates2global.cpp qtquicktemplates2global_p.h
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
diff --git a/src/quicktemplates2/accessible/accessible.pri b/src/quicktemplates2/accessible/accessible.pri
new file mode 100644
index 00000000..0c855d34
--- /dev/null
+++ b/src/quicktemplates2/accessible/accessible.pri
@@ -0,0 +1,4 @@
+HEADERS += \
+ $$PWD/qaccessiblequickpage_p.h \
+SOURCES += \
+ $$PWD/qaccessiblequickpage.cpp \
diff --git a/src/quicktemplates2/accessible/qaccessiblequickpage.cpp b/src/quicktemplates2/accessible/qaccessiblequickpage.cpp
new file mode 100644
index 00000000..90ac49f9
--- /dev/null
+++ b/src/quicktemplates2/accessible/qaccessiblequickpage.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaccessiblequickpage_p.h"
+#include "qquickpage_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QAccessibleQuickPage::QAccessibleQuickPage(QQuickPage *page)
+ : QAccessibleQuickItem(page)
+{
+}
+
+QAccessibleInterface *QAccessibleQuickPage::child(int index) const
+{
+ const QList<QQuickItem*> kids = orderedChildItems();
+ if (QQuickItem *item = kids.value(index))
+ return QAccessible::queryAccessibleInterface(item);
+ return nullptr;
+}
+
+int QAccessibleQuickPage::indexOfChild(const QAccessibleInterface *iface) const
+{
+ const QList<QQuickItem*> kids = orderedChildItems();
+ return (int)kids.indexOf(static_cast<QQuickItem*>(iface->object()));
+}
+
+QList<QQuickItem *> QAccessibleQuickPage::orderedChildItems() const
+{
+ // Just ensures that the header is first, and footer is last. Other existing order is kept.
+ const QQuickPage *p = page();
+ QList<QQuickItem*> kids = childItems();
+ const qsizetype hidx = kids.indexOf(p->header());
+ if (hidx != -1)
+ kids.move(hidx, 0);
+ const qsizetype fidx = kids.indexOf(p->footer());
+ if (fidx != -1)
+ kids.move(fidx, kids.count() - 1);
+ return kids;
+}
+
+QQuickPage *QAccessibleQuickPage::page() const
+{
+ return static_cast<QQuickPage*>(object());
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/quicktemplates2/accessible/qaccessiblequickpage_p.h b/src/quicktemplates2/accessible/qaccessiblequickpage_p.h
new file mode 100644
index 00000000..9b208c14
--- /dev/null
+++ b/src/quicktemplates2/accessible/qaccessiblequickpage_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QACCESSIBLEQUICKPAGE_H
+#define QACCESSIBLEQUICKPAGE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qaccessiblequickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPage;
+
+class QAccessibleQuickPage : public QAccessibleQuickItem
+{
+public:
+ QAccessibleQuickPage(QQuickPage *page);
+ QAccessibleInterface *child(int index) const override;
+ int indexOfChild(const QAccessibleInterface *iface) const override;
+private:
+ QQuickPage *page() const;
+ QList<QQuickItem *> orderedChildItems() const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QACCESSIBLEQUICKPAGE_H
diff --git a/src/quicktemplates2/qtquicktemplates2global.cpp b/src/quicktemplates2/qtquicktemplates2global.cpp
new file mode 100644
index 00000000..9b79d60c
--- /dev/null
+++ b/src/quicktemplates2/qtquicktemplates2global.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qquickpage_p.h"
+#include "accessible/qaccessiblequickpage_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#if QT_CONFIG(accessibility)
+QAccessibleInterface *qQuickAccessibleFactory(const QString &classname, QObject *object)
+{
+ if (classname == u"QQuickPage") {
+ return new QAccessibleQuickPage(qobject_cast<QQuickPage *>(object));
+ }
+ return nullptr;
+}
+#endif
+
+void QQuickTemplates_initializeModule()
+{
+#if QT_CONFIG(accessibility)
+ QAccessible::installFactory(&qQuickAccessibleFactory);
+#endif
+}
+
+Q_CONSTRUCTOR_FUNCTION(QQuickTemplates_initializeModule)
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qtquicktemplates2global_p.h b/src/quicktemplates2/qtquicktemplates2global_p.h
index 37d81888..db848229 100644
--- a/src/quicktemplates2/qtquicktemplates2global_p.h
+++ b/src/quicktemplates2/qtquicktemplates2global_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
@@ -64,6 +64,8 @@ QT_BEGIN_NAMESPACE
# define Q_QUICKTEMPLATES2_PRIVATE_EXPORT
#endif
+Q_QUICKTEMPLATES2_PRIVATE_EXPORT void QQuickTemplates_initializeModule();
+
QT_END_NAMESPACE
Q_QUICKTEMPLATES2_PRIVATE_EXPORT void qml_register_types_QtQuick_Templates();
diff --git a/src/quicktemplates2/quicktemplates2.pro b/src/quicktemplates2/quicktemplates2.pro
index 06fa0ee7..890845a5 100644
--- a/src/quicktemplates2/quicktemplates2.pro
+++ b/src/quicktemplates2/quicktemplates2.pro
@@ -10,7 +10,11 @@ DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
HEADERS += \
$$PWD/qtquicktemplates2global_p.h
+SOURCES += \
+ $$PWD/qtquicktemplates2global.cpp
+
include(quicktemplates2.pri)
+include(accessible/accessible.pri)
load(qt_module)
QMLTYPES_FILENAME = plugins.qmltypes
diff --git a/tests/auto/accessibility/accessibility.pro b/tests/auto/accessibility/accessibility.pro
index d8d5bb95..4cc101fb 100644
--- a/tests/auto/accessibility/accessibility.pro
+++ b/tests/auto/accessibility/accessibility.pro
@@ -12,5 +12,7 @@ include (../shared/util.pri)
TESTDATA = data/*
OTHER_FILES += \
- data/*.qml
+ data/defaults\*.qml \
+ data/ordering\*.qml \
+ data/override*.qml
diff --git a/tests/auto/accessibility/data/ordering/page.qml b/tests/auto/accessibility/data/ordering/page.qml
new file mode 100644
index 00000000..8efafe32
--- /dev/null
+++ b/tests/auto/accessibility/data/ordering/page.qml
@@ -0,0 +1,23 @@
+import QtQuick
+import QtQuick.Controls
+
+Page {
+ title: "Page"
+ Accessible.role: Accessible.Pane
+
+ header: Label {
+ text: "Header"
+ }
+
+ footer: Label {
+ text: "Footer"
+ }
+
+ Label {
+ text: "Content item 1"
+ }
+
+ Label {
+ text: "Content item 2"
+ }
+}
diff --git a/tests/auto/accessibility/tst_accessibility.cpp b/tests/auto/accessibility/tst_accessibility.cpp
index 3d9a318d..f2cb8b60 100644
--- a/tests/auto/accessibility/tst_accessibility.cpp
+++ b/tests/auto/accessibility/tst_accessibility.cpp
@@ -60,6 +60,7 @@ private slots:
void override_data();
void override();
+ void ordering();
private:
QQmlEngine engine;
};
@@ -268,6 +269,35 @@ void tst_accessibility::override()
Q_UNUSED(text);
#endif
}
+template <typename Predicate>
+void a11yDescendants(QAccessibleInterface *iface, Predicate pred)
+{
+ for (int i = 0; i < iface->childCount(); ++i) {
+ if (QAccessibleInterface *child = iface->child(i)) {
+ pred(child);
+ a11yDescendants(child, pred);
+ }
+ }
+}
+
+void tst_accessibility::ordering()
+{
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("ordering/page.qml"));
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
+
+#if QT_CONFIG(accessibility)
+ QQuickItem *item = findItem(object.data());
+ QVERIFY(item);
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(item);
+ QVERIFY(iface);
+ QStringList strings;
+ a11yDescendants(iface, [&](QAccessibleInterface *iface) {strings << iface->text(QAccessible::Name);});
+ QCOMPARE(strings.join(QLatin1String(", ")), "Header, Content item 1, Content item 2, Footer");
+#endif
+}
QTEST_MAIN(tst_accessibility)