X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=pyatspi%2Futils.py;h=fb7cfba591113c76368c8e8f0957eb73662e281a;hb=1889d0741dab87cb6a46246a1ebd8267f72ad148;hp=5f2bf4b31aae85d5fe87652cd7b35e497ba92258;hpb=1b3332199cafe52205457fffa15351f568c4df8d;p=platform%2Fcore%2Fuifw%2Fat-spi2-atk.git diff --git a/pyatspi/utils.py b/pyatspi/utils.py index 5f2bf4b..fb7cfba 100644 --- a/pyatspi/utils.py +++ b/pyatspi/utils.py @@ -1,525 +1,331 @@ -''' -Utility functions for AT-SPI for querying interfaces, searching the hierarchy, -converting constants to strings, and so forth. - -@author: Peter Parente -@organization: IBM Corporation -@copyright: Copyright (c) 2005, 2007 IBM Corporation -@license: LGPL - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public -License as published by the Free Software Foundation; either -version 2 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with this library; if not, write to the -Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. - -Portions of this code originally licensed and copyright (c) 2005, 2007 -IBM Corporation under the BSD license, available at -U{http://www.opensource.org/licenses/bsd-license.php} -''' -import ORBit -import Accessibility__POA +#Copyright (C) 2008 Codethink Ltd +#copyright: Copyright (c) 2005, 2007 IBM Corporation + +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU Lesser General Public +#License version 2 as published by the Free Software Foundation. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. +#You should have received a copy of the GNU Lesser General Public License +#along with this program; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#Portions of this code originally licensed and copyright (c) 2005, 2007 +#IBM Corporation under the BSD license, available at +#U{http://www.opensource.org/licenses/bsd-license.php} + +#authors: Peter Parente, Mark Doffman + +import relation +import state +import registry + +__all__ = [ + "setCacheLevel", + "getCacheLevel", + "clearCache", + "printCache", + "getInterfaceIID", + "getInterfaceName", + "listInterfaces", + "stringToConst", + "stateToString", + "stateToString", + "allModifiers", + "findDescendant", + "findAllDescendants", + "findAncestor", + "getPath", + ] + +def setCacheLevel(level): + pass + +def getCacheLevel(): + return None + +def clearCache(): + pass + +def printCache(): + print "Print cache function is deprecated"; def getInterfaceIID(obj): - ''' - Gets the ID of an interface class or object in string format for use in - queryInterface. - - @param obj: Class representing an AT-SPI interface or instance - @type obj: object - @return: IID for the interface - @rtype: string - @raise AttributeError: When the parameter does not provide typecode info - ''' - return obj.__typecode__.repo_id + """ + Gets the ID of an interface class or object in string format for use in + queryInterface. + + @param obj: Class representing an AT-SPI interface or instance + @type obj: object + @return: IID for the interface + @rtype: string + @raise AttributeError: When the parameter does not provide typecode info + + WARNING!! DEPRECATED!! + + In current D-Bus version of pyatspi this simply returns a null string. + """ + return "" def getInterfaceName(obj): - ''' - Gets the human readable name of an interface class or object in string - format. - - @param obj: Class representing an AT-SPI interface or instance - @type obj: class - @return: Name of the interface - @rtype: string - @raise AttributeError: When the parameter does not provide typecode info - ''' - return obj.__typecode__.name - -# we're importing here to avoid cyclic importants; constants relies on the -# two functions above -import constants + """ + Gets the human readable name of an interface class or object in string + format. + + @param obj: Class representing an AT-SPI interface or instance + @type obj: class + @return: Name of the interface + @rtype: string + @raise AttributeError: When the parameter does not provide typecode info + """ + return obj._dbus_interface.lstrip("org.freedesktop.atspi.") def listInterfaces(obj): - ''' - Gets a list of the names of all interfaces supported by this object. The - names are the short-hand interface names like "Accessible" and "Component", - not the full interface identifiers. - - @param obj: Arbitrary object to query for all accessibility related - interfaces. Must provide a queryInterface method. - @type obj: object - @return: Set of supported interface names - @rtype: set - @raise AttributeError: If the object provide does not implement - queryInterface - ''' - names = set() - for ic in constants.ALL_INTERFACES: - io = obj.queryInterface(getInterfaceIID(ic)) - if io is None: - continue - names.add(getInterfaceName(ic)) - return names + """ + Gets a list of the names of all interfaces supported by this object. The + names are the short-hand interface names like "Accessible" and "Component", + not the full interface identifiers. + + @param obj: Arbitrary object to query for all accessibility related + interfaces. Must provide a queryInterface method. + @type obj: object + @return: Set of supported interface names + @rtype: set + @raise AttributeError: If the object provide does not implement + queryInterface + """ + return [itf.lstrip("org.freedesktop.atspi.") for itf in obj.interfaces] def stringToConst(prefix, suffix): - ''' - Maps a string name to an AT-SPI constant. The rules for the mapping are as - follows: - - The prefix is captalized and has an _ appended to it. - - All spaces in the suffix are mapped to the _ character. - - All alpha characters in the suffix are mapped to their uppercase. - - The resulting name is used with getattr to look up a constant with that name - in the L{constants} module. If such a constant does not exist, the string - suffix is returned instead. - - This method allows strings to be used to refer to roles, relations, etc. - without direct access to the constants. It also supports the future expansion - of roles, relations, etc. by allowing arbitrary strings which may or may not - map to the current standard set of roles, relations, etc., but may still - match some non-standard role, relation, etc. being reported by an - application. - - @param prefix: Prefix of the constant name such as role, relation, state, - text, modifier, key - @type prefix: string - @param suffix: Name of the role, relation, etc. to use to lookup the constant - @type suffix: string - @return: The matching constant value - @rtype: object - ''' - name = prefix.upper()+'_'+suffix.upper().replace(' ', '_') - return getattr(constants, name, suffix) + """ + Maps a string name to an AT-SPI constant. The rules for the mapping are as + follows: + - The prefix is captalized and has an _ appended to it. + - All spaces in the suffix are mapped to the _ character. + - All alpha characters in the suffix are mapped to their uppercase. + + The resulting name is used with getattr to look up a constant with that name + in the L{constants} module. If such a constant does not exist, the string + suffix is returned instead. + + This method allows strings to be used to refer to roles, relations, etc. + without direct access to the constants. It also supports the future expansion + of roles, relations, etc. by allowing arbitrary strings which may or may not + map to the current standard set of roles, relations, etc., but may still + match some non-standard role, relation, etc. being reported by an + application. + + @param prefix: Prefix of the constant name such as role, relation, state, + text, modifier, key + @type prefix: string + @param suffix: Name of the role, relation, etc. to use to lookup the constant + @type suffix: string + @return: The matching constant value + @rtype: object + """ + name = prefix.upper()+'_'+suffix.upper().replace(' ', '_') + return getattr(constants, name, suffix) def stateToString(value): - ''' - Converts a state value to a string based on the name of the state constant in - the L{constants} module that has the given value. - - @param value: An AT-SPI state - @type value: Accessibility.StateType - @return: Human readable, untranslated name of the state - @rtype: string - ''' - return constants.STATE_VALUE_TO_NAME.get(value) + """ + Converts a state value to a string based on the name of the state constant in + the L{constants} module that has the given value. + + @param value: An AT-SPI state + @type value: Accessibility.StateType + @return: Human readable, untranslated name of the state + @rtype: string + """ + return state.STATE_VALUE_TO_NAME.get(value) def relationToString(value): - ''' - Converts a relation value to a string based on the name of the state constant - in the L{constants} module that has the given value. - - @param value: An AT-SPI relation - @type value: Accessibility.RelationType - @return: Human readable, untranslated name of the relation - @rtype: string - ''' - return constants.RELATION_VALUE_TO_NAME.get(value) + """ + Converts a relation value to a string based on the name of the state constant + in the L{constants} module that has the given value. + + @param value: An AT-SPI relation + @type value: Accessibility.RelationType + @return: Human readable, untranslated name of the relation + @rtype: string + """ + return relation.RELATION_VALUE_TO_NAME.get(value) def allModifiers(): - ''' - Generates all possible keyboard modifiers for use with - L{registry.Registry.registerKeystrokeListener}. - ''' - mask = 0 - while mask <= (1 << constants.MODIFIER_NUMLOCK): - yield mask - mask += 1 + """ + Generates all possible keyboard modifiers for use with + L{registry.Registry.registerKeystrokeListener}. + """ + mask = 0 + while mask <= (1 << registry.MODIFIER_NUMLOCK): + yield mask + mask += 1 def findDescendant(acc, pred, breadth_first=False): - ''' - Searches for a descendant node satisfying the given predicate starting at - this node. The search is performed in depth-first order by default or - in breadth first order if breadth_first is True. For example, - - my_win = findDescendant(lambda x: x.name == 'My Window') - - will search all descendants of x until one is located with the name 'My - Window' or all nodes are exausted. Calls L{_findDescendantDepth} or - L{_findDescendantBreadth} to start the recursive search. - - @param acc: Root accessible of the search - @type acc: Accessibility.Accessible - @param pred: Search predicate returning True if accessible matches the - search criteria or False otherwise - @type pred: callable - @param breadth_first: Search breadth first (True) or depth first (False)? - @type breadth_first: boolean - @return: Accessible matching the criteria or None if not found - @rtype: Accessibility.Accessible or None - ''' - if breadth_first: - return _findDescendantBreadth(acc, pred) - - for child in acc: - try: - ret = _findDescendantDepth(acc, pred) - except Exception: - ret = None - if ret is not None: return ret + """ + Searches for a descendant node satisfying the given predicate starting at + this node. The search is performed in depth-first order by default or + in breadth first order if breadth_first is True. For example, + + my_win = findDescendant(lambda x: x.name == 'My Window') + + will search all descendants of x until one is located with the name 'My + Window' or all nodes are exausted. Calls L{_findDescendantDepth} or + L{_findDescendantBreadth} to start the recursive search. + + @param acc: Root accessible of the search + @type acc: Accessibility.Accessible + @param pred: Search predicate returning True if accessible matches the + search criteria or False otherwise + @type pred: callable + @param breadth_first: Search breadth first (True) or depth first (False)? + @type breadth_first: boolean + @return: Accessible matching the criteria or None if not found + @rtype: Accessibility.Accessible or None + """ + if breadth_first: + return _findDescendantBreadth(acc, pred) + + for child in acc: + try: + ret = _findDescendantDepth(acc, pred) + except Exception: + ret = None + if ret is not None: return ret def _findDescendantBreadth(acc, pred): - ''' - Internal function for locating one descendant. Called by L{findDescendant} to - start the search. - - @param acc: Root accessible of the search - @type acc: Accessibility.Accessible - @param pred: Search predicate returning True if accessible matches the - search criteria or False otherwise - @type pred: callable - @return: Matching node or None to keep searching - @rtype: Accessibility.Accessible or None - ''' - for child in acc: - try: - if pred(child): return child - except Exception: - pass - for child in acc: - try: - ret = _findDescendantBreadth(child, pred) - except Exception: - ret = None - if ret is not None: return ret + """ + Internal function for locating one descendant. Called by L{findDescendant} to + start the search. + + @param acc: Root accessible of the search + @type acc: Accessibility.Accessible + @param pred: Search predicate returning True if accessible matches the + search criteria or False otherwise + @type pred: callable + @return: Matching node or None to keep searching + @rtype: Accessibility.Accessible or None + """ + for child in acc: + try: + if pred(child): return child + except Exception: + pass + for child in acc: + try: + ret = _findDescendantBreadth(child, pred) + except Exception: + ret = None + if ret is not None: return ret def _findDescendantDepth(acc, pred): - ''' - Internal function for locating one descendant. Called by L{findDescendant} to - start the search. - - @param acc: Root accessible of the search - @type acc: Accessibility.Accessible - @param pred: Search predicate returning True if accessible matches the - search criteria or False otherwise - @type pred: callable - @return: Matching node or None to keep searching - @rtype: Accessibility.Accessible or None - ''' - try: - if pred(acc): return acc - except Exception: - pass - for child in acc: - try: - ret = _findDescendantDepth(child, pred) - except Exception: - ret = None - if ret is not None: return ret - + """ + Internal function for locating one descendant. Called by L{findDescendant} to + start the search. + + @param acc: Root accessible of the search + @type acc: Accessibility.Accessible + @param pred: Search predicate returning True if accessible matches the + search criteria or False otherwise + @type pred: callable + @return: Matching node or None to keep searching + @rtype: Accessibility.Accessible or None + """ + try: + if pred(acc): return acc + except Exception: + pass + for child in acc: + try: + ret = _findDescendantDepth(child, pred) + except Exception: + ret = None + if ret is not None: return ret + def findAllDescendants(acc, pred): - ''' - Searches for all descendant nodes satisfying the given predicate starting at - this node. Does an in-order traversal. For example, - - pred = lambda x: x.getRole() == pyatspi.ROLE_PUSH_BUTTON - buttons = pyatspi.findAllDescendants(node, pred) - - will locate all push button descendants of node. - - @param acc: Root accessible of the search - @type acc: Accessibility.Accessible - @param pred: Search predicate returning True if accessible matches the - search criteria or False otherwise - @type pred: callable - @return: All nodes matching the search criteria - @rtype: list - ''' - matches = [] - _findAllDescendants(acc, pred, matches) - return matches + """ + Searches for all descendant nodes satisfying the given predicate starting at + this node. Does an in-order traversal. For example, + + pred = lambda x: x.getRole() == pyatspi.ROLE_PUSH_BUTTON + buttons = pyatspi.findAllDescendants(node, pred) + + will locate all push button descendants of node. + + @param acc: Root accessible of the search + @type acc: Accessibility.Accessible + @param pred: Search predicate returning True if accessible matches the + search criteria or False otherwise + @type pred: callable + @return: All nodes matching the search criteria + @rtype: list + """ + matches = [] + _findAllDescendants(acc, pred, matches) + return matches def _findAllDescendants(acc, pred, matches): - ''' - Internal method for collecting all descendants. Reuses the same matches - list so a new one does not need to be built on each recursive step. - ''' - for child in acc: - try: - if pred(child): matches.append(child) - except Exception: - pass - findAllDescendants(child, pred, matches) - + """ + Internal method for collecting all descendants. Reuses the same matches + list so a new one does not need to be built on each recursive step. + """ + for child in acc: + try: + if pred(child): matches.append(child) + except Exception: + pass + _findAllDescendants(child, pred, matches) + def findAncestor(acc, pred): - ''' - Searches for an ancestor satisfying the given predicate. Note that the - AT-SPI hierarchy is not always doubly linked. Node A may consider node B its - child, but B is not guaranteed to have node A as its parent (i.e. its parent - may be set to None). This means some searches may never make it all the way - up the hierarchy to the desktop level. - - @param acc: Starting accessible object - @type acc: Accessibility.Accessible - @param pred: Search predicate returning True if accessible matches the - search criteria or False otherwise - @type pred: callable - @return: Node matching the criteria or None if not found - @rtype: Accessibility.Accessible - ''' - if acc is None: - # guard against bad start condition - return None - while 1: - if acc.parent is None: - # stop if there is no parent and we haven't returned yet - return None - try: - if pred(acc.parent): return acc.parent - except Exception: - pass - # move to the parent - acc = acc.parent + """ + Searches for an ancestor satisfying the given predicate. Note that the + AT-SPI hierarchy is not always doubly linked. Node A may consider node B its + child, but B is not guaranteed to have node A as its parent (i.e. its parent + may be set to None). This means some searches may never make it all the way + up the hierarchy to the desktop level. + + @param acc: Starting accessible object + @type acc: Accessibility.Accessible + @param pred: Search predicate returning True if accessible matches the + search criteria or False otherwise + @type pred: callable + @return: Node matching the criteria or None if not found + @rtype: Accessibility.Accessible + """ + if acc is None: + # guard against bad start condition + return None + while 1: + if acc.parent is None: + # stop if there is no parent and we haven't returned yet + return None + try: + if pred(acc.parent): return acc.parent + except Exception: + pass + # move to the parent + acc = acc.parent def getPath(acc): - ''' - Gets the path from the application ancestor to the given accessible in - terms of its child index at each level. - - @param acc: Target accessible - @type acc: Accessibility.Accessible - @return: Path to the target - @rtype: list of integer - @raise LookupError: When the application accessible cannot be reached - ''' - path = [] - while 1: - if acc.parent is None: - path.reverse() - return path - try: - path.append(acc.getIndexInParent()) - except Exception: - raise LookupError - acc = acc.parent - -class _StateSetImpl(Accessibility__POA.StateSet): - ''' - Implementation of the StateSet interface. Clients should not use this class - directly, but rather the L{StateSet} proxy class. - - @param states: Set of states - @type states: set - ''' - def __init__(self): - '''Initializes the state set.''' - self.states = set() - - def contains(self, state): - ''' - Checks if this StateSet contains the given state. - - @param state: State to check - @type state: Accessibility.StateType - @return: True if the set contains the given state - @rtype: boolean - ''' - return state in self.states - - def add(self, state): - ''' - Adds a state to this set. - - @param state: State to add - @type state: Accessibility.StateType - ''' - self.states.add(state) - - def remove(self, state): - ''' - Removes a state from this set. - - @param state: State to remove - @type state: Accessibility.StateType - ''' - self.states.remove(state) - - def equals(self, state_set): - ''' - Checks if this StateSet contains exactly the same members as the given - StateSet. - - @param state_set: Another set - @type state_set: Accessibility.StateSet - @return: Are the sets equivalent in terms of their contents? - @rtype: boolean - ''' - # don't check private members, object might be from another process - # or implementation - return set(state_set.getStates()) == self.states - - def compare(self, state_set): - ''' - Computes the symmetric differences of this L{StateSet} and the given - L{StateSet}. - - @note: This method is not currently implemented because of difficulties - with reference counting. This method needs to return a new - Accessibility.StateSet object, but the Python implementation for that - object needs to be kept alive. The problem is who will keep that - server implementation alive? As soon as it goes out of scope, it's - GC'ed. This object cannot keep it alive either as it may go out of - scope before the new object is ready to be finalized. With a global - cache of objects, we don't know when to invalidate. - - @param state_set: Another set - @type state_set: Accessibility.StateSet - @return: Elements in only one of the two sets - @rtype: Accessibility.StateSet - ''' - raise ORBit.CORBA.NO_IMPLEMENT - - # don't check private members, object might be from another process - # or implementation - #states = set(state_set.getStates()) - #diff = self.states.symmetric_difference(states) - #new_ss = _StateSetImpl() - #map(new_ss._this().add, diff) - #return new_ss._this() - - def isEmpty(self): - ''' - Checks if this L{StateSet} is empty. - - @return: Is it empty? - @rtype: boolean - ''' - return len(self.states) == 0 - - def getStates(self): - ''' - Gets the sequence of all states in this set. - - @return: List of states - @rtype: list - ''' - return list(self.states) - -class StateSet(object): - ''' - Python proxy for the L{_StateSetImpl} class. Use this to safely instantiate - new StateSet objects in Python. - - @param impl: State set implementation - @type impl: L{_StateSetImpl} - ''' - def __init__(self, *states): - ''' - Initializes the state set with the given states. - - @param states: States to add immediately - @type states: list - ''' - self.impl = _StateSetImpl() - map(self.impl._this().add, states) - - def contains(self, state): - ''' - Checks if this StateSet contains the given state. - - @param state: State to check - @type state: Accessibility.StateType - @return: True if the set contains the given state - @rtype: boolean - ''' - return self.impl._this().contains(state) - - def add(self, *states): - ''' - Adds states to this set. - - @param states: State(s) to add - @type states: Accessibility.StateType - ''' - map(self.impl._this().add, state) - - def remove(self, state): - ''' - Removes states from this set. - - @param states: State(s) to remove - @type states: Accessibility.StateType - ''' - map(self.impl._this().remove, state) - - def equals(self, state_set): - ''' - Checks if this StateSet contains exactly the same members as the given - StateSet. - - @param state_set: Another set - @type state_set: Accessibility.StateSet - @return: Are the sets equivalent in terms of their contents? - @rtype: boolean - ''' - if isinstance(state_set, self.__class__): - # convenience if we're given a proxy - state_set = state_set.raw() - return self.impl._this().equals(state_set) - - def compare(self, state_set): - ''' - Finds the symmetric difference between this state set andthe one provided, - and returns it as a new StateSet. - - @note: This does not use L{_StateSetImpl.compare} which cannot be - implemented at this time - @param state_set: Set to compare against - @type state_set: Accessibility.StateSet - @return: Proxy for the new set - @rtype: L{StateSet} - ''' - if isinstance(state_set, self.__class__): - # shortcut if it's another one of our proxies - state_set = state_set.raw() - a = set(self.impl._this().getStates()) - b = set(state_set.getStates()) - diff = a.symmetric_difference(b) - return StateSet(*diff) - - def isEmpty(self): - ''' - Checks if this StateSet is empty. - - @return: Is it empty? - @rtype: boolean - ''' - return self.impl._this().isEmpty() - - def getStates(self): - ''' - Gets the sequence of all states in this set. - - @return: List of states - @rtype: list - ''' - return self.impl._this().getStates() - - def raw(self): - ''' - Gets the Accessibility.StateSet object proxied for use in a remote - call. - - @return: State set - @rtype: Accessibility.StateSet - ''' - return self.impl._this() + """ + Gets the path from the application ancestor to the given accessible in + terms of its child index at each level. + + @param acc: Target accessible + @type acc: Accessibility.Accessible + @return: Path to the target + @rtype: list of integer + @raise LookupError: When the application accessible cannot be reached + """ + path = [] + while 1: + if acc.parent is None: + path.reverse() + return path + try: + path.append(acc.getIndexInParent()) + except Exception: + raise LookupError + acc = acc.parent