[orca/570658-whereami] Work on the Gecko whereAmI refactor.



commit 34e8e09425254fa0fd72c1e5012aba66f6d4e2af
Author: Joanmarie Diggs <joanmarie diggs gmail com>
Date:   Sun Jun 7 15:19:05 2009 -0400

    Work on the Gecko whereAmI refactor.
---
 src/orca/formatting.py                             |    4 +-
 src/orca/liveregions.py                            |   13 +-
 src/orca/scripts/toolkits/Gecko/Makefile.am        |    3 +-
 src/orca/scripts/toolkits/Gecko/formatting.py      |   12 +
 src/orca/scripts/toolkits/Gecko/script.py          |  114 ++++++++-
 .../scripts/toolkits/Gecko/speech_generator.py     |  118 ++++++++-
 src/orca/scripts/toolkits/Gecko/where_am_i.py      |  281 --------------------
 src/orca/speech_generator.py                       |   20 +-
 test/keystrokes/firefox/codetalks_tree.py          |    4 +-
 test/keystrokes/firefox/dojo_tree.py               |    5 +-
 test/keystrokes/firefox/moz_slider.py              |    7 +-
 test/keystrokes/firefox/moz_tabpanel.py            |    2 +-
 test/keystrokes/firefox/uiuc_slider.py             |    2 +-
 test/keystrokes/firefox/uiuc_tree.py               |    2 +-
 test/keystrokes/firefox/xul_role_accel_label.py    |    3 +-
 .../keystrokes/firefox/xul_role_check_menu_item.py |    3 +-
 test/keystrokes/firefox/xul_role_combo_box.py      |    5 +-
 test/keystrokes/firefox/xul_role_page_tab.py       |    4 +-
 .../keystrokes/firefox/xul_role_radio_menu_item.py |    6 +-
 test/keystrokes/firefox/xul_role_tree.py           |    2 +-
 test/keystrokes/gtk-demo/role_radio_button.py      |    4 +-
 test/keystrokes/gtk-demo/role_toolbar.py           |    9 +-
 22 files changed, 286 insertions(+), 337 deletions(-)

