[orca] Add structural navigation commands to move to start and end of current container
- From: Joanmarie Diggs <joanied src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [orca] Add structural navigation commands to move to start and end of current container
- Date: Mon, 6 Feb 2017 15:57:47 +0000 (UTC)
commit 7dd90e5691def1d93799299a1cd7e10b833f6e84
Author: Joanmarie Diggs <jdiggs igalia com>
Date: Mon Feb 6 10:56:14 2017 -0500
Add structural navigation commands to move to start and end of current container
* Shift+comma: start of container
* comma: end of container
help/C/commands_structural_navigation.page | 7 ++
src/orca/cmdnames.py | 10 ++
src/orca/messages.py | 15 +++
src/orca/script_utilities.py | 8 ++
src/orca/scripts/toolkits/WebKitGtk/script.py | 1 +
src/orca/scripts/web/script.py | 3 +-
src/orca/structural_navigation.py | 115 ++++++++++++++++++++++++-
7 files changed, 156 insertions(+), 3 deletions(-)
---
diff --git a/help/C/commands_structural_navigation.page b/help/C/commands_structural_navigation.page
index 4401d28..4dd3dc2 100644
--- a/help/C/commands_structural_navigation.page
+++ b/help/C/commands_structural_navigation.page
@@ -431,6 +431,13 @@
<keyseq><key>Alt</key><key>Shift</key><key>G</key></keyseq>
</p>
</item>
+ <item>
+ <p>
+ Start and end of current container:
+ <keyseq><key>Shift</key><key>comma</key></keyseq> and
+ <keyseq><key>comma</key></keyseq>
+ </p>
+ </item>
</list>
</section>
</page>
diff --git a/src/orca/cmdnames.py b/src/orca/cmdnames.py
index 5e61d1a..7e50b54 100644
--- a/src/orca/cmdnames.py
+++ b/src/orca/cmdnames.py
@@ -817,6 +817,16 @@ COMBO_BOX_PREV = _("Goes to previous combo box.")
# Translators: this is for navigating among combo boxes in a document.
COMBO_BOX_NEXT = _("Goes to next combo box.")
+# Translators: This string describes a document navigation command which moves
+# to the start of the current container. Examples of containers include tables,
+# lists, and blockquotes.
+CONTAINER_START = _("Goes to start of container.")
+
+# Translators: This string describes a document navigation command which moves
+# to the end of the current container. Examples of containers include tables,
+# lists, and blockquotes.
+CONTAINER_END = _("Goes to end of container.")
+
# Translators: this is for navigating among combo boxes in a document.
COMBO_BOX_LIST = _("Displays a list of combo boxes.")
diff --git a/src/orca/messages.py b/src/orca/messages.py
index 86b4b32..a2a3abb 100644
--- a/src/orca/messages.py
+++ b/src/orca/messages.py
@@ -386,6 +386,21 @@ DATE_FORMAT_ABBREVIATED_DMY = "%a, %-d %b, %Y"
DATE_FORMAT_ABBREVIATED_MDY = "%a, %b %-d, %Y"
DATE_FORMAT_ABBREVIATED_YMD = "%Y. %b %-d, %a."
+# Translators: This is for navigating document content by moving to the start
+# or end of a container. Examples of containers include tables, lists, and
+# blockquotes. When moving to the end of a container, Orca attempts to place
+# the caret at the content which follows that container. If this is cannot be
+# done (e.g. because the container is the last element on the page), Orca will
+# instead present this message as an indication that the container was not
+# exited as expected.
+CONTAINER_END = _("End of container.")
+
+# Translators: This is for navigating document content by moving to the start
+# or end of a container. Examples of containers include tables, lists, and
+# blockquotes. If the user attempts to use this command in an object which is
+# not a container, this message will be presented.
+CONTAINER_NOT_IN_A = _("Not in a container.")
+
# Translators: The "default" button in a dialog box is the button that gets
# activated when Enter is pressed anywhere within that dialog box.
DEFAULT_BUTTON_IS = _("Default button is %s")
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index 1bce4e0..f9dd001 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -3264,6 +3264,14 @@ class Utilities:
return obj, offset + 1
+ def lastContext(self, root):
+ offset = 0
+ text = self.queryNonEmptyText(root)
+ if text:
+ offset = text.characterCount - 1
+
+ return root, offset
+
@staticmethod
def getHyperlinkRange(obj):
"""Returns the start and end indices associated with the embedded
diff --git a/src/orca/scripts/toolkits/WebKitGtk/script.py b/src/orca/scripts/toolkits/WebKitGtk/script.py
index 641728c..6207d98 100644
--- a/src/orca/scripts/toolkits/WebKitGtk/script.py
+++ b/src/orca/scripts/toolkits/WebKitGtk/script.py
@@ -148,6 +148,7 @@ class Script(default.Script):
structural_navigation.StructuralNavigation.CHUNK,
structural_navigation.StructuralNavigation.CLICKABLE,
structural_navigation.StructuralNavigation.COMBO_BOX,
+ structural_navigation.StructuralNavigation.CONTAINER,
structural_navigation.StructuralNavigation.ENTRY,
structural_navigation.StructuralNavigation.FORM_FIELD,
structural_navigation.StructuralNavigation.HEADING,
diff --git a/src/orca/scripts/web/script.py b/src/orca/scripts/web/script.py
index c8ca248..53c0354 100644
--- a/src/orca/scripts/web/script.py
+++ b/src/orca/scripts/web/script.py
@@ -254,6 +254,7 @@ class Script(default.Script):
structural_navigation.StructuralNavigation.CHUNK,
structural_navigation.StructuralNavigation.CLICKABLE,
structural_navigation.StructuralNavigation.COMBO_BOX,
+ structural_navigation.StructuralNavigation.CONTAINER,
structural_navigation.StructuralNavigation.ENTRY,
structural_navigation.StructuralNavigation.FORM_FIELD,
structural_navigation.StructuralNavigation.HEADING,
@@ -801,7 +802,7 @@ class Script(default.Script):
def presentObject(self, obj, **args):
priorObj = None
- if self._lastCommandWasCaretNav:
+ if self._lastCommandWasCaretNav or args.get("includeContext"):
priorObj, priorOffset = self.utilities.getPriorContext()
offset = args.get("offset", 0)
diff --git a/src/orca/structural_navigation.py b/src/orca/structural_navigation.py
index 0cc9b0c..0ebea92 100644
--- a/src/orca/structural_navigation.py
+++ b/src/orca/structural_navigation.py
@@ -295,6 +295,8 @@ class StructuralNavigationObject:
directions["Down"] = self.bindings.get("down")
directions["First"] = self.bindings.get("first")
directions["Last"] = self.bindings.get("last")
+ directions["Start"] = self.bindings.get("start")
+ directions["End"] = self.bindings.get("end")
for direction in directions:
binding = directions.get(direction)
@@ -510,6 +512,12 @@ class StructuralNavigationObject:
else:
script.presentMessage(messages.LIVE_REGIONS_OFF)
+ def goContainerEdge(script, inputEvent):
+ isStart = direction == "Start"
+ self.structuralNavigation.goEdge(self, isStart)
+
+ if self.objType == StructuralNavigation.CONTAINER:
+ return goContainerEdge
if self.objType == StructuralNavigation.TABLE_CELL:
return goCell
elif self.objType == StructuralNavigation.LIVE_REGION \
@@ -551,6 +559,7 @@ class StructuralNavigation:
CHUNK = "chunk"
CLICKABLE = "clickable"
COMBO_BOX = "comboBox"
+ CONTAINER = "container"
ENTRY = "entry"
FORM_FIELD = "formField"
HEADING = "heading"
@@ -601,6 +610,16 @@ class StructuralNavigation:
pyatspi.ROLE_DOCUMENT_TEXT,
pyatspi.ROLE_DOCUMENT_WEB]
+ CONTAINER_ROLES = [pyatspi.ROLE_BLOCK_QUOTE,
+ pyatspi.ROLE_FORM,
+ pyatspi.ROLE_FOOTER,
+ pyatspi.ROLE_HEADER,
+ pyatspi.ROLE_LANDMARK,
+ pyatspi.ROLE_LIST,
+ pyatspi.ROLE_PANEL,
+ pyatspi.ROLE_SECTION,
+ pyatspi.ROLE_TABLE]
+
IMAGE_ROLES = [pyatspi.ROLE_IMAGE,
pyatspi.ROLE_IMAGE_MAP]
@@ -865,6 +884,36 @@ class StructuralNavigation:
self._objectCache[hash(document)] = cache
return rv
+ def goEdge(self, structuralNavigationObject, isStart, container=None, arg=None):
+ if container is None:
+ obj, offset = self._script.utilities.getCaretContext()
+ container = self.getContainerForObject(obj)
+
+ if container is None or self._script.utilities.isDead(container):
+ structuralNavigationObject.present(None, arg)
+ return
+
+ if isStart:
+ obj, offset = self._script.utilities.nextContext(container, -1)
+ structuralNavigationObject.present(obj, offset)
+ return
+
+ obj, offset = self._script.utilities.lastContext(container)
+ newObj, newOffset = self._script.utilities.nextContext(obj, offset)
+ if not newObj:
+ document = self._script.utilities.getDocumentForObject(obj)
+ newObj = self._script.utilities.getNextObjectInDocument(obj, document)
+
+ newContainer = self.getContainerForObject(newObj)
+ if newObj and newContainer != container:
+ structuralNavigationObject.present(newObj)
+ return
+
+ if obj == container:
+ obj = obj[-1]
+
+ structuralNavigationObject.present(obj, sameContainer=True)
+
def goObject(self, structuralNavigationObject, isNext, obj=None, arg=None):
"""The method used for navigation among StructuralNavigationObjects
which are not table cells.
@@ -1004,6 +1053,31 @@ class StructuralNavigation:
return obj
+ def _isContainer(self, obj):
+ try:
+ role = obj.getRole()
+ except:
+ return False
+
+ if role not in self.CONTAINER_ROLES:
+ return False
+
+ if role == pyatspi.ROLE_SECTION \
+ and not self._script.utilities.isLandmark(obj) \
+ and not self._script.utilities.isBlockquote(obj):
+ return False
+
+ return self._script.utilities.inDocumentContent(obj)
+
+ def getContainerForObject(self, obj):
+ if not obj:
+ return None
+
+ if self._isContainer(obj):
+ return obj
+
+ return pyatspi.utils.findAncestor(obj, self._isContainer)
+
def getTableForCell(self, obj):
"""Looks for a table in the ancestry of obj, if obj is not a table.
@@ -1143,7 +1217,7 @@ class StructuralNavigation:
self._script.updateBraille(obj)
self._script.sayLine(obj)
- def _presentObject(self, obj, offset):
+ def _presentObject(self, obj, offset, includeContext=False):
"""Presents the entire object to the user.
Arguments:
@@ -1157,7 +1231,7 @@ class StructuralNavigation:
if self._presentWithSayAll(obj, offset):
return
- self._script.presentObject(obj, offset=offset)
+ self._script.presentObject(obj, offset=offset, includeContext=includeContext)
def _presentWithSayAll(self, obj, offset):
if self._script.inSayAll() \
@@ -3211,3 +3285,40 @@ class StructuralNavigation:
return [self._getText(obj), self._getRoleName(obj)]
return guilabels.SN_TITLE_CLICKABLE, columnHeaders, rowData
+
+ ########################
+ # #
+ # Containers #
+ # #
+ ########################
+
+ def _containerBindings(self):
+ bindings = {}
+ desc = cmdnames.CONTAINER_START
+ bindings["start"] = ["comma", keybindings.SHIFT_MODIFIER_MASK, desc]
+
+ desc = cmdnames.CONTAINER_END
+ bindings["end"] = ["comma", keybindings.NO_MODIFIER_MASK, desc]
+
+ return bindings
+
+ def _containerCriteria(self, collection, arg=None):
+ return MatchCriteria(collection, roles=self.CONTAINER_ROLES, applyPredicate=True)
+
+ def _containerPredicate(self, obj, arg=None):
+ return self._isContainer(obj)
+
+ def _containerPresentation(self, obj, arg=None, **kwargs):
+ if not obj:
+ self._script.presentMessage(messages.CONTAINER_NOT_IN_A)
+ return
+
+ if kwargs.get("sameContainer"):
+ self._script.presentMessage(messages.CONTAINER_END)
+
+ characterOffset = arg
+ if characterOffset is None:
+ obj, characterOffset = self._getCaretPosition(obj)
+
+ self._setCaretPosition(obj, characterOffset)
+ self._presentObject(obj, characterOffset, True)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]