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
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 '''
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
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
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 '''
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
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
119 self.state = sett_man.loadState(__name__, self.state)
120 except KeyError:
121
122 pass
123
124 self.setEventInterest(AEEvent.PrivateChange, True)
125
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
132 self.sett_manager.saveState(__name__, self.state)
133
134 map(Tier.clearPerks, self.tiers.values())
135
136 self.monitors.clear()
137
139 '''
140 @return: State shared across all L{Tier}s
141 @rtype: L{LSRState}
142 '''
143 return self.state
144
146 '''
147 @return: Collection of all loaded L{AEMonitor}s
148 @rtype: L{AEMonitor.MonitorCollection}
149 '''
150 return self.monitors
151
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
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
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
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
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
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
238 reg = UIRegistrar
239 prof = self.acc_eng.getProfile()
240
241
242 if init and not reg.hasTierAssociated(PERK, prof, name):
243 return None
244
245 tier = Tier(self, name, aid, por)
246 self.tiers[aid] = tier
247
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
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
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
284 tier = self.createTier(name, aid, por, False)
285
286 self.active_tier = tier
287
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
304 '''
305 Resets the gesture sequence counter.
306 '''
307 self.gesture = [None, 0]
308
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
323
324 if self.active_tier and self.active_tier.wantsEvent(event):
325
326 task_layer = event.getLayer()
327 else:
328
329 task_layer = AEConstants.LAYER_BACKGROUND
330
331 aid = event.getAppID()
332 if aid is None:
333
334 tier = self.active_tier
335 else:
336 try:
337
338 tier = self.tiers[aid]
339 except KeyError:
340
341 return
342
343 if tier is not self.active_tier:
344
345
346 event.setLayer(AEConstants.LAYER_BACKGROUND)
347 elif task_layer != AEConstants.LAYER_FOCUS:
348
349
350 event.setLayer(AEConstants.LAYER_TIER)
351
352 tier.setShow(len(self.monitors))
353 tier.manageEvent(event)
354 tier.clearState()
355
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
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
375 tier.setShow(len(self.monitors))
376 tier.manageGesture(event, self.gesture[1])
377 tier.clearState()
378
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
392 tier = self.tiers[aid]
393 except KeyError:
394 return
395
396 tier.setShow(len(self.monitors))
397 tier.manageKeyedTask(event)
398 tier.clearState()
399
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
412 tier = self.tiers[aid]
413 except KeyError:
414 return
415 if tier is self.active_tier:
416
417 event.setLayer(AEConstants.LAYER_TIER)
418
419 tier.setShow(len(self.monitors))
420 tier.manageKeyedTask(event)
421 tier.clearState()
422
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