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-02-02 09:45:11 +0100
commit180dbd050173d20c99f730eeacf2b0376fcb895e (patch)
tree30829dd47722419ec96bce940d5da382252349c8
parent950f8bff7cbbdbd472234fd32ef659c9d0e8ba7c (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 Change-Id: Ic3e8ec3f7dcf18af9262b1d35c986835c8da6900 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit 4b1acb290dc8869d0d2d1250dc1ed415d6b6e202)
-rw-r--r--src/imports/templates/qtquicktemplates2plugin.cpp2
-rw-r--r--src/quicktemplates2/accessible/accessible.pri5
-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.h2
-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
10 files changed, 283 insertions, 1 deletions
diff --git a/src/imports/templates/qtquicktemplates2plugin.cpp b/src/imports/templates/qtquicktemplates2plugin.cpp
index 961f2b7b..4bcb9bd4 100644
--- a/src/imports/templates/qtquicktemplates2plugin.cpp
+++ b/src/imports/templates/qtquicktemplates2plugin.cpp
@@ -142,6 +142,8 @@ private:
QtQuickTemplates2Plugin::QtQuickTemplates2Plugin(QObject *parent)
: QQmlExtensionPlugin(parent), registered(false)
{
+ volatile auto initialization = &QQuickTemplates_initializeModule;
+ Q_UNUSED(initialization)
#if QT_CONFIG(shortcut)
originalContextMatcher = qt_quick_shortcut_context_matcher();
qt_quick_set_shortcut_context_matcher(QQuickShortcutContext::matcher);
diff --git a/src/quicktemplates2/accessible/accessible.pri b/src/quicktemplates2/accessible/accessible.pri
new file mode 100644
index 00000000..93660b9f
--- /dev/null
+++ b/src/quicktemplates2/accessible/accessible.pri
@@ -0,0 +1,5 @@
+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 cec648d3..4bf6488a 100644
--- a/src/quicktemplates2/qtquicktemplates2global_p.h
+++ b/src/quicktemplates2/qtquicktemplates2global_p.h
@@ -64,6 +64,8 @@ QT_BEGIN_NAMESPACE
# define Q_QUICKTEMPLATES2_PRIVATE_EXPORT
#endif
+Q_QUICKTEMPLATES2_PRIVATE_EXPORT void QQuickTemplates_initializeModule();
+
QT_END_NAMESPACE
#endif // QTQUICKTEMPLATES2GLOBAL_P_H
diff --git a/src/quicktemplates2/quicktemplates2.pro b/src/quicktemplates2/quicktemplates2.pro
index 8ed0151a..5138b610 100644
--- a/src/quicktemplates2/quicktemplates2.pro
+++ b/src/quicktemplates2/quicktemplates2.pro
@@ -10,5 +10,9 @@ 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)
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..5eeb1530
--- /dev/null
+++ b/tests/auto/accessibility/data/ordering/page.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+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 6e5a37df..30bd4757 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;
};
@@ -284,6 +285,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)