Package dogtail :: Module procedural
[hide private]
[frames] | no frames]

Source Code for Module dogtail.procedural

  1  """ 
  2  Dogtail's procedural UI 
  3  All the classes here are intended to be single-instance, except for Action. 
  4  """ 
  5  __author__ = 'Zack Cerza <zcerza@redhat.com>' 
  6  ############################################################################## 
  7  #                                                                            # 
  8  # WARNING: Here There Be Dragons (TM)                                        # 
  9  #                                                                            # 
 10  # If you don't understand how to use this API, you almost certainly don't    # 
 11  # want to read the code first. We make use of some very non-intuitive        # 
 12  # features of Python in order to make the API very simplistic. Therefore,    # 
 13  # you should probably only read this code if you're already familiar with    # 
 14  # some of Python's advanced features. You have been warned. ;)               # 
 15  #                                                                            # 
 16  ############################################################################## 
 17   
 18  import tree 
 19  import predicate 
 20  from config import config 
 21  import rawinput 
 22   
 23  #FocusError = "FocusError: %s not found" 
24 -class FocusError(Exception):
25 pass
26 27 import errors
28 -def focusFailed(pred):
29 errors.warn('The requested widget could not be focused: %s' % pred.debugName)
30 31 ENOARGS = "At least one argument is needed" 32
33 -class FocusBase:
34 """ 35 The base for every class in the module. Does nothing special, really. 36 """ 37 node = None 38
39 - def __getattr__ (self, name):
40 # Fold all the Node's AT-SPI properties into the Focus object. 41 try: return getattr(self.node, name) 42 except AttributeError: 43 raise AttributeError, name
44
45 - def __setattr__ (self, name, value):
46 # Fold all the Node's AT-SPI properties into the Focus object. 47 if name == 'node': 48 self.__dict__[name] = value 49 else: 50 try: setattr(self.node, name, value) 51 except AttributeError: 52 raise AttributeError, name
53
54 -class FocusApplication (FocusBase):
55 """ 56 Keeps track of which application is currently focused. 57 """ 58 desktop = tree.root
59 - def __call__ (self, name):
60 """ 61 Search for an application that matches and refocus on the given name. 62 """ 63 try: 64 pred = predicate.IsAnApplicationNamed(name) 65 app = self.desktop.findChild(pred, recursive = False, retry = False) 66 except tree.SearchError, desc: 67 if config.fatalErrors: raise FocusError, name 68 else: 69 focusFailed(pred) 70 return False 71 if app: 72 FocusApplication.node = app 73 FocusDialog.node = None 74 FocusWidget.node = None 75 return True
76
77 -class FocusDesktop (FocusBase):
78 """ 79 This isn't used yet, and may never be used. 80 """ 81 pass
82
83 -class FocusWindow (FocusBase):
84 """ 85 Keeps track of which window is currently focused. 86 """
87 - def __call__ (self, name):
88 """ 89 Search for a dialog that matches the given name and refocus on it. 90 """ 91 result = None 92 pred = predicate.IsAWindowNamed(name) 93 try: 94 result = FocusApplication.node.findChild(pred, requireResult=False, recursive = False) 95 except AttributeError: pass 96 if result: 97 FocusWindow.node = result 98 FocusDialog.node = None 99 FocusWidget.node = None 100 else: 101 if config.fatalErrors: raise FocusError, pred.debugName 102 else: 103 focusFailed(pred) 104 return False 105 return True
106
107 -class FocusDialog (FocusBase):
108 """ 109 Keeps track of which dialog is currently focused. 110 """
111 - def __call__ (self, name):
112 """ 113 Search for a dialog that matches the given name and refocus on it. 114 """ 115 result = None 116 pred = predicate.IsADialogNamed(name) 117 try: 118 result = FocusApplication.node.findChild(pred, requireResult=False, recursive = False) 119 except AttributeError: pass 120 if result: 121 FocusDialog.node = result 122 FocusWidget.node = None 123 else: 124 if config.fatalErrors: raise FocusError, pred.debugName 125 else: 126 focusFailed(pred) 127 return False 128 return True
129
130 -class FocusWidget (FocusBase):
131 """ 132 Keeps track of which widget is currently focused. 133 """
134 - def findByPredicate(self, pred):
135 result = None 136 try: 137 result = FocusWidget.node.findChild(pred, requireResult = False, retry = False) 138 except AttributeError: pass 139 if result: FocusWidget.node = result 140 else: 141 try: 142 result = FocusDialog.node.findChild(pred, requireResult = False, retry = False) 143 except AttributeError: pass 144 if result: FocusWidget.node = result 145 else: 146 try: 147 result = FocusWindow.node.findChild(pred, requireResult = False, retry = False) 148 except AttributeError: pass 149 if result: FocusWidget.node = result 150 else: 151 try: 152 result = FocusApplication.node.findChild(pred, requireResult = False, retry = False) 153 if result: FocusWidget.node = result 154 except AttributeError: 155 if config.fatalErrors: raise FocusError, name 156 else: 157 focusFailed(pred) 158 return False 159 160 if result == None: 161 FocusWidget.node = result 162 if config.fatalErrors: raise FocusError, pred.debugName 163 else: 164 focusFailed(pred) 165 return False 166 return True
167
168 - def __call__ (self, name = '', roleName = '', description = ''):
169 """ 170 If name, roleName or description are specified, search for a widget that matches and refocus on it. 171 """ 172 if not name and not roleName and not description: 173 raise TypeError, ENOARGS 174 175 # search for a widget. 176 pred = predicate.GenericPredicate(name = name, 177 roleName = roleName, description = description) 178 return self.findByPredicate(pred)
179
180 -class Focus (FocusBase):
181 """ 182 The container class for the focused application, dialog and widget. 183 """ 184
185 - def __getattr__ (self, name):
186 raise AttributeError, name
187 - def __setattr__(self, name, value):
188 if name in ('application', 'dialog', 'widget', 'window'): 189 self.__dict__[name] = value 190 else: 191 raise AttributeError, name
192 193 desktop = tree.root 194 application = FocusApplication() 195 app = application # shortcut :) 196 dialog = FocusDialog() 197 window = FocusWindow() 198 frame = window 199 widget = FocusWidget() 200
201 - def button (self, name):
202 """ 203 A shortcut to self.widget.findByPredicate(predicate.IsAButtonNamed(name)) 204 """ 205 return self.widget.findByPredicate(predicate.IsAButtonNamed(name))
206
207 - def icon (self, name):
208 """ 209 A shortcut to self.widget(name, roleName = 'icon') 210 """ 211 return self.widget(name = name, roleName = 'icon')
212
213 - def menu (self, name):
214 """ 215 A shortcut to self.widget.findByPredicate(predicate.IsAMenuNamed(name)) 216 """ 217 return self.widget.findByPredicate(predicate.IsAMenuNamed(name))
218
219 - def menuItem (self, name):
220 """ 221 A shortcut to self.widget.findByPredicate(predicate.IsAMenuItemNamed(name)) 222 """ 223 return self.widget.findByPredicate(predicate.IsAMenuItemNamed(name))
224
225 - def table (self, name = ''):
226 """ 227 A shortcut to self.widget(name, roleName 'table') 228 """ 229 return self.widget(name = name, roleName = 'table')
230
231 - def tableCell (self, name = ''):
232 """ 233 A shortcut to self.widget(name, roleName 'table cell') 234 """ 235 return self.widget(name = name, roleName = 'table cell')
236
237 - def text (self, name = ''):
238 """ 239 A shortcut to self.widget.findByPredicate(IsATextEntryNamed(name)) 240 """ 241 return self.widget.findByPredicate(predicate.IsATextEntryNamed(name))
242
243 -class Action (FocusWidget):
244 """ 245 Aids in executing AT-SPI actions, refocusing the widget if necessary. 246 """
247 - def __init__ (self, action):
248 """ 249 action is a string with the same name as the AT-SPI action you wish to execute using this class. 250 """ 251 self.action = action
252
253 - def __call__ (self, name = '', roleName = '', description = '', delay = config.actionDelay):
254 """ 255 If name, roleName or description are specified, first search for a widget that matches and refocus on it. 256 Then execute the action. 257 """ 258 if name or roleName or description: 259 FocusWidget.__call__(self, name = name, roleName = roleName, description = description) 260 self.node.doAction(self.action)
261
262 - def __getattr__ (self, attr):
263 return getattr(FocusWidget.node, attr)
264
265 - def __setattr__ (self, attr, value):
266 if attr == 'action': 267 self.__dict__[attr] = value 268 else: setattr(FocusWidget, attr, value)
269
270 - def button (self, name):
271 """ 272 A shortcut to self(name, roleName = 'push button') 273 """ 274 self.__call__(name = name, roleName = 'push button')
275
276 - def menu (self, name):
277 """ 278 A shortcut to self(name, roleName = 'menu') 279 """ 280 self.__call__(name = name, roleName = 'menu')
281
282 - def menuItem (self, name):
283 """ 284 A shortcut to self(name, roleName = 'menu item') 285 """ 286 self.__call__(name = name, roleName = 'menu item')
287
288 - def table (self, name = ''):
289 """ 290 A shortcut to self(name, roleName 'table') 291 """ 292 self.__call__(name = name, roleName = 'table')
293
294 - def tableCell (self, name = ''):
295 """ 296 A shortcut to self(name, roleName 'table cell') 297 """ 298 self.__call__(name = name, roleName = 'table cell')
299
300 - def text (self, name = ''):
301 """ 302 A shortcut to self(name, roleName = 'text') 303 """ 304 self.__call__(name = name, roleName = 'text')
305
306 -class Click (Action):
307 """ 308 A special case of Action, Click will eventually handle raw mouse events. 309 """ 310 primary = 1 311 middle = 2 312 secondary = 3
313 - def __init__ (self):
314 Action.__init__(self, 'click')
315
316 - def __call__ (self, name = '', roleName = '', description = '', raw = True, button = primary, delay = config.actionDelay):
317 """ 318 By default, execute a raw mouse event. 319 If raw is False or if button evaluates to False, just pass the rest of 320 the arguments to Action. 321 """ 322 if name or roleName or description: 323 FocusWidget.__call__(self, name = name, roleName = roleName, description = description) 324 if raw and button: 325 # We're doing a raw mouse click 326 Click.node.click(button) 327 else: 328 Action.__call__(self, name = name, roleName = roleName, description = description, delay = delay)
329
330 -class Select (Action):
331 """ 332 Aids in selecting and deselecting widgets, i.e. page tabs 333 """ 334 select = 'select' 335 deselect = 'deselect'
336 - def __init__(self, action):
337 """ 338 action must be 'select' or 'deselect'. 339 """ 340 if action not in (self.select, self.deselect): 341 raise ValueError, action 342 Action.__init__(self, action)
343
344 - def __call__ (self, name = '', roleName = '', description = '', delay = config.actionDelay):
345 """ 346 If name, roleName or description are specified, first search for a widget that matches and refocus on it. 347 Then execute the action. 348 """ 349 if name or roleName or description: 350 FocusWidget.__call__(self, name = name, roleName = roleName, description = description) 351 func = getattr(self.node, self.action) 352 func()
353
354 -def type(text):
355 if focus.widget.node: 356 focus.widget.node.typeText(text) 357 else: 358 rawinput.typeText(text)
359
360 -def keyCombo(combo):
361 if focus.widget.node: 362 focus.widget.node.keyCombo(combo) 363 else: 364 rawinput.keyCombo(combo)
365
366 -def run(application, arguments = '', appName = ''):
367 from utils import run as utilsRun 368 pid = utilsRun(application + ' ' + arguments, appName = appName) 369 focus.application(application) 370 return pid
371 372 focus = Focus() 373 click = Click() 374 activate = Action('activate') 375 openItem = Action('open') 376 menu = Action('menu') 377 select = Select(Select.select) 378 deselect = Select(Select.deselect) 379