orca r4016 - in trunk: . po src/orca src/orca/scripts/toolkits src/orca/scripts/toolkits/J2SE-access-bridge



Author: wwalker
Date: Tue Jul  1 17:40:13 2008
New Revision: 4016
URL: http://svn.gnome.org/viewvc/orca?rev=4016&view=rev

Log:
Work on bug #435623 - Java platform accessibility.


Added:
   trunk/src/orca/scripts/toolkits/J2SE-access-bridge/
   trunk/src/orca/scripts/toolkits/J2SE-access-bridge/Makefile.am
   trunk/src/orca/scripts/toolkits/J2SE-access-bridge/__init__.py
   trunk/src/orca/scripts/toolkits/J2SE-access-bridge/braillegenerator.py
   trunk/src/orca/scripts/toolkits/J2SE-access-bridge/script.py
   trunk/src/orca/scripts/toolkits/J2SE-access-bridge/speechgenerator.py
   trunk/src/orca/scripts/toolkits/J2SE-access-bridge/where_am_I.py
Removed:
   trunk/src/orca/scripts/toolkits/J2SE-access-bridge.py
Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/po/POTFILES.in
   trunk/src/orca/braillegenerator.py
   trunk/src/orca/default.py
   trunk/src/orca/orca.py
   trunk/src/orca/scripts/toolkits/Makefile.am

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Tue Jul  1 17:40:13 2008
@@ -187,6 +187,7 @@
 src/orca/scripts/apps/gnome-window-properties/Makefile
 src/orca/scripts/toolkits/Makefile
 src/orca/scripts/toolkits/Gecko/Makefile
+src/orca/scripts/toolkits/J2SE-access-bridge/Makefile
 src/orca/orca
 src/orca/orca_i18n.py
 src/orca/platform.py

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Tue Jul  1 17:40:13 2008
@@ -60,7 +60,8 @@
 src/orca/scripts/toolkits/Gecko/speech_generator.py
 src/orca/scripts/toolkits/Gecko/structural_navigation.py
 src/orca/scripts/toolkits/Gecko/where_am_i.py
-src/orca/scripts/toolkits/J2SE-access-bridge.py
+src/orca/scripts/toolkits/J2SE-access-bridge/braillegenerator.py
+src/orca/scripts/toolkits/J2SE-access-bridge/speechgenerator.py
 src/orca/settings.py
 src/orca/speechdispatcherfactory.py
 src/orca/speechgenerator.py

Modified: trunk/src/orca/braillegenerator.py
==============================================================================
--- trunk/src/orca/braillegenerator.py	(original)
+++ trunk/src/orca/braillegenerator.py	Tue Jul  1 17:40:13 2008
@@ -1719,7 +1719,22 @@
             if (row >= 0) \
                 and (not obj.getRole() in [pyatspi.ROLE_ROW_HEADER,
                                            pyatspi.ROLE_TABLE_ROW_HEADER]):
+                # Get the header information.  In Java Swing, the
+                # information is not exposed via the description
+                # but is instead a header object, so we fall back
+                # to that if it exists.
+                #
+                # [[[TODO: WDW - the more correct thing to do, I 
+                # think, is to look at the row header object.
+                # We've been looking at the description for so 
+                # long, though, that we'll give the description 
+                # preference for now.]]]
+                #
                 desc = table.getRowDescription(row)
+                if not desc:
+                    header = table.getRowHeader(row)
+                    if header:
+                        desc = self._script.getDisplayedText(header)
             else:
                 desc = None
             if desc and len(desc):
@@ -1740,7 +1755,22 @@
             if (col >= 0) \
                 and (not obj.getRole() in [pyatspi.ROLE_COLUMN_HEADER,
                                            pyatspi.ROLE_TABLE_COLUMN_HEADER]):
+                # Get the header information.  In Java Swing, the
+                # information is not exposed via the description
+                # but is instead a header object, so we fall back
+                # to that if it exists.
+                #
+                # [[[TODO: WDW - the more correct thing to do, I 
+                # think, is to look at the row header object.
+                # We've been looking at the description for so 
+                # long, though, that we'll give the description 
+                # preference for now.]]]
+                #
                 desc = table.getColumnDescription(col)
