Skip to content

Commit 3308a43

Browse files
Merge 6f38ac5 into 134d8b2
2 parents 134d8b2 + 6f38ac5 commit 3308a43

2 files changed

Lines changed: 93 additions & 22 deletions

File tree

source/appModules/soffice.py

Lines changed: 89 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,28 @@
3131

3232

3333
class SymphonyTextInfo(IA2TextTextInfo):
34-
35-
def _getFormatFieldAndOffsets(self,offset,formatConfig,calculateOffsets=True):
36-
obj = self.obj
37-
try:
38-
startOffset,endOffset,attribsString=obj.IAccessibleTextObject.attributes(offset)
39-
except COMError:
40-
log.debugWarning("could not get attributes",exc_info=True)
41-
return textInfos.FormatField(),(self._startOffset,self._endOffset)
34+
# C901 '_getFormatFieldFromLegacyAttributesString' is too complex
35+
# Note: when working on _getFormatFieldFromLegacyAttributesString, look for opportunities to simplify
36+
# and move logic out into smaller helper functions.
37+
# This is legacy code, kept for compatibility reasons.
38+
def _getFormatFieldFromLegacyAttributesString( # noqa: C901
39+
self,
40+
attribsString: str,
41+
offset: int
42+
) -> textInfos.FormatField:
43+
44+
"""Get format field with information retrieved from a text
45+
attributes string containing LibreOffice's legacy custom text
46+
attributes (used by LibreOffice <= 7.6), instead of attributes
47+
according to the IAccessible2 text attributes specification
48+
(used by LibreOffice >= 24.2).
49+
50+
:param attribsString: Legacy text attributes string.
51+
:param offset: Character offset for which to retrieve the
52+
attributes.
53+
:return: Format field containing the text attribute information.
54+
"""
4255
formatField=textInfos.FormatField()
43-
if not attribsString and offset>0:
44-
try:
45-
attribsString=obj.IAccessibleTextObject.attributes(offset-1)[2]
46-
except COMError:
47-
pass
4856
if attribsString:
4957
formatField.update(splitIA2Attribs(attribsString))
5058

@@ -101,6 +109,73 @@ def _getFormatFieldAndOffsets(self,offset,formatConfig,calculateOffsets=True):
101109
if backgroundColor:
102110
formatField['background-color']=colors.RGB.fromString(backgroundColor)
103111

