def _promote(self, accessible):
        '''
        Promote a pyatspi.Accessibility.Accessible to a specific strongwind class 
        if possible (e.g., a strongwind.accessibles.Dialog), or to a generic
        strongwind.accessibles.Accessible otherwise.
        '''

        # look in the application/widget cache first
        if accessible.getRole() == pyatspi.ROLE_APPLICATION:
            try:
                return cache.getApplicationById(accessible.queryApplication().id)
            except KeyError:
                pass # not in cache
        else:
            try:
                return cache.getWidget(accessible)
            except KeyError:
                pass # not in cache

        # try looking for a specific strongwind class, e.g. strongwind.accessibles.MenuBar
        try:
            className = utils.toClassName(accessible.getRoleName()) # convert the accessible's role name to a class name, e.g. "menu bar" => "MenuBar"
            module = __import__(__name__)   # import the current module (strongwind.accessibles) so we can inspect its vars
            klass = vars(module)[className] # turn the className (a string) into the class of that name (e.g., a MenuBar class)
            return klass(accessible)        # return an instance of the class (e.g., a MenuBar object)
        except KeyError:
            return Accessible(accessible)
Exemple #2
0
    def _promote(self, accessible):
        '''
        Promote a pyatspi.Accessibility.Accessible to a specific strongwind class 
        if possible (e.g., a strongwind.accessibles.Dialog), or to a generic
        strongwind.accessibles.Accessible otherwise.
        '''

        # look in the application/widget cache first
        if accessible.getRole() == pyatspi.ROLE_APPLICATION:
            try:
                return cache.getApplicationById(
                    accessible.queryApplication().id)
            except KeyError:
                pass  # not in cache
        else:
            try:
                return cache.getWidget(accessible)
            except KeyError:
                pass  # not in cache

        # try looking for a specific strongwind class, e.g. strongwind.accessibles.MenuBar
        try:
            className = utils.toClassName(
                accessible.getRoleName()
            )  # convert the accessible's role name to a class name, e.g. "menu bar" => "MenuBar"
            module = __import__(
                __name__
            )  # import the current module (strongwind.accessibles) so we can inspect its vars
            klass = vars(
                module
            )[className]  # turn the className (a string) into the class of that name (e.g., a MenuBar class)
            return klass(
                accessible
            )  # return an instance of the class (e.g., a MenuBar object)
        except KeyError:
            return Accessible(accessible)
