2008-08-27 Mark Doffman <mark.doffman@codethink.co.uk>
[platform/core/uifw/at-spi2-atk.git] / pyatspi / utils.py
index a914375..f086bdc 100644 (file)
-'''
-Utility functions for AT-SPI for querying interfaces, searching the hierarchy,
-converting constants to strings, and so forth.
+#Copyright (C) 2008 Codethink Ltd
+#copyright: Copyright (c) 2005, 2007 IBM Corporation
 
-@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 Lesser General Public
+#License version 2 as published by the Free Software Foundation.
 
-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 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.
 
-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.
+#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}
 
-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.
+#authors: Peter Parente, Mark Doffman
 
-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 Accessibility__POA
+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
+       """
+       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.")
 
 # we're importing here to avoid cyclic importants; constants relies on the
 # two functions above
 import constants
 
 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.
+       """
+       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
+       @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.
+       """
+       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)
+       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 constants.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 constants.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 << constants.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)
+       """
+       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
+       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 = _findDescedantBreadth(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.
+       """
+       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
-    
+       @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 StateSet(Accessibility__POA.StateSet):
-  '''
-  Convenience implementation of AT-SPI StateSet, for future use with Collection
-  interface.
-  
-  @param states: Set of states
-  @type states: set
-  '''
-  def __init__(self, *states):
-    '''Initializes the state set with the given states.'''
-    self.states = set(states)
-    
-  def contains(self, state):
-    '''
-    Checks if this L{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 one or more states to this set.
-    
-    @param state: State(s) to add
-    @type state: Accessibility.StateType
-    '''
-    self.states.add(state)
-  
-  def remove(self, *state):
-    '''
-    Removes one or more states from this set.
-    
-    @param state: State(s) to remove
-    @type state: Accessibility.StateType
-    '''
-    self.states.remove(state)
-  
-  def equals(self, state_set):
-    '''
-    Checks if this L{StateSet} contains exactly the same members as the given
-    L{StateSet}.
-    
-    @param state_set: Another set
-    @type state_set: L{StateSet}
-    @return: Are the sets equivalent in terms of their contents?
-    @rtype: boolean
-    '''
-    return self.state_set == self.states
-  
-  def compare(self, state_set):
-    '''
-    Computes the symmetric differences of this L{StateSet} and the given
-    L{StateSet}.
-    
-    @param state_set: Another set
-    @type state_set: L{StateSet}
-    @return: Elements in only one of the two sets
-    @rtype: L{StateSet}
-    '''
-    diff = self.states.symmetric_difference(state_set.states)
-    return StateSet(*diff)
-  
-  def isEmpty(self):
-    '''
-    Checks if this L{StateSet} is empty.
-    
-    @return: Is it empty?
-    @rtype: boolean
-    '''
-    return len(self.states) == 0
+       """
+       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
 
-  def getStates(self):
-    '''
-    Gets the sequence of all states in this set.
-    
-    @return: List of states
-    @rtype: list
-    '''
-    return list(self.states)
+del constants