1 '''
2 Defines a class responsible for handling events in the currently focused view.
3
4 @var CHECK_INTERVAL: Time in ms that the L{ViewManager} will iterate over all
5 top level applications and provide them in a list to L{TierManager}
6 @type CHECK_INTERVAL: integer
7 @var DEFAULT_EVENTS: Names of events that will be dispatched by the
8 L{ViewManager} by default
9 @type DEFAULT_EVENTS: list
10
11 @author: Peter Parente
12 @author: Pete Brunet
13 @author: Brett Clippingdale
14 @organization: IBM Corporation
15 @copyright: Copyright (c) 2005, 2007 IBM Corporation
16 @license: The BSD License
17
18 All rights reserved. This program and the accompanying materials are made
19 available under the terms of the BSD license which accompanies
20 this distribution, and is available at
21 U{http://www.opensource.org/licenses/bsd-license.php}
22 '''
23 import logging
24 import pyLinAcc
25 from AEEvent import *
26 from POR import POR
27 from AEInterfaces import *
28 from Walker import AccessibleWalker
29
30 log = logging.getLogger('View')
31
32
33 CHECK_INTERVAL = 60000
34
35
36 DEFAULT_EVENTS = [ViewChange, FocusChange, SelectorChange, CaretChange,
37 PropertyChange, PrivateChange]
38
40 '''
41 Stores a root accessible representing the active view when an event occurs
42 indicating that the view may have changed. Two view roots must be tracked
43 by this object. The first, the raw view, is needed by L{Adapters} which will
44 handle raw view change events. The second, the L{AccessEngine} view, is
45 needed by the rest of the system when processing L{AEEvent}s.
46
47 @ivar event_manager: Reference to the L{EventManager}
48 @type event_manager: L{EventManager}
49 @ivar raw_view: Root accessible representing the active view according to the
50 raw event stream.
51 @type raw_view: L{pyLinAcc.Accessible}
52 @ivar ae_view: Root L{POR} represnting the active view according to the
53 L{AEEvent} stream.
54 @type ae_view: L{POR}
55 @ivar tier_manager: Reference to the L{TierManager} for clearing dead L{Tier}
56 objects on a set interval
57 @type tier_manager: L{TierManager}
58 @ivar wanted_events: Lookup table for what L{AEEvent}s are desired by any
59 L{Task} in any L{Perk} in all L{Tier}s. Used to optimize event dispatch and
60 processing. Unwanted events are ignored.
61 @type wanted_events: dictionary
62 @ivar raw_active: Is there an raw active view?
63 @type raw_active: boolean
64 '''
66 '''
67 Initializes instance variables that will store a reference to the
68 L{EventManager} and active view to None.
69
70 @param ae: Reference to the L{AccessEngine}, currently unused
71 @type ae: L{AccessEngine}
72 '''
73 self.tier_manager = None
74 self.event_manager = None
75 self.raw_view = None
76 self.wanted_events = {}
77 self.raw_active = False
78
79 ae.addTimer(self.onIterateApps, CHECK_INTERVAL)
80
81 - def init(self, event_man, tier_man, **kwargs):
82 '''
83 Stores a reference to the L{EventManager}. Registers with the
84 L{EventManager} using the L{EventManager.EventManager.addClient} to receive
85 raw events related to the active view. Also registers
86 for raw events that may indicate that this L{ViewManager} needs to manage a
87 new view. Called by L{AccessEngine} at startup.
88
89 @param event_man: Reference to the L{EventManager}
90 @type event_man: L{EventManager}
91 '''
92
93 self.tier_manager = tier_man
94
95 self.event_manager = event_man
96
97 self.event_manager.addClient(self.onRawViewEvent,
98 *IEventHandler().getRawEvents(ViewChange))
99
100 for kind in DEFAULT_EVENTS:
101 self.setEventInterest(kind, True)
102
104 '''Does nothing.'''
105 pass
106
108 '''
109 Walks through the top level applications on the first desktop. Calls
110 L{TierManager.TierManager.createTier} for application encountered. If the
111 L{TierManager} determines that an app has at least one L{Perk} written for
112 that application, creates a L{Tier} for the application and loads all of
113 its L{Perk}s. If the L{Tier} is created, this method sends
114 L{AEEvent.ViewChange} messages to the L{Tier} with a flag of
115 L{AEConstants.Event.EVENT_VIEW_STARTUP} such that L{Perk}s in the L{Tier}
116 may initialize themselves and begin any desired background processes.
117 '''
118 try:
119 d = pyLinAcc.Registry.getDesktop(0)
120 except Exception:
121
122 return
123 ai = IAccessibleInfo(POR(d))
124 an = IAccessibleNav(POR(d))
125 events = []
126
127 for i in xrange(ai.getAccChildCount()):
128 try:
129 app = an.getChildAcc(i)
130 except (LookupError, IndexError):
131 continue
132
133 aai = IAccessibleInfo(app)
134 aid = aai.getAccAppID()
135 name = aai.getAccAppName()
136
137 if self.tier_manager.createTier(name, aid, app, True) is not None:
138 events.append(ViewChange(app, AEConstants.EVENT_VIEW_STARTUP))
139
140 if self.raw_view is not None:
141 continue
142 aan = IAccessibleNav(app)
143
144 for x in xrange(aai.getAccChildCount()):
145 try:
146 win = aan.getChildAcc(x)
147 except (LookupError, IndexError):
148 continue
149
150 wai = IAccessibleInfo(win)
151 if wai.hasAccState('active'):
152 self.raw_view = win
153 self.raw_active = True
154 break
155
156 if self.raw_view is not None:
157 events.append(ViewChange(self.raw_view,
158 AEConstants.EVENT_VIEW_FIRST_GAINED))
159 self.event_manager.postEvents(*events)
160
162 '''
163 Sets or unsets an interest in a particular kind of L{AEEvent}. This
164 information is used to register or unregister for raw events on-demand as
165 an optimization.
166
167 @param kind: Indicates the type of L{AEEvent} some part of the system wants
168 to be able to process
169 @type kind: L{AEEvent} class
170 @param wants: Does the system want to process the given kind of L{AEEvent}?
171 @type wants: boolean
172 '''
173 count = self.wanted_events.setdefault(kind, 0)
174 if wants:
175 count += 1
176 else:
177 count -= 1
178 if count <= 0:
179 del self.wanted_events[kind]
180 self.event_manager.removeClient(self.onRawEvent,
181 *IEventHandler().getRawEvents(kind))
182 return
183 elif count == 1:
184 self.event_manager.addClient(self.onRawEvent,
185 *IEventHandler().getRawEvents(kind))
186 self.wanted_events[kind] = count
187
189 '''
190 Gets the whether some view is active or not.
191
192 @return: Value of L{raw_active}
193 @rtype: boolean
194 '''
195 return self.raw_active
196
198 '''
199 Sets the whether some view is active or not.
200
201 @param val: Value to store in L{raw_active}
202 @type val: boolean
203 '''
204 self.raw_active = val
205
207 '''
208 Gets the root L{POR} of the active view according to the raw event
209 stream. This is the view known to L{Adapters}.
210
211 @see: L{setRawView}
212 @return: Root L{POR} of the raw active view
213 @rtype: L{POR}
214 '''
215 return self.raw_view
216
218 '''
219 Stores the root L{POR} of the active view according to the raw event
220 stream. This is the view known to L{Adapters}.
221
222 @see: L{getRawView}
223 @param accessible: Event source that triggered the change of view. Usually
224 a top level window or panel.
225 @type accessible: L{pyLinAcc.Accessible}
226 @return: Was a new view root set or not?
227 @rtype: boolean
228 '''
229 rv = False
230
231 root = POR(accessible)
232
233 if root != self.raw_view:
234
235 self.raw_view = root
236 rv = True
237 return rv
238
240 '''
241 Gets the root L{POR} of the active view according to the L{AEEvent} stream.
242 This is the view known to L{Perk}s.
243
244 @see: L{setAEView}
245 @return: Root L{POR} of the active L{AccessEngine} view
246 @rtype: L{POR}
247 '''
248 return self.ae_view
249
251 '''
252 Stores the root L{POR} of the active view according to the L{AEEvent}
253 stream. This is the view known to L{Adapters}.
254
255 @see: L{getAEView}
256 @param por: New root L{POR} of the active L{AccessEngine} view. May be
257 set to None if there is no active view.
258 @type por: L{POR}
259 '''
260 self.ae_view = por
261
263 '''
264 Collects all application names and IDs and gives them to the L{TierManager}
265 so it can free any L{Tier}s that are no longer associated with running
266 applications.
267
268 @return: True to continue receiving notifications
269 @rtype: boolean
270 '''
271 try:
272 d = pyLinAcc.Registry.getDesktop(0)
273 except Exception:
274
275 return
276 ai = IAccessibleInfo(POR(d))
277 an = IAccessibleNav(POR(d))
278 aids = []
279
280 for i in xrange(ai.getAccChildCount()):
281 try:
282 app = an.getChildAcc(i)
283 except (LookupError, IndexError):
284 continue
285
286 aai = IAccessibleInfo(app)
287 aids.append(aai.getAccAppID())
288
289 self.tier_manager.freeDeadTiers(aids)
290 return True
291
293 '''
294 Based on a raw L{pyLinAcc.Event.Event} posts L{AEEvent}s to the active
295 L{Tier} through the L{EventManager}.
296
297 @param event: Event indicating some change
298 @type event: L{pyLinAcc.Event.Event}
299 '''
300
301 if self.raw_view is not None:
302 try:
303 eh = IEventHandler(event.source)
304 eh.getAEEvents(event, self.event_manager.postEvents)
305 except LookupError:
306
307 return
308
310 '''
311 Creates a L{AEEvent.ViewChange} event in response to a window activation or
312 deactivation. Also responds to create or destroy events from floating
313 windows. Called in response to any of the raw events returned by
314 L{AEInterfaces.IEventHandler.getAEViewEvents} and registered with the
315 L{EventManager} in the L{ViewManager.init} method when this object was
316 created.
317
318 @param event: Event that may indicate the view has changed
319 @type event: L{pyLinAcc.Event.Event}
320 '''
321 try:
322 eh = IEventHandler(event.source)
323 eh.getAEViewEvents(event, self.event_manager.postEvents, self)
324 except LookupError:
325
326 return
327