# Orca # # Copyright 2010 Joanmarie Diggs. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Boston MA 02110-1301 USA. """Custom script for Instantbird.""" __id__ = "$Id$" __version__ = "$Revision$" __date__ = "$Date$" __copyright__ = "Copyright (c) 2010 Joanmarie Diggs." __license__ = "LGPL" import pyatspi import orca.bookmarks as bookmarks import orca.scripts.default as default import orca.orca as orca import orca.settings_manager as settings_manager import orca.orca_state as orca_state import orca.scripts.toolkits.Gecko as Gecko from .chat import Chat from .script_utilities import Utilities _settingsManager = settings_manager.getManager() ######################################################################## # # # The Instantbird script class. # # # ######################################################################## class Script(Gecko.Script): def __init__(self, app): """Creates a new script for the given application.""" # So we can take an educated guess at identifying the buddy list. # self._buddyListAncestries = [[pyatspi.ROLE_LIST, pyatspi.ROLE_FRAME]] Gecko.Script.__init__(self, app) def getBookmarks(self): """Returns the "bookmarks" class for this script.""" # This is a copy of orca.script.getBookmarks(). It's here to # prevent the Gecko script's from being used. # try: return self.bookmarks except AttributeError: self.bookmarks = bookmarks.Bookmarks(self) return self.bookmarks def getChat(self): """Returns the 'chat' class for this script.""" return Chat(self, self._buddyListAncestries) def getUtilities(self): """Returns the utilites for this script.""" return Utilities(self) def getEnabledStructuralNavigationTypes(self): """Returns a list of the structural navigation object types enabled in this script. """ return [] def setupInputEventHandlers(self): """Defines InputEventHandler fields for this script that can be called by the key and braille bindings. Here we need to add the handlers for chat functionality. """ Gecko.Script.setupInputEventHandlers(self) self.inputEventHandlers.update(self.chat.inputEventHandlers) def getAppKeyBindings(self): """Returns the application-specific keybindings for this script.""" return self.chat.keyBindings def getAppPreferencesGUI(self): """Return a GtkGrid containing the application unique configuration GUI items for the current application. The chat-related options get created by the chat module.""" return self.chat.getAppPreferencesGUI() def getPreferencesFromGUI(self): """Returns a dictionary with the app-specific preferences.""" return self.chat.getPreferencesFromGUI() def onTextDeleted(self, event): """Called whenever text is deleted from an object. Arguments: - event: the Event """ default.Script.onTextDeleted(self, event) def onTextInserted(self, event): """Called whenever text is added to an object.""" if self.chat.presentInsertedText(event): return default.Script.onTextInserted(self, event) def onCaretMoved(self, event): """Caret movement in Gecko is somewhat unreliable and unpredictable, but we need to handle it. When we detect caret movement, we make sure we update our own notion of the caret position: our caretContext is an [obj, characterOffset] that points to our current item and character (if applicable) of interest. If our current item doesn't implement the accessible text specialization, the characterOffset value is meaningless (and typically -1).""" if self.utilities.inDocumentContent(event.source): orca.setLocusOfFocus(event, event.source) Gecko.Script.onCaretMoved(self, event) else: default.Script.onCaretMoved(self, event) def onChildrenAdded(self, event): """Callback for object:children-changed:add accessibility events.""" return def onDocumentLoadComplete(self, event): """Called when a web page load is completed.""" return def onDocumentLoadStopped(self, event): """Called when a web page load is interrupted.""" return def onNameChanged(self, event): """Called whenever a property on an object changes. Arguments: - event: the Event """ default.Script.onNameChanged(self, event) def onFocusedChanged(self, event): """Callback for object:state-changed:focused accessibility events.""" # This seems to be the most reliable way to identify that the # active chatroom was changed via keyboard from within the entry. # In this case, speak and flash braille the new room name. # if orca_state.locusOfFocus and event.source \ and orca_state.locusOfFocus.getRole() == pyatspi.ROLE_ENTRY \ and event.source.getRole() == pyatspi.ROLE_ENTRY \ and orca_state.locusOfFocus != event.source: room1 = self.chat.getChatRoomName(orca_state.locusOfFocus) room2 = self.chat.getChatRoomName(event.source) if room1 != room2: voice = self.speechGenerator.voice(obj=event.source, string=room2) self.speakMessage(room2, voice=voice) flashTime = _settingsManager.getSetting('brailleFlashTime') self.displayBrailleMessage(room2, flashTime) orca.setLocusOfFocus(event, event.source) return if self.utilities.inDocumentContent(event.source): Gecko.Script.onFocusedChanged(self, event) else: default.Script.onFocusedChanged(self, event) def onWindowActivated(self, event): """Called whenever a toplevel window is activated.""" # Hack to "tickle" the accessible hierarchy. Otherwise, the # events we need to present text added to the chatroom are # missing. hasRole = lambda x: x and x.getRole() == pyatspi.ROLE_PAGE_TAB allPageTabs = pyatspi.findAllDescendants(event.source, hasRole) default.Script.onWindowActivated(self, event)