2008-08-21 Mark Doffman <mark.doffman@codethink.co.uk>
[platform/core/uifw/at-spi2-atk.git] / pyatspi / accessible.py
index 433d05b..093ac03 100644 (file)
-'''
-Creates functions at import time that are mixed into the 
-Accessibility.Accessible base class to make it more Pythonic.
+#Copyright (C) 2008 Codethink Ltd
 
-Based on public domain code originally posted at 
-U{http://wwwx.cs.unc.edu/~parente/cgi-bin/RuntimeClassMixins}.
+#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.
 
-@var _ACCESSIBLE_CACHE: Pairs hash values for accessible objects to 
-  L{_PropertyCache} bags. We do not store actual accessibles in the dictionary
-  because that would +1 their ref counts and cause __del__ to never be called
-  which is the method we rely on to properly invalidate cache entries.
-@type _ACCESSIBLE_CACHE: dictionary
-@var _CACHE_LEVEL: Current level of caching enabled. Checked dynamically by
-  L{_AccessibleMixin}
-@type _CACHE_LEVEL: integer
+#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.
 
-@author: Peter Parente
-@organization: IBM Corporation
-@copyright: Copyright (c) 2005, 2007 IBM Corporation
-@license: LGPL
+import interfaces
+from base import BaseProxy, Enum
+from factory import create_accessible, add_accessible_class
+from state import StateSet, _marshal_state_set
+from relation import _marshal_relation_set
+from role import Role
 
-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.
+__all__ = [
+          "LOCALE_TYPE",
+          "LOCALE_TYPE_COLLATE",
+          "LOCALE_TYPE_CTYPE",
+          "LOCALE_TYPE_MESSAGES",
+          "LOCALE_TYPE_MONETARY",
+          "LOCALE_TYPE_NUMERIC",
+          "LOCALE_TYPE_TIME",
+          "BoundingBox",
+          "Accessible",
+         ]
 
-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.
+class LOCALE_TYPE(Enum):
+    _enum_lookup = {
+        0:'LOCALE_TYPE_MESSAGES',
+        1:'LOCALE_TYPE_COLLATE',
+        2:'LOCALE_TYPE_CTYPE',
+        3:'LOCALE_TYPE_MONETARY',
+        4:'LOCALE_TYPE_NUMERIC',
+        5:'LOCALE_TYPE_TIME',
+    }
 
-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 new
-import types
-import ORBit
-import Accessibility
-import constants
-import utils
-import registry
+LOCALE_TYPE_COLLATE = LOCALE_TYPE(1)
+LOCALE_TYPE_CTYPE = LOCALE_TYPE(2)
+LOCALE_TYPE_MESSAGES = LOCALE_TYPE(0)
+LOCALE_TYPE_MONETARY = LOCALE_TYPE(3)
+LOCALE_TYPE_NUMERIC = LOCALE_TYPE(4)
+LOCALE_TYPE_TIME = LOCALE_TYPE(5)
 
-_ACCESSIBLE_CACHE = {}
-_CACHE_LEVEL = None
+#------------------------------------------------------------------------------
 
-class _PropertyCache(object):
-  '''Fixed-size bag class for holding cached values.'''
-  __slots__ = ('name', 'description', 'rolename')
-
-def getCacheLevel():
-  '''
-  Gets the current level of caching.
-  
-  @return: None indicating no caching is in effect. 
-    L{constants.CACHE_INTERFACES} indicating all interface query results are
-    cached. L{constants.CACHE_PROPERTIES} indicating all basic accessible
-    properties are cached.
-  @rtype: integer
-  '''
-  return _CACHE_LEVEL
-
-def setCacheLevel(val):
-  '''
-  Sets the desired level of caching for all accessible objects created after
-  this function is invoked. Immediately clears the current accessible cache.
-  
-  @param val: None indicating no caching is in effect. 
-    L{constants.CACHE_INTERFACES} indicating all interface query results are
-    cached. L{constants.CACHE_PROPERTIES} indicating all basic accessible
-    properties are cached plus all interfaces.
-  @type val: integer
-  '''
-  global _CACHE_LEVEL
-  if _CACHE_LEVEL != val:
-    # empty our accessible cache  
-    _ACCESSIBLE_CACHE.clear()
-    # need to register/unregister for listeners depending on caching level
-    if val == constants.CACHE_PROPERTIES:
-      r = registry.Registry()
-      r.registerEventListener(_updateCache, *constants.CACHE_EVENTS)
-    else:
-      r = registry.Registry()
-      r.deregisterEventListener(_updateCache, *constants.CACHE_EVENTS)
-  _CACHE_LEVEL = val
-  
-def clearCache():
-  '''Forces a clear of the entire cache.'''
-  _ACCESSIBLE_CACHE.clear()
-  
-def printCache(template='%s'):
-  '''
-  Prints the contents of the cache.
-  
-  @param template: Format string to use when printing
-  @type template: string
-  '''
-  print template % _ACCESSIBLE_CACHE
-
-def _updateCache(event):
-  '''
-  Invalidates an entry in the cache when the hash value of a source of an event
-  matches an entry in the cache.
-  
-  @param event: One of the L{constants.CACHE_EVENTS} event types
-  @type event: L{event.Event}
-  '''
-  try:
-    del _ACCESSIBLE_CACHE[hash(event.source)]
-  except KeyError:
-    return
-
-def _makeQuery(interface):
-  '''
-  Builds a function querying to a specific interface and returns it.
-  
-  @param interface: Class representing an AT-SPI interface
-  @type interface: class
-  @return: Function querying to the given interface
-  @rtype: function
-  '''
-  def _inner(self):
-    '''
-    Queries an object for another interface.
-  
-    @return: An object with the desired interface
-    @rtype: object
-    @raise NotImplementedError: When the desired interface is not supported    
-    '''
-    iid = utils.getInterfaceIID(interface)
-    try:
-      i = self._icache[iid]
-    except KeyError:
-      # interface not cached
-      caching = True
-    except AttributeError:
-      # determine if we're caching
-      caching = _CACHE_LEVEL is not None
-      if caching:
-        # initialize the cache
-        self._icache = {}
-    else:
-      # check if our cached result was an interface, or an indicator that the
-      # interface is not supported
-      if i is None:
-        raise NotImplementedError
-      else:
-        return i
-
-    try:
-      # do the query remotely
-      i = self.queryInterface(iid)
-      if i is not None:
-        i = i._narrow(interface)
-    except Exception, e:
-      raise LookupError(e)      
-    if i is None:
-      # cache that the interface is not supported
-      if caching:
-        self._icache[iid] = None
-      raise NotImplementedError
+class BoundingBox(list):
+    def __new__(cls, x, y, width, height):
+        return list.__new__(cls, (x, y, width, height))
+    def __init__(self, x, y, width, height):
+        list.__init__(self, (x, y, width, height))
     
-    if caching:
-      # cache the narrow'ed result, but only if we're caching for this object
-      self._icache[iid] = i
-    return i
-  
-  return _inner
-
-def _makeExceptionHandler(func):
-  '''
-  Builds a function calling the one it wraps in try/except statements catching
-  CORBA exceptions.
-  
-  @return: Function calling the method being wrapped
-  @rtype: function
-  '''
-  def _inner(self, *args, **kwargs):
-    try:
-      # try calling the original func
-      rv = func(self, *args, **kwargs)
-      if isinstance(rv, ORBit.CORBA.Object): rv.ref()
-      return rv
-    except ORBit.CORBA.NO_IMPLEMENT, e:
-      # raise Python exception
-      raise NotImplementedError(e)
-    except ORBit.CORBA.Exception, e:
-      # raise Python exception
-      raise LookupError(e)
-  return _inner
+    def _get_x(self):
+        return self[0]
+    def _set_x(self, val):
+        self[0] = val
+    x = property(fget=_get_x, fset=_set_x)
+    def _get_y(self):
+        return self[1]
+    def _set_y(self, val):
+        self[1] = val
+    y = property(fget=_get_y, fset=_set_y)
+    def _get_width(self):
+        return self[2]
+    def _set_width(self, val):
+        self[2] = val
+    width = property(fget=_get_width, fset=_set_width)
+    def _get_height(self):
+        return self[3]
+    def _set_height(self, val):
+        self[3] = val
+    height = property(fget=_get_height, fset=_set_height)
 
-def _mixInterfaces(cls, interfaces):
-  '''
-  Add methods for querying to interfaces other than the base accessible to
-  the given class.
-  
-  @param cls: Class to mix interface methods into
-  @type cls: class
-  @param interfaces: Classes representing AT-SPI interfaces
-  @type interfaces: list of class
-  '''
-  # create functions in this module for all interfaces listed in constants
-  for interface in interfaces:
-    # build name of converter from the name of the interface
-    name = 'query%s' % utils.getInterfaceName(interface)
-    # build a function that queries to the given interface
-    func = _makeQuery(interface)
-    # build a new method that is a clone of the original function
-    method = new.function(func.func_code, func.func_globals, name, 
-                          func.func_defaults, func.func_closure)
-    # add the method to the given class
-    setattr(cls, name, method)
+#------------------------------------------------------------------------------
 
-def _mixExceptions(cls):
-  '''
-  Wraps all methods and properties in a class with handlers for CORBA 
-  exceptions.
-  
-  @param cls: Class to mix interface methods into
-  @type cls: class
-  '''
-  # get a method type as a reference from a known method
-  method_type = Accessibility.Accessible.getRole.__class__
-  # loop over all names in the new class
-  for name in cls.__dict__.keys():
-    obj = cls.__dict__[name]
-    # check if we're on a protected or private method
-    if name.startswith('_'):
-      continue
-    # check if we're on a method
-    elif isinstance(obj, method_type):
-      # wrap the function in an exception handler
-      method = _makeExceptionHandler(obj)
-      # add the wrapped function to the class
-      setattr(cls, name, method)
-    # check if we're on a property
-    elif isinstance(obj, property):
-      # wrap the getters and setters
-      if obj.fget:
-        func = getattr(cls, obj.fget.__name__)
-        getter = _makeExceptionHandler(func)
-      else:
-        getter = None
-      if obj.fset:
-        func = getattr(cls, obj.fset.__name__)
-        setter = _makeExceptionHandler(func)
-      else:
-        setter = None
-      setattr(cls, name, property(getter, setter))
+class Accessible(BaseProxy):
+    """
+    The base interface which is implemented by all accessible objects.
+    All objects support interfaces for querying their contained
+    'children' and position in the accessible-object hierarchy,
+    whether or not they actually have children.
+    """
 
-def _mixClass(cls, new_cls, ignore=[]):
-  '''
-  Adds the methods in new_cls to cls. After mixing, all instances of cls will
-  have the new methods. If there is a method name clash, the method already in
-  cls will be prefixed with '_mix_' before the new method of the same name is 
-  mixed in.
-  
-  @note: _ is not the prefix because if you wind up with __ in front of a 
-  variable, it becomes private and mangled when an instance is created. 
-  Difficult to invoke from the mixin class.
+    def __len__(self):
+           return self.getChildCount()
 