+                if not desc:
+                    header = table.getColumnHeader(col)
+                    if header:
+                        desc = self._script.getDisplayedText(header)
             else:
                 desc = None
             if desc and len(desc):

Modified: trunk/src/orca/default.py
==============================================================================
--- trunk/src/orca/default.py	(original)
+++ trunk/src/orca/default.py	Tue Jul  1 17:40:13 2008
@@ -2754,15 +2754,21 @@
             # We also keep track of tree level depth and only announce
             # that if it changes.
             #
+            # Note that Java Swing allows things like ROLE_LABEL objects
+            # in trees and tables, so we'll check the parent's role to 
+            # see if it is a table.
+            #
             oldNodeLevel = -1
             newNodeLevel = -1
-            if newLocusOfFocus.getRole() == pyatspi.ROLE_TABLE_CELL:
+            if (newLocusOfFocus.getRole() == pyatspi.ROLE_TABLE_CELL) \
+               or (newParent.getRole() == pyatspi.ROLE_TABLE):
                 try:
                     table = oldParent.queryTable()
                 except:
                     table = None
                 if table and \
-                      oldLocusOfFocus.getRole() == pyatspi.ROLE_TABLE_CELL:
+                      ((oldLocusOfFocus.getRole() == pyatspi.ROLE_TABLE_CELL) \
+                       or (oldParent.getRole() == pyatspi.ROLE_TABLE)):
                     index = self.getCellIndex(oldLocusOfFocus)
                     oldRow = table.getRowAtIndex(index)
                     oldCol = table.getColumnAtIndex(index)
@@ -2780,7 +2786,22 @@
                     newCol = table.getColumnAtIndex(index)
 
                     if (newRow != oldRow) or (oldParent != newParent):
+                        # Get the header information.  In Java Swing, the
+                        # information is not exposed via the description
+                        # but is instead a header object, so we fall back
+                        # to that if it exists.
+                        #
+                        # [[[TODO: WDW - the more correct thing to do, I 
+                        # think, is to look at the row header object.
+                        # We've been looking at the description for so 
+                        # long, though, that we'll give the description 
+                        # preference for now.]]]
+                        #
                         desc = table.getRowDescription(newRow)
+                        if not desc:
+                            header = table.getRowHeader(newRow)
+                            if header:
+                                desc = self.getDisplayedText(header)
                         if desc and len(desc):
                             text = desc
                             if settings.speechVerbosityLevel \
@@ -2794,7 +2815,22 @@
                         # it's not possible to navigate across a row.
                         topName = self.getTopLevelName(newLocusOfFocus)
                         if not topName.endswith(" - Thunderbird"):
+                            # Get the header information.  In Java Swing, the
+                            # information is not exposed via the description
+                            # but is instead a header object, so we fall back
+                            # to that if it exists.
+                            #
+                            # [[[TODO: WDW - the more correct thing to do, I 
+                            # think, is to look at the row header object.
+                            # We've been looking at the description for so 
+                            # long, though, that we'll give the description 
+                            # preference for now.]]]
+                            #
                             desc = table.getColumnDescription(newCol)
+                            if not desc:
+                                header = table.getColumnHeader(newCol)
+                                if header:
+                                    desc = self.getDisplayedText(header)
                             cellText = self.getDisplayedText(newLocusOfFocus)
                             if desc and len(desc) and cellText != desc:
                                 text = desc
@@ -3046,7 +3082,7 @@
                             self.speechGenerator.getSpeech(target, True))
                         return
 
-        if obj != orca_state.locusOfFocus:
+        if not self.isSameObject(obj, orca_state.locusOfFocus):
             return
 
         if event:
@@ -3279,8 +3315,11 @@
 
         return selSpoken
 
-    def _presentTextAtNewCaretPosition(self, event):
-        obj = event.source
+    def _presentTextAtNewCaretPosition(self, event, otherObj=None):
+        """Updates braille, magnification, and outputs speech for the 
+        event.source or the otherObj."""
+
+        obj = otherObj or event.source
         text = obj.queryText()
 
         if obj:

