home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / python-support / gnome-orca / orca / script.py < prev    next >
Encoding:
Python Source  |  2009-04-13  |  19.8 KB  |  548 lines

  1. # Orca
  2. #
  3. # Copyright 2004-2008 Sun Microsystems Inc.
  4. #
  5. # This library is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU Library General Public
  7. # License as published by the Free Software Foundation; either
  8. # version 2 of the License, or (at your option) any later version.
  9. #
  10. # This library is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13. # Library General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Library General Public
  16. # License along with this library; if not, write to the
  17. # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
  18. # Boston MA  02110-1301 USA.
  19.  
  20. """Each script maintains a set of key bindings, braille bindings, and
  21. AT-SPI event listeners.  The key bindings are an instance of
  22. KeyBindings.  The braille bindings are also a dictionary where the
  23. keys are BrlTTY command integers and the values are instances of
  24. InputEventHandler.  The listeners field is a dictionary where the keys
  25. are AT-SPI event names and the values are function pointers.
  26.  
  27. Instances of scripts are intended to be created solely by the
  28. focus_tracking_presenter.
  29.  
  30. This Script class is not intended to be instantiated directly.
  31. Instead, it is expected that subclasses of the Script class will be
  32. created in their own module.  The module defining the Script subclass
  33. is also required to have a 'getScript(app)' method that returns an
  34. instance of the Script subclass.  See default.py for an example."""
  35.  
  36. __id__        = "$Id: script.py 4103 2008-08-15 11:07:31Z wwalker $"
  37. __version__   = "$Revision: 4103 $"
  38. __date__      = "$Date: 2008-08-15 07:07:31 -0400 (Fri, 15 Aug 2008) $"
  39. __copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
  40. __license__   = "LGPL"
  41.  
  42. import braillegenerator
  43. import debug
  44. import flat_review
  45. import keybindings
  46. import orca_state
  47. import settings
  48. import speechgenerator
  49. import structural_navigation
  50. import where_am_I
  51. import bookmarks
  52. import tutorialgenerator
  53.  
  54. class Script:
  55.     """The specific focus tracking scripts for applications.
  56.     """
  57.  
  58.     def __init__(self, app):
  59.         """Creates a script for the given application, if necessary.
  60.         This method should not be called by anyone except the
  61.         focus_tracking_presenter.
  62.  
  63.         Arguments:
  64.         - app: the Python Accessible application to create a script for
  65.         """
  66.         self.app = app
  67.  
  68.         if app:
  69.             self.name = self.app.name
  70.         else:
  71.             self.name = "default"
  72.  
  73.         self.name += " (module=" + self.__module__ + ")"
  74.         
  75.         self.listeners = self.getListeners()
  76.  
  77.         # By default, handle events for non-active applications.
  78.         #
  79.         self.presentIfInactive = True
  80.  
  81.         self.structuralNavigation = self.getStructuralNavigation()
  82.         self.inputEventHandlers = {}
  83.         self.pointOfReference = {}
  84.         self.setupInputEventHandlers()
  85.         self.keyBindings = self.getKeyBindings()
  86.         self.brailleBindings = self.getBrailleBindings()
  87.         self.app_pronunciation_dict = self.getPronunciations()
  88.  
  89.         self.brailleGenerator = self.getBrailleGenerator()
  90.         self.speechGenerator = self.getSpeechGenerator()
  91.         self.whereAmI = self.getWhereAmI()
  92.         self.bookmarks = self.getBookmarks()
  93.         self.voices = settings.voices
  94.         self.tutorialGenerator = self.getTutorialGenerator()
  95.  
  96.         self.flatReviewContextClass = flat_review.Context
  97.  
  98.         self.findCommandRun = False
  99.  
  100.         # Assists with dealing with CORBA COMM_FAILURES.  A failure doesn't
  101.         # always mean an object disappeared - there just might be a network
  102.         # glitch.  So, on COMM_FAILURES, we might retry a few times before
  103.         # giving up on an object.  This might need to be overridden by the
  104.         # script.  See bug #397787.
  105.         #
  106.         self.commFailureWaitTime = settings.commFailureWaitTime
  107.         self.commFailureAttemptLimit = settings.commFailureAttemptLimit
  108.  
  109.         debug.println(debug.LEVEL_FINE, "NEW SCRIPT: %s" % self.name)
  110.  
  111.     def getListeners(self):
  112.         """Sets up the AT-SPI event listeners for this script.
  113.  
  114.         Returns a dictionary where the keys are AT-SPI event names
  115.         and the values are script methods.
  116.         """
  117.         return {}
  118.  
  119.     def setupInputEventHandlers(self):
  120.         """Defines InputEventHandler fields for this script that can be
  121.         called by the key and braille bindings."""
  122.         pass
  123.  
  124.     def getKeyBindings(self):
  125.         """Defines the key bindings for this script.
  126.  
  127.         Returns an instance of keybindings.KeyBindings.
  128.         """
  129.         return keybindings.KeyBindings()
  130.  
  131.     def getKeyBindingsForInputHandler(self, inputEventHandler):
  132.         """ Returns a KeyBindings object with the list of KeyBindings that
  133.         matche the passed inputEventHandler as argument (at least the
  134.         inputEventHandler that has the same handler function)
  135.  
  136.         Arguments:
  137.         - inputEventHandler: an instance of input_event.InputEventHandler
  138.  
  139.         Returns an instance of keybindings.KeyBindings populated with
  140.         keybindings.KeyBinding instances that match the inputEventHandler.
  141.         """
  142.         matches = keybindings.KeyBindings()
  143.  
  144.         for binding in self.keyBindings.keyBindings:
  145.             if inputEventHandler == binding.handler:
  146.                 matches.add(binding)
  147.  
  148.         return matches
  149.  
  150.     def getBrailleBindings(self):
  151.         """Defines the braille bindings for this script.
  152.  
  153.         Returns a dictionary where the keys are BrlTTY commands and the
  154.         values are InputEventHandler instances.
  155.         """
  156.         return {}
  157.  
  158.     def getPronunciations(self):
  159.         """Defines the application specific pronunciations for this script.
  160.  
  161.         Returns a dictionary where the keys are the actual text strings and
  162.         the values are the replacement strings that are spoken instead.
  163.         """
  164.  
  165.         return {}
  166.  
  167.     def getBrailleCommandsForInputHandler(self, inputEventHandler):
  168.         """Returns a list of BrlTTY commands (they're in braille.py) that
  169.         match the given inputEventHandler passed as argument.
  170.  
  171.         Arguments:
  172.         - inputEventHandler: an instance of input_event.InputEventHandler
  173.  
  174.         Returns a list (possibly empty) of BrlTTY commands (they're in
  175.         braille.py) that match the given inputEventHandler passed.
  176.         """
  177.         return [command
  178.                 for command, handler in self.brailleBindings.iteritems()
  179.                 if inputEventHandler == handler]
  180.  
  181.     def getBrailleGenerator(self):
  182.         """Returns the braille generator for this script.
  183.         """
  184.         return braillegenerator.BrailleGenerator(self)
  185.  
  186.     def getSpeechGenerator(self):
  187.         """Returns the speech generator for this script.
  188.         """
  189.         return speechgenerator.SpeechGenerator(self)
  190.  
  191.     def getTutorialGenerator(self):
  192.         """Returns the tutorial generator for this script.
  193.         """
  194.         return tutorialgenerator.TutorialGenerator(self)
  195.  
  196.     def getEnabledStructuralNavigationTypes(self):
  197.         """Returns a list of the structural navigation object types
  198.         enabled in this script.
  199.         """
  200.         return []
  201.  
  202.     def getStructuralNavigation(self):
  203.         """Returns the 'structural navigation' class for this script.
  204.         """
  205.         types = self.getEnabledStructuralNavigationTypes()
  206.         return structural_navigation.StructuralNavigation(self, types)
  207.  
  208.     def useStructuralNavigationModel(self):
  209.         """Returns True if we should use structural navigation. Most
  210.         scripts will have no need to override this.  Gecko does however
  211.         because within an HTML document there are times when we do want
  212.         to use it and times when we don't even though it is enabled,
  213.         e.g. in a form field.
  214.         """
  215.         return self.structuralNavigation.enabled
  216.  
  217.     def getWhereAmI(self):
  218.         """Returns the "where am I" class for this script.
  219.         """
  220.         return where_am_I.WhereAmI(self)
  221.     
  222.     def echoKey(self, keyEvent):
  223.         """Determine whether this script should echo the current key event.
  224.         Note that the keyEcho() method in orca.py will still take into 
  225.         account whatever the user's various preferences for key echoing
  226.         are, which may override what is return by this echoKey() method.
  227.  
  228.         Arguments:
  229.         - keyEvent - the key event
  230.  
  231.         Returns an indication of whether a key echo event should be
  232.         allowed to happen for this script.
  233.         """
  234.  
  235.         return True
  236.  
  237.     def getBookmarks(self):
  238.         """Returns the "bookmarks" class for this script.
  239.         """
  240.         try:
  241.             return self.bookmarks 
  242.         except AttributeError:
  243.             self.bookmarks = bookmarks.Bookmarks(self)
  244.             return self.bookmarks
  245.  
  246.     def getAppPreferencesGUI(self):
  247.         """Return a GtkVBox contain the application unique configuration
  248.         GUI items for the current application.
  249.         """
  250.         return None
  251.  
  252.     def setAppPreferences(self, prefs):
  253.         """Write out the application specific preferences lines and set the
  254.         new values.
  255.  
  256.         Arguments:
  257.         - prefs: file handle for application preferences.
  258.         """
  259.         pass
  260.  
  261.     def overrideAppKeyBindings(self, script, keyBindings):
  262.         """Allow for the customization of application specific key bindings.
  263.  
  264.         Arguments:
  265.         - script: the application script.
  266.         - keyBindings: the set of key bindings for this script.
  267.         """
  268.  
  269.         return keyBindings
  270.  
  271.     def overridePronunciations(self, script, pronunciations):
  272.         """Allow for the customization of application specific pronunciations.
  273.  
  274.         Arguments:
  275.         - script: the application script.
  276.         - pronunciations: the dictionary of pronunciations for this script.
  277.         """
  278.  
  279.         return pronunciations
  280.  
  281.     def getAppState(self):
  282.         """Returns an object that can be passed to setAppState.  This
  283.         object will be used by setAppState to restore any state
  284.         information that was being maintained by the script."""
  285.         return None
  286.  
  287.     def setAppState(self, appState):
  288.         """Sets the application state using the given appState object.
  289.  
  290.         Arguments:
  291.         - appState: an object obtained from getAppState
  292.         """
  293.         return
  294.  
  295.     def getClickCount(self):
  296.         """Return the count of the number of clicks a user has made to one
  297.         of the keys on the keyboard.
  298.         """
  299.  
  300.         return orca_state.clickCount
  301.  
  302.     # [[[WDW - There is a circular reference going on somewhere (see
  303.     # bug 333168).  In the presence of this reference, the existence
  304.     # of a __del__ method prevents the garbage collector from
  305.     # collecting this object. So, we will not define a __del__ method
  306.     # until we understand where the circular reference is coming from.
  307.     #
  308.     #def __del__(self):
  309.     #    debug.println(debug.LEVEL_FINE, "DELETE SCRIPT: %s" % self.name)
  310.  
  311.     def processObjectEvent(self, event):
  312.         """Processes all AT-SPI object events of interest to this
  313.         script.  The interest in events is specified via the
  314.         'listeners' field that was defined during the construction of
  315.         this script.
  316.  
  317.         In general, the primary purpose of handling object events is to
  318.         keep track of changes to the locus of focus and notify the
  319.         orca module of these changes via orca.setLocusOfFocus and
  320.         orca.visualAppearanceChanged.
  321.  
  322.         Note that this script may be passed events it doesn't care
  323.         about, so it needs to react accordingly.
  324.  
  325.         Arguments:
  326.         - event: the Event
  327.         """
  328.  
  329.         # Check to see if we really want to process this event.
  330.         #
  331.         processEvent = (orca_state.activeScript == self \
  332.                         or self.presentIfInactive)
  333.  
  334.         if not processEvent:
  335.             return
  336.  
  337.         # This calls the first listener it finds whose key *begins with* or is
  338.         # the same as the event.type.  The reason we do this is that the event
  339.         # type in the listeners dictionary may not be as specific as the event
  340.         # type we received (e.g., the listeners dictionary might contain the
  341.         # key "object:state-changed:" and the event.type might be
  342.         # "object:state-changed:focused".  [[[TODO: WDW - the order of the
  343.         # keys is *not* deterministic, and is not guaranteed to be related
  344.         # to the order in which they were added.  So...we need to do something
  345.         # different here.  Logged as bugzilla bug 319781.]]]
  346.         #
  347.         for key in self.listeners.keys():
  348.             if event.type.startswith(key):
  349.                 self.listeners[key](event)
  350.  
  351.     def consumesKeyboardEvent(self, keyboardEvent):
  352.         """Called when a key is pressed on the keyboard.
  353.  
  354.         Arguments:
  355.         - keyboardEvent: an instance of input_event.KeyboardEvent
  356.  
  357.         Returns True if the event is of interest.
  358.         """
  359.  
  360.         user_bindings = None
  361.         user_bindings_map = settings.keyBindingsMap
  362.         if self.__module__ in user_bindings_map:
  363.             user_bindings = user_bindings_map[self.__module__]
  364.         elif "default" in user_bindings_map:
  365.             user_bindings = user_bindings_map["default"]
  366.  
  367.         consumes = False
  368.         if user_bindings:
  369.             handler = user_bindings.getInputHandler(keyboardEvent)
  370.             if handler \
  371.                  and handler.function in self.structuralNavigation.functions:
  372.                 return self.useStructuralNavigationModel()
  373.             else:
  374.                 consumes = handler != None
  375.         if not consumes:
  376.             handler = self.keyBindings.getInputHandler(keyboardEvent)
  377.             if handler \
  378.                  and handler.function in self.structuralNavigation.functions:
  379.                 return self.useStructuralNavigationModel()
  380.             else:
  381.                 consumes = handler != None
  382.         return consumes
  383.  
  384.     def processKeyboardEvent(self, keyboardEvent):
  385.         """Processes the given keyboard event.
  386.  
  387.         This method will primarily use the keybindings field of this
  388.         script instance see if this script has an interest in the
  389.         event.
  390.  
  391.         NOTE: there is latent, but unsupported, logic for allowing
  392.         the user's user-settings.py file to extend and/or override
  393.         the keybindings for a script.
  394.  
  395.         Arguments:
  396.         - keyboardEvent: an instance of input_event.KeyboardEvent
  397.         """
  398.  
  399.         # We'll annotate the event with a reference to this script.
  400.         # This will allow external scripts to muck with the script
  401.         # instance if they wish.
  402.         #
  403.         keyboardEvent.script = self
  404.  
  405.         # We'll let the user keybindings take precedence.  First, we'll
  406.         # check to see if they have keybindings specific for the particular
  407.         # application, then we'll check to see if they have any default
  408.         # bindings to use.
  409.         #
  410.         # [[[TODO: WDW - for performance, these bindings should probably
  411.         # be conflated at initialization time.]]]
  412.         #
  413.         user_bindings = None
  414.  
  415.         user_bindings_map = settings.keyBindingsMap
  416.         if self.__module__ in user_bindings_map:
  417.             user_bindings = user_bindings_map[self.__module__]
  418.         elif "default" in user_bindings_map:
  419.             user_bindings = user_bindings_map["default"]
  420.  
  421.         consumed = False
  422.         if user_bindings:
  423.             consumed = user_bindings.consumeKeyboardEvent(self,
  424.                                                           keyboardEvent)
  425.         if not consumed:
  426.             consumed = self.keyBindings.consumeKeyboardEvent(self,
  427.                                                              keyboardEvent)
  428.         return consumed
  429.  
  430.     def consumesBrailleEvent(self, brailleEvent):
  431.         """Called when a key is pressed on the braille display.
  432.  
  433.         Arguments:
  434.         - brailleEvent: an instance of input_event.KeyboardEvent
  435.  
  436.         Returns True if the event is of interest.
  437.         """
  438.         user_bindings = None
  439.         user_bindings_map = settings.brailleBindingsMap
  440.         if self.__module__ in user_bindings_map:
  441.             user_bindings = user_bindings_map[self.__module__]
  442.         elif "default" in user_bindings_map:
  443.             user_bindings = user_bindings_map["default"]
  444.  
  445.         command = brailleEvent.event
  446.         consumes = False
  447.         if user_bindings:
  448.             consumes = command in user_bindings
  449.         if not consumes:
  450.             consumes = command in self.brailleBindings
  451.         return consumes
  452.  
  453.     def processBrailleEvent(self, brailleEvent):
  454.         """Called whenever a key is pressed on the Braille display.
  455.  
  456.         This method will primarily use the brailleBindings field of
  457.         this script instance see if this script has an interest in the
  458.         event.
  459.  
  460.         NOTE: there is latent, but unsupported, logic for allowing
  461.         the user's user-settings.py file to extend and/or override
  462.         the brailleBindings for a script.
  463.  
  464.         Arguments:
  465.         - brailleEvent: an instance of input_event.BrailleEvent
  466.         """
  467.  
  468.         # We'll annotate the event with a reference to this script.
  469.         # This will allow external scripts to muck with the script
  470.         # instance if they wish.
  471.         #
  472.         brailleEvent.script = self
  473.  
  474.         # We'll let the user bindings take precedence.  First, we'll
  475.         # check to see if they have bindings specific for the particular
  476.         # application, then we'll check to see if they have any default
  477.         # bindings to use.
  478.         #
  479.         # [[[TODO: WDW - for performance, these bindings should probably
  480.         # be conflated at initialization time.]]]
  481.         #
  482.         consumed = False
  483.         user_bindings = None
  484.         command = brailleEvent.event
  485.  
  486.         user_bindings_map = settings.brailleBindingsMap
  487.         if self.name in user_bindings_map:
  488.             user_bindings = user_bindings_map[self.name]
  489.         elif "default" in user_bindings_map:
  490.             user_bindings = user_bindings_map["default"]
  491.  
  492.         if user_bindings and command in user_bindings:
  493.             handler = user_bindings[command]
  494.             consumed = handler.processInputEvent(self, brailleEvent)
  495.  
  496.         if (not consumed) and command in self.brailleBindings:
  497.             handler = self.brailleBindings[command]
  498.             consumed = handler.processInputEvent(self, brailleEvent)
  499.  
  500.         return consumed
  501.  
  502.     def locusOfFocusChanged(self, event, oldLocusOfFocus, newLocusOfFocus):
  503.         """Called when the visual object with focus changes.
  504.  
  505.         The primary purpose of this method is to present locus of focus
  506.         information to the user.
  507.  
  508.         NOTE: scripts should not call this method directly.  Instead,
  509.         a script should call orca.setLocusOfFocus, which will eventually
  510.         result in this method being called.
  511.  
  512.         Arguments:
  513.         - event: if not None, the Event that caused the change
  514.         - oldLocusOfFocus: Accessible that is the old locus of focus
  515.         - newLocusOfFocus: Accessible that is the new locus of focus
  516.         """
  517.         pass
  518.  
  519.     def visualAppearanceChanged(self, event, obj):
  520.         """Called when the visual appearance of an object changes.
  521.         This method should not be called for objects whose visual
  522.         appearance changes solely because of focus -- setLocusOfFocus
  523.         is used for that.  Instead, it is intended mostly for objects
  524.         whose notional 'value' has changed, such as a checkbox
  525.         changing state, a progress bar advancing, a slider moving,
  526.         text inserted, caret moved, etc.
  527.  
  528.         The primary purpose of this method is to present the changed
  529.         information to the user.
  530.  
  531.         NOTE: scripts should not call this method directly.  Instead,
  532.         a script should call orca.visualAppearanceChanged, which will
  533.         eventually result in this method being called.
  534.  
  535.         Arguments:
  536.         - event: if not None, the Event that caused this to happen
  537.         - obj: the Accessible whose visual appearance changed.
  538.         """
  539.         pass
  540.  
  541.     def activate(self):
  542.         """Called when this script is activated."""
  543.         pass
  544.  
  545.     def deactivate(self):
  546.         """Called when this script is deactivated."""
  547.         pass
  548.