1# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
2#
3# This file is part of the LibreOffice project.
4#
5# This Source Code Form is subject to the terms of the Mozilla Public
6# License, v. 2.0. If a copy of the MPL was not distributed with this
7# file, You can obtain one at http://mozilla.org/MPL/2.0/.
8#
9# This file incorporates work covered by the following license notice:
10#
11#   Licensed to the Apache Software Foundation (ASF) under one or more
12#   contributor license agreements. See the NOTICE file distributed
13#   with this work for additional information regarding copyright
14#   ownership. The ASF licenses this file to you under the Apache
15#   License, Version 2.0 (the "License"); you may not use this file
16#   except in compliance with the License. You may obtain a copy of
17#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18#
19import uno
20import pyuno
21import os
22import sys
23
24from com.sun.star.lang import XTypeProvider, XSingleComponentFactory, XServiceInfo
25from com.sun.star.uno import RuntimeException, XCurrentContext
26from com.sun.star.beans.MethodConcept import ALL as METHOD_CONCEPT_ALL
27from com.sun.star.beans.PropertyConcept import ALL as PROPERTY_CONCEPT_ALL
28
29from com.sun.star.reflection.ParamMode import \
30     IN as PARAM_MODE_IN, \
31     OUT as PARAM_MODE_OUT, \
32     INOUT as PARAM_MODE_INOUT
33
34from com.sun.star.beans.PropertyAttribute import \
35     MAYBEVOID as PROP_ATTR_MAYBEVOID, \
36     BOUND as PROP_ATTR_BOUND, \
37     CONSTRAINED as PROP_ATTR_CONSTRAINED, \
38     TRANSIENT as PROP_ATTR_TRANSIENT, \
39     READONLY as PROP_ATTR_READONLY, \
40     MAYBEAMBIGUOUS as PROP_ATTR_MAYBEAMBIGUOUS, \
41     MAYBEDEFAULT as PROP_ATTR_MAYBEDEFAULT, \
42     REMOVABLE as PROP_ATTR_REMOVABLE
43
44def _mode_to_str( mode ):
45    ret = "[]"
46    if mode == PARAM_MODE_INOUT:
47        ret = "[inout]"
48    elif mode == PARAM_MODE_OUT:
49        ret = "[out]"
50    elif mode == PARAM_MODE_IN:
51        ret = "[in]"
52    return ret
53
54def _propertymode_to_str( mode ):
55    ret = ""
56    if PROP_ATTR_REMOVABLE & mode:
57        ret = ret + "removable "
58    if PROP_ATTR_MAYBEDEFAULT & mode:
59        ret = ret + "maybedefault "
60    if PROP_ATTR_MAYBEAMBIGUOUS & mode:
61        ret = ret + "maybeambiguous "
62    if PROP_ATTR_READONLY & mode:
63        ret = ret + "readonly "
64    if PROP_ATTR_TRANSIENT & mode:
65        ret = ret + "transient "
66    if PROP_ATTR_CONSTRAINED & mode:
67        ret = ret + "constrained "
68    if PROP_ATTR_BOUND & mode:
69        ret = ret + "bound "
70    if PROP_ATTR_MAYBEVOID & mode:
71        ret = ret + "maybevoid "
72    return ret.rstrip()
73
74def inspect( obj , out ):
75    if isinstance( obj, uno.Type ) or \
76       isinstance( obj, uno.Char ) or \
77       isinstance( obj, uno.Bool ) or \
78       isinstance( obj, uno.ByteSequence ) or \
79       isinstance( obj, uno.Enum ) or \
80       isinstance( obj, uno.Any ):
81        out.write( str(obj) + "\n")
82        return
83
84    ctx = uno.getComponentContext()
85    introspection = \
86         ctx.ServiceManager.createInstanceWithContext( "com.sun.star.beans.Introspection", ctx )
87
88    out.write( "Supported services:\n" )
89    if hasattr( obj, "getSupportedServiceNames" ):
90        names = obj.getSupportedServiceNames()
91        for ii in names:
92            out.write( "  " + ii + "\n" )
93    else:
94        out.write( "  unknown\n" )
95
96    out.write( "Interfaces:\n" )
97    if hasattr( obj, "getTypes" ):
98        interfaces = obj.getTypes()
99        for ii in interfaces:
100            out.write( "  " + ii.typeName + "\n" )
101    else:
102        out.write( "  unknown\n" )
103
104    access = introspection.inspect( obj )
105    methods = access.getMethods( METHOD_CONCEPT_ALL )
106    out.write( "Methods:\n" )
107    for ii in methods:
108        out.write( "  " + ii.ReturnType.Name + " " + ii.Name )
109        args = ii.ParameterTypes
110        infos = ii.ParameterInfos
111        out.write( "( " )
112        for i in range( 0, len( args ) ):
113            if i > 0:
114                out.write( ", " )
115            out.write( _mode_to_str( infos[i].aMode ) + " " + args[i].Name + " " + infos[i].aName )
116        out.write( " )\n" )
117
118    props = access.getProperties( PROPERTY_CONCEPT_ALL )
119    out.write ("Properties:\n" )
120    for ii in props:
121        out.write( "  ("+_propertymode_to_str( ii.Attributes ) + ") "+ii.Type.typeName+" "+ii.Name+ "\n" )
122
123def createSingleServiceFactory( clazz, implementationName, serviceNames ):
124    return _FactoryHelper_( clazz, implementationName, serviceNames )
125
126class _ImplementationHelperEntry:
127    def __init__(self, ctor,serviceNames):
128        self.ctor = ctor
129        self.serviceNames = serviceNames
130
131class ImplementationHelper:
132    def __init__(self):
133        self.impls = {}
134
135    def addImplementation( self, ctor, implementationName, serviceNames ):
136        self.impls[implementationName] =  _ImplementationHelperEntry(ctor,serviceNames)
137
138    def writeRegistryInfo( self, regKey, smgr ):
139        for i in list(self.impls.items()):
140            keyName = "/"+ i[0] + "/UNO/SERVICES"
141            key = regKey.createKey( keyName )
142            for serviceName in i[1].serviceNames:
143                key.createKey( serviceName )
144        return 1
145
146    def getComponentFactory( self, implementationName , regKey, smgr ):
147        entry = self.impls.get( implementationName, None )
148        if entry is None:
149            raise RuntimeException( implementationName + " is unknown" , None )
150        return createSingleServiceFactory( entry.ctor, implementationName, entry.serviceNames )
151
152    def getSupportedServiceNames( self, implementationName ):
153        entry = self.impls.get( implementationName, None )
154        if entry is None:
155            raise RuntimeException( implementationName + " is unknown" , None )
156        return entry.serviceNames
157
158    def supportsService( self, implementationName, serviceName ):
159        entry = self.impls.get( implementationName,None )
160        if entry is None:
161            raise RuntimeException( implementationName + " is unknown", None )
162        return serviceName in entry.serviceNames
163
164
165class ImplementationEntry:
166    def __init__(self, implName, supportedServices, clazz ):
167        self.implName = implName
168        self.supportedServices = supportedServices
169        self.clazz = clazz
170
171def writeRegistryInfoHelper( smgr, regKey, seqEntries ):
172    for entry in seqEntries:
173        keyName = "/"+ entry.implName + "/UNO/SERVICES"
174        key = regKey.createKey( keyName )
175        for serviceName in entry.supportedServices:
176            key.createKey( serviceName )
177
178def systemPathToFileUrl( systemPath ):
179    "returns a file-url for the given system path"
180    return pyuno.systemPathToFileUrl( systemPath )
181
182def fileUrlToSystemPath( url ):
183    "returns a system path (determined by the system, the python interpreter is running on)"
184    return pyuno.fileUrlToSystemPath( url )
185
186def absolutize( path, relativeUrl ):
187    "returns an absolute file url from the given urls"
188    return pyuno.absolutize( path, relativeUrl )
189
190def getComponentFactoryHelper( implementationName, smgr, regKey, seqEntries ):
191    for x in seqEntries:
192        if x.implName == implementationName:
193            return createSingleServiceFactory( x.clazz, implementationName, x.supportedServices )
194
195def addComponentsToContext( toBeExtendedContext, contextRuntime, componentUrls, loaderName ):
196    smgr = contextRuntime.ServiceManager
197    loader = smgr.createInstanceWithContext( loaderName, contextRuntime )
198    implReg = smgr.createInstanceWithContext( "com.sun.star.registry.ImplementationRegistration",contextRuntime)
199
200    isWin = os.name == 'nt' or os.name == 'dos'
201    isMac = sys.platform == 'darwin'
202    #   create a temporary registry
203    for componentUrl in componentUrls:
204        reg = smgr.createInstanceWithContext( "com.sun.star.registry.SimpleRegistry", contextRuntime )
205        reg.open( "", 0, 1 )
206        if not isWin and componentUrl.endswith( ".uno" ):  # still allow platform independent naming
207            if isMac:
208                componentUrl = componentUrl + ".dylib"
209            else:
210                componentUrl = componentUrl + ".so"
211
212        implReg.registerImplementation( loaderName,componentUrl, reg )
213        rootKey = reg.getRootKey()
214        implementationKey = rootKey.openKey( "IMPLEMENTATIONS" )
215        implNames = implementationKey.getKeyNames()
216        extSMGR = toBeExtendedContext.ServiceManager
217        for x in implNames:
218            fac = loader.activate( max(x.split("/")),"",componentUrl,rootKey)
219            extSMGR.insert( fac )
220        reg.close()
221
222# never shrinks !
223_g_typeTable = {}
224def _unohelper_getHandle( self):
225    ret = None
226    if self.__class__ in _g_typeTable:
227        ret = _g_typeTable[self.__class__]
228    else:
229        names = {}
230        traverse = list(self.__class__.__bases__)
231        while len( traverse ) > 0:
232            item = traverse.pop()
233            bases = item.__bases__
234            if uno.isInterface( item ):
235                names[item.__pyunointerface__] = None
236            elif len(bases) > 0:
237                # the "else if", because we only need the most derived interface
238                traverse = traverse + list(bases)#
239
240        lst = list(names.keys())
241        types = []
242        for x in lst:
243            t = uno.getTypeByName( x )
244            types.append( t )
245
246        ret = tuple(types)
247        _g_typeTable[self.__class__] = ret
248    return ret
249
250class Base(XTypeProvider):
251    def getTypes( self ):
252        return _unohelper_getHandle( self )
253    def getImplementationId(self):
254        return ()
255
256class CurrentContext(XCurrentContext, Base ):
257    """a current context implementation, which first does a lookup in the given
258       hashmap and if the key cannot be found, it delegates to the predecessor
259       if available
260    """
261    def __init__( self, oldContext, hashMap ):
262        self.hashMap = hashMap
263        self.oldContext = oldContext
264
265    def getValueByName( self, name ):
266        if name in self.hashMap:
267            return self.hashMap[name]
268        elif self.oldContext is not None:
269            return self.oldContext.getValueByName( name )
270        else:
271            return None
272
273# -------------------------------------------------
274# implementation details
275# -------------------------------------------------
276class _FactoryHelper_( XSingleComponentFactory, XServiceInfo, Base ):
277    def __init__( self, clazz, implementationName, serviceNames ):
278        self.clazz = clazz
279        self.implementationName = implementationName
280        self.serviceNames = serviceNames
281
282    def getImplementationName( self ):
283        return self.implementationName
284
285    def supportsService( self, ServiceName ):
286        return ServiceName in self.serviceNames
287
288    def getSupportedServiceNames( self ):
289        return self.serviceNames
290
291    def createInstanceWithContext( self, context ):
292        return self.clazz( context )
293
294    def createInstanceWithArgumentsAndContext( self, args, context ):
295        return self.clazz( context, *args )
296
297# vim: set shiftwidth=4 softtabstop=4 expandtab:
298