From 0170323c19275febbaf6698f9d2aae68cafe571b Mon Sep 17 00:00:00 2001 From: Michael Weghorn Date: Thu, 30 Jun 2022 02:56:59 +0200 Subject: [PATCH] soffice: Make selected cell announcement more efficient (#13233) Fixes #13232 Summary of the issue: Since PR #12849, information about selected cells in LibreOffice Calc is queried using the 'IAccessibleTable2' interface which is supported from LibreOffice 7.3 on. The call to the 'selectedCells' method on that interface requests a list of a11y objects for all currently selected cells, of which only the first and the last one are actually needed for the announcement of selected cells. Since Calc spreadsheets have more than a billion cells, this is inefficient when many cells are selected and resulted in Calc becoming unresponsive. Description of how this pull request fixes the issue: Instead of using the 'selectedCells' method from the 'IAccessibleTable2' interface, the first and last selected cell are now retrieved using the 'accSelection' on the 'IAccessible' object of the table, which avoids that a11y objects for all other selected cells have to be generated as well. Testing strategy: use LibreOffice Calc 7.3 or above select all cells in LO Calc and check that NVDA announces coordinate + content of the first cell (A1) and the last cell (AMJ1048576) in the spreadsheet test a few other selections in the spreadsheet (use shift + arrow keys to increase/decrease selection) --- source/appModules/soffice.py | 29 ++++++++++++++++++++++++++--- user_docs/en/changes.t2t | 1 + 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/source/appModules/soffice.py b/source/appModules/soffice.py index d499db9c50b..e007570ad83 100755 --- a/source/appModules/soffice.py +++ b/source/appModules/soffice.py @@ -3,7 +3,13 @@ # See the file COPYING for more details. # Copyright (C) 2006-2022 NV Access Limited, Bill Dengler, Leonard de Ruijter +from typing import ( + Union +) + from comtypes import COMError +import comtypes.client +import oleacc from IAccessibleHandler import IA2, splitIA2Attribs import appModuleHandler import controlTypes @@ -209,11 +215,28 @@ def announceSelectionChange(self): def _get_cellCoordsText(self): if self.hasSelection and controlTypes.State.FOCUSED in self.states: - selected, count = self.table.IAccessibleTable2Object.selectedCells - firstAccessible = selected[0].QueryInterface(IA2.IAccessible2) + count = self.table.IAccessibleTable2Object.nSelectedCells + selection = self.table.IAccessibleObject.accSelection + enumObj = selection.QueryInterface(oleacc.IEnumVARIANT) + firstChild: Union[int, comtypes.client.dynamic._Dispatch] + firstChild, _retrievedCount = enumObj.Next(1) + # skip over all except the last element + enumObj.Skip(count - 2) + lastChild: Union[int, comtypes.client.dynamic._Dispatch] + lastChild, _retrieveCount = enumObj.Next(1) + # in LibreOffice 7.3.0, the IEnumVARIANT returns a child ID, + # in LibreOffice >= 7.4, it returns an IDispatch + if isinstance(firstChild, int): + tableAccessible = self.table.IAccessibleTable2Object.QueryInterface(IA2.IAccessible2) + firstAccessible = tableAccessible.accChild(firstChild).QueryInterface(IA2.IAccessible2) + lastAccessible = tableAccessible.accChild(lastChild).QueryInterface(IA2.IAccessible2) + elif isinstance(firstChild, comtypes.client.dynamic._Dispatch): + firstAccessible = firstChild.QueryInterface(IA2.IAccessible2) + lastAccessible = lastChild.QueryInterface(IA2.IAccessible2) + else: + raise RuntimeError(f"Unexpected LibreOffice object {firstChild}, type: {type(firstChild)}") firstAddress = firstAccessible.accName(0) firstValue = firstAccessible.accValue(0) or '' - lastAccessible = selected[count - 1].QueryInterface(IA2.IAccessible2) lastAddress = lastAccessible.accName(0) lastValue = lastAccessible.accValue(0) or '' # Translators: LibreOffice, report selected range of cell coordinates with their values diff --git a/user_docs/en/changes.t2t b/user_docs/en/changes.t2t index 0e8896caabd..9a88fabaddb 100644 --- a/user_docs/en/changes.t2t +++ b/user_docs/en/changes.t2t @@ -27,6 +27,7 @@ It can be re-enabled in NVDA's advanced settings panel. (#11554) - Font size measurements are now translatable in NVDA. (#13573) - Ignore Java Access Bridge events where no window handle can be found for Java applications. This will improve performance for some Java applications including IntelliJ IDEA. (#13039) +- Announcement of selected cells for LibreOffice Calc is more efficient and no longer results in a Calc freeze when many cells are selected. (#13232) -