diff options
author | Michael Weghorn <m.weghorn@posteo.de> | 2022-08-24 11:42:04 +0200 |
---|---|---|
committer | Michael Weghorn <m.weghorn@posteo.de> | 2022-08-24 19:05:35 +0200 |
commit | 812fe185fba48b439fb1229517d62aa67c209016 (patch) | |
tree | 46f8c31fc22b3b80ca3b5efff0f9d8b5fcac693e /vcl | |
parent | 9931d6b1fb0406e16d56e186812884511738dcfa (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.mk | 1 | ||||
-rw-r--r-- | vcl/Library_vclplug_qt6.mk | 1 | ||||
-rw-r--r-- | vcl/inc/qt5/QtAccessibleRegistry.hxx | 40 | ||||
-rw-r--r-- | vcl/inc/qt6/QtAccessibleRegistry.hxx | 12 | ||||
-rw-r--r-- | vcl/qt5/QtAccessibleRegistry.cxx | 37 | ||||
-rw-r--r-- | vcl/qt5/QtAccessibleWidget.cxx | 35 | ||||
-rw-r--r-- | vcl/qt6/QtAccessibleRegistry.cxx | 12 |
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: */ |