[orca] Announce when object has aria-details set on it



commit 5d1293a646947689972b389078be9b3639ffbd71
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Mon Jan 6 18:02:21 2020 +0100

    Announce when object has aria-details set on it

 src/orca/formatting.py                   |  3 ++-
 src/orca/generator.py                    |  3 +++
 src/orca/object_properties.py            |  7 +++++++
 src/orca/script_utilities.py             |  8 ++++----
 src/orca/scripts/web/script_utilities.py | 27 +++++++++++++++++++++++++++
 src/orca/scripts/web/speech_generator.py | 15 +++++++++++++++
 src/orca/speech_generator.py             | 10 ++++++++++
 7 files changed, 68 insertions(+), 5 deletions(-)
---
diff --git a/src/orca/formatting.py b/src/orca/formatting.py
index d712d5a18..f213b8eac 100644
--- a/src/orca/formatting.py
+++ b/src/orca/formatting.py
@@ -69,6 +69,7 @@ formatting = {
             'groupindex': object_properties.GROUP_INDEX_SPEECH,
             'clickable': object_properties.STATE_CLICKABLE,
             'haslongdesc': object_properties.STATE_HAS_LONGDESC,
+            'hasdetails': object_properties.STATE_HAS_DETAILS,
         },
         'braille': {
             'eol': object_properties.EOL_INDICATOR_BRAILLE,
@@ -116,7 +117,7 @@ formatting = {
             },
         'suffix': {
             'focused': '[]',
-            'unfocused': 'newNodeLevel + unselectedCell + clickable + hasLongDesc + ' + TUTORIAL + ' + 
description + pause + hasPopup',
+            'unfocused': 'newNodeLevel + unselectedCell + clickable + pause + hasLongDesc + hasDetails +' + 
TUTORIAL + ' + description + pause + hasPopup',
             'basicWhereAmI': TUTORIAL + ' + clickable + hasLongDesc + description + pause + hasPopup',
             'detailedWhereAmI': TUTORIAL + ' + clickable + hasLongDesc + description + pause + hasPopup'
             },
diff --git a/src/orca/generator.py b/src/orca/generator.py
index 1c7beed48..d072320ec 100644
--- a/src/orca/generator.py
+++ b/src/orca/generator.py
@@ -486,6 +486,9 @@ class Generator:
     def _generateHasLongDesc(self, obj, **args):
         return []
 
+    def _generateHasDetails(self, obj, **args):
+        return []
+
     def _generateHasPopup(self, obj, **args):
         return []
 
diff --git a/src/orca/object_properties.py b/src/orca/object_properties.py
index 07fbce407..8d6bf65b6 100644
--- a/src/orca/object_properties.py
+++ b/src/orca/object_properties.py
@@ -453,6 +453,13 @@ STATE_EXPANDED = _("expanded")
 # which have a longdesc attribute. http://www.w3.org/TR/WCAG20-TECHS/H45.html
 STATE_HAS_LONGDESC = _("has long description")
 
+# Translators: This is a state which applies to elements in document content
+# which have a detailed description or explanation. That description might
+# be hidden or might be in a different location on the page. Therefore Orca
+# announces the presence of the additional information so that the user can
+# use native application and/or Orca commands to read those details.
+STATE_HAS_DETAILS = _("has details")
+
 # Translators: This is a state which applies to the orientation of widgets
 # such as sliders and scroll bars.
 STATE_HORIZONTAL = _("horizontal")
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index 7613ee5aa..0134513fc 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -477,13 +477,10 @@ class Utilities:
             debug.println(debug.LEVEL_INFO, msg, True)
             return []
 
-        if not state.contains(pyatspi.STATE_EXPANDED):
-            return []
-
         hasDetails = lambda x: x.getRelationType() == pyatspi.RELATION_DETAILS
         relation = filter(hasDetails, relations)
         details = [r.getTarget(i) for r in relation for i in range(r.getNTargets())]
-        if not details and role == pyatspi.ROLE_TOGGLE_BUTTON:
+        if not details and role == pyatspi.ROLE_TOGGLE_BUTTON and state.contains(pyatspi.STATE_EXPANDED):
             details = [child for child in obj]
 
         if not textOnly:
@@ -3943,6 +3940,9 @@ class Utilities:
     def hasLongDesc(self, obj):
         return False
 
+    def hasDetails(self, obj):
+        return False
+
     def popupType(self, obj):
         return ''
 
diff --git a/src/orca/scripts/web/script_utilities.py b/src/orca/scripts/web/script_utilities.py
index 47d1c617d..272ebb79a 100644
--- a/src/orca/scripts/web/script_utilities.py
+++ b/src/orca/scripts/web/script_utilities.py
@@ -76,6 +76,7 @@ class Utilities(script_utilities.Utilities):
         self._hasExplicitName = {}
         self._hasNoSize = {}
         self._hasLongDesc = {}
+        self._hasDetails = {}
         self._popupType = {}
         self._hasUselessCanvasDescendant = {}
         self._id = {}
@@ -156,6 +157,7 @@ class Utilities(script_utilities.Utilities):
         self._hasExplicitName = {}
         self._hasNoSize = {}
         self._hasLongDesc = {}
+        self._hasDetails = {}
         self._popupType = {}
         self._hasUselessCanvasDescendant = {}
         self._id = {}
@@ -3577,6 +3579,31 @@ class Utilities(script_utilities.Utilities):
         self._hasLongDesc[hash(obj)] = rv
         return rv
 
+    def hasDetails(self, obj):
+        if not (obj and self.inDocumentContent(obj)):
+            return super().hasDetails(obj)
+
+        rv = self._hasDetails.get(hash(obj))
+        if rv is not None:
+            return rv
+
+        try:
+            relations = obj.getRelationSet()
+        except:
+            msg = 'ERROR: Exception getting relationset for %s' % obj
+            debug.println(debug.LEVEL_INFO, msg, True)
+            return False
+
+        rv = False
+        relation = filter(lambda x: x.getRelationType() == pyatspi.RELATION_DETAILS, relations)
+        for r in relation:
+            if r.getNTargets() > 0:
+                rv = True
+                break
+
+        self._hasDetails[hash(obj)] = rv
+        return rv
+
     def popupType(self, obj):
         if not (obj and self.inDocumentContent(obj)):
             return 'false'
diff --git a/src/orca/scripts/web/speech_generator.py b/src/orca/scripts/web/speech_generator.py
index 3c3acbbf5..85f43b6d6 100644
--- a/src/orca/scripts/web/speech_generator.py
+++ b/src/orca/scripts/web/speech_generator.py
@@ -198,6 +198,21 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
 
         return []
 
+    def _generateHasDetails(self, obj, **args):
+        if _settingsManager.getSetting('onlySpeakDisplayedText'):
+            return []
+
+        if not self._script.utilities.inDocumentContent(obj):
+            return super()._generateHasDetails(obj, **args)
+
+        args['stringType'] = 'hasdetails'
+        if self._script.utilities.hasDetails(obj):
+            result = [self._script.formatting.getString(**args)]
+            result.extend(self.voice(speech_generator.SYSTEM))
+            return result
+
+        return []
+
     def _generateLabelOrName(self, obj, **args):
         if not self._script.utilities.inDocumentContent(obj):
             return super()._generateLabelOrName(obj, **args)
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index b82ef75a0..96234bad9 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -286,6 +286,16 @@ class SpeechGenerator(generator.Generator):
             result.extend(acss)
         return result
 
+    def _generateHasDetails(self, obj, **args):
+        if _settingsManager.getSetting('onlySpeakDisplayedText'):
+            return []
+
+        acss = self.voice(SYSTEM)
+        result = generator.Generator._generateHasDetails(self, obj, **args)
+        if result:
+            result.extend(acss)
+        return result
+
     def _generateAvailability(self, obj, **args):
         if _settingsManager.getSetting('onlySpeakDisplayedText'):
             return []


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