[orca/570658-whereami] New 570658-whereami branch based on Joanie's first pass



commit fd0df0d666908944314e6d0a303028a5aa1c951e
Author: Willie Walker <william walker sun com>
Date:   Wed Jun 3 10:07:32 2009 -0400

    New 570658-whereami branch based on Joanie's first pass
    
    This also includes my changes to Joanie's pass.  These changes
    include the following:
    
    1) Updating the tests to answer some questions and remove others
       that Joanie had in the code
    2) Moving the tooltip code to the formatting string
    3) Changing some append's to extend's in the text code (I need
       to update the tests)
    4) Reconciling the diffs with the current master branch
---
 src/orca/default.py                                |  147 ++-
 src/orca/formatting.py                             |  129 ++-
 src/orca/scripts/apps/gnome-panel.py               |    3 +-
 src/orca/scripts/toolkits/Gecko/formatting.py      |    3 +-
 .../scripts/toolkits/Gecko/speech_generator.py     |    3 +
 src/orca/speech_generator.py                       |  487 ++++++-
 src/orca/where_am_I.py                             | 1518 +-------------------
 test/keystrokes/gtk-demo/role_column_header.py     |   33 +-
 test/keystrokes/gtk-demo/role_combo_box.py         |   32 +-
 test/keystrokes/gtk-demo/role_label.py             |   22 +-
 test/keystrokes/gtk-demo/role_menu.py              |    8 +-
 test/keystrokes/gtk-demo/role_page_tab.py          |    4 +-
 test/keystrokes/gtk-demo/role_radio_menu_item.py   |   16 +-
 test/keystrokes/gtk-demo/role_table.py             |    6 +-
 test/keystrokes/gtk-demo/role_text_multiline.py    |   20 +-
 test/keystrokes/gtk-demo/role_toolbar.py           |    4 +-
 test/keystrokes/gtk-demo/role_tree_table.py        |   52 +-
 17 files changed, 868 insertions(+), 1619 deletions(-)

diff --git a/src/orca/default.py b/src/orca/default.py
index a1c4e3e..b09b849 100644
--- a/src/orca/default.py
+++ b/src/orca/default.py
@@ -49,7 +49,6 @@ import orca_state
 import phonnames
 import pronunciation_dict
 import punctuation_settings
-import rolenames
 import script
 import settings
 import speech
@@ -190,17 +189,17 @@ class Script(script.Script):
                 #
                 _("Performs the detailed where am I operation."))
 
-        self.inputEventHandlers["getTitleHandler"] = \
+        self.inputEventHandlers["presentTitleHandler"] = \
             input_event.InputEventHandler(
-                Script.getTitle,
+                Script.presentTitle,
                 # Translators: This command will cause the window's
                 # title to be spoken.
                 #
                 _("Speaks the title bar."))
 
-        self.inputEventHandlers["getStatusBarHandler"] = \
+        self.inputEventHandlers["presentStatusBarHandler"] = \
             input_event.InputEventHandler(
-                Script.getStatusBar,
+                Script.presentStatusBar,
                 # Translators: This command will cause the window's
                 # status bar contents to be spoken.
                 #
@@ -1095,7 +1094,7 @@ class Script(script.Script):
                 "KP_Enter",
                 settings.defaultModifierMask,
                 settings.ORCA_MODIFIER_MASK,
-                self.inputEventHandlers["getTitleHandler"],
+                self.inputEventHandlers["presentTitleHandler"],
                 1))
 
         keyBindings.add(
@@ -1103,7 +1102,7 @@ class Script(script.Script):
                 "KP_Enter",
                 settings.defaultModifierMask,
                 settings.ORCA_MODIFIER_MASK,
-                self.inputEventHandlers["getStatusBarHandler"],
+                self.inputEventHandlers["presentStatusBarHandler"],
                 2))
 
         keyBindings.add(
@@ -1486,7 +1485,7 @@ class Script(script.Script):
                 "slash",
                 settings.defaultModifierMask,
                 settings.ORCA_MODIFIER_MASK,
-                self.inputEventHandlers["getTitleHandler"],
+                self.inputEventHandlers["presentTitleHandler"],
                 1))
 
         keyBindings.add(
@@ -1494,7 +1493,7 @@ class Script(script.Script):
                 "slash",
                 settings.defaultModifierMask,
                 settings.ORCA_MODIFIER_MASK,
-                self.inputEventHandlers["getStatusBarHandler"],
+                self.inputEventHandlers["presentStatusBarHandler"],
                 2))
 
         keyBindings.add(
@@ -2515,15 +2514,26 @@ class Script(script.Script):
         #
         text = ""
         if obj.description:
-            text = obj.description
+            speechResult = brailleResult = obj.description
         else:
-            # Reuse the "where am I" algorithm.
-            text = self.whereAmI.getObjLabelAndName(obj)
-
-        debug.println(debug.LEVEL_FINEST, "presentTooltip: text='%s'" % text)
-        if text != "":
-            braille.displayMessage(text)
-            speech.speak(text)
+            # [[[TODO: WDW to JD: I see what you mean about making the
+            # _getLabelAndName method a public method.  We might consider
+            # doing that when we get to the braille refactor where we
+            # will probably make an uber generator class/module that the
+            # speech and braille generator classes can subclass.  For
+            # now, I've kind of hacked at the speech result.  The idea
+            # is that the speech result might return an audio cue and
+            # voice specification.  Of course, if it does that, then 
+            # the speechResult[0] assumption will fail. :-(]]]
+            #
+            speechResult = self.whereAmI.getWhereAmI(obj, True)
+            brailleResult = speechResult[0]
+        debug.println(debug.LEVEL_FINEST,
+                      "presentTooltip: text='%s'" % speechResult)
+        if speechResult:
+            speech.speak(speechResult)
+        if brailleResult:
+            braille.displayMessage(brailleResult)
 
     def doWhereAmI(self, inputEvent, basicOnly):
         """Peforms the whereAmI operation.
@@ -2550,23 +2560,109 @@ class Script(script.Script):
 
         self.doWhereAmI(inputEvent, False)
 
-    def getTitle(self, inputEvent):
-        """Speaks the title of the window with focus.
+    def presentTitle(self, inputEvent):
+        """Speaks and brailles the title of the window with focus.
         """
 
         obj = orca_state.locusOfFocus
         self.updateBraille(obj)
+        speech.speak(self.speechGenerator.getTitle(obj))
 
-        return self.whereAmI.speakTitle(orca_state.locusOfFocus)
-
-    def getStatusBar(self, inputEvent):
-        """Speaks the contents of the status bar of the window with focus.
+    def presentStatusBar(self, inputEvent):
+        """Speaks and brailles the contents of the status bar and/or default
+        button of the window with focus.
         """
 
         obj = orca_state.locusOfFocus
         self.updateBraille(obj)
 
-        return self.whereAmI.speakStatusBar(orca_state.locusOfFocus)
+        frame, dialog = self.findFrameAndDialog(obj)
+        if frame:
+            # In windows with lots of objects (Thunderbird, Firefox, etc.)
+            # If we wait until we've checked for both the status bar and
+            # a default button, there may be a noticable delay. Therefore,
+            # speak the status bar info immediately and then go looking
+            # for a default button.
+            #
+            speech.speak(self.speechGenerator.getStatusBar(frame))
+        window = dialog or frame
+        if window:
+            speech.speak(self.speechGenerator.getDefaultButton(window))
+
+    def findStatusBar(self, obj):
+        """Returns the status bar in the window which contains obj.
+        """
+
+        # There are some objects which are not worth descending.
+        #
+        skipRoles = [pyatspi.ROLE_TREE,
+                     pyatspi.ROLE_TREE_TABLE,
+                     pyatspi.ROLE_TABLE]
+
+        if obj.getState().contains(pyatspi.STATE_MANAGES_DESCENDANTS) \
+           or obj.getRole() in skipRoles:
+            return
+
+        statusBar = None
+        # The status bar is likely near the bottom of the window.
+        #
+        for i in range(obj.childCount - 1, -1, -1):
+            if obj[i].getRole() == pyatspi.ROLE_STATUS_BAR:
+                statusBar = obj[i]
+            elif not obj[i] in skipRoles:
+                statusBar = self.findStatusBar(obj[i])
+
+            if statusBar:
+                break
+
+        return statusBar
+
+    def findDefaultButton(self, obj):
+        """Returns the default button in dialog, obj.
+        """
+
+        # There are some objects which are not worth descending.
+        #
+        skipRoles = [pyatspi.ROLE_TREE,
+                     pyatspi.ROLE_TREE_TABLE,
+                     pyatspi.ROLE_TABLE]
+
+        if obj.getState().contains(pyatspi.STATE_MANAGES_DESCENDANTS) \
+           or obj.getRole() in skipRoles:
+            return
+
+        defaultButton = None
+        # The default button is likely near the bottom of the window.
+        #
+        for i in range(obj.childCount - 1, -1, -1):
+            if obj[i].getRole() == pyatspi.ROLE_PUSH_BUTTON \
+                and obj[i].getState().contains(pyatspi.STATE_IS_DEFAULT):
+                defaultButton = obj[i]
+            elif not obj[i].getRole() in skipRoles:
+                defaultButton = self.findDefaultButton(obj[i])
+
+            if defaultButton:
+                break
+
+        return defaultButton
+
+    def findFrameAndDialog(self, obj):
+        """Returns the frame and (possibly) the dialog containing
+        the object.
+        """
+
+        results = [None, None]
+
+        parent = obj.parent
+        while parent and (parent.parent != parent):
+            if parent.getRole() == pyatspi.ROLE_FRAME:
+                results[0] = parent
+            if parent.getRole() in [pyatspi.ROLE_DIALOG,
+                                    pyatspi.ROLE_FILE_CHOOSER]:
+                results[1] = parent
+            parent = parent.parent
+
+        return results
 
     def findCommonAncestor(self, a, b):
         """Finds the common ancestor between Accessible a and Accessible b.
@@ -3753,7 +3849,6 @@ class Script(script.Script):
         #
         if event.source.getRole() == pyatspi.ROLE_TOOL_TIP:
             obj = event.source
-
             if event.type.startswith("object:state-changed:showing"):
                 if event.detail1 == 1:
                     self.presentTooltip(obj)
@@ -3761,7 +3856,7 @@ class Script(script.Script):
                     and isinstance(orca_state.lastInputEvent,
                                    input_event.KeyboardEvent) \
                     and (orca_state.lastNonModifierKeyEvent.event_string \
-                                                                  == "F1"):
+                         == "F1"):
                     self.updateBraille(orca_state.locusOfFocus)
                     utterances = self.speechGenerator.getSpeech(
                         orca_state.locusOfFocus)
