[orca] More updates to Mesar's patch for bgo#570658
- From: William Walker <wwalker src gnome org>
- To: svn-commits-list gnome org
- Subject: [orca] More updates to Mesar's patch for bgo#570658
- Date: Tue, 12 May 2009 14:04:30 -0400 (EDT)
commit b0a497e67056f5ef8506cffddc3b58844a706dd4
Author: Willie Walker <william walker sun com>
Date: Mon May 11 21:57:37 2009 -0400
More updates to Mesar's patch for bgo#570658
---
src/orca/Makefile.am | 2 +
src/orca/altspeechgenerator.py | 736 ++++++++++++++++++++++++++++++++++++++++
src/orca/formatting.py | 189 ++++++++++
src/orca/script.py | 6 +
src/orca/speechgenerator.py | 15 +-
5 files changed, 946 insertions(+), 2 deletions(-)
diff --git a/src/orca/Makefile.am b/src/orca/Makefile.am
index 21ccabc..b4a026d 100644
--- a/src/orca/Makefile.am
+++ b/src/orca/Makefile.am
@@ -9,6 +9,7 @@ orca_pathdir=$(pyexecdir)
orca_python_PYTHON = \
__init__.py \
acss.py \
+ altspeechgenerator.py \
app_gui_prefs.py \
app_prefs.py \
bookmarks.py \
@@ -25,6 +26,7 @@ orca_python_PYTHON = \
find.py \
flat_review.py \
focus_tracking_presenter.py \
+ formatting.py \
gnomespeechfactory.py \
httpserver.py \
input_event.py \
diff --git a/src/orca/altspeechgenerator.py b/src/orca/altspeechgenerator.py
new file mode 100644
index 0000000..f39f047
--- /dev/null
+++ b/src/orca/altspeechgenerator.py
@@ -0,0 +1,736 @@
+# 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.
+
+"""Utilities for obtaining speech utterances for objects. In general,
+there probably should be a singleton instance of the SpeechGenerator
+class."""
+
+__id__ = "$Id:$"
+__version__ = "$Revision:$"
+__date__ = "$Date:$"
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
+__license__ = "LGPL"
+
+import sys
+import re
+import traceback
+
+import pyatspi
+import rolenames
+import settings
+import generator_settings
+
+from orca_i18n import _ # for gettext support
+from orca_i18n import ngettext # for ngettext support
+from orca_i18n import C_ # to provide qualified translatable strings
+
+def formatExceptionInfo(maxTBlevel=5):
+ cla, exc, trbk = sys.exc_info()
+ excName = cla.__name__
+ try:
+ excArgs = exc.args
+ except KeyError:
+ excArgs = "<no args>"
+ excTb = traceback.format_tb(trbk, maxTBlevel)
+ return (excName, excArgs, excTb)
+
+class AltSpeechGenerator:
+ """Takes accessible objects and produces a string to speak for
+ those objects. See the getSpeech method, which is the primary
+ entry point. Subclasses can feel free to override/extend the
+ speechGenerators instance field as they see fit."""
+
+ def __init__(self, script):
+ self._script = script
+ self._methodsDict = {}
+ for method in \
+ filter(lambda z: callable(z),
+ map(lambda y: getattr(self, y).__get__(self, self.__class__),
+ filter(lambda x: x.startswith("_get"), dir(self)))):
+ name = method.__name__[4:]
+ name = name[0].lower() + name[1:]
+ self._methodsDict[name] = method
+
+ for roleKey in generator_settings.formattingDict.keys():
+ for speechKey in ["focusedSpeech", "unfocusedSpeech"]:
+ try:
+ evalString = \
+ generator_settings.formattingDict[roleKey][speechKey]
+ except:
+ continue
+ else:
+ if not evalString:
+ # It's legal to have an empty string for speech.
+ #
+ continue
+ generatedResultsDict = {}
+ while True:
+ try:
+ eval(evalString, generatedResultsDict)
+ break
+ except NameError:
+ info = formatExceptionInfo()
+ arg = info[1][0]
+ arg = arg.replace("name '", "")
+ arg = arg.replace("' is not defined", "")
+ if not self._methodsDict.has_key(arg):
+ print roleKey, speechKey, evalString, \
+ " no function for '%s'\n" % arg
+ generatedResultsDict[arg] = ""
+ except:
+ print roleKey, speechKey, evalString, \
+ formatExceptionInfo()
+ break
+
+ #####################################################################
+ # #
+ # Name, role, and label information #
+ # #
+ #####################################################################
+
+ def _getName(self, obj, **args):
+ result = []
+ name = self._script.getDisplayedText(obj)
+ if name:
+ result.append(name)
+ elif obj.description:
+ result.append(obj.description)
+ return result
+
+ def _getTextRole(self, obj, **args):
+ result = []
+ # pylint: disable-msg=W0142
+ if obj.getRole() != pyatspi.ROLE_PARAGRAPH:
+ result.extend(self._getRoleName(obj, **args))
+ return result
+
+ def _getRoleName(self, obj, forceRole=None, **args):
+ result = []
+ if forceRole:
+ role = forceRole
+ else:
+ role = args.get('role', None)
+ if (obj.getRole() != pyatspi.ROLE_UNKNOWN):
+ result.append(rolenames.getSpeechForRoleName(obj, role))
+ return result
+
+ def _getLabel(self, obj, **args):
+ result = []
+ label = self._script.getDisplayedLabel(obj)
+ if label:
+ result = [label]
+ return result
+
+ def _getLabelAndName(self, obj, **args):
+ """Gets the label and the name if the name is different from the label."""
+ # pylint: disable-msg=W0142
+ result = []
+ label = self._getLabel(obj, **args)
+ name = self._getName(obj, **args)
+ result.extend(label)
+ if not len(label):
+ result.extend(name)
+ elif len(name) and name[0] != label[0]:
+ result.extend(name)
+ return result
+
+ def _getLabelOrName(self, obj, **args ):
+ """Gets the label or the name if the label is not preset."""
+ result = []
+ # pylint: disable-msg=W0142
+ result.extend(self._getLabel(obj, **args))
+ if not result:
+ if obj.name and (len(obj.name)):
+ result.append(obj.name)
+ return result
+
+ def _getUnrelatedLabels(self, obj, **args):
+ """Finds all labels not in a label for or labelled by relation."""
+ labels = self._script.findUnrelatedLabels(obj)
+ result = []
+ for label in labels:
+ name = self._getName(label, False)
+ result.extend(name)
+ return result
+
+ def _getEmbedded(self, obj, **args):
+ # pylint: disable-msg=W0142
+ result = self._getLabelOrName(obj, **args)
+ if not result:
+ try:
+ result.append(obj.getApplication().name)
+ except:
+ pass
+ return result
+
+ #####################################################################
+ # #
+ # State information #
+ # #
+ #####################################################################
+
+ def _getCheckedState(self, obj, **args):
+ result = []
+ state = obj.getState()
+ if state.contains(pyatspi.STATE_INDETERMINATE):
+ # Translators: this represents the state of a checkbox.
+ #
+ result.append(_("partially checked"))
+ elif state.contains(pyatspi.STATE_CHECKED):
+ # Translators: this represents the state of a checkbox.
+ #
+ result.append(_("checked"))
+ else:
+ # Translators: this represents the state of a checkbox.
+ #
+ result.append(_("not checked"))
+ return result
+
+ def _getCellCheckedState(self, obj, **args):
+ # pylint: disable-msg=W0142
+ result = []
+ try:
+ action = obj.queryAction()
+ except NotImplementedError:
+ action = None
+ if action:
+ for i in range(0, action.nActions):
+ # Translators: this is the action name for
+ # the 'toggle' action. It must be the same
+ # string used in the *.po file for gail.
+ #
+ if action.getName(i) in ["toggle", _("toggle")]:
+ oldFormat = args.get('format', None)
+ args['format'] = self._script.formatting.getFormat(
+ forceRole=pyatspi.ROLE_CHECK_BOX, **args)
+ result.extend(
+ self.getSpeech(obj, **args))
+ args['format'] = oldFormat
+ break
+ return result
+
+ def _getRadioState(self, obj, **args):
+ result = []
+ state = obj.getState()
+ if state.contains(pyatspi.STATE_CHECKED):
+ # Translators: this is in reference to a radio button being
+ # selected or not.
+ #
+ result.append(C_("radiobutton", "selected"))
+ else:
+ # Translators: this is in reference to a radio button being
+ # selected or not.
+ #
+ result.append(C_("radiobutton", "not selected"))
+ return result
+
+ def _getToggleState(self, obj, **args):
+ result = []
+ state = obj.getState()
+ if state.contains(pyatspi.STATE_CHECKED) \
+ or state.contains(pyatspi.STATE_PRESSED):
+ # Translators: the state of a toggle button.
+ #
+ result.append(_("pressed"))
+ else:
+ # Translators: the state of a toggle button.
+ #
+ result.append(_("not pressed"))
+ return result
+
+ def _getExpandableState(self, obj, **args):
+ result = []
+ state = obj.getState()
+ if state.contains(pyatspi.STATE_EXPANDABLE):
+ if state.contains(pyatspi.STATE_EXPANDED):
+ # Translators: this represents the state of a node in a tree.
+ # 'expanded' means the children are showing.
+ # 'collapsed' means the children are not showing.
+ #
+ result.append(_("expanded"))
+ else:
+ # Translators: this represents the state of a node in a tree.
+ # 'expanded' means the children are showing.
+ # 'collapsed' means the children are not showing.
+ #
+ result.append(_("collapsed"))
+ return result
+
+ def _getMenuItemCheckedState(self, obj, **args):
+ result = []
+ if state.contains(pyatspi.STATE_CHECKED):
+ # Translators: this represents the state of a checked menu item.
+ #
+ result.append(_("checked"))
+ return result
+
+ def _getAvailability(self, obj, **args):
+ result = []
+ state = obj.getState()
+ if not state.contains(pyatspi.STATE_SENSITIVE):
+ # Translators: this represents an item on the screen that has
+ # been set insensitive (or grayed out).
+ #
+ result.append(_("grayed"))
+ return result
+
+ def _getRequired(self, obj, **args):
+ result = []
+ state = obj.getState()
+ if state.contains(pyatspi.STATE_REQUIRED):
+ result = [settings.speechRequiredStateString]
+ return result
+
+ def _getReadOnly(self, obj, **args):
+ result = []
+ if settings.presentReadOnlyText \
+ and self._script.isReadOnlyTextArea(obj):
+ result.append(settings.speechReadOnlyString)
+ return result
+
+ #####################################################################
+ # #
+ # Image information #
+ # #
+ #####################################################################
+
+ def _getImageDescription(self, obj, **args ):
+ result = []
+ try:
+ image = obj.queryImage()
+ except NotImplementedError:
+ pass
+ else:
+ description = image.imageDescription
+ if description and len(description):
+ result.append(description)
+ return result
+
+ def _getImage(self, obj, **args):
+ result = []
+ try:
+ image = obj.queryImage()
+ except:
+ pass
+ else:
+ role = pyatspi.ROLE_IMAGE
+ result.extend(self.getSpeech(obj, role=role))
+ return result
+
+ #####################################################################
+ # #
+ # Table interface information #
+ # #
+ #####################################################################
+
+ def _getTableCell2ChildLabel(self, obj, **args):
+ """Get the speech utterances for the label of single table cell that
+ has a special 2 child pattern that we run into."""
+ # pylint: disable-msg=W0142
+ result = []
+
+ # If this table cell has 2 children and one of them has a
+ # 'toggle' action and the other does not, then present this
+ # as a checkbox where:
+ # 1) we get the checked state from the cell with the 'toggle' action
+ # 2) we get the label from the other cell.
+ # See Orca bug #376015 for more details.
+ #
+ if obj.childCount == 2:
+ cellOrder = []
+ hasToggle = [False, False]
+ for i, child in enumerate(obj):
+ try:
+ action = child.queryAction()
+ except NotImplementedError:
+ continue
+ else:
+ for j in range(0, action.nActions):
+ # Translators: this is the action name for
+ # the 'toggle' action. It must be the same
+ # string used in the *.po file for gail.
+ #
+ if action.getName(j) in ["toggle", _("toggle")]:
+ hasToggle[i] = True
+ break
+ if hasToggle[0] and not hasToggle[1]:
+ cellOrder = [ 1, 0 ]
+ elif not hasToggle[0] and hasToggle[1]:
+ cellOrder = [ 0, 1 ]
+ if cellOrder:
+ args['format'] = self._script.formatting.getFormat( \
+ forceRole=pyatspi.ROLE_TABLE_CELL, **args)
+ for i in cellOrder:
+ if not hasToggle[i]:
+ result.extend(self.getSpeech(obj[i], **args))
+ return result
+
+ def _getTableCell2ChildToggle(self, obj, **args):
+ """Get the speech utterances for the label of single table cell that
+ has a special 2 child pattern that we run into."""
+ # pylint: disable-msg=W0142
+ result = []
+
+ # If this table cell has 2 children and one of them has a
+ # 'toggle' action and the other does not, then present this
+ # as a checkbox where:
+ # 1) we get the checked state from the cell with the 'toggle' action
+ # 2) we get the label from the other cell.
+ # See Orca bug #376015 for more details.
+ #
+ if obj.childCount == 2:
+ cellOrder = []
+ hasToggle = [False, False]
+ for i, child in enumerate(obj):
+ try:
+ action = child.queryAction()
+ except NotImplementedError:
+ continue
+ else:
+ for j in range(0, action.nActions):
+ # Translators: this is the action name for
+ # the 'toggle' action. It must be the same
+ # string used in the *.po file for gail.
+ #
+ if action.getName(j) in ["toggle", _("toggle")]:
+ hasToggle[i] = True
+ break
+
+ if hasToggle[0] and not hasToggle[1]:
+ cellOrder = [ 1, 0 ]
+ elif not hasToggle[0] and hasToggle[1]:
+ cellOrder = [ 0, 1 ]
+ if cellOrder:
+ args['role'] = pyatspi.ROLE_CHECK_BOX
+ for i in cellOrder:
+ if hasToggle[i]:
+ result.extend(self.getSpeech(obj[i], **args))
+ return result
+
+ def _getTableCellRow(self, obj, **args):
+ """Get the speech for a table cell row or a single table cell
+ if settings.readTableCellRow is False."""
+ # pylint: disable-msg=W0142
+ result = []
+
+ try:
+ parentTable = obj.parent.queryTable()
+ except NotImplementedError:
+ parentTable = None
+ if settings.readTableCellRow and parentTable \
+ and (not self._script.isLayoutOnly(obj.parent)):
+ parent = obj.parent
+ index = self._script.getCellIndex(obj)
+ row = parentTable.getRowAtIndex(index)
+ column = parentTable.getColumnAtIndex(index)
+
+ # This is an indication of whether we should speak all the
+ # table cells (the user has moved focus up or down a row),
+ # or just the current one (focus has moved left or right in
+ # the same row).
+ #
+ speakAll = True
+ if "lastRow" in self._script.pointOfReference and \
+ "lastColumn" in self._script.pointOfReference:
+ pointOfReference = self._script.pointOfReference
+ speakAll = (pointOfReference["lastRow"] != row) or \
+ ((row == 0 or row == parentTable.nRows-1) and \
+ pointOfReference["lastColumn"] == column)
+ if speakAll:
+ for i in range(0, parentTable.nColumns):
+ cell = parentTable.getAccessibleAt(row, i)
+ if not cell:
+ continue
+ state = cell.getState()
+ showing = state.contains(pyatspi.STATE_SHOWING)
+ if showing:
+ # If this table cell has a "toggle" action, and
+ # doesn't have any label associated with it then
+ # also speak the table column header.
+ # See Orca bug #455230 for more details.
+ #
+ label = self._script.getDisplayedText( \
+ self._script.getRealActiveDescendant(cell))
+ try:
+ action = cell.queryAction()
+ except NotImplementedError:
+ action = None
+ if action and (label == None or len(label) == 0):
+ for j in range(0, action.nActions):
+ # Translators: this is the action name for
+ # the 'toggle' action. It must be the same
+ # string used in the *.po file for gail.
+ #
+ if action.getName(j) in ["toggle", \
+ _("toggle")]:
+ accHeader = \
+ parentTable.getColumnHeader(i)
+ result.append(accHeader.name)
+ format = self._script.formatting.getFormat( \
+ forceRole='REAL_ROLE_TABLE_CELL', **args)
+ result.extend( \
+ self.getSpeech(cell,
+ format=format,
+ **args))
+ else:
+ format = self._script.formatting.getFormat( \
+ forceRole='REAL_ROLE_TABLE_CELL', **args)
+ result.extend( \
+ self.getSpeech(obj, format=format, **args))
+ else:
+ format = self._script.formatting.getFormat(
+ forceRole='REAL_ROLE_TABLE_CELL',
+ **args)
+ result = self.getSpeech(obj, format=format, **args)
+ return result
+
+ #####################################################################
+ # #
+ # Terminal information #
+ # #
+ #####################################################################
+
+ def _getTerminal(self, obj, **args):
+ result = []
+ title = None
+ frame = self._script.getFrame(obj)
+ if frame:
+ title = frame.name
+ if not title:
+ title = self._script.getDisplayedLabel(obj)
+ result.append(title)
+ return result
+
+ #####################################################################
+ # #
+ # Text interface information #
+ # #
+ #####################################################################
+
+ def _getCurrentLineText(self, obj, **args ):
+ [text, caretOffset, startOffset] = self._script.getTextLineAtCaret(obj)
+ return [text]
+
+ def _getDisplayedText(self, obj, **args ):
+ """Returns the text being displayed for an object or the object's
+ name if no text is being displayed."""
+ return [self._script.getDisplayedText(obj)]
+
+ def _getAllTextSelection(self, obj, **args):
+ """Check if this object has text associated with it and it's
+ completely selected."""
+ result = []
+ try:
+ textObj = obj.queryText()
+ except:
+ pass
+ else:
+ noOfSelections = textObj.getNSelections()
+ if noOfSelections == 1:
+ [string, startOffset, endOffset] = \
+ textObj.getTextAtOffset(0, pyatspi.TEXT_BOUNDARY_LINE_START)
+ if startOffset == 0 and endOffset == len(string):
+ # Translators: when the user selects (highlights) text in
+ # a document, Orca lets them know this.
+ #
+ result = [C_("text", "selected")]
+ return result
+
+ #####################################################################
+ # #
+ # Value interface information #
+ # #
+ #####################################################################
+
+ def _getValue(self, obj, **args):
+ return [self._script.getTextForValue(obj)]
+
+ def _getPercentage(self, obj, **args ):
+ result = []
+ try:
+ value = obj.queryValue()
+ except NotImplementedError:
+ pass
+ else:
+ percentValue = \
+ (value.currentValue \
+ / (value.maximumValue - value.minimumValue)) \
+ * 100.0
+ # Translators: this is the percentage value of a progress bar.
+ #
+ percentage = _("%d percent.") % percentValue + " "
+ result.append(percentage)
+ return result
+
+ #####################################################################
+ # #
+ # Hierarchy and related dialog information #
+ # #
+ #####################################################################
+
+ def _getRealActiveDescendantDisplayedText(self, obj, **args ):
+ text = self._script.getDisplayedText(\
+ self._script.getRealActiveDescendant(obj))
+ if text:
+ return [text]
+ else:
+ return []
+
+ def _getNumberOfChildren(self, obj, **args):
+ result = []
+ childNodes = self._script.getChildNodes(obj)
+ children = len(childNodes)
+ if children:
+ # Translators: this is the number of items in a layered
+ # pane or table.
+ #
+ itemString = ngettext("%d item", "%d items", children) % children
+ result.append(itemString)
+ return result
+
+ def _getNoShowingChildren(self, obj, **args):
+ result = []
+ hasItems = False
+ for child in obj:
+ state = child.getState()
+ if state.contains(pyatspi.STATE_SHOWING):
+ hasItems = True
+ break
+ if not hasItems:
+ # Translators: this is the number of items in a layered pane
+ # or table.
+ #
+ result.append(_("0 items"))
+ return result
+
+ def _getNoChildren(self, obj, **args ):
+ result = []
+ if not obj.childCount:
+ # Translators: this is the number of items in a layered pane
+ # or table.
+ #
+ result.append(_("0 items"))
+ return result
+
+ def _getUnfocusedDialogCount(self, obj, **args):
+ result = []
+ # If this application has more than one unfocused alert or
+ # dialog window, then speak '<m> unfocused dialogs'
+ # to let the user know.
+ #
+ alertAndDialogCount = \
+ self._script.getUnfocusedAlertAndDialogCount(obj)
+ if alertAndDialogCount > 0:
+ # Translators: this tells the user how many unfocused
+ # alert and dialog windows that this application has.
+ #
+ result.append(ngettext("%d unfocused dialog",
+ "%d unfocused dialogs",
+ alertAndDialogCount) % alertAndDialogCount)
+ return result
+
+ #####################################################################
+ # #
+ # Keyboard shortcut information #
+ # #
+ #####################################################################
+
+ def _getAccelerator(self, obj, **args):
+ result = []
+ [mnemonic, shortcut, accelerator] = self._script.getKeyBinding(obj)
+ if accelerator:
+ # Add punctuation for better prosody.
+ #
+ #if utterances:
+ # utterances[-1] += "."
+ result.append(accelerator)
+ return result
+
+ def _getMnemonic(self, obj, **args):
+ result = []
+ [mnemonic, shortcut, accelerator] = self._script.getKeyBinding(obj)
+ if mnemonic:
+ mnemonic = mnemonic[-1] # we just want a single character
+ if not mnemonic and shortcut:
+ mnemonic = shortcut
+ if mnemonic:
+ # Add punctuation for better prosody.
+ #
+ #if utterances:
+ # utterances[-1] += "."
+ result = [mnemonic]
+ return result
+
+ #####################################################################
+ # #
+ # Tie it all together #
+ # #
+ #####################################################################
+
+ def getSpeech(self, obj, already_focused=False, **args):
+ # pylint: disable-msg=W0142
+ result = []
+ generatedResultsDict = {}
+ try:
+ role = args.get('role', obj.getRole())
+ forceRole = args.get('forceRole', role)
+ role = forceRole
+
+ roleName = self._getRoleName(obj, forceRole=role, **args)
+
+ # If someone has already given us the format string to be used
+ # then we dont need to look it up.
+ #
+ format = args.get('format', '')
+ if not format:
+ args['already_focused'] = already_focused
+ format = self._script.formatting.getFormat('speech',
+ forceRole=role,
+ **args)
+
+ assert(format)
+ evalString = format
+
+ # We loop through the format string, catching each error
+ # as we go. Each error should always be a NameError, where
+ # the name is the name of one of our generator functions.
+ # When we encounter this, we call the function and get its
+ # results, placing them in the generatedResultDict,
+ # which serves as the globals for the call to eval.
+ #
+ while True:
+ try:
+ result = eval(evalString, generatedResultsDict)
+ break
+ except NameError:
+ result = []
+ info = formatExceptionInfo()
+ arg = info[1][0]
+ arg = arg.replace("name '", "")
+ arg = arg.replace("' is not defined", "")
+ if not self._methodsDict.has_key(arg):
+ print("unable to find function for '%s'\n" % arg)
+ break
+ generatedResultsDict[arg] = \
+ self._methodsDict[arg](obj, **args)
+ except:
+ print formatExceptionInfo()
+ result = []
+
+ return result
diff --git a/src/orca/formatting.py b/src/orca/formatting.py
new file mode 100644
index 0000000..8b7bfd6
--- /dev/null
+++ b/src/orca/formatting.py
@@ -0,0 +1,189 @@
+# Orca
+#
+# Copyright 2004-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.
+
+"""Manages the formatting settings for Orca."""
+
+__id__ = "$Id:$"
+__version__ = "$Revision:$"
+__date__ = "$Date:$"
+__copyright__ = "Copyright (c) 2004-2009 Sun Microsystems Inc."
+__license__ = "LGPL"
+
+import pyatspi
+
+defaultFormatting = {
+ 'speech': {
+ 'default': {
+ 'focused': '',
+ 'unfocused': 'labelAndName + allTextSelection + roleName + availability'
+ },
+ pyatspi.ROLE_ALERT: {
+ 'unfocused': 'labelAndName + unrelatedLabels'
+ },
+ pyatspi.ROLE_ANIMATION: {
+ 'unfocused': 'labelAndName'
+ },
+ pyatspi.ROLE_CHECK_BOX: {
+ 'focused': 'checkedState',
+ 'unfocused': 'labelAndName + roleName + checkedState + required + availability'
+ },
+ pyatspi.ROLE_CHECK_MENU_ITEM: {
+ 'focused': 'checkedState',
+ 'unfocused': 'labelAndName + roleName + checkedState + required + availability + accelerator'
+ },
+ pyatspi.ROLE_DIALOG: {
+ 'unfocused': 'labelAndName + unrelatedLabels'
+ },
+ pyatspi.ROLE_FRAME: {
+ 'focused': '',
+ 'unfocused': 'labelAndName + allTextSelection + roleName + unfocusedDialogCount + availability'
+ },
+ pyatspi.ROLE_ICON: {
+ 'focused': 'labelAndName + imageDescription + roleName',
+ 'unfocused': 'labelAndName + imageDescription + roleName'
+ },
+ pyatspi.ROLE_LAYERED_PANE: {
+ 'focused': 'labelAndName + allTextSelection + roleName + availability + noShowingChildren',
+ 'unfocused': 'labelAndName + allTextSelection + roleName + availability + noShowingChildren'
+ },
+ pyatspi.ROLE_LIST_ITEM: {
+ 'focused': 'expandableState + availability',
+ 'unfocused': 'labelAndName + allTextSelection + expandableState + availability'
+ },
+ pyatspi.ROLE_MENU: {
+ 'focused': '',
+ 'unfocused': 'labelAndName + allTextSelection + roleName + availability'
+ },
+ pyatspi.ROLE_MENU_ITEM: {
+ 'focused': '',
+ 'unfocused': 'labelAndName + menuItemCheckedState + availability + accelerator'
+ },
+ pyatspi.ROLE_PASSWORD_TEXT: {
+ 'focused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection',
+ 'unfocused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection'
+ },
+ pyatspi.ROLE_PROGRESS_BAR: {
+ 'focused': 'percentage',
+ 'unfocused': 'labelAndName + percentage'
+ },
+ pyatspi.ROLE_PUSH_BUTTON: {
+ 'unfocused': 'labelAndName + roleName'
+ },
+ pyatspi.ROLE_RADIO_BUTTON: {
+ 'focused': 'radioState',
+ 'unfocused': 'labelAndName + radioState + roleName + availability'
+ },
+ pyatspi.ROLE_RADIO_MENU_ITEM: {
+ # OpenOffice check menu items currently have a role of "menu item"
+ # rather then "check menu item", so we need to test if one of the
+ # states is CHECKED. If it is, then add that in to the list of
+ # speech utterances. Note that we can't tell if this is a "check
+ # menu item" that is currently unchecked and speak that state.
+ # See Orca bug #433398 for more details.
+ #
+ 'focused': 'labelAndName + radioState + roleName + availability',
+ 'unfocused': 'labelAndName + radioState + roleName + availability + accelerator'
+ },
+ pyatspi.ROLE_SLIDER: {
+ # Ignore the text on the slider. See bug 340559
+ # (http://bugzilla.gnome.org/show_bug.cgi?id=340559): the
+ # implementors of the slider support decided to put in a
+ # Unicode left-to-right character as part of the text,
+ # even though that is not painted on the screen.
+ #
+ # In Java, however, there are sliders without a label. In
+ # this case, we'll add to presentation the slider name if
+ # it exists and we haven't found anything yet.
+ #
+ 'focused': 'value',
+ 'unfocused': 'labelAndName + roleName + value + required + availability'
+ },
+ pyatspi.ROLE_SPIN_BUTTON: {
+ 'focused': 'name',
+ 'unfocused': 'labelAndName + allTextSelection + roleName + availability + required'
+ },
+ pyatspi.ROLE_SPLIT_PANE: {
+ 'focused': 'value',
+ 'unfocused': 'labelAndName + roleName + value + availability'
+ },
+ pyatspi.ROLE_TABLE: {
+ 'focused': 'labelAndName + allTextSelection + roleName + availability + noChildren',
+ 'unfocused': 'labelAndName + allTextSelection + roleName + availability + noChildren'
+ },
+ pyatspi.ROLE_TABLE_CELL: {
+ 'focused': '(tableCell2ChildLabel + tableCell2ChildToggle) or cellCheckedState + (realActiveDescendantDisplayedText or imageDescription) + (expandableState and (expandableState + numberOfChildren)) + required',
+ 'unfocused': 'tableCellRow'
+ },
+ 'REAL_ROLE_TABLE_CELL': {
+ # the real cell information
+ # note that pyatspi.ROLE_TABLE_CELL is used to work out if we need to
+ # read a whole row. It calls REAL_ROLE_TABLE_CELL internally.
+ # maybe it can be done in a cleaner way?
+ #
+ 'focused': '(tableCell2ChildLabel + tableCell2ChildToggle) or cellCheckedState + (realActiveDescendantDisplayedText or imageDescription + image) + (expandableState and (expandableState + numberOfChildren)) + required',
+ 'unfocused': '(tableCell2ChildLabel + tableCell2ChildToggle) or cellCheckedState + (realActiveDescendantDisplayedText or imageDescription + image) + (expandableState and (expandableState + numberOfChildren)) + required'
+ },
+ pyatspi.ROLE_TEAROFF_MENU_ITEM: {
+ 'focused': '',
+ 'unfocused': 'labelAndName + allTextSelection + roleName + availability'
+ },
+ pyatspi.ROLE_TERMINAL: {
+ 'focused': 'terminal',
+ 'unfocused': 'terminal'
+ },
+ pyatspi.ROLE_TEXT: {
+ 'focused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection',
+ 'unfocused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection'
+ },
+ pyatspi.ROLE_TOGGLE_BUTTON: {
+ 'focused': 'toggleState',
+ 'unfocused': 'labelAndName + roleName + toggleState + availability'
+ },
+ pyatspi.ROLE_PARAGRAPH: {
+ 'focused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection',
+ 'unfocused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection'
+ },
+ pyatspi.ROLE_EMBEDDED: {
+ 'focused': 'embedded',
+ 'unfocused': 'embedded'
+ },
+ }
+}
+
+class Formatting(dict):
+
+ def __init__(self, script):
+ self._script = script
+ self.update(defaultFormatting)
+
+ def getFormat(self, type, forceRole=None, **args):
+ already_focused = args.get('already_focused', False)
+ if forceRole:
+ role = forceRole
+ else:
+ role = args.get('role', None)
+ if self[type].has_key(role):
+ roleDict = self[type][role]
+ else:
+ roleDict = self[type]['default']
+ if already_focused and 'focused' in roleDict:
+ format = roleDict['focused']
+ else:
+ format = roleDict['unfocused']
+ return format
diff --git a/src/orca/script.py b/src/orca/script.py
index 563e09d..859f83a 100644
--- a/src/orca/script.py
+++ b/src/orca/script.py
@@ -42,6 +42,7 @@ __license__ = "LGPL"
import braillegenerator
import debug
import flat_review
+import formatting
import keybindings
import orca_state
import settings
@@ -86,6 +87,7 @@ class Script:
self.brailleBindings = self.getBrailleBindings()
self.app_pronunciation_dict = self.getPronunciations()
+ self.formatting = self.getFormatting()
self.brailleGenerator = self.getBrailleGenerator()
self.speechGenerator = self.getSpeechGenerator()
self.whereAmI = self.getWhereAmI()
@@ -178,6 +180,10 @@ class Script:
for command, handler in self.brailleBindings.iteritems()
if inputEventHandler == handler]
+ def getFormatting(self):
+ """Returns the formatting strings for this script."""
+ return formatting.Formatting(self)
+
def getBrailleGenerator(self):
"""Returns the braille generator for this script.
"""
diff --git a/src/orca/speechgenerator.py b/src/orca/speechgenerator.py
index 90a56b4..eb64d32 100644
--- a/src/orca/speechgenerator.py
+++ b/src/orca/speechgenerator.py
@@ -34,6 +34,7 @@ import debug
import orca_state
import rolenames
import settings
+import altspeechgenerator
from orca_i18n import _ # for gettext support
from orca_i18n import ngettext # for ngettext support
@@ -154,6 +155,8 @@ class SpeechGenerator:
self._getSpeechForTable
self.speechGenerators[pyatspi.ROLE_WINDOW] = \
self._getSpeechForWindow
+ #--- mesar----
+ self.alt = altspeechgenerator.AltSpeechGenerator(script)
def _addSpeechForObjectAccelerator(self, obj, utterances):
"""Adds an utterance that describes the keyboard accelerator for the
@@ -1873,8 +1876,16 @@ class SpeechGenerator:
generator = self.speechGenerators[role]
else:
generator = self._getDefaultSpeech
-
- return [" ".join(generator(obj, already_focused))]
+ print("processing obj of role %s\n" % obj.getRoleName())
+ result1 = [" ".join(generator(obj, already_focused))]
+ print("r%d='%s'\n" %(len(result1[0]), result1))
+
+ result2 = self.alt.getSpeech(obj, already_focused=already_focused)
+ # making the returned values from alt.getSpeech into a string.
+ speak = [" ".join(result2)]
+ print("s%d='%s'\n" %(len(speak[0]), speak))
+ print("r==s=%s\n" %cmp(result1[0], speak[0]))
+ return speak
def getSpeechContext(self, obj, stopAncestor=None):
"""Get the speech that describes the names and role of
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]