From 5cc3d198cabdcaebc69c2e6726af00d653523876 Mon Sep 17 00:00:00 2001
From: Peter Varga <pvarga@inf.u-szeged.hu>
Date: Fri, 6 Dec 2019 11:22:42 +0100
Subject: [PATCH] POC: QQuickWidget Accessibility

Change-Id: I14f260704d0e6a1776821ef33d015f1db4c23414
---
 src/quick/accessible/qaccessiblequickitem.cpp |   4 +
 src/quick/accessible/qaccessiblequickview.cpp |  29 +++++
 src/quickwidgets/qaccessiblequickwidget.cpp   | 104 ++++++++++++++++++
 src/quickwidgets/qaccessiblequickwidget_p.h   |  81 ++++++++++++++
 src/quickwidgets/qquickwidget.cpp             |   7 ++
 src/quickwidgets/quickwidgets.pro             |   5 +
 6 files changed, 230 insertions(+)
 create mode 100644 src/quickwidgets/qaccessiblequickwidget.cpp
 create mode 100644 src/quickwidgets/qaccessiblequickwidget_p.h

diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
index b87203c3ef..806f49b88b 100644
--- a/src/quick/accessible/qaccessiblequickitem.cpp
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
@@ -187,8 +187,12 @@ QAccessible::State QAccessibleQuickItem::state() const
     QRect viewRect_ = viewRect();
     QRect itemRect = rect();
 
+#if 0
     if (viewRect_.isNull() || itemRect.isNull() || !item()->window() || !item()->window()->isVisible() ||!item()->isVisible() || qFuzzyIsNull(item()->opacity()))
         state.invisible = true;
+#else
+    state.invisible = false;
+#endif
     if (!viewRect_.intersects(itemRect))
         state.offscreen = true;
     if ((role() == QAccessible::CheckBox || role() == QAccessible::RadioButton) && object()->property("checked").toBool())
diff --git a/src/quick/accessible/qaccessiblequickview.cpp b/src/quick/accessible/qaccessiblequickview.cpp
index 41a02fc09c..7dce904fb8 100644
--- a/src/quick/accessible/qaccessiblequickview.cpp
+++ b/src/quick/accessible/qaccessiblequickview.cpp
@@ -70,7 +70,19 @@ int QAccessibleQuickWindow::childCount() const
 QAccessibleInterface *QAccessibleQuickWindow::parent() const
 {
     // FIXME: for now we assume to be a top level window...
+#if 1
     return QAccessible::queryAccessibleInterface(qApp);
+#else
+    for (auto window : qApp->allWindows()) {
+        // Try to avoid this to be its own parent.
+        if (window == object())
+            continue;
+
+        qDebug() << "[QAccessibleQuickWindow::parent] parent window:" << window;
+
+        return QAccessible::queryAccessibleInterface(window);
+    }
+#endif
 }
 
 QAccessibleInterface *QAccessibleQuickWindow::child(int index) const
@@ -84,14 +96,27 @@ QAccessibleInterface *QAccessibleQuickWindow::child(int index) const
 QAccessibleInterface *QAccessibleQuickWindow::focusChild() const
 {
     QObject *focusObject = window()->focusObject();
+#if 1
     if (focusObject)
         return QAccessible::queryAccessibleInterface(focusObject);
+#else
+    if (focusObject) {
+        QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(focusObject);
+        if (!iface || iface == this || !iface->focusChild())
+            return iface;
+        return iface->focusChild();
+    }
+#endif
     return nullptr;
 }
 
 QAccessible::Role QAccessibleQuickWindow::role() const
 {
+#if 1
     return QAccessible::Window;
+#else
+    return QAccessible::Client;
+#endif
 }
 
 QAccessible::State QAccessibleQuickWindow::state() const
@@ -99,8 +124,12 @@ QAccessible::State QAccessibleQuickWindow::state() const
     QAccessible::State st;
     if (window() == QGuiApplication::focusWindow())
         st.active = true;
+#if 0
     if (!window()->isVisible())
         st.invisible = true;
+#else
+    st.invisible = false;
+#endif
     return st;
 }
 
