Module TierManager
[hide private]
[frames] | no frames]

Source Code for Module TierManager

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