1# Orca 2# 3# Copyright 2010 Joanmarie Diggs. 4# 5# This library is free software; you can redistribute it and/or 6# modify it under the terms of the GNU Lesser General Public 7# License as published by the Free Software Foundation; either 8# version 2.1 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# Lesser General Public License for more details. 14# 15# You should have received a copy of the GNU Lesser 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"""Custom script for Instantbird.""" 21 22__id__ = "$Id$" 23__version__ = "$Revision$" 24__date__ = "$Date$" 25__copyright__ = "Copyright (c) 2010 Joanmarie Diggs." 26__license__ = "LGPL" 27 28import pyatspi 29 30import orca.bookmarks as bookmarks 31import orca.scripts.default as default 32import orca.orca as orca 33import orca.settings_manager as settings_manager 34import orca.orca_state as orca_state 35import orca.scripts.toolkits.Gecko as Gecko 36import orca.speech as speech 37 38from .chat import Chat 39from .script_utilities import Utilities 40 41_settingsManager = settings_manager.getManager() 42 43######################################################################## 44# # 45# The Instantbird script class. # 46# # 47######################################################################## 48 49class Script(Gecko.Script): 50 51 def __init__(self, app): 52 """Creates a new script for the given application.""" 53 54 # So we can take an educated guess at identifying the buddy list. 55 # 56 self._buddyListAncestries = [[pyatspi.ROLE_LIST, 57 pyatspi.ROLE_FRAME]] 58 59 Gecko.Script.__init__(self, app) 60 61 def getBookmarks(self): 62 """Returns the "bookmarks" class for this script.""" 63 64 # This is a copy of orca.script.getBookmarks(). It's here to 65 # prevent the Gecko script's from being used. 66 # 67 try: 68 return self.bookmarks 69 except AttributeError: 70 self.bookmarks = bookmarks.Bookmarks(self) 71 return self.bookmarks 72 73 def getChat(self): 74 """Returns the 'chat' class for this script.""" 75 76 return Chat(self, self._buddyListAncestries) 77 78 def getUtilities(self): 79 """Returns the utilites for this script.""" 80 81 return Utilities(self) 82 83 def getEnabledStructuralNavigationTypes(self): 84 """Returns a list of the structural navigation object types 85 enabled in this script. 86 """ 87 88 return [] 89 90 def setupInputEventHandlers(self): 91 """Defines InputEventHandler fields for this script that can be 92 called by the key and braille bindings. Here we need to add the 93 handlers for chat functionality. 94 """ 95 96 Gecko.Script.setupInputEventHandlers(self) 97 self.inputEventHandlers.update(self.chat.inputEventHandlers) 98 99 def getAppKeyBindings(self): 100 """Returns the application-specific keybindings for this script.""" 101 102 return self.chat.keyBindings 103 104 def getAppPreferencesGUI(self): 105 """Return a GtkGrid containing the application unique configuration 106 GUI items for the current application. The chat-related options get 107 created by the chat module.""" 108 109 return self.chat.getAppPreferencesGUI() 110 111 def getPreferencesFromGUI(self): 112 """Returns a dictionary with the app-specific preferences.""" 113 114 return self.chat.getPreferencesFromGUI() 115 116 def onTextDeleted(self, event): 117 """Called whenever text is deleted from an object. 118 119 Arguments: 120 - event: the Event 121 """ 122 123 default.Script.onTextDeleted(self, event) 124 125 def onTextInserted(self, event): 126 """Called whenever text is added to an object.""" 127 128 if self.chat.presentInsertedText(event): 129 return 130 131 default.Script.onTextInserted(self, event) 132 133 def onCaretMoved(self, event): 134 """Caret movement in Gecko is somewhat unreliable and 135 unpredictable, but we need to handle it. When we detect caret 136 movement, we make sure we update our own notion of the caret 137 position: our caretContext is an [obj, characterOffset] that 138 points to our current item and character (if applicable) of 139 interest. If our current item doesn't implement the 140 accessible text specialization, the characterOffset value 141 is meaningless (and typically -1).""" 142 143 if self.utilities.inDocumentContent(event.source): 144 orca.setLocusOfFocus(event, event.source) 145 Gecko.Script.onCaretMoved(self, event) 146 else: 147 default.Script.onCaretMoved(self, event) 148 149 def onChildrenAdded(self, event): 150 """Callback for object:children-changed:add accessibility events.""" 151 152 return 153 154 def onDocumentLoadComplete(self, event): 155 """Called when a web page load is completed.""" 156 157 return 158 159 def onDocumentLoadStopped(self, event): 160 """Called when a web page load is interrupted.""" 161 162 return 163 164 def onNameChanged(self, event): 165 """Called whenever a property on an object changes. 166 167 Arguments: 168 - event: the Event 169 """ 170 171 default.Script.onNameChanged(self, event) 172 173 def onFocusedChanged(self, event): 174 """Callback for object:state-changed:focused accessibility events.""" 175 176 # This seems to be the most reliable way to identify that the 177 # active chatroom was changed via keyboard from within the entry. 178 # In this case, speak and flash braille the new room name. 179 # 180 if orca_state.locusOfFocus and event.source \ 181 and orca_state.locusOfFocus.getRole() == pyatspi.ROLE_ENTRY \ 182 and event.source.getRole() == pyatspi.ROLE_ENTRY \ 183 and orca_state.locusOfFocus != event.source: 184 room1 = self.chat.getChatRoomName(orca_state.locusOfFocus) 185 room2 = self.chat.getChatRoomName(event.source) 186 if room1 != room2: 187 speech.speak(room2) 188 flashTime = _settingsManager.getSetting('brailleFlashTime') 189 self.displayBrailleMessage(room2, flashTime) 190 orca.setLocusOfFocus(event, event.source) 191 return 192 193 if self.utilities.inDocumentContent(event.source): 194 Gecko.Script.onFocusedChanged(self, event) 195 else: 196 default.Script.onFocusedChanged(self, event) 197 198 def onWindowActivated(self, event): 199 """Called whenever a toplevel window is activated.""" 200 201 # Hack to "tickle" the accessible hierarchy. Otherwise, the 202 # events we need to present text added to the chatroom are 203 # missing. 204 hasRole = lambda x: x and x.getRole() == pyatspi.ROLE_PAGE_TAB 205 allPageTabs = pyatspi.findAllDescendants(event.source, hasRole) 206 default.Script.onWindowActivated(self, event) 207