[orca/570658] More work on braille generator



commit 8d18d21be4a19976eb582247bb8aa32e5793763d
Author: Willie Walker <william walker sun com>
Date:   Sat Jun 27 06:39:09 2009 -0400

    More work on braille generator
    
    Fixed a lot with row/column headers, text context, tree/list level, etc.
    Comboboxes and spin buttons still need work (the tests are failing).

 src/orca/braille.py                           |    1 -
 src/orca/braille_generator.py                 |   34 +++++++++++++---
 src/orca/default.py                           |   33 +++++++++++++++-
 src/orca/formatting.py                        |   50 +++++++++++++++++--------
 src/orca/generator.py                         |   30 +++++++++++++++
 src/orca/settings.py                          |   17 ++++++++-
 src/orca/speech_generator.py                  |   20 ----------
 test/keystrokes/gtk-demo/role_radio_button.py |   14 +++---
 8 files changed, 144 insertions(+), 55 deletions(-)
---
diff --git a/src/orca/braille.py b/src/orca/braille.py
index 63d08fc..cdb29e8 100644
--- a/src/orca/braille.py
+++ b/src/orca/braille.py
@@ -1120,7 +1120,6 @@ def refresh(panToCursor=True, targetCursorCell=0, getLinkMask=True):
         cursorCell += 1 # Normalize to 1-based offset
 
     logLine = "BRAILLE LINE:  '%s'" % string
-    print logLine
     debug.println(debug.LEVEL_INFO, logLine)
     log.info(logLine.encode("UTF-8"))
     logLine = "     VISIBLE:  '%s', cursor=%d" % \
diff --git a/src/orca/braille_generator.py b/src/orca/braille_generator.py
index 2dd83eb..033c669 100644
--- a/src/orca/braille_generator.py
+++ b/src/orca/braille_generator.py
@@ -73,13 +73,13 @@ class BrailleGenerator(generator.Generator):
             args['formatType'] = 'focused'
         result = self.generate(obj, **args)
 
-        print "RESULTS:"
-        for region in result:
-            if isinstance(region, (braille.Component, braille.Text)) \
-               and region.accessible == obj:
-                print "    (*)", region
-            else:
-                print "   ", region
+        #print "RESULTS:"
+        #for region in result:
+        #    if isinstance(region, (braille.Component, braille.Text)) \
+        #       and region.accessible == obj:
+        #        print "    (*)", region
+        #    else:
+        #        print "   ", region
 
         # We guess at the focused region.  It's going to be a
         # Component or Text region whose accessible is the same
@@ -259,6 +259,26 @@ class BrailleGenerator(generator.Generator):
             result.append(textObj)
         return result
 
+    def _generateIncludeContext(self, obj, **args):
+        """Returns True or False to indicate whether context should be
+        included or not.
+        """
+        # For multiline text areas, we only show the context if we
+        # are on the very first line.  Otherwise, we show only the
+        # line.
+        #
+        include = True
+        try:
+            text = obj.queryText()
+        except NotImplementedError:
+            text = None
+        if text and self._script.isTextArea(obj):
+            [lineString, startOffset, endOffset] = text.getTextAtOffset(
+                text.caretOffset,
+                pyatspi.TEXT_BOUNDARY_LINE_START)
+            include = startOffset == 0
+        return include
+
     #####################################################################
     #                                                                   #
     # Other things for spacing                                          #
diff --git a/src/orca/default.py b/src/orca/default.py
index 4454776..5380bfd 100644
--- a/src/orca/default.py
+++ b/src/orca/default.py
@@ -75,6 +75,7 @@ class Script(script.Script):
     DISPLAYED_LABEL = 'displayedLabel'
     DISPLAYED_TEXT = 'displayedText'
     KEY_BINDING = 'keyBinding'
+    NESTING_LEVEL = 'nestingLevel'
     NODE_LEVEL = 'nodeLevel'
 
     def __init__(self, app):
@@ -6950,6 +6951,32 @@ class Script(script.Script):
 
         return [content.encode("UTF-8"), text.caretOffset, startOffset]
 
+    def getNestingLevel(self, obj):
+        """Determines the nesting level of this object in a list.  If this
+        object is not in a list relation, then 0 will be returned.
+
+        Arguments:
+        -obj: the Accessible object
+        """
+
+        if not obj:
+            return 0
+
+        try:
+            return self.generatorCache[self.NESTING_LEVEL][obj]
+        except:
+            if not self.generatorCache.has_key(self.NESTING_LEVEL):
+                self.generatorCache[self.NESTING_LEVEL] = {}
+
+        nestingLevel = 0
+        parent = obj.parent
+        while parent.parent.getRole() == pyatspi.ROLE_LIST:
+            nestingLevel += 1
+            parent = parent.parent
+
+        self.generatorCache[self.NESTING_LEVEL][obj] = nestingLevel
+        return self.generatorCache[self.NESTING_LEVEL][obj]
+
     def getNodeLevel(self, obj):
         """Determines the node level of this object if it is in a tree
         relation, with 0 being the top level node.  If this object is
@@ -6959,15 +6986,15 @@ class Script(script.Script):
         -obj: the Accessible object
         """
 
+        if not obj:
+            return -1
+
         try:
             return self.generatorCache[self.NODE_LEVEL][obj]
         except:
             if not self.generatorCache.has_key(self.NODE_LEVEL):
                 self.generatorCache[self.NODE_LEVEL] = {}
 
-        if not obj:
-            return -1
-
         nodes = []
         node = obj
         done = False
diff --git a/src/orca/formatting.py b/src/orca/formatting.py
index 5bef7b5..b22cc30 100644
--- a/src/orca/formatting.py
+++ b/src/orca/formatting.py
@@ -59,6 +59,7 @@ formatting = {
             'togglebutton' : settings.speechToggleButtonIndicators,
             'expansion'    : settings.speechExpansionIndicators,
             'nodelevel'    : settings.speechNodeLevelString,
+            'nestinglevel' : settings.speechNestingLevelString,
             'multiselect'  : settings.speechMultiSelectString,
         },
         'braille' : {
@@ -71,6 +72,7 @@ formatting = {
             'togglebutton' : settings.brailleToggleButtonIndicators,
             'expansion'    : settings.brailleExpansionIndicators,
             'nodelevel'    : settings.brailleNodeLevelString,
+            'nestinglevel' : settings.brailleNestingLevelString,
         },
     },
 
@@ -301,7 +303,6 @@ formatting = {
             },
     },
 
-
     ####################################################################
     #                                                                  #
     # Formatting for braille.                                          #
@@ -310,16 +311,30 @@ formatting = {
 
     'braille': {
         'prefix': {
-            'focused':   'ancestors\
-                         + (rowHeader and [Region(" " + asString(rowHeader))])\
-                         + (columnHeader and [Region(" " + asString(columnHeader))])\
-                         + (radioButtonGroup and [Region(" " + asString(radioButtonGroup))])\
-                         + [Region(" ")]',
-            'unfocused': 'ancestors\
-                         + (rowHeader and [Region(" " + asString(rowHeader))])\
-                         + (columnHeader and [Region(" " + asString(columnHeader))])\
-                         + (radioButtonGroup and [Region(" " + asString(radioButtonGroup))])\
-                         + [Region(" ")]',
+#            'focused':   'ancestors\
+#                         + (rowHeader and [Region(" " + asString(rowHeader))])\
+#                         + (columnHeader and [Region(" " + asString(columnHeader))])\
+#                         + (radioButtonGroup and [Region(" " + asString(radioButtonGroup))])\
+#                         + [Region(" ")]',
+#            'unfocused': 'ancestors\
+#                         + (rowHeader and [Region(" " + asString(rowHeader))])\
+#                         + (columnHeader and [Region(" " + asString(columnHeader))])\
+#                         + (radioButtonGroup and [Region(" " + asString(radioButtonGroup))])\
+#                         + [Region(" ")]',
+            'focused':   '(includeContext\
+                           and (ancestors\
+                                + (rowHeader and [Region(" " + asString(rowHeader))])\
+                                + (columnHeader and [Region(" " + asString(columnHeader))])\
+                                + (radioButtonGroup and [Region(" " + asString(radioButtonGroup))])\
+                                + [Region(" ")])\
+                           or [])',
+            'unfocused': '(includeContext\
+                           and (ancestors\
+                                + (rowHeader and [Region(" " + asString(rowHeader))])\
+                                + (columnHeader and [Region(" " + asString(columnHeader))])\
+                                + (radioButtonGroup and [Region(" " + asString(radioButtonGroup))])\
+                                + [Region(" ")])\
+                           or [])',
             },
         'suffix': {
             'focused':   '(nodeLevel and [Region(" " + asString(nodeLevel))])',
@@ -349,9 +364,10 @@ formatting = {
             },
         #pyatspi.ROLE_COLUMN_HEADER: 'default'
         pyatspi.ROLE_COMBO_BOX: {
-            'unfocused': '[label and Region(asString(label) + " "),\
-                           (comboBoxTextObj and Text(comboBoxTextObj[0])) or Component(obj, asString(displayedText)),\
-                           Region(" " + asString(roleName))]'
+            'unfocused': '(label and [Region(asString(label) + " ")])\
+                          + (comboBoxTextObj and [Text(comboBoxTextObj[0])])\
+                            or [Component(obj, asString(displayedText)),\
+                                Region(" " + asString(roleName))]'
             },
         #pyatspi.ROLE_DESKTOP_ICON: 'default'
         #pyatspi.ROLE_DIAL: 'default'
@@ -379,9 +395,11 @@ formatting = {
         #pyatspi.ROLE_LIST: 'default'
         pyatspi.ROLE_LIST_ITEM: {
             'focused':   '[Component(obj,\
-                                     asString(label + displayedText + expandableState + roleName + availability) + asString(accelerator))]',
+                                     asString(label + displayedText + expandableState + roleName + availability) + asString(accelerator))]\
+                          + nestingLevel',
             'unfocused': '[Component(obj,\
-                                     asString(label + displayedText + expandableState))]',
+                                     asString(label + displayedText + expandableState))]\
+                          + nestingLevel',
             },
         pyatspi.ROLE_MENU: {
             'focused':   '[Component(obj,\
diff --git a/src/orca/generator.py b/src/orca/generator.py
index 27e1539..a504a87 100644
--- a/src/orca/generator.py
+++ b/src/orca/generator.py
@@ -533,6 +533,14 @@ class Generator:
         it exists.  Otherwise, an empty array is returned.
         """
         result = []
+
+        # Do not return yourself as a header.
+        #
+        role = args.get('role', obj.getRole())
+        if role in [pyatspi.ROLE_ROW_HEADER,
+                    pyatspi.ROLE_TABLE_ROW_HEADER]:
+            return result
+
         if not args.get('mode', None):
             args['mode'] = self._mode
         try:
@@ -588,6 +596,14 @@ class Generator:
         is returned.
         """
         result = []
+
+        # Do not return yourself as a header.
+        #
+        role = args.get('role', obj.getRole())
+        if role in [pyatspi.ROLE_COLUMN_HEADER,
+                    pyatspi.ROLE_TABLE_COLUMN_HEADER]:
+            return result
+
         try:
             table = obj.parent.queryTable()
         except:
@@ -899,6 +915,20 @@ class Generator:
             pass
         return result
 
+    def _generateNestingLevel(self, obj, **args):
+        """Returns an array of strings for use by speech and braille that
+        represent the nesting level of an object in a list.
+        """
+        result = []
+        if not args.get('mode', None):
+            args['mode'] = self._mode
+        args['stringType'] = 'nestinglevel'
+        nestingLevel = self._script.getNestingLevel(obj)
+        if nestingLevel:
+            result.append(self._script.formatting.getString(**args)\
+                          % nestingLevel)
+        return result
+
     def _generateRadioButtonGroup(self, obj, **args):
         """Returns an array of strings for use by speech and braille that
         represents the radio button group label for the object, or an
diff --git a/src/orca/settings.py b/src/orca/settings.py
index 9fbf62b..8048d82 100644
--- a/src/orca/settings.py
+++ b/src/orca/settings.py
@@ -1257,6 +1257,13 @@ speechMultiSelectString = _("multi-select")
 #
 speechNodeLevelString = _("tree level %d")
 
+# Translators: this represents a list item in a document.
+# The nesting level is how 'deep' the item is (e.g., a
+# level of 2 represents a list item inside a list that's
+# inside another list). This is meant to be spoken.
+#
+speechNestingLevelString = _("Nesting level %d")
+
 # string to indicate end of printed line for braille displays:
 #
 disableBrailleEOL = False
@@ -1297,7 +1304,15 @@ brailleExpansionIndicators = [_("collapsed"), _("expanded")]
 # view (i.e., how many ancestors a node has).  It is meant to
 # be presented on a braille display.
 #
-brailleNodeLevelString = _("LEVEL %d")
+brailleNodeLevelString = _("TREE LEVEL %d")
+
+# Translators: this represents a list item in a document.
+# The nesting level is how 'deep' the item is (e.g., a
+# level of 2 represents a list item inside a list that's
+# inside another list).  It is meant to be presented on
+# the braille display.
+#
+brailleNestingLevelString = _("LEVEL %d")
 
 # String for delimiters between table cells
 #
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index 1162d52..4b347d8 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -1306,26 +1306,6 @@ class SpeechGenerator(generator.Generator):
 
         return result
 
-    def _generateNestingLevel(self, obj, **args):
-        """Returns an array of strings (and possibly voice and audio
-        specifications) that represent the nesting level of an object
-        in a list.
-        """
-        result = []
-        nestingLevel = 0
-        parent = obj.parent
-        while parent.parent.getRole() == pyatspi.ROLE_LIST:
-            nestingLevel += 1
-            parent = parent.parent
-        if nestingLevel:
-            # Translators: this represents a list item in a document.
-            # The nesting level is how 'deep' the item is (e.g., a
-            # level of 2 represents a list item inside a list that's
-            # inside another list).
-            #
-            result.append(_("Nesting level %d") % nestingLevel)
-        return result
-
     def _generateDefaultButton(self, obj, **args):
         """Returns an array of strings (and possibly voice and audio
         specifications) that represent the default button in a dialog.
diff --git a/test/keystrokes/gtk-demo/role_radio_button.py b/test/keystrokes/gtk-demo/role_radio_button.py
index 2b5d929..162555e 100644
--- a/test/keystrokes/gtk-demo/role_radio_button.py
+++ b/test/keystrokes/gtk-demo/role_radio_button.py
@@ -33,7 +33,7 @@ sequence.append(KeyComboAction("<Alt>a", 500))
 sequence.append(WaitForFocus("All Pages", acc_role=pyatspi.ROLE_RADIO_BUTTON))
 sequence.append(utils.AssertPresentationAction(
     "All Pages radio button",
-    ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler &=y All Pages RadioButton'",
+    ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler Range &=y All Pages RadioButton'",
      "     VISIBLE:  '&=y All Pages RadioButton', cursor=1",
      "SPEECH OUTPUT: 'Range All Pages selected radio button'"]))
 
@@ -45,9 +45,9 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
 sequence.append(utils.AssertPresentationAction(
     "All Pages radio button Where Am I",
-    ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler &=y All Pages RadioButton'",
+    ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler Range &=y All Pages RadioButton'",
      "     VISIBLE:  '&=y All Pages RadioButton', cursor=1",
-     "SPEECH OUTPUT: 'Range All Pages radio button selected item 1 of 3.",
+     "SPEECH OUTPUT: 'Range All Pages radio button selected item 1 of 3.'",
      "SPEECH OUTPUT: 'Alt a'"]))
 
 ########################################################################
@@ -67,7 +67,7 @@ sequence.append(WaitForFocus("Pages:", acc_role=pyatspi.ROLE_RADIO_BUTTON))
 sequence.append(utils.AssertPresentationAction(
     "Range radio button",
     ["KNOWN ISSUE - the radio button should be presented as selected.",
-     "BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler & y Pages: RadioButton'",
+     "BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler Range & y Pages: RadioButton'",
      "     VISIBLE:  '& y Pages: RadioButton', cursor=1",
      "SPEECH OUTPUT: 'Pages: not selected radio button'"]))
 
@@ -79,9 +79,9 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
 sequence.append(utils.AssertPresentationAction(
     "Range radio button Where Am I",
-    ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler &=y Pages: RadioButton'",
+    ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler Range &=y Pages: RadioButton'",
      "     VISIBLE:  '&=y Pages: RadioButton', cursor=1",
-     "SPEECH OUTPUT: 'Range Pages: radio button selected item 3 of 3.",
+     "SPEECH OUTPUT: 'Range Pages: radio button selected item 3 of 3.'",
      "SPEECH OUTPUT: 'Alt e'"]))
 
 ########################################################################
@@ -93,7 +93,7 @@ sequence.append(WaitForFocus("All Pages", acc_role=pyatspi.ROLE_RADIO_BUTTON))
 sequence.append(utils.AssertPresentationAction(
     "All Pages radio button",
     ["KNOWN ISSUE - the radio button should be presented as selected.",
-     "BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler & y All Pages RadioButton'",
+     "BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler Range & y All Pages RadioButton'",
      "     VISIBLE:  '& y All Pages RadioButton', cursor=1",
      "SPEECH OUTPUT: 'All Pages not selected radio button'"]))
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]