diff --git a/src/orca/formatting.py b/src/orca/formatting.py
index 1c48a8a..4cda2b4 100644
--- a/src/orca/formatting.py
+++ b/src/orca/formatting.py
@@ -35,15 +35,21 @@ formatting = {
     'speech': {
         'prefix': {
             'focused': '[]',
-            'unfocused': 'newAncestors + newRowHeader + newColumnHeader + newRadioButtonGroup'
+            'unfocused': 'newAncestors + newRowHeader + newColumnHeader + newRadioButtonGroup',
+            'basicWhereAmI': 'toolbar',
+            'detailedWhereAmI' : '[]'
             },
         'suffix': {
             'focused': '[]',
-            'unfocused': 'newNodeLevel + unselectedCell + tutorial'
+            'unfocused': 'newNodeLevel + unselectedCell + tutorial',
+            'basicWhereAmI': 'tutorial + description',
+            'detailedWhereAmI' : '[]'
             },
         'default': {
             'focused': '[]',
-            'unfocused': 'labelAndName + allTextSelection + roleName + availability + mnemonic + accelerator'
+            'unfocused': 'labelAndName + allTextSelection + roleName + availability + mnemonic + accelerator',
+            'basicWhereAmI': 'labelAndName + roleName',
+            'detailedWhereAmI' : '[]'
             },
         pyatspi.ROLE_ALERT: {
             'unfocused': 'labelAndName + unrelatedLabels'
@@ -53,14 +59,17 @@ formatting = {
             },
         pyatspi.ROLE_CHECK_BOX: {
             'focused': 'checkedState',
-            'unfocused': 'labelAndName + roleName + checkedState + required + availability + mnemonic + accelerator'
+            'unfocused': 'labelAndName + roleName + checkedState + required + availability + mnemonic + accelerator',
+            'basicWhereAmI': 'labelAndName + roleName + checkedState + mnemonic + accelerator + required'
             },
         pyatspi.ROLE_CHECK_MENU_ITEM: {
             'focused': 'checkedState',
-            'unfocused': 'labelAndName + roleName + checkedState + required + availability + mnemonic + accelerator'
+            'unfocused': 'labelAndName + roleName + checkedState + required + availability + mnemonic + accelerator',
+            'basicWhereAmI': 'ancestors + labelAndName + roleName + checkedState + accelerator + positionInList + mnemonic'
             },
         pyatspi.ROLE_COMBO_BOX: {
             'focused': 'name',
+            'basicWhereAmI': 'label + roleName + name + positionInList + mnemonic + accelerator'
             },
         pyatspi.ROLE_DIALOG: {
             'unfocused': 'labelAndName + unrelatedLabels'
@@ -74,24 +83,38 @@ formatting = {
             'unfocused': 'labelAndName + allTextSelection + roleName + unfocusedDialogCount + availability'
             },
         pyatspi.ROLE_ICON: {
+            # Need to tack on tutorial for icon, then tutorial for frame and dialog.
             'focused': 'labelAndName + imageDescription + roleName',
-            'unfocused': 'labelAndName + imageDescription + roleName'
+            'unfocused': 'labelAndName + imageDescription + roleName',
+            'basicWhereAmI': 'parentRoleName + labelAndName + selectedItemCount',
+            'detailedWhereAmI': 'parentRoleName + labelAndName + selectedItemCount + selectedItems'
+            },
+        pyatspi.ROLE_LABEL: {
+            'basicWhereAmI': 'labelAndName + allTextSelection + roleName'
             },
         pyatspi.ROLE_LAYERED_PANE: {
             'focused': 'labelAndName + allTextSelection + roleName + availability + noShowingChildren',
-            'unfocused': 'labelAndName + allTextSelection + roleName + availability + noShowingChildren'
+            'unfocused': 'labelAndName + allTextSelection + roleName + availability + noShowingChildren',
+            'basicWhereAmI': 'labelAndName + roleName + selectedItemCount',
+            'detailedWhereAmI': 'labelAndName + roleName + selectedItemCount + selectedItems'
             },
         pyatspi.ROLE_LIST_ITEM: {
             'focused': 'expandableState + availability',
-            'unfocused': 'labelAndName + allTextSelection + expandableState + availability'
+            'unfocused': 'labelAndName + allTextSelection + expandableState + availability',
+            'basicWhereAmI': 'label + roleName + name + expandableState + positionInList + nodeLevel + nestingLevel'
             },
         pyatspi.ROLE_MENU: {
             'focused': '[]',
-            'unfocused': 'labelAndName + allTextSelection + roleName + availability + mnemonic + accelerator'
+            'unfocused': 'labelAndName + allTextSelection + roleName + availability + mnemonic + accelerator',
+            'basicWhereAmI': '(ancestors or parentRoleName) + labelAndName + roleName +  positionInList + mnemonic'
             },
         pyatspi.ROLE_MENU_ITEM: {
             'focused': '[]',
-            'unfocused': 'labelAndName + menuItemCheckedState + availability + mnemonic + accelerator'
+            'unfocused': 'labelAndName + menuItemCheckedState + availability + mnemonic + accelerator',
+            'basicWhereAmI': 'ancestors + labelAndName + accelerator + positionInList + mnemonic'
+            },
+        pyatspi.ROLE_PAGE_TAB: {
+            'basicWhereAmI': 'parentRoleName + labelAndName + roleName + positionInList + mnemonic + accelerator'
             },
         pyatspi.ROLE_PASSWORD_TEXT: {
             'focused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection',
@@ -102,11 +125,13 @@ formatting = {
             'unfocused': 'labelAndName + percentage'
             },
         pyatspi.ROLE_PUSH_BUTTON: {
-            'unfocused': 'labelAndName + roleName + availability + mnemonic + accelerator'
+            'unfocused': 'labelAndName + roleName + availability + mnemonic + accelerator',
+            'basicWhereAmI': 'labelAndName + roleName + mnemonic + accelerator'
             },
         pyatspi.ROLE_RADIO_BUTTON: {
             'focused': 'radioState',
-            'unfocused': 'labelAndName + radioState + roleName + availability + mnemonic + accelerator'
+            'unfocused': 'labelAndName + radioState + roleName + availability + mnemonic + accelerator',
+            'basicWhereAmI': '(radioButtonGroup or ancestors) + labelAndName + roleName + radioState + positionInGroup + mnemonic + accelerator'
             },
         pyatspi.ROLE_RADIO_MENU_ITEM: {
             # OpenOffice check menu items currently have a role of "menu item"
@@ -117,7 +142,8 @@ formatting = {
             # See Orca bug #433398 for more details.
             #
             'focused': 'labelAndName + radioState + roleName + availability',
-            'unfocused': 'labelAndName + radioState + roleName + availability + mnemonic + accelerator'
+            'unfocused': 'labelAndName + radioState + roleName + availability + mnemonic + accelerator',
+            'basicWhereAmI': 'ancestors + labelAndName + roleName + radioState + accelerator + positionInList + mnemonic'
             },
         pyatspi.ROLE_SLIDER: {
             # Ignore the text on the slider.  See bug 340559
@@ -131,23 +157,33 @@ formatting = {
             # it exists and we haven't found anything yet.
             #
             'focused': 'value',
-            'unfocused': 'labelAndName + roleName + value + required + availability + mnemonic'
+            'unfocused': 'labelAndName + roleName + value + required + availability + mnemonic',
+            'basicWhereAmI': 'label + roleName + value + percentage + mnemonic + accelerator + required'
             },
         pyatspi.ROLE_SPIN_BUTTON: {
             'focused': 'name',
-            'unfocused': 'labelAndName + allTextSelection + roleName + availability + mnemonic + required'
+            'unfocused': 'labelAndName + allTextSelection + roleName + availability + mnemonic + required',
+            'basicWhereAmI': 'label + roleName + name + allTextSelection + mnemonic + accelerator + required'
             },
         pyatspi.ROLE_SPLIT_PANE: {
             'focused': 'value',
-            'unfocused': 'labelAndName + roleName + value + availability + mnemonic'
+            'unfocused': 'labelAndName + roleName + value + availability + mnemonic',
+            'basicWhereAmI' : 'labelAndName + roleName + value'
             },
         pyatspi.ROLE_TABLE: {
             'focused': 'labelAndName + allTextSelection + roleName + availability + noChildren',
-            'unfocused': 'labelAndName + allTextSelection + roleName + availability + noChildren'
+            'unfocused': 'labelAndName + allTextSelection + roleName + availability + noChildren',
+            'unfocused': 'labelAndName + allTextSelection + roleName + availability + noChildren',
             },
         pyatspi.ROLE_TABLE_CELL: {
+            # TODO - JD: This seems to work for Gtk+ demo and packagemanager.
+            # For Evo (and things like it) we need to address what we speak
+            # for the attachment, status, and flagged columns.
+            #
             'focused': '(tableCell2ChildLabel + tableCell2ChildToggle) or cellCheckedState + (expandableState and (expandableState + numberOfChildren))',
-            'unfocused': 'tableCellRow'
+            'unfocused': 'tableCellRow',
+            'basicWhereAmI': 'parentRoleName + columnHeader + rowHeader + roleName + cellCheckedState + (realActiveDescendantDisplayedText or imageDescription + image) + columnAndRow + expandableState + nodeLevel',
+            'detailedWhereAmI': 'parentRoleName + columnHeader + rowHeader + roleName + cellCheckedState + (realActiveDescendantDisplayedText or imageDescription + image) + columnAndRow + tableCellRow + expandableState + nodeLevel'
             },
         'REAL_ROLE_TABLE_CELL': {
             # the real cell information
@@ -172,7 +208,12 @@ formatting = {
             },
         pyatspi.ROLE_TOGGLE_BUTTON: {
             'focused': 'toggleState',
-            'unfocused': 'labelAndName + roleName + toggleState + availability + mnemonic + accelerator'
+            'unfocused': 'labelAndName + roleName + toggleState + availability + mnemonic + accelerator',
+            'basicWhereAmI': 'labelAndName + roleName + toggleState'
+            },
+        pyatspi.ROLE_TOOL_TIP: {
+            'unfocused': 'labelAndName',
+            'basicWhereAmI': 'labelAndName'
             },
         pyatspi.ROLE_PARAGRAPH: {
             'focused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection',
@@ -208,42 +249,66 @@ class Formatting(dict):
             else:
                 self[key] = val
 
-    def getPrefix(self, dictType, **args):
+    def getPrefix(self, mode, **args):
         already_focused = args.get('already_focused', False)
         if already_focused:
-            focusType = 'focused'
+            # TODO - JD: This seems rather silly/hacky.
+            #
+            where_am_i_type = args.get('where_am_i_type', None)
+            if where_am_i_type == None:
+                focusType = 'focused'
+            elif where_am_i_type == True:
+                focusType = 'basicWhereAmI'
+            else:
+                focusType = 'detailedWhereAmI'
         else:
             focusType = 'unfocused'
         try:
-            prefix = self[dictType]['prefix'][focusType]
+            prefix = self[mode]['prefix'][focusType]
         except:
-            prefix = self[dictType]['prefix']['unfocused']
+            prefix = self[mode]['prefix']['unfocused']
         return prefix
 
-    def getSuffix(self, dictType, **args):
+    def getSuffix(self, mode, **args):
         already_focused = args.get('already_focused', False)
         if already_focused:
-            focusType = 'focused'
+            # TODO - JD: This seems rather silly/hacky.
+            #
+            where_am_i_type = args.get('where_am_i_type', None)
+            if where_am_i_type == None:
+                focusType = 'focused'
+            elif where_am_i_type == True:
+                focusType = 'basicWhereAmI'
+            else:
+                focusType = 'detailedWhereAmI' 
         else:
             focusType = 'unfocused'
         try:
-            suffix = self[dictType]['suffix'][focusType]
+            suffix = self[mode]['suffix'][focusType]
         except:
-            suffix = self[dictType]['suffix']['unfocused']
+            suffix = self[mode]['suffix']['unfocused']
         return suffix
 
-    def getFormat(self, dictType, **args):
+    def getFormat(self, mode, **args):
         already_focused = args.get('already_focused', False)
         if already_focused:
-            focusType = 'focused'
+            # TODO - JD: This seems rather silly/hacky.
+            #
+            where_am_i_type = args.get('where_am_i_type', None)
+            if where_am_i_type == None:
+                focusType = 'focused'
+            elif where_am_i_type == True:
+                focusType = 'basicWhereAmI'
+            else:
+                focusType = 'detailedWhereAmI'
         else:
             focusType = 'unfocused'
 
         role = args.get('role', None)
         try:
-            roleDict = self[dictType][role]
+            roleDict = self[mode][role]
         except:
-            roleDict = self[dictType]['default']
+            roleDict = self[mode]['default']
 
         try:
             format = roleDict[focusType]
@@ -251,6 +316,6 @@ class Formatting(dict):
             try:
                 format = roleDict['unfocused']
             except:
-                format = self[dictType]['default'][focusType]
+                format = self[mode]['default'][focusType]
 
         return format
diff --git a/src/orca/scripts/apps/gnome-panel.py b/src/orca/scripts/apps/gnome-panel.py
index f34a93b..0a1fc4a 100644
--- a/src/orca/scripts/apps/gnome-panel.py
+++ b/src/orca/scripts/apps/gnome-panel.py
@@ -88,7 +88,8 @@ class Script(default.Script):
             if event.type.startswith("object:state-changed:showing") and \
                event.detail1 == 1:
                 braille.displayMessage(obj.name)
-                speech.speak(obj.name)
+                utterances = self.speechGenerator.getSpeech(obj)
+                speech.speak(utterances)
 
         # If focus moves to something within a panel and focus was not
         # already in the containing panel, the panel will issue its
diff --git a/src/orca/scripts/toolkits/Gecko/formatting.py b/src/orca/scripts/toolkits/Gecko/formatting.py
index 7f8492a..55d64bc 100644
--- a/src/orca/scripts/toolkits/Gecko/formatting.py
+++ b/src/orca/scripts/toolkits/Gecko/formatting.py
@@ -45,7 +45,8 @@ formatting = {
             'unfocused': 'name + roleName'
             },
         pyatspi.ROLE_LINK: {
-            'unfocused': 'labelAndName + roleName + availability'
+            'unfocused': 'labelAndName + roleName + availability',
+            'basicWhereAmI': 'linkInfo + siteDescription + fileSize'
             },
         pyatspi.ROLE_LIST: {
             'focused': 'focusedItem',
diff --git a/src/orca/scripts/toolkits/Gecko/speech_generator.py b/src/orca/scripts/toolkits/Gecko/speech_generator.py
index 3f08fd1..5ac571b 100644
--- a/src/orca/scripts/toolkits/Gecko/speech_generator.py
+++ b/src/orca/scripts/toolkits/Gecko/speech_generator.py
@@ -92,6 +92,9 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
             result.extend(speech_generator.SpeechGenerator._getName(self,
                                                                     obj,
                                                                     **args))
+        if not result and role == pyatspi.ROLE_LIST_ITEM:
+            result.append(self._script.expandEOCs(obj))
+
         link = None
         if role == pyatspi.ROLE_LINK:
             link = obj
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index 36c1c70..bed9a68 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -29,6 +29,7 @@ __license__   = "LGPL"
 
 import sys
 import traceback
+import urlparse, urllib2
 
 import debug
 import orca_state
@@ -160,7 +161,8 @@ class SpeechGenerator:
         wonder if we should just have _getName, _getDescription,
         _getDisplayedText, etc., that don't do any fallback.  Then, we
         can allow the formatting to do the fallback (e.g.,
-        'displayedText or name or description')
+        'displayedText or name or description'). [[[JD to WDW - I needed
+        a _getDescription for whereAmI. :-) See below.
         """
         result = []
         name = self._script.getDisplayedText(obj)
@@ -170,6 +172,22 @@ class SpeechGenerator:
             result.append(obj.description)
         return result
 
+    def _getDescription(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the description of the object,
+        if that description is different from that of the name and
+        label.
+        """
+        result = []
+        try:
+            label = self._getLabel(obj)[0]
+            print label
+        except:
+            label = ""
+        if obj.description and not obj.description in [obj.name, label]:
+            result.append(obj.description)
+        return result
+
     def _getTextRole(self, obj, **args):
         """A convenience method to prevent the pyatspi.ROLE_PARAGRAPH role
         from being spoken. In the case of a pyatspi.ROLE_PARAGRAPH
@@ -459,7 +477,9 @@ class SpeechGenerator:
         Otherwise, and empty array will be returned.
         """
         result = []
-        if obj.getState().contains(pyatspi.STATE_REQUIRED):
+        if obj.getState().contains(pyatspi.STATE_REQUIRED) \
+           or (obj.getRole() == pyatspi.ROLE_RADIO_BUTTON \
+               and obj.parent.getState().contains(pyatspi.STATE_REQUIRED)):
             result = [settings.speechRequiredStateString]
         return result
 
@@ -477,6 +497,150 @@ class SpeechGenerator:
 
     #####################################################################
     #                                                                   #
+    # Link information                                                  #
+    #                                                                   #
+    #####################################################################
+
+    # [[[TODO/Question - JD for WDW: In the original whereAmI code,
+    # link handling was done in the main class; not in Gecko. In
+    # addition, there are other applications which have links which
+    # we want to handle. Yet, in the first part of the refactor,
+    # pyatspi.ROLE_LINK was placed in the Gecko formatting.py only.
+    # Why? For now, I'm leaving that as it is, but putting all of
+    # the link methods here.
+    #
+    def _getLinkInfo(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the protocol of the URI of
+        the link associated with obj.
+        """
+        result = []
+        # Get the URI for the link of interest and parse it. The parsed
+        # URI is returned as a tuple containing six components:
+        # scheme://netloc/path;parameters?query#fragment.
+        #
+        link_uri = self._script.getURI(obj)
+        if not link_uri:
+            # [[[TODO - JD: For some reason, this is failing for certain
+            # links. The current whereAmI code says, "It might be an anchor.
+            # Try to speak the text." and passes things off to whereAmI's
+            # _speakText method. That won't work in the new world order.
+            # Therefore, for now, I will hack in some code to do that
+            # work here so that the before and after end results match.]]]
+            #
+            result.extend(self._getLabel(obj))
+            result.extend(self._getRoleName(obj))
+            result.append(self._script.getDisplayedText(obj))
+        else:
+            link_uri_info = urlparse.urlparse(link_uri)
+            if link_uri_info[0] in ["ftp", "ftps", "file"]:
+                fileName = link_uri_info[2].split('/')
+                # Translators: this refers to a link to a file, where
+                # the first item is the protocol (ftp, ftps, or file)
+                # and the second item the name of the file being linked
+                # to.
+                #
+                result.append(_('%s link to %s') %\
+                               (link_uri_info[0], fileName[-1]))
+            else:
+                # Translators: this is the protocol of a link eg. http, mailto.
+                #
+                linkOutput = _('%s link') %link_uri_info[0]
+                text = self._script.getDisplayedText(obj)
+                if not text:
+                    # If there's no text for the link, expose part of the
+                    # URI to the user.
+                    #
+                    text = self._script.getLinkBasename(obj)
+                if text:
+                    linkOutput += " " + text
+                result.append(linkOutput)
+                if obj.childCount and obj[0].getRole() == pyatspi.ROLE_IMAGE:
+                    result.extend(self._getRoleName(obj[0]))
+        return result
+
+    def _getSiteDescription(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that describe the site (same or different)
+        pointed to by the URI of the link associated with obj.
+        """
+        result = []
+        link_uri = self._script.getURI(obj)
+        if link_uri:
+            link_uri_info = urlparse.urlparse(link_uri)
+        else:
+            return result
+        doc_uri = self._script.getDocumentFrameURI()
+        if doc_uri:
+            doc_uri_info = urlparse.urlparse(doc_uri)
+            if link_uri_info[1] == doc_uri_info[1]:
+                if link_uri_info[2] == doc_uri_info[2]:
+                    # Translators: this is an indication that a given
+                    # link points to an object that is on the same page.
+                    #
+                    result.append(_('same page'))
+                else:
+                    # Translators: this is an indication that a given
+                    # link points to an object that is at the same site
+                    # (but not on the same page as the link).
+                    #
+                    result.append(_('same site'))
+            else:
+                # check for different machine name on same site
+                #
+                linkdomain = link_uri_info[1].split('.')
+                docdomain = doc_uri_info[1].split('.')
+                if len(linkdomain) > 1 and docdomain > 1  \
+                    and linkdomain[-1] == docdomain[-1]  \
+                    and linkdomain[-2] == docdomain[-2]:
+                    # Translators: this is an indication that a given
+                    # link points to an object that is at the same site
+                    # (but not on the same page) as the link.
+                    #
+                    result.append(_('same site'))
+                else:
+                    # Translators: this is an indication that a given
+                    # link points to an object that is at a different
+                    # site than that of the link.
+                    #
+                    result.append(_('different site'))
+        return result
+
+    def _getFileSize(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the size (Content-length) of
+        the file pointed to by the URI of the link associated with
+        obj.
+        """
+        result = []
+        sizeString = ""
+        uri = self._script.getURI(obj)
+        try:
+            x = urllib2.urlopen(uri)
+            try:
+                sizeString = x.info()['Content-length']
+            except KeyError:
+                pass
+        except (ValueError, urllib2.URLError, OSError):
+            pass
+        if sizeString:
+            size = int(sizeString)
+            if size < 10000:
+                # Translators: This is the size of a file in bytes
+                #
+                result.append(ngettext('%d byte', '%d bytes', size) % size)
+            elif size < 1000000:
+                # Translators: This is the size of a file in kilobytes
+                #
+                result.append(_('%.2f kilobytes') % (float(size) * .001))
+            elif size >= 1000000:
+                # Translators: This is the size of a file in megabytes
+                #
+                result.append(_('%.2f megabytes') % (float(size) * .000001))
+        return result
+
+    #####################################################################
+    #                                                                   #
     # Image information                                                 #
     #                                                                   #
     #####################################################################
@@ -553,7 +717,8 @@ class SpeechGenerator:
                 if desc and len(desc):
                     text = desc
                     if settings.speechVerbosityLevel \
-                            == settings.VERBOSITY_LEVEL_VERBOSE:
+                            == settings.VERBOSITY_LEVEL_VERBOSE \
+                       and args.get('where_am_i_type', None) == None:
                         text += " " \
                             + rolenames.rolenames[\
                             pyatspi.ROLE_ROW_HEADER].speech
@@ -640,7 +805,8 @@ class SpeechGenerator:
                 if desc and len(desc):
                     text = desc
                     if settings.speechVerbosityLevel \
-                            == settings.VERBOSITY_LEVEL_VERBOSE:
+                            == settings.VERBOSITY_LEVEL_VERBOSE \
+                       and args.get('where_am_i_type', None) == None:
                         text += " " \
                             + rolenames.rolenames[\
                             pyatspi.ROLE_COLUMN_HEADER].speech
@@ -814,7 +980,8 @@ class SpeechGenerator:
             parentTable = obj.parent.queryTable()
         except NotImplementedError:
             parentTable = None
-        if settings.readTableCellRow and parentTable \
+        isDetailedWhereAmI = args.get('where_am_i_type', None) == False
+        if (settings.readTableCellRow or isDetailedWhereAmI) and parentTable \
            and (not self._script.isLayoutOnly(obj.parent)):
             parent = obj.parent
             index = self._script.getCellIndex(obj)
@@ -827,7 +994,10 @@ class SpeechGenerator:
             # the same row).
             #
             speakAll = True
-            if "lastRow" in self._script.pointOfReference \
+            if isDetailedWhereAmI:
+                if parentTable.nColumns <= 1:
+                    return result
+            elif "lastRow" in self._script.pointOfReference \
                and "lastColumn" in self._script.pointOfReference:
                 pointOfReference = self._script.pointOfReference
                 speakAll = \
@@ -921,6 +1091,32 @@ class SpeechGenerator:
 
         return result
 
+    def _getColumnAndRow(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) reflecting the position of the cell in terms
+        of its column number, the total number of columns, its row,
+        and the total number of rows.
+        """
+        result = []
+        if obj.parent.getRole() == pyatspi.ROLE_TABLE_CELL:
+            obj = obj.parent
+        parent = obj.parent
+        try:
+            table = parent.queryTable()
+        except:
+            table = None
+        else:
+            index = self._script.getCellIndex(obj)
+            col = table.getColumnAtIndex(index)
+            row = table.getRowAtIndex(index)
+            # Translators: this is in references to a column in a
+            # table.
+            result.append(_("column %d of %d") % ((col + 1), table.nColumns))
+            # Translators: this is in reference to a row in a table.
+            #
+            result.append(_("row %d of %d") % ((row + 1), table.nRows))
+        return result
+
     #####################################################################
     #                                                                   #
     # Terminal information                                              #
@@ -1099,6 +1295,17 @@ class SpeechGenerator:
                     break
             if radioGroupLabel:
                 result.append(self._script.getDisplayedText(radioGroupLabel))
+            else:
+                parent = obj.parent
+                while parent and (parent.parent != parent):
+                    if parent.getRole() in [pyatspi.ROLE_PANEL,
+                                            pyatspi.ROLE_FILLER]:
+                        label = self._script.getDisplayedText(parent)
+                        if label:
+                            result.append(label)
+                            break
+                    parent = parent.parent
+
         return result
 
     def _getNewRadioButtonGroup(self, obj, **args):
@@ -1207,6 +1414,62 @@ class SpeechGenerator:
             result.append(_("0 items"))
         return result
 
+    def _getSelectedItemCount(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) indicating how many items are selected in this
+        and the position of the current item. This object will be an icon
+        panel or a layered pane.
+        """
+        result = []
+        # TODO - JD: Is there a better way to do this other than
+        # hard-coding it in?
+        #
+        if args.get('role', obj.getRole()) == pyatspi.ROLE_ICON:
+            obj = obj.parent
+        childCount = obj.childCount
+        selectedItems = []
+        totalSelectedItems = 0
+        currentItem = 0
+        for child in obj:
+            state = child.getState()
+            if state.contains(pyatspi.STATE_SELECTED):
+                totalSelectedItems += 1
+                selectedItems.append(child)
+            if state.contains(pyatspi.STATE_FOCUSED):
+                currentItem = child.getIndexInParent() + 1
+        # Translators: this is a count of the number of selected icons
+        # and the count of the total number of icons within an icon panel.
+        # An example of an icon panel is the Nautilus folder view.
+        #
+        countString = ngettext("%d of %d item selected",
+                              "%d of %d items selected",
+                              childCount) % \
+                              (totalSelectedItems, childCount)
+        result.append(countString)
+        # Translators: this is a indication of the focused icon and the
+        # count of the total number of icons within an icon panel. An
+        # example of an icon panel is the Nautilus folder view.
+        #
+        itemString = _("on item %d of %d") % (currentItem, childCount)
+        result.append(itemString)
+        return result
+
+    def _getSelectedItems(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) containing the names of all the selected items.
+        This object will be an icon panel or a layered pane.
+        """
+        result = []
+        # TODO - JD: Is there a better way to do this other than
+        # hard-coding it in?
+        #
+        if args.get('role', obj.getRole()) == pyatspi.ROLE_ICON:
+            obj = obj.parent
+        for child in obj:
+            if child.getState().contains(pyatspi.STATE_SELECTED):
+                result.extend(self._getLabelAndName(child))
+        return result
+
     def _getUnfocusedDialogCount(self, obj,  **args):
         """Returns an array of strings (and possibly voice and audio
         specifications) that says how many unfocused alerts and
@@ -1290,6 +1553,217 @@ class SpeechGenerator:
             result = self._getAncestors(obj, **args)
         return result
 
+    def _getParentRoleName(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) containing the role name of the parent of obj.
+        """
+        if args.get('role', obj.getRole()) == pyatspi.ROLE_ICON \
+           and args.get('where_am_i_type', None) != None:
+            # Translators: this is an alternative name for the
+            # parent object of a series of icons.
+            #
+            return [_("Icon panel")]
+        elif obj.parent.getRole() == pyatspi.ROLE_TABLE_CELL:
+            obj = obj.parent
+        return self._getRoleName(obj.parent)
+
+    def _getToolbar(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) containing the name and role of the toolbar
+        which contains obj.
+        """
+        result = []
+        ancestor = self._script.getAncestor(obj,
+                                            [pyatspi.ROLE_TOOL_BAR],
+                                            [pyatspi.ROLE_FRAME])
+        if ancestor:
+            result.append(self._getLabelAndName(ancestor))
+            result.append(self._getRoleName(ancestor))
+        return result
+
+    def _getPositionInGroup(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the relative position of an
+        object in a group.
+        """
+        result = []
+        position = -1
+        total = -1
+
+        relations = obj.getRelationSet()
+        for relation in relations:
+            if relation.getRelationType() == pyatspi.RELATION_MEMBER_OF:
+                total = relation.getNTargets()
+                for i in range(0, total):
+                    target = relation.getTarget(i)
+                    if target == obj:
+                        position = total - i
+                        break
+
+        if position >= 0:
+            # Translators: this is an item in a list.
+            #
+            result.append(_("item %d of %d") % (position, total))
+
+        return result
+
+    def _getPositionInList(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the relative position of an
+        object in a list.
+        """
+        result = []
+        position = -1
+        index = 0
+        total = 0
+        name = self._getName(obj)
+        # TODO - JD: There might be a better way to do this (e.g. pass
+        # roles in maybe?).
+        #
+        role = args.get('role', obj.getRole())
+        if role == pyatspi.ROLE_COMBO_BOX:
+            obj = obj[0]
+        elif role in [pyatspi.ROLE_PAGE_TAB,
+                      pyatspi.ROLE_LIST_ITEM,
+                      pyatspi.ROLE_MENU,
+                      pyatspi.ROLE_MENU_ITEM,
+                      pyatspi.ROLE_CHECK_MENU_ITEM,
+                      pyatspi.ROLE_RADIO_MENU_ITEM]:
+            obj = obj.parent
+
+        # We want to return the position relative to this hierarchical
+        # level and not the entire list.  If the object in question
+        # uses the NODE_CHILD_OF relationship, we need to use it instead
+        # of the childCount.
+        #
+        childNodes = self._script.getChildNodes(obj)
+        total = len(childNodes)
+        for i in range(0, total):
+            childName = self._getName(childNodes[i])
+            if childName == name:
+                position = i+1
+                break
+
+        if not total:
+            for child in obj:
+                next = self._getName(child)
+                state = child.getState()
+                if not next or next[0] in ["", "Empty", "separator"] \
+                   or not state.contains(pyatspi.STATE_VISIBLE):
+                    continue
+
+                index += 1
+                total += 1
+
+                if next == name:
+                    position = index
+
+        if position >= 0:
+            # Translators: this is an item in a list.
+            #
+            result.append(_("item %d of %d") % (position, total))
+
+        return result
+
+    def _getNestingLevel(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the nesting level of an object
+        in a list.
+        """
+        result = []
+        nestingLevel = 0
+        parent = obj.parent
+        while parent.parent.getRole() == pyatspi.ROLE_LIST:
+            nestingLevel += 1
+            parent = parent.parent
+        if nestingLevel:
+            # Translators: this represents a list item in a document.
+            # The nesting level is how 'deep' the item is (e.g., a
+            # level of 2 represents a list item inside a list that's
+            # inside another list).
+            #
+            result.append(_("Nesting level %d") % nestingLevel)
+        return result
+
+    def _getDefaultButton(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the default button in a dialog.
+        This method should initially be called with a top-level window.
+        """
+        result = []
+        button = self._script.findDefaultButton(obj)
+        if button and button.getState().contains(pyatspi.STATE_SENSITIVE):
+            name = self._getName(button)
+            if name:
+                # Translators: The "default" button in a dialog box is the
+                # button that gets activated when Enter is pressed anywhere
+                # within that dialog box.
+                #
+                result.append(_("Default button is %s") % name[0])
+        return result
+
+    def getDefaultButton(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the default button of the window
+        containing the object.
+        """
+        # TODO/Question - JD to WDW: Do we want to add this to the
+        # formatting strings? For now, I've not done that.
+        #
+        return self._getDefaultButton(obj, **args)
+
+    def _getStatusBar(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the status bar of a window.
+        This method should initially be called with a top-level window.
+        """
+        result = []
+        statusBar = self._script.findStatusBar(obj)
+        if statusBar:
+            name = self._getName(statusBar)
+            if name:
+                result.extend(name)
+            else:
+                for child in statusBar:
+                    result.extend(self._getName(child))
+        return result
+
+    def getStatusBar(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the status bar of the window
+        containing the object.
+        """
+        # TODO/Question - JD to WDW: Do we want to add this to the
+        # formatting strings? For now, I've not done that.
+        #
+        return self._getStatusBar(obj, **args)
+
+    def getTitle(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the title of the window, obj.
+        containing the object, along with information associated with
+        any unfocused dialog boxes.
+        """
+        # TODO/Question - JD to WDW: Do we want to add this to the
+        # formatting strings? For now, I've not done that.
+        #
+        result = []
+        frame, dialog = self._script.findFrameAndDialog(obj)
+        if frame:
+            result.append(self._getLabelAndName(frame))
+        if dialog:
+            result.append(self._getLabelAndName(dialog))
+        alertAndDialogCount = \
+                    self._script.getUnfocusedAlertAndDialogCount(obj)
+        if alertAndDialogCount > 0:
+            # Translators: this tells the user how many unfocused
+            # alert and dialog windows that this application has.
+            #
+            result.append(ngettext("%d unfocused dialog",
+                                   "%d unfocused dialogs",
+                                   alertAndDialogCount) % alertAndDialogCount)
+        return result
+
     #####################################################################
     #                                                                   #
     # Keyboard shortcut information                                     #
@@ -1331,7 +1805,6 @@ class SpeechGenerator:
                 result = [mnemonic]
         return result
 
-
     #####################################################################
     #                                                                   #
     # Tutorial information                                              #
diff --git a/src/orca/where_am_I.py b/src/orca/where_am_I.py
index 835f6a2..4117077 100644
--- a/src/orca/where_am_I.py
+++ b/src/orca/where_am_I.py
@@ -27,16 +27,19 @@ __license__   = "LGPL"
 
 import pyatspi
 import debug
-import orca_state
 import settings
 import speech
 import text_attribute_names
-import urlparse, urllib2
 
 from orca_i18n import _ # for gettext support
-from orca_i18n import ngettext  # for ngettext support
 from orca_i18n import C_ # to provide qualified translatable strings
 
+# TODO - JD: As I remove duplicate/unnecessary methods from where_am_I.py,
+# I am replacing some with temporary calls to protected methods in the
+# speechgenerator. Therefore, disabling that complaint so I can find real
+# screw-ups. :-)
+# pylint: disable-msg=W0212
+
 class WhereAmI:
 
     def __init__(self, script):
@@ -46,8 +49,6 @@ class WhereAmI:
 
         self._script = script
         self._debugLevel = debug.LEVEL_FINEST
-        self._statusBar = None
-        self._defaultButton = None
         self._lastAttributeString = ""
 
     def whereAmI(self, obj, basicOnly):
@@ -65,435 +66,25 @@ class WhereAmI:
         if (not obj):
             return False
 
-        debug.println(self._debugLevel,
-            "whereAmI: \
-           \n  label=%s \
-           \n  name=%s \
-           \n  role=%s \
-           \n  keybinding=%s \
-           \n  parent label= %s \
-           \n  parent name=%s \
-           \n  parent role=%s \
-           \n  basicOnly=%s" % \
-            (self._getObjLabel(obj),
-             self._getObjName(obj),
-             obj.getRoleName(),
-             self._script.getKeyBinding(obj),
-             self._getObjLabel(obj.parent),
-             self._getObjName(obj.parent),
-             obj.parent.getRoleName(),
-             basicOnly))
-
         role = obj.getRole()
-
-        toolbar = self._getToolbar(obj)
-        if toolbar:
-            self._speakToolbar(toolbar)
-
-        if role == pyatspi.ROLE_CHECK_BOX:
-            self._speakCheckBox(obj, basicOnly)
-
-        elif role == pyatspi.ROLE_RADIO_BUTTON:
-            self._speakRadioButton(obj, basicOnly)
-
-        elif role == pyatspi.ROLE_COMBO_BOX:
-            self._speakComboBox(obj, basicOnly)
-
-        elif role == pyatspi.ROLE_SPIN_BUTTON:
-            self._speakSpinButton(obj, basicOnly)
-
-        elif role == pyatspi.ROLE_PUSH_BUTTON:
-            self._speakPushButton(obj, basicOnly)
-
-        elif role == pyatspi.ROLE_SLIDER:
-            self._speakSlider(obj, basicOnly)
-
-        elif role in [pyatspi.ROLE_MENU,
-                      pyatspi.ROLE_MENU_ITEM,
-                      pyatspi.ROLE_CHECK_MENU_ITEM,
-                      pyatspi.ROLE_RADIO_MENU_ITEM]:
-            self._speakMenuItem(obj, basicOnly)
-
-        elif role == pyatspi.ROLE_PAGE_TAB:
-            self._speakPageTab(obj, basicOnly)
-
-        elif role in [pyatspi.ROLE_ENTRY,
+        if role in [pyatspi.ROLE_ENTRY,
                       pyatspi.ROLE_TEXT,
                       pyatspi.ROLE_TERMINAL]:
             self._speakText(obj, basicOnly)
 
-        elif role == pyatspi.ROLE_TABLE_CELL:
-            self._speakTableCell(obj, basicOnly)
-
-        elif role == pyatspi.ROLE_LIST_ITEM:
-            self._speakListItem(obj, basicOnly)
-
         elif role in [pyatspi.ROLE_PARAGRAPH,
                       pyatspi.ROLE_SECTION,
                       pyatspi.ROLE_HEADING,
                       pyatspi.ROLE_DOCUMENT_FRAME]:
             self._speakParagraph(obj, basicOnly)
 
-        elif role == pyatspi.ROLE_ICON:
-            self._speakIconPanel(obj, basicOnly)
-
-        elif role == pyatspi.ROLE_LINK:
-            self._speakLink(obj, basicOnly)
-
-        elif role == pyatspi.ROLE_TOGGLE_BUTTON:
-            self._speakToggleButton(obj, basicOnly)
-
-        elif role == pyatspi.ROLE_SPLIT_PANE:
-            self._speakSplitPane(obj, basicOnly)
-
-        elif role == pyatspi.ROLE_LABEL:
-            self._speakLabel(obj, basicOnly)
-
-        elif role  == pyatspi.ROLE_LAYERED_PANE:
-            self._speakLayeredPane(obj, basicOnly)
-
         else:
-            self._speakGenericObject(obj, basicOnly)
-
-        if basicOnly:
-            self._speakObjDescription(obj)
+            speech.speak(self.getWhereAmI(obj, basicOnly))
 
         self._lastAttributeString = ""
 
         return True
 
-    def _speakCheckBox(self, obj, basicOnly):
-        """Checkboxes present the following information
-        (an example is 'Enable speech, checkbox checked, Alt E'):
-        1. label
-        2. role
-        3. state
-        4. accelerator (i.e. Alt plus the underlined letter), if any
-        5. tutorial string if enableTutorialMessages is set.
-        """
-
-        utterances = []
-        text = self.getObjLabelAndName(obj) + " " + \
-               self._getSpeechForRoleName(obj)
-        text = text + " " + self._getCheckBoxState(obj)
-        utterances.append(text)
-
-        accelerator = self._getObjAccelerator(obj)
-        utterances.append(accelerator)
-
-        text = self._getRequiredState(obj)
-        if text:
-            utterances.append(text)
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        debug.println(self._debugLevel, "check box utterances=%s" \
-                      % utterances)
-        speech.speak(utterances)
-
-    def _speakRadioButton(self, obj, basicOnly):
-        """Radio Buttons present the following information (an example is
-        'Punctuation Level, Some, Radio button, selected, item 2 of 4, Alt M'):
-
-        1. group name
-        2. label
-        3. role
-        4. state
-        5. relative position
-        6. accelerator (i.e. Alt plus the underlined letter), if any
-        7. tutorial string if enableTutorialMessages is set.
-        """
-
-        utterances = []
-        text = self._getGroupLabel(obj)
-        utterances.append(text)
-
-        text = self._getRequiredState(obj)
-        if text:
-            utterances.append(text)
-
-        text = self.getObjLabelAndName(obj) + " " + \
-               self._getSpeechForRoleName(obj)
-        utterances.append(text)
-
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_CHECKED):
-            # Translators: this is in reference to a radio button being
-            # selected or not.
-            #
-            text = C_("radiobutton", "selected")
-        else:
-            # Translators: this is in reference to a radio button being
-            # selected or not.
-            #
-            text = C_("radiobutton", "not selected")
-
-        utterances.append(text)
-
-        text = self._getPositionInGroup(obj)
-        utterances.append(text)
-
-        text = self._getObjAccelerator(obj)
-        utterances.append(text)
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        debug.println(self._debugLevel, "radio button utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
-    def _speakComboBox(self, obj, basicOnly):
-        """Comboboxes present the following information (an example is
-        'Speech system: combo box, GNOME Speech Services, item 1 of 1,
-        Alt S'):
-        1. label
-        2. role
-        3. current value
-        4. relative position
-        5. accelerator (i.e. Alt plus the underlined letter), if any
-        6. tutorial string if enableTutorialMessages is set.
-        """
-
-        utterances = []
-        text = self._getObjLabel(obj)
-        utterances.append(text)
-
-        text = self._getSpeechForRoleName(obj)
-        utterances.append(text)
-
-        name = self._getObjName(obj)
-        utterances.append(name)
-
-        # child(0) is the popup list
-        text = self._getPositionInList(obj[0], name)
-        utterances.append(text)
-
-        accelerator = self._getObjAccelerator(obj)
-        utterances.append(accelerator)
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        debug.println(self._debugLevel, "combo box utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
-    def _speakSpinButton(self, obj, basicOnly):
-        """Spin Buttons present the following information (an example is
-        'Scale factor: spin button, 4.00, Alt F'):
-
-        1. label
-        2. role
-        3. current value
-        4. selected (if True).
-        5. accelerator (i.e. Alt plus the underlined letter), if any
-        6. tutorial string if enableTutorialMessages is set.
-        """
-
-        utterances = []
-        label = self._getObjLabel(obj)
-        utterances.append(label)
-
-        text = self._getSpeechForRoleName(obj)
-        utterances.append(text)
-
-        name = self._getObjName(obj)
-        if name != label:
-            utterances.append(name)
-
-        utterances.extend(self._getSpeechForAllTextSelection(obj))
-
-        text = self._getObjAccelerator(obj)
-        utterances.append(text)
-
-        text = self._getRequiredState(obj)
-        if text:
-            utterances.append(text)
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        debug.println(self._debugLevel, "spin button utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
-    def _speakPushButton(self, obj, basicOnly):
-        """ Push Buttons present the following information (an example is
-        'Apply button, Alt A'):
-
-        1. label
-        2. role
-        3. accelerator (i.e. Alt plus the underlined letter), if any
-        4. tutorial string if enableTutorialMessages is set.
-        """
-
-        utterances = []
-        text = self.getObjLabelAndName(obj)
-        utterances.append(text)
-
-        text = self._getSpeechForRoleName(obj)
-        utterances.append(text)
-
-        text = self._getObjAccelerator(obj)
-        utterances.append(text)
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        debug.println(self._debugLevel, "push button utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
-    def _speakSlider(self, obj, basicOnly):
-        """Sliders present the following information (examples include
-        'Pitch slider, 5.0, 56%'; 'Volume slider, 9.0, 100%'):
-
-        1. label
-        2. role
-        3. value
-        4. percentage (if possible)
-        5. accelerator (i.e. Alt plus the underlined letter), if any
-        6. tutorial string if enableTutorialMessages is set.
-        """
-
-        utterances = []
-        text = self._getObjLabel(obj)
-        utterances.append(text)
-
-        text = self._getSpeechForRoleName(obj)
-        utterances.append(text)
-
-        values = self._getSliderValues(obj)
-        utterances.append(values[0])
-        # Translators: this is the percentage value of a slider.
-        #
-        utterances.append(_("%s percent") % values[1])
-
-        text = self._getObjAccelerator(obj)
-        utterances.append(text)
-
-        text = self._getRequiredState(obj)
-        if text:
-            utterances.append(text)
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        debug.println(self._debugLevel, "slider utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
-    def _speakMenuItem(self, obj, basicOnly):
-        """Menu items present the following information (examples include
-        'File menu, Open..., Control + O, item 2 of 20, O', 'File menu,
-        Wizards Menu, item 4 of 20, W'):
-
-        1. Name of the menu containing the item, followed by its role
-        2. item name, followed by its role (if a menu) followed by its
-        accelerator key binding, if any
-        3. relative position
-        4. mnemonic (i.e. the underlined letter), if any
-        5. tutorial string if enableTutorialMessages is set.
-        """
-
-        utterances = []
-        text = self.getObjLabelAndName(obj.parent) + " " \
-               + self._getSpeechForRoleName(obj.parent, force=True)
-        utterances.append(text.strip())
-
-        text = self.getObjLabelAndName(obj)
-        utterances.append(text)
-
-        state = obj.getState()
-
-        if obj.getRole() != pyatspi.ROLE_MENU_ITEM:
-            text = self._getSpeechForRoleName(obj)
-            utterances.append(text)
-
-        if obj.getRole() == pyatspi.ROLE_CHECK_MENU_ITEM:
-            if state.contains(pyatspi.STATE_INDETERMINATE):
-                # Translators: this represents the state of a checkbox.
-                #
-                text = _("partially checked")
-            elif state.contains(pyatspi.STATE_CHECKED):
-                # Translators: this represents the state of a checkbox.
-                #
-                text = _("checked")
-            else:
-                # Translators: this represents the state of a checkbox.
-                #
-                text = _("not checked")
-            utterances.append(text)
-
-        elif obj.getRole() == pyatspi.ROLE_RADIO_MENU_ITEM:
-            if state.contains(pyatspi.STATE_CHECKED):
-                # Translators: this is in reference to a radio button being
-                # selected or not.
-                #
-                text = _("selected")
-            else:
-                # Translators: this is in reference to a radio button being
-                # selected or not.
-                #
-                text = _("not selected")
-            utterances.append(text)
-
-        text = self._getObjAccelerator(obj, False, False)
-        utterances.append(text)
-
-        name = self._getObjName(obj)
-        text = self._getPositionInList(obj.parent, name)
-        utterances.append(text)
-
-        if obj.parent \
-           and obj.parent.getRole() in [pyatspi.ROLE_MENU,
-                                        pyatspi.ROLE_MENU_BAR]:
-            text = self._getObjMnemonic(obj)
-            utterances.append(text)
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        debug.println(self._debugLevel, "menu item utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
-    def _speakPageTab(self, obj, basicOnly):
-        """Tabs in a Tab List present the following information (an example
-        is 'Tab list, braille page, item 2 of 5'):
-
-        1. role
-        2. label + 'page'
-        3. relative position
-        4. accelerator (i.e. Alt plus the underlined letter), if any
-        5. tutorial string if enableTutorialMessages is set.
-        """
-
-        utterances = []
-        text = self._getSpeechForRoleName(obj.parent)
-        utterances.append(text)
-
-        # Translators: "page" is the word for a page tab in a tab list.
-        #
-        text = _("%s page") % self.getObjLabelAndName(obj)
-        utterances.append(text)
-
-        name = self._getObjName(obj)
-        text = self._getPositionInList(obj.parent, name)
-        utterances.append(text)
-
-        text = self._getObjAccelerator(obj)
-        utterances.append(text)
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        debug.println(self._debugLevel, "page utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
     def _speakText(self, obj, basicOnly):
         """Text boxes present the following information (an example is
         'Source display: text, blank, Alt O'):
@@ -526,20 +117,20 @@ class WhereAmI:
             #
             if ancestor.getRole() == pyatspi.ROLE_TABLE_CELL:
                 if obj.getRole() != pyatspi.ROLE_ENTRY:
-                    return self._speakTableCell(ancestor, basicOnly)
+                    return speech.speak(self.getWhereAmI(ancestor, basicOnly))
             else:
-                return self._speakListItem(ancestor, basicOnly)
+                return speech.speak(self.getWhereAmI(ancestor, basicOnly))
 
         utterances = []
-        text = self._getObjLabel(obj)
-        utterances.append(text)
+        text = self._script.speechGenerator._getLabel(obj)
+        utterances.extend(text)
 
         if settings.presentReadOnlyText \
            and self._script.isReadOnlyTextArea(obj):
             utterances.append(settings.speechReadOnlyString)
 
-        text = self._getSpeechForRoleName(obj)
-        utterances.append(text)
+        text = self._script.speechGenerator._getRoleName(obj)
+        utterances.extend(text)
 
         [textContents, startOffset, endOffset, selected] = \
                        self._getTextContents(obj, basicOnly)
@@ -555,7 +146,9 @@ class WhereAmI:
         utterances.append(text)
         debug.println(self._debugLevel, "first text utterances=%s" % \
                       utterances)
-
+        print utterances
+        print self.getWhereAmI(obj, basicOnly)
+        print "================"
         speech.speak(utterances)
 
         if not basicOnly:
@@ -569,8 +162,11 @@ class WhereAmI:
             text = C_("text", "selected")
             utterances.append(text)
 
-        text = self._getObjAccelerator(obj)
-        utterances.append(text)
+        text = self._script.speechGenerator.\
+                            _getAccelerator(obj,
+                                            fallbackToMnemonic=True,
+                                            fallbackToFullPath=True)
+        utterances.extend(text)
 
         getTutorial = self._script.tutorialGenerator.getTutorial
         utterances.extend(getTutorial(obj, False, forceMessage=True))
@@ -579,420 +175,14 @@ class WhereAmI:
                       utterances)
         speech.speak(utterances)
 
-    def _speakTableCell(self, obj, basicOnly):
-        """Tree Tables present the following information (an example is
-        'Tree table, Mike Pedersen, item 8 of 10, tree level 2'):
-
-        1. parent's role
-        2. column header of object
-        3. row header of object
-        4. object's role
-        5. object's contents, if there are multiple columns
-        6. relative position
-        7. current row (regardless of speak cell/row setting), if
-           performing a detailed whereAmI.
-        8. if expandable/collapsible: expanded/collapsed
-        9. if applicable, the level
-        10. tutorial string if enableTutorialMessages is set.
-
-        Nautilus and Gaim
-        """
-
-        utterances = []
-        if obj.parent.getRole() == pyatspi.ROLE_TABLE_CELL:
-            obj = obj.parent
-        parent = obj.parent
-
-        text = self._getSpeechForRoleName(parent)
-        utterances.append(text)
-
-        try:
-            table = parent.queryTable()
-        except:
-            table = None
-            nColumns = 0
-        else:
-            nColumns = table.nColumns
-            index = self._script.getCellIndex(obj)
-            column = table.getColumnAtIndex(index)
-            header = table.getColumnHeader(column)
-            if header:
-                text = self._getObjName(header)
-                utterances.append(text)
-
-            row = table.getRowAtIndex(index)
-            header = table.getRowHeader(row)
-            if header:
-                text = self._getObjName(header)
-                utterances.append(text)
-
-        text = self._getSpeechForRoleName(obj)
-        utterances.append(text)
-
-        if nColumns:
-            text = self._getTableCell(obj)
-            utterances.append(text)
-
-        text = self._getRequiredState(obj)
-        if text:
-            utterances.append(text)
-
-        debug.println(self._debugLevel, "first table cell utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
-        utterances = []
-        if table:
-            # Translators: this is in references to a column in a
-            # table.
-            text = _("column %d of %d") % ((column + 1), table.nColumns)
-            utterances.append(text)
-
-            # Translators: this is in reference to a row in a table.
-            #
-            text = _("row %d of %d") % ((row + 1), table.nRows)
-            utterances.append(text)
-            speech.speak(utterances)
-
-            # Speak the current row if performing a "detailed" whereAmI.
-            #
-            if not basicOnly:
-                utterances = self._getTableRow(obj)
-                debug.println(self._debugLevel, \
-                              "second table cell utterances=%s" % \
-                              utterances)
-                speech.speak(utterances)
-
-        utterances = []
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_EXPANDABLE):
-            if state.contains(pyatspi.STATE_EXPANDED):
-                # Translators: this represents the state of a node in a tree.
-                # 'expanded' means the children are showing.
-                # 'collapsed' means the children are not showing.
-                #
-                text = _("expanded")
-            else:
-                # Translators: this represents the state of a node in a tree.
-                # 'expanded' means the children are showing.
-                # 'collapsed' means the children are not showing.
-                #
-                text = _("collapsed")
-            utterances.append(text)
-
-        level = self._script.getNodeLevel(orca_state.locusOfFocus)
-        if level >= 0:
-            # Translators: this represents the depth of a node in a tree
-            # view (i.e., how many ancestors a node has).
-            #
-            utterances.append(_("tree level %d") % (level + 1))
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        debug.println(self._debugLevel, "third table cell utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
-    def _speakListItem(self, obj, basicOnly):
-        """List items should be treated like tree cells:
-
-        1. label, if any
-        2. role
-        3. name
-        4. relative position
-        5. if expandable/collapsible: expanded/collapsed
-        6. if applicable, the level
-        7. tutorial string if enableTutorialMessages is set.
-        """
-
-        utterances = []
-
-        text = self._getObjLabel(obj)
-        if text:
-            utterances.append(text)
-
-        text = self._getSpeechForRoleName(obj, force=True)
-        utterances.append(text)
-
-        text = self._getObjName(obj)
-        utterances.append(text)
-
-        parent = obj.parent
-        relationset = obj.getRelationSet()
-        for relation in relationset:
-            if relation.getRelationType() == pyatspi.RELATION_NODE_CHILD_OF:
-                parent = relation.getTarget(0)
-                break
-
-        name = self._getObjName(obj)
-        text = self._getPositionInList(parent, name)
-        utterances.append(text)
-
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_EXPANDABLE):
-            if state.contains(pyatspi.STATE_EXPANDED):
-                # Translators: this represents the state of a node in a tree.
-                # 'expanded' means the children are showing.
-                # 'collapsed' means the children are not showing.
-                #
-                text = _("expanded")
-            else:
-                # Translators: this represents the state of a node in a tree.
-                # 'expanded' means the children are showing.
-                # 'collapsed' means the children are not showing.
-                #
-                text = _("collapsed")
-            utterances.append(text)
-
-        level = self._script.getNodeLevel(orca_state.locusOfFocus)
-        if level >= 0:
-            # Translators: this represents the depth of a node in a tree
-            # view (i.e., how many ancestors a node has).
-            #
-            utterances.append(_("tree level %d") % (level + 1))
-        else:
-            nestingLevel = 0
-            parent = obj.parent
-            while parent.parent.getRole() == pyatspi.ROLE_LIST:
-                nestingLevel += 1
-                parent = parent.parent
-            if nestingLevel:
-                # Translators: this represents a list item in a document.
-                # The nesting level is how 'deep' the item is (e.g., a
-                # level of 2 represents a list item inside a list that's
-                # inside another list).
-                #
-                utterances.append(_("Nesting level %d") % nestingLevel)
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        debug.println(self._debugLevel, "list item utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
     def _speakParagraph(self, obj, basicOnly):
         """Speak a paragraph object.
         """
 
+        print self.getWhereAmI(obj, basicOnly)
+        print "================"
         self._speakText(obj, basicOnly)
 
-    def _speakIconPanel(self, obj, basicOnly):
-        """Speak the contents of the pane containing this icon. The
-        1. Number of icons in the pane is spoken.
-        2. The total number of selected icons.
-        3. The name of each of the selected icons.
-        4. tutorial string if enableTutorialMessages is set.
-
-        Arguments:
-        - obj: the icon object that currently has focus.
-        """
-
-        utterances = []
-        panel = obj.parent
-        childCount = panel.childCount
-
-        utterances.append(_("Icon panel"))
-        utterances.append(self.getObjLabelAndName(obj))
-        utterances.extend(self._getSelectedItemCount(panel, basicOnly))
-
-        # get our tutorial.
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-        # get the frames tutorial.
-        [frame, dialogue] = self._getFrameAndDialog(obj)
-        utterances.extend(getTutorial(frame, False, forceMessage=True))
-
-        speech.speak(utterances)
-
-    def _speakLink(self, obj, basicOnly):
-        """Speaks information about a link including protocol, domain
-        comparisons and size of file if possible.
-        Also tutorial string if enableTutorialMessages is set.
-
-        Arguments:
-        - obj: the icon object that currently has focus.
-        - basicOnly: True if the user is performing a standard/basic whereAmI.
-        """
-
-        # get the URI for the link of interest and parse it.
-        # parsed URI is returned as a tuple containing six components:
-        # scheme://netloc/path;parameters?query#fragment.
-        link_uri = self._script.getURI(obj)
-        if link_uri:
-            link_uri_info = urlparse.urlparse(link_uri)
-        else:
-            # It might be an anchor.  Try to speak the text.
-            #
-            return self._speakText(obj, basicOnly)
-
-        # Try to get the URI of the active document and parse it
-        doc_uri = self._script.getDocumentFrameURI()
-        if doc_uri:
-            doc_uri_info = urlparse.urlparse(doc_uri)
-        else:
-            doc_uri_info = None
-
-        # initialize our three outputs.  Output may change below for some
-        # protocols.
-        # Translators: this is the protocol of a link eg. http, mailto.
-        #
-        linkoutput = _('%s link') %link_uri_info[0]
-        text = self._script.getDisplayedText(obj)
-        if text:
-            linkoutput += " " + text
-        else:
-            # If there's no text for the link, expose part of the
-            # URI to the user.
-            #
-            basename = self._script.getLinkBasename(obj)
-            if basename:
-                linkoutput += " " + basename
-
-        # If the link has a child which is an image, we want
-        # to indicate that.
-        #
-        if obj.childCount and obj[0].getRole() == pyatspi.ROLE_IMAGE:
-            linkoutput += " " + self._getSpeechForRoleName(obj[0])
-
-        domainoutput = ''
-        sizeoutput = ''
-
-        # get size and other protocol specific information
-        if link_uri_info[0] == 'ftp' or \
-           link_uri_info[0] == 'ftps' or \
-           link_uri_info[0] == 'file':
-            # change link output message to include filename
-            filename = link_uri_info[2].split('/')
-            linkoutput = _('%s link to %s') %(link_uri_info[0], filename[-1])
-            sizestr = self.__extractSize(link_uri)
-            sizeoutput = self.__formatSizeOutput(sizestr)
-
-        # determine location differences if doc uri info is available
-        if doc_uri_info:
-            if link_uri_info[1] == doc_uri_info[1]:
-                if link_uri_info[2] == doc_uri_info[2]:
-                    # Translators: this is the domain relationship of a given
-                    # link to the current page.  eg. same page, same site.
-                    domainoutput = _('same page')
-                else:
-                    domainoutput = _('same site')
-            else:
-                # check for different machine name on same site
-                linkdomain = link_uri_info[1].split('.')
-                docdomain = doc_uri_info[1].split('.')
-                if len(linkdomain) > 1 and docdomain > 1  \
-                    and linkdomain[-1] == docdomain[-1]  \
-                    and linkdomain[-2] == docdomain[-2]:
-                    domainoutput = _('same site')
-                else:
-                    domainoutput = _('different site')
-
-        utterances = [linkoutput, domainoutput, sizeoutput]
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        speech.speak(utterances)
-
-    def _speakToggleButton(self, obj, basicOnly):
-        """Speak toggle button information:
-           1. Name/Label
-           2. Role
-           3. State (pressed/not pressed)
-           4. tutorial string if enableTutorialMessages is set.
-        """
-
-        utterances = []
-        text = self.getObjLabelAndName(obj)
-        utterances.append(text)
-
-        text = self._getSpeechForRoleName(obj)
-        utterances.append(text)
-
-        if obj.getState().contains(pyatspi.STATE_CHECKED):
-            # Translators: the state of a toggle button.
-            #
-            checkedState = _("pressed")
-        else:
-            # Translators: the state of a toggle button.
-            #
-            checkedState = _("not pressed")
-        utterances.append(checkedState)
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        speech.speak(utterances)
-
-    def _speakSplitPane(self, obj, basicOnly):
-        """Speak split pane information:
-           1. Name/Label
-           2. Role
-           3. Value
-           4. tutorial string if enableTutorialMessages is set.
-        """
-
-        utterances = []
-        text = self.getObjLabelAndName(obj)
-        utterances.append(text)
-
-        text = self._getSpeechForRoleName(obj)
-        utterances.append(text)
-
-        valueString = self._script.getTextForValue(obj)
-        utterances.append(valueString)
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        speech.speak(utterances)
-
-    def _speakLabel(self, obj, basicOnly):
-        """Speak label information:
-           1. Name/Label
-           2. selected (if True).
-           3. Role
-           4. tutorial string if enableTutorialMessages is set.
-        """
-
-        utterances = []
-        text = self.getObjLabelAndName(obj)
-        utterances.append(text)
-
-        utterances.extend(self._getSpeechForAllTextSelection(obj))
-
-        text = self._getSpeechForRoleName(obj)
-        utterances.append(text)
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        speech.speak(utterances)
-
-
-    def _speakLayeredPane(self, obj, basicOnly):
-        """Speak layered pane information:
-           1. Name/Label
-           2. Role
-           3. Number of selected items and total number of items.
-           4. tutorial string if enableTutorialMessages is set.
-        """
-
-        utterances = []
-        text = self.getObjLabelAndName(obj)
-        utterances.append(text)
-
-        text = self._getSpeechForRoleName(obj)
-        utterances.append(text)
-        utterances.extend(self._getSelectedItemCount(obj, basicOnly))
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        speech.speak(utterances)
-
-
     def _getSpeechForAllTextSelection(self, obj):
         """Check if this object has text associated with it and it's
         completely selected.
@@ -1019,421 +209,8 @@ class WhereAmI:
 
         return utterance
 
-    def _getSelectedItemCount(self, obj, basicOnly):
-        """Return an utterance indicating how many items are selected in this
-        object, the current item, and (if a detailed whereAmI), the names of
-        all the selected items. This object will be an icon panel or a
-        layered pane.
-
-        Arguments:
-        - obj: the object being presented
-        """
-
-        childCount = obj.childCount
-        selectedItems = []
-        totalSelectedItems = 0
-        currentItem = 0
-        for child in obj:
-            state = child.getState()
-            if state.contains(pyatspi.STATE_SELECTED):
-                totalSelectedItems += 1
-                selectedItems.append(child)
-            if state.contains(pyatspi.STATE_FOCUSED):
-                currentItem = child.getIndexInParent() + 1
-
-        utterances = []
-        # Translators: this is a count of the number of selected icons
-        # and the count of the total number of icons within an icon panel.
-        # An example of an icon panel is the Nautilus folder view.
-        #
-        countString = ngettext("%d of %d item selected",
-                              "%d of %d items selected",
-                              childCount) % \
-                              (totalSelectedItems, childCount)
-        utterances.append(countString)
-
-        # Translators: this is a indication of the focused icon and the
-        # count of the total number of icons within an icon panel. An
-        # example of an icon panel is the Nautilus folder view.
-        #
-        itemString = _("on item %d of %d") % (currentItem, childCount)
-        utterances.append(itemString)
-
-        if not basicOnly:
-            for i in range(0, len(selectedItems)):
-                utterances.append(self.getObjLabelAndName(selectedItems[i]))
-
-        return utterances
-
-    def __extractSize(self, uri):
-        """Get the http header for a given uri and try to extract the size
-        (Content-length).
-        """
-        try:
-            x = urllib2.urlopen(uri)
-            try:
-                return x.info()['Content-length']
-            except KeyError:
-                return None
-        except (ValueError, urllib2.URLError, OSError):
-            return None
-
-    def __formatSizeOutput(self, sizestr):
-        """Format the size output announcement.  Changes wording based on
-        size.
-        """
-        # sanity check
-        if sizestr is None or sizestr == '':
-            return ''
-        size = int(sizestr)
-        if size < 10000:
-            # Translators: This is the size of a file in bytes
-            #
-            return ngettext('%d byte', '%d bytes', size) % size
-        elif size < 1000000:
-            # Translators: This is the size of a file in kilobytes
-            #
-            return _('%.2f kilobytes') % (float(size) * .001)
-        elif size >= 1000000:
-            # Translators: This is the size of a file in megabytes
-            #
-            return _('%.2f megabytes') % (float(size) * .000001)
-
-    def _speakGenericObject(self, obj, basicOnly):
-        """Speak a generic object; one not specifically handled by
-        other methods.
-        """
-
-        utterances = []
-        text = self.getObjLabelAndName(obj)
-        utterances.append(text)
-
-        text = self._getSpeechForRoleName(obj)
-        utterances.append(text)
-
-        getTutorial = self._script.tutorialGenerator.getTutorial
-        utterances.extend(getTutorial(obj, False, forceMessage=True))
-
-        speech.speak(utterances)
-
-
-    def _getObjName(self, obj):
-        """Returns the name to speak for an object.
-        """
-
-        text = ""
-        name = self._script.getDisplayedText(obj)
-        if not name:
-            name = obj.description
-
-        if name and name != "None":
-            text = name.strip()
-        debug.println(self._debugLevel, "%s name=<%s>" % (obj.getRole(), text))
-
-        return text
-
-    def _getObjLabel(self, obj):
-        """Returns the label to speak for an object.
-        """
-
-        text = ""
-        label = self._script.getDisplayedLabel(obj)
-
-        if label and label != "None":
-            text = label.strip()
-
-        debug.println(self._debugLevel, "%s label=<%s>" % (obj.getRole(), text))
-
-        return text
-
-    def getObjLabelAndName(self, obj):
-        """Returns the object label plus the object name.
-        """
-
-        name = self._getObjName(obj)
-        label = self._getObjLabel(obj)
-
-        if name != label:
-            text = label + " " + name
-        else:
-            text = label
-
-        try:
-            textObj = obj.queryText()
-        except NotImplementedError:
-            pass
-        else:
-            [string, startOffset, endOffset] = textObj.getTextAtOffset(0,
-                pyatspi.TEXT_BOUNDARY_LINE_START)
-
-            debug.println(self._debugLevel, "%s text=<%s>" % \
-                            (obj.getRoleName(), string))
-
-        return text.strip()
-
     # pylint: disable-msg=W0142
 
-    def _getSpeechForRoleName(self, obj, **args):
-        """Returns the rolename to be spoken for the object.
-        """
-
-        try:
-            result = self._script.speechGenerator.getRoleName(obj, **args)
-            if result:
-                result = result[0]
-            else:
-                result = ""
-        except:
-            debug.printException(debug.LEVEL_WARNING)
-            result = ""
-
-        return result
-
-    def _getGroupLabel(self, obj):
-        """Returns the label for a group of components.
-        """
-
-        text = ""
-        labelledBy = None
-
-        relations = obj.getRelationSet()
-        for relation in relations:
-            if relation.getRelationType() ==  pyatspi.RELATION_LABELLED_BY:
-                labelledBy = relation.getTarget(0)
-                break
-
-        if labelledBy:
-            text = self.getObjLabelAndName(labelledBy)
-        else:
-            parent = obj.parent
-            while parent and (parent.parent != parent):
-                if parent.getRole() in [pyatspi.ROLE_PANEL,
-                                        pyatspi.ROLE_FILLER]:
-                    label = self.getObjLabelAndName(parent)
-                    if label and label != "":
-                        text = label
-                        break
-                parent = parent.parent
-
-        return text
-
-    def _getPositionInGroup(self, obj):
-        """Returns the relative position of an object in a group.
-        """
-
-        text = ""
-        position = -1
-        total = -1
-
-        relations = obj.getRelationSet()
-        for relation in relations:
-            if relation.getRelationType() == pyatspi.RELATION_MEMBER_OF:
-                total = relation.getNTargets()
-                for i in range(0, total):
-                    target = relation.getTarget(i)
-                    if target == obj:
-                        position = total - i
-                        break
-
-        if position >= 0:
-            # Translators: this is an item in a list.
-            #
-            text += _("item %d of %d") % (position, total)
-
-        return text
-
-    def _getPositionInList(self, obj, name):
-        """Returns the relative position of an object in a list.
-        """
-
-        text = ""
-        position = -1
-        index = 0
-        total = 0
-
-        # We want to return the position relative to this hierarchical
-        # level and not the entire list.  If the object in question
-        # uses the NODE_CHILD_OF relationship, we need to use it instead
-        # of the childCount.
-        #
-        childNodes = self._script.getChildNodes(obj)
-        total = len(childNodes)
-        for i in range(0, total):
-            childName = self._getObjName(childNodes[i])
-            if childName == name:
-                position = i+1
-                break
-
-        if not total:
-            for child in obj:
-                next = self._getObjName(child)
-                state = child.getState()
-                if next in ["", "Empty", "separator"] \
-                   or not state.contains(pyatspi.STATE_VISIBLE):
-                    continue
-
-                index += 1
-                total += 1
-
-                if next == name:
-                    position = index
-
-
-        if position >= 0:
-            # Translators: this is an item in a list.
-            #
-            text = _("item %d of %d") % (position, total)
-
-        return text
-
-    def _getObjAccelerator(self,
-                           obj,
-                           fallbackToMnemonic=True,
-                           fallbackToFullPath=True):
-        """Returns the accelerator for the object, if it exists.
-        """
-
-        # We'll try the real accelerator first, but fallback to the
-        # mnemonic if there is no accelerator.  This is done because
-        # some implementations, such as the Java platform, will
-        # only give us the mnemonic sometimes.
-        #
-        results = self._script.getKeyBinding(obj)
-        if results[2]:
-            return results[2]
-
-        mnemonic = results[0]
-        if mnemonic and fallbackToMnemonic:
-            return mnemonic
-
-        if fallbackToFullPath:
-            return results[1]
-
-        return ""
-
-    def _getObjMnemonic(self, obj):
-        """Returns the mnemonic (a letter) for the object, if it exists.
-        """
-        results = self._script.getKeyBinding(obj)
-        return results[0][-1:]
-
-    def _getSliderValues(self, obj):
-        """Returns the slider's current value and percentage.
-        """
-
-        value = obj.queryValue()
-
-        currentValue = "%.1f" % value.currentValue
-        percent = value.currentValue / value.maximumValue * 100
-        rounded = "%d" % round(percent, 5)
-
-        debug.println(self._debugLevel,
-            "_getSliderValues: min=%f, cur=%f, max=%f, str=%s, percent=%s" % \
-            (value.minimumValue, value.currentValue, value.maximumValue, \
-             currentValue, rounded))
-
-        return [currentValue, rounded]
-
-    def _getTableRow(self, obj):
-        """Get the speech for a table cell row or a single table cell
-        if settings.readTableCellRow is False.
-        Also return a tutorial string if enableTutorialMessages is set.
-
-        Arguments:
-        - obj: the table
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        parent = obj.parent
-        try:
-            table = parent.queryTable()
-        except NotImplementedError:
-            debug.println(self._debugLevel, "??? parent=%s" % parent.getRole())
-            return []
-        else:
-            index = self._script.getCellIndex(obj)
-            row = table.getRowAtIndex(index)
-            for i in range(0, table.nColumns):
-                acc = table.getAccessibleAt(row, i)
-                utterances.append(self._getTableCell(acc))
-
-            debug.println(self._debugLevel, "row=<%s>" % utterances)
-
-            getTutorial = self._script.tutorialGenerator.getTutorial
-            utterances.extend(getTutorial(obj, False, forceMessage=True))
-            return utterances
-
-    def _getTableCell(self, obj):
-        """Get the speech utterances for a single table cell.
-        """
-
-        isToggle = False
-        try:
-            action = obj.queryAction()
-        except NotImplementedError:
-            pass
-        else:
-            for i in range(0, action.nActions):
-                # Translators: this is the action name for
-                # the 'toggle' action. It must be the same
-                # string used in the *.po file for gail.
-                #
-                if action.getName(i) in ["toggle", _("toggle")]:
-                    isToggle = True
-                    break
-
-        if isToggle:
-            text = self._getSpeechForRoleName(obj, role=pyatspi.ROLE_CHECK_BOX)
-            text = text + " " + self._getCheckBoxState(obj)
-        else:
-            descendant = self._script.getRealActiveDescendant(obj)
-            text = self._script.getDisplayedText(descendant)
-
-        debug.println(self._debugLevel, "cell=<%s>" % text)
-        return text
-
-    def _getCheckBoxState(self, obj):
-        """Get the state of a checkbox/toggle-able table cell.
-        """
-
-        isToggle = (obj.getRole() == pyatspi.ROLE_CHECK_BOX)
-        if not isToggle:
-            try:
-                action = obj.queryAction()
-            except NotImplementedError:
-                pass
-            else:
-                for i in range(0, action.nActions):
-                    # Translators: this is the action name for
-                    # the 'toggle' action. It must be the same
-                    # string used in the *.po file for gail.
-                    #
-                    if action.getName(i) in ["toggle", _("toggle")]:
-                        isToggle = True
-                        break
-        if not isToggle:
-            return ""
-
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_INDETERMINATE):
-            # Translators: this represents the state of a checkbox.
-            #
-            text = _("partially checked")
-        elif state.contains(pyatspi.STATE_CHECKED):
-            # Translators: this represents the state of a checkbox.
-            #
-            text = _("checked")
-        else:
-            # Translators: this represents the state of a checkbox.
-            #
-            text = _("not checked")
-
-        return text
-
     def getTextSelection(self, obj):
         """Get the text selection for the given object.
 
@@ -1788,239 +565,20 @@ class WhereAmI:
 
         return dictionary
 
-    def speakTitle(self, obj):
-        """Orca will speak the following information:
-
-        1. The contents of the title bar of the application main window
-        2. If in a dialog box within an application, the contents of the
-        title bar of the dialog box.
-        3. '<n> unfocused dialogs' if this application has more than
-           one unfocused alert or dialog window.
-        4. Orca will pause briefly between these two pieces of information
-        so that the speech user can distinguish each.
+    def getWhereAmI(self, obj, basicOnly):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the complete speech for the
+        object.  The speech to be generated depends highly upon the
+        speech formatting strings in formatting.py.
         """
 
-        utterances = []
-
-        results = self._getFrameAndDialog(obj)
-
-        if results[0]:
-            text = self.getObjLabelAndName(results[0])
-            utterances.append(text)
-        if results[1]:
-            text = self.getObjLabelAndName(results[1])
-            utterances.append(text)
-
-        alertAndDialogCount = \
-                    self._script.getUnfocusedAlertAndDialogCount(obj)
-        if alertAndDialogCount > 0:
-            # Translators: this tells the user how many unfocused
-            # alert and dialog windows that this application has.
-            #
-            line = ngettext("%d unfocused dialog",
-                            "%d unfocused dialogs",
-                            alertAndDialogCount) % alertAndDialogCount
-            utterances.append(line)
-
-        debug.println(self._debugLevel, "titlebar utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
-    def speakStatusBar(self, obj):
-        """Speak the contents of the status bar of the window with focus.
-        """
-
-        utterances = []
-
-        results = self._getFrameAndDialog(obj)
-
-        if results[0]:
-            self._statusBar = None
-            self._getStatusBar(results[0])
-            if self._statusBar:
-                self._speakStatusBar()
-        window = results[1] or results[0]
-        if window:
-            self._speakDefaultButton(window)
-
-        debug.println(self._debugLevel, "status bar utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
-    def _getFrameAndDialog(self, obj):
-        """Returns the frame and (possibly) the dialog containing
-        the object.
-        """
-
-        results = [None, None]
-
-        parent = obj.parent
-        while parent and (parent.parent != parent):
-            #debug.println(self._debugLevel,
-            #              "_getFrameAndDialog: parent=%s, %s" % \
-            #              (parent.getRole(), self.getObjLabelAndName(parent)))
-            if parent.getRole() == pyatspi.ROLE_FRAME:
-                results[0] = parent
-            if parent.getRole() in [pyatspi.ROLE_DIALOG,
-                                    pyatspi.ROLE_FILE_CHOOSER]:
-                results[1] = parent
-            parent = parent.parent
-
-        return results
-
-    def _getStatusBar(self, obj):
-        """Gets the status bar.
-        """
-        if self._statusBar:
-            return
-
-        # debug.println(self._debugLevel, "_findStatusBar: ROOT=%s, %s" % \
-        #               (obj.getRole(), self.getObjLabelAndName(obj)))
-        state = obj.getState()
-        managesDescendants = state.contains(pyatspi.STATE_MANAGES_DESCENDANTS)
-        if managesDescendants:
-            return
-
-        for child in obj:
-            # debug.println(self._debugLevel,
-            #               "_findStatusBar: child=%s, %s" % \
-            #               (child.getRole(), self.getObjLabelAndName(child)))
-            if child.getRole() == pyatspi.ROLE_STATUS_BAR:
-                self._statusBar = child
-                return
-
-            if child.childCount > 0:
-                self._getStatusBar(child)
-
-    def _speakStatusBar(self):
-        """Speaks the status bar.
-        """
-
-        if not self._statusBar:
-            return
-
-        utterances = []
-
-        text = self._getObjName(self._statusBar)
-        if text:
-            utterances.append(text)
-        elif self._statusBar.childCount:
-            for child in self._statusBar:
-                text = self._getObjName(child)
-                utterances.append(text)
-
-        debug.println(self._debugLevel, "statusbar utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
-    def _getDefaultButton(self, obj):
-        """Gets the default button in a dialog.
-
-        Arguments:
-        - obj: the dialog box for which the default button should be obtained
-        """
-
-        defaultButton = None
-        for child in obj:
-            # debug.println(self._debugLevel,
-            #               "_getDefaultButton: child=%s, %s" % \
-            #               (child.getRole(), self.getObjLabelAndName(child)))
-            state = child.getState()
-            if child.getRole() == pyatspi.ROLE_PUSH_BUTTON \
-                and state.contains(pyatspi.STATE_IS_DEFAULT):
-                defaultButton = child
-            else:
-                defaultButton = self._getDefaultButton(child)
-
-            if defaultButton:
-                break
-
-        return defaultButton
-
-    def _speakDefaultButton(self, obj):
-        """Speaks the default button in a dialog.
-
-        Arguments:
-        - obj: the dialog box for which the default button should be obtained
-        """
-
-        defaultButton = self._getDefaultButton(obj)
-
-        if not defaultButton:
-            return
-
-        state = defaultButton.getState()
-        if not state.contains(pyatspi.STATE_SENSITIVE):
-            return
-
-        utterances = []
-
-        # Translators: The "default" button in a dialog box is the button
-        # that gets activated when Enter is pressed anywhere within that
-        # dialog box.
+        # TODO - JD: I don't think this is how we should do things.
+        # I'm just in the process of moving things out of here and
+        # into speech_generator.py or default.py (and the app scripts)
+        # as approriate. This keeps things working in the meantime.
         #
-        text = _("Default button is %s") % \
-               self._getObjName(defaultButton)
-        utterances.append(text)
-
-        debug.println(self._debugLevel, "default button utterances=%s" % \
-                      utterances)
-        speech.speak(utterances)
-
-    def _speakObjDescription(self, obj):
-        """Speaks the object's description if it is not the same as
-        the object's name or label.
-        """
-
-        description = obj.description
-        name = self._getObjName(obj)
-        label = self._getObjLabel(obj)
-
-        if description and not description in [name, label]:
-            speech.speak(description)
-
-    def _getToolbar(self, obj):
-        """Returns the toolbar containing the object or None if the object
-        is not contained in a toolbar.
-        """
-
-        parent = obj.parent
-        while parent and (parent.parent != parent):
-            if parent.getRole() == pyatspi.ROLE_TOOL_BAR:
-                return parent
-            parent = parent.parent
-
-        return None
-
-    def _speakToolbar(self, obj):
-        """Speaks the label and/or name of a toolbar, followed by its role.
-        """
-
-        utterances = []
-        text = self.getObjLabelAndName(obj) + " " + \
-               self._getSpeechForRoleName(obj)
-        utterances.append(text.strip())
-
-        debug.println(self._debugLevel, "toolbar utterances=%s" \
-                      % utterances)
-        speech.speak(utterances)
-
-    def _getRequiredState(self, obj):
-        """Returns a string describing the required state of the given
-        object.
-
-        Arguments:
-        - obj: the Accessible object
-        """
-
-        if not settings.presentRequiredState:
-            return ""
-
-        if obj.getRole() == pyatspi.ROLE_RADIO_BUTTON:
-            obj = obj.parent
-
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_REQUIRED):
-            return settings.speechRequiredStateString
-        else:
-            return ""
+        return self._script.speechGenerator.\
+            getSpeech(obj,
+                      already_focused = True,
+                      where_am_i_type = basicOnly,
+                      forceMessage=True)
diff --git a/test/keystrokes/gtk-demo/role_column_header.py b/test/keystrokes/gtk-demo/role_column_header.py
index d54ce12..168a3b9 100644
--- a/test/keystrokes/gtk-demo/role_column_header.py
+++ b/test/keystrokes/gtk-demo/role_column_header.py
@@ -105,12 +105,24 @@ sequence.append(utils.AssertPresentationAction(
     "Normal cell basic Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Severity ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
      "     VISIBLE:  'Normal scrollable notebooks and ', cursor=1",
-     "SPEECH OUTPUT: 'table Severity cell Normal'",
-     "SPEECH OUTPUT: 'column 3 of 4 row 1 of 14'"]))
+     "SPEECH OUTPUT: 'table Severity cell Normal column 3 of 4 row 1 of 14'"]))
 
 ########################################################################
 # Do a detailed "Where Am I" via KP_Enter.
 #
+# JD to WDW: This test was changed. Multiple utterances are now just
+# one. Do we care? 
+#
+# WDW to JD: No - it's OK.  If pauses are needed (which we can learn via
+# end user testing), we can add '+ ["."] +' things in the formatting
+# strings as needed.
+#
+# In addition, something I would consider a bug fix: Before we
+# didn't speak the name ("Fixed?") of the checkbox at the start of the row;
+# now we do.
+#
+# WDW to JD: I agree.
+#
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(KeyComboAction("KP_Enter"))
@@ -121,11 +133,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Normal scrollable notebooks and ', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Severity ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
      "     VISIBLE:  'Normal scrollable notebooks and ', cursor=1",
-     "SPEECH OUTPUT: 'table Severity cell Normal'",
-     "SPEECH OUTPUT: 'column 3 of 4 row 1 of 14'",
-     "SPEECH OUTPUT: 'table Severity cell Normal'",
-     "SPEECH OUTPUT: 'column 3 of 4 row 1 of 14'",
-     "SPEECH OUTPUT: 'check box not checked 60482 Normal scrollable notebooks and hidden tabs'"]))
+     "SPEECH OUTPUT: 'table Severity cell Normal column 3 of 4 row 1 of 14'",
+     "SPEECH OUTPUT: 'table Severity cell Normal column 3 of 4 row 1 of 14 Fixed? check box not checked 60482 Normal scrollable notebooks and hidden tabs'"]))
 
 ########################################################################
 # Now move to the cell to the left containing the number "60482".
@@ -169,8 +178,7 @@ sequence.append(utils.AssertPresentationAction(
     "Checkbox cell basic Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Fixed? ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
      "     VISIBLE:  '< > Fixed? 60482 Normal scrollab', cursor=1",
-     "SPEECH OUTPUT: 'table Fixed? cell check box not checked'",
-     "SPEECH OUTPUT: 'column 1 of 4 row 1 of 14'"]))
+     "SPEECH OUTPUT: 'table Fixed? cell check box not checked column 1 of 4 row 1 of 14'"]))
 
 ########################################################################
 # Do a detailed "Where Am I" via KP_Enter.
@@ -185,11 +193,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  '< > Fixed? 60482 Normal scrollab', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Fixed? ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
      "     VISIBLE:  '< > Fixed? 60482 Normal scrollab', cursor=1",
-     "SPEECH OUTPUT: 'table Fixed? cell check box not checked'",
-     "SPEECH OUTPUT: 'column 1 of 4 row 1 of 14'",
-     "SPEECH OUTPUT: 'table Fixed? cell check box not checked'",
-     "SPEECH OUTPUT: 'column 1 of 4 row 1 of 14'",
-     "SPEECH OUTPUT: 'check box not checked 60482 Normal scrollable notebooks and hidden tabs'"]))
+     "SPEECH OUTPUT: 'table Fixed? cell check box not checked column 1 of 4 row 1 of 14'",
+     "SPEECH OUTPUT: 'table Fixed? cell check box not checked column 1 of 4 row 1 of 14 Fixed? check box not checked 60482 Normal scrollable notebooks and hidden tabs'"]))
  
 ########################################################################
 # Close the GtkListStore demo
diff --git a/test/keystrokes/gtk-demo/role_combo_box.py b/test/keystrokes/gtk-demo/role_combo_box.py
index e5da7de..2ea9fb4 100644
--- a/test/keystrokes/gtk-demo/role_combo_box.py
+++ b/test/keystrokes/gtk-demo/role_combo_box.py
@@ -43,6 +43,13 @@ sequence.append(utils.AssertPresentationAction(
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
 #
+# JD to WDW: This to me looks like two bug fixes:
+# 1) Lost a trailing space
+# 2) Before we were saying "menu"; I don't think we should in a combo box,
+#    even though technically there is a menu in between a combo box and
+#    the options it contains in the hierarchy.
+# Question: Should we be presenting the containing panel or not?
+#
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
@@ -50,7 +57,7 @@ sequence.append(utils.AssertPresentationAction(
     "Warning combo box item Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Some stock icons Panel  ComboWarning Warning'",
      "     VISIBLE:  'Warning', cursor=1",
-     "SPEECH OUTPUT: 'menu Warning  item 1 of 5 '"]))
+     "SPEECH OUTPUT: 'Some stock icons panel Warning item 1 of 5'"]))
 
 ########################################################################
 # Now arrow down and select the "New" item.
@@ -67,6 +74,13 @@ sequence.append(utils.AssertPresentationAction(
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
 #
+# JD to WDW: This to me looks like two bug fixes:
+# 1) Lost a trailing space
+# 2) Before we were saying "menu"; I don't think we should in a combo box,
+#    even though technically there is a menu in between a combo box and
+#    the options it contains in the hierarchy.
+# Question: Should we be presenting the containing panel or not?
+#
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
@@ -74,7 +88,7 @@ sequence.append(utils.AssertPresentationAction(
     "New combo box item Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Some stock icons Panel  ComboWarning New'",
      "     VISIBLE:  'New', cursor=1",
-     "SPEECH OUTPUT: 'menu New  item 3 of 5 '"]))
+     "SPEECH OUTPUT: 'Some stock icons panel New item 3 of 5'"]))
 
 ########################################################################
 # Select the "New" entry and tab to the editable text combo box.  Skip
@@ -135,6 +149,9 @@ sequence.append(utils.AssertPresentationAction(
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
 #
+# TODO - JD: For some reason, this is split up into multiple utterances
+# now.
+#
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
@@ -142,7 +159,8 @@ sequence.append(utils.AssertPresentationAction(
     "Editable text combo box Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Editable Panel Four $l'",
      "     VISIBLE:  'Four $l', cursor=5",
-     "SPEECH OUTPUT: 'text Four'"]))
+     "SPEECH OUTPUT: 'text",
+     "SPEECH OUTPUT: 'Four'"]))
 
 ########################################################################
 # Tab to the triangular down arrow of the editable combo box.
@@ -196,6 +214,9 @@ sequence.append(utils.AssertPresentationAction(
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
 #
+# TODO - JD: For some reason, this is split up into multiple utterances
+# now.
+#
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
@@ -203,8 +224,9 @@ sequence.append(utils.AssertPresentationAction(
     "Editable text combo box with selected text Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Editable Panel Four $l'",
      "     VISIBLE:  'Four $l', cursor=5",
-     "SPEECH OUTPUT: 'text Four'",
-     "SPEECH OUTPUT: 'selected '"]))
+     "SPEECH OUTPUT: 'text",
+     "SPEECH OUTPUT: 'Four'",
+     "SPEECH OUTPUT: 'selected'"]))
 
 ########################################################################
 # Tab to the triangular down arrow of the editable combo box and open
diff --git a/test/keystrokes/gtk-demo/role_label.py b/test/keystrokes/gtk-demo/role_label.py
index cc7d0b6..fcf13f4 100644
--- a/test/keystrokes/gtk-demo/role_label.py
+++ b/test/keystrokes/gtk-demo/role_label.py
@@ -69,6 +69,15 @@ sequence.append(utils.AssertPresentationAction(
 ########################################################################
 # Do an extended "Where Am I" via double KP_Enter.
 #
+# JD to WDW: The difference here is that we are not repeating the speech
+# output. Personally I think that's a good thing. Is there any reason
+# we should be duplicating output in the case of a detailed/extended
+# where am i?
+#
+# WDW to JD: the first should be for the first KP_Enter (i.e., basic
+# where am I) and the second should be for the second KP_Enter (i.e.,
+# extended where am I). So, why did we end up losing one?
+#
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(KeyComboAction("KP_Enter"))
@@ -80,8 +89,6 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'gtk-demo Application Information Alert number of times: $l'",
      "     VISIBLE:  'number of times: $l', cursor=17",
      "SPEECH OUTPUT: 'This message box has been popped up the following",
-     "number of times: selected label'",
-     "SPEECH OUTPUT: 'This message box has been popped up the following",
      "number of times: selected label'"]))
 
 ########################################################################
@@ -139,6 +146,15 @@ sequence.append(utils.AssertPresentationAction(
 ########################################################################
 # Do an extended "Where Am I" via double KP_Enter.
 #
+# JD to WDW: The difference here is that we are not repeating the speech
+# output. Personally I think that's a good thing. Is there any reason
+# we should be duplicating output in the case of a detailed/extended
+# where am i?
+#
+# WDW to JD: the first should be for the first KP_Enter (i.e., basic
+# where am I) and the second should be for the second KP_Enter (i.e.,
+# extended where am I). So, why did we end up losing one?
+#
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(KeyComboAction("KP_Enter"))
@@ -150,8 +166,6 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'gtk-demo Application Information Alert This message box has been popped up the following $l'",
      "     VISIBLE:  'This message box has been popped', cursor=5",
      "SPEECH OUTPUT: 'This message box has been popped up the following",
-     "number of times: selected label'",
-     "SPEECH OUTPUT: 'This message box has been popped up the following",
      "number of times: selected label'"]))
 
 ########################################################################
diff --git a/test/keystrokes/gtk-demo/role_menu.py b/test/keystrokes/gtk-demo/role_menu.py
index faa8133..c2fb37d 100644
--- a/test/keystrokes/gtk-demo/role_menu.py
+++ b/test/keystrokes/gtk-demo/role_menu.py
@@ -48,7 +48,7 @@ sequence.append(utils.AssertPresentationAction(
     "File menu Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame File Menu'",
      "     VISIBLE:  'File Menu', cursor=1",
-     "SPEECH OUTPUT: 'menu bar File menu  item 1 of 3 f'"]))
+     "SPEECH OUTPUT: 'menu bar File menu item 1 of 3 f'"]))
 
 ########################################################################
 # Right arrow to the "Preferences" menu.
@@ -73,7 +73,7 @@ sequence.append(utils.AssertPresentationAction(
     "Preferences menu Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame Preferences Menu'",
      "     VISIBLE:  'Preferences Menu', cursor=1",
-     "SPEECH OUTPUT: 'menu bar Preferences menu  item 2 of 3 p'"]))
+     "SPEECH OUTPUT: 'menu bar Preferences menu item 2 of 3 p'"]))
 
 ########################################################################
 # Go down to the "Color" menu.
@@ -98,7 +98,7 @@ sequence.append(utils.AssertPresentationAction(
     "Color menu Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar Color Menu'",
      "     VISIBLE:  'Color Menu', cursor=1",
-     "SPEECH OUTPUT: 'Preferences menu Color menu  item 1 of 3 c'"]))
+     "SPEECH OUTPUT: 'Preferences menu Color menu item 1 of 3 c'"]))
 
 ########################################################################
 # Go down to the "Shape" menu.
@@ -123,7 +123,7 @@ sequence.append(utils.AssertPresentationAction(
     "Shape menu Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar Shape Menu'",
      "     VISIBLE:  'Shape Menu', cursor=1",
-     "SPEECH OUTPUT: 'Preferences menu Shape menu  item 2 of 3 s'"]))
+     "SPEECH OUTPUT: 'Preferences menu Shape menu item 2 of 3 s'"]))
 
 ########################################################################
 # Dismiss the menu and close the Application Window demo window
diff --git a/test/keystrokes/gtk-demo/role_page_tab.py b/test/keystrokes/gtk-demo/role_page_tab.py
index 2984beb..09b1489 100644
--- a/test/keystrokes/gtk-demo/role_page_tab.py
+++ b/test/keystrokes/gtk-demo/role_page_tab.py
@@ -56,7 +56,7 @@ sequence.append(utils.AssertPresentationAction(
     "General page tab Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Print Dialog General Page'",
      "     VISIBLE:  'General Page', cursor=1",
-     "SPEECH OUTPUT: 'tab list General page item 1 of 2 '"]))
+     "SPEECH OUTPUT: 'tab list General page item 1 of 2'"]))
 
 ########################################################################
 # Arrow Right to the "Page Setup" tab.
@@ -80,7 +80,7 @@ sequence.append(utils.AssertPresentationAction(
     "Page Setup page tab Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Print Dialog Page Setup Page'",
      "     VISIBLE:  'Page Setup Page', cursor=1",
-     "SPEECH OUTPUT: 'tab list Page Setup page item 2 of 2 '"]))
+     "SPEECH OUTPUT: 'tab list Page Setup page item 2 of 2'"]))
 
 ########################################################################
 # Close the demo
diff --git a/test/keystrokes/gtk-demo/role_radio_menu_item.py b/test/keystrokes/gtk-demo/role_radio_menu_item.py
index 2ba11ac..319c811 100644
--- a/test/keystrokes/gtk-demo/role_radio_menu_item.py
+++ b/test/keystrokes/gtk-demo/role_radio_menu_item.py
@@ -43,6 +43,12 @@ sequence.append(utils.AssertPresentationAction(
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
 #
+# JD to WDW: I'm not sure if this is a regression or not. Now we are
+# speaking a parent menu which we were not before. I *think* that's
+# a bug fix. :-)
+#
+# WDW to JD: I agree -- it looks like a bug fix (yeah!)
+#
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
@@ -50,7 +56,7 @@ sequence.append(utils.AssertPresentationAction(
     "Red button Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar Preferences Menu <x> Red CheckItem(Control r)'",
      "     VISIBLE:  '<x> Red CheckItem(Control r)', cursor=1",
-     "SPEECH OUTPUT: 'Color menu Red check item checked Control r item 1 of 3 r'"]))
+     "SPEECH OUTPUT: 'Preferences menu Color menu Red check item checked Control r item 1 of 3 r'"]))
 
 ########################################################################
 # Down arrow to the "Green" menu item.
@@ -68,6 +74,12 @@ sequence.append(utils.AssertPresentationAction(
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
 #
+# JD to WDW: I'm not sure if this is a regression or not. Now we are
+# speaking a parent menu which we were not before. I *think* that's
+# a bug fix. :-)
+#
+# WDW to JD: I agree -- it looks like a bug fix (yeah!)
+#
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
@@ -75,7 +87,7 @@ sequence.append(utils.AssertPresentationAction(
     "Green button Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar Preferences Menu < > Green CheckItem(Control g)'",
      "     VISIBLE:  '< > Green CheckItem(Control g)', cursor=1",
-     "SPEECH OUTPUT: 'Color menu Green check item not checked Control g item 2 of 3 g'"]))
+     "SPEECH OUTPUT: 'Preferences menu Color menu Green check item not checked Control g item 2 of 3 g'"]))
 
 ########################################################################
 # Dismiss the menu and close the Application Window demo window
diff --git a/test/keystrokes/gtk-demo/role_table.py b/test/keystrokes/gtk-demo/role_table.py
index d429935..f91c999 100644
--- a/test/keystrokes/gtk-demo/role_table.py
+++ b/test/keystrokes/gtk-demo/role_table.py
@@ -82,8 +82,7 @@ sequence.append(utils.AssertPresentationAction(
     "Table Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Shopping list Frame ScrollPane Table Number ColumnHeader 3 bottles of coke[ ]*'",
      "     VISIBLE:  '3 bottles of coke[ ]*', cursor=1",
-     "SPEECH OUTPUT: 'table Number cell 3'",
-     "SPEECH OUTPUT: 'column 1 of 3 row 1 of 5'"]))
+     "SPEECH OUTPUT: 'table Number cell 3 column 1 of 3 row 1 of 5'"]))
 
 ########################################################################
 # Down arrow to the next line.
@@ -110,8 +109,7 @@ sequence.append(utils.AssertPresentationAction(
     "Table Where Am I (again)",
     ["BRAILLE LINE:  'gtk-demo Application Shopping list Frame ScrollPane Table Number ColumnHeader 5'",
      "     VISIBLE:  '5', cursor=1",
-     "SPEECH OUTPUT: 'table Number cell 5'",
-     "SPEECH OUTPUT: 'column 1 of 3 row 2 of 5'"]))
+     "SPEECH OUTPUT: 'table Number cell 5 column 1 of 3 row 2 of 5'"]))
 
 ########################################################################
 # Turn reading of rows off.
diff --git a/test/keystrokes/gtk-demo/role_text_multiline.py b/test/keystrokes/gtk-demo/role_text_multiline.py
index ab20a11..ea2e3f7 100644
--- a/test/keystrokes/gtk-demo/role_text_multiline.py
+++ b/test/keystrokes/gtk-demo/role_text_multiline.py
@@ -230,8 +230,9 @@ sequence.append(utils.AssertPresentationAction(
     "Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame ScrollPane This is a test. $l'",
      "     VISIBLE:  'This is a test. $l', cursor=11",
-     "SPEECH OUTPUT: 'text  is a '",
-     "SPEECH OUTPUT: 'selected '"]))
+     "SPEECH OUTPUT: 'text'",
+     "SPEECH OUTPUT: ' is a '",
+     "SPEECH OUTPUT: 'selected'"]))
 
 ########################################################################
 # Press Home to move to the beginning of the line. Arrow down to 
@@ -307,8 +308,9 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I multiline selection",
     ["BRAILLE LINE:  'The keyboard sure can get sticky. $l'",
      "     VISIBLE:  'The keyboard sure can get sticky', cursor=13",
-     "SPEECH OUTPUT: 'text The keyboard'",
-     "SPEECH OUTPUT: 'selected '"]))
+     "SPEECH OUTPUT: 'text'",
+     "SPEECH OUTPUT: 'The keyboard'",
+     "SPEECH OUTPUT: 'selected'"]))
 
 ########################################################################
 # Do a detailed "Where Am I" via KP_Enter 2x.
@@ -323,11 +325,13 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'The keyboard sure can get sticky', cursor=13",
      "BRAILLE LINE:  'The keyboard sure can get sticky. $l'",
      "     VISIBLE:  'The keyboard sure can get sticky', cursor=13",
-     "SPEECH OUTPUT: 'text The keyboard'",
-     "SPEECH OUTPUT: 'selected '",
-     "SPEECH OUTPUT: 'text I'm just typing away like a mad little monkey with nothing better to do in my life than eat fruit and type.",
+     "SPEECH OUTPUT: 'text'",
+     "SPEECH OUTPUT: 'The keyboard'",
+     "SPEECH OUTPUT: 'selected'",
+     "SPEECH OUTPUT: 'text'",
+     "SPEECH OUTPUT: 'I'm just typing away like a mad little monkey with nothing better to do in my life than eat fruit and type.",
      "The keyboard'",
-     "SPEECH OUTPUT: 'selected '"]))
+     "SPEECH OUTPUT: 'selected'"]))
 
 ########################################################################
 # Try a "SayAll".
diff --git a/test/keystrokes/gtk-demo/role_toolbar.py b/test/keystrokes/gtk-demo/role_toolbar.py
index c244954..22a031e 100644
--- a/test/keystrokes/gtk-demo/role_toolbar.py
+++ b/test/keystrokes/gtk-demo/role_toolbar.py
@@ -55,7 +55,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame ToolBar Open Button'",
      "     VISIBLE:  'Open Button', cursor=1",
      "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: 'Open button '"]))
+     "SPEECH OUTPUT: 'Open button'"]))
 
 ########################################################################
 # Arrow Right to the triangular button next to the "Open" button.
@@ -105,7 +105,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame ToolBar Quit Button'",
      "     VISIBLE:  'Quit Button', cursor=1",
      "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: 'Quit button '"]))
+     "SPEECH OUTPUT: 'Quit button'"]))
 
 ########################################################################
 # Close the Application Window demo window
diff --git a/test/keystrokes/gtk-demo/role_tree_table.py b/test/keystrokes/gtk-demo/role_tree_table.py
index 4a971b3..9893218 100644
--- a/test/keystrokes/gtk-demo/role_tree_table.py
+++ b/test/keystrokes/gtk-demo/role_tree_table.py
@@ -82,13 +82,19 @@ sequence.append(utils.AssertPresentationAction(
     "January cell basic Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January expanded < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
      "     VISIBLE:  'January expanded < > Alex < > Ha', cursor=1",
-     "SPEECH OUTPUT: 'tree table Holiday cell January'",
-     "SPEECH OUTPUT: 'column 1 of 6 row 1 of 53'",
-     "SPEECH OUTPUT: 'expanded tree level 1'"]))
+     "SPEECH OUTPUT: 'tree table Holiday cell January column 1 of 6 row 1 of 53 expanded tree level 1'"]))
 
 ########################################################################
 # Do a detailed "Where Am I" via KP_Enter.
 #
+# JD to WDW: another case of utterances being collapsed.
+# In addition, before the detailed Where Am I didn't include the
+# names of the other checkboxes on the row; just their states in
+# rapid succession. Now we speak the names. I think this is a bug
+# fix. :-) Thoughts?
+#
+# WDW to JD: Agreed.  This looks like a fix.
+#
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(KeyComboAction("KP_Enter"))
@@ -99,13 +105,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'January expanded < > Alex < > Ha', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January expanded < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
      "     VISIBLE:  'January expanded < > Alex < > Ha', cursor=1",
-     "SPEECH OUTPUT: 'tree table Holiday cell January'",
-     "SPEECH OUTPUT: 'column 1 of 6 row 1 of 53'",
-     "SPEECH OUTPUT: 'expanded tree level 1'",
-     "SPEECH OUTPUT: 'tree table Holiday cell January'",
-     "SPEECH OUTPUT: 'column 1 of 6 row 1 of 53'",
-     "SPEECH OUTPUT: 'January check box not checked check box not checked check box not checked check box not checked check box not checked'",
-     "SPEECH OUTPUT: 'expanded tree level 1'"]))
+     "SPEECH OUTPUT: 'tree table Holiday cell January column 1 of 6 row 1 of 53 expanded tree level 1'",
+     "SPEECH OUTPUT: 'tree table Holiday cell January column 1 of 6 row 1 of 53 January expanded 3 items Alex check box not checked Havoc check box not checked Tim check box not checked Owen check box not checked Dave check box not checked expanded tree level 1'"]))
 
 ########################################################################
 # Collapse the cell.
@@ -133,13 +134,19 @@ sequence.append(utils.AssertPresentationAction(
     "January cell collapsed basic Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January collapsed < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
      "     VISIBLE:  'January collapsed < > Alex < > H', cursor=1",
-     "SPEECH OUTPUT: 'tree table Holiday cell January'",
-     "SPEECH OUTPUT: 'column 1 of 6 row 1 of 50'",
-     "SPEECH OUTPUT: 'collapsed tree level 1'"]))
+     "SPEECH OUTPUT: 'tree table Holiday cell January column 1 of 6 row 1 of 50 collapsed tree level 1'"]))
 
 ########################################################################
 # Do a detailed "Where Am I" via KP_Enter.
 #
+# JD to WDW: another case of utterances being collapsed.
+# In addition, before the detailed Where Am I didn't include the
+# names of the other checkboxes on the row; just their states in
+# rapid succession. Now we speak the names. I think this is a bug
+# fix. :-) Thoughts?
+#
+# WDW to JD: Agreed.  This looks like a fix.
+#
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(KeyComboAction("KP_Enter"))
@@ -150,13 +157,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'January collapsed < > Alex < > H', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January collapsed < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
      "     VISIBLE:  'January collapsed < > Alex < > H', cursor=1",
-     "SPEECH OUTPUT: 'tree table Holiday cell January'",
-     "SPEECH OUTPUT: 'column 1 of 6 row 1 of 50'",
-     "SPEECH OUTPUT: 'collapsed tree level 1'",
-     "SPEECH OUTPUT: 'tree table Holiday cell January'",
-     "SPEECH OUTPUT: 'column 1 of 6 row 1 of 50'",
-     "SPEECH OUTPUT: 'January check box not checked check box not checked check box not checked check box not checked check box not checked'",
-     "SPEECH OUTPUT: 'collapsed tree level 1'"]))
+     "SPEECH OUTPUT: 'tree table Holiday cell January column 1 of 6 row 1 of 50 collapsed tree level 1'",
+     "SPEECH OUTPUT: 'tree table Holiday cell January column 1 of 6 row 1 of 50 January collapsed Alex check box not checked Havoc check box not checked Tim check box not checked Owen check box not checked Dave check box not checked collapsed tree level 1'"]))
 
 ########################################################################
 # Expand the cell again.
@@ -220,8 +222,7 @@ sequence.append(utils.AssertPresentationAction(
     "Alex checkbox cell basic Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Alex ColumnHeader <x> Alex'",
      "     VISIBLE:  '<x> Alex', cursor=1",
-     "SPEECH OUTPUT: 'tree table Alex cell check box checked'",
-     "SPEECH OUTPUT: 'column 2 of 6 row 2 of 53'"]))
+     "SPEECH OUTPUT: 'tree table Alex cell check box checked column 2 of 6 row 2 of 53'"]))
 
 ########################################################################
 # Do a detailed "Where Am I" via KP_Enter.
@@ -236,11 +237,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  '<x> Alex', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Alex ColumnHeader <x> Alex'",
      "     VISIBLE:  '<x> Alex', cursor=1",
-     "SPEECH OUTPUT: 'tree table Alex cell check box checked'",
-     "SPEECH OUTPUT: 'column 2 of 6 row 2 of 53'",
-     "SPEECH OUTPUT: 'tree table Alex cell check box checked'",
-     "SPEECH OUTPUT: 'column 2 of 6 row 2 of 53'",
-     "SPEECH OUTPUT: 'New Years Day check box checked check box checked check box checked check box checked check box not checked'"]))
+     "SPEECH OUTPUT: 'tree table Alex cell check box checked column 2 of 6 row 2 of 53'",
+     "SPEECH OUTPUT: 'tree table Alex cell check box checked column 2 of 6 row 2 of 53 New Years Day Alex check box checked Havoc check box checked Tim check box checked Owen check box checked Dave check box not checked'"]))
 
 ########################################################################
 # Change the state of the checkbox.



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