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

Source Code for Module CommandChooser

  1  ''' 
  2  Defines a gtk window L{AEChooser} showing a list of all available key commands. 
  3  (Inspired by ScriptChooser and Orca's settings dialog (Keybindings Tab)) 
  4   
  5  Use + and - to expand and collapse tree view items (for all gtk tree views). 
  6   
  7  @author: Frank Zenker 
  8  @author: Martina Weicht 
  9  @organization: IT Science Center Ruegen gGmbH, Germany 
 10  @copyright: Copyright (c) 2007, 2008 ITSC Ruegen 
 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   
 19  import pygtk 
 20  pygtk.require('2.0') 
 21  import gtk, gobject, logging, pango, unicodedata, string 
 22  import gtk.gdk as gdk 
 23  import gtk.glade 
 24  import AccessEngine 
 25  from AccessEngine import AEChooser 
 26  import AccessEngine.AEConstants.Spelling as Spelling 
 27  from Tools.i18n import _, DOMAIN 
 28  import gettext 
 29  from GTKUIEView import * 
 30   
 31  __uie__ = dict(kind='chooser') 
 32   
 33  log = logging.getLogger('CommandChooser') 
 34   
35 -class CommandChooser(AEChooser.AEChooser):
36 ''' 37 Window presenting a list of all currently available key commands. 38 39 @note: MW: constant SEPARATOR should be turned into a setting so users 40 can decided on which characters to use (comma, plus, ...) 41 42 @ivar dialog: Window widget for looking at keybindings 43 @type dialog: gtk.Window 44 @ivar DESCRIPTION: constant for column named 'description' 45 @type DESCRIPTION: integer 46 @ivar KEYBINDINGS: constant for column named 'keybindung' 47 @type KEYBINDINGS: integer 48 @ivar DEVICE: constant for column named 'device' 49 @type DEVICE: integer 50 @ivar SEPARATOR: string separating keys within keybindings string 51 @type SEPARATOR: string 52 ''' 53 # column name constants 54 DESCRIPTION = 0 55 KEYBINDINGS = 1 56 DEVICE = 2 57 58 # separators inbetween keybindings - could be individualized by user 59 SEPARATOR = ', ' 60
61 - def init(self, **kwargs):
62 ''' 63 Creates and shows the chooser dialog and its components. 64 ''' 65 # load the glade file 66 source = gtk.glade.XML(self._getResource('command_chooser.glade'), 67 'main window', 68 DOMAIN) 69 self.window = source.get_widget('main window') 70 self.kb_tree_view = source.get_widget('kb tree view') 71 72 # create tree view and set data 73 self._createKeyBindingsView() 74 75 # connect all signal handlers 76 source.signal_autoconnect(self) 77 78 self.window.show_all()
79 80
81 - def _createKeyBindingsView(self):
82 ''' 83 Creates an ordered chooser widget. 84 85 @note: mw: The UIEView was not suitable since they have a fixed set of 86 columns for their list. Also, I wanted the keybindings to be assigned to 87 their parent script, so TreeStore was a better choice than ListStore. 88 Maybe a more generic approach to the UIEView can combine those two views 89 allowing the columns and the model to be specified individually. 90 ''' 91 self.kb_model = gtk.TreeStore( 92 gobject.TYPE_STRING, # human readable description 93 gobject.TYPE_STRING, # keybinding 94 gobject.TYPE_STRING) # device on which keys are pressed 95 96 self.kb_tree_view.set_model(self.kb_model) 97 self.kb_tree_view.set_headers_visible(True) 98 99 rendererText = gtk.CellRendererText() 100 rendererText.set_property("ellipsize", pango.ELLIPSIZE_END) 101 102 # description column 103 column = gtk.TreeViewColumn(_("description"), 104 rendererText, 105 text=self.DESCRIPTION) 106 column.set_resizable(True) 107 column.set_min_width(250) 108 column.set_sort_column_id(self.DESCRIPTION) 109 self.kb_tree_view.append_column(column) 110 111 # keybindings column 112 column = gtk.TreeViewColumn( _("keybinding"), 113 rendererText, 114 text=self.KEYBINDINGS) 115 column.set_resizable(True) 116 column.set_min_width(250) 117 column.set_sort_column_id(self.KEYBINDINGS) 118 self.kb_tree_view.append_column(column) 119 120 # description device 121 column = gtk.TreeViewColumn(_("device"), 122 rendererText, 123 text=self.DEVICE) 124 column.set_resizable(True) 125 column.set_sort_column_id(self.DEVICE) 126 self.kb_tree_view.append_column(column) 127 128 # populates treeview with keybindings 129 self._populateKeyBindings() 130 self.kb_model.set_sort_column_id(self.DESCRIPTION, gtk.SORT_ASCENDING)
131 132
133 - def _populateKeyBindings(self):
134 ''' 135 Populates the list of currently registered keybindings. 136 Traverses the list of all registered scripts (per tier, but excluding doubles) 137 and creates a list of all keybindings along with their description. 138 ''' 139 def_keymap = gdk.keymap_get_default() 140 141 kb_list = {} 142 kb_array = [] 143 queue2 = [] 144 145 # list of all tiers 146 tiers = AccessEngine.AETierManager.tiers.values() 147 for tier in tiers: 148 149 # list of all scripts per tier 150 scripts = tier.getScripts() 151 for script in scripts: 152 153 # if this node does not already exist 154 if self._getIterator( script.getName() ) == None: 155 156 # create node in tree view 157 script_iterator = self._createNode( script.getName()) 158 159 # for all commands registered for this script 160 for command, id in script.commands.iteritems(): 161 162 # textual description (maybe replace this by localized description?) 163 id = script.commands[command] 164 165 # retrieving the description from the tupel 166 id, name = id 167 #id = description 168 #gesture = command.getGestureAt(0) 169 device = command.getDevice() 170 171 # localized description of keybinding 172 description = script.command_descriptions[id] 173 174 #num = command.getNumGestures() 175 #i = 0 176 #while i < num: 177 #gesture = command.getGestureAt(i) 178 #action_codes = gesture.getActionCodes() 179 180 #code_string = '' 181 #for action_code in action_codes: 182 #key_name = None 183 #entries = def_keymap.get_entries_for_keycode(action_code) 184 #if entries and len(entries): 185 #keyval_name = gdk.keyval_name(entries[0][0]) 186 #log.info('Keyval_name: %s', keyval_name) 187 ##log.info('unicodedata_lookup %s', unicodedata.lookup(keyval_name)) 188 #try: 189 #key_name = Spelling.FUNCTION_KEYS[keyval_name] 190 191 #except KeyError: 192 #try: 193 194 #key_name = Spelling.SPELLED_MAP[ unicodedata.lookup(keyval_name) ] 195 #except KeyError: 196 #pass 197 #if key_name is not None: 198 #log.info('Key name: %s', _(key_name)) 199 #code_string += _(key_name) 200 #else: 201 #log.info('Key name not found: %s', keyval_name) 202 #code_string += keyval_name 203 #code_string += self.SEPARATOR 204 #i += 1 205 206 # clean up the string representing a keybinding 207 208 code_string = '' 209 command_string = command.asString().strip('()') 210 for code in command_string.split(','): 211 # Versuch, die einzelnen Tasten-Namen ebenfalls zu uebersetzen 212 # und dabei auf Spelling.py/ SPELLED_MAP zuzugreifen 213 code_string += _(code) 214 code_string += self.SEPARATOR 215 216 # remove separator at the end 217 code_string = code_string[0:len(code_string)-len(self.SEPARATOR)] 218 219 220 # In some cases (i.e. BookmarkScript) serveral similar keybindings 221 # exist. They only differ in their number to be pressed (i.e. goto 222 # bookmark 2-0), but carry the same description. 223 # Therefore, we're building a separate list to which we do not add 224 # duplicate descriptions. 225 226 # add keybinding to a separate list 227 # put code_string first to allow for duplicate descriptions 228 kb_list[code_string] = description 229 ##queue1.append((description, code_string)) 230 #kb_array.append((description, code_string)) 231 232 # now clean up list: 233 234 ## making things more easy :) 235 #kb_array.sort() 236 237 ## moving through the array using 2 pointers 238 #for i in range(0,len(kb_array)): 239 240 #entry1 = kb_array[i] 241 #log.info("Entry1: %s", entry1) 242 243 #for j in range(i+1,len(kb_array)): 244 245 #entry2 = kb_array[j] 246 #log.info("Entry2: %s", entry2) 247 248 249 #if entry1[0] == entry2[0]: 250 #log.info("gleiche description") 251 ## we found two entries with the same description 252 253 ## do they both have the same code_string ending with a digit? 254 #entry1 = entry1[1:len(entry1)] 255 #entry1.sort() 256 #log.info("Entry1_new: %s", entry1) 257 #entry2 = entry2[1:len(entry2)] 258 #entry2.sort() 259 #log.info("Entry2_new: %s", entry2) 260 261 262 263 #else: 264 #break 265 266 #log.info("--") 267 #log.info("--") 268 269 # add key sequence, description, and device to table 270 for entry in kb_list: 271 self._insertRow(kb_list[entry], entry, device.getName(), script_iterator) 272 273 274 # empty list 275 kb_list = {} 276 #kb_array = [] 277 278 # if a script does not contain any keybindings, then remove it 279 if not self.kb_model.iter_has_child(script_iterator): 280 self.kb_model.remove(script_iterator) 281 282 # select the first item in the loaded list if it is not empty 283 first = self.kb_model.get_iter_first() 284 if first is not None: 285 self.kb_tree_view.set_cursor_on_cell(self.kb_model.get_path(first))
286 287 # expand all rows to show their keybindings 288 # it seems a row cannot be expanded using the keyboard, so this command 289 # makes sure, all keybindings are readable 290 # self.kb_tree_view.expand_all() 291 # no longer necessary as tree views came be expanded and collapsed using + 292 # and - 293 # let them all be collapsed for a better overview 294 295 #for entry in kb_list: 296 #log.info("Entry: %s, %s|", entry, kb_list[entry]) 297 298
299 - def _createNode(self, scriptName):
300 ''' 301 Creates a new root node in the TreeStore model with the name of the script. 302 303 @author: Orca authors (orca_gui_prefs.py) 304 @param scriptName: the name of the new TreeStore Node = name of the script 305 @type scriptName: string 306 @return iterator at the new node 307 @rtype gtk.TreeIter 308 ''' 309 310 model = self.kb_model 311 iterator = model.append(None) 312 model.set(iterator, 313 self.DESCRIPTION, scriptName, 314 self.KEYBINDINGS, None, 315 self.DEVICE, None ) 316 return iterator
317
318 - def _insertRow(self, desc, kb, device, parent=None):
319 ''' 320 Appends a new row with the new keybinding data to the treeview. 321 322 @author: Orca authors (orca_gui_prefs.py) 323 @param kb: the new keybinding to be appended 324 @type kb: string 325 @param desc: description of the keybinding to be appended 326 @type desc: string 327 @param device: name of the device of which the keys are pressed 328 @type device: string 329 @param parent: the parent node on which to append 330 @type parent: gtk.TreeIter 331 @return iterator at the new row 332 @rtype gtk.TreeIter 333 ''' 334 model = self.kb_model 335 if parent != None: 336 iterator = model.append(parent) 337 model.set (iterator, 338 self.DESCRIPTION, desc, 339 self.KEYBINDINGS, kb, 340 self.DEVICE, device ) 341 return iterator 342 else: 343 return None
344
345 - def _getIterator(self, nodeName):
346 ''' 347 Returns the iterator matching the node name passed as argument or 348 None if the node was not found. 349 350 @author: Orca authors (orca_gui_prefs.py) 351 @param nodeName: a string providing the name the node wanted 352 @type nodeName: string 353 @return: iterator matching the nodeName passed as argument 354 @rtype: gtk.TreeIter or None 355 ''' 356 model = self.kb_model 357 for row in model: 358 if ((model.iter_depth(row.iter) == 0) \ 359 and (row[ self.DESCRIPTION ] == nodeName)): 360 return row.iter 361 return None
362 363
364 - def _onOK(self, widget):
365 ''' 366 Handles 'OK' button 'clicked' events. 367 368 @param widget: source of GUI event 369 @type widget: gtk.Widget 370 ''' 371 # notify DefaultDialogScript 372 #self._signal(self.OK) 373 self.close()
374
375 - def close(self):
376 ''' 377 Closes the chooser, preventing further chooser interaction with the user. 378 ''' 379 self.window.destroy()
380
381 - def getName(self):
382 ''' 383 Gets the name of the chooser. 384 385 @return: Human readable name of the chooser 386 @rtype: string 387 ''' 388 return _('Command Chooser')
389