-  @param cls: Existing class to mix features into
-  @type cls: class
-  @param new_cls: Class containing features to add
-  @type new_cls: class
-  @param ignore: Ignore these methods from the mixin
-  @type ignore: iterable
-  '''
-  # loop over all names in the new class
-  for name, func in new_cls.__dict__.items():
-    if name in ignore:
-      continue
-    if isinstance(func, types.FunctionType):
-      # build a new function that is a clone of the one from new_cls
-      method = new.function(func.func_code, func.func_globals, name, 
-                            func.func_defaults, func.func_closure)
-      try:
-        # check if a method of the same name already exists in the target
-        old_method = getattr(cls, name)
-      except AttributeError:
-        pass
-      else:
-        # rename the old method so we can still call it if need be
-        setattr(cls, '_mix_'+name, old_method)
-      # add the clone to cls
-      setattr(cls, name, method)
-    elif isinstance(func, staticmethod):
-      try:
-        # check if a method of the same name already exists in the target
-        old_method = getattr(cls, name)
-      except AttributeError:
-        pass
-      else:
-        # rename the old method so we can still call it if need be
-        setattr(cls, '_mix_'+name, old_method)
-      setattr(cls, name, func)
-    elif isinstance(func, property):
-      try:
-        # check if a method of the same name already exists in the target
-        old_prop = getattr(cls, name)
-      except AttributeError:
-        pass
-      else:
-        # IMPORTANT: We save the old property before overwriting it, even 
-        # though we never end up calling the old prop from our mixin class.
-        # If we don't save the old one, we seem to introduce a Python ref count
-        # problem where the property get/set methods disappear before we can
-        # use them at a later time. This is a minor waste of memory because
-        # a property is a class object and we only overwrite a few of them.
-        setattr(cls, '_mix_'+name, old_prop)
-      setattr(cls, name, func)
-
-class _AccessibleMixin(object):
-  '''
-  Defines methods to be added to the Accessibility.Accessible class. The
-  features defined here will be added to the Accessible class at run time so
-  that all instances of Accessible have them (i.e. there is no need to
-  explicitly wrap an Accessible in this class or derive a new class from it.)
-  
-  @cvar SLOTTED_CLASSES: Mapping from raw Accessibility class to a new class
-    having the slots defined by L{SLOTS}
-  @type SLOTTED_CLASSES: dictionary
-  @cvar SLOTS: All slots to create
-  @type SLOTS: tuple
-  '''
-  SLOTTED_CLASSES = {}
-  SLOTS = ('_icache', 'user_data')
-  
-  def __new__(cls):
-    '''
-    Creates a new class mimicking the one requested, but with extra named 
-    defined in __slots__. The _cache attribute is used internally for interface
-    caching. The user_data field may be populated with whatever data structure
-    a client wishes to use. Neither is set to a default value by default.
-    
-    Note that we can't simply mix __slots__ into this class because __slots__
-    has an effect only at class creation time. 
+    def __getitem__(self, index):
+           return self.getChildAtIndex(index)
     
