vcl/inc/qt5/QtAccessibleWidget.hxx | 19 +++ vcl/qt5/QtAccessibleWidget.cxx | 212 ++++++++++++++++++++++++++++--------- 2 files changed, 183 insertions(+), 48 deletions(-)
New commits: commit 84183c84d86456e3c311b35150b1fc9b63a85561 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Sat Apr 22 09:22:38 2023 +0300 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Sat Apr 22 11:33:32 2023 +0200 qt a11y: Implement QAccessibleSelectionInterface added in Qt 6.5 This adds an implementation of the `QAccessibleSelectionInterface` that was added in Qt 6.5 in commit [1] commit 9d16d5e2245c26e5746fd7609300b84a2a983457 Author: Michael Weghorn <m.wegh...@posteo.de> Date: Tue Oct 11 15:23:54 2022 +0200 a11y: Add new QAccessibleSelectionInterface , s.a. QTBUG-105909 [2]. The `QAccessibleSelectionInterface` is currently still marked as preliminary in Qt, so changes to the API *might* still happen and require an update of the implementation here as well). Quoting from the commit message of the above commit: > This interface is marked \preliminary until: > > 1. There is a working a11y bridge for macOS/VoiceOver > 2. There is a working a11y bridge for Windows/UI Automation > 3. There is a working a11y bridge for linux/AT-SPI > 4. There is at least one implementation (e.g. QAccessibleTable) > that implements it successfully (second candidate: > Qt Quick TableView [...]) The AT-SPI bridge (point 3 from above) has been implemented in [3] commit ece2feee0317b582a56a0bfc783f11fe67d3edee Author: Michael Weghorn <m.wegh...@posteo.de> Date: Tue Oct 11 15:24:04 2022 +0200 a11y atspi: Bridge newly introduced QAccessibleSelectionInterface , an implementation for `QAccessibleTable` (point 4 from above) was added in [4] commit 092bbc9ad30c6cd7389053dc4b332cc762693676 Author: Michael Weghorn <m.wegh...@posteo.de> Date: Wed Oct 12 07:07:48 2022 +0200 a11y: Implement QAccessibleSelectionInterface for item views . The Qt Gerrit changes for the macOS implementation (point 1 from above) and the Windows/UIA implementation (point 2 from above) are currently still awaiting review: [5] [6] To avoid duplication, just call the newly added methods `QtAccessibleWidget::selectedItemCount` and `QtAccessibleWidget::selectedItem` from the `QAccessibleTableInterface` methods `QtAccessibleWidget::selectedCellCount` and and `QtAccessibleWidget::selectedCells`, and therefore implement the former also for Qt < 6.5. Sample use of the interface from Accerciser's IPython console (with 18 cells selected in Calc and the spreadsheet object selected in Accerciser's a11y object tree; screencast attached to QTBUG-105909 [2]): In [10]: acc.get_interfaces() Out[10]: ['Accessible', 'Component', 'Selection', 'Table'] In [11]: sel = acc.querySelection() In [12]: sel.nSelectedChildren Out[12]: 18 In [13]: sel.getSelectedChild(0).name Out[13]: 'B1' In [14]: sel.deselectSelectedChild(1) Out[14]: True In [15]: sel.deselectChild(1) Out[15]: True In [16]: sel.selectChild(0) Out[16]: True In [17]: sel.clearSelection() Out[17]: True In [18]: sel.selectAll() Out[18]: True [1] https://code.qt.io/cgit/qt/qtbase.git/commit/?id=9d16d5e2245c26e5746fd7609300b84a2a983457 [2] https://bugreports.qt.io/browse/QTBUG-105909 [3] https://code.qt.io/cgit/qt/qtbase.git/commit/?id=ece2feee0317b582a56a0bfc783f11fe67d3edee [4] https://code.qt.io/cgit/qt/qtbase.git/commit/?id=092bbc9ad30c6cd7389053dc4b332cc762693676 [5] https://codereview.qt-project.org/c/qt/qtbase/+/451353 [6] https://codereview.qt-project.org/c/qt/qtbase/+/451646 Change-Id: Iac3c050448183610af3bd3b10a56e82d7d52cb91 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138750 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/vcl/inc/qt5/QtAccessibleWidget.hxx b/vcl/inc/qt5/QtAccessibleWidget.hxx index 7e7625041c4f..d6d27c9cfcbd 100644 --- a/vcl/inc/qt5/QtAccessibleWidget.hxx +++ b/vcl/inc/qt5/QtAccessibleWidget.hxx @@ -40,6 +40,9 @@ class QtAccessibleWidget final : public QAccessibleInterface, public QAccessibleActionInterface, public QAccessibleTextInterface, public QAccessibleEditableTextInterface, +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + public QAccessibleSelectionInterface, +#endif public QAccessibleTableCellInterface, public QAccessibleTableInterface, public QAccessibleValueInterface @@ -147,6 +150,22 @@ public: virtual int rowIndex() const override; virtual QAccessibleInterface* table() const override; +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + // QAccessibleSelectionInterface + virtual int selectedItemCount() const override; + virtual QList<QAccessibleInterface*> selectedItems() const override; + virtual QAccessibleInterface* selectedItem(int selectionIndex) const override; + virtual bool isSelected(QAccessibleInterface* item) const override; + virtual bool select(QAccessibleInterface* item) override; + virtual bool unselect(QAccessibleInterface* item) override; + virtual bool selectAll() override; + virtual bool clear() override; +#else + // no override, but used in QAccessibleTableInterface methods + virtual int selectedItemCount() const; + virtual QList<QAccessibleInterface*> selectedItems() const; +#endif + // Factory static QAccessibleInterface* customFactory(const QString& classname, QObject* object); diff --git a/vcl/qt5/QtAccessibleWidget.cxx b/vcl/qt5/QtAccessibleWidget.cxx index 237b2db64735..84b398c006cc 100644 --- a/vcl/qt5/QtAccessibleWidget.cxx +++ b/vcl/qt5/QtAccessibleWidget.cxx @@ -727,6 +727,10 @@ void* QtAccessibleWidget::interface_cast(QAccessible::InterfaceType t) } if (t == QAccessible::TableInterface && accessibleProvidesInterface<XAccessibleTable>()) return static_cast<QAccessibleTableInterface*>(this); +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + if (t == QAccessible::SelectionInterface && accessibleProvidesInterface<XAccessibleSelection>()) + return static_cast<QAccessibleSelectionInterface*>(this); +#endif return nullptr; } @@ -1631,55 +1635,9 @@ bool QtAccessibleWidget::selectRow(int row) return xTableSelection->selectRow(row); } -int QtAccessibleWidget::selectedCellCount() const -{ - Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); - if (!xAcc.is()) - return 0; - - Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY); - if (!xSelection.is()) - return 0; - - sal_Int64 nSelected = xSelection->getSelectedAccessibleChildCount(); - if (nSelected > std::numeric_limits<int>::max()) - { - SAL_WARN("vcl.qt", - "QtAccessibleWidget::selectedCellCount: Cell count exceeds maximum int value, " - "using max int."); - nSelected = std::numeric_limits<int>::max(); - } - return nSelected; -} - -QList<QAccessibleInterface*> QtAccessibleWidget::selectedCells() const -{ - Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); - if (!xAcc.is()) - return QList<QAccessibleInterface*>(); - - Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY); - if (!xSelection.is()) - return QList<QAccessibleInterface*>(); +int QtAccessibleWidget::selectedCellCount() const { return selectedItemCount(); } - QList<QAccessibleInterface*> aSelectedCells; - sal_Int64 nSelected = xSelection->getSelectedAccessibleChildCount(); - if (nSelected > std::numeric_limits<int>::max()) - { - SAL_WARN("vcl.qt", - "QtAccessibleWidget::selectedCells: Cell count exceeds maximum int value, " - "using max int."); - nSelected = std::numeric_limits<int>::max(); - } - for (sal_Int64 i = 0; i < nSelected; i++) - { - Reference<XAccessible> xChild = xSelection->getSelectedAccessibleChild(i); - QAccessibleInterface* pInterface - = QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xChild)); - aSelectedCells.push_back(pInterface); - } - return aSelectedCells; -} +QList<QAccessibleInterface*> QtAccessibleWidget::selectedCells() const { return selectedItems(); } int QtAccessibleWidget::selectedColumnCount() const { @@ -1897,4 +1855,162 @@ QAccessibleInterface* QtAccessibleWidget::table() const return QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xTableAcc)); } +// QAccessibleSelectionInterface +int QtAccessibleWidget::selectedItemCount() const +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return 0; + + Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY); + if (!xSelection.is()) + return 0; + + sal_Int64 nSelected = xSelection->getSelectedAccessibleChildCount(); + if (nSelected > std::numeric_limits<int>::max()) + { + SAL_WARN("vcl.qt", + "QtAccessibleWidget::selectedItemCount: Cell count exceeds maximum int value, " + "using max int."); + nSelected = std::numeric_limits<int>::max(); + } + return nSelected; +} + +QList<QAccessibleInterface*> QtAccessibleWidget::selectedItems() const +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return QList<QAccessibleInterface*>(); + + Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY); + if (!xSelection.is()) + return QList<QAccessibleInterface*>(); + + QList<QAccessibleInterface*> aSelectedItems; + sal_Int64 nSelected = xSelection->getSelectedAccessibleChildCount(); + if (nSelected > std::numeric_limits<int>::max()) + { + SAL_WARN("vcl.qt", + "QtAccessibleWidget::selectedItems: Cell count exceeds maximum int value, " + "using max int."); + nSelected = std::numeric_limits<int>::max(); + } + for (sal_Int64 i = 0; i < nSelected; i++) + { + Reference<XAccessible> xChild = xSelection->getSelectedAccessibleChild(i); + QAccessibleInterface* pInterface + = QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xChild)); + aSelectedItems.push_back(pInterface); + } + return aSelectedItems; +} + +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) +QAccessibleInterface* QtAccessibleWidget::selectedItem(int nSelectionIndex) const +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return nullptr; + + Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY); + if (!xSelection.is()) + return nullptr; + + if (nSelectionIndex < 0 || nSelectionIndex >= xSelection->getSelectedAccessibleChildCount()) + { + SAL_WARN("vcl.qt", + "QtAccessibleWidget::selectedItem called with invalid index: " << nSelectionIndex); + return nullptr; + } + + Reference<XAccessible> xChild = xSelection->getSelectedAccessibleChild(nSelectionIndex); + if (!xChild) + return nullptr; + + return QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xChild)); +} + +bool QtAccessibleWidget::isSelected(QAccessibleInterface* pItem) const +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return false; + + Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY); + if (!xSelection.is()) + return false; + + int nChildIndex = indexOfChild(pItem); + if (nChildIndex < 0) + return false; + + return xSelection->isAccessibleChildSelected(nChildIndex); +} + +bool QtAccessibleWidget::select(QAccessibleInterface* pItem) +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return false; + + Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY); + if (!xSelection.is()) + return false; + + int nChildIndex = indexOfChild(pItem); + if (nChildIndex < 0) + return false; + + xSelection->selectAccessibleChild(nChildIndex); + return true; +} + +bool QtAccessibleWidget::unselect(QAccessibleInterface* pItem) +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return false; + + Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY); + if (!xSelection.is()) + return false; + + int nChildIndex = indexOfChild(pItem); + if (nChildIndex < 0) + return false; + + xSelection->deselectAccessibleChild(nChildIndex); + return true; +} + +bool QtAccessibleWidget::selectAll() +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return false; + + Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY); + if (!xSelection.is()) + return false; + + xSelection->selectAllAccessibleChildren(); + return true; +} + +bool QtAccessibleWidget::clear() +{ + Reference<XAccessibleContext> xAcc = getAccessibleContextImpl(); + if (!xAcc.is()) + return false; + + Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY); + if (!xSelection.is()) + return false; + + xSelection->clearAccessibleSelection(); + return true; +} +#endif + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */