[orca/570658] Begin porting Gecko's speech generator
- From: William Walker <wwalker src gnome org>
- To: svn-commits-list gnome org
- Subject: [orca/570658] Begin porting Gecko's speech generator
- Date: Tue, 19 May 2009 16:28:09 -0400 (EDT)
commit a3abebf03b0d72a2c15d9e6cca0798e487811185
Author: Willie Walker <william walker sun com>
Date: Tue May 19 16:27:30 2009 -0400
Begin porting Gecko's speech generator
---
src/orca/scripts/toolkits/Gecko/Makefile.am | 3 +-
src/orca/scripts/toolkits/Gecko/formatting.py | 64 ++
src/orca/scripts/toolkits/Gecko/script.py | 4 +-
.../scripts/toolkits/Gecko/speech_generator.py | 814 +++++---------------
src/orca/speechgenerator.py | 18 +-
5 files changed, 261 insertions(+), 642 deletions(-)
diff --git a/src/orca/scripts/toolkits/Gecko/Makefile.am b/src/orca/scripts/toolkits/Gecko/Makefile.am
index af9a261..2de2e09 100644
--- a/src/orca/scripts/toolkits/Gecko/Makefile.am
+++ b/src/orca/scripts/toolkits/Gecko/Makefile.am
@@ -1,9 +1,10 @@
orca_pathdir=$(pyexecdir)
orca_python_PYTHON = \
+ __init__.py \
bookmarks.py \
braille_generator.py \
- __init__.py \
+ formatting.py \
script.py \
script_settings.py \
speech_generator.py \
diff --git a/src/orca/scripts/toolkits/Gecko/formatting.py b/src/orca/scripts/toolkits/Gecko/formatting.py
new file mode 100644
index 0000000..2fe7b04
--- /dev/null
+++ b/src/orca/scripts/toolkits/Gecko/formatting.py
@@ -0,0 +1,64 @@
+# Orca
+#
+# Copyright 2006-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 formatting for Gecko."""
+
+__id__ = "$Id$"
+__version__ = "$Revision$"
+__date__ = "$Date$"
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
+__license__ = "LGPL"
+
+import pyatspi
+
+import orca.formatting
+
+formatting = {
+ 'speech': {
+ pyatspi.ROLE_ALERT: {
+ 'unfocused': 'expandedEOCs or (labelAndName + unrelatedLabels)'
+ },
+ pyatspi.ROLE_DOCUMENT_FRAME: {
+ 'unfocused': 'name + roleName'
+ },
+ pyatspi.ROLE_LIST: {
+ 'unfocused': 'labelOrName + multiselectableState + numberOfChildren'
+ },
+ }
+}
+
+class Formatting(orca.formatting.Formatting):
+
+ # pylint: disable-msg=W0142
+
+ def __init__(self, script):
+ orca.formatting.Formatting.__init__(self, script)
+ self.update(formatting)
+ # This is a copy of the default formatting, which we will
+ # use for ARIA widgets.
+ #
+ self._defaultFormatting = orca.formatting.Formatting(script)
+
+ def getFormat(self, dictType, **args):
+ # ARIA widgets get treated like regular default widgets.
+ #
+ if args.get('isAria', False):
+ return self._defaultFormatting.getFormat(dictType, **args)
+ else:
+ return orca.formatting.Formatting.getFormat(self, dictType, **args)
diff --git a/src/orca/scripts/toolkits/Gecko/script.py b/src/orca/scripts/toolkits/Gecko/script.py
index 0f688eb..92dc1af 100644
--- a/src/orca/scripts/toolkits/Gecko/script.py
+++ b/src/orca/scripts/toolkits/Gecko/script.py
@@ -5425,7 +5425,7 @@ class Script(default.Script):
utterance = [string]
if speakRole and not role in doNotSpeakRoles:
utterance.extend(\
- self.speechGenerator.getSpeechForObjectRole(obj))
+ self.speechGenerator.getRoleName(obj))
# If the object is a heading, or is contained within a heading,
# speak that role information at the end of the object.
@@ -5442,7 +5442,7 @@ class Script(default.Script):
if heading:
utterance.extend(\
- self.speechGenerator.getSpeechForObjectRole(heading))
+ self.speechGenerator.getRoleName(heading))
for item in utterance:
utterances.append([item, self.getACSS(obj, item)])
diff --git a/src/orca/scripts/toolkits/Gecko/speech_generator.py b/src/orca/scripts/toolkits/Gecko/speech_generator.py
index c3c8bd9..e35cbdc 100644
--- a/src/orca/scripts/toolkits/Gecko/speech_generator.py
+++ b/src/orca/scripts/toolkits/Gecko/speech_generator.py
@@ -1,6 +1,6 @@
# Orca
#
-# Copyright 2005-2008 Sun Microsystems Inc.
+# 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
@@ -26,18 +26,16 @@ http://developer.mozilla.org/en/docs/Accessibility/ATSPI_Support
__id__ = "$Id$"
__version__ = "$Revision$"
__date__ = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
__license__ = "LGPL"
import pyatspi
import orca.rolenames as rolenames
-import orca.settings as settings
import orca.speechgenerator as speechgenerator
from orca.orca_i18n import _
from orca.orca_i18n import ngettext # for ngettext support
-from orca.orca_i18n import C_ # to provide qualified translatable strings
########################################################################
# #
@@ -49,21 +47,93 @@ class SpeechGenerator(speechgenerator.SpeechGenerator):
"""Provides a speech generator specific to Gecko.
"""
+ # pylint: disable-msg=W0142
+
def __init__(self, script):
speechgenerator.SpeechGenerator.__init__(self, script)
- self.speechGenerators[pyatspi.ROLE_DOCUMENT_FRAME] = \
- self._getSpeechForDocumentFrame
- self.speechGenerators[pyatspi.ROLE_ENTRY] = \
- self._getSpeechForText
- self.speechGenerators[pyatspi.ROLE_LINK] = \
- self._getSpeechForLink
- self.speechGenerators[pyatspi.ROLE_LIST_ITEM] = \
- self._getSpeechForListItem
- self.speechGenerators[pyatspi.ROLE_SLIDER] = \
- self._getSpeechForSlider
-
- def getSpeechForObjectRole(self, obj, role=None):
+
+ def _getName(self, obj, **args):
+ result = speechgenerator.SpeechGenerator._getName(self, obj, **args)
+ role = args.get('role', obj.getRole())
+ if role == pyatspi.ROLE_LINK:
+ # Handle empty alt tags.
+ #
+ if result and len(result[0].strip()):
+ pass
+ else:
+ # If there's no text for the link, expose part of the
+ # URI to the user.
+ #
+ basename = self._script.getLinkBasename(obj)
+ if basename:
+ result.append(basename)
+ return result
+
+ def _getLabel(self, obj, **args):
+ result = speechgenerator.SpeechGenerator._getLabel(self, obj, **args)
+ role = args.get('role', obj.getRole())
+ # We'll attempt to guess the label under some circumstances.
+ #
+ if not len(result) \
+ and role in [pyatspi.ROLE_CHECK_BOX,
+ pyatspi.ROLE_COMBO_BOX,
+ pyatspi.ROLE_ENTRY,
+ pyatspi.ROLE_LIST,
+ pyatspi.ROLE_PARAGRAPH,
+ pyatspi.ROLE_PASSWORD_TEXT,
+ pyatspi.ROLE_RADIO_BUTTON,
+ pyatspi.ROLE_TEXT] \
+ and self._script.inDocumentContent() \
+ and not self._script.isAriaWidget(obj):
+ label = self._script.guessTheLabel(obj)
+ if label:
+ result.append(label)
+ return result
+
+ def _getLabelAndName(self, obj, **args):
+ result = []
+ role = args.get('role', obj.getRole())
+ # For radio buttons, the label is handled as a context and we
+ # assume we don't have to guess it. If we need to guess it,
+ # we need to add it to utterances.
+ #
+ if role == pyatspi.ROLE_RADIO_BUTTON \
+ and self._script.getDisplayedLabel(obj):
+ pass
+ else:
+ result.extend(speechgenerator.SpeechGenerator._getLabelAndName(
+ self, obj, **args))
+ return result
+
+ def _getLabelOrName(self, obj, **args):
+ result = []
+ if obj.parent.getRole() == pyatspi.ROLE_AUTOCOMPLETE:
+ # This is the main difference between this class and the default
+ # class - we'll give this thing a name here, and we'll make it
+ # be the name of the autocomplete.
+ #
+ result.extend(self._getLabelOrName(obj.parent, **args))
+ else:
+ result.extend(speechgenerator.SpeechGenerator._getLabelOrName(
+ self, obj, **args))
+
+ def _getRoleName(self, obj, **args):
"""Prevents some roles from being spoken."""
+ result = []
+ role = args.get('role', obj.getRole())
+
+ # Saying "menu item" for a combo box can confuse users. Therefore,
+ # speak the combo box role instead. Also, only do it if the menu
+ # item is not focused (if the menu item is focused, it means we're
+ # navigating in the combo box)
+ #
+ if not obj.getState().contains(pyatspi.STATE_FOCUSED):
+ comboBox = self._script.getAncestor(obj,
+ [pyatspi.ROLE_COMBO_BOX],
+ [pyatspi.ROLE_DOCUMENT_FRAME])
+ if comboBox:
+ return self._getRoleName(comboBox, **args)
+
doNotSpeak = [pyatspi.ROLE_FORM,
pyatspi.ROLE_LABEL,
pyatspi.ROLE_MENU_ITEM,
@@ -77,9 +147,8 @@ class SpeechGenerator(speechgenerator.SpeechGenerator):
doNotSpeak.append(pyatspi.ROLE_LIST_ITEM)
doNotSpeak.append(pyatspi.ROLE_LIST)
- utterances = []
- if role or not obj.getRole() in doNotSpeak:
- if obj.getRole() == pyatspi.ROLE_HEADING:
+ if not (role in doNotSpeak):
+ if role == pyatspi.ROLE_HEADING:
level = self._script.getHeadingLevel(obj)
if level:
# Translators: the %(level)d is in reference to a heading
@@ -87,594 +156,99 @@ class SpeechGenerator(speechgenerator.SpeechGenerator):
# and the %(role)s is in reference to a previously
# translated rolename for the heading.
#
- utterances.append(_("%(role)s level %(level)d") % {
+ result.append(_("%(role)s level %(level)d") % {
'role': rolenames.getSpeechForRoleName(obj, role),
'level': level})
else:
- utterances.append(rolenames.getSpeechForRoleName(obj, role))
+ result.append(rolenames.getSpeechForRoleName(obj, role))
else:
- utterances.append(rolenames.getSpeechForRoleName(obj, role))
-
- return utterances
+ result.append(rolenames.getSpeechForRoleName(obj, role))
- def _getSpeechForAlert(self, obj, already_focused):
- """Gets the speech for an alert. What we do here is first try
- to see if the alert contains text via embedded object characters.
- If it does, we speak that text. If it doesn't, we defer to the
- super class. The prototype alert we're shooting for is the one
- from http://bugzilla.gnome.org/show_bug.cgi?id=570551
+ # If this is a link with a child which is an image, we want
+ # to indicate that.
+ #
+ if role == pyatspi.ROLE_LINK \
+ and obj.childCount and obj[0].getRole() == pyatspi.ROLE_IMAGE:
+ result.extend(self._getRoleName(obj[0], **args))
- Arguments:
- - obj: an Accessible
- - already_focused: False if object just received focus
+ return result
- Returns a list of utterances to be spoken for the object.
- """
+ def getRoleName(self, obj):
+ return self._getRoleName(obj)
+ def _getExpandedEOCs(self, obj, **args):
+ """Returns the expanded embedded object characters for an object."""
+ result = []
text = self._script.expandEOCs(obj)
if text:
- return [text]
- else:
- return speechgenerator.SpeechGenerator.\
- _getSpeechForAlert(self, obj, already_focused)
-
- def _getSpeechForDocumentFrame(self, obj, already_focused):
- """Gets the speech for a document frame.
-
- Arguments:
- - obj: an Accessible
- - already_focused: False if object just received focus
-
- Returns a list of utterances to be spoken for the object.
- """
-
- utterances = []
-
- name = obj.name
- if name and len(name):
- utterances.append(name)
- utterances.extend(self.getSpeechForObjectRole(obj))
-
- self._debugGenerator("Gecko._getSpeechForDocumentFrame",
- obj,
- already_focused,
- utterances)
-
- return utterances
-
- def _getSpeechForText(self, obj, already_focused):
- """Gets the speech for an autocomplete box.
-
- Arguments:
- - obj: an Accessible
- - already_focused: False if object just received focus
-
- Returns a list of utterances to be spoken for the object.
- """
-
- # Treat ARIA widgets like default.py widgets
- #
- if self._script.isAriaWidget(obj):
- return speechgenerator.SpeechGenerator.\
- _getSpeechForText(self, obj, already_focused)
-
- utterances = []
- parent = obj.parent
- if parent.getRole() == pyatspi.ROLE_AUTOCOMPLETE:
- # This is the main difference between this class and the default
- # class - we'll give this thing a name here, and we'll make it
- # be the name of the autocomplete.
- #
- label = self._script.getDisplayedLabel(parent)
- if not label or not len(label):
- label = parent.name
- utterances.append(label)
- elif obj.getRole() in [pyatspi.ROLE_ENTRY,
- pyatspi.ROLE_PASSWORD_TEXT] \
- and self._script.inDocumentContent():
- # This is a form field in web content. If we don't get a label,
- # we'll try to guess what text on the page is functioning as
- # the label.
+ result.append(text)
+ return result
+
+ def _getDisplayedText(self, obj, **args):
+ result = []
+ if obj.getRole() == pyatspi.ROLE_COMBO_BOX:
+ # With Gecko, a combo box has a menu as a child. The text being
+ # displayed for the combo box can be obtained via the selected
+ # menu item.
#
- label = self._script.getDisplayedLabel(obj)
- if not label or not len(label):
- label = self._script.guessTheLabel(obj)
- if label:
- utterances.append(label)
- else:
- return speechgenerator.SpeechGenerator._getSpeechForText(
- self, obj, already_focused)
-
- if settings.presentReadOnlyText \
- and self._script.isReadOnlyTextArea(obj):
- utterances.append(settings.speechReadOnlyString)
-
- utterances.extend(self.getSpeechForObjectRole(obj))
-
- [text, caretOffset, startOffset] = self._script.getTextLineAtCaret(obj)
- utterances.append(text)
-
- self._debugGenerator("Gecko._getSpeechForText",
- obj,
- already_focused,
- utterances)
-
- return utterances
-
- def _getSpeechForComboBox(self, obj, already_focused):
- """Get the speech for a combo box. If the combo box already has focus,
- then only the selection is spoken.
-
- Arguments:
- - obj: the combo box
- - already_focused: False if object just received focus
-
- Returns a list of utterances to be spoken for the object.
- """
-
- # Treat ARIA widgets like default.py widgets
- #
- if self._script.isAriaWidget(obj):
- return speechgenerator.SpeechGenerator.\
- _getSpeechForComboBox(self, obj, already_focused)
-
- utterances = []
-
- label = self._script.getDisplayedLabel(obj)
- if not label:
- if not self._script.inDocumentContent():
- label = obj.name
- else:
- label = self._script.guessTheLabel(obj)
-
- if not already_focused and label:
- utterances.append(label)
-
- # With Gecko, a combo box has a menu as a child. The text being
- # displayed for the combo box can be obtained via the selected
- # menu item.
- #
- menu = None
- for child in obj:
- if child.getRole() == pyatspi.ROLE_MENU:
- menu = child
- break
- if menu:
- child = None
- try:
- # This should work...
- #
- child = menu.querySelection().getSelectedChild(0)
- if not child:
- # It's probably a Gtk combo box.
+ menu = None
+ for child in obj:
+ if child.getRole() == pyatspi.ROLE_MENU:
+ menu = child
+ break
+ if menu:
+ child = None
+ try:
+ # This should work...
#
- return speechgenerator.SpeechGenerator.\
- _getSpeechForComboBox(self, obj, already_focused)
- except:
- # But just in case, we'll fall back on this.
- # [[[TODO - JD: Will we ever have a case where the first
- # fails, but this will succeed???]]]
- #
- for item in menu:
- if item.getState().contains(pyatspi.STATE_SELECTED):
- child = item
- break
- if child:
- utterances.append(child.name)
-
- utterances.extend(self._getSpeechForObjectAvailability(obj))
-
- if not already_focused:
- utterances.extend(self.getSpeechForObjectRole(obj))
-
- self._debugGenerator("Gecko._getSpeechForComboBox",
- obj,
- already_focused,
- utterances)
-
- return utterances
-
- def _getSpeechForMenuItem(self, obj, already_focused):
- """Get the speech for a menu item.
-
- Arguments:
- - obj: the menu item
- - already_focused: False if object just received focus
-
- Returns a list of utterances to be spoken for the object.
- """
-
- # Treat ARIA widgets like default.py widgets
- #
- if self._script.isAriaWidget(obj):
- return speechgenerator.SpeechGenerator.\
- _getSpeechForMenuItem(self, obj, already_focused)
-
- if not self._script.inDocumentContent():
- return speechgenerator.SpeechGenerator.\
- _getSpeechForMenuItem(self, obj, already_focused)
-
- utterances = self._getSpeechForObjectName(obj)
-
- # Saying "menu item" for a combo box can confuse users. Therefore,
- # speak the combo box role instead. Also, only do it if the menu
- # item is not focused (if the menu item is focused, it means we're
- # navigating in the combo box)
- #
- if not obj.getState().contains(pyatspi.STATE_FOCUSED):
- comboBox = \
- self._script.getAncestor(obj,
- [pyatspi.ROLE_COMBO_BOX],
- [pyatspi.ROLE_DOCUMENT_FRAME])
- if comboBox:
- utterances.extend(self.getSpeechForObjectRole(comboBox))
-
- self._debugGenerator("Gecko._getSpeechForMenuItem",
- obj,
- already_focused,
- utterances)
-
- return utterances
-
- def _getSpeechForListItem(self, obj, already_focused):
- """Get the speech for a list item.
-
- Arguments:
- - obj: the list item
- - already_focused: False if object just received focus
-
- Returns a list of utterances to be spoken for the object.
- """
-
- # Treat ARIA widgets like default.py widgets
- #
-
- if self._script.isAriaWidget(obj) \
- or not self._script.inDocumentContent(obj):
- return speechgenerator.SpeechGenerator.\
- _getSpeechForListItem(self, obj, already_focused)
-
- if not obj.getState().contains(pyatspi.STATE_SELECTABLE):
- return speechgenerator.SpeechGenerator.\
- _getDefaultSpeech(self, obj, already_focused)
-
- utterances = self._getSpeechForObjectName(obj)
-
- self._debugGenerator("Gecko._getSpeechForListItem",
- obj,
- already_focused,
- utterances)
-
- return utterances
-
- def _getSpeechForList(self, obj, already_focused):
- """Get the speech for a list.
-
- Arguments:
- - obj: the list
- - already_focused: False if object just received focus
-
- Returns a list of utterances to be spoken for the object.
- """
-
- # Treat ARIA widgets like default.py widgets
- #
- if self._script.isAriaWidget(obj):
- return speechgenerator.SpeechGenerator.\
- _getSpeechForList(self, obj, already_focused)
-
- if not obj.getState().contains(pyatspi.STATE_FOCUSABLE):
- return speechgenerator.SpeechGenerator.\
- _getSpeechForList(self, obj, already_focused)
-
- utterances = []
-
- label = self._script.getDisplayedLabel(obj)
- if not label:
- if not self._script.inDocumentContent():
- label = obj.name
- else:
- label = self._script.guessTheLabel(obj)
-
- if not already_focused and label:
- utterances.append(label)
-
- item = None
- selection = obj.querySelection()
- for i in xrange(obj.childCount):
- if selection.isChildSelected(i):
- item = obj[i]
- break
- item = item or obj[0]
- if item:
- name = self._getSpeechForObjectName(item)
- if name != label:
- utterances.extend(name)
-
- if not already_focused:
- if obj.getState().contains(pyatspi.STATE_MULTISELECTABLE):
- # Translators: "multi-select" refers to a web form list
- # in which more than one item can be selected at a time.
- #
- utterances.append(_("multi-select"))
-
- # Translators: this represents a list in HTML.
- #
- itemString = ngettext("List with %d item",
- "List with %d items",
- obj.childCount) % obj.childCount
- utterances.append(itemString)
-
- self._debugGenerator("Gecko._getSpeechForList",
- obj,
- already_focused,
- utterances)
-
- return utterances
-
- def _getSpeechForImage(self, obj, already_focused):
- """Gets a list of utterances to be spoken for an image.
-
- The default speech will be of the following form:
-
- label name role availability
-
- Arguments:
- - obj: an Accessible
- - already_focused: False if object just received focus
-
- Returns a list of utterances to be spoken for the object.
- """
-
- # Treat ARIA widgets like default.py widgets
- #
- if self._script.isAriaWidget(obj):
- return speechgenerator.SpeechGenerator.\
- _getSpeechForImage(self, obj, already_focused)
-
- utterances = []
-
- if not already_focused:
- label = self._getSpeechForObjectLabel(obj)
- utterances.extend(label)
- name = self._getSpeechForObjectName(obj)
- if name != label:
- utterances.extend(name)
-
- # If there's no text for the image, expose the link to
- # the user if the image is in a link.
- #
- link = self._script.getAncestor(obj,
- [pyatspi.ROLE_LINK],
- [pyatspi.ROLE_DOCUMENT_FRAME])
- if link:
- if not len(utterances):
- return self._getSpeechForLink(link, already_focused)
- else:
- utterances.extend(self.getSpeechForObjectRole(link))
-
- utterances.extend(self.getSpeechForObjectRole(obj))
-
- utterances.extend(self._getSpeechForObjectAvailability(obj))
-
- self._debugGenerator("Gecko._getSpeechForImage",
- obj,
- already_focused,
- utterances)
-
- return utterances
-
- def _getSpeechForLink(self, obj, already_focused):
- """Gets a list of utterances to be spoken for a link.
-
- Arguments:
- - obj: an Accessible
- - already_focused: False if object just received focus
-
- Returns a list of utterances to be spoken for the object.
- """
-
- utterances = []
-
- if not already_focused:
- label = self._getSpeechForObjectLabel(obj)
- utterances.extend(label)
- name = self._getSpeechForObjectName(obj)
-
- # Handle empty alt tags.
- #
- if name:
- lengthOfName = len(name[0].strip())
- if (lengthOfName > 0) and (name != label):
- utterances.extend(name)
-
- # If there's no text for the link, expose part of the
- # URI to the user.
- #
- if not len(utterances):
- basename = self._script.getLinkBasename(obj)
- if basename:
- utterances.append(basename)
-
- utterances.extend(self.getSpeechForObjectRole(obj))
-
- # 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:
- utterances.extend(self.getSpeechForObjectRole(obj[0]))
-
- utterances.extend(self._getSpeechForObjectAvailability(obj))
-
- self._debugGenerator("Gecko._getSpeechForLink",
- obj,
- already_focused,
- utterances)
-
- return utterances
-
- def _getSpeechForTable(self, obj, already_focused):
- """Get the speech for a table
-
- Arguments:
- - obj: the table
- - already_focused: False if object just received focus
-
- Returns a list of utterances to be spoken for the object.
- """
-
- # Treat ARIA widgets like default.py widgets
- #
- if self._script.isAriaWidget(obj):
- return speechgenerator.SpeechGenerator.\
- _getSpeechForTable(self, obj, already_focused)
-
- # [[[TODO: JD - We should decide if we want to provide
- # information about the table dimensions, whether or not
- # this is a layout table versus a data table, etc. For now,
- # however, if it's in HTML content let's ignore it so that
- # SayAll by sentence works. :-) ]]]
- #
- utterances = []
-
- if not self._script.inDocumentContent():
- return speechgenerator.SpeechGenerator.\
- _getSpeechForTable(self, obj, already_focused)
-
- return utterances
-
- def _getSpeechForRadioButton(self, obj, already_focused):
- """Get the speech for a radio button. If the button already had
- focus, then only the state is spoken.
-
- Arguments:
- - obj: the radio button
- - already_focused: False if object just received focus
-
- Returns a list of utterances to be spoken for the object.
- """
-
- # Treat ARIA widgets like default.py widgets
- #
- if self._script.isAriaWidget(obj):
- return speechgenerator.SpeechGenerator.\
- _getSpeechForRadioButton(self, obj, already_focused)
-
- if not self._script.inDocumentContent():
- return speechgenerator.SpeechGenerator.\
- _getSpeechForRadioButton(self, obj, already_focused)
-
- utterances = []
- if obj.getState().contains(pyatspi.STATE_CHECKED):
- # Translators: this is in reference to a radio button being
- # selected or not.
- #
- selectionState = C_("radiobutton", "selected")
- else:
- # Translators: this is in reference to a radio button being
- # selected or not.
- #
- selectionState = C_("radiobutton", "not selected")
-
- if not already_focused:
- # The label is handled as a context in default.py -- assuming we
- # don't have to guess it. If we need to guess it, we need to
- # add it to utterances.
- #
- label = self._script.getDisplayedLabel(obj)
- if not label:
- label = self._script.guessTheLabel(obj)
- if label:
- utterances.append(label)
-
- utterances.append(selectionState)
- utterances.extend(self.getSpeechForObjectRole(obj))
- utterances.extend(self._getSpeechForObjectAvailability(obj))
+ child = menu.querySelection().getSelectedChild(0)
+ if not child:
+ # It's probably a Gtk combo box.
+ #
+ result = \
+ speechgenerator.SpeechGenerator._getDisplayedText(
+ self, obj, **args)
+ except:
+ # But just in case, we'll fall back on this.
+ # [[[TODO - JD: Will we ever have a case where the first
+ # fails, but this will succeed???]]]
+ #
+ for item in menu:
+ if item.getState().contains(pyatspi.STATE_SELECTED):
+ child = item
+ break
+ if child and child.name:
+ result.append(child.name)
else:
- utterances.append(selectionState)
-
- self._debugGenerator("Gecko._getSpeechForRadioButton",
- obj,
- already_focused,
- utterances)
- return utterances
-
- def _getSpeechForCheckBox(self, obj, already_focused):
- """Get the speech for a check box. If the check box already had
- focus, then only the state is spoken.
+ result = \
+ speechgenerator.SpeechGenerator._getDisplayedText(
+ self, obj, **args)
+ return result
- Arguments:
- - obj: the check box
- - already_focused: False if object just received focus
+ def _getNumberOfChildren(self, obj, **args):
+ result = []
+ role = args.get('role', obj.getRole())
- Returns a list of utterances to be spoken for the object.
- """
-
- # Treat ARIA widgets like default.py widgets
- #
- if self._script.isAriaWidget(obj):
- return speechgenerator.SpeechGenerator.\
- _getSpeechForCheckBox(self, obj, already_focused)
-
- if not self._script.inDocumentContent():
- return speechgenerator.SpeechGenerator.\
- _getSpeechForCheckBox(self, obj, already_focused)
-
- utterances = []
- state = obj.getState()
- if state.contains(pyatspi.STATE_INDETERMINATE):
- # Translators: this represents the state of a checkbox.
- #
- checkedState = _("partially checked")
- elif state.contains(pyatspi.STATE_CHECKED):
- # Translators: this represents the state of a checkbox.
- #
- checkedState = _("checked")
- else:
- # Translators: this represents the state of a checkbox.
+ if role == pyatspi.ROLE_LIST:
+ # Translators: this represents a list in HTML.
#
- checkedState = _("not checked")
-
- # If it's not already focused, say its label.
- #
- if not already_focused:
- label = self._script.getDisplayedLabel(obj)
- if not label:
- label = self._script.guessTheLabel(obj)
- if label:
- utterances.append(label)
- utterances.extend(self.getSpeechForObjectRole(obj))
- utterances.append(checkedState)
- utterances.extend(self._getSpeechForObjectAvailability(obj))
+ result.append(ngettext("List with %d item",
+ "List with %d items",
+ obj.childCount) % obj.childCount)
else:
- utterances.append(checkedState)
+ result.extend(speechgenerator.SpeechGenerator._getNumberOfChildren(
+ self, obj, **args))
+ return result
- self._debugGenerator("Gecko._getSpeechForCheckBox",
- obj,
- already_focused,
- utterances)
+ def _getAncestors(self, obj, **args):
+ result = []
+ priorObj = args.get('priorObj', None)
+ commonAncestor = self._script.findCommonAncestor(priorObj, obj)
- return utterances
+ if obj is commonAncestor:
+ return result
- def getSpeechContext(self, obj, stopAncestor=None):
- """Get the speech that describes the names and role of
- the container hierarchy of the object, stopping at and
- not including the stopAncestor.
-
- Arguments:
- - obj: the object
- - stopAncestor: the ancestor to stop at and not include (None
- means include all ancestors)
-
- Returns a list of utterances to be spoken.
- """
-
- utterances = []
-
- if obj is stopAncestor:
- return utterances
-
- # Skip items of unknown rolenames, menu bars, labels with
+ # Skip items of unknown rolenames, menu bars, labels with
# children, and autocompletes. (With autocompletes, we
# wind up speaking the text object). Beginning with Firefox
# 3.2, list items have names corresponding with their text.
@@ -702,7 +276,7 @@ class SpeechGenerator(speechgenerator.SpeechGenerator):
parent = obj.parent
while parent and (parent.parent != parent):
role = parent.getRole()
- if self._script.isSameObject(parent, stopAncestor) \
+ if self._script.isSameObject(parent, commonAncestor) \
or role in stopRoles:
break
@@ -717,8 +291,8 @@ class SpeechGenerator(speechgenerator.SpeechGenerator):
and parent.parent.getRole() == pyatspi.ROLE_COMBO_BOX:
parent = parent.parent
continue
-
- # Also skip the parent if its accessible text is a single
+
+ # Also skip the parent if its accessible text is a single
# EMBEDDED_OBJECT_CHARACTER: Script.getDisplayedText will
# end up coming back to the child of an object for the text
# if an object's text contains a single EOC. In addition,
@@ -743,65 +317,39 @@ class SpeechGenerator(speechgenerator.SpeechGenerator):
#
text = self._script.getDisplayedText(parent)
label = self._script.getDisplayedLabel(parent)
- newUtterances = []
+ newResult = []
if text and (text != label) and len(text.strip()) \
and (not text.startswith("chrome://")):
- newUtterances.append(text)
+ newResult.append(text)
if label and len(label.strip()):
- newUtterances.append(label)
+ newResult.append(label)
# Finally add the role if it's not among the roles we don't
# wish to speak.
#
- if not role in dontSpeakRoles and len(newUtterances):
- utterances.append(rolenames.getSpeechForRoleName(parent))
+ if not (role in dontSpeakRoles) and len(newResult):
+ result.append(rolenames.getSpeechForRoleName(parent))
# If this object is an ARIA widget with STATE_REQUIRED, add
# that. (Note that for the most part, the ARIA widget itself
# has this state, but in the case of a group of radio buttons,
# it is the group which has the state).
#
- utterances.extend(self._getSpeechForRequiredObject(parent))
+ result.extend(self._getRequired(parent, **args))
- utterances.extend(newUtterances)
+ result.extend(newResult)
parent = parent.parent
- utterances.reverse()
+ result.reverse()
- return utterances
-
- def _getSpeechForSlider(self, obj, already_focused):
- """Get the speech for a slider. If the object already
- had focus, just the value is spoken.
+ return result
- Arguments:
- - obj: the slider
- - already_focused: False if object just received focus
-
- Returns a list of utterances to be spoken for the object.
- """
-
- # Let default handle non-ARIA widgets (XUL?)
- if self._script.isAriaWidget(obj):
- return speechgenerator.SpeechGenerator.\
- _getSpeechForSlider(self, obj, already_focused)
-
- valueString = self._script.getTextForValue(obj)
-
- if already_focused:
- utterances = [valueString]
- else:
- utterances = []
- utterances.extend(self._getSpeechForObjectLabel(obj))
- utterances.extend(self.getSpeechForObjectRole(obj))
- utterances.append(valueString)
- utterances.extend(self._getSpeechForObjectAvailability(obj))
-
- self._debugGenerator("Gecko._getSpeechForSlider",
- obj,
- already_focused,
- utterances)
-
- return utterances
-
+ def getSpeech(self, obj, **args):
+ # ARIA widgets get treated like regular default widgets.
+ #
+ result = []
+ args['isAria'] = self._script.isAriaWidget(obj)
+ result = speechgenerator.SpeechGenerator.getSpeech(self, obj, **args)
+ del args['isAria']
+ return result
diff --git a/src/orca/speechgenerator.py b/src/orca/speechgenerator.py
index fd41bfe..22da38c 100644
--- a/src/orca/speechgenerator.py
+++ b/src/orca/speechgenerator.py
@@ -293,10 +293,18 @@ class SpeechGenerator:
result.append(_("collapsed"))
return result
+ def _getMultiselectableState(self, obj, **args):
+ result = []
+ if obj.getState().contains(pyatspi.STATE_MULTISELECTABLE):
+ # Translators: "multi-select" refers to a web form list
+ # in which more than one item can be selected at a time.
+ #
+ result.append(_("multi-select"))
+ return result
+
def _getMenuItemCheckedState(self, obj, **args):
result = []
- state = obj.getState()
- if state.contains(pyatspi.STATE_CHECKED):
+ if obj.getState().contains(pyatspi.STATE_CHECKED):
# Translators: this represents the state of a checked menu item.
#
result.append(_("checked"))
@@ -304,8 +312,7 @@ class SpeechGenerator:
def _getAvailability(self, obj, **args):
result = []
- state = obj.getState()
- if not state.contains(pyatspi.STATE_SENSITIVE):
+ if not obj.getState().contains(pyatspi.STATE_SENSITIVE):
# Translators: this represents an item on the screen that has
# been set insensitive (or grayed out).
#
@@ -314,8 +321,7 @@ class SpeechGenerator:
def _getRequired(self, obj, **args):
result = []
- state = obj.getState()
- if state.contains(pyatspi.STATE_REQUIRED):
+ if obj.getState().contains(pyatspi.STATE_REQUIRED):
result = [settings.speechRequiredStateString]
return result
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]