-    We also do not completely obliterate __slots__ to allow __dict__ to be
-    instantiated as normal as reducing the initialization and memory overhead
-    of the millions of accessible objects that are created is a good thing for
-    many clients.
+    def getApplication(self):
+        """
+        Get the containing Application for this object.
+        @return the Application instance to which this object belongs.
+        """
+       application_root = self._cache[self._app_name]._get_root()
+       #TODO Set the desktop object as the parent of this.
+       return create_accessible(self._cache,
+                                self._app_name,
+                                application_root,
+                                interfaces.ATSPI_APPLICATION,
+                                connection=self._cache._connection)
     
-    @param cls: Accessibility object class
-    @type cls: class
-    @return: Instance of the new class
-    @rtype: object
-    '''
-    try:
-      # check if we've already created a new version of the class
-      new_cls = _AccessibleMixin.SLOTTED_CLASSES[cls]
-    except KeyError:
-      # create the new class if not
-      new_cls = type(cls.__name__, (cls,), 
-                     {'__module__' : cls.__module__, 
-                      '__slots__' : _AccessibleMixin.SLOTS})
-      _AccessibleMixin.SLOTTED_CLASSES[cls] = new_cls
-    obj = cls._mix___new__(new_cls)
-    return obj
-  
-  def __del__(self):
-    '''    
-    Decrements the reference count on the accessible object when there are no
-    Python references to this object. This provides automatic reference
-    counting for AT-SPI objects. Also removes this object from the cache if
-    we're caching properties. 
-    '''
-    try:
-      del _ACCESSIBLE_CACHE[hash(self)]
-    except KeyError:
-      pass
-    try:
-      self.unref()
-    except Exception:
-      pass
-    
-  def __iter__(self):
-    '''
-    Iterator that yields one accessible child per iteration. If an exception is
-    encountered, None is yielded instead.
-    
-    @return: A child accessible
-    @rtype: Accessibility.Accessible
-    '''
-    for i in xrange(self.childCount):
-      try:
-        yield self.getChildAtIndex(i)
-      except LookupError:
-        yield None
-    
-  def __str__(self):
-    '''
-    Gets a human readable representation of the accessible.
-    
-    @return: Role and name information for the accessible
-    @rtype: string
-    '''
-    try:
-      return '[%s | %s]' % (self.getRoleName(), self.name)
-    except Exception:
-      return '[DEAD]'
+    def getAttributes(self):
+        """
+        Get a list of properties applied to this object as a whole, as
+        an AttributeSet consisting of name-value pairs. As such these
+        attributes may be considered weakly-typed properties or annotations,
+        as distinct from the strongly-typed interface instance data declared
+        using the IDL "attribute" keyword.
+        Not all objects have explicit "name-value pair" AttributeSet
+        properties.
+        Attribute names and values may have any UTF-8 string value, however
+        where possible, in order to facilitate consistent use and exposure
+        of "attribute" properties by applications and AT clients, attribute
+        names and values should chosen from a publicly-specified namespace
+        where appropriate.
+        Where possible, the names and values in the name-value pairs
+        should be chosen from well-established attribute namespaces using
+        standard semantics. For example, attributes of Accessible objects
+        corresponding to XHTML content elements should correspond to
+        attribute names and values specified in the w3c XHTML specification,
+        at http://www.w3.org/TR/xhtml2, where such values are not already
+        exposed via a more strongly-typed aspect of the AT-SPI API. Metadata
+        names and values should be chosen from the 'Dublin Core' Metadata
+        namespace using Dublin Core semantics: http://dublincore.org/dcregistry/
+        Similarly, relevant structural metadata should be exposed using
+        attribute names and values chosen from the CSS2 and WICD specification:
+        http://www.w3.org/TR/1998/REC-CSS2-19980512 WICD (http://www.w3.org/TR/2005/WD-WICD-20051121/).
+
+        @return : An AttributeSet encapsulating any "attribute values"
+        currently defined for the object. An attribute set is a list of strings
+       with each string comprising an name-value pair format 'name:value'.
+        """
+        func = self.get_dbus_method("getAttributes")
+        return func()
     
-  def __nonzero__(self):
-    '''
-    @return: True, always
-    @rtype: boolean
-    '''
-    return True
+    def getChildAtIndex(self, index):
+        """
+        Get the accessible child of this object at index. 
+        @param : index
+        an in parameter indicating which child is requested (zero-indexed).
+        @return : the 'nth' Accessible child of this object.
+        """
+       path = self.cached_data.children[index]
+       return create_accessible(self._cache,
+                                self._app_name,
+                                path,
+                                interfaces.ATSPI_ACCESSIBLE,
+                                connection=self._cache._connection)
     
-  def __getitem__(self, index):
-    '''
-    Thin wrapper around getChildAtIndex.
+    def getIndexInParent(self):
+        """
+        Get the index of this object in its parent's child list. 
+        @return : a long integer indicating this object's index in the
+        parent's list.
+        """
+       for i in range(0, self.parent.childCount):
+               child = self.parent.getChildAtIndex(i)
+               if self.isEqual(child):
+                       return i
+       raise AccessibleObjectNoLongerExists("Child not found within parent")
     
-    @param index: Index of desired child
-    @type index: integer
-    @return: Accessible child
-    @rtype: Accessibility.Accessible
-    '''
-    n = self.childCount
-    if index >= n:
-      raise IndexError
-    elif index < -n:
-      raise IndexError
-    elif index < 0:
-      index += n
-    return self.getChildAtIndex(index)
-  
-  def __len__(self):
-    '''
-    Thin wrapper around childCount.
+    def getLocalizedRoleName(self):
+        """
+        Get a string indicating the type of UI role played by this object,
+        translated to the current locale.
+        @return : a UTF-8 string indicating the type of UI role played
+        by this object.
+        """
+        func = self.get_dbus_method("getLocalizedRoleName")
+        return func()
     
-    @return: Number of child accessibles
-    @rtype: integer
-    '''
-    return self.childCount
-  
-  def _get_name(self):
-    '''
-    Gets the name of the accessible from the cache if it is available, 
-    otherwise, fetches it remotely.
+    def getRelationSet(self):
+        """
+        Get a set defining this object's relationship to other accessible
+        objects. 
+        @return : a RelationSet defining this object's relationships.
+        """
+        func = self.get_dbus_method("getRelationSet")
+        relation_set = func()
+        return _marshal_relation_set(self._cache, self._dbus_object, self._app_name, relation_set)
     
