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

Source Code for Module DefaultDialogScript

  1  ''' 
  2  Defines tasks for managing the chooser dialogs packaged with the SUE core. 
  3   
  4  @author: Peter Parente 
  5  @organization: IBM Corporation 
  6  @copyright: Copyright (c) 2005, 2007 IBM Corporation 
  7  @license: The BSD License 
  8   
  9  @author: Frank Zenker 
 10  @author: Nicole Anacker 
 11  @organization: IT Science Center Ruegen gGmbH, Germany 
 12  @copyright: Copyright (c) 2007, 2008 ITSC Ruegen 
 13  @license: The BSD License 
 14   
 15  All rights reserved. This program and the accompanying materials are made  
 16  available under the terms of the BSD license which accompanies 
 17  this distribution, and is available at 
 18  U{http://www.opensource.org/licenses/bsd-license.php} 
 19  ''' 
 20  # import useful modules for Scripts 
 21  from AccessEngine import AEScript, AccessEngineAPI 
 22  from AccessEngine import AEConstants 
 23  import AccessEngine 
 24  #from AccessEngine.AEPor import AEPor 
 25  from Tools.i18n import _ 
 26   
 27  __uie__ = dict(kind='script', all_tiers=True) 
 28   
29 -class DefaultDialogScript(AEScript.EventScript):
30 ''' 31 Manages the basic SUE dialogs for configuring settings and loading Scripts. 32 33 Shows and hides default SUE chooser dialogs for configuring SUE settings, 34 loading and unloading extensions at run time, and so on. Tasks for starting 35 choosers are defined, but not mapped to any particular input device. Some 36 other Script must define the input mappings. 37 38 @ivar installed: All UIE class names, human readable names, and descriptions 39 installed keyed by their type 40 @type installed: dictionary of string : list of 3-tuple of string 41 @ivar associated: All UIE class names, human readable names, and descriptions 42 associated with this profile keyed by their type 43 @type associated: dictionary of string : list of 3-tuple of string 44 '''
45 - def init(self):
46 ''' 47 Registers named tasks for script chooser, settings chooser, and 48 command chooser 49 ''' 50 51 self.registerTask('show settings chooser', self.onChooserChange) 52 self.registerTask('show script chooser', self.onChooserChange) 53 self.registerTask('show command chooser', self.onChooserChange) 54 55 # get the Keyboard device and register modifiers and commands 56 kbd = AccessEngineAPI.getInputDevice(None, 'keyboard') 57 AccessEngineAPI.addInputModifiers(self, kbd, kbd.AEK_ALT_L, 58 kbd.AEK_SHIFT_L, kbd.AEK_ALT_R, 59 kbd.AEK_SHIFT_R, kbd.AEK_CAPS_LOCK) 60 61 # register commands for either left Alt-Shift or right Alt-Shift 62 pairs = [[kbd.AEK_ALT_L, kbd.AEK_SHIFT_L], [kbd.AEK_ALT_R, kbd.AEK_SHIFT_R]] 63 64 for pair in pairs: 65 self.registerCommand(kbd, 'show settings chooser', 66 _('show settings chooser'), 67 False, pair+[kbd.AEK_F2]) 68 self.registerCommand(kbd, 'show script chooser', 69 _('show script chooser'), 70 False, pair+[kbd.AEK_F3]) 71 self.registerCommand(kbd, 'show command chooser', 72 _('show command chooser'), 73 False, pair+[kbd.AEK_F4])
74 75
76 - def getName(self):
77 ''' 78 Provides the localized name of this L{AccessEngine.AEScript}. 79 ''' 80 return _('Basic dialogs')
81
82 - def onChooserStart(self, **kwargs):
83 ''' 84 Decides wich chooser shall be started. 85 ''' 86 if kwargs['task_name'] == 'show script chooser': 87 return self.onScriptChooserStart(**kwargs) 88 elif kwargs['task_name'] == 'show settings chooser': 89 return self.onSettingsChooserStart(**kwargs) 90 elif kwargs['task_name'] == 'show command chooser': 91 return self.onCommandChooserStart(**kwargs) 92 else: 93 return True
94
95 - def onChooserSignal(self, **kwargs):
96 ''' 97 Decides wich chooser shall get the signal. 98 ''' 99 if kwargs['task_name'] == 'show script chooser': 100 return self.onScriptChooserSignal(**kwargs) 101 elif kwargs['task_name'] == 'show settings chooser': 102 return self.onSettingsChooserSignal(**kwargs) 103 elif kwargs['task_name'] == 'show command chooser': 104 return self.onCommandChooserSignal(**kwargs) 105 else: 106 return True
107 108 ###################### 109 ### Script Chooser ### 110 ######################
111 - def onScriptChooserStart(self, timestamp, **kwargs):
112 ''' 113 Shows the Script chooser which allows a user to pick Scripts to load and 114 unload from the current application at runtime. 115 Runs when an input gesture is given to start the chooser. Buids lists of 116 currently loaded and available L{AccessEngine.AEScript}s, shows the chooser, 117 and provides it with the lists. 118 119 @param timestamp: Time to provide to the chooser dialog so it can raise 120 itself to the foreground properly 121 @type timestamp: float 122 ''' 123 # get programmatic and human readable names and description 124 loaded = AccessEngineAPI.getScriptMetadata(self.tier) 125 # put the Scripts in execution order, not load order 126 #loaded.reverse() 127 installed = AccessEngineAPI.getScriptMetadata(self.tier, 128 AEConstants.UIE_INSTALLED) 129 # compute the difference of the two lists using sets 130 unloaded = list(set(installed) - set(loaded)) 131 # sort the unloaded in alphabetical order 132 unloaded.sort() 133 # load the chooser and give it the two sets 134 AccessEngineAPI.loadChooser(self, 'ScriptChooser', loaded=loaded, 135 unloaded=unloaded, 136 app_name=AccessEngineAPI.getAppName(kwargs.get('por')), 137 timestamp=timestamp, **kwargs)
138
139 - def onScriptChooserSignal(self, **kwargs):
140 ''' 141 Runs when the chooser sends a signal to this L{AccessEngine.AEScript} 142 indicating some change in the dialog that the L{AccessEngine.AEScript} 143 should be aware of. Signals of interest defined by this particular chooser 144 include: 145 146 - OK: Complete the dialog accepting current load/unload configuration 147 - APPLY: Accept current load/unload configuration without completing 148 - RAISE: Move a L{AccessEngine.AEScript} up in the load order 149 - LOWER: Move a L{AccessEngine.AEScript} down in the load order 150 - TO_LOAD: Add a L{AccessEngine.AEScript} to the list of 151 L{AccessEngine.AEScript}s to load 152 - TO_UNLOAD: Remove a L{AccessEngine.AEScript} from the list of 153 L{AccessEngine.AEScript}s to load 154 155 @param kwargs: Keyword arguments specific to each signal type 156 @type kwargs: dictionary 157 @keyword kwargs['chooser']: Reference to the chooser object that sent the signal 158 @type kwargs['chooser']: L{AEChooser} 159 @keyword kwargs['kind']: Signal name 160 @type kwargs['kind']: string 161 ''' 162 kind = kwargs['kind'] 163 chooser = kwargs['chooser'] 164 # stop speech and make a model-based announcement 165 AccessEngineAPI.stopNow(self, cap='audio', role='output', **kwargs) 166 # inhibit the next event from stopping us (possibly a selection) 167 AccessEngineAPI.inhibitMayStop() 168 por = kwargs['por'] 169 if kind == chooser.APPLY: 170 text=_('applied changes to %s') % AccessEngineAPI.getAppName(por) 171 self.doTask('read message', 'BasicSpeechScript', text=text, **kwargs) 172 elif kind == chooser.RAISE: 173 text = _('raised %(name)s above %(below)s, below %(above)s') % kwargs 174 self.doTask('read message', 'BasicSpeechScript', text=text, **kwargs) 175 elif kind == chooser.LOWER: 176 text = _('lowered %(name)s below %(above)s, above %(below)s') % kwargs 177 self.doTask('read message', 'BasicSpeechScript', text=text, **kwargs) 178 elif kind == chooser.TO_LOAD: 179 kwargs['app'] = AccessEngineAPI.getAppName(por) 180 text = _('added %(name)s to %(app)s as first') % kwargs 181 self.doTask('read message', 'BasicSpeechScript', text=text, **kwargs) 182 elif kind == chooser.TO_UNLOAD: 183 kwargs['app'] = AccessEngineAPI.getAppName(por) 184 text = _('removed %(name)s from %(app)s') % kwargs 185 self.doTask('read message', 'BasicSpeechScript', text=text, **kwargs) 186 187 if kind in (chooser.OK, chooser.APPLY): 188 # load and unload Scripts 189 self._doScriptLoad(**kwargs)
190
191 - def _doScriptLoad(self, loaded, unloaded, **kwargs):
192 ''' 193 Loads and unloads L{AccessEngine.AEScript}s according to the current state 194 of the chooser dialog. 195 196 @param loaded: Names of L{AccessEngine.AEScript}s to load on this L{AETier} 197 @type loaded: list 198 @param unloaded: Names of L{AccessEngine.AEScript}s not to load on this 199 L{AETier} 200 @type unloaded: list 201 ''' 202 # get the names of all Scripts loaded on this AETier 203 curr_loaded = AccessEngineAPI.getScriptClassNames(self.tier) 204 # compute the difference between those that should be loaded according 205 # to the chooser and those that are currently loaded in the AETier 206 to_load = set(loaded) - set(curr_loaded) 207 # compute the intersection between those that are loaded in the AETier and 208 # those that should be unloaded according to the chooser 209 to_unload = set(curr_loaded).intersection(unloaded) 210 # get rid of scripts to unload first 211 indices = [curr_loaded.index(script) for script in to_unload] 212 AccessEngineAPI.popScript(self.getAETier() ,*indices) 213 # now load new scripts in the proper order 214 for script in to_load: 215 # get the proper index for this script 216 i = loaded.index(script) 217 # insert it into the script stack 218 AccessEngineAPI.insertScript(self.tier, i, script)
219 220 ######################## 221 ### Settings Chooser ### 222 ########################
223 - def initSettingsChooser(self):
224 ''' 225 Initialize installed, associated, and chooser variables. 226 ''' 227 self.installed = None 228 self.associated = None
229
230 - def onSettingsChooserStart(self, timestamp, **kwargs):
231 ''' 232 Shows the settings chooser which allows a user to configure SUE devices, 233 Scripts, profiles, and general system settings. 234 Load the L{SettingsChooser} and give it the required settings model for 235 the system, L{AccessEngine.AEScript}s, devices, and profile. 236 237 @param timestamp: Time to provide to the chooser dialog so it can raise 238 itself to the foreground properly 239 @type timestamp: float 240 ''' 241 self.initSettingsChooser() 242 # get profile information 243 self._getProfileInfo() 244 profile = AccessEngineAPI.getProfileName() 245 # get the SUE system settings and save state to support undo 246 system = AccessEngine.AETierManager.getState() 247 system.save() 248 249 # get metadata of all scripts in this profile and currently loaded 250 # can't just get names because ordering is lost when using sets to filter 251 # duplicates 252 md = set(AccessEngineAPI.getScriptMetadata(self.tier, 253 AEConstants.UIE_ALL_ASSOCIATED)) 254 md.update(AccessEngineAPI.getScriptMetadata(self.tier, AEConstants.UIE_LOADED)) 255 # load state for each named script 256 states = [(name, AccessEngineAPI.getScriptState(self.tier, cls_name)) 257 for (cls_name, name, desc) in md] 258 scripts = self._readyStates(states) 259 260 # get names of all devices currently loaded 261 names = AccessEngineAPI.getDeviceClassNames(AEConstants.UIE_LOADED) 262 # load state for each named device 263 states = [AccessEngineAPI.getDeviceState(name) for name in names] 264 states = zip(AccessEngineAPI.getDeviceNames(AEConstants.UIE_LOADED), states) 265 devices = self._readyStates(states) 266 267 # load and show the chooser 268 chooser = AccessEngineAPI.loadChooser(self, 'SettingsChooser', system=system, 269 scripts=scripts, associated=self.associated, 270 installed=self.installed, 271 profile=profile, devices=devices, 272 timestamp=timestamp, **kwargs)
273
274 - def _getProfileInfo(self):
275 ''' 276 Populates the installed and associated profile metadata dictionary. 277 ''' 278 self.installed = { 279 'scripts' : AccessEngineAPI.getScriptMetadata(self.tier, 280 AEConstants.UIE_INSTALLED), 281 'devices' : AccessEngineAPI.getDeviceMetadata(AEConstants.UIE_INSTALLED), 282 'monitors' : AccessEngineAPI.getMonitorMetadata(AEConstants.UIE_INSTALLED), 283 'choosers' : AccessEngineAPI.getChooserMetadata(AEConstants.UIE_INSTALLED)} 284 285 self.associated = { 286 'scripts' : AccessEngineAPI.getScriptMetadata(self.tier, 287 AEConstants.UIE_ALL_ASSOCIATED), 288 'devices' : AccessEngineAPI.getDeviceMetadata(AEConstants.UIE_ALL_ASSOCIATED), 289 'monitors' : AccessEngineAPI.getMonitorMetadata(AEConstants.UIE_ALL_ASSOCIATED), 290 'choosers' : AccessEngineAPI.getChooserMetadata(AEConstants.UIE_ALL_ASSOCIATED)}
291
292 - def _readyStates(self, states):
293 ''' 294 Prepare settings objects by storing a copy of the current settings so 295 that they may be restored at a later time. 296 297 @param states: States paired with the names of the UIEs having those 298 states 299 @type states: list of 2-tuple of string, L{AEState} 300 @return: Dictionary pairing UIE name with its state object 301 @rtype: dictionary 302 ''' 303 uies = {} 304 for name, state in states: 305 try: 306 state.save() 307 except AttributeError: 308 # ignore missing states 309 continue 310 state.save() 311 uies[name] = state 312 return uies
313
314 - def onSettingsChooserSignal(self, **kwargs):
315 ''' 316 Runs when the chooser sends a signal to this L{AccessEngine.AEScript} 317 indicating some change in the chooser that the L{AccessEngine.AEScript} 318 should be aware of. Signals of interest defined by this particular chooser 319 include: 320 321 - OK: Complete the dialog accepting current values 322 - APPLY: Accept current values without completing 323 - RAISE: Move a L{AEUserInterface} up in the load order 324 - LOWER: Move a L{AEUserInterface} down in the load order 325 - TO_LOAD: Add a L{AEUserInterface} to the list to load 326 - TO_UNLOAD: Remove a L{AEUserInterface} from the list to load 327 328 @param kwargs: Keyword arguments specific to each signal type 329 @type kwargs: dictionary 330 @keyword kwargs['chooser']: Reference to the chooser object that sent the 331 signal 332 @type kwargs['chooser']: L{AEChooser} 333 @keyword kwargs['kind']: Signal name 334 @type kwargs['kind']: string 335 ''' 336 kind = kwargs['kind'] 337 chooser = kwargs['chooser'] 338 # make changes first, then do announcements in case a new device is loaded 339 if kind == chooser.APPLY: 340 self._doApply(**kwargs) 341 elif kind == chooser.OK: 342 self._doApply(**kwargs) 343 elif kind == chooser.CANCEL: 344 # undo any setting changes 345 self._doCancel(**kwargs) 346 347 # stop speech and make a model-based announcement 348 AccessEngineAPI.stopNow(self, cap='audio', role='output', **kwargs) 349 350 # inhibit the next event from stopping us (possibly a selection) 351 AccessEngineAPI.inhibitMayStop() 352 if kind == chooser.APPLY: 353 text=_('applied changes to settings') 354 self.doTask('read message', 'BasicSpeechScript', text=text, **kwargs) 355 elif kind == chooser.RAISE: 356 text = _('raised %(name)s above %(below)s, below %(above)s') % kwargs 357 self.doTask('read message', 'BasicSpeechScript', text=text, **kwargs) 358 elif kind == chooser.LOWER: 359 text = _('lowered %(name)s below %(above)s, above %(below)s') % kwargs 360 self.doTask('read message', 'BasicSpeechScript', text=text, **kwargs) 361 elif kind == chooser.TO_LOAD: 362 text = _('added %(name)s as first') % kwargs 363 self.doTask('read message', 'BasicSpeechScript', text=text, **kwargs) 364 elif kind == chooser.TO_UNLOAD: 365 text = _('removed %(name)s') % kwargs 366 self.doTask('read message', 'BasicSpeechScript', text=text, **kwargs)
367
368 - def _doApply(self, chooser, system, scripts, devices, associated, 369 installed=None, **kwargs):
370 ''' 371 Apply all system, L{AccessEngine.AEScript}, and device settings. Make any 372 necessary changes to the current profile and install/uninstall any 373 L{AEUserInterface}s. 374 375 @param chooser: Reference to the chooser object that sent the signal 376 @type chooser: L{AEChooser} 377 @param system: System state 378 @type system: L{AEState} 379 @param scripts: L{AccessEngine.AEScript} state to apply 380 @type scripts: list of L{AEState} 381 @param devices: Device state to apply 382 @type devices: list of L{AEState} 383 @param installed: All UIE class names selected for installation keyed by 384 their type 385 @type installed: dictionary of string : list of string 386 @param associated: All UIE class names selected for association with this 387 profile keyed by their type 388 @type associated: dictionary of string : list of string 389 ''' 390 # save all runtime settings 391 system.save() 392 [state.save() for state in scripts.values()] 393 [state.save() for state in devices.values()] 394 # task tools to use to do associations and disassociations 395 tools = {'scripts' : (AccessEngineAPI.associateScript, 396 AccessEngineAPI.disassociateScript), 397 'monitors' : (AccessEngineAPI.associateMonitor, 398 AccessEngineAPI.disassociateMonitor), 399 'devices' : (AccessEngineAPI.associateDevice, 400 AccessEngineAPI.disassociateDevice)} 401 # compare current and saved associations 402 for kind in associated: 403 new = associated[kind] 404 old = [metadata[0] for metadata in self.associated[kind]] 405 to_remove = set(old) - set(new) 406 to_add = set(new) - set(old) 407 if len(to_add) > 0 or len(to_remove) > 0: 408 # do removals first 409 map(tools[kind][1], to_remove) 410 if kind == 'devices': 411 # reassociate all devices to get the order right 412 map(tools[kind][0], new) 413 # reload devices according to new preferences 414 AccessEngineAPI.refreshDevices() 415 if chooser is not None: 416 # update the chooser with the list of new devices 417 # get names of all devices currently loaded 418 names = AccessEngineAPI.getDeviceClassNames(AEConstants.UIE_LOADED) 419 # load state for each named device 420 states = [AccessEngineAPI.getDeviceState(name) for name in names] 421 states = zip(AccessEngineAPI.getDeviceNames(AEConstants.UIE_LOADED), 422 states) 423 devices = self._readyStates(states) 424 chooser.updateDevices(devices) 425 else: 426 # do new associations without regard to order for non-devices 427 map(tools[kind][0], to_add) 428 # rebuild lists of installed and associated 429 self._getProfileInfo()
430
431 - def _doCancel(self, system, scripts, devices, **kwargs):
432 ''' 433 Cancel all system, L{AccessEngine.AEScript}, and device setting changes. 434 Ignore changes to the current profile. 435 436 @param system: System state 437 @type system: L{AEState} 438 @param scripts: L{AccessEngine.AEScript} state to apply 439 @type scripts: list of L{AEState} 440 @param devices: Device state to apply 441 @type devices: list of L{AEState} 442 ''' 443 system.restore() 444 for state in scripts.values(): 445 state.restore() 446 for state in devices.values(): 447 state.restore()
448
449 - def onCommandChooserStart(self, timestamp, **kwargs):
450 ''' 451 Starts the command chooser providing a list of all currently registered 452 key commands sorted by their respective parent scripts. 453 ''' 454 AccessEngineAPI.loadChooser(self, 'CommandChooser', timestamp=timestamp, 455 **kwargs)
456
457 - def onCommandChooserSignal(self, **kwargs):
458 ''' 459 Runs when the chooser sends a signal to this L{AccessEngine.AEScript} 460 indicating some change in the chooser that the L{AccessEngine.AEScript} 461 should be aware of. There's only one signals of interest defined by this 462 particular chooser that we want to react upon: 463 - OK: Complete the dialog accepting current values 464 465 @param kwargs: Keyword arguments specific to each signal type 466 @type kwargs: dictionary 467 @keyword kwargs['chooser']: Reference to the chooser object that sent the 468 signal 469 @type kwargs['chooser']: L{AEChooser} 470 @keyword kwargs['kind']: Signal name 471 @type kwargs['kind']: string 472 ''' 473 # stop speech and make a model-based announcement 474 self.stopNow(self, cap='audio', role='output', **kwargs) 475 # inhibit the next event from stopping us (possibly a selection) 476 self.inhibitMayStop(self, **kwargs) 477 if kwargs['kind'] == kwargs['chooser'].OK: 478 self.doTask('read message', 'BasicSpeechScript', 479 text=_('leaving command chooser'), **kwargs)
480