[orca] Begin cleaning up LibreOffice's table-related support
- From: Joanmarie Diggs <joanied src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [orca] Begin cleaning up LibreOffice's table-related support
- Date: Tue, 2 Aug 2016 23:55:08 +0000 (UTC)
commit 6e0b03fc67645acafac23110c460c4fcf62db424
Author: Joanmarie Diggs <jdiggs igalia com>
Date: Tue Aug 2 19:54:39 2016 -0400
Begin cleaning up LibreOffice's table-related support
src/orca/script_utilities.py | 96 ++++++++++++++-
src/orca/scripts/apps/soffice/Makefile.am | 3 +-
src/orca/scripts/apps/soffice/braille_generator.py | 128 ++++++--------------
src/orca/scripts/apps/soffice/script.py | 41 +++----
src/orca/scripts/apps/soffice/script_utilities.py | 88 ++++---------
src/orca/scripts/apps/soffice/speech_generator.py | 33 +++---
.../scripts/apps/soffice/structural_navigation.py | 100 ---------------
src/orca/structural_navigation.py | 2 +-
8 files changed, 195 insertions(+), 296 deletions(-)
---
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index db252f0..e8c1c14 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -1019,6 +1019,22 @@ class Utilities:
return pyatspi.findAncestor(obj, self.isSpreadSheetTable)
+ def cellColumnChanged(self, cell):
+ row, column = self._script.utilities.coordinatesForCell(cell)
+ if column == -1:
+ return False
+
+ lastColumn = self._script.pointOfReference.get("lastColumn")
+ return column != lastColumn
+
+ def cellRowChanged(self, cell):
+ row, column = self._script.utilities.coordinatesForCell(cell)
+ if row == -1:
+ return False
+
+ lastRow = self._script.pointOfReference.get("lastRow")
+ return row != lastRow
+
def shouldReadFullRow(self, obj):
table = self.getTable(obj)
if not table:
@@ -2173,6 +2189,9 @@ class Utilities:
if textContents and self._script.pointOfReference.get('entireDocumentSelected'):
return textContents, startOffset, endOffset
+ if self.isSpreadSheetCell(obj):
+ return textContents, startOffset, endOffset
+
prevObj = self.findPreviousObject(obj)
while prevObj:
if self.queryNonEmptyText(prevObj):
@@ -2433,6 +2452,9 @@ class Utilities:
return obj, offset
+ def getFirstCaretPosition(self, obj):
+ return obj, 0
+
def setCaretPosition(self, obj, offset, documentFrame=None):
orca.setLocusOfFocus(None, obj, False)
self.setCaretOffset(obj, offset)
@@ -3482,13 +3504,83 @@ class Utilities:
return table.nRows, table.nColumns
- def cellForCoordinates(self, obj, row, column):
+ def _getTableRowRange(self, obj):
+ rowCount, columnCount = self.rowAndColumnCount(obj)
+ startIndex, endIndex = 0, columnCount
+ if not self.isSpreadSheetCell(obj):
+ return startIndex, endIndex
+
+ parent = self._script.utilities.getTable(obj)
+ try:
+ component = parent.queryComponent()
+ except:
+ msg = "ERROR: Exception querying component interface of %s" % parent
+ debug.println(debug.LEVEL_INFO, msg, True)
+ return startIndex, endIndex
+
+ x, y, width, height = component.getExtents(pyatspi.DESKTOP_COORDS)
+ cell = component.getAccessibleAtPoint(x+1, y, pyatspi.DESKTOP_COORDS)
+ if cell:
+ row, column = self.coordinatesForCell(cell)
+ startIndex = column
+
+ cell = component.getAccessibleAtPoint(x+width-1, y, pyatspi.DESKTOP_COORDS)
+ if cell:
+ row, column = self.coordinatesForCell(cell)
+ endIndex = column + 1
+
+ return startIndex, endIndex
+
+ def getShowingCellsInSameRow(self, obj):
+ parent = self._script.utilities.getTable(obj)
+ try:
+ table = parent.queryTable()
+ except:
+ msg = "ERROR: Exception querying table interface of %s" % parent
+ debug.println(debug.LEVEL_INFO, msg, True)
+ return []
+
+ row, column = self.coordinatesForCell(obj)
+ if row == -1:
+ return []
+
+ startIndex, endIndex = self._getTableRowRange(obj)
+ if startIndex == endIndex:
+ return []
+
+ cells = []
+ for i in range(startIndex, endIndex):
+ cell = table.getAccessibleAt(row, i)
+ try:
+ showing = cell.getState().contains(pyatspi.STATE_SHOWING)
+ except:
+ continue
+ if showing:
+ cells.append(cell)
+
+ return cells
+
+ def cellForCoordinates(self, obj, row, column, showingOnly=False):
try:
table = obj.queryTable()
except:
return None
- return table.getAccessibleAt(row, column)
+ cell = table.getAccessibleAt(row, column)
+ if not showingOnly:
+ return cell
+
+ try:
+ state = cell.getState()
+ except:
+ msg = "ERROR: Exception getting state of %s" % cell
+ debug.println(debug.LEVEL_INFO, msg, True)
+ return None
+
+ if not state().contains(pyatspi.STATE_SHOWING):
+ return None
+
+ return cell
def isLastCell(self, obj):
try:
diff --git a/src/orca/scripts/apps/soffice/Makefile.am b/src/orca/scripts/apps/soffice/Makefile.am
index 9ddc441..145f91e 100644
--- a/src/orca/scripts/apps/soffice/Makefile.am
+++ b/src/orca/scripts/apps/soffice/Makefile.am
@@ -5,8 +5,7 @@ orca_python_PYTHON = \
script.py \
script_utilities.py \
speech_generator.py \
- spellcheck.py \
- structural_navigation.py
+ spellcheck.py
orca_pythondir=$(pkgpythondir)/scripts/apps/soffice
diff --git a/src/orca/scripts/apps/soffice/braille_generator.py
b/src/orca/scripts/apps/soffice/braille_generator.py
index c12e8aa..21c662e 100644
--- a/src/orca/scripts/apps/soffice/braille_generator.py
+++ b/src/orca/scripts/apps/soffice/braille_generator.py
@@ -39,7 +39,7 @@ class BrailleGenerator(braille_generator.BrailleGenerator):
# pylint: disable-msg=W0142
def __init__(self, script):
- braille_generator.BrailleGenerator.__init__(self, script)
+ super().__init__(script)
def _generateRoleName(self, obj, **args):
if self._script.utilities.isDocument(obj):
@@ -88,7 +88,17 @@ class BrailleGenerator(braille_generator.BrailleGenerator):
return []
- def _generateSpreadSheetCell(self, obj, **args):
+ def _generateRealTableCell(self, obj, **args):
+ if not obj.childCount:
+ result = super()._generateRealTableCell(obj, **args)
+ else:
+ result = []
+ for child in obj:
+ result.extend(self.generate(child))
+
+ if not self._script.utilities.isSpreadSheetCell(obj):
+ return result
+
try:
objectText = self._script.utilities.substring(obj, 0, -1)
cellName = self._script.utilities.spreadSheetCellName(obj)
@@ -97,97 +107,27 @@ class BrailleGenerator(braille_generator.BrailleGenerator):
return [braille.Component(obj, " ".join((objectText, cellName)))]
- def _generateRealTableCell(self, obj, **args):
- """Get the speech for a table cell. If this isn't inside a
- spread sheet, just return the utterances returned by the default
- table cell speech handler.
-
- Arguments:
- - obj: the table cell
-
- Returns a list of utterances to be spoken for the object.
- """
- result = []
- if self._script.utilities.isSpreadSheetCell(obj):
- result.extend(self._generateSpreadSheetCell(obj, **args))
- else:
- # Check to see how many children this table cell has. If it's
- # just one (or none), then pass it on to the superclass to be
- # processed.
- #
- # If it's more than one, then get the speech for each child,
- # and call this method again.
- #
- if obj.childCount <= 1:
- result.extend(braille_generator.BrailleGenerator.\
- _generateRealTableCell(self, obj, **args))
- else:
- for child in obj:
- cellResult = self._generateRealTableCell(child, **args)
- if cellResult and result and self._mode == 'braille':
- result.append(braille.Region(
- object_properties.TABLE_CELL_DELIMITER_BRAILLE))
- result.extend(cellResult)
- return result
+ def _generateTableCellDelimiter(self, obj, **args):
+ return braille.Region(object_properties.TABLE_CELL_DELIMITER_BRAILLE)
def _generateTableCellRow(self, obj, **args):
- """Get the speech for a table row or cell depending on settings.
+ if not self._script.utilities.shouldReadFullRow(obj):
+ return self._generateRealTableCell(obj, **args)
- Arguments:
- - obj: the table cell
+ if not self._script.utilities.isSpreadSheetCell(obj):
+ return super()._generateTableCellRow(obj, **args)
+
+ cells = self._script.utilities.getShowingCellsInSameRow(obj)
+ if not cells:
+ return []
- Returns a list of utterances to be spoken for the object.
- """
result = []
- if self._script.utilities.isSpreadSheetCell(obj):
- # Adding in a check here to make sure that the parent is a
- # valid table. It's possible that the parent could be a
- # table cell too (see bug #351501).
- #
- parent = obj.parent
- parentTable = parent.queryTable()
- readFullRow = self._script.utilities.shouldReadFullRow(obj)
- if readFullRow and parentTable:
- index = self._script.utilities.cellIndex(obj)
- row = parentTable.getRowAtIndex(index)
- column = parentTable.getColumnAtIndex(index)
- # This is an indication of whether we should present all the
- # table cells (the user has moved focus up or down a row),
- # or just the current one (focus has moved left or right in
- # the same row).
- #
- presentAll = True
- if "lastRow" in self._script.pointOfReference and \
- "lastColumn" in self._script.pointOfReference:
- pointOfReference = self._script.pointOfReference
- presentAll = \
- (self._mode == 'braille') \
- or ((pointOfReference["lastRow"] != row) \
- or ((row == 0 or row == parentTable.nRows-1) \
- and pointOfReference["lastColumn"] == column))
- if presentAll:
- [startIndex, endIndex] = \
- self._script.utilities.getTableRowRange(obj)
- for i in range(startIndex, endIndex):
- cell = parentTable.getAccessibleAt(row, i)
- showing = cell.getState().contains( \
- pyatspi.STATE_SHOWING)
- if showing:
- cellResult = self._generateRealTableCell(cell,
- **args)
- if cellResult and result \
- and self._mode == 'braille':
- result.append(braille.Region(
- object_properties.TABLE_CELL_DELIMITER_BRAILLE))
- result.extend(cellResult)
- else:
- result.extend(self._generateRealTableCell(obj, **args))
- else:
- result.extend(self._generateRealTableCell(obj, **args))
- else:
- result.extend(
- braille_generator.BrailleGenerator._generateTableCellRow(
- self, obj, **args))
+ for cell in cells:
+ cellResult = self._generateRealTableCell(cell, **args)
+ if cellResult and result:
+ result.append(self._generateTableCellDelimiter(obj, **args))
+ result.extend(cellResult)
+
return result
def _generateChildTab(self, obj, **args):
@@ -211,6 +151,18 @@ class BrailleGenerator(braille_generator.BrailleGenerator):
result.extend(self.generate(tab, **args))
return result
+ def _generateAncestors(self, obj, **args):
+ if self._script._lastCommandWasStructNav:
+ return []
+
+ return super()._generateAncestors(obj, **args)
+
+ def _generateIncludeContext(self, obj, **args):
+ if self._script._lastCommandWasStructNav:
+ return False
+
+ return super()._generateIncludeContext(obj, **args)
+
def generateBraille(self, obj, **args):
args['useDefaultFormatting'] = self._script.utilities.isNonFocusableList(obj)
oldRole = self._overrideRole(self._getAlternativeRole(obj, **args), args)
diff --git a/src/orca/scripts/apps/soffice/script.py b/src/orca/scripts/apps/soffice/script.py
index f1b3b3e..8eb1540 100644
--- a/src/orca/scripts/apps/soffice/script.py
+++ b/src/orca/scripts/apps/soffice/script.py
@@ -42,13 +42,13 @@ import orca.orca_state as orca_state
import orca.speech as speech
import orca.settings as settings
import orca.settings_manager as settings_manager
+import orca.structural_navigation as structural_navigation
from .braille_generator import BrailleGenerator
from .formatting import Formatting
from .script_utilities import Utilities
from .spellcheck import SpellCheck
from .speech_generator import SpeechGenerator
-from .structural_navigation import StructuralNavigation
_settingsManager = settings_manager.getManager()
@@ -106,14 +106,14 @@ class Script(default.Script):
"""Returns the 'structural navigation' class for this script.
"""
types = self.getEnabledStructuralNavigationTypes()
- return StructuralNavigation(self, types, enabled=False)
+ return structural_navigation.StructuralNavigation(self, types, enabled=False)
def getEnabledStructuralNavigationTypes(self):
"""Returns a list of the structural navigation object types
enabled in this script.
"""
- enabledTypes = [StructuralNavigation.TABLE_CELL]
+ enabledTypes = [structural_navigation.StructuralNavigation.TABLE_CELL]
return enabledTypes
@@ -290,27 +290,6 @@ class Script(default.Script):
prefs.update(self.spellcheck.getPreferencesFromGUI())
return prefs
- def isStructuralNavigationCommand(self, inputEvent=None):
- """Checks to see if the inputEvent was a structural navigation
- command. This is necessary to prevent double-presentation of
- items. [[[TODO - JD: Perhaps this should be moved to default.py]]]
-
- Arguments:
- - inputEvent: The input event to examine. If none is provided,
- orca_state.lastInputEvent will be used.
-
- Returns True if inputEvent is a structural navigation command
- enabled in this script.
- """
-
- inputEvent = inputEvent or orca_state.lastInputEvent
- if isinstance(inputEvent, input_event.KeyboardEvent):
- if self.structuralNavigation.keyBindings.\
- getInputHandler(inputEvent):
- return True
-
- return False
-
def doWhereAmI(self, inputEvent, basicOnly):
"""Performs the whereAmI operation."""
@@ -319,6 +298,14 @@ class Script(default.Script):
super().doWhereAmI(inputEvent, basicOnly)
+ def presentObject(self, obj, offset=0):
+ if not self._lastCommandWasStructNav:
+ super().presentObject(obj, offset)
+ return
+
+ utterances = self.speechGenerator.generateSpeech(obj)
+ speech.speak(utterances)
+
def panBrailleLeft(self, inputEvent=None, panAmount=0):
"""In document content, we want to use the panning keys to browse the
entire document.
@@ -745,7 +732,7 @@ class Script(default.Script):
if self._inSayAll:
return
- if self.isStructuralNavigationCommand():
+ if self._lastCommandWasStructNav:
return
if not event.detail1:
@@ -810,7 +797,7 @@ class Script(default.Script):
if self.utilities._flowsFromOrToSelection(event.source):
return
- if self.isStructuralNavigationCommand():
+ if self._lastCommandWasStructNav:
return
if self.utilities.isSpreadSheetCell(orca_state.locusOfFocus):
@@ -936,5 +923,7 @@ class Script(default.Script):
def onWindowDeactivated(self, event):
"""Callback for window:deactivate accessibility events."""
+ self._lastCommandWasStructNav = False
+
super().onWindowDeactivated(event)
self.spellcheck.deactivate()
diff --git a/src/orca/scripts/apps/soffice/script_utilities.py
b/src/orca/scripts/apps/soffice/script_utilities.py
index 6cf6c8c..308605d 100644
--- a/src/orca/scripts/apps/soffice/script_utilities.py
+++ b/src/orca/scripts/apps/soffice/script_utilities.py
@@ -96,6 +96,11 @@ class Utilities(script_utilities.Utilities):
and (self.isSpreadSheetCell(obj) or self.isTextDocumentCell(obj)):
return ""
+ # More bogusness from (at least) Calc combined with the aforementioned
+ # fallback-to-name behavior....
+ if self.isDocument(obj) and text == obj.name and obj.name.startswith("file:///"):
+ return ""
+
# TODO - JD: Once the VCL script is completed and subclasses the
# appropriate toolkit scripts, this should not be needed.
if obj.parent and obj.parent.getRole() == pyatspi.ROLE_LIST_BOX:
@@ -156,67 +161,6 @@ class Utilities(script_utilities.Utilities):
return row, column, table
- def getShowingCellsInRow(self, obj):
- row, column, parentTable = self.getRowColumnAndTable(obj)
- try:
- table = parentTable.queryTable()
- except:
- return []
-
- startIndex, endIndex = self.getTableRowRange(obj)
- cells = []
- for i in range(startIndex, endIndex):
- cell = table.getAccessibleAt(row, i)
- try:
- showing = cell.getState().contains(pyatspi.STATE_SHOWING)
- except:
- continue
- if showing:
- cells.append(cell)
-
- return cells
-
- def getTableRowRange(self, obj):
- """If this is spread sheet cell, return the start and end indices
- of the spread sheet cells for the table that obj is in. Otherwise
- return the complete range (0, parentTable.nColumns).
-
- Arguments:
- - obj: a table cell.
-
- Returns the start and end table cell indices.
- """
-
- parent = obj.parent
- try:
- parentTable = parent.queryTable()
- except:
- return [-1, -1]
-
- startIndex = 0
- endIndex = parentTable.nColumns
-
- if self.isSpreadSheetCell(obj):
- extents = parent.queryComponent().getExtents(pyatspi.DESKTOP_COORDS)
- y = extents.y
- leftX = extents.x + 1
- leftCell = \
- parent.queryComponent().getAccessibleAtPoint(leftX, y, 0)
- if leftCell:
- table = leftCell.parent.queryTable()
- index = self.cellIndex(leftCell)
- startIndex = table.getColumnAtIndex(index)
-
- rightX = extents.x + extents.width - 1
- rightCell = \
- parent.queryComponent().getAccessibleAtPoint(rightX, y, 0)
- if rightCell:
- table = rightCell.parent.queryTable()
- index = self.cellIndex(rightCell)
- endIndex = table.getColumnAtIndex(index) + 1
-
- return [startIndex, endIndex]
-
def rowHeadersForCell(self, obj):
rowHeader, colHeader = self.getDynamicHeadersForCell(obj)
if rowHeader:
@@ -762,3 +706,25 @@ class Utilities(script_utilities.Utilities):
children.append(obj[i])
return children
+
+ def getFirstCaretPosition(self, obj):
+ try:
+ text = obj.queryText()
+ except:
+ if obj and obj.childCount:
+ return self.getFirstCaretPosition(obj[0])
+
+ return obj, 0
+
+ def shouldReadFullRow(self, obj):
+ if self._script._lastCommandWasStructNav:
+ return False
+
+ lastKey, mods = self.lastKeyAndModifiers()
+ if lastKey in ["Tab", "ISO_Left_Tab"]:
+ return False
+
+ if not super().shouldReadFullRow(obj):
+ return False
+
+ return self.cellRowChanged(obj)
diff --git a/src/orca/scripts/apps/soffice/speech_generator.py
b/src/orca/scripts/apps/soffice/speech_generator.py
index 703bd32..88e6231 100644
--- a/src/orca/scripts/apps/soffice/speech_generator.py
+++ b/src/orca/scripts/apps/soffice/speech_generator.py
@@ -361,10 +361,12 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
Returns a list of utterances to be spoken for the object.
"""
- result = speech_generator.SpeechGenerator._generateRealTableCell(
- self, obj, **args)
+ result = super()._generateRealTableCell(obj, **args)
if not self._script.utilities.isSpreadSheetCell(obj):
+ if self._script._lastCommandWasStructNav:
+ return result
+
if _settingsManager.getSetting('speakCellCoordinates'):
result.append(obj.name)
return result
@@ -393,24 +395,17 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
return result
def _generateTableCellRow(self, obj, **args):
- """Get the speech for a table cell row if the user wants to hear
- the full row and if the row has actually changed."""
+ if not self._script.utilities.shouldReadFullRow(obj):
+ return self._generateRealTableCell(obj, **args)
- speakFullRow = self._script.utilities.shouldReadFullRow(obj)
- if speakFullRow:
- row, column, table = \
- self._script.utilities.getRowColumnAndTable(obj)
- lastRow = self._script.pointOfReference.get("lastRow")
- if lastRow == -1 and self._script.utilities.isSpreadSheetCell(obj):
- speakFullRow = False
- else:
- speakFullRow = row != lastRow
+ if not self._script.utilities.isSpreadSheetCell(obj):
+ return super()._generateTableCellRow(obj, **args)
- if not speakFullRow:
- return self._generateRealTableCell(obj, **args)
+ cells = self._script.utilities.getShowingCellsInSameRow(obj)
+ if not cells:
+ return []
result = []
- cells = self._script.utilities.getShowingCellsInRow(obj)
for cell in cells:
result.extend(self._generateRealTableCell(cell, **args))
@@ -424,6 +419,9 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
dialog).
"""
+ if self._script._lastCommandWasStructNav:
+ return []
+
topLevel = self._script.utilities.topLevelObject(obj)
if topLevel and topLevel.getRole() == pyatspi.ROLE_DIALOG:
return []
@@ -468,6 +466,9 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
if self._script.utilities.isSpreadSheetCell(obj):
return []
+ if self._script._lastCommandWasStructNav:
+ return []
+
return super()._generateUnselectedCell(obj, **args)
def generateSpeech(self, obj, **args):
diff --git a/src/orca/structural_navigation.py b/src/orca/structural_navigation.py
index e225a2b..3ed180b 100644
--- a/src/orca/structural_navigation.py
+++ b/src/orca/structural_navigation.py
@@ -1110,7 +1110,7 @@ class StructuralNavigation:
positioned.
"""
- return [obj, 0]
+ return self._script.utilities.getFirstCaretPosition(obj)
def _setCaretPosition(self, obj, characterOffset):
"""Sets the caret at the specified offset within obj."""
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]