[orca] More work on custom localized role names:



commit 2fc1db1eab9e43fa97bb0dc0fd17de38ec261a04
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Fri Aug 12 14:29:25 2016 -0400

    More work on custom localized role names:
    
    * Move main support from speech and braille generators to superclass
    * Add support for optional keyword arguments
    * Create new localized role names for horizontal and vertical
      scroll bars, sliders, and splitters

 src/orca/braille_generator.py                      |   42 ++-----------
 src/orca/flat_review.py                            |   30 ++-------
 src/orca/generator.py                              |   65 ++++++++++++++++++--
 src/orca/object_properties.py                      |   56 +++++++++++++++++
 .../scripts/toolkits/WebKitGtk/speech_generator.py |    6 +-
 src/orca/scripts/web/braille_generator.py          |    6 +-
 src/orca/scripts/web/speech_generator.py           |   18 +++---
 src/orca/speech_generator.py                       |   57 ++++++-----------
 src/orca/structural_navigation.py                  |    2 +-
 9 files changed, 162 insertions(+), 120 deletions(-)
---
diff --git a/src/orca/braille_generator.py b/src/orca/braille_generator.py
index 3a4fc8c..f664367 100644
--- a/src/orca/braille_generator.py
+++ b/src/orca/braille_generator.py
@@ -26,7 +26,6 @@ __copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
 import pyatspi
-from gi.repository import Atspi, Atk
 
 from . import braille
 from . import debug
@@ -158,56 +157,25 @@ class BrailleGenerator(generator.Generator):
 
         elif verbosityLevel == settings.VERBOSITY_LEVEL_VERBOSE \
            and not args.get('readingRow', False) and role not in doNotPresent:
-            result.append(self.getLocalizedRoleName(obj, role))
+            result.append(self.getLocalizedRoleName(obj, **args))
         return result
 
-    def getLocalizedRoleName(self, obj, role=None):
+    def getLocalizedRoleName(self, obj, **args):
         """Returns the localized name of the given Accessible object; the name
         is suitable to be brailled.
 
         Arguments:
         - obj: an Accessible object
-        - role: an optional pyatspi role to use instead
         """
 
         if _settingsManager.getSetting('brailleRolenameStyle') \
                 == settings.BRAILLE_ROLENAME_STYLE_SHORT:
-            objRole = role or obj.getRole()
-            rv = shortRoleNames.get(objRole)
+            role = args.get('role', obj.getRole())
+            rv = shortRoleNames.get(role)
             if rv:
                 return rv
 
-        if not isinstance(role, (pyatspi.Role, Atspi.Role)):
-            try:
-                return obj.getLocalizedRoleName()
-            except:
-                return ''
-
-        if self._script.utilities.isLandmark(obj):
-            if self._script.utilities.isLandmarkBanner(obj):
-                return object_properties.ROLE_LANDMARK_BANNER
-            if self._script.utilities.isLandmarkComplementary(obj):
-                return object_properties.ROLE_LANDMARK_COMPLEMENTARY
-            if self._script.utilities.isLandmarkContentInfo(obj):
-                return object_properties.ROLE_LANDMARK_CONTENTINFO
-            if self._script.utilities.isLandmarkMain(obj):
-                return object_properties.ROLE_LANDMARK_MAIN
-            if self._script.utilities.isLandmarkNavigation(obj):
-                return object_properties.ROLE_LANDMARK_NAVIGATION
-            if self._script.utilities.isLandmarkRegion(obj):
-                return object_properties.ROLE_LANDMARK_REGION
-            if self._script.utilities.isLandmarkSearch(obj):
-                return object_properties.ROLE_LANDMARK_SEARCH
-            if self._script.utilities.isLandmarkForm(obj):
-                role = pyatspi.ROLE_FORM
-
-        if not role:
-            return ''
-
-        nonlocalized = Atspi.role_get_name(role)
-        atkRole = Atk.role_for_name(nonlocalized)
-
-        return Atk.role_get_localized_name(atkRole)
+        return super().getLocalizedRoleName(obj, **args)
 
     def _generateUnrelatedLabels(self, obj, **args):
         result = []
diff --git a/src/orca/flat_review.py b/src/orca/flat_review.py
index f417b78..b8d4052 100644
--- a/src/orca/flat_review.py
+++ b/src/orca/flat_review.py
@@ -400,15 +400,6 @@ class ValueZone(Zone):
 
     def __getattr__(self, attr):
         if attr in ["string", "length", "brailleString"]:
-            orientation = None
-            if self.role in [pyatspi.ROLE_SLIDER,
-                             pyatspi.ROLE_SCROLL_BAR]:
-                stateset = self.accessible.getState()
-                if stateset.contains(pyatspi.STATE_HORIZONTAL):
-                    orientation = object_properties.STATE_HORIZONTAL
-                elif stateset.contains(pyatspi.STATE_VERTICAL):
-                    orientation = object_properties.STATE_VERTICAL
-                        
             try:
                 value = self.accessible.queryValue()
             except NotImplementedError:
@@ -421,22 +412,15 @@ class ValueZone(Zone):
             except:
                 percentValue = 0
 
-            rolename = self.accessible.getLocalizedRoleName()
-            if orientation:
-                speechValue = orientation + " " + rolename
-            else:
-                speechValue = rolename
-
+            script = orca_state.activeScript
+            speechValue = script.speechGenerator.getLocalizedRoleName(
+                self.accessible, alreadyFocused=True)
             speechValue = speechValue + " " + messages.percentage(percentValue)
 
-            rolename = orca_state.activeScript.brailleGenerator.getLocalizedRoleName(
-                self.accessible)
-            if orientation:
-                brailleValue = "%s %s %d%%" % (orientation,
-                    rolename,
-                    percentValue)
-            else:
-                brailleValue = "%s %d%%" % (rolename, percentValue)
+            brailleValue = script.brailleGenerator.getLocalizedRoleName(
+                self.accessible, alreadyFocused=True)
+            brailleValue = "%s %d%%" % (brailleValue, percentValue)
+
             if attr == "string":
                 return speechValue
             elif attr == "length":
diff --git a/src/orca/generator.py b/src/orca/generator.py
index 0f74b47..6cd0081 100644
--- a/src/orca/generator.py
+++ b/src/orca/generator.py
@@ -27,11 +27,12 @@ __copyright__ = "Copyright (c) 2009 Sun Microsystems Inc." \
                 "Copyright (c) 2015-2016 Igalia, S.L."
 __license__   = "LGPL"
 
+import collections
+import pyatspi
 import sys
 import time
 import traceback
-
-import pyatspi
+from gi.repository import Atspi, Atk
 
 from . import braille
 from . import debug
@@ -40,8 +41,6 @@ from . import object_properties
 from . import settings
 from . import settings_manager
 
-import collections
-
 def _formatExceptionInfo(maxTBlevel=5):
     cla, exc, trbk = sys.exc_info()
     excName = cla.__name__
@@ -655,7 +654,7 @@ class Generator:
         if not text:
             return result
 
-        roleString =  self.getLocalizedRoleName(obj, pyatspi.ROLE_ROW_HEADER)
+        roleString =  self.getLocalizedRoleName(obj, role=pyatspi.ROLE_ROW_HEADER)
         if args.get('mode') == 'speech':
             if settings.speechVerbosityLevel == settings.VERBOSITY_LEVEL_VERBOSE \
                and not args.get('formatType') in ['basicWhereAmI', 'detailedWhereAmI']:
@@ -681,7 +680,7 @@ class Generator:
         if not text:
             return result
 
-        roleString =  self.getLocalizedRoleName(obj, pyatspi.ROLE_COLUMN_HEADER)
+        roleString =  self.getLocalizedRoleName(obj, role=pyatspi.ROLE_COLUMN_HEADER)
         if args.get('mode') == 'speech':
             if settings.speechVerbosityLevel == settings.VERBOSITY_LEVEL_VERBOSE \
                and not args.get('formatType') in ['basicWhereAmI', 'detailedWhereAmI']:
@@ -1154,3 +1153,57 @@ class Generator:
             return pyatspi.ROLE_LIST_ITEM
 
         return args.get('role', obj.getRole())
