[orca] Improve presentation and handling of editable ARIA combo boxes
- From: Joanmarie Diggs <joanied src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [orca] Improve presentation and handling of editable ARIA combo boxes
- Date: Mon, 11 Jul 2016 23:20:32 +0000 (UTC)
commit d913138c146614b2fd93d222447e3f78ee4f47e0
Author: Joanmarie Diggs <jdiggs igalia com>
Date: Mon Jul 11 19:11:37 2016 -0400
Improve presentation and handling of editable ARIA combo boxes
If we can determine a combo box is editable (which we cannot always do):
* Announce that it is editable
* Include it in structural navigation for entry
src/orca/object_properties.py | 7 ++++
src/orca/script_utilities.py | 6 +++
src/orca/scripts/web/script_utilities.py | 51 ++++++++++++++++++++++++++++++
src/orca/scripts/web/speech_generator.py | 3 ++
src/orca/speech_generator.py | 6 +++-
src/orca/structural_navigation.py | 2 +
6 files changed, 74 insertions(+), 1 deletions(-)
---
diff --git a/src/orca/object_properties.py b/src/orca/object_properties.py
index 7c010e4..a50e692 100644
--- a/src/orca/object_properties.py
+++ b/src/orca/object_properties.py
@@ -65,6 +65,13 @@ NODE_LEVEL_SPEECH = _("tree level %d")
# ancestors the node has). This is the braille version.
NODE_LEVEL_BRAILLE = _("TREE 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 for including the editable state as part of the role is to make it
+# possible for users to quickly identify combo boxes in which a value can be
+# typed or arrowed to.
+ROLE_EDITABLE_COMBO_BOX = _("editable combo box")
+
# Translators: The 'h' in this string represents a heading level attribute for
# content that you might find in something such as HTML content (e.g., <h1>).
# The translated form is meant to be a single character followed by a numeric
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index 04d9afc..ac5e25e 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -3256,6 +3256,12 @@ class Utilities:
def isEntryCompletionPopupItem(self, obj):
return False
+ def isEditableComboBox(self, obj):
+ return False
+
+ def isEditableDescendantOfComboBox(self, obj):
+ return False
+
def isPopOver(self, obj):
return False
diff --git a/src/orca/scripts/web/script_utilities.py b/src/orca/scripts/web/script_utilities.py
index 3764c8b..ea7dce8 100644
--- a/src/orca/scripts/web/script_utilities.py
+++ b/src/orca/scripts/web/script_utilities.py
@@ -65,6 +65,8 @@ class Utilities(script_utilities.Utilities):
self._id = {}
self._isClickableElement = {}
self._isAnchor = {}
+ self._isEditableComboBox = {}
+ self._isEditableDescendantOfComboBox = {}
self._isLandmark = {}
self._isLiveRegion = {}
self._isLink = {}
@@ -117,6 +119,8 @@ class Utilities(script_utilities.Utilities):
self._id = {}
self._isClickableElement = {}
self._isAnchor = {}
+ self._isEditableComboBox = {}
+ self._isEditableDescendantOfComboBox = {}
self._isLandmark = {}
self._isLiveRegion = {}
self._isLink = {}
@@ -2136,6 +2140,53 @@ class Utilities(script_utilities.Utilities):
self._isClickableElement[hash(obj)] = rv
return rv
+ def isEditableDescendantOfComboBox(self, obj):
+ if not (obj and self.inDocumentContent(obj)):
+ return super().isEditableDescendantOfComboBox(obj)
+
+ rv = self._isEditableDescendantOfComboBox.get(hash(obj))
+ if rv is not None:
+ return rv
+
+ try:
+ state = obj.getState()
+ except:
+ msg = "ERROR: Exception getting state for %s" % obj
+ debug.println(debug.LEVEL_INFO, msg, True)
+ return False
+
+ if not state.contains(pyatspi.STATE_EDITABLE):
+ return False
+
+ isComboBox = lambda x: x and x.getRole() == pyatspi.ROLE_COMBO_BOX
+ rv = pyatspi.findAncestor(obj, isComboBox) is not None
+
+ self._isEditableDescendantOfComboBox[hash(obj)] = rv
+ return rv
+
+ def isEditableComboBox(self, obj):
+ if not (obj and self.inDocumentContent(obj)):
+ return super().isEditableComboBox(obj)
+
+ rv = self._isEditableComboBox.get(hash(obj))
+ if rv is not None:
+ return rv
+
+ try:
+ role = obj.getRole()
+ state = obj.getState()
+ except:
+ msg = "ERROR: Exception getting role and state for %s" % obj
+ debug.println(debug.LEVEL_INFO, msg, True)
+ return False
+
+ rv = False
+ if role == pyatspi.ROLE_COMBO_BOX:
+ rv = state.contains(pyatspi.STATE_EDITABLE)
+
+ self._isEditableComboBox[hash(obj)] = rv
+ return rv
+
def isLandmark(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 ae72a85..49a2055 100644
--- a/src/orca/scripts/web/speech_generator.py
+++ b/src/orca/scripts/web/speech_generator.py
@@ -408,6 +408,9 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
if self._script.utilities.isTextBlockElement(obj):
return []
+ if self._script.utilities.isEditableComboBox(obj):
+ return []
+
position = self._script.utilities.getPositionInSet(obj)
total = self._script.utilities.getSetSize(obj)
if position is None or total is None:
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index d9350e5..d9f12f5 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -377,7 +377,7 @@ class SpeechGenerator(generator.Generator):
- role: an optional pyatspi role to use instead
"""
- if not isinstance(role, pyatspi.Role):
+ if not isinstance(role, (pyatspi.Role, Atspi.Role)):
try:
return obj.getLocalizedRoleName()
except:
@@ -386,6 +386,10 @@ class SpeechGenerator(generator.Generator):
if not role:
return ''
+ 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):
return object_properties.ROLE_VISITED_LINK
diff --git a/src/orca/structural_navigation.py b/src/orca/structural_navigation.py
index 418ebd2..e225a2b 100644
--- a/src/orca/structural_navigation.py
+++ b/src/orca/structural_navigation.py
@@ -1735,6 +1735,7 @@ class StructuralNavigation:
"""
role = [pyatspi.ROLE_DOCUMENT_FRAME,
+ pyatspi.ROLE_COMBO_BOX,
pyatspi.ROLE_ENTRY,
pyatspi.ROLE_PASSWORD_TEXT,
pyatspi.ROLE_TEXT]
@@ -1762,6 +1763,7 @@ class StructuralNavigation:
isMatch = False
if obj and obj.getRole() in [pyatspi.ROLE_DOCUMENT_FRAME,
+ pyatspi.ROLE_COMBO_BOX,
pyatspi.ROLE_ENTRY,
pyatspi.ROLE_PASSWORD_TEXT,
pyatspi.ROLE_TEXT]:
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]