112+
if offset == 0:
113+
# Only include the list item prefix on the first line of the paragraph.
114+
numbering = formatField.get("Numbering")
115+
if numbering:
116+
formatField["line-prefix"] = numbering.get("NumberingPrefix") or numbering.get("BulletChar")
117+
118+
return formatField
119+
120+
def _getFormatFieldAndOffsetsFromAttributes(
121+
self,
122+
offset: int,
123+
formatConfig: Optional[dict],
124+
calculateOffsets: bool
125+
) -> tuple[textInfos.FormatField, tuple[int, int]]:
126+
"""Get format field and offset information from either
127+
attributes according to the IAccessible2 specification
128+
(for LibreOffice >= 24.2) or from legacy custom
129+
text attributes (used by LibreOffice <= 7.6 and Apache OpenOffice).
130+
:param offset: Character offset for which to retrieve the
131+
attributes.
132+
:param formatConfig: Format configuration.
133+
:param calculateOffsets: Whether to calculate offsets.
134+
:return: Format field containing the text attribute information
135+
and start and end offset of the attribute run.
136+
"""
137+
obj = self.obj
138+
try:
139+
startOffset, endOffset, attribsString = obj.IAccessibleTextObject.attributes(offset)
140+
except COMError:
141+
log.debugWarning("could not get attributes", exc_info=True)
142+
return textInfos.FormatField(), (self._startOffset, self._endOffset)
143+
144+
if not attribsString and offset > 0:
145+
try:
146+
attribsString = obj.IAccessibleTextObject.attributes(offset - 1)[2]
147+
except COMError:
148+
pass
149+
150+
# LibreOffice >= 24.2 uses IAccessible2 text attributes, earlier versions use
151+
# custom attributes, with the attributes string starting with "Version:1;"
152+
if attribsString and attribsString.startswith('Version:1;'):
153+
formatField = self._getFormatFieldFromLegacyAttributesString(
154+
attribsString,
155+
offset
156+
)
157+
else:
158+
formatField, (startOffset, endOffset) = super()._getFormatFieldAndOffsets(
159+
offset,
160+
formatConfig,
161+
calculateOffsets
162+
)
163+
164+
return formatField, (startOffset, endOffset)
165+
166+
def _getFormatFieldAndOffsets(
167+
self,
168+
offset: int,
169+
formatConfig: Optional[dict],
170+
calculateOffsets: bool = True
171+
) -> tuple[textInfos.FormatField, tuple[int, int]]:
172+
formatField, (startOffset, endOffset) = self._getFormatFieldAndOffsetsFromAttributes(
173+
offset,
174+
formatConfig,
175+
calculateOffsets
176+
)
177+
obj = self.obj
178+
104179
# optimisation: Assume a hyperlink occupies a full attribute run.
105180
try:
106181
if obj.IAccessibleTextObject.QueryInterface(
@@ -110,12 +185,6 @@ def _getFormatFieldAndOffsets(self,offset,formatConfig,calculateOffsets=True):
110185
except COMError:
111186
pass
112187

113-
if offset == 0:
114-
# Only include the list item prefix on the first line of the paragraph.
115-
numbering = formatField.get("Numbering")
116-
if numbering:
117-
formatField["line-prefix"] = numbering.get("NumberingPrefix") or numbering.get("BulletChar")
118-
119188
if obj.hasFocus:
120189
# Symphony exposes some information for the caret position as attributes on the document object.
121190
# optimisation: Use the tree interceptor to get the document.
@@ -134,7 +203,7 @@ def _getFormatFieldAndOffsets(self,offset,formatConfig,calculateOffsets=True):
134203
except KeyError:
135204
pass
136205

137-
return formatField,(startOffset,endOffset)
206+
return formatField, (startOffset, endOffset)
138207

139208
def _getLineOffsets(self, offset):
140209
start, end = super(SymphonyTextInfo, self)._getLineOffsets(offset)

user_docs/en/changes.t2t

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ This option now announces additional relevant information about an object when t
3030
- Reporting of object shortcut keys has been improved. (#10807, @CyrilleB79)
3131
- The SAPI4 synthesizer now properly supports volume, rate and pitch changes embedded in speech. (#15271, @LeonarddeR)
3232
- Multi line state is now correctly reported in applications using Java Access Bridge. (#14609)
33-
- In LibreOffice, words deleted using the ``control+backspace`` keyboard shortcut are now also properly announced when the deleted word is followed by whitespace (like spaces and tabs). (#15436)
34-
- In LibreOffice, announcement of the status bar using the ``NVDA+end`` keyboard shortcut now also works for dialogs in LibreOffice version 24.2 and newer. (#15591)
33+
- In LibreOffice, words deleted using the ``control+backspace`` keyboard shortcut are now also properly announced when the deleted word is followed by whitespace (like spaces and tabs). (#15436, @michaelweghorn)
34+
- In LibreOffice, announcement of the status bar using the ``NVDA+end`` keyboard shortcut now also works for dialogs in LibreOffice version 24.2 and newer. (#15591, @michaelweghorn)
35+
- In LibreOffice, text attributes according to the [IAccessible2 text attributes specification https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes] are supported, which is required to support announcement of text attributes in LibreOffice versions 24.2 and above.
36+
This makes the announcement of spelling errors work when announcing a line in Writer. (#15648, @michaelweghorn)
3537
- In Microsoft Excel with UIA disabled, braille is updated, and the active cell content is spoken, when ``control+y``, ``control+z`` or ``alt+backspace`` is pressed. (15547)
3638
- In Microsoft Word with UIA disabled braille is updated when ``control+v``, ``control+x``, ``control+y``, ``control+z``, ``alt+backspace``, ``backspace`` or ``control+backspace`` is pressed.
3739
It is also updated with UIA enabled, when typing text and braille is tethered to review and review follows caret. (#3276)

0 commit comments

Comments
 (0)