+
+    def getLocalizedRoleName(self, obj, **args):
+        role = args.get('role', obj.getRole())
+
+        if "Value" in pyatspi.listInterfaces(obj):
+            state = obj.getState()
+            isVertical = state.contains(pyatspi.STATE_VERTICAL)
+            isHorizontal = state.contains(pyatspi.STATE_HORIZONTAL)
+            isFocused = state.contains(pyatspi.STATE_FOCUSED) \
+                        or args.get('alreadyFocused', False)
+
+            if role == pyatspi.ROLE_SLIDER:
+                if isHorizontal:
+                    return object_properties.ROLE_SLIDER_HORIZONTAL
+                if isVertical:
+                    return object_properties.ROLE_SLIDER_VERTICAL
+            elif role == pyatspi.ROLE_SCROLL_BAR:
+                if isHorizontal:
+                    return object_properties.ROLE_SCROLL_BAR_HORIZONTAL
+                if isVertical:
+                    return object_properties.ROLE_SCROLL_BAR_VERTICAL
+            elif role == pyatspi.ROLE_SEPARATOR:
+                if isHorizontal:
+                    return object_properties.ROLE_SPLITTER_HORIZONTAL
+                if isVertical:
+                    return object_properties.ROLE_SPLITTER_VERTICAL
+            elif role == pyatspi.ROLE_SPLIT_PANE and isFocused:
+                # The splitter has the opposite orientation of the split pane.
+                if isHorizontal:
+                    return object_properties.ROLE_SPLITTER_VERTICAL
+                if isVertical:
+                    return object_properties.ROLE_SPLITTER_HORIZONTAL
+
+        if self._script.utilities.isLandmark(obj):
+            if self._script.utilities.isLandmarkBanner(obj):
+                return object_properties.ROLE_LANDMARK_BANNER
+            if self._script.utilities.isLandmarkComplementary(obj):
+                return object_properties.ROLE_LANDMARK_COMPLEMENTARY
+            if self._script.utilities.isLandmarkContentInfo(obj):
+                return object_properties.ROLE_LANDMARK_CONTENTINFO
+            if self._script.utilities.isLandmarkMain(obj):
+                return object_properties.ROLE_LANDMARK_MAIN
+            if self._script.utilities.isLandmarkNavigation(obj):
+                return object_properties.ROLE_LANDMARK_NAVIGATION
+            if self._script.utilities.isLandmarkRegion(obj):
+                return object_properties.ROLE_LANDMARK_REGION
+            if self._script.utilities.isLandmarkSearch(obj):
+                return object_properties.ROLE_LANDMARK_SEARCH
+            if self._script.utilities.isLandmarkForm(obj):
+                role = pyatspi.ROLE_FORM
+
+        nonlocalized = Atspi.role_get_name(role)
+        atkRole = Atk.role_for_name(nonlocalized)
+        return Atk.role_get_localized_name(atkRole)
diff --git a/src/orca/object_properties.py b/src/orca/object_properties.py
index 823f7ff..b88d8a7 100644
--- a/src/orca/object_properties.py
+++ b/src/orca/object_properties.py
@@ -83,6 +83,62 @@ ROLE_HEADING_LEVEL_BRAILLE = _("h%d")
 # translated rolename for the heading.
 ROLE_HEADING_LEVEL_SPEECH = _("%(role)s level %(level)d")
 
