[orca/570658-whereami] Work on the Gecko whereAmI refactor.
- From: Joanmarie Diggs <joanied src gnome org>
- To: svn-commits-list gnome org
- Subject: [orca/570658-whereami] Work on the Gecko whereAmI refactor.
- Date: Sun, 7 Jun 2009 22:14:48 -0400 (EDT)
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]