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

Source Code for Module Tier_new

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