[orca] Move some speech generator methods to superclass; fix children-changed bug
- From: Joanmarie Diggs <joanied src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [orca] Move some speech generator methods to superclass; fix children-changed bug
- Date: Tue, 16 Feb 2016 10:51:27 +0000 (UTC)
commit 6665ad900a31a4c2b5970b41e2ef1355e7d70365
Author: Joanmarie Diggs <jdiggs igalia com>
Date: Tue Feb 16 05:47:00 2016 -0500
Move some speech generator methods to superclass; fix children-changed bug
src/orca/generator.py | 41 +++++++++++++++
src/orca/script_utilities.py | 26 ++++++++++
src/orca/scripts/apps/soffice/script.py | 57 ++++++++-------------
src/orca/speech_generator.py | 83 ++++++-------------------------
4 files changed, 105 insertions(+), 102 deletions(-)
---
diff --git a/src/orca/generator.py b/src/orca/generator.py
index 5adda16..9472e10 100644
--- a/src/orca/generator.py
+++ b/src/orca/generator.py
@@ -592,6 +592,22 @@ class Generator:
result.append(indicators[0])
return result
+ def _generateMultiselectableState(self, obj, **args):
+ """Returns an array of strings (and possibly voice and audio
+ specifications) that represent the multiselectable state of
+ the object. This is typically for list boxes. If the object
+ is not multiselectable, an empty array will be returned.
+ """
+
+ result = []
+ if not args.get('mode', None):
+ args['mode'] = self._mode
+ args['stringType'] = 'multiselect'
+ if obj.getState().contains(pyatspi.STATE_MULTISELECTABLE) \
+ and obj.childCount:
+ result.append(self._script.formatting.getString(**args))
+ return result
+
#####################################################################
# #
# Table interface information #
@@ -1035,3 +1051,28 @@ class Generator:
def _generateProgressBarValue(self, obj, **args):
return []
+
+ def _getAlternativeRole(self, obj, **args):
+ if self._script.utilities.isMath(obj):
+ if self._script.utilities.isMathFraction(obj):
+ return 'ROLE_MATH_FRACTION'
+ if self._script.utilities.isMathRoot(obj):
+ return 'ROLE_MATH_ROOT'
+ if self._script.utilities.isMathSubOrSuperScript(obj):
+ return 'ROLE_MATH_SCRIPT_SUBSUPER'
+ if self._script.utilities.isMathUnderOrOverScript(obj):
+ return 'ROLE_MATH_SCRIPT_UNDEROVER'
+ if self._script.utilities.isMathMultiScript(obj):
+ return 'ROLE_MATH_MULTISCRIPT'
+ if self._script.utilities.isMathEnclose(obj):
+ return 'ROLE_MATH_ENCLOSED'
+ if self._script.utilities.isMathFenced(obj):
+ return 'ROLE_MATH_FENCED'
+ if self._script.utilities.isMathTable(obj):
+ return 'ROLE_MATH_TABLE'
+ if self._script.utilities.isMathTableRow(obj):
+ return 'ROLE_MATH_TABLE_ROW'
+ if self._script.utilities.isStatic(obj):
+ return 'ROLE_STATIC'
+
+ return args.get('role', obj.getRole())
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index 339822c..da32a99 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -3340,6 +3340,17 @@ class Utilities:
row, col = table.getRowAtIndex(index), table.getColumnAtIndex(index)
return table.getRowExtentAt(row, col), table.getColumnExtentAt(row, col)
+ def rowAndColumnCount(self, obj):
+ if not (obj and obj.getRole() == pyatspi.ROLE_TABLE):
+ return -1, -1
+
+ try:
+ table = obj.queryTable()
+ except:
+ return -1, -1
+
+ return table.nRows, table.nColumns
+
def cellForCoordinates(self, obj, row, column):
try:
table = obj.queryTable()
@@ -3348,6 +3359,21 @@ class Utilities:
return table.getAccessibleAt(row, column)
+ def isLastCell(self, obj):
+ if not (obj and obj.getRole() == pyatspi.ROLE_TABLE_CELL):
+ return False
+
+ isTable = lambda x: x and 'Table' in pyatspi.listInterfaces(x)
+ parent = pyatspi.findAncestor(obj, isTable)
+ try:
+ table = parent.queryTable()
+ except:
+ return False
+
+ index = self.cellIndex(obj)
+ row, col = table.getRowAtIndex(index), table.getColumnAtIndex(index)
+ return row + 1 == table.nRows and col + 1 == table.nColumns
+
def isNonUniformTable(self, obj):
try:
table = obj.queryTable()
diff --git a/src/orca/scripts/apps/soffice/script.py b/src/orca/scripts/apps/soffice/script.py
index 482f2bb..7f0e868 100644
--- a/src/orca/scripts/apps/soffice/script.py
+++ b/src/orca/scripts/apps/soffice/script.py
@@ -595,10 +595,16 @@ class Script(default.Script):
# Pass the event onto the parent class to be handled in the default way.
default.Script.locusOfFocusChanged(self, event,
oldLocusOfFocus, newLocusOfFocus)
+ if not newLocusOfFocus:
+ return
+ cell = None
if self.utilities.isTextDocumentCell(newLocusOfFocus):
- row, column, table = \
- self.utilities.getRowColumnAndTable(newLocusOfFocus.parent)
+ cell = newLocusOfFocus
+ elif self.utilities.isTextDocumentCell(newLocusOfFocus.parent):
+ cell = newLocusOfFocus.parent
+ if cell:
+ row, column = self.utilities.coordinatesForCell(cell)
self.pointOfReference['lastRow'] = row
self.pointOfReference['lastColumn'] = column
@@ -661,47 +667,28 @@ class Script(default.Script):
default.Script.onActiveDescendantChanged(self, event)
def onChildrenChanged(self, event):
- """Called when a child node has changed.
-
- Arguments:
- - event: the Event
- """
-
- try:
- anyDataRole = event.any_data.getRole()
- except:
- return
+ """Callback for object:children-changed accessibility events."""
- if anyDataRole == pyatspi.ROLE_TABLE:
- if self.utilities.isSpreadSheetCell(event.any_data):
- orca.setLocusOfFocus(event, event.any_data)
+ if self.utilities.isSpreadSheetCell(event.any_data):
+ orca.setLocusOfFocus(event, event.any_data)
return
- if anyDataRole == pyatspi.ROLE_TABLE_CELL:
+ if self.utilities.isLastCell(event.any_data):
activeRow = self.pointOfReference.get('lastRow', -1)
activeCol = self.pointOfReference.get('lastColumn', -1)
if activeRow < 0 or activeCol < 0:
return
- eventRow, eventCol, table = \
- self.utilities.getRowColumnAndTable(event.any_data)
- try:
- itable = table.queryTable()
- except NotImplementedError:
- return
-
- if eventRow == itable.nRows - 1 and eventCol == itable.nColumns - 1:
- fullMessage = briefMessage = ""
- voice = self.voices.get(settings.SYSTEM_VOICE)
- if activeRow == itable.nRows:
- fullMessage = messages.TABLE_ROW_DELETED_FROM_END
- briefMessage = messages.TABLE_ROW_DELETED
- else:
- fullMessage = messages.TABLE_ROW_INSERTED_AT_END
- briefMessage = messages.TABLE_ROW_INSERTED
- if fullMessage:
- self.presentMessage(fullMessage, briefMessage, voice)
- return
+ self.utilities.handleUndoTextEvent(event)
+ rowCount, colCount = self.utilities.rowAndColumnCount(event.source)
+ if activeRow == rowCount:
+ full = messages.TABLE_ROW_DELETED_FROM_END
+ brief = messages.TABLE_ROW_DELETED
+ else:
+ full = messages.TABLE_ROW_INSERTED_AT_END
+ brief = messages.TABLE_ROW_INSERTED
+ self.presentMessage(full, brief)
+ return
default.Script.onChildrenChanged(self, event)
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index c50ea6e..b525a7f 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -465,19 +465,15 @@ class SpeechGenerator(generator.Generator):
def _generateMultiselectableState(self, obj, **args):
"""Returns an array of strings (and possibly voice and audio
specifications) that represent the multiselectable state of
- the object. This is typically for check boxes. If the object
+ the object. This is typically for list boxes. If the object
is not multiselectable, an empty array will be returned.
"""
if _settingsManager.getSetting('onlySpeakDisplayedText'):
return []
- result = []
acss = self.voice(STATE)
- if obj.getState().contains(pyatspi.STATE_MULTISELECTABLE) \
- and obj.childCount:
- result.append(self._script.formatting.getString(
- mode='speech',
- stringType='multiselect'))
+ result = super()._generateMultiselectableState(obj, **args)
+ if result:
result.extend(acss)
return result
@@ -928,27 +924,13 @@ class SpeechGenerator(generator.Generator):
if _settingsManager.getSetting('onlySpeakDisplayedText'):
return []
- result = []
- acss = self.voice(SYSTEM)
if _settingsManager.getSetting('speechVerbosityLevel') \
- == settings.VERBOSITY_LEVEL_VERBOSE:
- if obj.getRole() == pyatspi.ROLE_TABLE_CELL:
- cell = obj
- else:
- cell = self._script.utilities.ancestorWithRole(
- obj, [pyatspi.ROLE_TABLE_CELL], [pyatspi.ROLE_FRAME])
- try:
- table = cell.parent.queryTable()
- except:
- pass
- else:
- index = self._script.utilities.cellIndex(cell)
- row = table.getRowAtIndex(index)
- col = table.getColumnAtIndex(index)
- if row + 1 == table.nRows and col + 1 == table.nColumns:
- result.append(messages.TABLE_END)
- if result:
- result.extend(acss)
+ != settings.VERBOSITY_LEVEL_VERBOSE:
+ return []
+
+ if self._script.utilities.isLastCell(obj):
+ result = [messages.TABLE_END]
+ result.extend(self.voice(SYSTEM))
return result
#####################################################################
@@ -1315,21 +1297,13 @@ class SpeechGenerator(generator.Generator):
if _settingsManager.getSetting('onlySpeakDisplayedText'):
return []
- result = []
- acss = self.voice(SYSTEM)
- try:
- value = obj.queryValue()
- except NotImplementedError:
- pass
- else:
- percentValue = \
- (value.currentValue
- / (value.maximumValue - value.minimumValue)) \
- * 100.0
- result.append(messages.percentage(percentValue))
- if result:
- result.extend(acss)
- return result
+ percentValue = self._script.utilities.getValueAsPercent(obj)
+ if percentValue is not None:
+ result = [percentValue]
+ result.extend(self.voice(SYSTEM))
+ return result
+
+ return []
#####################################################################
# #
@@ -2252,31 +2226,6 @@ class SpeechGenerator(generator.Generator):
# #
#####################################################################
- def _getAlternativeRole(self, obj, **args):
- if self._script.utilities.isMath(obj):
- if self._script.utilities.isMathFraction(obj):
- return 'ROLE_MATH_FRACTION'
- if self._script.utilities.isMathRoot(obj):
- return 'ROLE_MATH_ROOT'
- if self._script.utilities.isMathSubOrSuperScript(obj):
- return 'ROLE_MATH_SCRIPT_SUBSUPER'
- if self._script.utilities.isMathUnderOrOverScript(obj):
- return 'ROLE_MATH_SCRIPT_UNDEROVER'
- if self._script.utilities.isMathMultiScript(obj):
- return 'ROLE_MATH_MULTISCRIPT'
- if self._script.utilities.isMathEnclose(obj):
- return 'ROLE_MATH_ENCLOSED'
- if self._script.utilities.isMathFenced(obj):
- return 'ROLE_MATH_FENCED'
- if self._script.utilities.isMathTable(obj):
- return 'ROLE_MATH_TABLE'
- if self._script.utilities.isMathTableRow(obj):
- return 'ROLE_MATH_TABLE_ROW'
- if self._script.utilities.isStatic(obj):
- return 'ROLE_STATIC'
-
- return args.get('role', obj.getRole())
-
def _generatePause(self, obj, **args):
if not _settingsManager.getSetting('enablePauseBreaks') \
or args.get('eliminatePauses', False):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]