-    @return: Name of the accessible
-    @rtype: string
-    '''
-    if _CACHE_LEVEL != constants.CACHE_PROPERTIES:
-      return self._get_name()
+    def getRole(self):
+        """
+        Get the Role indicating the type of UI role played by this object.
+        @return : a Role indicating the type of UI role played by this
+        object.
+        """
+        return Role(self.cached_data.role)
     
-    cache = _ACCESSIBLE_CACHE
-    h = hash(self)
-    try:
-      return cache[h].name
-    except KeyError:
-      # no cached info for this object yet
-      name = self._get_name()
-      pc = _PropertyCache()
-      pc.name = name
-      cache[h] = pc
-      return name
-    except AttributeError:
-      # no cached name for this object yet
-      name = self._get_name()
-      cache[h].name = name
-      return name
+    def getRoleName(self):
+        """
+        Get a string indicating the type of UI role played by this object.
+        @return : a UTF-8 string indicating the type of UI role played
+        by this object.
+        """
+        func = self.get_dbus_method("getRoleName")
+        return func()
     
-  name = property(_get_name, Accessibility.Accessible._set_name)
-  
-  def getRoleName(self):
-    '''
-    Gets the unlocalized role name of the accessible from the cache if it is 
-    available, otherwise, fetches it remotely.
+    def getState(self):
+        """
+        Get the current state of the object as a StateSet. 
+        @return : a StateSet encapsulating the currently true states
+        of the object.
+        """
+        func = self.get_dbus_method("getState")
+        bitfield = func()
+       return _marshal_state_set(bitfield)
     