Exemple #3
0
    def __getattr__(self, attr):
        if attr == 'childCount':
            return self._accessible.childCount
        elif attr == 'name':
            return self._accessible.name
        elif attr == 'logName':
            if not self.__dict__.has_key('logName'):
                self.__dict__['logName'] = self._accessible.name
            return self.__dict__['logName']
        elif attr == 'description':
            return self._accessible.description
        elif attr == 'parent':
            return self._promote(self._accessible.parent)
        elif attr == 'role':
            return self._accessible.getRole()
        elif attr == 'roleName':
            return self._accessible.getRoleName()
        elif attr == 'extents':
            return self._accessible.queryComponent().getExtents(
                pyatspi.DESKTOP_COORDS)
        elif attr == 'layer':
            return self._accessible.queryComponent().getLayer()
        elif attr == 'text':
            itext = self._accessible.queryText()
            return itext.getText(0, itext.characterCount)
        elif attr == 'value':
            return self._accessible.queryValue().currentValue
        elif attr == 'caretOffset':
            return self._accessible.queryText().caretOffset
        elif attr == 'characterCount':
            return self._accessible.queryText().characterCount
        elif attr == 'app':
            try:
                return cache.getApplicationById(
                    self._accessible.getApplication().id)
            except Exception:
                try:
                    return self._promote(self._accessible.getApplication())
                except Exception:
                    return None
        else:
            # bind states, e.g., showing, focusable, sensitive, etc.
            a = 'STATE_' + utils.toConstantName(attr)
            v = vars(pyatspi)
            if v.has_key(a):
                try:
                    return self._accessible.getState().contains(v[a])
                except AttributeError:
                    # when the app goes down, we sometimes get "AttributeError: 'CORBA.Object' object has no attribute 'contains'"
                    return False

            # FIXME: bind relations
            # FIXME: bind attributes

            # add find methods
            if attr.startswith('findAll'):
                a = None

                translations = {
                    'findAllCanvases': 'ROLE_CANVAS',
                    'findAllCheckBoxes': 'ROLE_CHECK_BOX',
                    'findAllComboBoxes': 'ROLE_COMBO_BOX',
                    'findAllEmbedded': 'ROLE_EMBEDDED',
                    'findAllEntries': 'ROLE_ENTRY',
                    'findAllFillers': 'ROLE_FILLER',
                    'findAllInvalid': 'ROLE_INVALID',
                    'findAllLastDefined': 'ROLE_LAST_DEFINED'
                }

                try:
                    a = translations[attr]
                except KeyError:
                    a = 'ROLE' + utils.toConstantName(attr[7:-1])

                v = vars(pyatspi)
                if v.has_key(a):
                    # generate a function on-the-fly and return it
                    def findMethod(name, checkShowing=True, recursive=True):
                        dontCheckShowing = not checkShowing
                        return utils.findAllDescendants(
                            self, lambda x: x.role == v[
                                a] and utils.equalsOrMatches(x.name, name) and
                            (dontCheckShowing or x.showing), recursive)

                    return findMethod

            if attr.startswith('find'):
                a = 'ROLE' + utils.toConstantName(attr[4:])
                v = vars(pyatspi)
                if v.has_key(a):
                    # generate a function on-the-fly and return it
                    def findMethod(name,
                                   logName=None,
                                   checkShowing=True,
                                   retry=True,
                                   recursive=True,
                                   breadthFirst=True,
                                   raiseException=True,
                                   setReference=False):
                        dontCheckShowing = not checkShowing
                        y = utils.findDescendant(self, lambda x: x.role == v[a] and utils.equalsOrMatches(x.name, name) and (dontCheckShowing or x.showing), \
                            retry=retry, recursive=recursive, breadthFirst=breadthFirst, raiseException=raiseException)

                        # don't try promoting y if it's None
                        if not raiseException and y is None:
                            return y

                        # look in the widget cache first
                        try:
                            return cache.getWidget(y)
                        except KeyError:
                            pass  # not in cache

                        # if the logName isn't given, set it to the name (unless the name is a regex)
                        if logName is None and type(name) is not type(
                                re.compile('r')):
                            logName = name

                        # if we still don't have a logname, just grab the name of the accessible
                        if logName is None:
                            logName = y.name

                        # at this point, we have a logName.  next, we look for a class named
                        # logName + roleName in moduleName.  if such a class can be found, we promote
                        # the widget to that class, cache the instance, and return it.
                        #
                        # if no such class can be found, and the logName is different than the name
                        # of the widget, set the widget's log name and cache the widget.  if the logName
                        # is the same as the widget's logName, there's no need to cache the widget.

                        # if the logName is 'Preferences' and roleName of the widget is 'Dialog',
                        # the name of the class to look for is 'PreferencesDialog'
                        className = utils.toClassName(
                            logName) + utils.toClassName(y.roleName)

                        # the module prefix is the module of this class.  so if we had a widget that had
                        # a class medsphere.openvistacis.OpenVistaCIS, and we call findDialog('Preferences')
                        # on it, the module prefix would be medsphere.openvistacis.  we append the name of
                        # the class we're looking for to the module prefix to get the name of the module.
                        # so continuing with the example, the full module name would be
                        # medsphere.openvistacis.preferencesdialog.  (In the medsphere.openvistacis.preferencesdialog
                        # module, we would look for 'PreferencesDialog' - that code is a few lines down)
                        moduleName = self.__class__.__module__ + '.' + className.lower(
                        )

                        try:
                            # import the module, grab the class, and make an instance of it, then cache the instance
                            module = __import__(moduleName, globals(), None,
                                                [className])
                            klass = vars(module)[className]
                            z = klass(y)
                            cache.addWidget(z)
                        except (ImportError, KeyError):
                            # if the found widget's logName isn't the same as the logName
                            # we were given, set the widget's logName and cache the widget
                            if y.name != logName:
                                y.logName = logName
                                cache.addWidget(
                                    y
                                )  # make the log name stick by caching the object with the logName property set on it
                            z = y

                        # set self.preferencesDialog = the widget we just found/promoted/cached
                        if setReference:
                            self.__setattr__(
                                utils.toVarName(logName) +
                                utils.toClassName(z.roleName), z)

                        return z

                    return findMethod

            # add assert methods
            if attr.startswith('assertNo'):
                a = 'ROLE' + utils.toConstantName(attr[8:])
                v = vars(pyatspi)
                if v.has_key(a):
                    # generate a function on-the-fly and return it
                    def assertMethod(name,
                                     checkShowing=True,
                                     retry=False,
                                     recursive=True,
                                     breadthFirst=False,
                                     raiseException=False):
                        def descendantNotFound():
                            dontCheckShowing = not checkShowing
                            return utils.findDescendant(self, lambda x: x.role == v[a] and utils.equalsOrMatches(x.name, name) and (dontCheckShowing or x.showing), \
                                retry=retry, recursive=recursive, breadthFirst=breadthFirst, raiseException=raiseException) == None

                        assert utils.retryUntilTrue(descendantNotFound)

                    return assertMethod

            if attr.startswith('assert'):
                a = 'ROLE' + utils.toConstantName(attr[6:])
                v = vars(pyatspi)
                if v.has_key(a):
                    # generate a function on-the-fly and return it
                    def assertMethod(name,
                                     checkShowing=True,
                                     retry=False,
                                     recursive=True,
                                     breadthFirst=False,
                                     raiseException=False):
                        def descendantFound():
                            dontCheckShowing = not checkShowing
                            return utils.findDescendant(self, lambda x: x.role == v[a] and utils.equalsOrMatches(x.name, name) and (dontCheckShowing or x.showing), \
                                retry=retry, recursive=recursive, breadthFirst=breadthFirst, raiseException=raiseException) != None

                        assert utils.retryUntilTrue(descendantFound)

                    return assertMethod

            if self.__dict__.has_key(attr):
                return self.__dict__[attr]

            raise AttributeError, "%s instance has no attribute '%s'" % (
                self.__class__.__name__, attr)
Exemple #4
0
def action(action, child=None):
    '''
    Log an action, e.g., Click Cancel

    If a child is given ... FIXME: decipher mysterious code below

    Multiple calls to action() (without a call to expectedResult() in between)
    will cause the message from each call to be concatenated to the message from
    previous calls.
    '''

    _flushBuffers()

    global _actionBuffer
    global _oldParents

    prefix = ''

    # TODO: benchmark the performance hit we receive from logparent using lists of parents
    if child is not None:
        def getValidParents(child, validRoles, checkParents=True):
                'Grab parents whose role is in validRoles'
        
                validParents = []
                current = child
                while current is not None:
                    if current.role in validRoles:
                        validParents.append(current)
                    if not checkParents:
                        return validParents
                    if current.role == pyatspi.ROLE_APPLICATION:
                        break
                    current = current.parent
                return validParents

        def isDifferent(new):
            'Relies on role and name to differentiate widgets'

            try:
                for old in _oldParents:
                    if old.role == new.role and old.name == new.name:
                        if new.role == pyatspi.ROLE_ALERT:
                            oldText = old.message
                            newText = new.message
                            if oldText == newText:
                                return False
                        else:
                            return False
            except (LookupError, KeyError, pyatspi.ORBit.CORBA.COMM_FAILURE):
                pass
            return True

        newParents = getValidParents(child, _childRoles, False) + getValidParents(child.parent, _containerParentRoles)
        application = None
        windowLike = None
        container = None

        #app
        if len(_oldParents) > 0:
            old = _oldParents[-1]
            new = newParents[-1]
            try:
                if old.id != new.id:
                    application = cache.getApplicationById(new.id)
            except (LookupError, KeyError, pyatspi.ORBit.CORBA.COMM_FAILURE):
                application = cache.getApplicationById(new.id)

        #container
        for x in newParents:
            if (container is None) and (x.role in _containerParentRoles) and isDifferent(x):
                if x.name != "":
                    container = x
                continue
            #windowLike
            #only execute this line if container is found
            if (container is not None) and (x.role in _windowLikeParentRoles) and isDifferent(x):
                windowLike = x

        if application is not None:
            prefix += "Switch to %s. " % application
        if container is not None:
            prefix += "In the %s" % container
            if windowLike is not None:
                prefix += " of the %s, " % windowLike
            else:
                prefix += ", "

            action = action[0].lower() + action[1:]

        _oldParents = newParents

    _actionBuffer += prefix + action + '  '
    print 'Action:', prefix + action

    # after each action, reset the watchdog timeout
    watchdog.resetTimeout()
    def __getattr__(self, attr):
        if attr == 'childCount':
            return self._accessible.childCount
        elif attr == 'name':
            return self._accessible.name
        elif attr == 'logName':
            if not self.__dict__.has_key('logName'):
                self.__dict__['logName'] = self._accessible.name
            return self.__dict__['logName']
        elif attr == 'description':
            return self._accessible.description
        elif attr == 'parent':
            return self._promote(self._accessible.parent)
        elif attr == 'role':
            return self._accessible.getRole()
        elif attr == 'roleName':
            return self._accessible.getRoleName()
        elif attr == 'extents':
            return self._accessible.queryComponent().getExtents(pyatspi.DESKTOP_COORDS)
        elif attr == 'layer':
            return self._accessible.queryComponent().getLayer()
        elif attr == 'text':
            itext = self._accessible.queryText()
            return itext.getText(0, itext.characterCount)
        elif attr == 'value':
            return self._accessible.queryValue().currentValue
        elif attr == 'caretOffset':
            return self._accessible.queryText().caretOffset
        elif attr == 'characterCount':
            return self._accessible.queryText().characterCount
        elif attr == 'app':
            try:
                return cache.getApplicationById(self._accessible.getApplication().id)
            except Exception:
                try:
                    return self._promote(self._accessible.getApplication())
                except Exception:
                    return None
        else:
            # bind states, e.g., showing, focusable, sensitive, etc.
            a = 'STATE_' + utils.toConstantName(attr)
            v = vars(pyatspi)
            if v.has_key(a):
                try:
                    return self._accessible.getState().contains(v[a])
                except AttributeError:
                    # when the app goes down, we sometimes get "AttributeError: 'CORBA.Object' object has no attribute 'contains'"
                    return False

            # FIXME: bind relations
            # FIXME: bind attributes

            # add find methods
            if attr.startswith('findAll'):
                a = None

                translations = {
                    'findAllCanvases': 'ROLE_CANVAS',
                    'findAllCheckBoxes': 'ROLE_CHECK_BOX',
                    'findAllComboBoxes': 'ROLE_COMBO_BOX',
                    'findAllEmbedded': 'ROLE_EMBEDDED',
                    'findAllEntries': 'ROLE_ENTRY',
                    'findAllFillers': 'ROLE_FILLER',
                    'findAllInvalid': 'ROLE_INVALID',
                    'findAllLastDefined': 'ROLE_LAST_DEFINED'}

                try:
                    a = translations[attr]
                except KeyError:
                    a = 'ROLE' + utils.toConstantName(attr[7:-1])

                v = vars(pyatspi)
                if v.has_key(a):
                    # generate a function on-the-fly and return it
                    def findMethod(name, checkShowing=True, recursive=True):
                        dontCheckShowing = not checkShowing
                        return utils.findAllDescendants(self, lambda x: x.role == v[a] and utils.equalsOrMatches(x.name, name) and (dontCheckShowing or x.showing), recursive)

                    return findMethod

            if attr.startswith('find'):
                a = 'ROLE' + utils.toConstantName(attr[4:])
                v = vars(pyatspi)
                if v.has_key(a):
                    # generate a function on-the-fly and return it
                    def findMethod(name, logName=None, checkShowing=True, retry=True, recursive=True, breadthFirst=True, raiseException=True, setReference=False):
                        dontCheckShowing = not checkShowing
                        y = utils.findDescendant(self, lambda x: x.role == v[a] and utils.equalsOrMatches(x.name, name) and (dontCheckShowing or x.showing), \
                            retry=retry, recursive=recursive, breadthFirst=breadthFirst, raiseException=raiseException)

                        # don't try promoting y if it's None
                        if not raiseException and y is None:
                            return y

                        # look in the widget cache first
                        try:
                            return cache.getWidget(y)
                        except KeyError:
                            pass # not in cache

                        # if the logName isn't given, set it to the name (unless the name is a regex)
                        if logName is None and type(name) is not type(re.compile('r')):
                            logName = name

                        # if we still don't have a logname, just grab the name of the accessible
                        if logName is None:
                            logName = y.name

                        # at this point, we have a logName.  next, we look for a class named 
                        # logName + roleName in moduleName.  if such a class can be found, we promote 
                        # the widget to that class, cache the instance, and return it.  
                        #
                        # if no such class can be found, and the logName is different than the name 
                        # of the widget, set the widget's log name and cache the widget.  if the logName 
                        # is the same as the widget's logName, there's no need to cache the widget.  

                        # if the logName is 'Preferences' and roleName of the widget is 'Dialog', 
                        # the name of the class to look for is 'PreferencesDialog'
                        className = utils.toClassName(logName) + utils.toClassName(y.roleName)

                        # the module prefix is the module of this class.  so if we had a widget that had 
                        # a class medsphere.openvistacis.OpenVistaCIS, and we call findDialog('Preferences') 
                        # on it, the module prefix would be medsphere.openvistacis.  we append the name of 
                        # the class we're looking for to the module prefix to get the name of the module.
                        # so continuing with the example, the full module name would be 
                        # medsphere.openvistacis.preferencesdialog.  (In the medsphere.openvistacis.preferencesdialog 
                        # module, we would look for 'PreferencesDialog' - that code is a few lines down)
                        moduleName = self.__class__.__module__ + '.' + className.lower()

                        try:
                            # import the module, grab the class, and make an instance of it, then cache the instance
                            module = __import__(moduleName, globals(), None, [className])
                            klass = vars(module)[className]
                            z = klass(y)
                            cache.addWidget(z)
                        except (ImportError, KeyError):
                            # if the found widget's logName isn't the same as the logName 
                            # we were given, set the widget's logName and cache the widget
                            if y.name != logName:
                                y.logName = logName
                                cache.addWidget(y) # make the log name stick by caching the object with the logName property set on it
                            z = y

                        # set self.preferencesDialog = the widget we just found/promoted/cached
                        if setReference:
                            self.__setattr__(utils.toVarName(logName) + utils.toClassName(z.roleName), z)

                        return z

                    return findMethod

            # add assert methods
            if attr.startswith('assertNo'):
                a = 'ROLE' + utils.toConstantName(attr[8:])
                v = vars(pyatspi)
                if v.has_key(a):
                    # generate a function on-the-fly and return it
                    def assertMethod(name, checkShowing=True, retry=False, recursive=True, breadthFirst=False, raiseException=False):
                        def descendantNotFound():
                            dontCheckShowing = not checkShowing
                            return utils.findDescendant(self, lambda x: x.role == v[a] and utils.equalsOrMatches(x.name, name) and (dontCheckShowing or x.showing), \
                                retry=retry, recursive=recursive, breadthFirst=breadthFirst, raiseException=raiseException) == None

                        assert utils.retryUntilTrue(descendantNotFound)

                    return assertMethod

            if attr.startswith('assert'):
                a = 'ROLE' + utils.toConstantName(attr[6:])
                v = vars(pyatspi)
                if v.has_key(a):
                    # generate a function on-the-fly and return it
                    def assertMethod(name, checkShowing=True, retry=False, recursive=True, breadthFirst=False, raiseException=False):
                        def descendantFound():
                            dontCheckShowing = not checkShowing
                            return utils.findDescendant(self, lambda x: x.role == v[a] and utils.equalsOrMatches(x.name, name) and (dontCheckShowing or x.showing), \
                                retry=retry, recursive=recursive, breadthFirst=breadthFirst, raiseException=raiseException) != None

                        assert utils.retryUntilTrue(descendantFound)

                    return assertMethod

            if self.__dict__.has_key(attr):
                return self.__dict__[attr]

            raise AttributeError, "%s instance has no attribute '%s'" % (self.__class__.__name__, attr)
