[orca] Explicitly announce the popup type when aria-haspopup is used



commit 25c642543816bca7514734414e98ddae2ece0dfe
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Wed Oct 9 13:32:38 2019 -0400

    Explicitly announce the popup type when aria-haspopup is used
    
    Notes:
    * This will not be presented if the verbosity is set to brief.
    * At the present time, no filtering of obvious or default types is
      taking place. (Example: The default popup of an ARIA combo box is
      "listbox". Rather than filtering it out, Orca will present it.
    * The information is being tacked on to the very end of presentation
      so it can be interrupted by users who don't find it meaningful.
    * What gets spoken when is subject to change based on user feedback.

 src/orca/formatting.py                   |  6 +++---
 src/orca/generator.py                    |  3 +++
 src/orca/messages.py                     | 22 ++++++++++++++++++++++
 src/orca/script_utilities.py             |  3 +++
 src/orca/scripts/web/script_utilities.py | 19 +++++++++++++++++++
 src/orca/scripts/web/speech_generator.py | 22 ++++++++++++++++++++++
 src/orca/speech_generator.py             | 12 ++++++++++++
 7 files changed, 84 insertions(+), 3 deletions(-)
---
diff --git a/src/orca/formatting.py b/src/orca/formatting.py
index 2ac39d5d5..f3d7ecbb2 100644
--- a/src/orca/formatting.py
+++ b/src/orca/formatting.py
@@ -116,9 +116,9 @@ formatting = {
             },
         'suffix': {
             'focused': '[]',
-            'unfocused': 'newNodeLevel + unselectedCell + clickable + hasLongDesc + ' + TUTORIAL + ' + 
description',
-            'basicWhereAmI': TUTORIAL + ' + clickable + hasLongDesc + description',
-            'detailedWhereAmI': TUTORIAL + ' + clickable + hasLongDesc + description'
+            'unfocused': 'newNodeLevel + unselectedCell + clickable + hasLongDesc + ' + TUTORIAL + ' + 
description + pause + hasPopup',
+            'basicWhereAmI': TUTORIAL + ' + clickable + hasLongDesc + description + pause + hasPopup',
+            'detailedWhereAmI': TUTORIAL + ' + clickable + hasLongDesc + description + pause + hasPopup'
             },
         'default': {
             'focused': '[]',
diff --git a/src/orca/generator.py b/src/orca/generator.py
index eac846dc2..57fb1f269 100644
--- a/src/orca/generator.py
+++ b/src/orca/generator.py
@@ -486,6 +486,9 @@ class Generator:
     def _generateHasLongDesc(self, obj, **args):
         return []
 
+    def _generateHasPopup(self, obj, **args):
+        return []
+
     def _generateAvailability(self, obj, **args):
         """Returns an array of strings for use by speech and braille that
         represent the grayed/sensitivity/availability state of the
diff --git a/src/orca/messages.py b/src/orca/messages.py
index e5ea8321c..9e5725f75 100644
--- a/src/orca/messages.py
+++ b/src/orca/messages.py
@@ -563,6 +563,28 @@ FLAT_REVIEW_STOP = _("Leaving flat review.")
 # (e.g., "=sum(a1:d1)")
 HAS_FORMULA = _("has formula")
 
+# Translators: this message will be presented to indicate the focused object
+# will cause a dialog to appear if activated.
+HAS_POPUP_DIALOG = _("opens dialog")
+
+# Translators: this message will be presented to indicate the focused object
+# will cause a grid to appear if activated. A grid is an interactive table.
+HAS_POPUP_GRID = _("opens grid")
+
+# Translators: this message will be presented to indicate the focused object
+# will cause a listbox to appear if activated.
+HAS_POPUP_LISTBOX = _("opens listbox")
+
+# Translators: this message will be presented to indicate the focused object
+# will cause a menu to appear if activated.
+HAS_POPUP_MENU = _("opens menu")
+
+# Translators: this message will be presented to indicate the focused object
+# will cause a tree to appear if activated. A tree is a list with sub-levels
+# which can be expanded or collapsed, similar to the list of folders in an
+# email client.
+HAS_POPUP_TREE = _("opens tree")
+
 # Translators: The following string is spoken to let the user know that he/she
 # is on a link within an image map. An image map is an image/graphic which has
 # been divided into regions. Each region can be clicked on and has an associated
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index d376758ab..04bf9df7a 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -3901,6 +3901,9 @@ class Utilities:
     def hasLongDesc(self, obj):
         return False
 
+    def popupType(self, obj):
+        return ''
+
     def headingLevel(self, obj):
         if not (obj and obj.getRole() == pyatspi.ROLE_HEADING):
             return 0
diff --git a/src/orca/scripts/web/script_utilities.py b/src/orca/scripts/web/script_utilities.py
index 27ad8ec9d..8860365b8 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._popupType = {}
         self._hasUselessCanvasDescendant = {}
         self._id = {}
         self._displayStyle = {}
@@ -155,6 +156,7 @@ class Utilities(script_utilities.Utilities):
         self._hasExplicitName = {}
         self._hasNoSize = {}
         self._hasLongDesc = {}
+        self._popupType = {}
         self._hasUselessCanvasDescendant = {}
         self._id = {}
         self._displayStyle = {}
@@ -3530,6 +3532,23 @@ class Utilities(script_utilities.Utilities):
         self._hasLongDesc[hash(obj)] = rv
         return rv
 
+    def popupType(self, obj):
+        if not (obj and self.inDocumentContent(obj)):
+            return False
+
+        rv = self._popupType.get(hash(obj))
+        if rv is not None:
+            return rv
+
+        try:
+            attrs = dict([attr.split(':', 1) for attr in obj.getAttributes()])
+        except:
+            attrs = {}
+
+        rv = attrs.get('haspopup', 'false').lower()
+        self._popupType[hash(obj)] = rv
+        return rv
+
     def inferLabelFor(self, obj):
         if not self.shouldInferLabelFor(obj):
             return None, []
diff --git a/src/orca/scripts/web/speech_generator.py b/src/orca/scripts/web/speech_generator.py
index 5bb9c3f60..dbbe6ef90 100644
--- a/src/orca/scripts/web/speech_generator.py
+++ b/src/orca/scripts/web/speech_generator.py
@@ -104,6 +104,28 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
         # call utility methods rather than generate it.
         return super()._generateAnyTextSelection(obj, **args)
 
+    def _generateHasPopup(self, obj, **args):
+        if not self._script.utilities.inDocumentContent(obj):
+            return []
+
+        result = []
+        popupType = self._script.utilities.popupType(obj)
+        if popupType == 'dialog':
+            result = [messages.HAS_POPUP_DIALOG]
+        elif popupType == 'grid':
+            result = [messages.HAS_POPUP_GRID]
+        elif popupType == 'listbox':
+            result = [messages.HAS_POPUP_LISTBOX]
+        elif popupType in ('menu', 'true'):
+            result = [messages.HAS_POPUP_MENU]
+        elif popupType == 'tree':
+            result = [messages.HAS_POPUP_TREE]
+
+        if result:
+            result.extend(self.voice(speech_generator.SYSTEM))
+
+        return result
+
     def _generateClickable(self, obj, **args):
         if not self._script.utilities.inDocumentContent(obj):
             return []
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index 7937d789f..56744fb46 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -252,6 +252,18 @@ class SpeechGenerator(generator.Generator):
             result.extend(acss)
         return result
 
+    def _generateHasPopup(self, obj, **args):
+        if _settingsManager.getSetting('onlySpeakDisplayedText') \
+           or _settingsManager.getSetting('speechVerbosityLevel') \
+               == settings.VERBOSITY_LEVEL_BRIEF:
+            return []
+
+        acss = self.voice(SYSTEM)
+        result = generator.Generator._generateHasPopup(self, obj, **args)
+        if result:
+            result.extend(acss)
+        return result
+
     def _generateClickable(self, obj, **args):
         if _settingsManager.getSetting('onlySpeakDisplayedText') \
            or _settingsManager.getSetting('speechVerbosityLevel') \


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