Python container components

From Apache OpenOffice Wiki
Jump to: navigation, search

Python container components

I have been dabbling with creating components in Python. This message is intended as an update on what I have learned and am experimenting with.

As a first experiment, here is a single python component program which implements two services.

The two new services are....

name.dannyBrewer.util.IndexContainer 
name.dannyBrewer.util.NameContainer 

Here is how you install the new component.

  • Copy the text of the following python source code.
  • Put it into a file named "DannyComponentTest2004052217.py"
  • Put the file DannyComponentTest2004052217.py into the uno_components folder of your "user" folder.

The user folder on Windows is probably the folder named "user" under your OOo installation. The user folder on Linux is contained within a folder in your home directory with a name like OpenOffice.org1.1.1. (Note on Linux, be sure that when you copy the python program that it has no carriage returns, but instead has unix linefeeds. Otherwise the component will not install properly!)

(New edit 2005-03-28: It may in fact be important now on ALL platforms to make sure that the ".py" file of python source has its line endings separated by linefeeds only with NO carriage returns!)

  • Be sure that OOo is NOT running.
  • Run the command "pkgchk" in your OOo\programs folder.

To uninstall do this....

  • Remove the DannyComponentTest2004052217.py file from your uno_components folder.
  • Be sure that OOo is NOT running.
  • Run the pkgchk command.

After installing the component, you have two new data structure services that can be instantiated from any language which can access UNO components. For instance, in OOo Basic, you can simply do...

 oItems = createUnoService( "name.dannyBrewer.util.IndexContainer" )
import unohelper 

g_ImplementationHelper = unohelper.ImplementationHelper() 


################################################################## 
class DannysUnoBaseClass: 
    cServiceName = "" 
    tServiceNames = ( cServiceName, ) 
    # stuff to support the XTypeProvider interface. 
    tInterfaceTypes = ( 
                    uno.getTypeByName( "com.sun.star.lang.XServiceName" ), 
                    uno.getTypeByName( "com.sun.star.lang.XServiceInfo" ), 
                    uno.getTypeByName( "com.sun.star.lang.XTypeProvider" ), 
                    ) 
    uuid = uno.generateUuid() 
    
    # The component must have a ctor with the component context as argument. 
    def __init__( self, oContext ): 
        self.DannysUnoBaseClass_init( oContext ) 

    def DannysUnoBaseClass_init( self, oContext ): 
        self.oContext = oContext 

        self.oCoreReflection = None 
        self.StarDesktop = None 
        self.getDesktop() 

    #---------------------------------------- 
    #   Danny's stuff to make programming less convenient. 
    #---------------------------------------- 

    def getServiceManager( self ): 
        """Get the ServiceManager from the running OpenOffice.org. 
        """ 
        return self.oContext.ServiceManager 
    
    def createUnoService( self, cClass ): 
        """A handy way to create a global objects within the running OOo. 
        """ 
        oServiceManager = self.getServiceManager() 
        oObj = oServiceManager.createInstance( cClass ) 
        return oObj 
    
    def getDesktop( self ): 
        """An easy way to obtain the Desktop object from a running OOo. 
        """ 
        if self.StarDesktop == None: 
            self.StarDesktop = self.createUnoService( "com.sun.star.frame.Desktop" ) 
        return self.StarDesktop 

    def getCoreReflection( self ): 
        if self.oCoreReflection == None: 
            self.oCoreReflection = self.createUnoService( "com.sun.star.reflection.CoreReflection" ) 
        return oCoreReflection 
    
    def createUnoStruct( self, cTypeName ): 
        """Create a UNO struct and return it. 
        """ 
        oCoreReflection = self.getCoreReflection() 

        # Get the IDL class for the type name 
        oXIdlClass = oCoreReflection.forName( cTypeName ) 

        # Create the struct. 
        oReturnValue, oStruct = oXIdlClass.createObject( None ) 

        return oStruct 

    def makePropertyValue( self, cName=None, uValue=None, nHandle=None, nState=None ): 
        """Create a com.sun.star.beans.PropertyValue struct and return it. 
        """ 
        oPropertyValue = self.createUnoStruct( "com.sun.star.beans.PropertyValue" ) 

        if cName != None: 
            oPropertyValue.Name = cName 
        if uValue != None: 
            oPropertyValue.Value = uValue 
        if nHandle != None: 
            oPropertyValue.Handle = nHandle 
        if nState != None: 
            oPropertyValue.State = nState 

        return oPropertyValue 

    #---------------------------------------- 
    #   Interface: XServiceName 
    #---------------------------------------- 

    # string 
    # getServiceName(); 
    def getServiceName( self ): 
        return self.cServiceName 

    #---------------------------------------- 
    #   Interface: XServiceInfo 
    #---------------------------------------- 

    # string 
    # getImplementationName(); 
    def getImplementationName( self ): 
        return self.cServiceName 

    # boolean 
    # supportsService( [in] string ServiceName ); 
    def supportsService( self, cServiceName ): 
        return cServiceName in self.getSupportedServiceNames() 

    # sequence< string > 
    # getSupportedServiceNames(); 
    def getSupportedServiceNames( self ): 
        return self.tServiceNames 

    #---------------------------------------- 
    #   Interface: XTypeProvider 
    #---------------------------------------- 

    # sequence< type > 
    # getTypes(); 
    def getTypes( self ): 
        #if self.tInterfaceTypes == None: 
        #    self.tInterfaceTypes = () 
        #    for cTypeName in self.tInterfaces: 
        #        self.tInterfaceTypes += ( uno.getTypeByName( cTypeName ), ) 
        return self.tInterfaceTypes 

    # sequence< byte > 
    # getImplementationId(); 
    def getImplementationId( self ): 
        return self.uuid 