+# Translators: This string should be treated as a role describing an object.
+# Examples of roles include "checkbox", "radio button", "paragraph", and "link."
+# The reason we include the orientation as part of the role is because in some
+# applications and toolkits, it can dictate which keyboard keys should be used
+# to modify the value of the widget.
+ROLE_SCROLL_BAR_HORIZONTAL = _("horizontal scroll bar")
+
+# Translators: This string should be treated as a role describing an object.
+# Examples of roles include "checkbox", "radio button", "paragraph", and "link."
+# The reason we include the orientation as part of the role is because in some
+# applications and toolkits, it can dictate which keyboard keys should be used
+# to modify the value of the widget.
+ROLE_SCROLL_BAR_VERTICAL = _("vertical scroll bar")
+
+# Translators: This string should be treated as a role describing an object.
+# Examples of roles include "checkbox", "radio button", "paragraph", and "link."
+# A slider is a widget which looks like a bar and displays a value as a range.
+# A common example of a slider can be found in UI for modifying volume levels.
+# The reason we include the orientation as part of the role is because in some
+# applications and toolkits, it can dictate which keyboard keys should be used
+# to modify the value of the widget.
+ROLE_SLIDER_HORIZONTAL = _("horizontal slider")
+
+# Translators: This string should be treated as a role describing an object.
+# Examples of roles include "checkbox", "radio button", "paragraph", and "link."
+# A slider is a widget which looks like a bar and displays a value as a range.
+# A common example of a slider can be found in UI for modifying volume levels.
+# The reason we include the orientation as part of the role is because in some
+# applications and toolkits, it can dictate which keyboard keys should be used
+# to modify the value of the widget.
+ROLE_SLIDER_VERTICAL = _("vertical slider")
+
+# Translators: This string should be treated as a role describing an object.
+# Examples of roles include "checkbox", "radio button", "paragraph", and "link."
+# A splitter is a bar that divides a container into two parts. It is often, but
+# not necessarily, user resizable. A common example of a splitter can be found
+# in email applications, where there is a container on the left which holds a
+# list of all the mail folders and a container on the right which lists all of
+# the messages in the selected folder. The bar which you click on and drag to
+# resize these containers is the splitter. The reason we include the orientation
+# as part of the role is because in some applications and toolkits, it can
+# dictate which keyboard keys should be used to modify the value of the widget.
+ROLE_SPLITTER_HORIZONTAL = _("horizontal splitter")
+
+# Translators: This string should be treated as a role describing an object.
+# Examples of roles include "checkbox", "radio button", "paragraph", and "link."
+# A splitter is a bar that divides a container into two parts. It is often, but
+# not necessarily, user resizable. A common example of a splitter can be found
+# in email applications, where there is a container on the left which holds a
+# list of all the mail folders and a container on the right which lists all of
+# the messages in the selected folder. The bar which you click on and drag to
+# resize these containers is the splitter. The reason we include the orientation
+# as part of the role is because in some applications and toolkits, it can
+# dictate which keyboard keys should be used to modify the value of the widget.
+ROLE_SPLITTER_VERTICAL = _("vertical splitter")
+
 # Translators: This is an alternative name for the parent object of a series
 # of icons.
 ROLE_ICON_PANEL = _("Icon panel")
diff --git a/src/orca/scripts/toolkits/WebKitGtk/speech_generator.py 
b/src/orca/scripts/toolkits/WebKitGtk/speech_generator.py
index 672adfc..256c27e 100644
--- a/src/orca/scripts/toolkits/WebKitGtk/speech_generator.py
+++ b/src/orca/scripts/toolkits/WebKitGtk/speech_generator.py
@@ -84,10 +84,10 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
         level = self._script.utilities.headingLevel(obj)
         if level:
             result.append(object_properties.ROLE_HEADING_LEVEL_SPEECH % {
-                    'role': self.getLocalizedRoleName(obj, role),
+                    'role': self.getLocalizedRoleName(obj, role=role),
                     'level': level})
         else:
-            result.append(self.getLocalizedRoleName(obj, role))
+            result.append(self.getLocalizedRoleName(obj, role=role))
 
         return result
 
@@ -120,7 +120,7 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
             elif role == pyatspi.ROLE_HEADING:
                 result.extend(self.__generateHeadingRole(obj))
             else:
-                result.append(self.getLocalizedRoleName(obj, role))
+                result.append(self.getLocalizedRoleName(obj, role=role))
                 if obj.parent and obj.parent.getRole() == pyatspi.ROLE_HEADING:
                     result.extend(self.__generateHeadingRole(obj.parent))
 
