boa-constructor / RTTI.py

#----------------------------------------------------------------------
# Name:        RTTI.py
# Purpose:
#
# Author:      Riaan Booysen
#
# Created:     1999
# RCS-ID:      $Id$
# Copyright:   (c) 1999, 2000 Riaan Booysen
# Licence:     GPL
#----------------------------------------------------------------------
from types import *
from wxPython.wx import *

def sort_proxy(self, other):
    return self < other and -1 or self > other and 1 or 0

class PropertyWrapper:
    # XXX This would be better implemented with subclassing
    def __init__(self, name, rType, getter, setter):
        """ Types: 'CtrlRoute', 'CompnRoute', 'EventRoute', 'NoneRoute',
                   'IndexRoute', 'NameRoute'
        """

        self.name = name
        self.routeType = rType
        self.getter = getter
        self.setter = setter
        self.ctrl = None
        self.compn = None

        # Not used yet
        self.setterName = ''

    def __cmp__(self, other):
        """ This is for sorting lists of PropertyWrappers """
#        sort_proxy(self.name, other.name)
        if self.name < other.name:
            return -1
        if self.name > other.name:
            return 1
        return 0

    def __repr__(self):
        return '<instance PropertyWrapper: %s, %s (%s, %s)'%(self.name,
          self.routeType, self.getter, self.setter)

    def connect(self, ctrl, compn):
        self.ctrl = ctrl
        self.compn = compn

    def getValue(self, *params):
        if self.routeType == 'CtrlRoute' and self.ctrl:
            return self.getter(self.ctrl)
        elif self.routeType == 'CompnRoute' and self.compn:
            return self.getter(self.compn)
        elif self.routeType == 'EventRoute' and self.compn and len(params):
            return self.getter(params[0])
        elif self.routeType == 'IndexRoute' and self.ctrl and len(params):
            return self.getter(self.ctrl, params[0])
        elif self.routeType == 'NameRoute':
            return self.getter(self.name)
        else:
            return None

    def setValue(self, value, *params):
        if self.routeType == 'CtrlRoute' and self.ctrl:
            self.setter(self.ctrl, value)
        elif self.routeType == 'CompnRoute' and self.compn:
            self.setter(value)
        elif self.routeType == 'EventRoute' and self.compn and len(params):
            self.setter(params[0], value)
        elif self.routeType == 'IndexRoute' and self.ctrl and len(params):
            self.setter(self.ctrl, params[0], value)
        elif self.routeType == 'ReApplyRoute' and self.compn and len(params):
            apply(self.setter, [self.ctrl], params)
        elif self.routeType == 'NameRoute':
            return self.setter(self.name, value)

    def getSetterName(self):
        from types import FunctionType, MethodType
        if self.setter:
            if self.setterName:
                return self.setterName
            if type(self.setter) == FunctionType:
                return self.setter.func_name
            if type(self.setter) == MethodType:
                return self.setter.im_func.func_name
            else:
                return ''
        else:
            return ''

_methodTypeCache = {}
def getPropList(obj, cmp):
    """
       Function to extract sorted list of properties and getter/setter methods
       from a given object and companion.
       Property names that also occur in the Constructor list are stored under
       the 'constructor' key
       Vetoes are dangerous methods that should not be inspected

       Returns:
       {'constructor': [ PropertyWrapper, ... ],
        'properties': [ PropertyWrapper, ... ] }

    """
    def catalogProperty(name, methType, meths, constructors, propLst, constrLst):
        if constructors.has_key(name):
            constrLst.append(PropertyWrapper(name, methType, meths[0], meths[1]))
        else:
            propLst.append(PropertyWrapper(name, methType, meths[0], meths[1]))

    #getPropList(obj, cmp):
    props = {}
    props['Properties']= {}
    props['Methods']= {}
    props['Built-ins']= {}

    # traverse inheritance hierarchy
    # populate property list
    propLst = []
    constrLst = []
    if obj and type(obj) is InstanceType:
        traverseAndBuildProps(props, cmp.vetoedMethods(), obj, obj.__class__)

        # populate property list
        if cmp:
            constrNames = cmp.constructor()
        else:
            constrNames = {}
        propNames = props['Properties'].keys()
        propNames.sort()
        for propName in propNames:
            if cmp and propName in cmp.hideDesignTime():
                continue
            propMeths = props['Properties'][propName]
            try:
                catalogProperty(propName, 'CtrlRoute', propMeths,
                  constrNames, propLst, constrLst)
            except:
                catalogProperty(propName, 'NoneRoute', (None, None),
                  constrNames, propLst, constrLst)
        if cmp:
            xtraProps = cmp.properties()
            propNames = xtraProps.keys()
            propNames.sort()
            for propName in propNames:
##                if propName in cmp.hideDesignTime():
##                    continue
                propMeths = xtraProps[propName]
                try:
                    catalogProperty(propName, propMeths[0], propMeths[1:],
                      constrNames, propLst, constrLst)
                except: pass

        propLst.sort()
        constrLst.sort()
    else :
        if cmp:
            xtraProps = cmp.properties()
            propNames = xtraProps.keys()
            propNames.sort()
            for propName in propNames:
                propMeths = xtraProps[propName]
                try:
                    catalogProperty(propName, propMeths[0], propMeths[1:],
                      constrNames, propLst, constrLst)
                except: pass
        else:
            pass #print 'Empty object', obj, cmp

    return {'constructor': constrLst, 'properties': propLst}

def getMethodType(method, obj, dict):
    """ classify methods according to prefix
        return category, property name, getter, setter
    """
    result = ('Methods', method, dict[method], dict[method])
    if (type(dict[method]) == FunctionType):
        prefix = method[:3]
        property = method[3:]

        try:
            if (method[:2] == '__'):
                result = ('Built-ins', method, dict[method], dict[method])
            elif (prefix == 'Get') and dict.has_key('Set'+property) and property:
                #see if getter breaks
                v = dict[method](obj)
                result = ('Properties', property, dict[method], dict['Set'+property])
            elif (prefix == 'Set') and dict.has_key('Get'+property) and property:
                #see if getter breaks
                v = dict['Get'+property](obj)
                result = ('Properties', property, dict['Get'+property], dict[method])
        except:
            pass
    return result

def traverseAndBuildProps(props, vetoes, obj, Class):
    for m in Class.__dict__.keys():
        if m not in vetoes:
            cat, method, methGetter, methSetter = \
              getMethodType(m, obj, Class.__dict__)
            props[cat][method] = (methGetter, methSetter)
    
    for Cls in Class.__bases__:
        traverseAndBuildProps(props, vetoes, obj, Cls)
        
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.