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

Source Code for Module Tier

  1  ''' 
  2  Defines a class for managing the L{Perk}s loaded for a single instance of an 
  3  application. 
  4   
  5  @author: Peter Parente 
  6  @author: Pete Brunet 
  7  @author: Larry Weiss 
  8  @author: Scott Haeger 
  9  @organization: IBM Corporation 
 10  @copyright: Copyright (c) 2005, 2007 IBM Corporation 
 11  @license: The BSD License 
 12   
 13  All rights reserved. This program and the accompanying materials are made  
 14  available under the terms of the BSD license which accompanies 
 15  this distribution, and is available at 
 16  U{http://www.opensource.org/licenses/bsd-license.php} 
 17  ''' 
 18  import logging, weakref, traceback, sys, os 
 19  import AEState, AEInput, Perk, Task, AEConstants 
 20  from POR import POR 
 21   
 22  log = logging.getLogger('Tier') 
 23   
24 -class Tier(object):
25 ''' 26 Manages the L{Perk}s for a single instance of a running program (a process). 27 Supports the addition and removal of L{Perk}s from its stack. Executes 28 L{Task}s registered in each L{Perk} in response to L{AEEvent}s. Provides 29 methods to assist L{Perk}s and L{Task}s in finding registered L{Task}s 30 throughout the L{Tier}. 31 32 @ivar perks: List of L{Perk}s treated as a stack (last in, first executed) 33 @type perks: list 34 @ivar wanted_events: Lookup table for what L{AEEvent}s are desired by any 35 L{Task} in any L{Perk} in this L{Tier}. Used to optimize event dispatch and 36 processing. Unwanted events are ignored. 37 @type wanted_events: dictionary 38 @ivar tier_manager: L{TierManager} that created this L{Tier} 39 @type tier_manager: L{TierManager} 40 @ivar pointer_por: Pointer of regard for the user focus 41 @type pointer_por: L{POR} 42 @ivar focus_por: Point of regard for the application focus 43 @type focus_por: L{POR} 44 @ivar name: Name of this L{Tier} 45 @type name: string 46 @ivar aid: ID uniquely identifying this L{Tier} from all other L{Tier}s 47 @type aid: opaque 48 @ivar last_key: Stores the key code, key sym, and modifiers for the last key 49 pressed 50 @type last_key: 3-tuple of integer, string, integer 51 @ivar perk_refs: References to L{Perk}s keyed by task names, commands, 52 identifiers, etc. Many to one mapping. See L{addTaskRef} and 53 L{removeTaskRef}. 54 @type perk_refs: weakref.WeakValueDictionary 55 @ivar chain_refs: References to L{Perk}s keyed by task names. Many to many 56 mapping. See L{addChainRef} and L{removeChainRef}. 57 @type chain_refs: dictionary 58 @ivar chain_stack: Stack of L{Task} and L{Perk} names currently executing in 59 one or more chains before, after, or around one or more anchors 60 @type chain_stack: list 61 @ivar temp_data: Arbitrary name/value pairs stored by L{Task}s executing in 62 this L{Tier} in response to a single event. The data is persistent until 63 the event has been handled by all L{Task}s at which time it is cleared. 64 @type temp_data: dictionary 65 @ivar task_history: Stack of L{Task} and L{Perk} names having already 66 executed in response to an L{AEEvent}, including all chained L{Task}s and 67 all L{Task}s executed from within other L{Task}s 68 @type task_history: list 69 @ivar show: Call show* methods on L{TierManager} to log events? Set by the 70 L{TierManager} based on whether monitors are loaded or not. Optimization. 71 @type show: boolean 72 '''
73 - def __init__(self, tier_manager, name, aid, por):
74 ''' 75 Stores a reference to the L{TierManager} that created this L{Tier}. Creates 76 an empty list of L{Perk}s. Initializes the stored focus L{POR} to None and 77 the pointer L{POR} to the application. Creates the weak dictionary for 78 L{Perk} L{Task}s and stores other information about the L{Tier}. 79 80 @param tier_manager: Manager that created this L{Tier} 81 @type tier_manager: L{TierManager} 82 @param name: Name of this L{Tier} 83 @type name: string 84 @param aid: ID uniquely identifying this L{Tier} from all other L{Tier}s 85 @type aid: opaque 86 @param por: First point of regard to the application represented by 87 this L{Tier}. Typically, the top most accessible. 88 @type por: L{POR} 89 ''' 90 self.tier_manager = tier_manager 91 self.perks = [] 92 self.wanted_events = {} 93 self.name = name 94 self.aid = aid 95 self.perk_refs = weakref.WeakValueDictionary() 96 self.chain_refs = {} 97 self.pointer_por = por 98 self.focus_por = None 99 self.last_key = (None, None, None) 100 self.auto_pointer = True 101 # fields to be cleared after each event 102 self.clearState()
103
104 - def close(self):
105 ''' 106 Clears all L{Perk}s and closes them. 107 ''' 108 self.clearPerks()
109
110 - def setShow(self, show):
111 ''' 112 Sets whether show methods should be called on the L{TierManager} when 113 handling events or not based on the presence of L{AEMonitor}s in the 114 manager. 115 116 @param show: Call show methods to notify monitors? 117 @type show: boolean 118 ''' 119 self.show = show
120
121 - def getPointer(self):
122 ''' 123 Gets the user L{POR} for this L{Tier}. 124 125 @return: Point of regard of user attention 126 @rtype: L{POR} 127 ''' 128 return self.pointer_por
129
130 - def setPointer(self, por):
131 ''' 132 Sets the user L{POR} for this L{Tier}. 133 134 @param por: Point of regard of user attention 135 @type por: L{POR} 136 ''' 137 self.pointer_por = por
138
139 - def getFocus(self):
140 ''' 141 Gets the application focus L{POR} for this L{Tier}. 142 143 @return: Point of regard of application focus 144 @rtype: L{POR} 145 ''' 146 return self.focus_por
147
148 - def getHistory(self):
149 ''' 150 Gets the entire linear history of L{Task}s that have executed and the 151 L{Perk}s they are in. 152 153 @return: List of L{Task} identities and L{Perk} class names 154 @rtype: list of 2-tuple of string 155 ''' 156 return self.task_history
157
158 - def getAnchor(self):
159 ''' 160 Gets the identity of the L{Task} to which the current L{Task} is chained 161 and its corresponding L{Perk}. If there is no anchor for the executing 162 L{Task}, this method returns None. 163 164 @return: L{Task} identity and L{Perk} class name or None 165 @rtype: 2-tuple of string 166 ''' 167 try: 168 return self.chain_stack[-1] 169 except IndexError: 170 return None
171
172 - def getLastKey(self):
173 ''' 174 Gets the last key code, key sym, and key modifiers. Useful for dealing with 175 applications that do a poor job of synthesizing caret and text events. 176 177 @return: The key code, key sym, and modifiers for the last key pressed 178 @rtype: 3-tuple of integer, string, integer 179 ''' 180 return self.last_key
181
182 - def getTempVal(self, name):
183 ''' 184 Gets data from L{temp_data}. 185 186 @param name: Name of the stored data 187 @type name: immutable 188 @return: Value stored under the given name 189 @rtype: object 190 @raise KeyError: When no data is stored under the given name 191 ''' 192 return self.temp_data[name]
193
194 - def setTempVal(self, name, value):
195 ''' 196 Stores data for the duration of the execution of an L{AEEvent}. 197 198 @param name: Name to associate with the value 199 @type name: immutable 200 @param value: Any value to store 201 @type value: object 202 ''' 203 self.temp_data[name] = value
204
205 - def clearState(self):
206 ''' 207 Clears all stored L{temp_data}, the L{chain_stack}, L{task_history}, and 208 the L{show} flag. 209 ''' 210 self.temp_data = {} 211 self.task_history = [] 212 self.chain_stack = [] 213 self.show = False
214
215 - def addChainRef(self, target, perk):
216 ''' 217 Adds a weak reference to a L{Perk} as one to check for L{Task}s which are 218 part of a the chain for the target. Optimization for the L{manageChain} 219 method. 220 221 @param target: Name of the L{Task} to link to 222 @type target: string 223 @param perk: Perk have at least one link in the chain for the target 224 @type perk: L{Perk} 225 ''' 226 chain = self.chain_refs.setdefault(target, weakref.WeakKeyDictionary()) 227 chain[perk] = None
228
229 - def removeChainRef(self, target, perk):
230 ''' 231 Removes a weak reference to a L{Perk} as one to no longer check for 232 L{Task}s which are part of the chain for the target. Optimization for the 233 L{manageChain} method. 234 235 @param target: Name of the L{Task} to unlink from 236 @type target: string 237 @param perk: Perk have at least one link in the chain for the target 238 @type perk: L{Perk} 239 ''' 240 try: 241 chain = self.chain_refs[target] 242 del chain[perk] 243 except (KeyError, ValueError): 244 pass
245
246 - def addTaskRef(self, key, perk):
247 ''' 248 Adds a key that can be used later to quickly look up a reference to a 249 L{Perk} in this L{Tier}. Optimization for the L{getKeyedTask}, 250 L{getCommandTask}, and L{getNamedTask} methods. 251 252 @param key: Key under which to hash the L{Perk} 253 @type key: immutable 254 @param perk: Perk to store in the hash 255 @type perk: L{Perk} 256 ''' 257 self.perk_refs[key] = perk
258
259 - def removeTaskRef(self, key):
260 ''' 261 Removes a key used to quickly look up a reference to a L{Perk} in this 262 L{Tier}. Keys are cleaned up automatically when L{Perk}s are destroyed. 263 However, this method may be used to manually remove L{Perk}s at any time. 264 265 @param key: Key under which to hash the L{Perk} 266 @type key: immutable 267 ''' 268 try: 269 del self.perk_refs[key] 270 except KeyError: 271 pass
272
273 - def getName(self):
274 ''' 275 @return: Name of this L{Tier} (i.e. name of the app with which it is 276 associated) 277 @rtype: string 278 ''' 279 return self.name
280
281 - def getIdentity(self):
282 ''' 283 @return: Unique identifier for this L{Tier} 284 @rtype: opaque 285 ''' 286 return self.aid
287
288 - def pushPerk(self, ae, *perks):
289 ''' 290 Adds one or more L{Perk}s to the top of the stack. If more than one L{Perk} 291 is specified, the last specified L{Perk} will be at the top of the stack 292 when this method completes. That is, the behavior of pushing more than one 293 L{Perk} at a time is the same as if each L{Perk} were pushed individually. 294 295 @param ae: The AccessEngine context to use for initializing the Perk 296 @type ae: L{AccessEngine} 297 @param perks: L{Perk}s to add 298 @type perks: list of L{Perk} 299 ''' 300 self.insertPerk(ae, 0, *perks)
301
302 - def insertPerk(self, ae, index, *perks):
303 ''' 304 Adds one L{Perk} to the stack at the insertion index. Negative indices are 305 valid per Python list convention. 306 307 @param ae: The AccessEngine context to use for initializing the Perk 308 @type ae: L{AccessEngine} 309 @param index: Index at which the L{Perk} should be inserted in the stack 310 @type index: integer 311 @param perks: L{Perk}s to add 312 @type perks: list of L{Perk} 313 ''' 314 for perk in perks: 315 # put the Perk somewhere in the stack 316 self.perks.insert(index, perk) 317 # initialize the Perk base classes with important, persistent references 318 perk.preInit(ae, self) 319 # initialize this particular instance with temporary references 320 perk.preExecute(AEConstants.LAYER_FOCUS) 321 try: 322 # now let Perk specific code run 323 perk.init() 324 except Exception, e: 325 # pop the perk from the stack if it fails to initialize 326 self.perks.pop(index) 327 # let it finalize 328 try: 329 perk.close() 330 except Exception: 331 # ignore errors while finalizing 332 pass 333 perk.postClose() 334 # warn about the error 335 info = traceback.extract_tb(sys.exc_info()[2]) 336 log.debug('cannot initialize %s (%s, %d): %s', perk.getClassName(), 337 os.path.basename(info[-1][0]), 338 info[-1][1], str(e))
339
340 - def popPerk(self, *indices):
341 ''' 342 Removes one or more L{Perk}s from the stack given their indices. Negative 343 indices are valid per Python list convention. Calls L{Perk.Perk.close} on 344 each to ensure they have a chance to persist state. 345 346 @param indices: Indices of L{Perk}s to remove 347 @type indices: list of integer 348 @raise IndexError: When the stack is empty 349 @raise ValueError: When a specific index is out of the bounds of the stack 350 ''' 351 indices = list(indices) 352 # have to pop in reverse order to avoid corrupting original indices 353 indices.sort(reverse=True) 354 perks = map(self.perks.pop, indices) 355 for perk in perks: 356 try: 357 perk.close() 358 except Exception: 359 # ignore errors during close 360 pass 361 perk.postClose()
362
363 - def clearPerks(self):
364 ''' 365 Removes all L{Perk}s from the stack. Calls L{Perk.Perk.close} on each to 366 ensure they have a chance to persist state. 367 ''' 368 for perk in self.perks: 369 try: 370 perk.close() 371 except Exception: 372 # ignore errors during close 373 pass 374 perk.postClose() 375 self.perks = []
376
377 - def getPerks(self):
378 ''' 379 Gets all L{Perk}s pushed onto this L{Tier} in execution order. 380 381 @note: This method does not return a copy of the stack. Modifications will 382 affect this L{Tier}! 383 @return: All L{Perk}s pushed onto this L{Tier} 384 @rtype: list of L{Perk} 385 ''' 386 return self.perks
387
388 - def setEventInterest(self, kind, wants):
389 ''' 390 Updates the L{wanted_events} dictionary to indicate that a L{Task} in a 391 L{Perk} in this L{Tier} has been registered for a particular kind of 392 L{AEEvent}. This information is used for optimization purposes such that no 393 processing will occur on the event unless at least one L{Task} is 394 registered that will use it. 395 396 @param kind: Kind of L{AEEvent} of interest to a L{Task} 397 @type kind: L{AEEvent} class 398 @param wants: Does a L{Perk} want an event (i.e. a L{Task} is registering 399 for it or no longer want an event (i.e. a L{Task} is unregistering for 400 it)? 401 @type wants: boolean 402 ''' 403 count = self.wanted_events.setdefault(kind, 0) 404 if wants: 405 count += 1 406 else: 407 count -= 1 408 if count <= 0: 409 del self.wanted_events[kind] 410 else: 411 self.wanted_events[kind] = count 412 # inform the TierManager of the new event interest 413 self.tier_manager.setEventInterest(kind, wants)
414
415 - def wantsEvent(self, event):
416 ''' 417 Gets if this L{Tier} wants a particular kind of L{AEEvent} given that one of 418 its L{Perk}s has a L{Task} that wants to handle it. 419 420 @param event: Event to be tested 421 @type event: L{AEEvent} 422 ''' 423 return self.wanted_events.has_key(type(event))
424
425 - def getKeyedTask(self, key):
426 ''' 427 Gets a L{Task} registered under a particular key set to execute in response 428 to events. None is returned if not found. 429 430 @param key: Unique ID for locating a registered L{Task} 431 @type key: integer 432 @return: L{Task} set to execute in response to the event or None 433 @rtype: L{Task} 434 ''' 435 try: 436 perk = self.perk_refs[key] 437 except KeyError: 438 return None 439 return perk.getKeyedTask(key)
440
441 - def getCommandTask(self, gesture_list):
442 ''' 443 Gets a L{Task} registered to execute in response to the L{AEInput.Gesture}. 444 None is returned if not found. 445 446 @param gesture_list: Gestures and device expressed as a list of virtual key 447 codes 448 @type gesture_list: L{AEInput.Gesture} 449 @return: Name of the L{Task} to execute in response to the input gesture 450 or None if no L{Task} registered to execute 451 @rtype: string 452 ''' 453 try: 454 perk = self.perk_refs[gesture_list] 455 except KeyError: 456 return None 457 return perk.getCommandTask(gesture_list)
458
459 - def getNamedTask(self, name):
460 ''' 461 Gets a L{Task} with the given name by iterating through the registered 462 L{Perk}s until one is found containing a L{Task} registered under the given 463 name. None is returned if not found. 464 465 @param name: Name of the L{Task} to find 466 @type name: string 467 @return: L{Task} with the given name or None 468 @rtype: L{Task.Base.Task} 469 ''' 470 try: 471 perk = self.perk_refs[name] 472 except KeyError: 473 return None 474 return perk.getNamedTask(name)
475
476 - def getEventTasks(self, event_type, task_layer):
477 ''' 478 Gets all L{Task}s registered to handle the given type of event on the 479 given layer by iterating through the registered {Perk}s. The L{Task}s are 480 returned in the order they will be executed both within and across 481 L{Perk}s in this L{Tier}. 482 483 @param event_type: Desired type of L{AEEvent} 484 @type event_type: L{AEEvent} class 485 @param task_layer: Layer on which the desired L{Task}s are registered 486 @type task_layer: integer 487 @return: List of all L{Task}s registered to handle the given type of event 488 on the given layer 489 @rtype: list of L{Task.Base.Task} 490 ''' 491 tasks = [] 492 map(tasks.extend, [p.getEventTasks(event_type, task_layer) for p in 493 self.perks]) 494 return tasks
495
496 - def getChainedTasks(self, target):
497 ''' 498 Gets all L{Task}s linked to the target by iterating through L{Perk} 499 references established by L{addChainRef}. The L{Task}s are returned in the 500 order in which they were registered within a L{Perk}. Ordering is undefined 501 across L{Perk}s within a chain segment. 502 503 @param target: Name of the L{Task} to link to 504 @type target: string 505 @return: L{Task} names for before, around, and after segments 506 @rtype: 3-tuple of list, string, list 507 @raise KeyError: When the target has no chained L{Task}s 508 ''' 509 befores = [] 510 afters = [] 511 perks = self.chain_refs[target].keys() 512 arounds = [p.mergeChain(target, befores, afters) for p in perks] 513 return befores, arounds[0], afters
514
515 - def _executeTask(self, task, perk, por, layer, params, propagate):
516 ''' 517 Executes the given L{Task} in response to the given L{AEEvent}. 518 519 @param task: A L{Task} registered to handle the given event 520 @type task: L{Task} 521 @param perk: The L{Perk} containing the L{Task} 522 @type perk: L{Perk} 523 @param por: Point of regard where the event occurred 524 @type por: L{POR} 525 @param propagate: Should this event be propagated to the 526 L{Task.Base.Task.execute} method or should we call 527 L{Task.Base.Task.update} instead for housekeeping? 528 @type propagate: boolean 529 @param layer: Layer on which the L{AEEvent} occurred, one of 530 L{AEConstants.Event.LAYER_FOCUS}, L{AEConstants.Event.LAYER_TIER}, 531 L{AEConstants.Event.LAYER_BACKGROUND} 532 @type layer: integer 533 @param params: Keyword arguments to be provided to the L{Task} as 534 parameters 535 @type params: dictionary 536 @return: Should the next registered L{Task} be executed or only updated? 537 @rtype: boolean 538 @raise AssertionError: When the L{Perk} or L{Task} does not preExecute 539 successfully 540 ''' 541 # pass important references to the Task 542 if not (perk.preExecute(layer, por) and task.preExecute(layer, por)): 543 raise AssertionError 544 try: 545 if propagate: 546 # unpack the dictionary and execute the task 547 rv = task.execute(layer=layer, **params) 548 else: 549 # unpack the dictionary and update the task 550 task.update(layer=layer, **params) 551 rv = False 552 except Task.ToolsError, ex: 553 # output the Task.ToolsError if state.Trap is True 554 if self.tier_manager.getState().Trap: 555 task.sayError(text=str(ex)) 556 else: 557 log.exception(ex) 558 rv = True 559 except Exception: 560 # log any other Perk exception 561 log.exception('%s: %s %s', task.getClassName(), layer, params) 562 # continue processing 563 rv = True 564 if rv is None: 565 # continue processing if no return value is specified 566 rv = True 567 elif not rv: 568 # inhibit automatic updating of the pointer if propogation is blocked 569 task.inhibitAutoPointer() 570 # uninitialize the Task, but not the Perk since it has nothing to do 571 task.postExecute() 572 return rv
573
574 - def manageChain(self, por, name, task, perk, layer, task_params, 575 propagate, chain):
576 ''' 577 Executes all L{Task}s chained the the given L{Task}, recursively if 578 chain=True. 579 580 @note: This method is purposely long because much code that could be 581 refactored into other methods is inlined for performance reasons. 582 583 @param name: Identity of the L{Task} to execute 584 @type name: string 585 @param task: Task to execute 586 @type task: L{Task} 587 @param perk: Perk in which the Task resides 588 @type perk: L{Perk} 589 @param layer: Layer in which to execute the L{Task}, one of 590 L{AEConstants.Event.LAYER_FOCUS}, L{AEConstants.Event.LAYER_TIER}, 591 L{AEConstants.Event.LAYER_BACKGROUND} 592 @type layer: integer 593 @param task_params: Keyword data to pass to the L{Task} as parameters on 594 execution or update 595 @type task_params: dictionary 596 @param propagate: Should chained L{Task}s be executed or updated? 597 @type propagate: boolean 598 @param chain: Execute all L{Task}s chained to the one named or not? 599 @type chain: boolean 600 ''' 601 # pull show into local vars 602 show = self.show 603 # pull perk name into local vars once 604 p_name = perk.getClassName() 605 606 if not chain: 607 # no chaining, just execute, duplicate execute code for performance 608 # add to the linear history before executing so that it's available 609 # to changed and doTask tasks 610 self.task_history.append((name, p_name)) 611 if show: 612 # execute this Task and log information 613 self.tier_manager.showTask(task, perk) 614 try: 615 propagate = self._executeTask(task, perk, por, layer, task_params, 616 propagate) 617 except AssertionError: 618 pass 619 self.tier_manager.showPropagate(propagate) 620 else: 621 # execute only, duplicated for performance 622 try: 623 propagate = self._executeTask(task, perk, por, layer, task_params, 624 propagate) 625 except AssertionError: 626 pass 627 # do not push the task back on the stack because we're done anyways 628 else: 629 # fetch all chain segments at once 630 try: 631 befores, around_name, afters = self.getChainedTasks(name) 632 except KeyError: 633 # no chaining, just execute, duplicate execute code for performance 634 # add to the linear history before executing so that it's available 635 # to changed and doTask tasks 636 self.task_history.append((name, p_name)) 637 if show: 638 # execute this Task and log information 639 self.tier_manager.showTask(task, perk) 640 try: 641 propagate = self._executeTask(task, perk, por, layer, task_params, 642 propagate) 643 except AssertionError: 644 pass 645 self.tier_manager.showPropagate(propagate) 646 else: 647 # execute only, duplicated for performance 648 try: 649 propagate = self._executeTask(task, perk, por, layer, task_params, 650 propagate) 651 except AssertionError: 652 pass 653 # do not push the task back on the stack because we're done anyways 654 else: 655 # put the name of this task and its perk onto the stack 656 self.chain_stack.append((name, p_name)) 657 658 # get the chain of tasks to run before this one 659 for before_name in befores: 660 if show: 661 self.tier_manager.showChain(AEConstants.CHAIN_BEFORE, name) 662 # look for a Perk with a Task with the given name 663 task = self.getNamedTask(before_name) 664 # bail immediately if it doesn't exist 665 if task is not None: 666 perk = task.getPerk() 667 # recurse with before tasks 668 propagate = self.manageChain(por, before_name, task, perk, layer, 669 task_params, propagate, chain) 670 671 # check for task to run instead of this one 672 if around_name is None: 673 # pop this task 674 cache = self.chain_stack.pop() 675 # add to the linear history before executing so that it's available 676 # to changed and doTask tasks 677 self.task_history.append((name, p_name)) 678 if show: 679 # execute this Task and log information 680 self.tier_manager.showTask(task, perk) 681 try: 682 propagate = self._executeTask(task, perk, por, layer, 683 task_params, propagate) 684 except AssertionError: 685 pass 686 self.tier_manager.showPropagate(propagate) 687 else: 688 # execute only, duplicated for performance 689 try: 690 propagate = self._executeTask(task, perk, por, layer, 691 task_params, propagate) 692 except AssertionError: 693 pass 694 # get the pointer as the starting POR for the next task execution 695 por = self.getPointer() 696 # push this task back onto the stack 697 self.chain_stack.append(cache) 698 else: 699 if show: 700 self.tier_manager.showChain(AEConstants.CHAIN_AROUND, name) 701 # look for a Perk with a Task with the given name 702 task = self.getNamedTask(around_name) 703 # bail immediately if it doesn't exist 704 if task is not None: 705 perk = task.getPerk() 706 # recurse with around tasks 707 propagate = self.manageChain(por, around_name, task, perk, layer, 708 task_params, propagate, chain) 709 # get the pointer after the recursive step 710 por = self.getPointer() 711 712 # get the chain of tasks to run after this one 713 for after_name in afters: 714 if show: 715 self.tier_manager.showChain(AEConstants.CHAIN_AFTER, name) 716 # look for a Perk with a Task with the given name 717 task = self.getNamedTask(after_name) 718 # bail immediately if it doesn't exist 719 if task is not None: 720 perk = task.getPerk() 721 # recurse with fter tasks 722 propagate = self.manageChain(por, after_name, task, perk, layer, 723 task_params, propagate, chain) 724 # pop the name of this task off the stack permanently 725 self.chain_stack.pop() 726 # return the current value of propagate 727 return propagate
728
729 - def manageEvent(self, event):
730 ''' 731 Manages an event by iterating through the L{Perk} stack (top to bottom) and 732 checking for registered L{Task}s of the given type. Executes the registered 733 L{Task}s (last registered, first executed) in each L{Perk} until one of the 734 following conditions is met: 735 - All L{Task}s have executed 736 - A L{Task} returns False 737 - A L{Task} raises an exception 738 739 In the latter two cases, no additional L{Task}s in the current L{Perk} or 740 additional L{Perk}s in this L{Tier} are executed. Instead the 741 L{Task.Base.Task.update} methods are called to allow housekeeping 742 operations (e.g updating state) to be performed. 743 744 If a L{Task} returns neither True or False (e.g. it returns None) a 745 warning is logged and the return value is treated as if it were True. This 746 likely means the L{Task} forgot to specify a return value. 747 748 @param event: Event to process 749 @type event: L{AEEvent.Base.AccessEngineEvent} 750 ''' 751 try: 752 # grab POR from any focus type event 753 self.focus_por = event.getFocusPOR() 754 except AttributeError: 755 pass 756 757 if not self.wantsEvent(event): 758 # quit immediately if no Task wants this event 759 return 760 761 # pull show into local vars 762 show = self.show 763 764 # show the event in registered monitors 765 if show: 766 self.tier_manager.showEvent(event, self.name) 767 768 # get these values once to initialize, most are constant for all Tasks 769 event_por = event.getPOR() 770 task_layer = event.getLayer() 771 task_params = event.getDataForTask() 772 event_type = type(event) 773 774 # run through all the registered Perks 775 propagate = True 776 for perk in self.perks: 777 # run through all Tasks of the given type in this Perk 778 for task in perk.getEventTasks(event_type, task_layer): 779 try: 780 i = task.getIdentity() 781 except ValueError: 782 i = None 783 # add to linear history before executing so it's available to chained 784 # and doTask tasks 785 self.task_history.append((i, perk.getClassName())) 786 787 if show: 788 # execute task and log information 789 self.tier_manager.showTask(task, perk) 790 propagate = self.manageChain(event_por, i, task, perk, task_layer, 791 task_params, propagate, True) 792 self.tier_manager.showPropagate(propagate) 793 else: 794 # execute only, duplicated for performance 795 propagate = self.manageChain(event_por, i, task, perk, task_layer, 796 task_params, propagate, True)
797
798 - def manageGesture(self, event, count):
799 ''' 800 Manages an event by getting the L{AEInput.Gesture} that triggered it and 801 locating a L{Task} registered to execute in response to it. If a L{Task} 802 could not be found for the given event, the L{Task} registered for invalid 803 gestures is executed instead. 804 805 @param event: Event to process 806 @type event: L{AEEvent.InputGesture} 807 @param count: Number of times this gesture has been issued without 808 interruption 809 @type count: integer 810 ''' 811 # look for a Perk with a Task registered to respond to this input command 812 name = self.getCommandTask(event.getTaskKey()) 813 if name is None: return 814 815 # show the event in registered monitors 816 if self.show: 817 self.tier_manager.showEvent(event, self.name) 818 # extract layer and data for task 819 layer = event.getLayer() 820 task_params = event.getDataForTask() 821 # insert the count into the data for the task 822 task_params['cycle_count'] = count 823 # look for a Perk with a Task with the given name 824 task = self.getNamedTask(name) 825 if task is not None: 826 # account for chains on the task 827 perk = task.getPerk() 828 self.manageChain(None, name, task, perk, layer, task_params, True, True)
829
830 - def manageKeyedTask(self, event):
831 ''' 832 Manages an event by locating a L{Task} under a particular key (not keyboard 833 key, but some immutable identifier) registered to execute in response to 834 it. 835 836 @param event: Event to process 837 @type event: L{AEEvent} 838 ''' 839 # look for a Perk with a Task registered to respond to this event 840 task = self.getKeyedTask(event.getTaskKey()) 841 # pull show into local namespace 842 show = self.show 843 # show the event in registered monitors 844 if show: 845 self.tier_manager.showEvent(event, self.name) 846 if task is not None: 847 layer = event.getLayer() 848 perk = task.getPerk() 849 task_params = event.getDataForTask() 850 if show: 851 # execute that Task and log its information 852 self.tier_manager.showTask(task, perk) 853 try: 854 rv = self._executeTask(task, perk, None, layer, task_params, True) 855 except AssertionError: 856 pass 857 self.tier_manager.showPropagate(rv) 858 else: 859 # execute only, duplicated for performance 860 try: 861 self._executeTask(task, perk, None, layer, task_params, True) 862 except AssertionError: 863 pass
864
865 - def managePrivate(self, event):
866 ''' 867 Pulls private data from an event and stores it in appropriate instance 868 variables. Does not forward the event to L{Perk}s and L{Task}s. Rather, 869 the stored information is made public through L{Task.Tools} methods. 870 871 @param event: Event to process 872 @type event: L{AEEvent} 873 ''' 874 data = event.getDataForTask() 875 kind = data['kind'] 876 if kind == event.KEY_PRESS: 877 # store last scan code and key sym string 878 self.last_key = data['code'], data['sym'], data['mod']
879