[orca] Improve presentation of nested lists and blockquotes as context



commit d387e1b8be35eade05fc4bed4f5dbb8e0bfeafd8
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Wed Feb 1 12:42:17 2017 +0100

    Improve presentation of nested lists and blockquotes as context
    
    * Present level of nested elements
    * Collapse "leaving" messages into a single message

 src/orca/formatting.py                             |    6 +-
 src/orca/messages.py                               |   11 +
 src/orca/script_utilities.py                       |   22 ++-
 src/orca/speech_generator.py                       |   79 ++++---
 test/html/nested-stuff.html                        |   44 ++++
 .../firefox/line_nav_nested_items.params           |    1 +
 test/keystrokes/firefox/line_nav_nested_items.py   |  240 ++++++++++++++++++++
 .../firefox/line_nav_nested_items.settings         |  165 ++++++++++++++
 .../line_nav_nested_items_no_context.params        |    1 +
 .../firefox/line_nav_nested_items_no_context.py    |  199 ++++++++++++++++
 .../line_nav_nested_items_no_context.settings      |  165 ++++++++++++++
 11 files changed, 889 insertions(+), 44 deletions(-)
---
diff --git a/src/orca/formatting.py b/src/orca/formatting.py
index c524e87..3ea24f4 100644
--- a/src/orca/formatting.py
+++ b/src/orca/formatting.py
@@ -133,8 +133,8 @@ formatting = {
             'unfocused': 'labelAndName'
             },
         pyatspi.ROLE_BLOCK_QUOTE: {
-            'focused' : 'leaving or roleName',
-            'unfocused': 'roleName + pause + displayedText',
+            'focused' : 'leaving or (roleName + pause + nestingLevel)',
+            'unfocused': 'roleName + pause + nestingLevel + pause + displayedText',
             },
         pyatspi.ROLE_CANVAS: {
             'focused': 'labelAndName + imageDescription + roleName + pause + positionInList',
@@ -244,7 +244,7 @@ formatting = {
             'basicWhereAmI': 'linkInfo + pause + siteDescription + pause + fileSize + pause + ' + MNEMONIC
             },
         pyatspi.ROLE_LIST: {
-            'focused': 'leaving or (labelOrName + multiselectableState + numberOfChildren)',
+            'focused' : 'leaving or (numberOfChildren + pause + nestingLevel)',
             'unfocused': 'labelOrName + pause + focusedItem + pause + multiselectableState + 
numberOfChildren + pause'
             },
         pyatspi.ROLE_LIST_BOX: {
diff --git a/src/orca/messages.py b/src/orca/messages.py
index 9f9deb2..86b4b32 100644
--- a/src/orca/messages.py
+++ b/src/orca/messages.py
@@ -2134,6 +2134,17 @@ def itemsFound(count):
     # presented to the user to indicate how many matching items were found.
     return ngettext("%d item found", "%d items found", count) % count
 
+def leavingNBlockquotes(count):
+    # Translators: This message is presented when a user is navigating within a
+    # series of nested blockquotes, such as can be seen in deep email threads,
+    # and then navigates out of several levels at once.
+    return ngettext("Leaving %d blockquote.", "Leaving %d blockquotes.", count) % count
+
+def leavingNLists(count):
+    # Translators: This message is presented when a user is navigating within a
+    # series of nested lists and then navigates out of several levels at once.
+    return ngettext("Leaving %d list.", "Leaving %d lists.", count) % count
+
 def listItemCount(count):
     # Translators: This message describes a bulleted or numbered list.
     return ngettext("List with %d item", "List with %d items", count) % count
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index 623d2fd..1bce4e0 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -1510,8 +1510,7 @@ class Utilities:
         return -1
 
     def nestingLevel(self, obj):
-        """Determines the nesting level of this object in a list.  If this
-        object is not in a list relation, then 0 will be returned.
+        """Determines the nesting level of this object.
 
         Arguments:
         -obj: the Accessible object
@@ -1526,12 +1525,21 @@ class Utilities:
             if self.NESTING_LEVEL not in self._script.generatorCache:
                 self._script.generatorCache[self.NESTING_LEVEL] = {}
 
-        nestingLevel = 0
-        parent = obj.parent
-        while parent.parent and parent.parent.getRole() == pyatspi.ROLE_LIST:
-            nestingLevel += 1
-            parent = parent.parent
+        if self.isBlockquote(obj):
+            pred = lambda x: self.isBlockquote(x)
+        elif obj.getRole() == pyatspi.ROLE_LIST_ITEM:
+            pred = lambda x: x and x.parent and x.parent.getRole() == pyatspi.ROLE_LIST
+        else:
+            role = obj.getRole()
+            pred = lambda x: x and x.getRole() == role
+
+        ancestors = []
+        ancestor = pyatspi.findAncestor(obj, pred)
+        while ancestor:
+            ancestors.append(ancestor)
+            ancestor = pyatspi.findAncestor(ancestor, pred)
 
+        nestingLevel = len(ancestors)
         self._script.generatorCache[self.NESTING_LEVEL][obj] = nestingLevel
         return self._script.generatorCache[self.NESTING_LEVEL][obj]
 
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index d8aa108..fa175d3 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -1584,11 +1584,19 @@ class SpeechGenerator(generator.Generator):
         if not role in enabled:
             return []
 
+        count = args.get('count', 1)
+
         result = []
         if role == pyatspi.ROLE_BLOCK_QUOTE:
-            result.append(messages.LEAVING_BLOCKQUOTE)
+            if count > 1:
+                result.append(messages.leavingNBlockquotes(count))
+            else:
+                result.append(messages.LEAVING_BLOCKQUOTE)
         elif role == pyatspi.ROLE_LIST and self._script.utilities.isDocumentList(obj):
-            result.append(messages.LEAVING_LIST)
+            if count > 1:
+                result.append(messages.leavingNLists(count))
+            else:
+                result.append(messages.LEAVING_LIST)
         elif role == pyatspi.ROLE_PANEL and self._script.utilities.isDocumentPanel(obj):
             result.append(messages.LEAVING_PANEL)
         elif role == pyatspi.ROLE_TABLE and self._script.utilities.isTextDocumentTable(obj):
@@ -1646,20 +1654,8 @@ class SpeechGenerator(generator.Generator):
             return []
 
         commonAncestor = self._script.utilities.commonAncestor(priorObj, obj)
-        try:
-            role = commonAncestor.getRole()
-            name = commonAncestor.name
-        except:
-            role = None
-            name = None
-        else:
-            if role == pyatspi.ROLE_COMBO_BOX:
-                return []
-
-        def _isCommonAncestor(x):
-            if not (name and role):
-                return False
-            return x and x.getRole() == role and x.name == name
+        if obj == commonAncestor:
+            return []
 
         includeOnly = args.get('includeOnly', [])
 
@@ -1671,25 +1667,40 @@ class SpeechGenerator(generator.Generator):
         stopAtRoles = args.get('stopAtRoles', [])
         stopAtRoles.append(pyatspi.ROLE_APPLICATION)
 
-        if obj != commonAncestor:
-            parent = obj.parent
-            while parent and not parent in [commonAncestor, parent.parent]:
-                if _isCommonAncestor(parent):
-                    break
+        presentOnce = [pyatspi.ROLE_BLOCK_QUOTE, pyatspi.ROLE_LIST]
 
-                parentRole = self._getAlternativeRole(parent)
-                if parentRole in stopAtRoles:
-                    break
-                if parentRole in skipRoles:
-                    pass
-                elif includeOnly and parentRole not in includeOnly:
-                    pass
-                elif not self._script.utilities.isLayoutOnly(parent):
-                    self._overrideRole(parentRole, args)
-                    result.append(self.generate(parent, formatType='focused',
-                                                role=parentRole, leaving=leaving))
-                    self._restoreRole(parentRole, args)
-                parent = parent.parent
+        ancestors, ancestorRoles = [], []
+        parent = obj.parent
+        while parent and parent != parent.parent:
+            parentRole = self._getAlternativeRole(parent)
+            if parentRole in stopAtRoles:
+                break
+            if parentRole in skipRoles:
+                pass
+            elif includeOnly and parentRole not in includeOnly:
+                pass
+            elif self._script.utilities.isLayoutOnly(parent):
+                pass
+            elif parent != commonAncestor or (not leaving and parentRole in presentOnce):
+                ancestors.append(parent)
+                ancestorRoles.append(parentRole)
+
+            if parent == commonAncestor:
+                break
+
+            parent = parent.parent
+
+        presentedRoles = []
+        for i, x in enumerate(ancestors):
+            altRole = ancestorRoles[i]
+            if altRole in presentOnce and altRole in presentedRoles:
+                continue
+
+            presentedRoles.append(altRole)
+            count = ancestorRoles.count(altRole)
+            self._overrideRole(altRole, args)
+            result.append(self.generate(x, formatType='focused', role=altRole, leaving=leaving, count=count))
+            self._restoreRole(altRole, args)
 
         if not leaving:
             result.reverse()
diff --git a/test/html/nested-stuff.html b/test/html/nested-stuff.html
new file mode 100644
index 0000000..397fa9a
--- /dev/null
+++ b/test/html/nested-stuff.html
@@ -0,0 +1,44 @@
+<html>
+<head>
+<style>
+ul { list-style: none; }
+blockquote { border-left: 5px solid grey; padding-left: 10px; margin-left:5px; }
+</style>
+</head>
+<body>
+<p>Nest all the things!</p>
+<ul>
+  <li>Hello world</li>
+  <li>
+    <ul>
+      <li>Nested item</li>
+      <li>
+        <ul>
+          <li>Even-more-nested item</li>
+          <li>
+            <ul>
+              <li>Is this seriously necessary?</li>
+            </ul>
+          </li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+</ul>
+<p>Because why not?</p>
+<blockquote>
+  <p>Here's a quote</p>
+  <blockquote>
+      <p>A nested quote</p>
+       <blockquote>
+          <p>Containing a quote</p>
+          <blockquote>
+             <p>Which contains a quote</p>
+          </blockquote>
+       </blockquote>
+  </blockquote>
+  <p>Just... one... more... thing!</p>
+</blockquote>
+<p>The end.</p>
+</body>
+</html>
diff --git a/test/keystrokes/firefox/line_nav_nested_items.params 
b/test/keystrokes/firefox/line_nav_nested_items.params
new file mode 100644
index 0000000..f19a661
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_nested_items.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/nested-stuff.html
diff --git a/test/keystrokes/firefox/line_nav_nested_items.py 
b/test/keystrokes/firefox/line_nav_nested_items.py
new file mode 100644
index 0000000..abe51d0
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_nested_items.py
@@ -0,0 +1,240 @@
+#!/usr/bin/python
+
+"""Test of line navigation output of Firefox."""
+
+from macaroon.playback import *
+import utils
+
+sequence = MacroSequence()
+
+#sequence.append(WaitForDocLoad())
+sequence.append(PauseAction(5000))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("<Control>Home"))
+sequence.append(utils.AssertPresentationAction(
+    "1. Top of file",
+    ["BRAILLE LINE:  'Nest all the things!'",
+     "     VISIBLE:  'Nest all the things!', cursor=1",
+     "SPEECH OUTPUT: 'Nest all the things!'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "2. Line Down",
+    ["BRAILLE LINE:  'Hello world'",
+     "     VISIBLE:  'Hello world', cursor=1",
+     "SPEECH OUTPUT: 'List with 2 items.'",
+     "SPEECH OUTPUT: 'Hello world.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "3. Line Down",
+    ["BRAILLE LINE:  'Nested item'",
+     "     VISIBLE:  'Nested item', cursor=1",
+     "SPEECH OUTPUT: 'List with 2 items.'",
+     "SPEECH OUTPUT: 'Nesting level 1'",
+     "SPEECH OUTPUT: 'Nested item.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "4. Line Down",
+    ["BRAILLE LINE:  'Even-more-nested item'",
+     "     VISIBLE:  'Even-more-nested item', cursor=1",
+     "SPEECH OUTPUT: 'List with 2 items.'",
+     "SPEECH OUTPUT: 'Nesting level 2'",
+     "SPEECH OUTPUT: 'Even-more-nested item.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "5. Line Down",
+    ["BRAILLE LINE:  'Is this seriously necessary?'",
+     "     VISIBLE:  'Is this seriously necessary?', cursor=1",
+     "SPEECH OUTPUT: 'List with 1 item.'",
+     "SPEECH OUTPUT: 'Nesting level 3'",
+     "SPEECH OUTPUT: 'Is this seriously necessary?.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "6. Line Down",
+    ["BRAILLE LINE:  'Because why not?'",
+     "     VISIBLE:  'Because why not?', cursor=1",
+     "SPEECH OUTPUT: 'Leaving 4 lists.'",
+     "SPEECH OUTPUT: 'Because why not?'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "7. Line Down",
+    ["BRAILLE LINE:  'Here's a quote'",
+     "     VISIBLE:  'Here's a quote', cursor=1",
+     "SPEECH OUTPUT: 'block quote.'",
+     "SPEECH OUTPUT: 'Here's a quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "8. Line Down",
+    ["BRAILLE LINE:  'A nested quote'",
+     "     VISIBLE:  'A nested quote', cursor=1",
+     "SPEECH OUTPUT: 'block quote.'",
+     "SPEECH OUTPUT: 'Nesting level 1'",
+     "SPEECH OUTPUT: 'A nested quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "9. Line Down",
+    ["BRAILLE LINE:  'Containing a quote'",
+     "     VISIBLE:  'Containing a quote', cursor=1",
+     "SPEECH OUTPUT: 'block quote.'",
+     "SPEECH OUTPUT: 'Nesting level 2'",
+     "SPEECH OUTPUT: 'Containing a quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "10. Line Down",
+    ["BRAILLE LINE:  'Which contains a quote'",
+     "     VISIBLE:  'Which contains a quote', cursor=1",
+     "SPEECH OUTPUT: 'block quote.'",
+     "SPEECH OUTPUT: 'Nesting level 3'",
+     "SPEECH OUTPUT: 'Which contains a quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "11. Line Down",
+    ["BRAILLE LINE:  'Just... one... more... thing!'",
+     "     VISIBLE:  'Just... one... more... thing!', cursor=1",
+     "SPEECH OUTPUT: 'Leaving 3 blockquotes.'",
+     "SPEECH OUTPUT: 'block quote.'",
+     "SPEECH OUTPUT: 'Just... one... more... thing!'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "12. Line Down",
+    ["BRAILLE LINE:  'The end.'",
+     "     VISIBLE:  'The end.', cursor=1",
+     "SPEECH OUTPUT: 'leaving blockquote.'",
+     "SPEECH OUTPUT: 'The end.'"]))
+
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "13. Line Up",
+    ["BRAILLE LINE:  'Just... one... more... thing!'",
+     "     VISIBLE:  'Just... one... more... thing!', cursor=1",
+     "SPEECH OUTPUT: 'block quote.'",
+     "SPEECH OUTPUT: 'Just... one... more... thing!'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "14. Line Up",
+    ["BRAILLE LINE:  'Which contains a quote'",
+     "     VISIBLE:  'Which contains a quote', cursor=1",
+     "SPEECH OUTPUT: 'block quote.'",
+     "SPEECH OUTPUT: 'Nesting level 3'",
+     "SPEECH OUTPUT: 'Which contains a quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "15. Line Up",
+    ["BRAILLE LINE:  'Containing a quote'",
+     "     VISIBLE:  'Containing a quote', cursor=1",
+     "SPEECH OUTPUT: 'leaving blockquote.'",
+     "SPEECH OUTPUT: 'block quote.'",
+     "SPEECH OUTPUT: 'Nesting level 2'",
+     "SPEECH OUTPUT: 'Containing a quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "16. Line Up",
+    ["BRAILLE LINE:  'A nested quote'",
+     "     VISIBLE:  'A nested quote', cursor=1",
+     "SPEECH OUTPUT: 'leaving blockquote.'",
+     "SPEECH OUTPUT: 'block quote.'",
+     "SPEECH OUTPUT: 'Nesting level 1'",
+     "SPEECH OUTPUT: 'A nested quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "17. Line Up",
+    ["BRAILLE LINE:  'Here's a quote'",
+     "     VISIBLE:  'Here's a quote', cursor=1",
+     "SPEECH OUTPUT: 'leaving blockquote.'",
+     "SPEECH OUTPUT: 'block quote.'",
+     "SPEECH OUTPUT: 'Here's a quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "18. Line Up",
+    ["BRAILLE LINE:  'Because why not?'",
+     "     VISIBLE:  'Because why not?', cursor=1",
+     "SPEECH OUTPUT: 'leaving blockquote.'",
+     "SPEECH OUTPUT: 'Because why not?'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "19. Line Up",
+    ["BRAILLE LINE:  'Is this seriously necessary?'",
+     "     VISIBLE:  'Is this seriously necessary?', cursor=1",
+     "SPEECH OUTPUT: 'List with 1 item.'",
+     "SPEECH OUTPUT: 'Nesting level 3'",
+     "SPEECH OUTPUT: 'Is this seriously necessary?.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "20. Line Up",
+    ["BRAILLE LINE:  'Even-more-nested item'",
+     "     VISIBLE:  'Even-more-nested item', cursor=1",
+     "SPEECH OUTPUT: 'leaving list.'",
+     "SPEECH OUTPUT: 'List with 2 items.'",
+     "SPEECH OUTPUT: 'Nesting level 2'",
+     "SPEECH OUTPUT: 'Even-more-nested item.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "21. Line Up",
+    ["BRAILLE LINE:  'Nested item'",
+     "     VISIBLE:  'Nested item', cursor=1",
+     "SPEECH OUTPUT: 'leaving list.'",
+     "SPEECH OUTPUT: 'List with 2 items.'",
+     "SPEECH OUTPUT: 'Nesting level 1'",
+     "SPEECH OUTPUT: 'Nested item.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "22. Line Up",
+    ["BRAILLE LINE:  'Hello world'",
+     "     VISIBLE:  'Hello world', cursor=1",
+     "SPEECH OUTPUT: 'leaving list.'",
+     "SPEECH OUTPUT: 'List with 2 items.'",
+     "SPEECH OUTPUT: 'Hello world.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "23. Line Up",
+    ["BRAILLE LINE:  'Nest all the things!'",
+     "     VISIBLE:  'Nest all the things!', cursor=1",
+     "SPEECH OUTPUT: 'leaving list.'",
+     "SPEECH OUTPUT: 'Nest all the things!'"]))
+
+sequence.append(utils.AssertionSummaryAction())
+sequence.start()
diff --git a/test/keystrokes/firefox/line_nav_nested_items.settings 
b/test/keystrokes/firefox/line_nav_nested_items.settings
new file mode 100644
index 0000000..7efb046
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_nested_items.settings
@@ -0,0 +1,165 @@
+{
+    "general": {
+        "enabledSpokenTextAttributes": "size:; family-name:; weight:400; indent:0; underline:none; 
strikethrough:false; justification:left; style:normal; paragraph-style:; text-spelling:none; fg-color:; 
bg-color:;",
+        "orcaModifierKeys": [
+            "Insert",
+            "KP_Insert"
+        ],
+        "skipBlankCells": false,
+        "onlySpeakDisplayedText": false,
+        "enableMnemonicSpeaking": false,
+        "chatAnnounceBuddyTyping": false,
+        "messagesAreDetailed": true,
+        "speakProgressBarUpdates": true,
+        "speakCellCoordinates": true,
+        "enableAlphabeticKeys": true,
+        "enableBraille": false,
+        "brailleAlignmentStyle": 0,
+        "playSoundForPositionInSet": false,
+        "sayAllStyle": 1,
+        "enableEchoBySentence": false,
+        "chatSpeakRoomName": false,
+        "soundVolume": 0.5,
+        "activeProfile": [
+            "Default",
+            "default"
+        ],
+        "brailleVerbosityLevel": 1,
+        "sayAllContextTable": true,
+        "enableTutorialMessages": false,
+        "wrappedStructuralNavigation": true,
+        "capitalizationStyle": "none",
+        "findResultsMinimumLength": 4,
+        "enableContractedBraille": false,
+        "presentDateFormat": "%x",
+        "enableSpeechIndentation": false,
+        "brailleContractionTable": "",
+        "structNavTriggersFocusMode": false,
+        "enablePauseBreaks": true,
+        "speakNumbersAsDigits": false,
+        "spellcheckSpellError": true,
+        "useColorNames": true,
+        "speakContextTable": true,
+        "readFullRowInGUITable": true,
+        "enabledBrailledTextAttributes": "size:; family-name:; weight:400; indent:0; underline:none; 
strikethrough:false; justification:left; style:normal; text-spelling:none;",
+        "enableSpace": true,
+        "brailleSelectorIndicator": 192,
+        "profile": [
+            "Default",
+            "default"
+        ],
+        "verbalizePunctuationStyle": 1,
+        "enableBrailleContext": true,
+        "enableNavigationKeys": false,
+        "structNavInSayAll": false,
+        "enableSound": true,
+        "speakCellSpan": true,
+        "speechVerbosityLevel": 1,
+        "brailleRolenameStyle": 1,
+        "mouseDwellDelay": null,
+        "enableSpeech": true,
+        "caretNavTriggersFocusMode": false,
+        "enableDiacriticalKeys": false,
+        "findResultsVerbosity": 2,
+        "sayAllContextBlockquote": true,
+        "speakBlankLines": true,
+        "speakSpreadsheetCoordinates": true,
+        "flashIsPersistent": false,
+        "enableNumericKeys": true,
+        "enableFlashMessages": true,
+        "progressBarVerbosity": 1,
+        "brailleLinkIndicator": 192,
+        "presentTimeFormat": "%X",
+        "enablePunctuationKeys": true,
+        "enableKeyEcho": false,
+        "playSoundForState": false,
+        "beepProgressBarUpdates": false,
+        "enableFunctionKeys": true,
+        "speakMisspelledIndicator": true,
+        "textAttributesBrailleIndicator": 0,
+        "voices": {
+            "default": {
+                "established": false
+            },
+            "system": {
+                "established": false
+            },
+            "uppercase": {
+                "average-pitch": 7.0
+            },
+            "hyperlink": {
+                "established": false
+            }
+        },
+        "enableBrailleMonitor": true,
+        "layoutMode": true,
+        "brailleFlashTime": 5000,
+        "largeObjectTextLength": 75,
+        "speakContextList": true,
+        "ignoreStatusBarProgressBars": true,
+        "keyboardLayout": 1,
+        "brailleProgressBarUpdates": false,
+        "readFullRowInSpreadSheet": false,
+        "enableActionKeys": true,
+        "enablePositionSpeaking": false,
+        "structuralNavigationEnabled": true,
+        "playSoundForRole": false,
+        "disableBrailleEOL": false,
+        "presentToolTips": false,
+        "enableMouseReview": false,
+        "speechServerFactory": "speechdispatcherfactory",
+        "chatMessageVerbosity": 0,
+        "enableEchoByWord": false,
+        "spellcheckSpellSuggestion": true,
+        "enableModifierKeys": true,
+        "speakMultiCaseStringsAsWords": false,
+        "flashIsDetailed": true,
+        "speakCellHeaders": true,
+        "rewindAndFastForwardInSayAll": false,
+        "sayAllContextList": true,
+        "speakContextBlockquote": true,
+        "enableEchoByCharacter": false,
+        "playSoundForValue": false,
+        "progressBarUpdateInterval": 10,
+        "spellcheckPresentContext": true,
+        "speechServerInfo": null,
+        "chatRoomHistories": false,
+        "readFullRowInDocumentTable": true,
+        "startingProfile": [
+            "Default",
+            "default"
+        ]
+    },
+    "keybindings": {},
+    "profiles": {
+        "default": {
+            "profile": [
+                "Default",
+                "default"
+            ],
+            "brailleContractionTable": "/usr/share/liblouis/tables/en-us-compbrl.ctb",
+            "voices": {
+                "default": {
+                    "established": false
+                },
+                "system": {
+                    "established": false
+                },
+                "uppercase": {
+                    "average-pitch": 7.0
+                },
+                "hyperlink": {
+                    "established": false
+                }
+            },
+            "pronunciations": {},
+            "speechServerInfo": [
+                "Default Synthesizer",
+                "default"
+            ],
+            "keybindings": {},
+            "speechServerFactory": "orca.speechdispatcherfactory"
+        }
+    },
+    "pronunciations": {}
+}
\ No newline at end of file
diff --git a/test/keystrokes/firefox/line_nav_nested_items_no_context.params 
b/test/keystrokes/firefox/line_nav_nested_items_no_context.params
new file mode 100644
index 0000000..f19a661
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_nested_items_no_context.params
@@ -0,0 +1 @@
+PARAMS=$TEST_DIR/../../html/nested-stuff.html
diff --git a/test/keystrokes/firefox/line_nav_nested_items_no_context.py 
b/test/keystrokes/firefox/line_nav_nested_items_no_context.py
new file mode 100644
index 0000000..6fe16fe
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_nested_items_no_context.py
@@ -0,0 +1,199 @@
+#!/usr/bin/python
+
+"""Test of line navigation output of Firefox."""
+
+from macaroon.playback import *
+import utils
+
+sequence = MacroSequence()
+
+#sequence.append(WaitForDocLoad())
+sequence.append(PauseAction(5000))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("<Control>Home"))
+sequence.append(utils.AssertPresentationAction(
+    "1. Top of file",
+    ["BRAILLE LINE:  'Nest all the things!'",
+     "     VISIBLE:  'Nest all the things!', cursor=1",
+     "SPEECH OUTPUT: 'Nest all the things!'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "2. Line Down",
+    ["BRAILLE LINE:  'Hello world'",
+     "     VISIBLE:  'Hello world', cursor=1",
+     "SPEECH OUTPUT: 'Hello world.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "3. Line Down",
+    ["BRAILLE LINE:  'Nested item'",
+     "     VISIBLE:  'Nested item', cursor=1",
+     "SPEECH OUTPUT: 'Nested item.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "4. Line Down",
+    ["BRAILLE LINE:  'Even-more-nested item'",
+     "     VISIBLE:  'Even-more-nested item', cursor=1",
+     "SPEECH OUTPUT: 'Even-more-nested item.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "5. Line Down",
+    ["BRAILLE LINE:  'Is this seriously necessary?'",
+     "     VISIBLE:  'Is this seriously necessary?', cursor=1",
+     "SPEECH OUTPUT: 'Is this seriously necessary?.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "6. Line Down",
+    ["BRAILLE LINE:  'Because why not?'",
+     "     VISIBLE:  'Because why not?', cursor=1",
+     "SPEECH OUTPUT: 'Because why not?'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "7. Line Down",
+    ["BRAILLE LINE:  'Here's a quote'",
+     "     VISIBLE:  'Here's a quote', cursor=1",
+     "SPEECH OUTPUT: 'Here's a quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "8. Line Down",
+    ["BRAILLE LINE:  'A nested quote'",
+     "     VISIBLE:  'A nested quote', cursor=1",
+     "SPEECH OUTPUT: 'A nested quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "9. Line Down",
+    ["BRAILLE LINE:  'Containing a quote'",
+     "     VISIBLE:  'Containing a quote', cursor=1",
+     "SPEECH OUTPUT: 'Containing a quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "10. Line Down",
+    ["BRAILLE LINE:  'Which contains a quote'",
+     "     VISIBLE:  'Which contains a quote', cursor=1",
+     "SPEECH OUTPUT: 'Which contains a quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "11. Line Down",
+    ["BRAILLE LINE:  'Just... one... more... thing!'",
+     "     VISIBLE:  'Just... one... more... thing!', cursor=1",
+     "SPEECH OUTPUT: 'Just... one... more... thing!'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Down"))
+sequence.append(utils.AssertPresentationAction(
+    "12. Line Down",
+    ["BRAILLE LINE:  'The end.'",
+     "     VISIBLE:  'The end.', cursor=1",
+     "SPEECH OUTPUT: 'The end.'"]))
+
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "13. Line Up",
+    ["BRAILLE LINE:  'Just... one... more... thing!'",
+     "     VISIBLE:  'Just... one... more... thing!', cursor=1",
+     "SPEECH OUTPUT: 'Just... one... more... thing!'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "14. Line Up",
+    ["BRAILLE LINE:  'Which contains a quote'",
+     "     VISIBLE:  'Which contains a quote', cursor=1",
+     "SPEECH OUTPUT: 'Which contains a quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "15. Line Up",
+    ["BRAILLE LINE:  'Containing a quote'",
+     "     VISIBLE:  'Containing a quote', cursor=1",
+     "SPEECH OUTPUT: 'Containing a quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "16. Line Up",
+    ["BRAILLE LINE:  'A nested quote'",
+     "     VISIBLE:  'A nested quote', cursor=1",
+     "SPEECH OUTPUT: 'A nested quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "17. Line Up",
+    ["BRAILLE LINE:  'Here's a quote'",
+     "     VISIBLE:  'Here's a quote', cursor=1",
+     "SPEECH OUTPUT: 'Here's a quote'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "18. Line Up",
+    ["BRAILLE LINE:  'Because why not?'",
+     "     VISIBLE:  'Because why not?', cursor=1",
+     "SPEECH OUTPUT: 'Because why not?'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "19. Line Up",
+    ["BRAILLE LINE:  'Is this seriously necessary?'",
+     "     VISIBLE:  'Is this seriously necessary?', cursor=1",
+     "SPEECH OUTPUT: 'Is this seriously necessary?.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "20. Line Up",
+    ["BRAILLE LINE:  'Even-more-nested item'",
+     "     VISIBLE:  'Even-more-nested item', cursor=1",
+     "SPEECH OUTPUT: 'Even-more-nested item.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "21. Line Up",
+    ["BRAILLE LINE:  'Nested item'",
+     "     VISIBLE:  'Nested item', cursor=1",
+     "SPEECH OUTPUT: 'Nested item.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "22. Line Up",
+    ["BRAILLE LINE:  'Hello world'",
+     "     VISIBLE:  'Hello world', cursor=1",
+     "SPEECH OUTPUT: 'Hello world.'"]))
+
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Up"))
+sequence.append(utils.AssertPresentationAction(
+    "23. Line Up",
+    ["BRAILLE LINE:  'Nest all the things!'",
+     "     VISIBLE:  'Nest all the things!', cursor=1",
+     "SPEECH OUTPUT: 'Nest all the things!'"]))
+
+sequence.append(utils.AssertionSummaryAction())
+sequence.start()
diff --git a/test/keystrokes/firefox/line_nav_nested_items_no_context.settings 
b/test/keystrokes/firefox/line_nav_nested_items_no_context.settings
new file mode 100644
index 0000000..39c1cea
--- /dev/null
+++ b/test/keystrokes/firefox/line_nav_nested_items_no_context.settings
@@ -0,0 +1,165 @@
+{
+    "general": {
+        "enabledSpokenTextAttributes": "size:; family-name:; weight:400; indent:0; underline:none; 
strikethrough:false; justification:left; style:normal; paragraph-style:; text-spelling:none; fg-color:; 
bg-color:;",
+        "orcaModifierKeys": [
+            "Insert",
+            "KP_Insert"
+        ],
+        "skipBlankCells": false,
+        "onlySpeakDisplayedText": false,
+        "enableMnemonicSpeaking": false,
+        "chatAnnounceBuddyTyping": false,
+        "messagesAreDetailed": true,
+        "speakProgressBarUpdates": true,
+        "speakCellCoordinates": true,
+        "enableAlphabeticKeys": true,
+        "enableBraille": false,
+        "brailleAlignmentStyle": 0,
+        "playSoundForPositionInSet": false,
+        "sayAllStyle": 1,
+        "enableEchoBySentence": false,
+        "chatSpeakRoomName": false,
+        "soundVolume": 0.5,
+        "activeProfile": [
+            "Default",
+            "default"
+        ],
+        "brailleVerbosityLevel": 1,
+        "sayAllContextTable": false,
+        "enableTutorialMessages": false,
+        "wrappedStructuralNavigation": true,
+        "capitalizationStyle": "none",
+        "findResultsMinimumLength": 4,
+        "enableContractedBraille": false,
+        "presentDateFormat": "%x",
+        "enableSpeechIndentation": false,
+        "brailleContractionTable": "",
+        "structNavTriggersFocusMode": false,
+        "enablePauseBreaks": true,
+        "speakNumbersAsDigits": false,
+        "spellcheckSpellError": true,
+        "useColorNames": true,
+        "speakContextTable": false,
+        "readFullRowInGUITable": true,
+        "enabledBrailledTextAttributes": "size:; family-name:; weight:400; indent:0; underline:none; 
strikethrough:false; justification:left; style:normal; text-spelling:none;",
+        "enableSpace": true,
+        "brailleSelectorIndicator": 192,
+        "profile": [
+            "Default",
+            "default"
+        ],
+        "verbalizePunctuationStyle": 1,
+        "enableBrailleContext": true,
+        "enableNavigationKeys": false,
+        "structNavInSayAll": false,
+        "enableSound": true,
+        "speakCellSpan": true,
+        "speechVerbosityLevel": 1,
+        "brailleRolenameStyle": 1,
+        "mouseDwellDelay": null,
+        "enableSpeech": true,
+        "caretNavTriggersFocusMode": false,
+        "enableDiacriticalKeys": false,
+        "findResultsVerbosity": 2,
+        "sayAllContextBlockquote": false,
+        "speakBlankLines": true,
+        "speakSpreadsheetCoordinates": true,
+        "flashIsPersistent": false,
+        "enableNumericKeys": true,
+        "enableFlashMessages": true,
+        "progressBarVerbosity": 1,
+        "brailleLinkIndicator": 192,
+        "presentTimeFormat": "%X",
+        "enablePunctuationKeys": true,
+        "enableKeyEcho": false,
+        "playSoundForState": false,
+        "beepProgressBarUpdates": false,
+        "enableFunctionKeys": true,
+        "speakMisspelledIndicator": true,
+        "textAttributesBrailleIndicator": 0,
+        "voices": {
+            "default": {
+                "established": false
+            },
+            "system": {
+                "established": false
+            },
+            "uppercase": {
+                "average-pitch": 7.0
+            },
+            "hyperlink": {
+                "established": false
+            }
+        },
+        "enableBrailleMonitor": true,
+        "layoutMode": true,
+        "brailleFlashTime": 5000,
+        "largeObjectTextLength": 75,
+        "speakContextList": false,
+        "ignoreStatusBarProgressBars": true,
+        "keyboardLayout": 1,
+        "brailleProgressBarUpdates": false,
+        "readFullRowInSpreadSheet": false,
+        "enableActionKeys": true,
+        "enablePositionSpeaking": false,
+        "structuralNavigationEnabled": true,
+        "playSoundForRole": false,
+        "disableBrailleEOL": false,
+        "presentToolTips": false,
+        "enableMouseReview": false,
+        "speechServerFactory": "speechdispatcherfactory",
+        "chatMessageVerbosity": 0,
+        "enableEchoByWord": false,
+        "spellcheckSpellSuggestion": true,
+        "enableModifierKeys": true,
+        "speakMultiCaseStringsAsWords": false,
+        "flashIsDetailed": true,
+        "speakCellHeaders": true,
+        "rewindAndFastForwardInSayAll": false,
+        "sayAllContextList": false,
+        "speakContextBlockquote": false,
+        "enableEchoByCharacter": false,
+        "playSoundForValue": false,
+        "progressBarUpdateInterval": 10,
+        "spellcheckPresentContext": true,
+        "speechServerInfo": null,
+        "chatRoomHistories": false,
+        "readFullRowInDocumentTable": true,
+        "startingProfile": [
+            "Default",
+            "default"
+        ]
+    },
+    "keybindings": {},
+    "profiles": {
+        "default": {
+            "profile": [
+                "Default",
+                "default"
+            ],
+            "brailleContractionTable": "/usr/share/liblouis/tables/en-us-compbrl.ctb",
+            "voices": {
+                "default": {
+                    "established": false
+                },
+                "system": {
+                    "established": false
+                },
+                "uppercase": {
+                    "average-pitch": 7.0
+                },
+                "hyperlink": {
+                    "established": false
+                }
+            },
+            "pronunciations": {},
+            "speechServerInfo": [
+                "Default Synthesizer",
+                "default"
+            ],
+            "keybindings": {},
+            "speechServerFactory": "orca.speechdispatcherfactory"
+        }
+    },
+    "pronunciations": {}
+}
\ No newline at end of file



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