def action(action, child=None):
    '''
    Log an action, e.g., Click Cancel

    If a child is given ... FIXME: decipher mysterious code below

    Multiple calls to action() (without a call to expectedResult() in between)
    will cause the message from each call to be concatenated to the message from
    previous calls.
    '''

    _flushBuffers()

    global _actionBuffer
    global _oldParents

    prefix = ''

    # TODO: benchmark the performance hit we receive from logparent using lists of parents
    if child is not None:
        def getValidParents(child, validRoles, checkParents=True):
                'Grab parents whose role is in validRoles'
        
                validParents = []
                current = child
                while current is not None:
                    if current.role in validRoles:
                        validParents.append(current)
                    if not checkParents:
                        return validParents
                    if current.role == pyatspi.ROLE_APPLICATION:
                        break
                    current = current.parent
                return validParents

        def isDifferent(new):
            'Relies on role and name to differentiate widgets'

            try:
                for old in _oldParents:
                    if old.role == new.role and old.name == new.name:
                        if new.role == pyatspi.ROLE_ALERT:
                            oldText = old.message
                            newText = new.message
                            if oldText == newText:
                                return False
                        else:
                            return False
            except (LookupError, KeyError, pyatspi.ORBit.CORBA.COMM_FAILURE):
                pass
            return True

        newParents = getValidParents(child, _childRoles, False) + getValidParents(child.parent, _containerParentRoles)
        application = None
        windowLike = None
        container = None

        #app
        if len(_oldParents) > 0:
            old = _oldParents[-1]
            new = newParents[-1]
            try:
                if old.id != new.id:
                    application = cache.getApplicationById(new.id)
            except (LookupError, KeyError, pyatspi.ORBit.CORBA.COMM_FAILURE):
                application = cache.getApplicationById(new.id)

        #container
        for x in newParents:
            if (container is None) and (x.role in _containerParentRoles) and isDifferent(x):
                if x.name != "":
                    container = x
                continue
            #windowLike
            #only execute this line if container is found
            if (container is not None) and (x.role in _windowLikeParentRoles) and isDifferent(x):
                windowLike = x

        if application is not None:
            prefix += "Switch to %s. " % application
        if container is not None:
            prefix += "In the %s" % container
            if windowLike is not None:
                prefix += " of the %s, " % windowLike
            else:
                prefix += ", "

            action = action[0].lower() + action[1:]

        _oldParents = newParents

    _actionBuffer += prefix + action + '  '
    print 'Action:', prefix + action

    # after each action, reset the watchdog timeout
    watchdog.resetTimeout()