################################################################## 
from com.sun.star.lang import IndexOutOfBoundsException 

class IndexContainer( DannysUnoBaseClass ): 
    cServiceName = "name.dannyBrewer.util.IndexContainer" 
    tServiceNames = ( cServiceName, ) 
    tInterfaceTypes = DannysUnoBaseClass.tInterfaceTypes + ( 
                    uno.getTypeByName( "com.sun.star.container.XIndexContainer" ), 
                    uno.getTypeByName( "com.sun.star.container.XIndexReplace" ), 
                    uno.getTypeByName( "com.sun.star.container.XIndexAccess" ), 
                    uno.getTypeByName( "com.sun.star.container.XElementAccess" ), 
                    ) 
    
    # The component must have a ctor with the component context as argument. 
    def __init__( self, oContext ): 
        # Initialize the base class! 
        self.DannysUnoBaseClass_init( oContext ) 
        # This is the list of items in the IndexContainer. 
        self.items = [] 

    #---------------------------------------- 
    #   Interface: com.sun.star.container.XIndexContainer 
    #---------------------------------------- 

    # void 
    # insertByIndex( [in] long nIndex, 
    #                [in] any uElement ); 
    def insertByIndex( self, nIndex, uElement ): 
        if nIndex < 0: 
            raise IndexOutOfBoundsException( 
                """You specified an index that was less than zero. 
                """, self ) 
        nItems = len( self.items ) 
        if nIndex > nItems: 
            raise IndexOutOfBoundsException( 
                """You specified an index that was greater than the last item in the container. 
                Since there are """ + str( nItems ) + """ items in the container, you must specify an 
                insert index that is from zero to """ + str( nItems ) + """. 
                """, self ) 
        if nIndex == nItems: 
            self.items += [uElement] 
            return 
        self.items = self.items[:nIndex] + [uElement] + self.items[nIndex:] 

    # void 
    # removeByIndex( [in] long nIndex ); 
    def removeByIndex( self, nIndex ): 
        if nIndex < 0: 
            raise IndexOutOfBoundsException( 
                """You specified an index that was less than zero. 
                """, self ) 
        nItems = len( self.items ) 
        if nIndex > nItems: 
            raise IndexOutOfBoundsException( 
                """You specified an index that was greater than or equal to the last item in the container. 
                Since there are """ + str( nItems ) + """ items in the container, you must specify an 
                insert index that is from zero to """ + str( nItems-1 ) + """. 
                """, self ) 
        self.items = self.items[:nIndex] + self.items[nIndex+1:] 
        
    #---------------------------------------- 
    #   Interface: com.sun.star.container.XIndexReplace 
    #---------------------------------------- 

    # void 
    # replaceByIndex( [in] long nIndes, 
    #                 [in] any uElement ); 
    def replaceByIndex( self, nIndex, uElement ): 
        if nIndex < 0: 
            raise IndexOutOfBoundsException( 
                """You specified an index that was less than zero. 
                """, self ) 
        nItems = len( self.items ) 
        if nIndex > nItems: 
            raise IndexOutOfBoundsException( 
                """You specified an index that was greater than or equal to the last item in the container. 
                Since there are """ + str( nItems ) + """ items in the container, you must specify an 
                insert index that is from zero to """ + str( nItems-1 ) + """. 
                """, self ) 
        self.items = self.items[:nIndex] + [uElement] + self.items[nIndex+1:] 
    
    #---------------------------------------- 
    #   Interface: com.sun.star.container.XIndexAccess 
    #---------------------------------------- 

    # long 
    # getCount(); 
    def getCount( self ): 
        return len( self.items ) 

    # any 
    # getByIndex( [in] long nIndex ); 
    def getByIndex( self, nIndex ): 
        if nIndex < 0: 
            raise IndexOutOfBoundsException( 
                """You specified an index that was less than zero. 
                """, self ) 
        nItems = len( self.items ) 
        if nIndex > nItems: 
            raise IndexOutOfBoundsException( 
                """You specified an index that was greater than or equal to the last item in the container. 
                Since there are """ + str( nItems ) + """ items in the container, you must specify an 
                insert index that is from zero to """ + str( nItems-1 ) + """. 
                """, self ) 
        return self.items[ nIndex ] 
    
    #---------------------------------------- 
    #   Interface: com.sun.star.container.XElementAccess 
    #---------------------------------------- 

    # type 
    # getElementType(); 
    def getElementType( self ): 
        return None 

    # boolean 
    # hasElements(); 
    def hasElements( self ): 
        return len( self.items ) > 0 


