Package AccessEngine :: Module AETierManager'
[hide private]
[frames] | no frames]

Source Code for Module AccessEngine.AETierManager'

  1  ''' 
  2  Defines a class responsible for managing all L{AETier}s. 
  3   
  4  @author: Peter Parente 
  5  @author: Pete Brunet 
  6  @organization: IBM Corporation 
  7  @copyright: Copyright (c) 2005, 2007 IBM Corporation 
  8   
  9  @author: Frank Zenker 
 10  @author: Ramona Bunk 
 11  @organization: IT Science Center Ruegen gGmbH, Germany 
 12  @copyright: Copyright (c) 2007, 2008 ITSC Ruegen 
 13   
 14  @license: I{The BSD License} 
 15  All rights reserved. This program and the accompanying materials are made  
 16  available under the terms of the BSD license which accompanies 
 17  this distribution, and is available at 
 18  U{http://www.opensource.org/licenses/bsd-license.php} 
 19  ''' 
 20  import logging 
 21  import AccessEngine 
 22  from AccessEngine import AERegistrar, AEEvent, AEMonitor 
 23  import AEState, AEConstants 
 24  from AETier import AETier 
 25  from AERegistrar import MONITOR, SCRIPT 
 26  from AccessEngine.AEAccInterfaces import implements 
 27  from Tools.i18n import _ 
 28   
 29  log = logging.getLogger('AETier') 
 30   
 31   