diff --git a/src/orca/scripts/web/braille_generator.py b/src/orca/scripts/web/braille_generator.py
index 14ee288..b301bdb 100644
--- a/src/orca/scripts/web/braille_generator.py
+++ b/src/orca/scripts/web/braille_generator.py
@@ -41,15 +41,15 @@ class BrailleGenerator(braille_generator.BrailleGenerator):
     def __init__(self, script):
         super().__init__(script)
 
-    def getLocalizedRoleName(self, obj, role=None):
+    def getLocalizedRoleName(self, obj, **args):
         if not self._script.utilities.inDocumentContent(obj):
-            return super().getLocalizedRoleName(obj, role)
+            return super().getLocalizedRoleName(obj, **args)
 
         roledescription = self._script.utilities.getRoleDescription(obj)
         if roledescription:
             return roledescription
 
-        return super().getLocalizedRoleName(obj, role)
+        return super().getLocalizedRoleName(obj, **args)
 
     def _generateRoleName(self, obj, **args):
         """Prevents some roles from being displayed."""
diff --git a/src/orca/scripts/web/speech_generator.py b/src/orca/scripts/web/speech_generator.py
index a9e4659..5fd92a4 100644
--- a/src/orca/scripts/web/speech_generator.py
+++ b/src/orca/scripts/web/speech_generator.py
@@ -221,15 +221,15 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
     def _generateTextRole(self, obj, **args):
         return self._generateRoleName(obj, **args)
 
-    def getLocalizedRoleName(self, obj, role=None):
+    def getLocalizedRoleName(self, obj, **args):
         if not self._script.utilities.inDocumentContent(obj):
-            return super().getLocalizedRoleName(obj, role)
+            return super().getLocalizedRoleName(obj, **args)
 
         roledescription = self._script.utilities.getRoleDescription(obj)
         if roledescription:
             return roledescription
 
-        return super().getLocalizedRoleName(obj, role)
+        return super().getLocalizedRoleName(obj, **args)
 
     def _generateRoleName(self, obj, **args):
         if not self._script.utilities.inDocumentContent(obj):
@@ -283,18 +283,18 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
                 if text and end not in [None, text.characterCount]:
                     return []
             if role not in doNotSpeak:
-                result.append(self.getLocalizedRoleName(obj, role))
+                result.append(self.getLocalizedRoleName(obj, **args))
                 result.extend(acss)
 
         elif role == pyatspi.ROLE_HEADING:
             level = self._script.utilities.headingLevel(obj)
             if level:
                 result.append(object_properties.ROLE_HEADING_LEVEL_SPEECH % {
-                    'role': self.getLocalizedRoleName(obj, role),
+                    'role': self.getLocalizedRoleName(obj, **args),
                     'level': level})
                 result.extend(acss)
             else:
-                result.append(self.getLocalizedRoleName(obj, role))
+                result.append(self.getLocalizedRoleName(obj, **args))
                 result.extend(acss)
 
         elif self._script.utilities.isLink(obj):
@@ -303,13 +303,13 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
                 result.extend(acss)
             else:
                 if self._script.utilities.hasUselessCanvasDescendant(obj):
-                    result.append(self.getLocalizedRoleName(obj, pyatspi.ROLE_IMAGE))
+                    result.append(self.getLocalizedRoleName(obj, role=pyatspi.ROLE_IMAGE))
                     result.extend(acss)
-                result.append(self.getLocalizedRoleName(obj, role))
+                result.append(self.getLocalizedRoleName(obj, **args))
                 result.extend(acss)
 
         elif role not in doNotSpeak:
-            result.append(self.getLocalizedRoleName(obj, role))
+            result.append(self.getLocalizedRoleName(obj, **args))
             result.extend(acss)
 
         index = args.get('index', 0)
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index c423b5a..6d0cc99 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -27,7 +27,6 @@ __license__   = "LGPL"
 
 import pyatspi
 import urllib.parse, urllib.request, urllib.error, urllib.parse
-from gi.repository import Atspi, Atk
 
 from . import chnames
 from . import debug