-    @return: Role name of the accessible
-    @rtype: string
-    '''
-    if _CACHE_LEVEL != constants.CACHE_PROPERTIES:
-      return self._mix_getRoleName()
-
-    cache = _ACCESSIBLE_CACHE
-    h = hash(self)
-    try:
-      return cache[h].rolename
-    except KeyError, e:
-      # no cached info for this object yet
-      rolename = self._mix_getRoleName()
-      pc = _PropertyCache()
-      pc.rolename = rolename
-      cache[h] = pc
-      return rolename
-    except AttributeError, e:
-      # no cached name for this object yet
-      rolename = self._mix_getRoleName()
-      cache[h].rolename = rolename
-      return rolename
-  
-  def _get_description(self):
-    '''    
-    Gets the description of the accessible from the cache if it is available,
-    otherwise, fetches it remotely.
+    def isEqual(self, accessible):
+        """
+        Determine whether an Accessible refers to the same object as
+        another. This method should be used rather than brute-force comparison
+        of object references (i.e. "by-value" comparison), as two object
+        references may have different apparent values yet refer to the
+        same object.
+        @param : obj
+        an Accessible object reference to compare to 
+        @return : a boolean indicating whether the two object references
+        point to the same object.
+        """
+        return  (self._app_name == accessible._app_name) and \
+               (self._acc_path == accessible._acc_path)        
     