diff --git a/src/quickwidgets/qaccessiblequickwidget.cpp b/src/quickwidgets/qaccessiblequickwidget.cpp
new file mode 100644
index 0000000000..18c0290c33
--- /dev/null
+++ b/src/quickwidgets/qaccessiblequickwidget.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "qaccessiblequickwidget_p.h"
+
+QT_BEGIN_NAMESPACE
+#if QT_CONFIG(accessibility)
+
+QAccessibleInterface *qQuickWidgetAccessibleFactory(const QString &classname, QObject *object)
+{
+    if (classname == QLatin1String("QQuickWidget")) {
+        return new QAccessibleQuickWidget(qobject_cast<QQuickWidget *>(object));
+    }
+
+    return nullptr;
+}
+
+QAccessibleQuickWidget::QAccessibleQuickWidget(QWidget *widget)
+    : QAccessibleWidget(widget)
+{
+}
+
+#if 0
+QAccessibleInterface *QAccessibleQuickWidget::parent() const
+{
+    return QAccessible::queryAccessibleInterface(qApp);
+}
+
+QWindow *QAccessibleQuickWidget::window() const
+{
+    QQuickWidget *quickWidget = static_cast<QQuickWidget *>(widget());
+    return quickWidget->window()->windowHandle();
+}
+
+QAccessibleInterface *QAccessibleQuickWidget::focusChild() const
+{
+    QQuickWidget *quickWidget = static_cast<QQuickWidget *>(widget());
+    return QAccessible::queryAccessibleInterface(quickWidget->quickWindow())->focusChild();
+}
+#endif
+
+QAccessibleInterface *QAccessibleQuickWidget::child(int index) const
+{
+    if (index == 0) {
+        QQuickWidget *quickWidget = static_cast<QQuickWidget *>(widget());
+        return QAccessible::queryAccessibleInterface(quickWidget->quickWindow());
+    }
+
+    return nullptr;
+}
+
+int QAccessibleQuickWidget::childCount() const
+{
+    return 1;
+}
+
+int QAccessibleQuickWidget::indexOfChild(const QAccessibleInterface *iface) const
+{
+    if (iface == child(0))
+        return 0;
+
+    return -1;
+}
+
+
+#endif // QT_CONFIG(accessibility)
+QT_END_NAMESPACE
+
diff --git a/src/quickwidgets/qaccessiblequickwidget_p.h b/src/quickwidgets/qaccessiblequickwidget_p.h
new file mode 100644
index 0000000000..05fcfdf95e
--- /dev/null
+++ b/src/quickwidgets/qaccessiblequickwidget_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+#ifndef QACCESSIBLEQUICKWIDGET_P_H
+#define QACCESSIBLEQUICKWIDGET_P_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 <QtQuickWidgets/QQuickWidget>
+#include <QtWidgets/QAccessibleWidget>
+
+QT_BEGIN_NAMESPACE
+#if QT_CONFIG(accessibility)
+
+QAccessibleInterface *qQuickWidgetAccessibleFactory(const QString &classname, QObject *object);
+
+class QAccessibleQuickWidget : public QAccessibleWidget
+{
+public:
+    QAccessibleQuickWidget(QWidget *widget);
+
+#if 0
+    QAccessibleInterface *parent() const override;
+    QWindow *window() const override;
+    QAccessibleInterface *focusChild() const override;
+#endif
+
+    QAccessibleInterface *child(int index) const override;
+    int childCount() const override;
+    int indexOfChild(const QAccessibleInterface *iface) const override;
+};
+
+#endif // QT_CONFIG(accessibility)
+QT_END_NAMESPACE
+
+#endif // QACCESSIBLEQUICKWIDGET_P_H
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 083b7dbae1..4f48914d78 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -40,6 +40,10 @@
 #include "qquickwidget.h"
 #include "qquickwidget_p.h"
 
+#if QT_CONFIG(accessibility)
+#include "qaccessiblequickwidget_p.h"
+#endif
+
 #include "private/qquickwindow_p.h"
 #include "private/qquickitem_p.h"
 #include "private/qquickitemchangelistener_p.h"
@@ -214,6 +218,9 @@ QQuickWidgetPrivate::QQuickWidgetPrivate()
     , useSoftwareRenderer(false)
     , forceFullUpdate(false)
 {
+#if QT_CONFIG(accessibility)
+    QAccessible::installFactory(&qQuickWidgetAccessibleFactory);
+#endif
 }
 
 QQuickWidgetPrivate::~QQuickWidgetPrivate()
diff --git a/src/quickwidgets/quickwidgets.pro b/src/quickwidgets/quickwidgets.pro
index 2438e577ae..d2bce802b1 100644
--- a/src/quickwidgets/quickwidgets.pro
+++ b/src/quickwidgets/quickwidgets.pro
@@ -12,4 +12,9 @@ HEADERS += \
 SOURCES += \
     qquickwidget.cpp
 
+qtConfig(accessibility) {
+    HEADERS += qaccessiblequickwidget_p.h
+    SOURCES += qaccessiblequickwidget.cpp
+}
+
 load(qt_module)
-- 
2.24.0

