[orca] Make presentation of the status bar fully generator-based



commit 761aa5f40b5d72bb9819f110b71a0bbe2837e7bc
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Fri May 8 19:14:15 2020 -0400

    Make presentation of the status bar fully generator-based
    
    * When the command to speak the status bar is given, also generate
      and display braille
    * When a status bar claims focus (which it now can in, at least,
      VSCode) present the status bar items in speech and braille
    * Generate end-of-line indicators for braille labels, if the user
      has that setting enabled. This causes status bar labels in apps
      like LibreOffice Writer to not be a bunch of disjointed text.
      And we normally display the end-of-line indicator for text
      objects anyway.
    * Harmonize link presentation between speech and braille. This
      not only makes presentation consistent, but it eliminates things
      like non-printable / private-use-area characters from showing
      up in the braille of the status bar of (at least) VSCode.

 src/orca/braille_generator.py | 18 ++++++++++++++++++
 src/orca/formatting.py        | 18 +++++++++++-------
 src/orca/generator.py         | 14 +++++++++++++-
 src/orca/script_utilities.py  | 10 +++++++++-
 src/orca/scripts/default.py   |  7 ++++++-
 src/orca/speech_generator.py  |  7 -------
 6 files changed, 57 insertions(+), 17 deletions(-)
---
diff --git a/src/orca/braille_generator.py b/src/orca/braille_generator.py
index d323e8968..131311a00 100644
--- a/src/orca/braille_generator.py
+++ b/src/orca/braille_generator.py
@@ -345,6 +345,24 @@ class BrailleGenerator(generator.Generator):
 
         return result
 
+    def _generateStatusBar(self, obj, **args):
+        statusBar = self._script.utilities.statusBar(obj)
+        if not statusBar:
+            return []
+
+        items = self._script.utilities.statusBarItems(obj)
+        if not items:
+            return []
+
+        result = []
+        for child in items:
+            childResult = self.generate(child, includeContext=False)
+            if childResult:
+                result.extend(childResult)
+                result.append(braille.Region(" "))
+
+        return result
+
     def _generateListBoxItemWidgets(self, obj, **args):
         widgetRoles = [pyatspi.ROLE_CHECK_BOX,
                        pyatspi.ROLE_COMBO_BOX,
diff --git a/src/orca/formatting.py b/src/orca/formatting.py
index 81ae2cac9..d1af3f8fa 100644
--- a/src/orca/formatting.py
+++ b/src/orca/formatting.py
@@ -450,13 +450,16 @@ formatting = {
             },
         pyatspi.ROLE_STATIC: {
             'unfocused': '(displayedText or name) + roleName',
-        },
+            },
+        pyatspi.ROLE_STATUS_BAR: {
+            'focused': 'labelAndName + roleName',
+            'unfocused': 'labelAndName + roleName + pause + statusBar',
+            },
         'ROLE_SWITCH': {
             'focused': 'switchState',
             'unfocused': 'labelOrName + roleName + switchState + availability + ' + MNEMONIC + ' + 
accelerator',
             'basicWhereAmI': 'labelOrName + roleName + switchState'
             },
-
         pyatspi.ROLE_TABLE: {
             'focused': 'leaving or (labelAndName + pause + table)',
             'unfocused': 'labelAndName + pause + table',
@@ -661,13 +664,10 @@ formatting = {
                                      asString(labelAndName + value + roleName + required))]',
             },
         pyatspi.ROLE_LABEL: {
-            'focused': '[Text(obj, asString(labelAndName))]',
-            'unfocused': '[Text(obj, asString(labelAndName))]'
+            'unfocused': BRAILLE_TEXT
             },
         pyatspi.ROLE_LINK: {
-            'unfocused': '[Link(obj, asString(currentLineText)\
-                                     or asString(displayedText)\
-                                     or asString(name))] \
+            'unfocused': '[Link(obj, asString(name or displayedText))] \
                         + (roleName and [Region(" " + asString(roleName))])',
         },
         pyatspi.ROLE_LIST: {
@@ -777,6 +777,10 @@ formatting = {
                           + (required and [Region(" " + asString(required))] or [])\
                           + (readOnly and [Region(" " + asString(readOnly))] or [])'
             },
+        pyatspi.ROLE_STATUS_BAR: {
+            'unfocused': '[Component(obj, asString(labelOrName + roleName))]\
+                              + [Region(" ")] + statusBar',
+            },
         'ROLE_SWITCH' : {
             'unfocused': '[Component(obj,\
                                      asString((labelOrName or description) + roleName),\
diff --git a/src/orca/generator.py b/src/orca/generator.py
index b8e350f92..94f1964cd 100644
--- a/src/orca/generator.py
+++ b/src/orca/generator.py
@@ -287,6 +287,13 @@ class Generator:
         # Subclasses must override this.
         return []
 
+    def _fallBackOnDescriptionForName(self, obj, **args):
+        role = args.get('role', obj.getRole())
+        if role == pyatspi.ROLE_LABEL:
+            return False
+
+        return True
+
     def _generateName(self, obj, **args):
         """Returns an array of strings for use by speech and braille that
         represent the name of the object.  If the object is directly
@@ -306,7 +313,7 @@ class Generator:
         name = obj.name
         if name:
             result.append(name)
-        else:
+        elif self._fallBackOnDescriptionForName(obj, **args):
             try:
                 description = obj.description
             except (LookupError, RuntimeError):
@@ -438,6 +445,11 @@ class Generator:
             result.append(label)
         return result
 
+    def generateStatusBar(self, obj, **args):
+        """Returns an array of strings that represent a status bar."""
+
+        return self._generateStatusBar(obj, **args)
+
     #####################################################################
     #                                                                   #
     # Image information                                                 #
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index 1e041ad8a..b19e4bf4d 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -2102,6 +2102,9 @@ class Utilities:
         if objects:
             return objects
 
+        if role == pyatspi.ROLE_LABEL and not (root.name or self.queryNonEmptyText(root)):
+            return []
+
         containers = [pyatspi.ROLE_CANVAS,
                       pyatspi.ROLE_FILLER,
                       pyatspi.ROLE_IMAGE,
@@ -2200,7 +2203,12 @@ class Utilities:
         if not (obj and obj.getRole() == pyatspi.ROLE_STATUS_BAR):
             return []
 
-        return self.getOnScreenObjects(obj)
+        items = self._script.pointOfReference.get('statusBarItems')
+        if not items:
+            items = self.getOnScreenObjects(obj)
+            self._script.pointOfReference['statusBarItems'] = items
+
+        return items
 
     def statusBar(self, obj):
         """Returns the status bar in the window which contains obj.
diff --git a/src/orca/scripts/default.py b/src/orca/scripts/default.py
index 36f560eb7..e92c0db87 100644
--- a/src/orca/scripts/default.py
+++ b/src/orca/scripts/default.py
@@ -1246,7 +1246,12 @@ class Script(script.Script):
 
         frame, dialog = self.utilities.frameAndDialog(obj)
         if frame:
-            speech.speak(self.speechGenerator.generateStatusBar(frame))
+            statusbar = self.utilities.statusBar(frame)
+            if statusbar:
+                self.pointOfReference['statusBarItems'] = None
+                self.presentObject(statusbar)
+                self.pointOfReference['statusBarItems'] = None
+
             infobar = self.utilities.infoBar(frame)
             if infobar:
                 speech.speak(self.speechGenerator.generateSpeech(infobar))
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index 52512ff8e..65978b43d 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -2336,13 +2336,6 @@ class SpeechGenerator(generator.Generator):
 
         return result
 
-    def generateStatusBar(self, obj, **args):
-        """Returns an array of strings (and possibly voice and audio
-        specifications) that represent the status bar of the window
-        containing the object.
-        """
-        return self._generateStatusBar(obj, **args)
-
     def generateTitle(self, obj, **args):
         """Returns an array of strings (and possibly voice and audio
         specifications) that represent the title of the window, obj.


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