diff --git a/src/orca/formatting.py b/src/orca/formatting.py
index fafcd14..ac7feea 100644
--- a/src/orca/formatting.py
+++ b/src/orca/formatting.py
@@ -118,7 +118,7 @@ formatting = {
         pyatspi.ROLE_LIST_ITEM: {
             'focused': 'expandableState + availability',
             'unfocused': 'labelAndName + allTextSelection + expandableState + availability',
-            'basicWhereAmI': 'label + roleName + name + expandableState + positionInList + nodeLevel + nestingLevel'
+            'basicWhereAmI': 'label + roleName + name + positionInList + expandableState + (nodeLevel or nestingLevel)'
             },
         pyatspi.ROLE_MENU: {
             'focused': '[]',
@@ -156,7 +156,7 @@ formatting = {
         pyatspi.ROLE_RADIO_BUTTON: {
             'focused': 'radioState',
             'unfocused': 'labelAndName + radioState + roleName + availability + mnemonic + accelerator',
-            'basicWhereAmI': '(radioButtonGroup or ancestors) + labelAndName + roleName + radioState + positionInGroup + mnemonic + accelerator'
+            'basicWhereAmI': 'radioButtonGroup + labelAndName + roleName + radioState + positionInGroup + mnemonic + accelerator'
             },
         pyatspi.ROLE_RADIO_MENU_ITEM: {
             # OpenOffice check menu items currently have a role of "menu item"
diff --git a/src/orca/liveregions.py b/src/orca/liveregions.py
index a318812..c56f8d6 100644
--- a/src/orca/liveregions.py
+++ b/src/orca/liveregions.py
@@ -346,13 +346,13 @@ class LiveRegionManager:
             # Toggle our flag
             self.monitoring = True  
 
-    def outputLiveRegionDescription(self, obj):
+    def generateLiveRegionDescription(self, obj, **args):
         """Used in conjuction with whereAmI to output description and 
         politeness of the given live region object"""
         objectid = self._getObjectId(obj)
         uri = self._script.bookmarks.getURIKey()
 
-        utterances = []
+        results = []
 
         # get the description if there is one.
         for relation in obj.getRelationSet():
@@ -367,7 +367,7 @@ class LiveRegionManager:
                     #
                     description = targetobj.queryText().getText(0, -1)
                     if description.strip() != obj.description.strip():
-                        utterances.append(description)
+                        results.append(description)
                 except NotImplemented:
                     pass
 
@@ -380,11 +380,12 @@ class LiveRegionManager:
 
         # We will only output useful information
         # 
-        if utterances or liveprioritystr != 'none':
+        if results or liveprioritystr != 'none':
             # Translators: output the politeness level
             #
-            utterances.append(_('politeness level %s') %liveprioritystr)
-            speech.speak(utterances)
+            results.append(_('politeness level %s') %liveprioritystr)
+
+        return results
 
     def matchLiveRegion(self, obj):
         """Predicate used to find a live region"""
diff --git a/src/orca/scripts/toolkits/Gecko/Makefile.am b/src/orca/scripts/toolkits/Gecko/Makefile.am
index 2de2e09..44e9962 100644
--- a/src/orca/scripts/toolkits/Gecko/Makefile.am
+++ b/src/orca/scripts/toolkits/Gecko/Makefile.am
@@ -8,8 +8,7 @@ orca_python_PYTHON = \
 	script.py \
 	script_settings.py \
 	speech_generator.py \
-	structural_navigation.py \
-	where_am_i.py
+	structural_navigation.py
 
 orca_pythondir=$(pyexecdir)/orca/scripts/toolkits/Gecko
 
diff --git a/src/orca/scripts/toolkits/Gecko/formatting.py b/src/orca/scripts/toolkits/Gecko/formatting.py
index c02b0cf..83a6493 100644
--- a/src/orca/scripts/toolkits/Gecko/formatting.py
+++ b/src/orca/scripts/toolkits/Gecko/formatting.py
@@ -35,6 +35,18 @@ import orca.formatting
 
 formatting = {
     'speech': {
+        'suffix': {
+            'focused': '[]',
+            'unfocused': 'newNodeLevel + unselectedCell + tutorial',
+            'basicWhereAmI': 'tutorial + description + liveRegionDescription',
+            'detailedWhereAmI' : '[]'
+            },
+        'default': {
+            'focused': '[]',
+            'unfocused': 'labelAndName + allTextSelection + roleName + availability + mnemonic + accelerator',
+            'basicWhereAmI': 'labelAndName + roleName',
+            'detailedWhereAmI' : 'pageSummary'
+            },
         pyatspi.ROLE_ALERT: {
             'unfocused': 'expandedEOCs or (labelAndName + unrelatedLabels)'
             },
diff --git a/src/orca/scripts/toolkits/Gecko/script.py b/src/orca/scripts/toolkits/Gecko/script.py
index 8a8f5b0..570958d 100644
--- a/src/orca/scripts/toolkits/Gecko/script.py
+++ b/src/orca/scripts/toolkits/Gecko/script.py
@@ -65,7 +65,6 @@ import script_settings
 from braille_generator import BrailleGenerator
 from speech_generator import SpeechGenerator
 from formatting import Formatting
-from where_am_i import GeckoWhereAmI
 from bookmarks import GeckoBookmarks
 from structural_navigation import GeckoStructuralNavigation
 
@@ -286,11 +285,6 @@ class Script(default.Script):
             self.savedEnabledSpokenTextAttributes
         settings.allTextAttributes = self.savedAllTextAttributes
 
-    def getWhereAmI(self):
-        """Returns the "where am I" class for this script.
-        """
-        return GeckoWhereAmI(self)
-
     def getBookmarks(self):
         """Returns the "bookmarks" class for this script.
         """
@@ -3874,7 +3868,7 @@ class Script(default.Script):
             #
             if end > childOffset + 1:
                 restOfText = unicodeText[offset:len(unicodeText)]
-                objects.append([obj, childOffset + 1, end, restOfText])                
+                objects.append([obj, childOffset + 1, end, restOfText])
  
         if obj.getRole() in [pyatspi.ROLE_IMAGE, pyatspi.ROLE_TABLE]:
             # Imagemaps that don't have alternative text won't implement
@@ -3942,6 +3936,112 @@ class Script(default.Script):
 
         return lineContents
 
+    def getPageSummary(self, obj, **args):
+        """Returns the quantity of headings, forms, tables, visited links,
+        and unvisited links on the page containing obj.
+        """
+
+        if settings.useCollection:
+            try:
+                summary = self._collectionPageSummary()
+            except:
+                debug.printException(debug.LEVEL_SEVERE)
+                summary = self._iterativePageSummary(obj)
+        else:
+            summary = self._iterativePageSummary(obj)
+
+        return summary
+
+    def _collectionPageSummary(self):
+        """Uses the Collection interface to get the quantity of headings,
+        forms, tables, visited and unvisited links.
+        """
+
+        docframe = self.getDocumentFrame()
+        col = docframe.queryCollection()
+        # We will initialize these after the queryCollection() call in case
+        # Collection is not supported
+        #
+        headings = 0
+        forms = 0
+        tables = 0
+        vlinks = 0
+        uvlinks = 0
+        percentRead = None
+
+        stateset = pyatspi.StateSet()
+        roles = [pyatspi.ROLE_HEADING, pyatspi.ROLE_LINK, pyatspi.ROLE_TABLE,
+                 pyatspi.ROLE_FORM]
+        rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,
+                                   "", col.MATCH_NONE,
+                                   roles, col.MATCH_ANY,
+                                   "", col.MATCH_NONE,
+                                   False)
+
+        matches = col.getMatches(rule, col.SORT_ORDER_CANONICAL, 0, True)
+        col.freeMatchRule(rule)
+        for obj in matches:
+            role = obj.getRole()
+            if role == pyatspi.ROLE_HEADING:
+                headings += 1
+            elif role == pyatspi.ROLE_FORM:
+                forms += 1
+            elif role == pyatspi.ROLE_TABLE \
+                      and not self.isLayoutOnly(obj):
+                tables += 1
+            elif role == pyatspi.ROLE_LINK:
+                if obj.getState().contains(pyatspi.STATE_VISITED):
+                    vlinks += 1
+                else:
+                    uvlinks += 1
+
+        return [headings, forms, tables, vlinks, uvlinks, percentRead]
+
+    def _iterativePageSummary(self, obj):
+        """Reads the quantity of headings, forms, tables, visited and
+        unvisited links.
+        """
+
+        headings = 0
+        forms = 0
+        tables = 0
+        vlinks = 0
+        uvlinks = 0
+        percentRead = None
+        nodetotal = 0
+        obj_index = None
+        currentobj = obj
+
+        # Start at the first object after document frame.
+        #
+        obj = self.getDocumentFrame()[0]
+        while obj:
+            nodetotal += 1
+            if obj == currentobj:
+                obj_index = nodetotal
+            role = obj.getRole()
+            if role == pyatspi.ROLE_HEADING:
+                headings += 1
+            elif role == pyatspi.ROLE_FORM:
+                forms += 1
+            elif role == pyatspi.ROLE_TABLE \
+                      and not self.isLayoutOnly(obj):
+                tables += 1
+            elif role == pyatspi.ROLE_LINK:
+                if obj.getState().contains(pyatspi.STATE_VISITED):
+                    vlinks += 1
+                else:
+                    uvlinks += 1
+
+            obj = self.findNextObject(obj)
+
+        # Calculate the percentage of the document that has been read.
+        #
+        if obj_index:
+            percentRead = int(obj_index*100/nodetotal)
+
+        return [headings, forms, tables, vlinks, uvlinks, percentRead]
+
     def guessLabelFromLine(self, obj):
         """Attempts to guess what the label of an unlabeled form control
         might be by looking at surrounding contents from the same line.
diff --git a/src/orca/scripts/toolkits/Gecko/speech_generator.py b/src/orca/scripts/toolkits/Gecko/speech_generator.py
index a755969..4857632 100644
--- a/src/orca/scripts/toolkits/Gecko/speech_generator.py
+++ b/src/orca/scripts/toolkits/Gecko/speech_generator.py
@@ -110,6 +110,28 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
 
         return result
 
+    def _generateDescription(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.
+        """
+        if args.get('role', obj.getRole()) == pyatspi.ROLE_LINK \
+           and obj.parent.getRole() == pyatspi.ROLE_IMAGE:
+            result = self._generateName(obj, **args)
+            # Translators: The following string is spoken to let the user
+            # know that he/she is on a link within an image map. An image
+            # map is an image/graphic which has been divided into regions.
+            # Each region can be clicked on and has an associated link.
+            # Please see http://en.wikipedia.org/wiki/Imagemap for more
+            # information and examples.
+            #
+            result.append(_("image map link"))
+        else:
+            result = speech_generator.SpeechGenerator.\
+                           _generateDescription(self, obj, **args)
+        return result
+
     def _generateLabel(self, obj, **args):
         result = speech_generator.SpeechGenerator._generateLabel(self,
                                                                  obj,
@@ -204,7 +226,8 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
 
         if not force and self._script.inDocumentContent(obj):
             doNotSpeak.append(pyatspi.ROLE_TABLE_CELL)
-            if not self._script.isAriaWidget(obj):
+            if not self._script.isAriaWidget(obj) \
+               and args.get('formatType', 'unfocused') != 'basicWhereAmI':
                 doNotSpeak.append(pyatspi.ROLE_LIST_ITEM)
                 doNotSpeak.append(pyatspi.ROLE_LIST)
 
@@ -308,6 +331,14 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
         stopRoles = [pyatspi.ROLE_DOCUMENT_FRAME,
                      pyatspi.ROLE_INTERNAL_FRAME]
 
+        # [[[TODO - JD: Right now we're using this method to get the
+        # full context of menu items in whereAmI. It seems to work for
+        # gtk-demo, but here we're getting way too much context. So for
+        # now, add in a check. Later, look for better way.]]]
+        #
+        if args.get('formatType', 'unfocused') == 'basicWhereAmI':
+            stopRoles.append(pyatspi.ROLE_MENU_BAR)
+
         # There are some objects we want to include in the context,
         # but not add their rolenames.
         #
@@ -380,18 +411,101 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
 
             result.extend(newResult)
 
+            # [[[TODO - JD: Right now we're using this method to get the
+            # full context of menu items in whereAmI. It seems to work for
+            # gtk-demo, but here we're getting way too much context. So for
+            # now, add in a check. Later, look for better way.]]]
+            #
+            if args.get('formatType', 'unfocused') == 'basicWhereAmI' \
+               and parent.getRole() == pyatspi.ROLE_COMBO_BOX:
+                break
+
             parent = parent.parent
 
         result.reverse()
 
         return result
 
+    def _generateDefaultButton(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.
+        """
+        if self._script.inDocumentContent(obj) \
+           and not self._script.isAriaWidget(obj):
+            return []
+
+        return speech_generator.SpeechGenerator.\
+                     _generateDefaultButton(self, obj, **args)
+
+    def _generateLiveRegionDescription(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the live region.
+        """
+        return self._script.liveMngr.\
+                    generateLiveRegionDescription(obj, **args)
+
+    def _generatePageSummary(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that summarize the objects found on the page
+        containing obj.
+        """
+        result = []
+        headings, forms, tables, vlinks, uvlinks, percent = \
+            self._script.getPageSummary(obj, **args)
+        if headings:
+            # Translators: Announces the number of headings in the
+            # web page that is currently being displayed.
+            #
+            result.append(ngettext \
+                ('%d heading', '%d headings', headings) % headings)
+        if forms:
+            # Translators: Announces the number of forms in the
+            # web page that is currently being displayed.
+            #
+            result.append(ngettext('%d form', '%d forms', forms) % forms)
+        if tables:
+            # Translators: Announces the number of non-layout tables in the
+            # web page that is currently being displayed.
+            #
+            result.append(ngettext('%d table', '%d tables', tables) % tables)
+        if vlinks:
+            # Translators: Announces the number of visited links in the
+            # web page that is currently being displayed.
+            #
+            result.append(ngettext \
+                ('%d visited link', '%d visited links', vlinks) % vlinks)
+        if uvlinks:
+            # Translators: Announces the number of unvisited links in the
+            # web page that is currently being displayed.
+            #
+            result.append(ngettext \
+                ('%d unvisited link', '%d unvisited links', uvlinks) % uvlinks)
+        if percent is not None:
+            # Translators: Announces the percentage of the document that has
+            # been read.  This is calculated by knowing the index of the
+            # current position divided by the total number of objects on the
+            # page.
+            #
+            result.append(_('%d percent of document read') % percent)
+
+        return result
+
     def generateSpeech(self, obj, **args):
+        result = []
+        # Detailed WhereAmI always overrides role-based output and produces
+        # a page summary when in document content. [[[JD to WDW: What's the
+        # "right" way to do this?]]]
+        #
+        args['oldRole'] = args.get('role')
+        if args.get('formatType', 'unfocused') == 'detailedWhereAmI' \
+           and self._script.inDocumentContent(obj):
+            args['role'] = 'default'
         # ARIA widgets get treated like regular default widgets.
         #
-        result = []
         args['isAria'] = self._script.isAriaWidget(obj)
         result = speech_generator.SpeechGenerator.generateSpeech(
                      self, obj, **args)
         del args['isAria']
+        args['role'] = args['oldRole']
         return result
diff --git a/src/orca/scripts/toolkits/Gecko/where_am_i.py b/src/orca/scripts/toolkits/Gecko/where_am_i.py
deleted file mode 100644
index 8051465..0000000
--- a/src/orca/scripts/toolkits/Gecko/where_am_i.py
+++ /dev/null
@@ -1,281 +0,0 @@
-# Orca
-#
-# Copyright 2005-2009 Sun Microsystems Inc.
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Library General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Library General Public License for more details.
-#
-# You should have received a copy of the GNU Library General Public
-# License along with this library; if not, write to the
-# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
-# Boston MA  02110-1301 USA.
-
-"""Custom script for Gecko toolkit.
-Please refer to the following URL for more information on the AT-SPI
-implementation in Gecko:
-http://developer.mozilla.org/en/docs/Accessibility/ATSPI_Support
-"""
-
-__id__        = "$Id$"
-__version__   = "$Revision$"
-__date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
-__license__   = "LGPL"
-
-import pyatspi
-
-import orca.debug as debug
-import orca.orca_state as orca_state
-import orca.settings as settings
-import orca.speech as speech
-import orca.where_am_I as where_am_I
-
-from orca.orca_i18n import _
-from orca.orca_i18n import ngettext # for ngettext support
-
-########################################################################
-#                                                                      #
-# Custom WhereAmI                                                      #
-#                                                                      #
-########################################################################
-
-class GeckoWhereAmI(where_am_I.WhereAmI):
-    def __init__(self, script):
-        """Gecko specific WhereAmI that will be used to speak information
-        about the current object of interest and will provide additional Gecko
-        specific information.
-        """
-        where_am_I.WhereAmI.__init__(self, script)
-        self._script = script
-
-    def whereAmI(self, obj, basicOnly):
-        """Calls the base class method for basic information and Gecko
-        specific presentation methods for detailed/custom information.
-        """
-        if basicOnly or not self._script.inDocumentContent(obj):
-            where_am_I.WhereAmI.whereAmI(self, obj, basicOnly)
-            self._script.liveMngr.outputLiveRegionDescription(obj)
-        else:
-            if settings.useCollection:
-                try:
-                    self._collectionPageSummary()
-                except:
-                    debug.printException(debug.LEVEL_SEVERE)
-                    self._iterativePageSummary(obj)
-            else:
-                self._iterativePageSummary(obj)
-
-    def _speakDefaultButton(self, obj):
-        """Speaks the default button in a dialog.
-
-        Arguments:
-        - obj: the dialog box for which the default button should be obtained
-        """
-
-        if not (self._script.inDocumentContent(orca_state.locusOfFocus) \
-                and not self._script.isAriaWidget(orca_state.locusOfFocus)):
-            where_am_I.WhereAmI._speakDefaultButton(self, obj)
-
-    # pylint: disable-msg=W0142
-
-    def _getSpeechForRoleName(self, obj, **args):
-        """Returns the rolename to be spoken for the object. Overridden
-        here because there are times when we do not want the speech
-        generator returning a role to speak (e.g. navigating within
-        a document), but other times when we would (e.g. during a
-        whereAmI).
-        """
-        role = args.get('role', None)
-        objRole = obj.getRole()
-        if not role and objRole in [pyatspi.ROLE_DOCUMENT_FRAME,
-                                    pyatspi.ROLE_FORM,
-                                    pyatspi.ROLE_LIST_ITEM,
-                                    pyatspi.ROLE_LIST,
-                                    pyatspi.ROLE_PARAGRAPH,
-                                    pyatspi.ROLE_SECTION,
-                                    pyatspi.ROLE_TABLE_CELL]:
-            role = objRole
-        if role:
-            args['role'] = role
-        return where_am_I.WhereAmI._getSpeechForRoleName(self, obj, **args)
-
-    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 not name and obj.getRole() == pyatspi.ROLE_LIST_ITEM:
-                name = self._script.expandEOCs(obj)
-
-        if name and name != "None":
-            text = name.strip()
-        debug.println(self._debugLevel, "%s name=<%s>" % (obj.getRole(), text))
-
-        return text
-
-    def _speakObjDescription(self, obj):
-        """Speaks the object's description if it is not the same as the
-        object's name or label. Overridden here because Gecko tacks on
-        the tag associated with an imagemap in the object's description.
-        We don't want to speak that information as-is.
-
-        Arguments:
-        - obj: the accessible whose description we might wish to speak
-        """
-
-        if not (obj.getRole() == pyatspi.ROLE_LINK \
-                and obj.parent.getRole() == pyatspi.ROLE_IMAGE):
-            where_am_I.WhereAmI._speakObjDescription(self, obj)
-        else:
-            name = self._getObjName(obj)
-            if name:
-                speech.speak(name)
-            # Translators: The following string is spoken to let the user
-            # know that he/she is on a link within an image map. An image
-            # map is an image/graphic which has been divided into regions.
-            # Each region can be clicked on and has an associated link.
-            # Please see http://en.wikipedia.org/wiki/Imagemap for more
-            # information and examples.
-            #
-            speech.speak(_("image map link"))
-
-    def _collectionPageSummary(self):
-        """Uses the Collection interface to get the quantity of headings,
-        forms, tables, visited and unvisited links.
-        """
-        docframe = self._script.getDocumentFrame()
-        col = docframe.queryCollection()
-        # We will initialize these after the queryCollection() call in case
-        # Collection is not supported
-        headings = 0
-        forms = 0
-        tables = 0
-        vlinks = 0
-        uvlinks = 0
-
-        stateset = pyatspi.StateSet()
-        roles = [pyatspi.ROLE_HEADING, pyatspi.ROLE_LINK, pyatspi.ROLE_TABLE,
-                 pyatspi.ROLE_FORM]
-        rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,
-                                   "", col.MATCH_NONE,
-                                   roles, col.MATCH_ANY,
-                                   "", col.MATCH_NONE,
-                                   False)
-
-        matches = col.getMatches(rule, col.SORT_ORDER_CANONICAL, 0, True)
-
-        col.freeMatchRule(rule)
-        for obj in matches:
-            role = obj.getRole()
-            if role == pyatspi.ROLE_HEADING:
-                headings += 1
-            elif role == pyatspi.ROLE_FORM:
-                forms += 1
-            elif role == pyatspi.ROLE_TABLE \
-                      and not self._script.isLayoutOnly(obj):
-                tables += 1
-            elif role == pyatspi.ROLE_LINK:
-                if obj.getState().contains(pyatspi.STATE_VISITED):
-                    vlinks += 1
-                else:
-                    uvlinks += 1
-
-        self._outputPageSummary(headings, forms, tables, vlinks, uvlinks, None)
-
-    def _iterativePageSummary(self, obj):
-        """Reads the quantity of headings, forms, tables, visited and
-        unvisited links.
-        """
-        headings = 0
-        forms = 0
-        tables = 0
-        vlinks = 0
-        uvlinks = 0
-        nodetotal = 0
-        obj_index = None
-        currentobj = obj
-
-        # start at the first object after document frame
-        obj = self._script.getDocumentFrame()[0]
-        while obj:
-            nodetotal += 1
-            if obj == currentobj:
-                obj_index = nodetotal
-            role = obj.getRole()
-            if role == pyatspi.ROLE_HEADING:
-                headings += 1
-            elif role == pyatspi.ROLE_FORM:
-                forms += 1
-            elif role == pyatspi.ROLE_TABLE \
-                      and not self._script.isLayoutOnly(obj):
-                tables += 1
-            elif role == pyatspi.ROLE_LINK:
-                if obj.getState().contains(pyatspi.STATE_VISITED):
-                    vlinks += 1
-                else:
-                    uvlinks += 1
-
-            obj = self._script.findNextObject(obj)
-
-        # Calculate the percentage of the document that has been read.
-        if obj_index:
-            percentread = int(obj_index*100/nodetotal)
-        else:
-            percentread = None
-
-        self._outputPageSummary(headings, forms, tables,
-                               vlinks, uvlinks, percentread)
-
-    def _outputPageSummary(self, headings, forms, tables,
-                                 vlinks, uvlinks, percent):
-
-        utterances = []
-        if headings:
-            # Translators: Announces the number of headings in the
-            # web page that is currently being displayed.
-            #
-            utterances.append(ngettext \
-                 ('%d heading', '%d headings', headings) %headings)
-        if forms:
-            # Translators: Announces the number of forms in the
-            # web page that is currently being displayed.
-            #
-            utterances.append(ngettext \
-                 ('%d form', '%d forms', forms) %forms)
-        if tables:
-            # Translators: Announces the number of non-layout tables in the
-            # web page that is currently being displayed.
-            #
-            utterances.append(ngettext \
-                 ('%d table', '%d tables', tables) %tables)
-        if vlinks:
-            # Translators: Announces the number of visited links in the
-            # web page that is currently being displayed.
-            #
-            utterances.append(ngettext \
-                 ('%d visited link', '%d visited links', vlinks) %vlinks)
-        if uvlinks:
-            # Translators: Announces the number of unvisited links in the
-            # web page that is currently being displayed.
-            #
-            utterances.append(ngettext \
-                 ('%d unvisited link', '%d unvisited links', uvlinks) %uvlinks)
-        if percent is not None:
-            # Translators: Announces the percentage of the document that has
-            # been read.  This is calculated by knowing the index of the
-            # current position divided by the total number of objects on the
-            # page.
-            #
-            utterances.append(_('%d percent of document read') %percent)
-
-        speech.speak(utterances)
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index a12e1bd..1aaebd5 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -614,6 +614,8 @@ class SpeechGenerator:
         result = []
         sizeString = ""
         uri = self._script.getURI(obj)
+        if not uri:
+            return result
         try:
             x = urllib2.urlopen(uri)
             try:
@@ -1496,12 +1498,11 @@ class SpeechGenerator:
                 while parent and (parent.parent != parent):
                     if parent.getRole() in [pyatspi.ROLE_PANEL,
                                             pyatspi.ROLE_FILLER]:
-                        label = self._script.getDisplayedText(parent)
+                        label = self._generateLabelAndName(parent)
                         if label:
-                            result.append(label)
+                            result.extend(label)
                             break
                     parent = parent.parent
-
         return result
 
     def _generateNewRadioButtonGroup(self, obj, **args):
@@ -1774,8 +1775,8 @@ class SpeechGenerator:
                                             [pyatspi.ROLE_TOOL_BAR],
                                             [pyatspi.ROLE_FRAME])
         if ancestor:
-            result.append(self._generateLabelAndName(ancestor))
-            result.append(self._generateRoleName(ancestor))
+            result.extend(self._generateLabelAndName(ancestor))
+            result.extend(self._generateRoleName(ancestor))
         return result
 
     def _generatePositionInGroup(self, obj, **args):
@@ -1821,12 +1822,19 @@ class SpeechGenerator:
         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
+        elif role == pyatspi.ROLE_LIST_ITEM:
+            parent = obj.parent
+            for relation in obj.getRelationSet():
+                if relation.getRelationType() == \
+                        pyatspi.RELATION_NODE_CHILD_OF:
+                    parent = relation.getTarget(0)
+                    break
+            obj = parent
 
         # We want to return the position relative to this hierarchical
         # level and not the entire list.  If the object in question
diff --git a/test/keystrokes/firefox/codetalks_tree.py b/test/keystrokes/firefox/codetalks_tree.py
index 87f775e..8e39b71 100644
--- a/test/keystrokes/firefox/codetalks_tree.py
+++ b/test/keystrokes/firefox/codetalks_tree.py
@@ -65,7 +65,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  ' Fruits'",
      "     VISIBLE:  ' Fruits', cursor=1",
-     "SPEECH OUTPUT: 'Fruits list item Fruits collapsed item 1 of 2 tree level 1'"]))
+     "SPEECH OUTPUT: 'Fruits list item Fruits item 1 of 2 collapsed tree level 1'"]))
 
 ########################################################################
 # Right Arrow to expand fruits.
@@ -90,7 +90,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  ' Fruits'",
      "     VISIBLE:  ' Fruits', cursor=1",
-     "SPEECH OUTPUT: 'Fruits list item Fruits expanded item 1 of 2 tree level 1'"]))
+     "SPEECH OUTPUT: 'Fruits list item Fruits item 1 of 2 expanded tree level 1'"]))
 
 ########################################################################
 # Close the demo
diff --git a/test/keystrokes/firefox/dojo_tree.py b/test/keystrokes/firefox/dojo_tree.py
index bc11932..fa006d9 100644
--- a/test/keystrokes/firefox/dojo_tree.py
+++ b/test/keystrokes/firefox/dojo_tree.py
@@ -60,9 +60,10 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
 sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
-    ["BRAILLE LINE:  'Africa ListItem'",
+    ["BUG? - Not speaking the item count",
+     "BRAILLE LINE:  'Africa ListItem'",
      "     VISIBLE:  'Africa ListItem', cursor=1",
-     "SPEECH OUTPUT: 'list item Africa collapsed item 1 of 6 tree level 2'"]))
+     "SPEECH OUTPUT: 'list item Africa collapsed tree level 2'"]))
 
 ########################################################################
 # Use arrows to expand/collapse/navigate tree.  
diff --git a/test/keystrokes/firefox/moz_slider.py b/test/keystrokes/firefox/moz_slider.py
index 55d1a2b..ff09fcd 100644
--- a/test/keystrokes/firefox/moz_slider.py
+++ b/test/keystrokes/firefox/moz_slider.py
@@ -43,10 +43,11 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
 sequence.append(utils.AssertPresentationAction(
-    "basic whereAmI", 
-    ["BRAILLE LINE:  '10% Slider'",
+    "basic whereAmI",
+    ["BUG? - We used to present '10.0 10 percent '. But there is not any text displayed for the current value. What is the desired output?",
+     "BRAILLE LINE:  '10% Slider'",
      "     VISIBLE:  '10% Slider', cursor=1",
-     "SPEECH OUTPUT: 'slider 10.0 10 percent '"]))
+     "SPEECH OUTPUT: 'slider 10% 10 percent. '"]))
 
 ########################################################################
 # Move the slider several times.  The following will be presented for each.
diff --git a/test/keystrokes/firefox/moz_tabpanel.py b/test/keystrokes/firefox/moz_tabpanel.py
index 8a24843..301b8c8 100644
--- a/test/keystrokes/firefox/moz_tabpanel.py
+++ b/test/keystrokes/firefox/moz_tabpanel.py
@@ -40,7 +40,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  'Tab Zero Page Tab One Page Tab Two Page Tab Three Page Tab Four Page'",
      "     VISIBLE:  'Tab Zero Page Tab One Page Tab T', cursor=1",
-     "SPEECH OUTPUT: 'tab list Tab Zero page item 1 of 5 '"]))
+     "SPEECH OUTPUT: 'tab list Tab Zero page item 1 of 5'"]))
 
 ########################################################################
 # Move to tab 2.
diff --git a/test/keystrokes/firefox/uiuc_slider.py b/test/keystrokes/firefox/uiuc_slider.py
index 2e830f3..0b67f7d 100644
--- a/test/keystrokes/firefox/uiuc_slider.py
+++ b/test/keystrokes/firefox/uiuc_slider.py
@@ -46,7 +46,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  'Slider Control 1 50 Slider'",
      "     VISIBLE:  'Slider Control 1 50 Slider', cursor=1",
-     "SPEECH OUTPUT: 'Slider Control 1 slider 50.0 50 percent '"]))
+     "SPEECH OUTPUT: 'Slider Control 1 slider 50 50 percent. '"]))
     
 ########################################################################
 # Increment slider several times
diff --git a/test/keystrokes/firefox/uiuc_tree.py b/test/keystrokes/firefox/uiuc_tree.py
index 0dbb552..8d7e69e 100644
--- a/test/keystrokes/firefox/uiuc_tree.py
+++ b/test/keystrokes/firefox/uiuc_tree.py
@@ -51,7 +51,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  'Fruits ListItem'",
      "     VISIBLE:  'Fruits ListItem', cursor=1",
-     "SPEECH OUTPUT: 'list item Fruits expanded item 1 of 2 tree level 1'"]))
+     "SPEECH OUTPUT: 'list item Fruits item 1 of 2 expanded tree level 1'"]))
 
 ########################################################################
 # Navigate the tree using the arrows.  
diff --git a/test/keystrokes/firefox/xul_role_accel_label.py b/test/keystrokes/firefox/xul_role_accel_label.py
index 2ea4ff1..fe4bac0 100755
--- a/test/keystrokes/firefox/xul_role_accel_label.py
+++ b/test/keystrokes/firefox/xul_role_accel_label.py
@@ -70,8 +70,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar Open File...\(Control O\)'",
      "     VISIBLE:  'Open File...(Control O)', cursor=1",
-     "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: 'File menu Open Fileâ?¦ Control O item 4 of [0-9]+ '"]))
+     "SPEECH OUTPUT: 'tool bar File menu Open Fileâ?¦ Control O item 4 of [0-9]+'"]))
 
 ########################################################################
 # Dismiss the menu by pressing Escape and wait for the location bar
diff --git a/test/keystrokes/firefox/xul_role_check_menu_item.py b/test/keystrokes/firefox/xul_role_check_menu_item.py
index 02a80f7..4ec0cb1 100755
--- a/test/keystrokes/firefox/xul_role_check_menu_item.py
+++ b/test/keystrokes/firefox/xul_role_check_menu_item.py
@@ -49,8 +49,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar < > Full Screen CheckItem\(F11\)'",
      "     VISIBLE:  '< > Full Screen CheckItem(F11)', cursor=1",
-     "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: 'View menu Full Screen check item not checked F11 item 10 of 10 '"]))
+     "SPEECH OUTPUT: 'tool bar View menu Full Screen check item not checked F11 item 10 of 10'"]))
 
 ########################################################################
 # Dismiss the menu by pressing Escape and wait for the location bar
diff --git a/test/keystrokes/firefox/xul_role_combo_box.py b/test/keystrokes/firefox/xul_role_combo_box.py
index 3d48d94..3c0945c 100644
--- a/test/keystrokes/firefox/xul_role_combo_box.py
+++ b/test/keystrokes/firefox/xul_role_combo_box.py
@@ -159,9 +159,10 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
 sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
-    ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel  ComboShow a blank pageWhen " + utils.firefoxAppNames + " starts:  Show a blank page'",
+    ["BUG? - We claim this is item 1 of 1. This is how it was before the refactor as well.",
+     "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel  ComboShow a blank pageWhen " + utils.firefoxAppNames + " starts:  Show a blank page'",
      "     VISIBLE:  'Show a blank page', cursor=1",
-     "SPEECH OUTPUT: 'Show a blank page combo box Show a blank page  item 1 of 1 '"]))
+     "SPEECH OUTPUT: 'When " + utils.firefoxAppNames + " starts: combo box Show a blank page item 1 of 1'"]))
 
 ########################################################################
 # Press Shift+Tab to move back to the Main list item.
diff --git a/test/keystrokes/firefox/xul_role_page_tab.py b/test/keystrokes/firefox/xul_role_page_tab.py
index 81c1fc2..f8bf441 100755
--- a/test/keystrokes/firefox/xul_role_page_tab.py
+++ b/test/keystrokes/firefox/xul_role_page_tab.py
@@ -33,7 +33,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog General Page'",
      "     VISIBLE:  'General Page', cursor=1",
-     "SPEECH OUTPUT: 'tab list General page item 1 of [0-9]+ '"]))
+     "SPEECH OUTPUT: 'tab list General page item 1 of [0-9]+'"]))
 
 ########################################################################
 # Right Arrow to move to the second page tab.  
@@ -56,7 +56,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog Page Setup Page'",
      "     VISIBLE:  'Page Setup Page', cursor=1",
-     "SPEECH OUTPUT: 'tab list Page Setup page item 2 of [0-9]+ '"]))
+     "SPEECH OUTPUT: 'tab list Page Setup page item 2 of [0-9]+'"]))
 
 ########################################################################
 # Left Arrow to move to the first page tab.  
diff --git a/test/keystrokes/firefox/xul_role_radio_menu_item.py b/test/keystrokes/firefox/xul_role_radio_menu_item.py
index 783d63d..7848284 100755
--- a/test/keystrokes/firefox/xul_role_radio_menu_item.py
+++ b/test/keystrokes/firefox/xul_role_radio_menu_item.py
@@ -49,8 +49,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar View Menu & y No Style RadioItem'",
      "     VISIBLE:  '& y No Style RadioItem', cursor=1",
-     "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: 'Page Style menu No Style radio menu item not selected  item 1 of 2 '"]))
+     "SPEECH OUTPUT: 'tool bar View menu Page Style menu No Style radio menu item not selected item 1 of 2'"]))
 
 ########################################################################
 # Down Arrow to the "Basic Page Style" radio menu item.
@@ -73,8 +72,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar View Menu &=y Basic Page Style RadioItem'",
      "     VISIBLE:  '&=y Basic Page Style RadioItem', cursor=1",
-     "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: 'Page Style menu Basic Page Style radio menu item selected  item 2 of 2 '"]))
+     "SPEECH OUTPUT: 'tool bar View menu Page Style menu Basic Page Style radio menu item selected item 2 of 2'"]))
 
 ########################################################################
 # Dismiss the "Page Style" menu by pressing Escape.
diff --git a/test/keystrokes/firefox/xul_role_tree.py b/test/keystrokes/firefox/xul_role_tree.py
index d15cb3c..2bfac99 100644
--- a/test/keystrokes/firefox/xul_role_tree.py
+++ b/test/keystrokes/firefox/xul_role_tree.py
@@ -181,7 +181,7 @@ sequence.append(utils.AssertPresentationAction(
     "Tab back to tree table",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame ScrollPane TreeTable Name ColumnHeader Bookmarks Toolbar   TREE LEVEL 1'",
      "     VISIBLE:  'Bookmarks Toolbar   TREE LEVEL 1', cursor=1",
-     "SPEECH OUTPUT: 'Name column header Bookmarks Toolbar blank blank not selected'"]))
+     "SPEECH OUTPUT: 'Name column header Bookmarks Toolbar not selected'"]))
 
 ########################################################################
 # Now that the Places Manager is back to its pre-explored state,
diff --git a/test/keystrokes/gtk-demo/role_radio_button.py b/test/keystrokes/gtk-demo/role_radio_button.py
index 5139c15..ce94f42 100644
--- a/test/keystrokes/gtk-demo/role_radio_button.py
+++ b/test/keystrokes/gtk-demo/role_radio_button.py
@@ -47,7 +47,7 @@ sequence.append(utils.AssertPresentationAction(
     "All Pages radio button Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler &=y All Pages RadioButton'",
      "     VISIBLE:  '&=y All Pages RadioButton', cursor=1",
-     "SPEECH OUTPUT: 'General page Range All Pages radio button selected item 1 of 3 Alt a'"]))
+     "SPEECH OUTPUT: 'Range All Pages radio button selected item 1 of 3 Alt a'"]))
 
 ########################################################################
 # Down arrow to the "Pages:" radio button.
@@ -80,7 +80,7 @@ sequence.append(utils.AssertPresentationAction(
     "Range radio button Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler &=y Pages: RadioButton'",
      "     VISIBLE:  '&=y Pages: RadioButton', cursor=1",
-     "SPEECH OUTPUT: 'General page Range Pages: radio button selected item 3 of 3 Alt e'"]))
+     "SPEECH OUTPUT: 'Range Pages: radio button selected item 3 of 3 Alt e'"]))
 
 ########################################################################
 # Put everything back and close the demo.
diff --git a/test/keystrokes/gtk-demo/role_toolbar.py b/test/keystrokes/gtk-demo/role_toolbar.py
index 22a031e..7e96179 100644
--- a/test/keystrokes/gtk-demo/role_toolbar.py
+++ b/test/keystrokes/gtk-demo/role_toolbar.py
@@ -54,8 +54,7 @@ sequence.append(utils.AssertPresentationAction(
     "Open button Where Am I",
     ["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: 'tool bar Open button'"]))
 
 ########################################################################
 # Arrow Right to the triangular button next to the "Open" button.
@@ -79,8 +78,7 @@ sequence.append(utils.AssertPresentationAction(
     "Open triangle toggle button Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame ToolBar & y ToggleButton'",
      "     VISIBLE:  '& y ToggleButton', cursor=1",
-     "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: 'toggle button not pressed'"]))
+     "SPEECH OUTPUT: 'tool bar toggle button not pressed'"]))
 
 ########################################################################
 # Arrow Right to the the "Quit" button.
@@ -104,8 +102,7 @@ sequence.append(utils.AssertPresentationAction(
     "Quit button Where Am I",
     ["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: 'tool bar Quit button'"]))
 
 ########################################################################
 # Close the Application Window demo window



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