Modified: trunk/src/orca/orca.py
==============================================================================
--- trunk/src/orca/orca.py	(original)
+++ trunk/src/orca/orca.py	Tue Jul  1 17:40:13 2008
@@ -607,7 +607,9 @@
 
 def _setClickCount(inputEvent):
     """Sets the count of the number of clicks a user has made to one
-    of the non-modifier keys on the keyboard.
+    of the non-modifier keys on the keyboard.  Note that this looks at
+    the event_string (keysym) instead of hw_code (keycode) because
+    the Java platform gives us completely different keycodes for keys.
 
     Arguments:
     - inputEvent: the current input event.
@@ -621,7 +623,7 @@
         orca_state.clickCount = 0
     elif not isinstance(lastInputEvent, KeyboardEvent):
         orca_state.clickCount = 1
-    elif (lastInputEvent.hw_code != inputEvent.hw_code) or \
+    elif (lastInputEvent.event_string != inputEvent.event_string) or \
          (lastInputEvent.modifiers != inputEvent.modifiers):
         orca_state.clickCount = 1
     elif (inputEvent.time - lastInputEvent.time) < \

Added: trunk/src/orca/scripts/toolkits/J2SE-access-bridge/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/orca/scripts/toolkits/J2SE-access-bridge/Makefile.am	Tue Jul  1 17:40:13 2008
@@ -0,0 +1,11 @@
+orca_pathdir=$(pyexecdir)
+
+orca_python_PYTHON = \
+	__init__.py \
+	braillegenerator.py \
+	script.py \
+	speechgenerator.py \
+	where_am_I.py
+
+orca_pythondir=$(pyexecdir)/orca/scripts/toolkits/J2SE-access-bridge
+

Added: trunk/src/orca/scripts/toolkits/J2SE-access-bridge/__init__.py
==============================================================================
--- (empty file)
+++ trunk/src/orca/scripts/toolkits/J2SE-access-bridge/__init__.py	Tue Jul  1 17:40:13 2008
@@ -0,0 +1,4 @@
+from script import Script
+from speechgenerator import SpeechGenerator
+from braillegenerator import BrailleGenerator
+from where_am_I import WhereAmI

Added: trunk/src/orca/scripts/toolkits/J2SE-access-bridge/braillegenerator.py
==============================================================================
--- (empty file)
+++ trunk/src/orca/scripts/toolkits/J2SE-access-bridge/braillegenerator.py	Tue Jul  1 17:40:13 2008
@@ -0,0 +1,89 @@
+# Orca
+#
+# Copyright 2006-2008 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.
+
+__id__        = "$Id: J2SE-access-bridge.py 3882 2008-05-07 18:22:10Z richb $"
+__version__   = "$Revision: 3882 $"
+__date__      = "$Date: 2008-05-07 14:22:10 -0400 (Wed, 07 May 2008) $"
+__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import pyatspi
+
+import orca.braille as braille
+import orca.braillegenerator as braillegenerator
+
+from orca.orca_i18n import _ # for gettext support
+
+########################################################################
+#                                                                      #
+# Braille Generator                                                    #
+#                                                                      #
+########################################################################
+
+class BrailleGenerator(braillegenerator.BrailleGenerator):
+    def __init__(self, script):
+        braillegenerator.BrailleGenerator.__init__(self, script)
+
+    def _getBrailleRegionsForLabel(self, obj):
+        """Get the braille for a label.
+
+        Arguments:
+        - obj: the label
+
+        Returns a list where the first element is a list of Regions to display
+        and the second element is the Region which should get focus.
+        """
+
+        self._debugGenerator("J2SE-access-bridge:_getBrailleRegionsForLabel",
+                             obj)
+
+        regions = []
+
+        text = self._script.getDisplayedText(obj)
+
+        # In Java, tree objects are labels, so we need to look at their
+        # states in order to tell whether they are expanded or collapsed.
+        #
+        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.
+                #
+                text = self._script.appendString(text, _('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.
+                #
+                text = self._script.appendString(text, _('collapsed'))
+
+        level = self._script.getNodeLevel(obj)
+        if level >= 0:
+            # Translators: this represents the depth of a node in a tree
+            # view (i.e., how many ancestors a node has).
+            #
+            text = self._script.appendString(text,
+                                             _("TREE LEVEL %d") % (level + 1))
+
+        region = braille.Component(obj, text)
+        regions.append(region)
+
+        return [regions, region]

Added: trunk/src/orca/scripts/toolkits/J2SE-access-bridge/script.py
==============================================================================
--- (empty file)
+++ trunk/src/orca/scripts/toolkits/J2SE-access-bridge/script.py	Tue Jul  1 17:40:13 2008
@@ -0,0 +1,305 @@
+# Orca
+#
+# Copyright 2006-2008 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.
+
+__id__        = "$Id: J2SE-access-bridge.py 3882 2008-05-07 18:22:10Z richb $"
+__version__   = "$Revision: 3882 $"
+__date__      = "$Date: 2008-05-07 14:22:10 -0400 (Wed, 07 May 2008) $"
+__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import pyatspi
+
+import orca.default as default
+import orca.input_event as input_event
+import orca.orca as orca
+import orca.orca_state as orca_state
+import orca.keybindings as keybindings
+
+from braillegenerator import BrailleGenerator
+from speechgenerator import SpeechGenerator
+from where_am_I import WhereAmI
+
+########################################################################
+#                                                                      #
+# The Java script class.                                               #
+#                                                                      #
+########################################################################
+
+class Script(default.Script):
+
+    def __init__(self, app):
+        """Creates a new script for Java applications.
+
+        Arguments:
+        - app: the application to create a script for.
+        """
+        default.Script.__init__(self, app)
+
+    def getWhereAmI(self):
+        """Returns the "where am I" class for this script.
+        """
+        return WhereAmI(self)
+
+    def getBrailleGenerator(self):
+        """Returns the braille generator for this script.
+        """
+        return BrailleGenerator(self)
+
+    def getSpeechGenerator(self):
+        """Returns the braille generator for this script.
+        """
+        return SpeechGenerator(self)
+
+    def consumesKeyboardEvent(self, keyboardEvent):
+        """Called when a key is pressed on the keyboard.
+
+        Arguments:
+        - keyboardEvent: an instance of input_event.KeyboardEvent
+
+        Returns True if the event is of interest.
+        """
+
+        # The Java platform chooses to give us keycodes different from
+        # the native platform keycodes.  So, we hack here by converting
+        # the keysym we get from Java into a keycode.
+
+        keysym = keyboardEvent.event_string
+
+        # We need to make sure we have a keysym-like thing.  The space
+        # character is not a keysym, so we convert it into the string,
+        # 'space', which is.
+        #
+        if keysym == " ":
+            keysym = "space"
+
+        keyboardEvent.hw_code = keybindings.getKeycode(keysym)
+        return default.Script.consumesKeyboardEvent(self, keyboardEvent)
+
+    def getNodeLevel(self, obj):
+        """Determines the node level of this object if it is in a tree
+        relation, with 0 being the top level node.  If this object is
+        not in a tree relation, then -1 will be returned.
+
+        Arguments:
+        -obj: the Accessible object
+        """
+
+        if not obj:
+            return -1
+
+        treeLikeThing = self.getAncestor(obj,
+                                         [pyatspi.ROLE_TREE,
+                                          pyatspi.ROLE_TABLE,
+                                          pyatspi.ROLE_TREE_TABLE],
+                                         None)
+        if not treeLikeThing:
+            return -1
+
+        count = 0
+        while True:
+            state = obj.getState()
+            if state.contains(pyatspi.STATE_EXPANDABLE) \
+               or state.contains(pyatspi.STATE_COLLAPSED):
+                if state.contains(pyatspi.STATE_VISIBLE):
+                    count += 1
+                obj = obj.parent
+            else:
+                break
+
+        return count - 1
+
+    def onFocus(self, event):
+        """Called whenever an object gets focus.
+
+        Arguments:
+        - event: the Event
+        """
+
+        role = event.source.getRole()
+
+        if role == pyatspi.ROLE_MENU:
+            # Override default.py's onFocus decision to ignore focus
+            # events on MENU items with selected children.  This is
+            # because JMenu's pop up without their children selected,
+            # but for some reason they always have
+            # selection.nSelectedChildren > 0.  I suspect this is a
+            # bug in JMenu.java:getAccessibleSelectionCount, but the
+            # details of Swing's MenuSelectionManager are foreign to
+            # me.  So, for now, we'll just be happy knowing that
+            # Java's menu items will give us focus events when they
+            # are selected.
+            #
+            orca.setLocusOfFocus(event, event.source)
+            return
+
+        default.Script.onFocus(self, event)
+
+    def onActiveDescendantChanged(self, event):
+        """Called when an object who manages its own descendants detects a
+        change in one of its children.
+
+        Arguments:
+        - event: the Event
+        """
+
+        # In Java comboboxes, when the list of options is popped up via
+        # an up or down action, control (but not focus) goes to a LIST
+        # object that manages the descendants.  So, we detect that here
+        # and keep focus on the combobox.
+        #
+        if event.source.getRole() == pyatspi.ROLE_COMBO_BOX:
+            orca.visualAppearanceChanged(event, event.source)
+            return
+
+        if event.source.getRole() == pyatspi.ROLE_LIST:
+            combobox = self.getAncestor(event.source,
+                                        [pyatspi.ROLE_COMBO_BOX],
+                                        [pyatspi.ROLE_PANEL])
+            if combobox:
+                orca.visualAppearanceChanged(event, combobox)
+                return
+
+        default.Script.onActiveDescendantChanged(self, event)
+
+    def onCaretMoved(self, event):
+        # Java's SpinButtons are the most caret movement happy thing
+        # I've seen to date.  If you Up or Down on the keyboard to
+        # change the value, they typically emit three caret movement
+        # events, first to the beginning, then to the end, and then
+        # back to the beginning.  It's a very excitable little widget.
+        # Luckily, it only issues one value changed event.  So, we'll
+        # ignore caret movement events caused by value changes and
+        # just process the single value changed event.
+        #
+        isSpinBox = self.isDesiredFocusedItem(event.source,
+                                              [pyatspi.ROLE_TEXT,
+                                               pyatspi.ROLE_PANEL,
+                                               pyatspi.ROLE_SPIN_BUTTON])
+        if isSpinBox:
+            if isinstance(orca_state.lastInputEvent,
+                          input_event.KeyboardEvent):
+                eventStr = orca_state.lastNonModifierKeyEvent.event_string
+            else:
+                eventStr = None
+            if (eventStr in ["Up", "Down"]) \
+               or isinstance(orca_state.lastInputEvent,
+                             input_event.MouseButtonEvent):
+                return
+
+        default.Script.onCaretMoved(self, event)
+
+    def onSelectionChanged(self, event):
+        """Called when an object's selection changes.
+
+        Arguments:
+        - event: the Event
+        """
+
+        # Ignore selection in TREE and TABLE objects since they send us
+        # an active descendant changed event.
+        #
+        if event.source.getRole() in [pyatspi.ROLE_TREE, pyatspi.ROLE_TABLE]:
+            return
+
+        default.Script.onSelectionChanged(self, event)
+
+    def onStateChanged(self, event):
+        """Called whenever an object's state changes.
+
+        Arguments:
+        - event: the Event
+        """
+
+        # Handle state changes when JTree labels become expanded
+        # or collapsed.
+        #
+        if (event.source.getRole() == pyatspi.ROLE_LABEL) and \
+            event.type.startswith("object:state-changed:expanded"):
+            orca.visualAppearanceChanged(event, event.source)
+            return
+
+        # This is a workaround for a java-access-bridge bug (Bug 355011)
+        # where popup menu events are not sent to Orca.
+        #
+        # When a root pane gets focus, a popup menu may have been invoked.
+        # If there is a popup menu, give locus of focus to the armed menu
+        # item.
+        #
+        if event.source.getRole() == pyatspi.ROLE_ROOT_PANE and \
+               event.type.startswith("object:state-changed:focused") and \
+               event.detail1 == 1:
+
+            for child in event.source:
+                # search the layered pane for a popup menu
+                if child.getRole() == pyatspi.ROLE_LAYERED_PANE:
+                    popup = self.findByRole(child,
+                                            pyatspi.ROLE_POPUP_MENU, False)
+                    if len(popup) > 0:
+                        # set the locus of focus to the armed menu item
+                        items = self.findByRole(popup[0],
+                                                pyatspi.ROLE_MENU_ITEM, False)
+                        for item in items:
+                            if item.getState().contains(pyatspi.STATE_ARMED):
+                                orca.setLocusOfFocus(event, item)
+                                return
+
+        # Present a value change in case of an focused popup menu.
+        # Fix for Swing file chooser.
+        #
+        if event.type.startswith("object:state-changed:visible") and \
+                event.source.getRole() == pyatspi.ROLE_POPUP_MENU and \
+                event.source.parent.getState().contains(pyatspi.STATE_FOCUSED):
+            orca.setLocusOfFocus(event, event.source.parent)
+            return
+
+        default.Script.onStateChanged(self, event)
+
+    def onValueChanged(self, event):
+        """Called whenever an object's value changes.
+
+        Arguments:
+        - event: the Event
+        """
+
+        # We'll ignore value changed events for Java's toggle buttons since
+        # they also send a redundant object:state-changed:checked event.
+        #
+        if event.source.getRole() == pyatspi.ROLE_TOGGLE_BUTTON:
+            return
+
+        # Java's SpinButtons are the most caret movement happy thing
+        # I've seen to date.  If you Up or Down on the keyboard to
+        # change the value, they typically emit three caret movement
+        # events, first to the beginning, then to the end, and then
+        # back to the beginning.  It's a very excitable little widget.
+        # Luckily, it only issues one value changed event.  So, we'll
+        # ignore caret movement events caused by value changes and
+        # just process the single value changed event.
+        #
+        if event.source.getRole() == pyatspi.ROLE_SPIN_BUTTON:
+            try:
+                thisBox = orca_state.locusOfFocus.parent.parent == event.source
+            except:
+                thisBox = False
+            if thisBox:
+                self._presentTextAtNewCaretPosition(event,
+                                                    orca_state.locusOfFocus)
+                return
+
+        default.Script.onValueChanged(self, event)

Added: trunk/src/orca/scripts/toolkits/J2SE-access-bridge/speechgenerator.py
==============================================================================
--- (empty file)
+++ trunk/src/orca/scripts/toolkits/J2SE-access-bridge/speechgenerator.py	Tue Jul  1 17:40:13 2008
@@ -0,0 +1,141 @@
+# Orca
+#
+# Copyright 2006-2008 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.
+
+__id__        = "$Id: J2SE-access-bridge.py 3882 2008-05-07 18:22:10Z richb $"
+__version__   = "$Revision: 3882 $"
+__date__      = "$Date: 2008-05-07 14:22:10 -0400 (Wed, 07 May 2008) $"
+__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import pyatspi
+
+import orca.rolenames as rolenames
+import orca.speechgenerator as speechgenerator
+
+from orca.orca_i18n import _ # for gettext support
+
+########################################################################
+#                                                                      #
+# Speech Generator                                                     #
+#                                                                      #
+########################################################################
+
+class SpeechGenerator(speechgenerator.SpeechGenerator):
+    def __init__(self, script):
+        speechgenerator.SpeechGenerator.__init__(self, script)
+
+    def _getSpeechForLabel(self, obj, already_focused):
+        """Get the speech for a label.
+
+        Arguments:
+        - obj: the label
+        - already_focused: False if object just received focus
+
+        Returns a list of utterances to be spoken for the object.
+        """
+
+        utterances = []
+        if (not already_focused):
+            text = self._script.getDisplayedText(obj)
+            if not text:
+                text = rolenames.getSpeechForRoleName(obj)
+            if text:
+                utterances.append(text)
+
+        # In Java, tree objects are labels, so we need to look at their
+        # states in order to tell whether they are expanded or collapsed.
+        #
+        state = obj.getState()
+        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.
+            #
+            utterances.append(_("expanded"))
+        elif not state.contains(pyatspi.STATE_EXPANDED) and \
+                 state.contains(pyatspi.STATE_EXPANDABLE):
+            # Translators: this represents the state of a node in a tree.
+            # 'expanded' means the children are showing.
+            # 'collapsed' means the children are not showing.
+            #
+            utterances.append(_("collapsed"))
+
+        self._debugGenerator("J2SE-access-bridge:_getSpeechForLabel",
+                             obj,
+                             already_focused,
+                             utterances)
+
+        return utterances
+
+    def getSpeechContext(self, obj, stopAncestor=None):
+        """This method is identical to speechgeneratior.getSpeechContext
+        with one exception. The following test in
+        speechgenerator.getSpeechContext:
+
+            if not text and 'Text' in pyatspi.listInterfaces(parent):
+                text = self._script.getDisplayedText(parent)
+
+        has be replaced by
+
+           if not text:
+               text = self._script.getDisplayedText(parent)
+
+        The Swing toolkit has labelled panels that do not implement the
+        AccessibleText interface, but getDisplayedText returns
+        a meaningful string that needs to be used if getDisplayedLabel
+        returns None.
+        """
+
+        utterances = []
+
+        if not obj:
+            return utterances
+
+        if obj == stopAncestor:
+            return utterances
+
+        parent = obj.parent
+        if parent \
+            and (obj.getRole() == pyatspi.ROLE_TABLE_CELL) \
+            and (parent.getRole() == pyatspi.ROLE_TABLE_CELL):
+            parent = parent.parent
+
+        while parent and (parent.parent != parent):
+            if parent == stopAncestor:
+                break
+            if not self._script.isLayoutOnly(parent):
+                text = self._script.getDisplayedLabel(parent)
+                if not text and (parent.getRole() == pyatspi.ROLE_PANEL):
+                    text = self._script.getDisplayedText(parent)
+                if text and len(text.strip()):
+                    # Push announcement of cell to the end
+                    #
+                    if parent.getRole() not in [pyatspi.ROLE_TABLE_CELL,
+                                                pyatspi.ROLE_FILLER]:
+                        utterances.append(\
+                            rolenames.getSpeechForRoleName(parent))
+                    utterances.append(text)
+                    if parent.getRole() == pyatspi.ROLE_TABLE_CELL:
+                        utterances.append(\
+                            rolenames.getSpeechForRoleName(parent))
+            parent = parent.parent
+
+        utterances.reverse()
+
+        return utterances

Added: trunk/src/orca/scripts/toolkits/J2SE-access-bridge/where_am_I.py
==============================================================================
--- (empty file)
+++ trunk/src/orca/scripts/toolkits/J2SE-access-bridge/where_am_I.py	Tue Jul  1 17:40:13 2008
@@ -0,0 +1,55 @@
+# Orca
+#
+# Copyright 2006-2008 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.
+
+__id__        = "$Id: J2SE-access-bridge.py 3882 2008-05-07 18:22:10Z richb $"
+__version__   = "$Revision: 3882 $"
+__date__      = "$Date: 2008-05-07 14:22:10 -0400 (Wed, 07 May 2008) $"
+__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import pyatspi
+
+import orca.where_am_I as where_am_I
+
+########################################################################
+#                                                                      #
+# Custom WhereAmI                                                      #
+#                                                                      #
+########################################################################
+
+class WhereAmI(where_am_I.WhereAmI):
+    def __init__(self, script):
+        where_am_I.WhereAmI.__init__(self, script)
+
+    def whereAmI(self, obj, basicOnly):
+        """Calls the base class method for basic information and Java
+        specific presentation methods for detailed/custom information.
+        """
+
+        # If we're in the text area of a spin button, then we'll do the
+        # where am I for the spin button.
+        #
+        if obj and obj.getRole() == pyatspi.ROLE_TEXT:
+            spinbox = self._script.getAncestor(obj,
+                                               [pyatspi.ROLE_SPIN_BUTTON],
+                                               None)
+            if spinbox:
+                obj = spinbox
+
+        where_am_I.WhereAmI.whereAmI(self, obj, basicOnly)

Modified: trunk/src/orca/scripts/toolkits/Makefile.am
==============================================================================
--- trunk/src/orca/scripts/toolkits/Makefile.am	(original)
+++ trunk/src/orca/scripts/toolkits/Makefile.am	Tue Jul  1 17:40:13 2008
@@ -1,11 +1,10 @@
-SUBDIRS = Gecko
+SUBDIRS = Gecko J2SE-access-bridge
 
 orca_pathdir=$(pyexecdir)
 
 orca_python_PYTHON = \
 	__init__.py \
 	GAIL.py \
-	J2SE-access-bridge.py \
 	VCL.py
 
 orca_pythondir=$(pyexecdir)/orca/scripts/toolkits



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