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

Source Code for Module dogtail.predicate

  1  """Predicates that can be used when searching for nodes. 
  2   
  3  Author: David Malcolm <dmalcolm@redhat.com>""" 
  4  __author__ = 'David Malcolm <dmalcolm@redhat.com>' 
  5   
  6  from i18n import TranslatableString 
  7  from gi.repository import GLib 
  8  from time import sleep 
  9  from logging import debugLogger as logger 
 10  from config import config 
 11   
12 -def stringMatches(scriptName, reportedName):
13 assert isinstance(scriptName, TranslatableString) 14 15 return scriptName.matchedBy(reportedName)
16 17
18 -def makeScriptRecursiveArgument(isRecursive, defaultValue):
19 if isRecursive == defaultValue: 20 return "" 21 else: 22 return ", recursive=%s" % isRecursive
23 24
25 -def makeCamel(string):
26 """ 27 Convert string to camelCaps 28 """ 29 string = str(string) 30 # FIXME: this function is probably really fragile, lots of difficult cases 31 # here 32 33 # Sanitize string, replacing bad characters with spaces: 34 for char in ":;!@#$%^&*()-+=_~`\\/?|[]{}<>,.\t\n\r\"'": 35 string = string.replace(char, " ") 36 words = string.strip().split(" ") 37 for word in words: 38 word.strip 39 result = "" 40 firstWord = True 41 for word in words: 42 lowercaseWord = word.lower() 43 if firstWord: 44 result += lowercaseWord 45 firstWord = False 46 else: 47 result += lowercaseWord.capitalize() 48 return result
49 50
51 -class Predicate(object):
52 53 """Abstract base class representing a predicate function on nodes. 54 55 It's more than just a function in that it has data and can describe itself""" 56
57 - def satisfiedByNode(self, node):
58 """Pure virtual method returning a boolean if the predicate is satisfied by the node""" 59 raise NotImplementedError
60
61 - def describeSearchResult(self, node):
62 raise NotImplementedError
63
64 - def makeScriptMethodCall(self, isRecursive):
65 """ 66 Method to generate a string containing a (hopefully) readable search 67 method call on a node (to be used when generating Python source code in 68 the event recorder) 69 """ 70 raise NotImplementedError
71
72 - def makeScriptVariableName(self):
73 """ 74 Method to generate a string containing a (hopefully) readable name 75 for a Node instance variable that would be the result of a search on 76 this predicate (to be used when generating Python source code in the 77 event recorder). 78 """ 79 raise NotImplementedError
80
81 - def __eq__(self, other):
82 """ 83 Predicates are considered equal if they are of the same subclass and 84 have the same data 85 """ 86 # print "predeq: self:%s"%self 87 # print " other:%s"%other 88 # print "predeq: selfdict:%s"%self.__dict__ 89 # print " otherdict:%s"%other.__dict__ 90 91 if type(self) != type(other): 92 return False 93 else: 94 return self.__dict__ == other.__dict__
95 96
97 -class IsAnApplicationNamed(Predicate):
98 99 """Search subclass that looks for an application by name""" 100
101 - def __init__(self, appName):
102 self.appName = TranslatableString(appName) 103 self.debugName = self.describeSearchResult() 104 self.satisfiedByNode = self._genCompareFunc()
105
106 - def _genCompareFunc(self):
107 def satisfiedByNode(node): 108 try: 109 return node.roleName == 'application' and stringMatches(self.appName, node.name) 110 except GLib.GError as e: 111 if 'name :1.0 was not provided' in e.message: 112 logger.log("Dogtail: warning: omiting possibly broken at-spi application record") 113 return False 114 else: 115 try: 116 sleep(config.defaults['searchWarningThreshold']) 117 return node.roleName == 'application' and stringMatches(self.appName, node.name) 118 except GLib.GError: 119 logger.log("Dogtail: warning: application may be hanging") 120 return False
121 return satisfiedByNode
122
123 - def describeSearchResult(self):
124 return '%s application' % self.appName
125
126 - def makeScriptMethodCall(self, isRecursive):
127 # ignores the isRecursive parameter 128 return "application(%s)" % self.appName
129
130 - def makeScriptVariableName(self):
131 return makeCamel(self.appName) + "App"
132 133
134 -class GenericPredicate(Predicate):
135 136 """SubtreePredicate subclass that takes various optional search fields""" 137
138 - def __init__(self, name=None, roleName=None, description=None, label=None, debugName=None):
139 if name: 140 self.name = TranslatableString(name) 141 else: 142 self.name = None 143 self.roleName = roleName 144 self.description = description 145 if label: 146 self.label = TranslatableString(label) 147 else: 148 self.label = None 149 150 if debugName: 151 self.debugName = debugName 152 else: 153 if label: 154 self.debugName = "labelled '%s'" % self.label 155 else: 156 self.debugName = "child with" 157 if name: 158 self.debugName += " name=%s" % self.name 159 if roleName: 160 self.debugName += " roleName='%s'" % roleName 161 if description: 162 self.debugName += " description='%s'" % description 163 assert self.debugName 164 165 self.satisfiedByNode = self._genCompareFunc()
166
167 - def _genCompareFunc(self):
168 def satisfiedByNode(node): 169 # labelled nodes are handled specially: 170 if self.label: 171 # this reverses the search; we're looking for a node with LABELLED_BY 172 # and then checking the label, rather than looking for a label and 173 # then returning whatever LABEL_FOR targets 174 if node.labeller: 175 return stringMatches(self.label, node.labeller.name) 176 else: 177 return False 178 else: 179 # Ensure the node matches any criteria that were set: 180 try: 181 if self.name: 182 if not stringMatches(self.name, node.name): 183 return False 184 if self.roleName: 185 if self.roleName != node.roleName: 186 return False 187 if self.description: 188 if self.description != node.description: 189 return False 190 except GLib.GError as e: 191 if 'name :1.0 was not provided' in e.message: 192 logger.log("Dogtail: warning: omiting possibly broken at-spi application record") 193 return False 194 else: 195 raise e 196 return True
197 return satisfiedByNode
198
199 - def describeSearchResult(self):
200 return self.debugName
201
202 - def makeScriptMethodCall(self, isRecursive):
203 if self.label: 204 args = "label=%s" % self.label 205 else: 206 args = "" 207 if self.name: 208 print(self.name) 209 args += " name=%s" % self.name 210 if self.roleName: 211 args += " roleName='%s'" % self.roleName 212 if self.description: 213 args += " description='%s'" % self.description 214 return "child(%s%s)" % (args, makeScriptRecursiveArgument(isRecursive, True))
215
216 - def makeScriptVariableName(self):
217 if self.label: 218 return makeCamel(self.label) + "Node" 219 else: 220 if self.name: 221 return makeCamel(self.name) + "Node" 222 if self.roleName: 223 return makeCamel(self.roleName) + "Node" 224 if self.description: 225 return makeCamel(self.description) + "Node"
226 227
228 -class IsNamed(Predicate):
229 230 """Predicate subclass that looks simply by name""" 231
232 - def __init__(self, name):
236
237 - def _genCompareFunc(self):
238 def satisfiedByNode(node): 239 return stringMatches(self.name, node.name)
240 return satisfiedByNode
241
242 - def describeSearchResult(self):
243 return "named %s" % self.name
244
245 - def makeScriptMethodCall(self, isRecursive):
246 return "child(name=%s%s)" % (self.name, makeScriptRecursiveArgument(isRecursive, True))
247
248 - def makeScriptVariableName(self):
249 return makeCamel(self.name) + "Node"
250 251
252 -class IsAWindowNamed(Predicate):
253 254 """Predicate subclass that looks for a top-level window by name""" 255
256 - def __init__(self, windowName):
257 self.windowName = TranslatableString(windowName) 258 self.debugName = self.describeSearchResult() 259 self.satisfiedByNode = self._genCompareFunc()
260
261 - def _genCompareFunc(self):
262 def satisfiedByNode(node): 263 return node.roleName == 'frame' and stringMatches(self.windowName, node.name)
264 return satisfiedByNode
265
266 - def describeSearchResult(self):
267 return "%s window" % self.windowName
268
269 - def makeScriptMethodCall(self, isRecursive):
270 return "window(%s%s)" % (self.windowName, makeScriptRecursiveArgument(isRecursive, False))
271
272 - def makeScriptVariableName(self):
273 return makeCamel(self.windowName) + "Win"
274 275
276 -class IsAWindow(Predicate):
277 278 """Predicate subclass that looks for top-level windows""" 279
280 - def __init__(self):
281 self.satisfiedByNode = lambda node: node.roleName == 'frame'
282
283 - def describeSearchResult(self):
284 return "window"
285 286
287 -class IsADialogNamed(Predicate):
288 289 """Predicate subclass that looks for a top-level dialog by name""" 290
291 - def __init__(self, dialogName):
292 self.dialogName = TranslatableString(dialogName) 293 self.debugName = self.describeSearchResult() 294 self.satisfiedByNode = self._genCompareFunc()
295
296 - def _genCompareFunc(self):
297 def satisfiedByNode(node): 298 return node.roleName == 'dialog' and stringMatches(self.dialogName, node.name)
299 return satisfiedByNode
300
301 - def describeSearchResult(self):
302 return '%s dialog' % self.dialogName
303
304 - def makeScriptMethodCall(self, isRecursive):
305 return "dialog(%s%s)" % (self.dialogName, makeScriptRecursiveArgument(isRecursive, False))
306
307 - def makeScriptVariableName(self):
308 return makeCamel(self.dialogName) + "Dlg"
309 310
311 -class IsLabelledBy(Predicate):
312 313 """Predicate: is this node labelled by another node""" 314 pass
315 316
317 -class IsLabelledAs(Predicate):
318 319 """Predicate: is this node labelled with the text string (i.e. by another node with that as a name)""" 320
321 - def __init__(self, labelText):
322 self.labelText = TranslatableString(labelText) 323 self.debugName = self.describeSearchResult() 324 self.satisfiedByNode = self._genCompareFunc()
325
326 - def _genCompareFunc(self):
327 def satisfiedByNode(node): 328 # FIXME 329 if node.labeller: 330 return stringMatches(self.labelText, node.labeller.name) 331 else: 332 return False
333 return satisfiedByNode
334
335 - def describeSearchResult(self):
336 return 'labelled %s' % self.labelText
337
338 - def makeScriptMethodCall(self, isRecursive):
339 return "child(label=%s%s)" % (self.labelText, makeScriptRecursiveArgument(isRecursive, True))
340
341 - def makeScriptVariableName(self):
342 return makeCamel(self.labelText) + "Node"
343 344
345 -class IsAMenuNamed(Predicate):
346 347 """Predicate subclass that looks for a menu by name""" 348
349 - def __init__(self, menuName):
350 self.menuName = TranslatableString(menuName) 351 self.debugName = self.describeSearchResult() 352 self.satisfiedByNode = lambda node: node.roleName == 'menu' and \ 353 stringMatches(self.menuName, node.name)
354
355 - def describeSearchResult(self):
356 return '%s menu' % (self.menuName)
357
358 - def makeScriptMethodCall(self, isRecursive):
359 return "menu(%s%s)" % (self.menuName, makeScriptRecursiveArgument(isRecursive, True))
360
361 - def makeScriptVariableName(self):
362 return makeCamel(self.menuName) + "Menu"
363 364
365 -class IsAMenuItemNamed(Predicate):
366 367 """Predicate subclass that looks for a menu item by name""" 368
369 - def __init__(self, menuItemName):
370 self.menuItemName = TranslatableString(menuItemName) 371 self.debugName = self.describeSearchResult() 372 self.satisfiedByNode = lambda node: \ 373 node.roleName.endswith('menu item') and \ 374 stringMatches(self.menuItemName, node.name)
375
376 - def describeSearchResult(self):
377 return '%s menuitem' % (self.menuItemName)
378
379 - def makeScriptMethodCall(self, isRecursive):
380 return "menuItem(%s%s)" % (self.menuItemName, makeScriptRecursiveArgument(isRecursive, True))
381
382 - def makeScriptVariableName(self):
383 return makeCamel(self.menuItemName) + "MenuItem"
384 385
386 -class IsATextEntryNamed(Predicate):
387 388 """Predicate subclass that looks for a text entry by name""" 389
390 - def __init__(self, textEntryName):
391 self.textEntryName = TranslatableString(textEntryName) 392 self.debugName = self.describeSearchResult() 393 self.satisfiedByNode = lambda node: node.roleName == 'text' and \ 394 stringMatches(self.textEntryName, node.name)
395
396 - def describeSearchResult(self):
397 return '%s textentry' % (self.textEntryName)
398
399 - def makeScriptMethodCall(self, isRecursive):
400 return "textentry(%s%s)" % (self.textEntryName, makeScriptRecursiveArgument(isRecursive, True))
401
402 - def makeScriptVariableName(self):
403 return makeCamel(self.textEntryName) + "Entry"
404 405
406 -class IsAButtonNamed(Predicate):
407 408 """Predicate subclass that looks for a button by name""" 409
410 - def __init__(self, buttonName):
411 self.buttonName = TranslatableString(buttonName) 412 self.debugName = self.describeSearchResult() 413 self.satisfiedByNode = lambda node: node.roleName == 'push button' \ 414 and stringMatches(self.buttonName, node.name)
415
416 - def describeSearchResult(self):
417 return '%s button' % (self.buttonName)
418
419 - def makeScriptMethodCall(self, isRecursive):
420 return "button(%s%s)" % (self.buttonName, makeScriptRecursiveArgument(isRecursive, True))
421
422 - def makeScriptVariableName(self):
423 return makeCamel(self.buttonName) + "Button"
424 425
426 -class IsATabNamed(Predicate):
427 428 """Predicate subclass that looks for a tab by name""" 429
430 - def __init__(self, tabName):
431 self.tabName = TranslatableString(tabName) 432 self.debugName = self.describeSearchResult() 433 self.satisfiedByNode = lambda node: node.roleName == 'page tab' and \ 434 stringMatches(self.tabName, node.name)
435
436 - def describeSearchResult(self):
437 return '%s tab' % (self.tabName)
438
439 - def makeScriptMethodCall(self, isRecursive):
440 return "tab(%s%s)" % (self.tabName, makeScriptRecursiveArgument(isRecursive, True))
441
442 - def makeScriptVariableName(self):
443 return makeCamel(self.tabName) + "Tab"
444