[orca] More updates to Mesar's patch for bgo#570658



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]