32 -class _AETierManager(object):
33 ''' 34 Creates L{AETier}s for all processes detectable by C{pyatspi}. 35 36 Routes L{AEEvent <AEEvent.AEEvent>}s to the active AETier for handling by 37 task functions registered by L{AEScript <AEScript.AEScript>}s. 38 Changes the active AETier as the active top-level application changes. 39 40 @ivar tiers: All L{AETier}s created for running applications:: 41 Dictionary: { 42 key: unique application ID, 43 value: AETier 44 } 45 @type tiers: dictionary 46 @ivar active_tier: AETier for the application currently in focus 47 @type active_tier: L{AETier} 48 @ivar state: Global state informaion. 49 50 Has properties representing system-wide settings. 51 @type state: L{AEState <AEState.AEState>} 52 @ivar monitors: Collection of all loaded L{AEMonitor <AEMonitor.AEMonitor>}s 53 @type monitors: L{AEMonitor.MonitorCollection} 54 @ivar gesture: counts how often in a row the last key combination was pressed:: 55 gesture[0]: pressed key, 56 gesture[1]: counts how often in a row the key was pressed 57 @type gesture: list with two entrys 58 '''
59 - def __init__(self):
60 ''' 61 Creates the empty dictionary for storing L{AETier}s and initializes the 62 active tier to None. 63 ''' 64 self.state = None 65 self.tiers = {} 66 self.active_tier = None 67 self.monitors = AEMonitor.MonitorCollection() 68 self.gesture = [None, 0]
69
70 - def init(self, application_state):
71 ''' 72 Called by L{AEMain} at startup. 73 74 @param application_state: defines the settings for this application 75 @type application_state: L{AEState <AEState.AEState>} 76 ''' 77 # load all startup monitors 78 reg = AERegistrar 79 mons = reg.loadAssociated(MONITOR, AccessEngine.AESettingsManager.getProfileName()) 80 self.addMonitors(*mons) 81 self.state = application_state 82 self.state.init() 83 try: 84 # load the Application State if available 85 self.state = AccessEngine.AESettingsManager.loadState(__name__, self.state) 86 except KeyError: 87 # or use the new one 88 pass 89 # indicate interest in private events 90 self.setEventInterest(AEEvent.PrivateChange, True)
91
92 - def close(self):
93 ''' 94 Removes all monitors and persists the current L{AEState <AEState.AEState>}. 95 96 Informs all existing L{AETier}s that their state should be persisted also. 97 ''' 98 # persist global state if it's dirty 99 AccessEngine.AESettingsManager.saveState(__name__, self.state) 100 # let all AETiers persist their state too 101 map(AETier.clearScripts, self.tiers.values()) 102 # shut down all monitors 103 self.monitors.clear()
104
105 - def getState(self):
106 ''' 107 Gets the shared state for all L{AETier}s 108 109 @return: State shared across all AETiers 110 @rtype: L{AEState <AEState.AEState>} 111 ''' 112 return self.state
113
114 - def getMonitors(self):
115 ''' 116 Gets all loaded L{AEMonitor <AEMonitor.AEMonitor>}s 117 118 @return: Collection of all loaded AEMonitors 119 @rtype: L{AEMonitor.MonitorCollection} 120 ''' 121 return self.monitors
122
123 - def addMonitors(self, *monitors):
124 ''' 125 Adds one or more L{AEMonitor <AEMonitor.AEMonitor>}s to the list of monitors 126 to be notified about events. 127 128 @param monitors: Monitors to notify 129 @type monitors: tuple of L{AEMonitor <AEMonitor.AEMonitor>}s 130 ''' 131 self.monitors.add(AEEvent.Base.AEEvent, monitors)
132
133 - def showTask(self, task_name, script):
134 ''' 135 Informs L{AEMonitor <AEMonitor.AEMonitor>}s added via L{addMonitors} of a 136 script task executing or updating. 137 138 @param task_name: registered name of the task handling the event 139 @type task_name: string 140 @param script: Script in which the task function is implemented 141 @type script: L{AEScript <AEScript.AEScript>} 142 ''' 143 self.monitors.show(task_name=task_name, script=script)
144
145 - def showEvent(self, event, tier_name):
146 ''' 147 Informs L{AEMonitor <AEMonitor.AEMonitor>}s added via L{addMonitors} of an 148 event. 149 150 @param event: An event object 151 @type event: L{AEEvent <AEEvent.AEEvent>} 152 @param tier_name: Name of the L{AETier} executing the event 153 @type tier_name: string 154 ''' 155 self.monitors.show(event=event, tier_name=tier_name)
156
157 - def showChain(self, chain_type, anchor_ident):
158 ''' 159 Informs L{AEMonitor <AEMonitor.AEMonitor>}s added via L{addMonitors} of a 160 chained script task executing. 161 162 @param chain_type: One of the L{AEConstants} CHAIN_* constants 163 @type chain_type: integer 164 @param anchor_ident: Identifier of the anchor task 165 @type anchor_ident: string 166 ''' 167 self.monitors.show(chain_type=chain_type, anchor_ident=anchor_ident)
168
169 - def showPropagate(self, propagate):
170 ''' 171 Informs L{AEMonitor <AEMonitor.AEMonitor>}s added via L{addMonitors} of the 172 propagation return value from a script task. 173 174 @param propagate: Was the event consumed (C{False}) or allowed to propagate 175 (C{True})? 176 @type propagate: boolean 177 ''' 178 self.monitors.show(propagate=propagate)
179
180 - def freeDeadAETiers(self, aids):
181 ''' 182 Compares the list of given application names and IDs with those currently 183 associated with L{AETier}s. 184 185 Frees tiers in the L{tiers} dictionary that no longer have associated 186 applications. 187 188 @param aids: List of identifiers for applications currently in existence 189 @type aids: list 190 ''' 191 map(self.removeAETier, set(self.tiers) - set(aids))
192
193 - def createAETier(self, name, aid, por, init):
194 ''' 195 Creates a new L{AETier} using the application name and ID as a hash code. 196 197 If C{init} is C{True}, only creates the L{AETier} if a specific 198 L{AEScript <AEScript.AEScript>} is associated with this profile for the 199 named application. 200 201 @param name: Name of the now active application 202 @type name: string 203 @param aid: Unique ID for the application associated with the L{AETier} 204 @type aid: hashable 205 @param por: Point of regard to the top object represented by the L{AETier} 206 @type por: L{AEPor <AEPor.AEPor>} 207 @param init: Initialize the L{AETier} only if a 208 L{AEScript <AEScript.AEScript>} is associated for this particular 209 application? 210 @type init: boolean 211 @return: The new L{AETier} that was created 212 @rtype: L{AETier} 213 ''' 214 # create a AERegistrar instance 215 reg = AERegistrar 216 prof = AccessEngine.AESettingsManager.getProfileName() 217 # don't create the AETier if we're only initializing AETiers for applications 218 # that have app specific Scripts 219 if init and not reg.hasAETierAssociated(SCRIPT, prof, name): 220 return None 221 # create the AETier object and store it 222 tier = AETier(name, aid, por) 223 self.tiers[aid] = tier 224 # load all default and application specific Scripts, push them onto the AETier 225 scripts = reg.loadAssociated(SCRIPT, prof, name) 226 tier.pushScript(*scripts) 227 log.debug('created AETier %s', name) 228 return tier
229
230 - def removeAETier(self, aid):
231 ''' 232 Removes an existing L{AETier}. 233 234 @param aid: Unique ID for the application associated with the L{AETier} 235 @type aid: hashable 236 ''' 237 self.tiers[aid].clearScripts() 238 del self.tiers[aid] 239 log.debug('removed AETier %s', aid)
240
241 - def switchAETier(self, name, aid, por):
242 ''' 243 Switches the active L{AETier} based on the current view's root accessible. 244 245 The view's root accessible is queried for information that can uniquely 246 identify the AETier to use. 247 248 If an AETier already exists for the given view, it is activated. If one 249 does not exist, an AETier is created using L{createAETier} and made active. 250 251 @param name: Name of the now active application 252 @type name: string 253 @param aid: Unique ID for the application associated with the L{AETier} 254 @type aid: hashable 255 @param por: Point of regard to the top object represented by the L{AETier} 256 @type por: L{AEPor <AEPor.AEPor>} 257 ''' 258 try: 259 tier = self.tiers[aid] 260 except KeyError: 261 # create a new tier for this application 262 tier = self.createAETier(name, aid, por, False) 263 # make the tier active 264 self.active_tier = tier
265
266 - def setEventInterest(self, kind, wants):
267 ''' 268 Informs the L{AEViewManager} of a change in interest in 269 L{AEEvent <AEEvent.AEEvent>}s by some L{AETier}. 270 271 Used to optimize which system events are monitored in order to improve 272 performance. Just acts as a proxy. 273 274 @param kind: Kind of AEEvent of interest to a script task 275 @type kind: L{AEEvent <AEEvent.AEEvent>} 276 @param wants: Does a L{AEScript <AEScript.AEScript>} wants an event 277 (i.e. a task is registering for it) or no longer wants an event 278 (i.e. a task is unregistering for it)? 279 @type wants: boolean 280 ''' 281 AccessEngine.AEViewManager.setEventInterest(kind, wants)
282
283 - def _resetGesture(self):
284 ''' 285 Resets the gesture sequence counter. 286 ''' 287 self.gesture = [None, 0]
288
289 - def manageEvent(self, event):
290 ''' 291 Dispatches an L{AEEvent <AEEvent.AEEvent>} to the L{AETier} to be handled by 292 its L{AEScript <AEScript.AEScript>}s. 293 294 Makes the final determination of on what layer the event occurred. Events 295 from a focused source are already marked as 296 L{AEConstants.Event.LAYER_FOCUS}. Events from an unfocused source in the 297 active AETier are marked as L{AEConstants.Event.LAYER_TIER}. All other 298 events for which a AETier exists to handle them are marked as 299 L{AEConstants.Event.LAYER_BACKGROUND}. 300 301 @param event: Event to dispatch to the L{AETier} 302 @type event: L{AEEvent <AEEvent.AEEvent>} 303 ''' 304 # opt: check if the active tier wants this kind of event so we don't waste 305 # time completing PORs when we request the event layer 306 if self.active_tier and self.active_tier.wantsEvent(event): 307 # get the current task layer and complete the event POR 308 task_layer = event.getLayer() 309 else: 310 # otherwise, assume background 311 task_layer = AEConstants.LAYER_BACKGROUND 312 313 aid = event.getAppID() 314 if aid is None: 315 # no app ID means a global event, use the active tier 316 tier = self.active_tier 317 318 else: 319 try: 320 # get the tier that should handle the event 321 tier = self.tiers[aid] 322 323 except KeyError: 324 # no tier means no handler, filter the event 325 return 326 327 if tier is not self.active_tier: 328 # if the tier is not the active tier, the event layer is always 329 # background 330 event.setLayer(AEConstants.LAYER_BACKGROUND) 331 elif task_layer != AEConstants.LAYER_FOCUS: 332 # if the tier is the active tier, but the layer is not already marked as 333 # focus, then the layer is always the tier layer 334 event.setLayer(AEConstants.LAYER_TIER) 335 # let the tier manage the event 336 tier.setShow(len(self.monitors)) 337 tier.manageEvent(event) 338 tier.clearState()
339
340 - def manageGesture(self, event):
341 ''' 342 Dispatches an L{AEEvent <AEEvent.AEEvent>} to the active L{AETier} so that 343 it can determine which registered script task, if any, should be executed in 344 response to some L{AEInput.Gesture}. 345 346 @param event: Event to dispatch to the L{AETier} 347 @type event: L{AEEvent <AEEvent.AEEvent>} 348 ''' 349 tier = self.active_tier 350 if tier is not None: 351 # keep track of sequences of input gestures 352 g = event.getTaskKey() 353 if g == self.gesture[0]: 354 self.gesture[1] += 1 355 else: 356 self.gesture[0] = g 357 self.gesture[1] = 0 358 # let the active AETier manage the event 359 tier.setShow(len(self.monitors)) 360 tier.manageGesture(event, self.gesture[1]) 361 tier.clearState()
362
363 - def manageChooser(self, event):
364 ''' 365 Dispatches an L{AEEvent.ChooserChange} to the L{AETier} associated with the 366 event so that it can determine which registered script task, if any, should 367 be executed in response to a change in the chooser such as its completion or 368 its cancellation. 369 370 @param event: Event to dispatch to the L{AETier} 371 @type event: L{AEEvent.ChooserChange} 372 ''' 373 aid = event.getAppID() 374 try: 375 # choose the AETier given its application ID 376 tier = self.tiers[aid] 377 except KeyError: 378 return 379 # let that AETier manage the event 380 tier.setShow(len(self.monitors)) 381 tier.manageChooserTask(event) 382 tier.clearState()
383
384 - def manageTimer(self, event):
385 ''' 386 Dispatches an L{AEEvent.TimerAlert} to the L{AETier} associated with the 387 event so that it can determine which registered task, if any, should be 388 executed in response to the timer firing. 389 390 @param event: Event to dispatch to the L{AETier} 391 @type event: L{AEEvent.TimerAlert} 392 ''' 393 aid = event.getAppID() 394 try: 395 # choose the AETier given its application ID 396 tier = self.tiers[aid] 397 except KeyError: 398 return 399 if tier is self.active_tier: 400 # the event came from an unfocused control in the active tier 401 event.setLayer(AEConstants.LAYER_TIER) 402 # let that AETier manage the event 403 tier.setShow(len(self.monitors)) 404 tier.manageTimerTask(event) 405 tier.clearState()
406
407 - def managePrivate(self, event):
408 ''' 409 Dispatches an L{AEEvent.PrivateChange} to the active L{AETier} so it can 410 store important information without passing it along to 411 L{AEScript <AEScript.AEScript>}s and tasks. 412 413 @param event: Event to dispatch to the L{AETier} 414 @type event: L{AEEvent.PrivateChange} 415 ''' 416 if self.active_tier is not None: 417 self.active_tier.managePrivate(event) 418 self.active_tier.clearState()
419
420 - def getAETiers(self):
421 ''' 422 Gets all L{AETier}s created for running applications. 423 424 @return: dictionary L{tiers} with all created L{AETier}s 425 @rtype: dictionary 426 ''' 427 return self.tiers
428