[orca] Present aria-sort value when focus moves to sorted row/col header



commit 87399fa27ec4147c7fe4a11288e69c7b352c513f
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Fri Apr 24 15:57:53 2020 -0400

    Present aria-sort value when focus moves to sorted row/col header

 src/orca/formatting.py                   | 16 ++++++++++++----
 src/orca/generator.py                    | 12 ++++++++++++
 src/orca/object_properties.py            | 14 ++++++++++++++
 src/orca/script_utilities.py             |  6 ++++++
 src/orca/scripts/web/script_utilities.py | 14 ++++++++++++++
 src/orca/speech_generator.py             |  7 +++++++
 6 files changed, 65 insertions(+), 4 deletions(-)
---
diff --git a/src/orca/formatting.py b/src/orca/formatting.py
index 2ede5ceb2..9d36bb66f 100644
--- a/src/orca/formatting.py
+++ b/src/orca/formatting.py
@@ -167,7 +167,8 @@ formatting = {
             'basicWhereAmI': 'label + roleName + value + percentage + ' + MNEMONIC + ' + accelerator + 
required'
             },
         pyatspi.ROLE_COLUMN_HEADER: {
-            'unfocused': '((substring and currentLineText) or labelAndName) + roleName'
+            'focused': 'labelAndName + roleName + pause + sortOrder',
+            'unfocused': '((substring and currentLineText) or labelAndName) + roleName + pause + sortOrder'
             },
         pyatspi.ROLE_COMBO_BOX: {
             'focused': 'labelOrName + roleName + expandableState',
@@ -413,7 +414,8 @@ formatting = {
             'basicWhereAmI': 'ancestors + labelOrName + roleName + radioState + accelerator + positionInList 
+ ' + MNEMONIC
             },
         pyatspi.ROLE_ROW_HEADER: {
-            'unfocused': '((substring and currentLineText) or labelAndName) + roleName'
+            'focused': 'labelAndName + roleName + pause + sortOrder',
+            'unfocused': '((substring and currentLineText) or labelAndName) + roleName + pause + sortOrder'
             },
         pyatspi.ROLE_SCROLL_BAR: {
             'focused': 'value',
@@ -597,7 +599,10 @@ formatting = {
                                      asString(label + displayedText + roleName + availability) + 
asString(accelerator),\
                                      indicator=asString(checkedState))]'
             },
-        #pyatspi.ROLE_COLUMN_HEADER: 'default'
+        pyatspi.ROLE_COLUMN_HEADER: {
+            'unfocused': '[Component(obj,\
+                                     asString(((substring and currentLineText) or labelAndName) + roleName + 
sortOrder))]',
+            },
         pyatspi.ROLE_COMBO_BOX: {
             'unfocused': '[Component(obj, asString(labelOrName + value + roleName), \
                                      labelOrName and (len(asString(labelOrName)) + 1) or 0)]'
@@ -744,7 +749,10 @@ formatting = {
                                      + asString(accelerator),\
                                      indicator=asString(radioState))]'
             },
