Repository: nvaccess/nvda

Issue:
Exception when only a single cell is selected in LibreOffice >= 7.3
### Steps to reproduce:

1) start NVDA from current git master
2) start LibreOffice Calc (version 7.3 or later; issue not reproducible with older versions because the relevant code path that triggers the issue is not taken)
3) press Shift+Right to select cells A1 and B1
4) press Shift+Left to leave only cell A1 selected

### Actual behavior:

An error occurs, NVDA "beeps".

Traceback from the NVDA log:

```
NVDA initialized
ERROR - eventHandler.executeEvent (15:50:59.902) - MainThread (6012):
error executing event: selectionRemove on <NVDAObjects.Dynamic_SymphonyIATableCellEditableTextWithAutoSelectDetectionIAccessible object at 0x0E0AB4F0> with extra args of {}
Traceback (most recent call last):
  File "eventHandler.py", line 284, in executeEvent
    _EventExecuter(eventName,obj,kwargs)
  File "eventHandler.py", line 98, in __init__
    self.next()
  File "eventHandler.py", line 107, in next
    return func(*args, **self.kwargs)
  File "appModules\soffice.py", line 196, in event_selectionRemove
    self.event_selectionAdd()
  File "appModules\soffice.py", line 193, in event_selectionAdd
    curFocus.announceSelectionChange()
  File "appModules\soffice.py", line 204, in announceSelectionChange
    reason=controlTypes.OutputReason.CHANGE
  File "speech\speech.py", line 402, in speakObjectProperties
    **allowedProperties,
  File "speech\speech.py", line 453, in getObjectPropertiesSpeech
    newPropertyValues[name]=getattr(obj,tryName)
  File "baseObject.py", line 42, in __get__
    return instance._getPropertyViaCache(self.fget)
  File "baseObject.py", line 146, in _getPropertyViaCache
    val=getterMethod(self)
  File "appModules\soffice.py", line 174, in _get_states
    if self.hasSelection:
  File "baseObject.py", line 42, in __get__
    return instance._getPropertyViaCache(self.fget)
  File "baseObject.py", line 146, in _getPropertyViaCache
    val=getterMethod(self)
  File "appModules\soffice.py", line 164, in _get_hasSelection
    and 1 < self.selectionContainer.getSelectedItemsCount()
  File "NVDAObjects\IAccessible\__init__.py", line 1342, in getSelectedItemsCount
    return self._getSelectedItemsCount_accSelection(maxCount)
  File "NVDAObjects\IAccessible\__init__.py", line 1318, in _getSelectedItemsCount_accSelection
    enumObj=sel.QueryInterface(IEnumVARIANT)
AttributeError: 'int' object has no attribute 'QueryInterface'
```

### Expected behavior:

Corrdinates of cell A1 should be announced after step 4.

### System configuration
#### NVDA installed/portable/running from source:

running from source

#### NVDA version:

self-compiled from git master as of commit 7735d96259d02eb8cc8d84f13a870ecfec0635b9

#### Windows version:

Windows 10 Version 21H2 (OS Build 19044.1466)

#### Name and version of other software in use when reproducing the issue:

LibreOffice (version >= 7.3, in my case current development version self-compiled from git master as of commit 86a9c860410351125708543c1050bfc0977d3b97)

#### Other information about your system:

### Other questions
#### Does the issue still occur after restarting your computer?

n/a

#### Have you tried any other versions of NVDA? If so, please report their behaviors.

no

#### If NVDA add-ons are disabled, is your problem still occurring?

n/a

#### Does the issue still occur after you run the COM Registration Fixing Tool in NVDA's tools menu?

n/a


Discussion:

Resolving patch:
diff --git a/source/NVDAObjects/IAccessible/__init__.py b/source/NVDAObjects/IAccessible/__init__.py
--- a/source/NVDAObjects/IAccessible/__init__.py
+++ b/source/NVDAObjects/IAccessible/__init__.py
@@ -13,6 +13,7 @@
 	BSTR,
 )
 from comtypes.hresult import S_OK, S_FALSE
+import comtypes.client
 import ctypes
 import os
 import re
@@ -1317,8 +1318,11 @@ def _getSelectedItemsCount_accSelection(self, maxCount: int) -> int:
 		if not sel:
 			raise NotImplementedError
 		# accSelection can return a child ID of a simple element, for instance in QT tree tables. 
-		# Therefore treat this as a single selection.
-		if isinstance(sel,int) and sel>0:
+		# Therefore treat this as a single selection unless the child ID is CHILDID_SELF (0).
+		if isinstance(sel, int) and sel != 0:
+			return 1
+		# accSelection can return IDispatch for a single selected child object
+		if isinstance(sel, comtypes.client.dynamic._Dispatch):
 			return 1
 		enumObj=sel.QueryInterface(IEnumVARIANT)
 		if not enumObj:


Test patch: