1 '''
2 Defines a L{AEScript <AEScript.AEScript>} that keeps track of user assigned
3 bookmarks to L{AEPor}s in an application.
4
5 Steps for tying an input gesture to a bookmark location and another gesture
6 to jump to the bookmark stored at the new location:
7
8 Do the following to bind a gesture
9 1. that adds a bookmark:
10 C{self.doTask('bookmark reg add gesture',dev=dev, gesture=gesture,
11 name=aname)}
12 - 'dev' is an L{AEInput} object,
13 - 'gesture' is a list of key commands and
14 - 'name' is the name of the bookmark.
15 Please note that 'name' will be announced during the bookmark review
16 procedure.
17
18 2. that goes to a bookmark:
19 C{self.doTask('bookmark reg goto gesture',dev=dev, gesture=gesture,
20 name=aname)}
21 - 'dev' is an L{AEInput} object,
22 - 'gesture' is a list of key commands and
23 - 'name' is the name of the bookmark used in step 1.
24
25 @author: Scott Haeger
26 @author: Peter Parente
27 @organization: IBM Corporation
28 @copyright: Copyright (c) 2005, 2007 IBM Corporation
29
30 @author: Nicole Anacker
31 @organization: IT Science Center Ruegen gGmbH, Germany
32 @copyright: Copyright (c) 2007, 2008 ITSC Ruegen
33
34 @license: I{The BSD License}
35 All rights reserved. This program and the accompanying materials are made
36 available under the terms of the BSD license which accompanies
37 this distribution, and is available at
38 U{http://www.opensource.org/licenses/bsd-license.php}
39 '''
40
41 from AccessEngine import AEScript, AccessEngineAPI
42
43 from Tools.i18n import _
44 from AccessEngine.AEConstants import *
45
46 __uie__ = dict(kind='script', tier=None, all_tiers=True)
47
49 '''
50 Defines a user interface into a collection of bookmarked L{AEPor}s.
51
52 @ivar bookmarks: Collection of bookmarks I{(Alt+Caps-Lock+1-0)}::
53 Dictionary {
54 key: 'bookmark name',
55 value: {'add gesture':[gesture], 'por': bookmarkedPor}
56 }
57 @type bookmarks: dictionary
58 @ivar goto_gestures: Collection of 'goto' gestures I{(Caps-Lock+1-0)}::
59 Dictionary {
60 key: 'bookmark name',
61 value: [goto gesture]
62 }
63 @type goto_gestures: dictionary
64 @ivar whereami_gestures: Collection of 'where am i' gestures
65 I{(Alt+Shift+1-0)}::
66 Dictionary {
67 key: 'bookmark name',
68 value: [where am i gesture]
69 }
70 @type whereami_gestures: dictionary
71 @ivar bm_compare_gestures: Collection of 'compare' gestures
72 I{(Alt+Caps-Lock+Shift+1-0)}::
73 Dictionary {
74 key: 'bookmark name',
75 value: [compare gesture]
76 }
77 @type bm_compare_gestures: dictionary
78 '''
80 '''
81 Registers L{tasks <AEScript.registered_tasks>} that can be mapped to
82 L{AEInput.Gesture}s.
83 '''
84 self.bookmarks = {}
85 self.goto_gestures = {}
86 self.whereami_gestures = {}
87 self.bm_compare_gestures = {}
88
89
90 AccessEngineAPI.setScriptIdealOutput(self, 'audio')
91
92
93 self.registerTask('bookmark add bookmark', self.addBookmark)
94 self.registerTask('bookmark goto bookmark', self.gotoBookmark)
95 self.registerTask('bookmark review bookmark', self.reviewBookmark)
96 self.registerTask('bookmark where am i', self.whereAmIBookmark)
97 self.registerTask('bookmark compare bookmark', self.compareBookmark)
98
99 self.registerTask('bookmark reg add gesture', self.regBookmarkAddGesture)
100 self.registerTask('bookmark reg goto gesture', self.regBookmarkGotoGesture)
101 self.registerTask('bookmark reg where am i gesture',
102 self.regBookmarkWhereAmIGesture)
103 self.registerTask('bookmark reg bm compare gesture',
104 self.regBookmarkCompareGesture)
105
106
107 self.registerCyclicInputTask('add bookmarks', 'bookmark add bookmark')
108 self.registerCyclicInputTask('review bookmarks', 'bookmark review bookmark')
109
110
111
112 kbd = AccessEngineAPI.getInputDevice(None, 'keyboard')
113
114
115 AccessEngineAPI.addInputModifiers(self, kbd, kbd.AEK_ALT_L, kbd.AEK_ALT_R,
116 kbd.AEK_CAPS_LOCK)
117
118 AccessEngineAPI.addInputModifiers(self, kbd, kbd.AEK_ALT_L, kbd.AEK_SHIFT_L,
119 kbd.AEK_ALT_R, kbd.AEK_SHIFT_R)
120
121 self.keys = [kbd.AEK_1, kbd.AEK_2, kbd.AEK_3, kbd.AEK_4, kbd.AEK_5,
122 kbd.AEK_6, kbd.AEK_7, kbd.AEK_8, kbd.AEK_9, kbd.AEK_0]
123 modifiers = [[kbd.AEK_ALT_L, kbd.AEK_CAPS_LOCK],
124 [kbd.AEK_ALT_R, kbd.AEK_CAPS_LOCK]]
125 keynames = ['keyboard 1', 'keyboard 2', 'keyboard 3', 'keyboard 4',
126 'keyboard 5', 'keyboard 6', 'keyboard 7', 'keyboard 8',
127 'keyboard 9', 'keyboard 0']
128
129
130
131
132 for modifier in modifiers:
133 for i in range(len(self.keys)):
134 self.doTask('bookmark reg add gesture', 'BookmarkScript',
135 dev=kbd, gesture=modifier+[self.keys[i]], name=keynames[i])
136
137
138
139
140 for i in range(len(self.keys)):
141 self.doTask('bookmark reg goto gesture', 'BookmarkScript',
142 dev=kbd, gesture=[kbd.AEK_CAPS_LOCK]+[self.keys[i]],
143 name=keynames[i])
144
145
146
147 for modifier in modifiers:
148 self.registerCommand(kbd, 'bookmark review bookmark',
149 _('bookmark review bookmark'),
150 False, modifier+[kbd.AEK_TILDE])
151
152
153
154
155
156 modifiers = [[kbd.AEK_ALT_L, kbd.AEK_SHIFT_L],
157 [kbd.AEK_ALT_R, kbd.AEK_SHIFT_R]]
158 for modifier in modifiers:
159 for i in range(len(self.keys)):
160 self.doTask('bookmark reg where am i gesture', 'BookmarkScript',
161 dev=kbd, gesture=modifier+[self.keys[i]],
162 name=keynames[i])
163
164
165
166 self.command_descriptions['bookmark where am i 1-0'] = \
167 _('bookmark where am i 1-0')
168
169
170
171
172 modifiers = [[kbd.AEK_ALT_L, kbd.AEK_SHIFT_L, kbd.AEK_CAPS_LOCK],
173 [kbd.AEK_ALT_R, kbd.AEK_SHIFT_R, kbd.AEK_CAPS_LOCK]]
174 for modifier in modifiers:
175 for i in range(len(self.keys)):
176 self.doTask('bookmark reg bm compare gesture', 'BookmarkScript',
177 dev=kbd, gesture=modifier+[self.keys[i]], name=keynames[i])
178
180 '''
181 Provides the localized name of this L{AEScript <AEScript.AEScript>}.
182
183 @return: Human readable translated description of this script.
184 @rtype: string
185 '''
186 return _('Bookmarks')
187
189 '''
190 Describe which L{AETier} this script applies to by default.
191
192 @return: Human readable translated description of this script.
193 @rtype: string
194 '''
195 return _('Allows the user to bookmark locations in an application and '
196 'return to them using hotkeys at a later time.')
197
199 '''
200 Speaks information about the given L{AEPor} using an audio output device.
201
202 @param por: Point of regard for a bookmark
203 @type por: L{AEPor}
204 @param kwargs: Arbitrary keyword arguments to pass to the task
205 @type kwargs: dictionary
206 '''
207
208 self.setVirtualPOR(por)
209
210 self.doTask('read item details', 'BasicSpeechScript',
211 text=AccessEngineAPI.getItemText(por=por), por=por, **kwargs)
212
213
214
215
217 '''
218 Does a reverse lookup on L{bookmarks} using given gesture.
219
220 @param gesture: The given gesture.
221 @type gesture: L{AEInput.Gesture}
222 @return: Bookmark name
223 @rtype: string
224 '''
225 for name, value in self.bookmarks.iteritems():
226 for g in value['gestures']:
227 if g == gesture:
228 return name
229 return None
230
231 - def addBookmark(self, cycle_count, gesture=None, **kwargs):
232 '''
233 Adds a new L{bookmarks}. If a current, different bookmark will be
234 overwritten, warns the user first and requires they activate this task
235 again.
236
237 @param cycle_count: Number of times this gesture has been issued without
238 interruption
239 @type cycle_count: integer
240 @param gesture: given input gesture
241 @type gesture: L{AEInput.Gesture}
242 @param kwargs: Arbitrary keyword arguments to pass to the task
243 @type kwargs: dictionary
244 '''
245 if gesture is None: return
246 AccessEngineAPI.stopNow(self, cap='audio', role='output', **kwargs)
247
248 sorted_gest = gesture.getSortedActionCodes()
249
250 bm_index = self._reverseBookmarks(sorted_gest)
251
252 if bm_index is None:
253 return
254
255 if cycle_count == 0:
256
257 if self.bookmarks[bm_index]['por']:
258 text = _('activate again to overwrite bookmark %s')
259 AccessEngineAPI.sayInfo(self, cap='audio', role='output',
260 text=text %(bm_index), **kwargs)
261
262 else:
263 AccessEngineAPI.sayInfo(self, cap='audio', role='output',
264 text=_('adding bookmark %s') %(bm_index), **kwargs)
265 self.bookmarks[bm_index]['por'] = self.getVirtualPOR()
266
267 elif self.bookmarks[bm_index]['por'] == self.getVirtualPOR():
268 AccessEngineAPI.sayInfo(self, cap='audio', role='output',
269 text=_('already bookmarked'), **kwargs)
270 else:
271
272 AccessEngineAPI.sayInfo(self, text=_('overwriting bookmark %s.') %(bm_index),
273 cap='audio', role='output', **kwargs)
274 self.bookmarks[bm_index]['por'] = self.getVirtualPOR()
275
276
277
278
280 '''
281 Does a reverse lookup on L{goto_gestures} using given gesture.
282
283 @param gesture: The given gesture.
284 @type gesture: L{AEInput.Gesture}
285 @return: Bookmark name
286 @rtype: string
287 '''
288 for name, value in self.goto_gestures.iteritems():
289 for g in value:
290 if g == gesture:
291 return name
292 return None
293
295 '''
296 Triggers a 'pointer to por' event using the bookmarked L{AEPor}.
297
298 @param gesture: The given input gesture.
299 @type gesture: L{AEInput.Gesture}
300 @param kwargs: Arbitrary keyword arguments to pass to the task.
301 @type kwargs: dictionary
302 '''
303 if gesture is None: return
304
305 sorted_gest = gesture.getSortedActionCodes()
306 AccessEngineAPI.stopNow(self, cap='audio', role='output', **kwargs)
307
308 bm_index = self._reverseGotoGestures(sorted_gest)
309
310 if bm_index is None or self.bookmarks[bm_index]['por'] is None:
311 AccessEngineAPI.sayError(self, cap='audio', role='output',
312 text=_('no bookmark registered'), **kwargs)
313 else:
314
315 kwargs['por'] = self.bookmarks[bm_index]['por']
316 self.doTask('pointer to por', 'ReviewScript', **kwargs)
317 self.doTask('focus to por', 'ReviewScript', **kwargs)
318
319
320
321
323 '''
324 Reviews all L{bookmarks} saved in the current application.
325
326 @param cycle_count: Number of times this gesture has been issued without
327 interruption.
328 @type cycle_count: integer
329 @param gesture: The given input gesture.
330 @type gesture: L{AEInput.Gesture}
331 @param kwargs: Arbitrary keyword arguments to pass to the task.
332 @type kwargs: dictionary
333 '''
334 AccessEngineAPI.stopNow(self, cap='audio', role='output', **kwargs)
335
336 if cycle_count == 0:
337
338 havebookmark = False
339 for value in self.bookmarks.values():
340 if value['por'] is not None:
341 havebookmark = True
342 break
343
344 if not havebookmark:
345 AccessEngineAPI.sayInfo(self, cap='audio', role='output',
346 text=_("no bookmarks registered"), **kwargs)
347
348 else:
349 bm_keys = self.bookmarks.keys()
350 bm_keys.sort()
351 for key in bm_keys:
352 if self.bookmarks[key]['por'] is not None:
353 AccessEngineAPI.sayInfo(self, cap='audio', role='output',
354 text=_(key), talk=False, **kwargs)
355 kwargs['por'] = self.bookmarks[key]['por']
356 self._sayBookmark(**kwargs)
357
358 else:
359 haveavailable = False
360 for value in self.bookmarks.values():
361 if value['por'] is None:
362 haveavailable = True
363 break
364
365 if not haveavailable:
366 AccessEngineAPI.sayInfo(self, cap='audio', role='output',
367 text=_("no open bookmarks"), **kwargs)
368 else:
369 bm_keys = self.bookmarks.keys()
370 bm_keys.sort()
371 outtext = []
372 for key in bm_keys:
373 if self.bookmarks[key]['por'] is None:
374 outtext.append(_(key))
375 AccessEngineAPI.sayInfo(self, cap='audio', role='output',
376 text=_("Bookmarks %s are available.") % ', '.join(outtext), **kwargs)
377
378
379
380
382 '''
383 Does a reverse lookup on L{bm_compare_gestures} using given gesture.
384
385 @param gesture: The given gesture.
386 @type gesture: L{AEInput.Gesture}
387 @return: bookmark name
388 @rtype: string
389 '''
390 for name, value in self.bm_compare_gestures.iteritems():
391 for g in value:
392 if g == gesture:
393 return name
394 return None
395
397 '''
398 Compares the position of a given bookmark to that of the current
399 L{AETier.virtual_por <AccessEngine.AETier.AETier.virtual_por>} and announces
400 comparison information. ie. 'same POR', 'same container'
401
402 @param gesture: The given input gesture.
403 @type gesture: L{AEInput.Gesture}
404 @param kwargs: Arbitrary keyword arguments to pass to the task.
405 @type kwargs: dictionary
406 '''
407 if gesture is None: return
408 sorted_gest = gesture.getSortedActionCodes()
409 AccessEngineAPI.stopNow(self, cap='audio', role='output', **kwargs)
410
411 bm_index = self._reverseCompare(sorted_gest)
412
413 if bm_index is None or self.bookmarks[bm_index]['por'] is None:
414 AccessEngineAPI.sayError(self, cap='audio', role='output',
415 text=_('no bookmark registered'), **kwargs)
416 else:
417 bm_por = self.bookmarks[bm_index]['por']
418
419
420
421 if bm_por == self.getVirtualPOR():
422 AccessEngineAPI.sayInfo(self, cap='audio', role='output',
423 text=_('bookmark equals pointer'), **kwargs)
424 return
425
426 parent = AccessEngineAPI.getParentAcc(kwargs['por'])
427 if parent == AccessEngineAPI.getParentAcc(por=bm_por):
428 AccessEngineAPI.sayInfo(self, cap='audio', role='output',
429 text=_('bookmark and pointer have same parent'), **kwargs)
430 kwargs['por'] = parent
431 self._sayBookmark(**kwargs)
432 return
433
434 taskpor_ancestors = {}
435 for p in AccessEngineAPI.iterAncestorAccs(self.getVirtualPOR()):
436 taskpor_ancestors[p] = None
437
438 for p in AccessEngineAPI.iterAncestorAccs(por=bm_por):
439 if taskpor_ancestors.has_key(p):
440 AccessEngineAPI.sayInfo(self, cap='audio', role='output',
441 text=_('bookmark in same container'), **kwargs)
442 kwargs['por'] = p
443 self._sayBookmark(**kwargs)
444 return
445
446
447 if AccessEngineAPI.getAppName(kwargs['por']) == AccessEngineAPI.getAppName(bm_por):
448 AccessEngineAPI.sayInfo(self, cap='audio', role='output',
449 text=_('bookmark and pointer are in the same application'),
450 **kwargs)
451 return
452
453 AccessEngineAPI.sayInfo(self, cap='audio', role='output',
454 text=_('comparison unknown'), **kwargs)
455
456
457
458
460 '''
461 Does a reverse lookup on L{whereami_gestures} using given gesture.
462
463 @param gesture: The given gesture.
464 @type gesture: L{AEInput.Gesture}
465 @return: bookmark name
466 @rtype: string
467 '''
468 for name, value in self.whereami_gestures.iteritems():
469 for g in value:
470 if g == gesture:
471 return name
472 return None
473
475 '''
476 Reports the location of the selected bookmark by announcing all control and
477 container names in child-to-parent order.
478
479 @param gesture: The given input gesture.
480 @type gesture: L{AEInput.Gesture}
481 @param kwargs: Arbitrary keyword arguments to pass to the task.
482 @type kwargs: dictionary
483 '''
484 if gesture is None: return
485 sorted_gest = gesture.getSortedActionCodes()
486 AccessEngineAPI.stopNow(self, cap='audio', role='output', **kwargs)
487
488 bm_index = self._reverseWhereAmI(sorted_gest)
489
490 if bm_index is None or self.bookmarks[bm_index]['por'] is None:
491 AccessEngineAPI.sayError(self, cap='audio', role='output',
492 text=_('no bookmark registered'), **kwargs)
493 else:
494 kwargs['por'] = self.bookmarks[bm_index]['por']
495 self.doTask('where am i ancestors', 'BasicSpeechScript', **kwargs)
496
497
498
499
501 '''
502 Register a named L{'add' bookmark <bookmarks>} gesture.
503
504 @param dev: An input device.
505 @type dev: L{AEInput}
506 @param gesture: List of keys that represent a gesture.
507 @type gesture: list
508 @param name: Point of regard for a bookmark
509 @type name: string
510 @param kwargs: Arbitrary keyword arguments to pass to the task.
511 @type kwargs: dictionary
512 '''
513 if dev is None or gesture is None or name is None:
514 return
515
516 self.registerCommand(dev, 'bookmark add bookmark',
517 _('bookmark add bookmark'), False, gesture)
518
519 gesture.sort()
520
521 if not self.bookmarks.has_key(name):
522 self.bookmarks[name] = {'gestures':[gesture], 'por':None}
523 else:
524 self.bookmarks[name]['gestures'].append(gesture)
525
527 '''
528 Register a named L{'goto' bookmark <goto_gestures>} gesture.
529
530 @param dev: An input device
531 @type dev: L{AEInput}
532 @param gesture: List of keys that represent a gesture.
533 @type gesture: list
534 @param name: Point of regard for a bookmark
535 @type name: string
536 @param kwargs: Arbitrary keyword arguments to pass to the task.
537 @type kwargs: dictionary
538 '''
539 if dev is None or gesture is None or name is None:
540 return
541
542 self.registerCommand(dev, 'bookmark goto bookmark',
543 _('bookmark goto bookmark'), False, gesture)
544
545 gesture.sort()
546
547 if not self.goto_gestures.has_key(name):
548 self.goto_gestures[name] = [gesture]
549 else:
550 self.goto_gestures[name].append(gesture)
551
553 '''
554 Register a named L{'where am i' bookmark <whereami_gestures>} gesture.
555
556 @param dev: An input device
557 @type dev: L{AEInput}
558 @param gesture: List of keys that represent a gesture.
559 @type gesture: list
560 @param name: Point of regard for a bookmark
561 @type name: string
562 @param kwargs: Arbitrary keyword arguments to pass to the task.
563 @type kwargs: dictionary
564 '''
565 if dev is None or gesture is None or name is None:
566 return
567
568 self.registerCommand(dev, 'bookmark where am i', _('bookmark where am i'),
569 False, gesture)
570
571 gesture.sort()
572
573 if not self.whereami_gestures.has_key(name):
574 self.whereami_gestures[name] = [gesture]
575 else:
576 self.whereami_gestures[name].append(gesture)
577
579 '''
580 Register a named L{'compare bookmark' <bm_compare_gestures>} gesture.
581
582 @param dev: An input device
583 @type dev: L{AEInput}
584 @param gesture: List of keys that represent a gesture.
585 @type gesture: list
586 @param name: Point of regard for a bookmark
587 @type name: string
588 @param kwargs: Arbitrary keyword arguments to pass to the task.
589 @type kwargs: dictionary
590 '''
591 if dev is None or gesture is None or name is None:
592 return
593
594 self.registerCommand(dev, 'bookmark compare bookmark',
595 _('bookmark compare bookmark'), False, gesture)
596
597 gesture.sort()
598
599 if not self.bm_compare_gestures.has_key(name):
600 self.bm_compare_gestures[name] = [gesture]
601 else:
602 self.bm_compare_gestures[name].append(gesture)
603