-        #pyatspi.ROLE_ROW_HEADER: 'default'
+        pyatspi.ROLE_ROW_HEADER: {
+            'unfocused': '[Component(obj,\
+                                     asString(((substring and currentLineText) or labelAndName) + roleName + 
sortOrder))]',
+            },
         pyatspi.ROLE_SCROLL_BAR: {
             'unfocused': '[Component(obj,\
                                      asString(labelOrName + value + roleName + required))]'
diff --git a/src/orca/generator.py b/src/orca/generator.py
index 4f24e4308..d926b8522 100644
--- a/src/orca/generator.py
+++ b/src/orca/generator.py
@@ -775,6 +775,18 @@ class Generator:
         result.append(text)
         return result
 
+    def _generateSortOrder(self, obj, **args):
+        if not self._script.utilities.isSorted(obj):
+            return []
+
+        if self._script.utilities.isAscending(obj):
+            return [object_properties.SORT_ORDER_ASCENDING]
+
+        if self._script.utilities.isDescending(obj):
+            return [object_properties.SORT_ORDER_DESCENDING]
+
+        return [object_properties.SORT_ORDER_OTHER]
+
     def _generateTableCell2ChildLabel(self, obj, **args):
         """Returns an array of strings for use by speech and braille for the
         label of a toggle in a table cell that has a special 2 child
diff --git a/src/orca/object_properties.py b/src/orca/object_properties.py
index 978cb6205..3522952c7 100644
--- a/src/orca/object_properties.py
+++ b/src/orca/object_properties.py
@@ -465,6 +465,19 @@ ROLE_VISITED_LINK = _("visited link")
 # activates the button.
 ROLE_MENU_BUTTON = _("menu button")
 
+# Translators: This string refers to a row or column whose sort-order has been set
+# to ascending.
+SORT_ORDER_ASCENDING = _("sorted ascending")
+
+# Translators: This string refers to a row or column whose sort-order has been set
+# to descending.
+SORT_ORDER_DESCENDING = _("sorted descending")
+
+# Translators: This string refers to a row or column whose sort-order has been set,
+# but the nature of the sort order is unknown or something other than ascending or
+# descending.
+SORT_ORDER_OTHER = _("sorted")
+
 # Translators: This is a state which applies to elements in document content
 # which have an "onClick" action.
 STATE_CLICKABLE = _("clickable")
@@ -609,6 +622,7 @@ INVALID_INDICATORS_SPEECH = \
      STATE_INVALID_GRAMMAR_SPEECH]
 RADIO_BUTTON_INDICATORS_SPEECH = \
     [STATE_UNSELECTED_RADIO_BUTTON, STATE_SELECTED_RADIO_BUTTON]
+
 SWITCH_INDICATORS_SPEECH = [STATE_OFF_SWITCH, STATE_ON_SWITCH]
 TOGGLE_BUTTON_INDICATORS_SPEECH = \
     [STATE_NOT_PRESSED, STATE_PRESSED]
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index 9eea10f7e..1ed090286 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -1397,6 +1397,12 @@ class Utilities:
 
         return _settingsManager.getSetting('readFullRowInDocumentTable')
 
+    def isAscending(self, obj):
+        return False
+
+    def isDescending(self, obj):
+        return False
+
     def isFocusableLabel(self, obj):
         try:
             role = obj.getRole()
diff --git a/src/orca/scripts/web/script_utilities.py b/src/orca/scripts/web/script_utilities.py
index 8392e7457..34eae08a5 100644
--- a/src/orca/scripts/web/script_utilities.py
+++ b/src/orca/scripts/web/script_utilities.py
@@ -2650,6 +2650,18 @@ class Utilities(script_utilities.Utilities):
         self._isGridDescendant[hash(obj)] = rv
         return rv
 
+    def isSorted(self, obj):
+        attrs = self.objectAttributes(obj, False)
+        return not attrs.get("sort") in ("none", None)
+
+    def isAscending(self, obj):
+        attrs = self.objectAttributes(obj, False)
+        return attrs.get("sort") == "ascending"
+
+    def isDescending(self, obj):
+        attrs = self.objectAttributes(obj, False)
+        return attrs.get("sort") == "descending"
+
     def _rowAndColumnIndices(self, obj):
         rowindex = colindex = None
 
@@ -2867,6 +2879,8 @@ class Utilities(script_utilities.Utilities):
             rv = False
         elif self.isFigure(obj):
             rv = False
+        elif role in [pyatspi.ROLE_COLUMN_HEADER, pyatspi.ROLE_ROW_HEADER]:
+            rv = False
         elif role == pyatspi.ROLE_PANEL:
             rv = not self.hasExplicitName(obj)
         elif role == pyatspi.ROLE_TABLE_ROW and not state.contains(pyatspi.STATE_EXPANDABLE):
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index a01cdcb93..bf53f3067 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -951,6 +951,13 @@ class SpeechGenerator(generator.Generator):
 
         return result
 
+    def _generateSortOrder(self, obj, **args):
+        result = super()._generateSortOrder(obj, **args)
+        if result:
+            result.extend(self.voice(SYSTEM))
+
+        return result
+
     def _generateNewRowHeader(self, obj, **args):
         """Returns an array of strings (and possibly voice and audio
         specifications) that represent the row header for an object


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