# Add the class to the implementation container, 
#  which the loader uses to register/instantiate the component. 
g_ImplementationHelper.addImplementation( 
        # The class 
   IndexContainer, 
        # The implementation name. 
        # Change this name for your own service. 
        IndexContainer.cServiceName, 
        # A list of services that that are implemented. 
   IndexContainer.tServiceNames, 
        ) 


################################################################## 
from com.sun.star.lang import IndexOutOfBoundsException 
from com.sun.star.container import ElementExistException 
from com.sun.star.container import NoSuchElementException 

class NameContainer( DannysUnoBaseClass ): 
    cServiceName = "name.dannyBrewer.util.NameContainer" 
    tServiceNames = ( cServiceName, ) 
    tInterfaceTypes = DannysUnoBaseClass.tInterfaceTypes + ( 
                    uno.getTypeByName( "com.sun.star.container.XNameContainer" ), 
                    uno.getTypeByName( "com.sun.star.container.XNameReplace" ), 
                    uno.getTypeByName( "com.sun.star.container.XNameAccess" ), 
                    uno.getTypeByName( "com.sun.star.container.XIndexAccess" ), 
                    uno.getTypeByName( "com.sun.star.container.XElementAccess" ), 
                    ) 
    
    # The component must have a ctor with the component context as argument. 
    def __init__( self, oContext ): 
        # Initialize the base class! 
        self.DannysUnoBaseClass_init( oContext ) 
        # This is the dictionary of items in the NameContainer. 
        self.items = {} 

    #---------------------------------------- 
    #   Interface: com.sun.star.container.XNameContainer 
    #---------------------------------------- 

    # void 
    # insertByName( [in] string cName, 
    #               [in] any uElement ); 
    def insertByName( self, cName, uElement ): 
        if cName in self.items: 
            raise ElementExistException( 
                """You specified an element name of \"""" + cName + """\" 
                which is already present in the container. 
                """, self ) 
        self.items[ cName ] = uElement 

    # void 
    # removeByName( [in] string cName ); 
    def removeByName( self, cName ): 
        if cName not in self.items: 
            raise NoSuchElementException( 
                """You specified an element name of \"""" + cName + """\" 
                which does not exist in the container. 
                """, self ) 
        del self.items[ cName ] 
        
    #---------------------------------------- 
    #   Interface: com.sun.star.container.XNameReplace 
    #---------------------------------------- 

    # void 
    # replaceByName( [in] string cName, 
    #                [in] any uElement ); 
    def replaceByName( self, cName, uElement ): 
        if cName not in self.items: 
            raise NoSuchElementException( 
                """You specified an element name of \"""" + cName + """\" 
                which does not exist in the container. 
                """, self ) 
        self.items[ cName ] = uElement 
    
    #---------------------------------------- 
    #   Interface: com.sun.star.container.XNameAccess 
    #---------------------------------------- 

    # any 
    # getByName( [in] string cName ); 
    def getByName( self, cName ): 
        if cName not in self.items: 
            raise NoSuchElementException( 
                """You specified an element name of \"""" + cName + """\" 
                which does not exist in the container. 
                """, self ) 
        return self.items[ cName ] 
    
    # boolean 
    # hasByName( [in] string cName ); 
    def hasByName( self, cName ): 
        return cName in self.items 

    # sequence< string > 
    # getElementNames(); 
    def getElementNames( self ): 
        return tuple( self.items.keys() ) 
    
    #---------------------------------------- 
    #   Interface: com.sun.star.container.XIndexAccess 
    #---------------------------------------- 

    # long 
    # getCount(); 
    def getCount( self ): 
        return len( self.items ) 

    # any 
    # getByIndex( [in] long nIndex ); 
    def getByIndex( self, nIndex ): 
        if nIndex < 0: 
            raise IndexOutOfBoundsException( 
                """You specified an index that was less than zero. 
                """, self ) 
        nItems = len( self.items ) 
        if nIndex > nItems: 
            raise IndexOutOfBoundsException( 
                """You specified an index that was greater than or equal to the last item in the container. 
                Since there are """ + str( nItems ) + """ items in the container, you must specify an 
                insert index that is from zero to """ + str( nItems-1 ) + """. 
                """, self ) 
        return self.items.values()[ nIndex ] 
    
    #---------------------------------------- 
    #   Interface: com.sun.star.container.XElementAccess 
    #---------------------------------------- 

    # type 
    # getElementType(); 
    def getElementType( self ): 
        return None 

    # boolean 
    # hasElements(); 
    def hasElements( self ): 
        return len( self.items ) > 0 


# Add the class to the implementation container, 
#  which the loader uses to register/instantiate the component. 
g_ImplementationHelper.addImplementation( 
        # The class 
   NameContainer, 
        # The implementation name. 
        # Change this name for your own service. 
        NameContainer.cServiceName, 
        # A list of services that that are implemented. 
   NameContainer.tServiceNames, 
        )

There are still some issues I am working out. I just want other interested people to be able to take my experimentation further or in different directions.

The above demonstrates several useful features.

  • Component code written in pure python.
  • Two services in one component.
  • Two components which inherit from a base class which implements some of the underlying "plumbing" machinery.
  • A way to inherit from multiple interfaces.

So why don't I just

   from com.sun.star.container import XIndexAccess

and then just make my class do....

   class IndexContainer( unohelper.Base, XIndexAccess )
Personal tools