@@ -349,12 +348,12 @@ class SpeechGenerator(generator.Generator):
             level = self._script.utilities.headingLevel(obj)
             if level:
                 result.append(object_properties.ROLE_HEADING_LEVEL_SPEECH % {
-                    'role': self.getLocalizedRoleName(obj, role),
+                    'role': self.getLocalizedRoleName(obj, **args),
                     'level': level})
                 result.extend(acss)
 
         if role not in doNotPresent and not result:
-            result.append(self.getLocalizedRoleName(obj, role))
+            result.append(self.getLocalizedRoleName(obj, **args))
             result.extend(acss)
         return result
 
@@ -366,55 +365,37 @@ class SpeechGenerator(generator.Generator):
         accessible role of the obj.  This is provided mostly as a
         method for scripts to call.
         """
-        return self._generateRoleName(obj, **args)
+        generated = self._generateRoleName(obj, **args)
+        if generated:
+            return generated[0]
 
-    def getLocalizedRoleName(self, obj, role=None):
+        return ""
+
+    def getName(self, obj, **args):
+        generated = self._generateName(obj, **args)
+        if generated:
+            return generated[0]
+
+        return ""
+
+    def getLocalizedRoleName(self, obj, **args):
         """Returns the localized name of the given Accessible object; the name
         is suitable to be spoken.
 
         Arguments:
         - obj: an Accessible object
-        - role: an optional pyatspi role to use instead
         """
 
-        if not isinstance(role, (pyatspi.Role, Atspi.Role)):
-            try:
-                return obj.getLocalizedRoleName()
-            except:
-                return ''
-
-        if not role:
-            return ''
-
-        if self._script.utilities.isLandmark(obj):
-            if self._script.utilities.isLandmarkBanner(obj):
-                return object_properties.ROLE_LANDMARK_BANNER
-            if self._script.utilities.isLandmarkComplementary(obj):
-                return object_properties.ROLE_LANDMARK_COMPLEMENTARY
-            if self._script.utilities.isLandmarkContentInfo(obj):
-                return object_properties.ROLE_LANDMARK_CONTENTINFO
-            if self._script.utilities.isLandmarkMain(obj):
-                return object_properties.ROLE_LANDMARK_MAIN
-            if self._script.utilities.isLandmarkNavigation(obj):
-                return object_properties.ROLE_LANDMARK_NAVIGATION
-            if self._script.utilities.isLandmarkRegion(obj):
-                return object_properties.ROLE_LANDMARK_REGION
-            if self._script.utilities.isLandmarkSearch(obj):
-                return object_properties.ROLE_LANDMARK_SEARCH
-            if self._script.utilities.isLandmarkForm(obj):
-                role = pyatspi.ROLE_FORM
-
         if self._script.utilities.isEditableComboBox(obj) \
            or self._script.utilities.isEditableDescendantOfComboBox(obj):
             return object_properties.ROLE_EDITABLE_COMBO_BOX
 
-        if role == pyatspi.ROLE_LINK and obj.getState().contains(pyatspi.STATE_VISITED):
+        role = args.get('role', obj.getRole())
+        state = obj.getState()
+        if role == pyatspi.ROLE_LINK and state.contains(pyatspi.STATE_VISITED):
             return object_properties.ROLE_VISITED_LINK
 
-        nonlocalized = Atspi.role_get_name(role)
-        atkRole = Atk.role_for_name(nonlocalized)
-
-        return Atk.role_get_localized_name(atkRole)
+        return super().getLocalizedRoleName(obj, **args)
 
     def _generateUnrelatedLabels(self, obj, **args):
         """Returns, as an array of strings (and possibly voice
diff --git a/src/orca/structural_navigation.py b/src/orca/structural_navigation.py
index dc22db8..c219e33 100644
--- a/src/orca/structural_navigation.py
+++ b/src/orca/structural_navigation.py
@@ -1161,7 +1161,7 @@ class StructuralNavigation:
     def _getRoleName(self, obj):
         # Another case where we'll do this for now, and clean it up when
         # object presentation is refactored.
-        return self._script.speechGenerator.getLocalizedRoleName(obj, obj.getRole())
+        return self._script.speechGenerator.getLocalizedRoleName(obj)
 
     def _getSelectedItem(self, obj):
         # Another case where we'll do this for now, and clean it up when


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