-    @return: Description of the accessible
-    @rtype: string
-    '''
-    if _CACHE_LEVEL != constants.CACHE_PROPERTIES:
-      return self._get_description()
-
-    cache = _ACCESSIBLE_CACHE
-    h = hash(self)
-    try:
-      return cache[h].description
-    except KeyError:
-      # no cached info for this object yet
-      description = self._get_description()
-      pc = _PropertyCache()
-      pc.description = description
-      cache[h] = pc
-      return description
-    except AttributeError:
-      # no cached name for this object yet
-      description = self._get_description()
-      cache[h].description = description
-      return description
+    def get_childCount(self):
+        return len(self.cached_data.children)
+    _childCountDoc = \
+        """
+        childCount: the number of children contained by this object.
+        """
+    childCount = property(fget=get_childCount, doc=_childCountDoc)
     
-  description = property(_get_description, 
-                         Accessibility.Accessible._set_description)
-  
-  def getIndexInParent(self):
-    '''
-    Gets the index of this accessible in its parent. Uses the implementation of
-    this method provided by the Accessibility.Accessible object, but checks the
-    bound of the value to ensure it is not outside the range of childCount 
-    reported by this accessible's parent.
+    def get_description(self):
+        return self.cached_data.description
+    _descriptionDoc = \
+        """
+        a string describing the object in more detail than name.
+        """
+    description = property(fget=get_description, doc=_descriptionDoc)
     
-    @return: Index of this accessible in its parent
-    @rtype: integer
-    '''
-    i = self._mix_getIndexInParent()
-    try:
-      # correct for out-of-bounds index reporting
-      return min(self.parent.childCount-1, i)
-    except AttributeError:
-      # return sentinel if there is no parent
-      return -1
-
-  def getApplication(self):
-    '''
-    Gets the most-parent accessible (the application) of this accessible. Tries 
-    using the getApplication method introduced in AT-SPI 1.7.0 first before 
-    resorting to traversing parent links.
+    def get_name(self):
+        return self.cached_data.name
+    _nameDoc = \
+        """
+        a (short) string representing the object's name.
+        """
+    name = property(fget=get_name, doc=_nameDoc)
     
-    @warning: Cycles involving more than the previously traversed accessible 
-      are not detected by this code.
-    @return: Application object
-    @rtype: Accessibility.Application
-    '''
-    try:
-      return self._mix_getApplication()
-    except AttributeError:
-      pass
-    curr = self
-    try:
-      while curr.parent is not None and (not curr.parent == curr):
-        curr = curr.parent
-      return curr
-    except Exception:
-      pass
-    # return None if the application isn't reachable for any reason
-    return None
+    def get_parent(self):
+       if self._parent:
+               return self._parent
+       else:
+               return create_accessible(self._cache,
+                                        self._app_name,
+                                        self.cached_data.parent,
+                                        interfaces.ATSPI_ACCESSIBLE,
+                                        connection=self._cache._connection)
 
-class _RelationMixin(object):
-  '''
-  Defines methods to be added to the Relation class. At this time it only
-  overrides L{_RelationMixin.getTarget} which by the IDL's standard is
-  supposed to return CORBA.Objects but we expect LAccessibility.Accessible
-  objects (see http://bugzilla.gnome.org/show_bug.cgi?id=435833). 
-  This seems to be a problem especially with the Java implementation of CORBA.
-  '''
-  def getTarget(self, index):
-    '''
-    Overrides the regular getTarget to return Accessibility.Accessible
-    objects.
+    _parentDoc = \
+        """
+        an Accessible object which is this object's containing object.
+        """
+    parent = property(fget=get_parent, doc=_parentDoc)
 
-    @return: The 'nth' target of this Relation.
-    @rtype: Accessibility.Accessible
-    '''
-    target = self._mix_getTarget(index)
-    target.ref()
-    return target._narrow(Accessibility.Accessible)
+# Register the Accessible class with the accessible factory.
+add_accessible_class(interfaces.ATSPI_ACCESSIBLE, Accessible)
 
-# 1. mix the exception handlers into all queryable interfaces
-map(_mixExceptions, constants.ALL_INTERFACES)
-# 2. mix the exception handlers into other Accessibility objects
-map(_mixExceptions, [Accessibility.StateSet])
-# 3. mix the new functions
-_mixClass(Accessibility.Accessible, _AccessibleMixin,
-          ['_get_name', '_get_description'])
-# 4. mix queryInterface convenience methods
-_mixInterfaces(Accessibility.Accessible, constants.ALL_INTERFACES)
-# 5. mix Relation class
-_mixClass(Accessibility.Relation, _RelationMixin)
+#END----------------------------------------------------------------------------