summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorMichael Weghorn <m.weghorn@posteo.de>2022-08-24 11:42:04 +0200
committerMichael Weghorn <m.weghorn@posteo.de>2022-08-24 19:05:35 +0200
commit812fe185fba48b439fb1229517d62aa67c209016 (patch)
tree46f8c31fc22b3b80ca3b5efff0f9d8b5fcac693e /vcl
parent9931d6b1fb0406e16d56e186812884511738dcfa (diff)
qt a11y: Remember and reuse existing QObject for XAccessible
Previously, a new `QtXAccessible` object was created for an `XAccessible` each time before `QAccessible::queryAccessibleInterface` was called, which is not only unnecessary but also causes various issues, e.g. it breaks walking the a11y hierarchy upwards (i.e. from children to parents), since a new object is created for the parent. This introduces `QtAccessibleRegistry` that keeps a mapping between the `XAccessible` and the associated `QObject`. That mapping is used to reuse already created objects instead of creating new ones for the same `XAccessible`. The entry for an `XAccessible` is removed again from the map in `QtAccessibleWidget::invalidate`, which gets called when the `XAccessible` gets disposed, s. `QtAccessibleEventListener::disposing`. With this in place, Orca now also nicely announces only the text of the push buttons themselves in the "Save Document?" dialog when switching between the buttons using the Tab key, rather than announcing the whole widget hierarchy every time (probably because creating a new object every time prevented Orca from recognizing that the previously selected pushbutton and the newly selected one are siblings, i.e. have the same parent object.) Change-Id: Ic890a387ff016e889f25dba70c82d0d81ae7a9e3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138757 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/Library_vclplug_qt5.mk1
-rw-r--r--vcl/Library_vclplug_qt6.mk1
-rw-r--r--vcl/inc/qt5/QtAccessibleRegistry.hxx40
-rw-r--r--vcl/inc/qt6/QtAccessibleRegistry.hxx12
-rw-r--r--vcl/qt5/QtAccessibleRegistry.cxx37
-rw-r--r--vcl/qt5/QtAccessibleWidget.cxx35
-rw-r--r--vcl/qt6/QtAccessibleRegistry.cxx12
7 files changed, 125 insertions, 13 deletions
diff --git a/vcl/Library_vclplug_qt5.mk b/vcl/Library_vclplug_qt5.mk
index 25a8864c83ad..2a72693e0e85 100644
--- a/vcl/Library_vclplug_qt5.mk
+++ b/vcl/Library_vclplug_qt5.mk
@@ -76,6 +76,7 @@ endif
$(eval $(call gb_Library_add_exception_objects,vclplug_qt5,\
vcl/qt5/QtAccessibleEventListener \
+ vcl/qt5/QtAccessibleRegistry \
vcl/qt5/QtAccessibleWidget \
vcl/qt5/QtBitmap \
vcl/qt5/QtClipboard \
diff --git a/vcl/Library_vclplug_qt6.mk b/vcl/Library_vclplug_qt6.mk
index 36da06abb294..a6b14da23f5c 100644
--- a/vcl/Library_vclplug_qt6.mk
+++ b/vcl/Library_vclplug_qt6.mk
@@ -75,6 +75,7 @@ endif
$(eval $(call gb_Library_add_exception_objects,vclplug_qt6,\
vcl/qt6/QtAccessibleEventListener \
+ vcl/qt6/QtAccessibleRegistry \
vcl/qt6/QtAccessibleWidget \
vcl/qt6/QtBitmap \
vcl/qt6/QtClipboard \
diff --git a/vcl/inc/qt5/QtAccessibleRegistry.hxx b/vcl/inc/qt5/QtAccessibleRegistry.hxx
new file mode 100644
index 000000000000..00acf80fd68c
--- /dev/null
+++ b/vcl/inc/qt5/QtAccessibleRegistry.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <map>
+
+#include <QtCore/QObject>
+
+#include <com/sun/star/accessibility/XAccessible.hpp>
+
+using namespace css::accessibility;
+
+/**
+ * Maintains a mapping between XAccessible objects and the
+ * associated QObjects. The corresponding QObject can be
+ * passed to the QAccessible::queryAccessibleInterface method in
+ * order to retrieve the QAccessibleInterface for the
+ * XAccessible object.
+ */
+class QtAccessibleRegistry
+{
+private:
+ static std::map<css::accessibility::XAccessible*, QObject*> m_aMapping;
+ QtAccessibleRegistry() = delete;
+
+public:
+ /** Returns the related QObject* for the XAccessible. Creates a new one if none exists yet. */
+ static QObject* getQObject(css::uno::Reference<XAccessible> xAcc);
+ /** Removes the entry for the given XAccessible. */
+ static void remove(css::uno::Reference<XAccessible> xAcc);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/qt6/QtAccessibleRegistry.hxx b/vcl/inc/qt6/QtAccessibleRegistry.hxx
new file mode 100644
index 000000000000..b29fbb32633e
--- /dev/null
+++ b/vcl/inc/qt6/QtAccessibleRegistry.hxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "../qt5/QtAccessibleRegistry.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/qt5/QtAccessibleRegistry.cxx b/vcl/qt5/QtAccessibleRegistry.cxx
new file mode 100644
index 000000000000..e64f8ae03868
--- /dev/null
+++ b/vcl/qt5/QtAccessibleRegistry.cxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <QtAccessibleRegistry.hxx>
+#include <QtXAccessible.hxx>
+
+std::map<XAccessible*, QObject*> QtAccessibleRegistry::m_aMapping = {};
+
+QObject* QtAccessibleRegistry::getQObject(css::uno::Reference<XAccessible> xAcc)
+{
+ if (!xAcc.is())
+ return nullptr;
+
+ // look for existing entry in the map
+ auto entry = m_aMapping.find(xAcc.get());
+ if (entry != m_aMapping.end())
+ return entry->second;
+
+ // create a new object and remember it in the map
+ QtXAccessible* pQtAcc = new QtXAccessible(xAcc);
+ m_aMapping.emplace(xAcc.get(), pQtAcc);
+ return pQtAcc;
+}
+
+void QtAccessibleRegistry::remove(css::uno::Reference<XAccessible> xAcc)
+{
+ assert(xAcc.is());
+ m_aMapping.erase(xAcc.get());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/qt5/QtAccessibleWidget.cxx b/vcl/qt5/QtAccessibleWidget.cxx
index b23a8c9a2844..fc81332465e7 100644
--- a/vcl/qt5/QtAccessibleWidget.cxx
+++ b/vcl/qt5/QtAccessibleWidget.cxx
@@ -22,6 +22,7 @@
#include <QtGui/QAccessibleInterface>
#include <QtAccessibleEventListener.hxx>
+#include <QtAccessibleRegistry.hxx>
#include <QtFrame.hxx>
#include <QtTools.hxx>
#include <QtWidget.hxx>
@@ -74,7 +75,11 @@ QtAccessibleWidget::QtAccessibleWidget(const Reference<XAccessible> xAccessible,
}
}
-void QtAccessibleWidget::invalidate() { m_xAccessible.clear(); }
+void QtAccessibleWidget::invalidate()
+{
+ QtAccessibleRegistry::remove(m_xAccessible);
+ m_xAccessible.clear();
+}
Reference<XAccessibleContext> QtAccessibleWidget::getAccessibleContextImpl() const
{
@@ -251,7 +256,8 @@ void lcl_appendRelation(QVector<QPair<QAccessibleInterface*, QAccessible::Relati
{
Reference<XAccessible> xAccessible(aRelation.TargetSet[i], uno::UNO_QUERY);
relations->append(
- { QAccessible::queryAccessibleInterface(new QtXAccessible(xAccessible)), aQRelation });
+ { QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xAccessible)),
+ aQRelation });
}
}
}
@@ -315,7 +321,8 @@ QAccessibleInterface* QtAccessibleWidget::parent() const
return nullptr;
if (xAc->getAccessibleParent().is())
- return QAccessible::queryAccessibleInterface(new QtXAccessible(xAc->getAccessibleParent()));
+ return QAccessible::queryAccessibleInterface(
+ QtAccessibleRegistry::getQObject(xAc->getAccessibleParent()));
// go via the QObject hierarchy; some a11y objects like the application
// (at the root of the a11y hierarchy) are handled solely by Qt and have
@@ -332,8 +339,8 @@ QAccessibleInterface* QtAccessibleWidget::child(int index) const
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
if (!xAc.is())
return nullptr;
-
- return QAccessible::queryAccessibleInterface(new QtXAccessible(xAc->getAccessibleChild(index)));
+ return QAccessible::queryAccessibleInterface(
+ QtAccessibleRegistry::getQObject(xAc->getAccessibleChild(index)));
}
QString QtAccessibleWidget::text(QAccessible::Text text) const
@@ -736,7 +743,7 @@ QAccessibleInterface* QtAccessibleWidget::childAt(int x, int y) const
// convert from screen to local coordinates
QPoint aLocalCoords = QPoint(x, y) - rect().topLeft();
return QAccessible::queryAccessibleInterface(
- new QtXAccessible(xAccessibleComponent->getAccessibleAtPoint(
+ QtAccessibleRegistry::getQObject(xAccessibleComponent->getAccessibleAtPoint(
awt::Point(aLocalCoords.x(), aLocalCoords.y()))));
}
@@ -1458,7 +1465,8 @@ QAccessibleInterface* QtAccessibleWidget::caption() const
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
if (!xTable.is())
return nullptr;
- return QAccessible::queryAccessibleInterface(new QtXAccessible(xTable->getAccessibleCaption()));
+ return QAccessible::queryAccessibleInterface(
+ QtAccessibleRegistry::getQObject(xTable->getAccessibleCaption()));
}
QAccessibleInterface* QtAccessibleWidget::cellAt(int row, int column) const
@@ -1471,7 +1479,7 @@ QAccessibleInterface* QtAccessibleWidget::cellAt(int row, int column) const
if (!xTable.is())
return nullptr;
return QAccessible::queryAccessibleInterface(
- new QtXAccessible(xTable->getAccessibleCellAt(row, column)));
+ QtAccessibleRegistry::getQObject(xTable->getAccessibleCellAt(row, column)));
}
int QtAccessibleWidget::columnCount() const
@@ -1603,7 +1611,7 @@ QList<QAccessibleInterface*> QtAccessibleWidget::selectedCells() const
{
Reference<XAccessible> xChild = xSelection->getSelectedAccessibleChild(i);
QAccessibleInterface* pInterface
- = QAccessible::queryAccessibleInterface(new QtXAccessible(xChild));
+ = QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xChild));
aSelectedCells.push_back(pInterface);
}
return aSelectedCells;
@@ -1666,7 +1674,8 @@ QAccessibleInterface* QtAccessibleWidget::summary() const
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
if (!xTable.is())
return nullptr;
- return QAccessible::queryAccessibleInterface(new QtXAccessible(xTable->getAccessibleSummary()));
+ return QAccessible::queryAccessibleInterface(
+ QtAccessibleRegistry::getQObject(xTable->getAccessibleSummary()));
}
bool QtAccessibleWidget::unselectColumn(int column)
@@ -1710,7 +1719,7 @@ QList<QAccessibleInterface*> QtAccessibleWidget::columnHeaderCells() const
{
Reference<XAccessible> xCell = xHeaders->getAccessibleCellAt(nRow, nCol);
QAccessibleInterface* pInterface
- = QAccessible::queryAccessibleInterface(new QtXAccessible(xCell));
+ = QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xCell));
aHeaderCells.push_back(pInterface);
}
return aHeaderCells;
@@ -1776,7 +1785,7 @@ QList<QAccessibleInterface*> QtAccessibleWidget::rowHeaderCells() const
{
Reference<XAccessible> xCell = xHeaders->getAccessibleCellAt(nRow, nCol);
QAccessibleInterface* pInterface
- = QAccessible::queryAccessibleInterface(new QtXAccessible(xCell));
+ = QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xCell));
aHeaderCells.push_back(pInterface);
}
return aHeaderCells;
@@ -1821,7 +1830,7 @@ QAccessibleInterface* QtAccessibleWidget::table() const
if (!xTableAcc.is())
return nullptr;
- return QAccessible::queryAccessibleInterface(new QtXAccessible(xTableAcc));
+ return QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xTableAcc));
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/qt6/QtAccessibleRegistry.cxx b/vcl/qt6/QtAccessibleRegistry.cxx
new file mode 100644
index 000000000000..782393e71353
--- /dev/null
+++ b/vcl/qt6/QtAccessibleRegistry.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "../qt5/QtAccessibleRegistry.cxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */