aboutsummaryrefslogtreecommitdiffstats
path: root/build/lib.linux-x86_64-2.7/dogtail/predicate.py
blob: aa100e1f05498c7c7c71c41a076a0a63ef4a91ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
"""Predicates that can be used when searching for nodes.

Author: David Malcolm <dmalcolm@redhat.com>"""
__author__ = 'David Malcolm <dmalcolm@redhat.com>'

from i18n import TranslatableString
from gi.repository import GLib
from time import sleep
from logging import debugLogger as logger
from config import config

def stringMatches(scriptName, reportedName):
    assert isinstance(scriptName, TranslatableString)

    return scriptName.matchedBy(reportedName)


def makeScriptRecursiveArgument(isRecursive, defaultValue):
    if isRecursive == defaultValue:
        return ""
    else:
        return ", recursive=%s" % isRecursive


def makeCamel(string):
    """
    Convert string to camelCaps
    """
    string = str(string)
    # FIXME: this function is probably really fragile, lots of difficult cases
    # here

    # Sanitize string, replacing bad characters with spaces:
    for char in ":;!@#$%^&*()-+=_~`\\/?|[]{}<>,.\t\n\r\"'":
        string = string.replace(char, " ")
    words = string.strip().split(" ")
    for word in words:
        word.strip
    result = ""
    firstWord = True
    for word in words:
        lowercaseWord = word.lower()
        if firstWord:
            result += lowercaseWord
            firstWord = False
        else:
            result += lowercaseWord.capitalize()
    return result


class Predicate(object):

    """Abstract base class representing a predicate function on nodes.

    It's more than just a function in that it has data and can describe itself"""

    def satisfiedByNode(self, node):
        """Pure virtual method returning a boolean if the predicate is satisfied by the node"""
        raise NotImplementedError

    def describeSearchResult(self, node):
        raise NotImplementedError

    def makeScriptMethodCall(self, isRecursive):
        """
        Method to generate a string containing a (hopefully) readable search
        method call on a node (to be used when generating Python source code in
        the event recorder)
        """
        raise NotImplementedError

    def makeScriptVariableName(self):
        """
        Method to generate a string containing a (hopefully) readable name
        for a Node instance variable that would be the result of a search on
        this predicate (to be used when generating Python source code in the
        event recorder).
        """
        raise NotImplementedError

    def __eq__(self, other):
        """
        Predicates are considered equal if they are of the same subclass and
        have the same data
        """
        # print "predeq: self:%s"%self
        # print "               other:%s"%other
        # print "predeq: selfdict:%s"%self.__dict__
        # print "               otherdict:%s"%other.__dict__

        if type(self) != type(other):
            return False
        else:
            return self.__dict__ == other.__dict__


class IsAnApplicationNamed(Predicate):

    """Search subclass that looks for an application by name"""

    def __init__(self, appName):
        self.appName = TranslatableString(appName)
        self.debugName = self.describeSearchResult()
        self.satisfiedByNode = self._genCompareFunc()

    def _genCompareFunc(self):
        def satisfiedByNode(node):
            try:
                return node.roleName == 'application' and stringMatches(self.appName, node.name)
            except GLib.GError as e:
                if 'name :1.0 was not provided' in e.message:
                    logger.log("Dogtail: warning: omiting possibly broken at-spi application record")
                    return False
                else:
                    try:
                        sleep(config.defaults['searchWarningThreshold'])
                        return node.roleName == 'application' and stringMatches(self.appName, node.name)
                    except GLib.GError:
                        logger.log("Dogtail: warning: application may be hanging")
                        return False
        return satisfiedByNode

    def describeSearchResult(self):
        return '%s application' % self.appName

    def makeScriptMethodCall(self, isRecursive):
        # ignores the isRecursive parameter
        return "application(%s)" % self.appName

    def makeScriptVariableName(self):
        return makeCamel(self.appName) + "App"


class GenericPredicate(Predicate):

    """SubtreePredicate subclass that takes various optional search fields"""

    def __init__(self, name=None, roleName=None, description=None, label=None, debugName=None):
        if name:
            self.name = TranslatableString(name)
        else:
            self.name = None
        self.roleName = roleName
        self.description = description
        if label:
            self.label = TranslatableString(label)
        else:
            self.label = None

        if debugName:
            self.debugName = debugName
        else:
            if label:
                self.debugName = "labelled '%s'" % self.label
            else:
                self.debugName = "child with"
            if name:
                self.debugName += " name=%s" % self.name
            if roleName:
                self.debugName += " roleName='%s'" % roleName
            if description:
                self.debugName += " description='%s'" % description
        assert self.debugName

        self.satisfiedByNode = self._genCompareFunc()

    def _genCompareFunc(self):
        def satisfiedByNode(node):
            # labelled nodes are handled specially:
            if self.label:
                # this reverses the search; we're looking for a node with LABELLED_BY
                # and then checking the label, rather than looking for a label and
                # then returning whatever LABEL_FOR targets
                if node.labeller:
                    return stringMatches(self.label, node.labeller.name)
                else:
                    return False
            else:
                # Ensure the node matches any criteria that were set:
                try:
                    if self.name:
                        if not stringMatches(self.name, node.name):
                            return False
                    if self.roleName:
                        if self.roleName != node.roleName:
                            return False
                    if self.description:
                        if self.description != node.description:
                            return False
                except GLib.GError as e:
                    if 'name :1.0 was not provided' in e.message:
                        logger.log("Dogtail: warning: omiting possibly broken at-spi application record")
                        return False
                    else:
                        raise e
                return True
        return satisfiedByNode

    def describeSearchResult(self):
        return self.debugName

    def makeScriptMethodCall(self, isRecursive):
        if self.label:
            args = "label=%s" % self.label
        else:
            args = ""
            if self.name:
                print(self.name)
                args += " name=%s" % self.name
            if self.roleName:
                args += " roleName='%s'" % self.roleName
            if self.description:
                args += " description='%s'" % self.description
        return "child(%s%s)" % (args, makeScriptRecursiveArgument(isRecursive, True))

    def makeScriptVariableName(self):
        if self.label:
            return makeCamel(self.label) + "Node"
        else:
            if self.name:
                return makeCamel(self.name) + "Node"
            if self.roleName:
                return makeCamel(self.roleName) + "Node"
            if self.description:
                return makeCamel(self.description) + "Node"


class IsNamed(Predicate):

    """Predicate subclass that looks simply by name"""

    def __init__(self, name):
        self.name = TranslatableString(name)
        self.debugName = self.describeSearchResult()
        self.satisfiedByNode = self._genCompareFunc()

    def _genCompareFunc(self):
        def satisfiedByNode(node):
            return stringMatches(self.name, node.name)
        return satisfiedByNode

    def describeSearchResult(self):
        return "named %s" % self.name

    def makeScriptMethodCall(self, isRecursive):
        return "child(name=%s%s)" % (self.name, makeScriptRecursiveArgument(isRecursive, True))

    def makeScriptVariableName(self):
        return makeCamel(self.name) + "Node"


class IsAWindowNamed(Predicate):

    """Predicate subclass that looks for a top-level window by name"""

    def __init__(self, windowName):
        self.windowName = TranslatableString(windowName)
        self.debugName = self.describeSearchResult()
        self.satisfiedByNode = self._genCompareFunc()

    def _genCompareFunc(self):
        def satisfiedByNode(node):
            return node.roleName == 'frame' and stringMatches(self.windowName, node.name)
        return satisfiedByNode

    def describeSearchResult(self):
        return "%s window" % self.windowName

    def makeScriptMethodCall(self, isRecursive):
        return "window(%s%s)" % (self.windowName, makeScriptRecursiveArgument(isRecursive, False))

    def makeScriptVariableName(self):
        return makeCamel(self.windowName) + "Win"


class IsAWindow(Predicate):

    """Predicate subclass that looks for top-level windows"""

    def __init__(self):
        self.satisfiedByNode = lambda node: node.roleName == 'frame'

    def describeSearchResult(self):
        return "window"


class IsADialogNamed(Predicate):

    """Predicate subclass that looks for a top-level dialog by name"""

    def __init__(self, dialogName):
        self.dialogName = TranslatableString(dialogName)
        self.debugName = self.describeSearchResult()
        self.satisfiedByNode = self._genCompareFunc()

    def _genCompareFunc(self):
        def satisfiedByNode(node):
            return node.roleName == 'dialog' and stringMatches(self.dialogName, node.name)
        return satisfiedByNode

    def describeSearchResult(self):
        return '%s dialog' % self.dialogName

    def makeScriptMethodCall(self, isRecursive):
        return "dialog(%s%s)" % (self.dialogName, makeScriptRecursiveArgument(isRecursive, False))

    def makeScriptVariableName(self):
        return makeCamel(self.dialogName) + "Dlg"


class IsLabelledBy(Predicate):

    """Predicate: is this node labelled by another node"""
    pass


class IsLabelledAs(Predicate):

    """Predicate: is this node labelled with the text string (i.e. by another node with that as a name)"""

    def __init__(self, labelText):
        self.labelText = TranslatableString(labelText)
        self.debugName = self.describeSearchResult()
        self.satisfiedByNode = self._genCompareFunc()

    def _genCompareFunc(self):
        def satisfiedByNode(node):
            # FIXME
            if node.labeller:
                return stringMatches(self.labelText, node.labeller.name)
            else:
                return False
        return satisfiedByNode

    def describeSearchResult(self):
        return 'labelled %s' % self.labelText

    def makeScriptMethodCall(self, isRecursive):
        return "child(label=%s%s)" % (self.labelText, makeScriptRecursiveArgument(isRecursive, True))

    def makeScriptVariableName(self):
        return makeCamel(self.labelText) + "Node"


class IsAMenuNamed(Predicate):

    """Predicate subclass that looks for a menu by name"""

    def __init__(self, menuName):
        self.menuName = TranslatableString(menuName)
        self.debugName = self.describeSearchResult()
        self.satisfiedByNode = lambda node: node.roleName == 'menu' and \
            stringMatches(self.menuName, node.name)

    def describeSearchResult(self):
        return '%s menu' % (self.menuName)

    def makeScriptMethodCall(self, isRecursive):
        return "menu(%s%s)" % (self.menuName, makeScriptRecursiveArgument(isRecursive, True))

    def makeScriptVariableName(self):
        return makeCamel(self.menuName) + "Menu"


class IsAMenuItemNamed(Predicate):

    """Predicate subclass that looks for a menu item by name"""

    def __init__(self, menuItemName):
        self.menuItemName = TranslatableString(menuItemName)
        self.debugName = self.describeSearchResult()
        self.satisfiedByNode = lambda node: \
            node.roleName.endswith('menu item') and \
            stringMatches(self.menuItemName, node.name)

    def describeSearchResult(self):
        return '%s menuitem' % (self.menuItemName)

    def makeScriptMethodCall(self, isRecursive):
        return "menuItem(%s%s)" % (self.menuItemName, makeScriptRecursiveArgument(isRecursive, True))

    def makeScriptVariableName(self):
        return makeCamel(self.menuItemName) + "MenuItem"


class IsATextEntryNamed(Predicate):

    """Predicate subclass that looks for a text entry by name"""

    def __init__(self, textEntryName):
        self.textEntryName = TranslatableString(textEntryName)
        self.debugName = self.describeSearchResult()
        self.satisfiedByNode = lambda node: node.roleName == 'text' and \
            stringMatches(self.textEntryName, node.name)

    def describeSearchResult(self):
        return '%s textentry' % (self.textEntryName)

    def makeScriptMethodCall(self, isRecursive):
        return "textentry(%s%s)" % (self.textEntryName, makeScriptRecursiveArgument(isRecursive, True))

    def makeScriptVariableName(self):
        return makeCamel(self.textEntryName) + "Entry"


class IsAButtonNamed(Predicate):

    """Predicate subclass that looks for a button by name"""

    def __init__(self, buttonName):
        self.buttonName = TranslatableString(buttonName)
        self.debugName = self.describeSearchResult()
        self.satisfiedByNode = lambda node: node.roleName == 'push button' \
            and stringMatches(self.buttonName, node.name)

    def describeSearchResult(self):
        return '%s button' % (self.buttonName)

    def makeScriptMethodCall(self, isRecursive):
        return "button(%s%s)" % (self.buttonName, makeScriptRecursiveArgument(isRecursive, True))

    def makeScriptVariableName(self):
        return makeCamel(self.buttonName) + "Button"


class IsATabNamed(Predicate):

    """Predicate subclass that looks for a tab by name"""

    def __init__(self, tabName):
        self.tabName = TranslatableString(tabName)
        self.debugName = self.describeSearchResult()
        self.satisfiedByNode = lambda node: node.roleName == 'page tab' and \
            stringMatches(self.tabName, node.name)

    def describeSearchResult(self):
        return '%s tab' % (self.tabName)

    def makeScriptMethodCall(self, isRecursive):
        return "tab(%s%s)" % (self.tabName, makeScriptRecursiveArgument(isRecursive, True))

    def makeScriptVariableName(self):
        return makeCamel(self.tabName) + "Tab"