xref: /trunk/main/scripting/source/pyprov/pythonscript.py (revision 7686e66c7a7e4c93b95d81d0d636b7da9d226718)
1# *************************************************************
2#
3#  Licensed to the Apache Software Foundation (ASF) under one
4#  or more contributor license agreements.  See the NOTICE file
5#  distributed with this work for additional information
6#  regarding copyright ownership.  The ASF licenses this file
7#  to you under the Apache License, Version 2.0 (the
8#  "License"); you may not use this file except in compliance
9#  with the License.  You may obtain a copy of the License at
10#
11#    http://www.apache.org/licenses/LICENSE-2.0
12#
13#  Unless required by applicable law or agreed to in writing,
14#  software distributed under the License is distributed on an
15#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16#  KIND, either express or implied.  See the License for the
17#  specific language governing permissions and limitations
18#  under the License.
19#
20# *************************************************************
21
22# XScript implementation for python
23import uno
24import unohelper
25import sys
26import os
27import imp
28import time
29import ast
30
31try:
32    unicode
33except NameError:
34    unicode = str
35
36class LogLevel:
37    NONE = 0   # production level
38    ERROR = 1  # for script developers
39    DEBUG = 2  # for script framework developers
40
41PYSCRIPT_LOG_ENV = "PYSCRIPT_LOG_LEVEL"
42PYSCRIPT_LOG_STDOUT_ENV = "PYSCRIPT_LOG_STDOUT"
43
44# Configuration ----------------------------------------------------
45LogLevel.use = LogLevel.NONE
46if os.environ.get(PYSCRIPT_LOG_ENV) == "ERROR":
47    LogLevel.use = LogLevel.ERROR
48elif os.environ.get(PYSCRIPT_LOG_ENV) == "DEBUG":
49    LogLevel.use = LogLevel.DEBUG
50
51# True, writes to stdout (difficult on windows)
52# False, writes to user/Scripts/python/log.txt
53LOG_STDOUT = os.environ.get(PYSCRIPT_LOG_STDOUT_ENV, "1") != "0"
54
55ENABLE_EDIT_DIALOG=False                    # offers a minimal editor for editing.
56#-------------------------------------------------------------------
57
58def encfile(uni):
59    if sys.version_info[0] > 2:
60        return uni
61    else:
62        return uni.encode( sys.getfilesystemencoding())
63
64def lastException2String():
65    (excType,excInstance,excTraceback) = sys.exc_info()
66    ret = str(excType) + ": "+str(excInstance) + "\n" + \
67          uno._uno_extract_printable_stacktrace( excTraceback )
68    return ret
69
70def logLevel2String( level ):
71    ret = " NONE"
72    if level == LogLevel.ERROR:
73        ret = "ERROR"
74    elif level >= LogLevel.DEBUG:
75        ret = "DEBUG"
76    return ret
77
78def getLogTarget():
79    ret = sys.stdout
80    if not LOG_STDOUT:
81        try:
82            pathSubst = uno.getComponentContext().ServiceManager.createInstance(
83                "com.sun.star.util.PathSubstitution" )
84            userInstallation =  pathSubst.getSubstituteVariableValue( "user" )
85            if len( userInstallation ) > 0:
86                systemPath = uno.fileUrlToSystemPath( userInstallation + "/Scripts/python/log.txt" )
87                ret = open( systemPath , "a" )
88        except Exception as e:
89            print("Exception during creation of pythonscript logfile: "+ lastException2String() + "\n, delagating log to stdout\n")
90    return ret
91
92class Logger(LogLevel):
93    def __init__(self , target ):
94        self.target = target
95
96    def isDebugLevel( self ):
97        return self.use >= self.DEBUG
98
99    def debug( self, msg ):
100        if self.isDebugLevel():
101            self.log( self.DEBUG, msg )
102
103    def isErrorLevel( self ):
104        return self.use >= self.ERROR
105
106    def error( self, msg ):
107        if self.isErrorLevel():
108            self.log( self.ERROR, msg )
109
110    def log( self, level, msg ):
111        if self.use >= level:
112            try:
113                self.target.write(
114                    time.asctime() +
115                    " [" +
116                    logLevel2String( level ) +
117                    "] " +
118                    encfile(msg) +
119                    "\n" )
120                self.target.flush()
121            except Exception as e:
122                print("Error during writing to stdout: " +lastException2String() + "\n")
123
124log = Logger( getLogTarget() )
125
126log.debug( "pythonscript loading" )
127
128#from com.sun.star.lang import typeOfXServiceInfo, typeOfXTypeProvider
129from com.sun.star.uno import RuntimeException
130from com.sun.star.lang import XServiceInfo
131from com.sun.star.io import IOException, XInputStream
132from com.sun.star.ucb import CommandAbortedException, XCommandEnvironment, XProgressHandler, Command
133from com.sun.star.task import XInteractionHandler
134from com.sun.star.beans import XPropertySet, Property
135from com.sun.star.container import XNameContainer
136from com.sun.star.xml.sax import XDocumentHandler, InputSource
137from com.sun.star.uno import Exception as UnoException
138from com.sun.star.script import XInvocation
139from com.sun.star.awt import XActionListener
140
141from com.sun.star.script.provider import XScriptProvider, XScript, XScriptContext, ScriptFrameworkErrorException
142from com.sun.star.script.browse import XBrowseNode
143from com.sun.star.script.browse.BrowseNodeTypes import SCRIPT, CONTAINER, ROOT
144from com.sun.star.util import XModifyListener
145
146LANGUAGENAME = "Python"
147GLOBAL_SCRIPTCONTEXT_NAME = "XSCRIPTCONTEXT"
148CALLABLE_CONTAINER_NAME =  "g_exportedScripts"
149
150# pythonloader looks for a static g_ImplementationHelper variable
151g_ImplementationHelper = unohelper.ImplementationHelper()
152g_implName = "org.openoffice.pyuno.LanguageScriptProviderFor"+LANGUAGENAME
153
154
155
156BLOCK_SIZE = 65536
157def readTextFromStream( inputStream ):
158    # read the file
159    code = uno.ByteSequence( b"" )
160    while True:
161        read,out = inputStream.readBytes( None , BLOCK_SIZE )
162        code = code + out
163        if read < BLOCK_SIZE:
164            break
165    if sys.version_info[0] > 2:
166        return str( code.value, 'utf-8' )
167    else:
168        return code.value
169
170def toIniName( str ):
171    # TODO: what is the official way to get to know whether i am on the windows platform ?
172    if( hasattr(sys , "dllhandle") ):
173        return str + ".ini"
174    return str + "rc"
175
176class EmptyInputStream( unohelper.Base, XInputStream ):
177      def __init__( self ):
178          pass
179
180      def closeInput(self):
181          pass
182
183      def readBytes( self, seq, n ):
184          return 0, ""
185
186      def readSomeBytes( self, seq, n ):
187          return 0, ""
188
189      def skipBytes( self, n ):
190          pass
191
192      def available( self ):
193          return 0
194
195
196""" definition: storageURI is the system dependent, absolute file url, where the script is stored on disk
197                scriptURI is the system independent uri
198"""
199class MyUriHelper:
200
201    def __init__( self, ctx, location ):
202        self.s_UriMap = \
203        { "share" : "vnd.sun.star.expand:${$OOO_BASE_DIR/program/" +  toIniName( "bootstrap") + "::BaseInstallation}/share/Scripts/python" , \
204          "share:uno_packages" : "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/uno_packages", \
205          "user" : "vnd.sun.star.expand:${$OOO_BASE_DIR/program/" + toIniName( "bootstrap") + "::UserInstallation}/user/Scripts/python" , \
206          "user:uno_packages" : "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages" }
207        self.m_uriRefFac = ctx.ServiceManager.createInstanceWithContext("com.sun.star.uri.UriReferenceFactory",ctx)
208        if location.startswith( "vnd.sun.star.tdoc" ):
209            self.m_baseUri = location + "/Scripts/python"
210            self.m_scriptUriLocation = "document"
211        else:
212            self.m_baseUri = expandUri( self.s_UriMap[location] )
213            self.m_scriptUriLocation = location
214        log.debug( "initialized urihelper with baseUri="+self.m_baseUri + ",m_scriptUriLocation="+self.m_scriptUriLocation )
215
216    def getRootStorageURI( self ):
217        return self.m_baseUri
218
219    def getStorageURI( self, scriptURI ):
220        return self.scriptURI2StorageUri(scriptURI)
221
222    def getScriptURI( self, storageURI ):
223        return self.storageURI2ScriptUri(storageURI)
224
225    def storageURI2ScriptUri( self, storageURI ):
226        if not storageURI.startswith( self.m_baseUri ):
227            message = "pythonscript: storage uri '" + storageURI + "' not in base uri '" + self.m_baseUri + "'"
228            log.debug( message )
229            raise RuntimeException( message )
230
231        ret = "vnd.sun.star.script:" + \
232              storageURI[len(self.m_baseUri)+1:].replace("/","|") + \
233              "?language=" + LANGUAGENAME + "&location=" + self.m_scriptUriLocation
234        log.debug( "converting storageURI="+storageURI + " to scriptURI=" + ret )
235        return ret
236
237    def scriptURI2StorageUri( self, scriptURI ):
238        try:
239            myUri = self.m_uriRefFac.parse(scriptURI)
240            ret = self.m_baseUri + "/" + myUri.getName().replace( "|", "/" )
241            log.debug( "converting scriptURI="+scriptURI + " to storageURI=" + ret )
242            return ret
243        except UnoException as e:
244            log.error( "error during converting scriptURI="+scriptURI + ": " + e.Message)
245            raise RuntimeException( "pythonscript:scriptURI2StorageUri: " +e.getMessage(), None )
246        except Exception as e:
247            log.error( "error during converting scriptURI="+scriptURI + ": " + str(e))
248            raise RuntimeException( "pythonscript:scriptURI2StorageUri: " + str(e), None )
249
250
251class ModuleEntry:
252    def __init__( self, lastRead, module ):
253        self.lastRead = lastRead
254        self.module = module
255
256def hasChanged( oldDate, newDate ):
257    return newDate.Year > oldDate.Year or \
258           newDate.Month > oldDate.Month or \
259           newDate.Day > oldDate.Day or \
260           newDate.Hours > oldDate.Hours or \
261           newDate.Minutes > oldDate.Minutes or \
262           newDate.Seconds > oldDate.Seconds or \
263           newDate.HundredthSeconds > oldDate.HundredthSeconds
264
265def ensureSourceState( code ):
266    if not code.endswith( "\n" ):
267        code = code + "\n"
268    code = code.replace( "\r", "" )
269    return code
270
271
272def checkForPythonPathBesideScript( url ):
273    if url.startswith( "file:" ):
274        path = unohelper.fileUrlToSystemPath( url+"/pythonpath.zip" );
275        log.log( LogLevel.DEBUG,  "checking for existence of " + path )
276        if 1 == os.access( encfile(path), os.F_OK) and not path in sys.path:
277            log.log( LogLevel.DEBUG, "adding " + path + " to sys.path" )
278            sys.path.append( path )
279
280        path = unohelper.fileUrlToSystemPath( url+"/pythonpath" );
281        log.log( LogLevel.DEBUG,  "checking for existence of " + path )
282        if 1 == os.access( encfile(path), os.F_OK) and not path in sys.path:
283            log.log( LogLevel.DEBUG, "adding " + path + " to sys.path" )
284            sys.path.append( path )
285
286
287class ScriptContext(unohelper.Base):
288    def __init__( self, ctx, doc, inv ):
289        self.ctx = ctx
290        self.doc = doc
291        self.inv = inv
292
293   # XScriptContext
294    def getDocument(self):
295        if self.doc:
296            return self.doc
297        return self.getDesktop().getCurrentComponent()
298
299    def getDesktop(self):
300        return self.ctx.ServiceManager.createInstanceWithContext(
301            "com.sun.star.frame.Desktop", self.ctx )
302
303    def getComponentContext(self):
304        return self.ctx
305
306    def getInvocationContext(self):
307        return self.inv
308
309#----------------------------------
310# Global Module Administration
311# does not fit together with script
312# engine lifetime management
313#----------------------------------
314#g_scriptContext = ScriptContext( uno.getComponentContext(), None )
315#g_modules = {}
316#def getModuleByUrl( url, sfa ):
317#    entry =  g_modules.get(url)
318#    load = True
319#    lastRead = sfa.getDateTimeModified( url )
320#    if entry:
321#        if hasChanged( entry.lastRead, lastRead ):
322#            log.debug("file " + url + " has changed, reloading")
323#        else:
324#            load = False
325#
326#    if load:
327#        log.debug( "opening >" + url + "<" )
328#
329#        code = readTextFromStream( sfa.openFileRead( url ) )
330
331        # execute the module
332#        entry = ModuleEntry( lastRead, imp.new_module("ooo_script_framework") )
333#        entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = g_scriptContext
334#        entry.module.__file__ = url
335#        exec code in entry.module.__dict__
336#        g_modules[ url ] = entry
337#        log.debug( "mapped " + url + " to " + str( entry.module ) )
338#    return entry.module
339
340class ProviderContext:
341    def __init__( self, storageType, sfa, uriHelper, scriptContext ):
342        self.storageType = storageType
343        self.sfa = sfa
344        self.uriHelper = uriHelper
345        self.scriptContext = scriptContext
346        self.modules = {}
347        self.rootUrl = None
348        self.mapPackageName2Path = None
349
350    def getTransientPartFromUrl( self, url ):
351        rest = url.replace( self.rootUrl , "",1 ).replace( "/","",1)
352        return rest[0:rest.find("/")]
353
354    def getPackageNameFromUrl( self, url ):
355        rest = url.replace( self.rootUrl , "",1 ).replace( "/","",1)
356        start = rest.find("/") +1
357        return rest[start:rest.find("/",start)]
358
359
360    def removePackageByUrl( self, url ):
361        items = list(self.mapPackageName2Path.items())
362        for i in items:
363            if url in i[1].pathes:
364                self.mapPackageName2Path.pop(i[0])
365                break
366
367    def addPackageByUrl( self, url ):
368        packageName = self.getPackageNameFromUrl( url )
369        transientPart = self.getTransientPartFromUrl( url )
370        log.debug( "addPackageByUrl : " + packageName + ", " + transientPart + "("+url+")" + ", rootUrl="+self.rootUrl )
371        if packageName in self.mapPackageName2Path:
372            package = self.mapPackageName2Path[ packageName ]
373            package.pathes = package.pathes + (url, )
374        else:
375            package = Package( (url,), transientPart)
376            self.mapPackageName2Path[ packageName ] = package
377
378    def isUrlInPackage( self, url ):
379        values = list(self.mapPackageName2Path.values())
380        for i in values:
381#           print "checking " + url + " in " + str(i.pathes)
382            if url in i.pathes:
383                return True
384#        print "false"
385        return False
386
387    def setPackageAttributes( self, mapPackageName2Path, rootUrl ):
388        self.mapPackageName2Path = mapPackageName2Path
389        self.rootUrl = rootUrl
390
391    def getPersistentUrlFromStorageUrl( self, url ):
392        # package name is the second directory
393        ret = url
394        if self.rootUrl:
395            pos = len( self.rootUrl) +1
396            ret = url[0:pos]+url[url.find("/",pos)+1:len(url)]
397        log.debug( "getPersistentUrlFromStorageUrl " + url +  " -> "+ ret)
398        return ret
399
400    def getStorageUrlFromPersistentUrl( self, url):
401        ret = url
402        if self.rootUrl:
403            pos = len(self.rootUrl)+1
404            packageName = url[pos:url.find("/",pos+1)]
405            package = self.mapPackageName2Path[ packageName ]
406            ret = url[0:pos]+ package.transientPathElement + "/" + url[pos:len(url)]
407        log.debug( "getStorageUrlFromPersistentUrl " + url + " -> "+ ret)
408        return ret
409
410    def getFuncsByUrl( self, url ):
411        src = readTextFromStream( self.sfa.openFileRead( url ) )
412        checkForPythonPathBesideScript( url[0:url.rfind('/')] )
413        src = ensureSourceState( src )
414
415        allFuncs = []
416        g_exportedScripts = []
417
418        a = ast.parse(src, url)
419
420        if isinstance(a, ast.Module):
421            for node in a.body:
422                if isinstance(node, ast.FunctionDef):
423                    allFuncs.append(node.name)
424                elif isinstance(node, ast.Assign):
425                    is_exported = False
426                    for subnode in node.targets:
427                        if isinstance(subnode, ast.Name) and \
428                            subnode.id == "g_exportedScripts":
429                            is_exported = True
430                            break
431                    if is_exported:
432                        value_node = node.value
433                        if isinstance(value_node, ast.List) or \
434                            isinstance(value_node, ast.Tuple):
435                            for elt in value_node.elts:
436                                if isinstance(elt, ast.Str):
437                                    g_exportedScripts.append(elt.s)
438                                elif isinstance(elt, ast.Name):
439                                    g_exportedScripts.append(elt.id)
440                        elif isinstance(value_node, ast.Str):
441                            g_exportedScripts.append(value_node.s)
442                        elif isinstance(value_node, ast.Name):
443                            g_exportedScripts.append(value_node.id)
444                        return g_exportedScripts
445        return allFuncs
446
447    def getModuleByUrl( self, url ):
448        entry =  self.modules.get(url)
449        load = True
450        lastRead = self.sfa.getDateTimeModified( url )
451        if entry:
452            if hasChanged( entry.lastRead, lastRead ):
453                log.debug( "file " + url + " has changed, reloading" )
454            else:
455                load = False
456
457        if load:
458            log.debug( "opening >" + url + "<" )
459
460            src = readTextFromStream( self.sfa.openFileRead( url ) )
461            checkForPythonPathBesideScript( url[0:url.rfind('/')] )
462            src = ensureSourceState( src )
463
464            # execute the module
465            entry = ModuleEntry( lastRead, imp.new_module("ooo_script_framework") )
466            entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = self.scriptContext
467
468            code = None
469            if url.startswith( "file:" ):
470                code = compile( src, encfile(uno.fileUrlToSystemPath( url ) ), "exec" )
471            else:
472                code = compile( src, url, "exec" )
473            exec(code, entry.module.__dict__)
474            entry.module.__file__ = url
475            self.modules[ url ] = entry
476            log.debug( "mapped " + url + " to " + str( entry.module ) )
477        return  entry.module
478
479#--------------------------------------------------
480def isScript( candidate ):
481    ret = False
482    if isinstance( candidate, type(isScript) ):
483        ret = True
484    return ret
485
486#-------------------------------------------------------
487class ScriptBrowseNode( unohelper.Base, XBrowseNode , XPropertySet, XInvocation, XActionListener ):
488    def __init__( self, provCtx, parent, fileName, funcName ):
489        self.parent = parent
490        self.fileName = fileName
491        self.funcName = funcName
492        self.provCtx = provCtx
493
494    def uri( self ):
495        return self.parent.uri()
496
497    def getName( self ):
498        return self.funcName
499
500    def getChildNodes(self):
501        return ()
502
503    def hasChildNodes(self):
504        return False
505
506    def getType( self):
507        return SCRIPT
508
509    def getPropertyValue( self, name ):
510        ret = None
511        try:
512            if name == "URI":
513                ret = self.provCtx.uriHelper.getScriptURI(
514                    self.provCtx.getPersistentUrlFromStorageUrl( self.uri() + "$" + self.funcName ) )
515            elif name == "Editable" and ENABLE_EDIT_DIALOG:
516                ret = not self.provCtx.sfa.isReadOnly( self.uri() )
517
518            log.debug( "ScriptBrowseNode.getPropertyValue called for " + name + ", returning " + str(ret) )
519        except Exception as e:
520            log.error( "ScriptBrowseNode.getPropertyValue error " + lastException2String())
521            raise
522
523        return ret
524    def setPropertyValue( self, name, value ):
525        log.debug( "ScriptBrowseNode.setPropertyValue called " + name + "=" +str(value ) )
526    def getPropertySetInfo( self ):
527        log.debug( "ScriptBrowseNode.getPropertySetInfo called "  )
528        return None
529
530    def getIntrospection( self ):
531        return None
532
533    def invoke( self, name, params, outparamindex, outparams ):
534        if name == "Editable":
535            servicename = "com.sun.star.awt.DialogProvider"
536            ctx = self.provCtx.scriptContext.getComponentContext()
537            dlgprov = ctx.ServiceManager.createInstanceWithContext(
538                servicename, ctx )
539
540            self.editor = dlgprov.createDialog(
541                "vnd.sun.star.script:" +
542                "ScriptBindingLibrary.MacroEditor?location=application")
543
544            code = readTextFromStream(self.provCtx.sfa.openFileRead(self.uri()))
545            code = ensureSourceState( code )
546            self.editor.getControl("EditorTextField").setText(code)
547
548            self.editor.getControl("RunButton").setActionCommand("Run")
549            self.editor.getControl("RunButton").addActionListener(self)
550            self.editor.getControl("SaveButton").setActionCommand("Save")
551            self.editor.getControl("SaveButton").addActionListener(self)
552
553            self.editor.execute()
554
555        return None, (), ()
556
557    def actionPerformed( self, event ):
558        try:
559            if event.ActionCommand == "Run":
560                code = self.editor.getControl("EditorTextField").getText()
561                code = ensureSourceState( code )
562                mod = imp.new_module("ooo_script_framework")
563                mod.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = self.provCtx.scriptContext
564                exec(code, mod.__dict__)
565                values = mod.__dict__.get( CALLABLE_CONTAINER_NAME , None )
566                if not values:
567                    values = list(mod.__dict__.values())
568
569                for i in values:
570                    if isScript( i ):
571                        i()
572                        break
573
574            elif event.ActionCommand == "Save":
575                toWrite = uno.ByteSequence(
576                    str(
577                    self.editor.getControl("EditorTextField").getText().encode(
578                    sys.getdefaultencoding())) )
579                copyUrl = self.uri() + ".orig"
580                self.provCtx.sfa.move( self.uri(), copyUrl )
581                out = self.provCtx.sfa.openFileWrite( self.uri() )
582                out.writeBytes( toWrite )
583                out.close()
584                self.provCtx.sfa.kill( copyUrl )
585#                log.debug("Save is not implemented yet")
586#                text = self.editor.getControl("EditorTextField").getText()
587#                log.debug("Would save: " + text)
588        except Exception as e:
589            # TODO: add an error box here !
590            log.error( lastException2String() )
591
592
593    def setValue( self, name, value ):
594        return None
595
596    def getValue( self, name ):
597        return None
598
599    def hasMethod( self, name ):
600        return False
601
602    def hasProperty( self, name ):
603        return False
604
605
606#-------------------------------------------------------
607class FileBrowseNode( unohelper.Base, XBrowseNode, XPropertySet, XInvocation ):
608    def __init__( self, provCtx, parent, name ):
609        self.provCtx = provCtx
610        self.parent = parent
611        self.name = name
612        self.funcnames = None
613
614    def uri( self ):
615        return self.parent.rootUrl + "/" + self.name + ".py"
616
617    def getName( self ):
618        return self.name
619
620    def getChildNodes(self):
621        ret = ()
622        try:
623            self.funcnames = self.provCtx.getFuncsByUrl( self.uri() )
624
625            scriptNodeList = []
626            for i in self.funcnames:
627                scriptNodeList.append(
628                    ScriptBrowseNode(
629                    self.provCtx, self, self.name, i ))
630            ret = tuple( scriptNodeList )
631        except Exception as e:
632            text = lastException2String()
633            log.error( "FileBrowseNode.getChildNodes error while evaluating " + self.uri() + ":" + text )
634            raise
635        return ret
636
637    def hasChildNodes(self):
638        try:
639            return len(self.getChildNodes()) > 0
640        except Exception as e:
641            return False
642
643    def getType( self):
644        return CONTAINER
645
646    # XPropertySet
647
648    def getPropertyValue( self, name ):
649        ret = None
650        try:
651            if name == "Editable":
652                ret = not self.provCtx.sfa.isReadOnly( self.uri() )
653            elif name == "Deletable":
654                ret = not self.provCtx.sfa.isReadOnly( self.uri() )
655            elif name == "Renamable":
656                ret = not self.provCtx.sfa.isReadOnly( self.uri() )
657
658            log.debug( "FileBrowseNode.getPropertyValue called for " + name + ", returning " + str(ret) )
659        except Exception as e:
660            log.error( "FileBrowseNode.getPropertyValue error " + lastException2String())
661            raise
662
663        return ret
664
665    def setPropertyValue( self, name, value ):
666        log.debug( "FileBrowseNode.setPropertyValue called " + name + "=" +str(value ) )
667
668    def getPropertySetInfo( self ):
669        log.debug( "FileBrowseNode.getPropertySetInfo called "  )
670        return None
671
672    # XInvocation
673
674    def getIntrospection( self ):
675        log.debug( "FileBrowseNode.getIntrospection() called" )
676        return None
677
678    def invoke( self, name, params, outparamindex, outparams ):
679        log.debug("FileBrowseNode.invoke called for " + name + "," + str(params) + "," + str(outparamindex) + "," + str(outparams))
680        try:
681            if name == "Editable":
682                log.error("Editable not implemented")
683            elif name == "Deletable":
684                self.provCtx.sfa.kill( self.uri() )
685                return True, (), ()
686            elif name == "Renamable":
687                if params is None or not params:
688                    raise IllegalArgumentException( "invoke with Creatable needs the name in params" )
689                newUri = self.parent.rootUrl + "/" + params[0] + ".py"
690                self.provCtx.sfa.move( self.uri(), newUri )
691                self.name = params[0]
692                return self, (), ()
693        except Exception as e:
694            log.error( "FileBrowseNode.invoke error " + lastException2String() )
695            raise
696        return None, (), ()
697
698    def setValue( self, name, value ):
699        return None
700
701    def getValue( self, name ):
702        log.debug( "FileBrowseNode.getValue() called" )
703        return None
704
705    def hasMethod( self, name ):
706        return False
707
708    def hasProperty( self, name ):
709        return False
710
711
712class DirBrowseNode( unohelper.Base, XBrowseNode, XPropertySet, XInvocation ):
713    def __init__( self, provCtx, name, rootUrl, depth ):
714        self.provCtx = provCtx
715        self.name = name
716        self.rootUrl = rootUrl
717        self.depth = depth
718        log.debug( "DirBrowseNode constructor for " + name + "," + rootUrl )
719
720    def getName( self ):
721        return self.name
722
723    def getChildNodes( self ):
724        try:
725            log.debug( "DirBrowseNode.getChildNodes called for " + self.rootUrl )
726            contents = self.provCtx.sfa.getFolderContents( self.rootUrl, True )
727            browseNodeList = []
728            for i in contents:
729                if i.endswith( ".py" ):
730                    log.debug( "adding filenode " + i )
731                    browseNodeList.append(
732                        FileBrowseNode( self.provCtx, self, i[i.rfind("/")+1:len(i)-3] ) )
733                elif self.provCtx.sfa.isFolder( i ) and not i.endswith("/pythonpath"):
734                    log.debug( "adding DirBrowseNode " + i )
735                    browseNodeList.append(
736                        DirBrowseNode( self.provCtx, i[i.rfind("/")+1:len(i)], i, self.depth + 1 ) )
737            return tuple( browseNodeList )
738        except Exception as e:
739            text = lastException2String()
740            log.error( "DirBrowseNode error: " + str(e) + " while evaluating " + self.rootUrl)
741            log.error( text)
742            return ()
743
744    def hasChildNodes( self ):
745        return True
746
747    def getType( self ):
748        return CONTAINER
749
750    # XScriptProvider
751
752    def getScript( self, uri ):
753        log.debug( "DirBrowseNode getScript " + uri + " invoked" )
754        raise IllegalArgumentException( "DirBrowseNode couldn't instantiate script " + uri , self , 0 )
755
756    # XPropertySet
757
758    def getPropertyValue( self, name ):
759        ret = None
760        try:
761            if name == "Creatable":
762                ret = True
763            elif name == "Deletable":
764                ret = self.depth > 0 and not self.provCtx.sfa.isReadOnly( self.rootUrl )
765            elif name == "Renamable":
766                ret = self.depth > 0 and not self.provCtx.sfa.isReadOnly( self.rootUrl )
767
768            log.debug( "DirBrowseNode.getPropertyValue called for " + name + ", returning " + str(ret) )
769        except Exception as e:
770            log.error( "DirBrowseNode.getPropertyValue error " + lastException2String())
771            raise
772
773        return ret
774
775    def setPropertyValue( self, name, value ):
776        log.debug( "DirBrowseNode.setPropertyValue called " + name + "=" +str(value ) )
777
778    def getPropertySetInfo( self ):
779        log.debug( "DirBrowseNode.getPropertySetInfo called "  )
780        return None
781
782    # XInvocation
783
784    def getIntrospection( self ):
785        log.debug( "DirBrowseNode.getIntrospection() called" )
786        return None
787
788    def invoke( self, name, params, outparamindex, outparams ):
789        log.debug("DirBrowseNode.invoke called for " + name + "," + str(params) + "," + str(outparamindex) + "," + str(outparams))
790        try:
791            if name == "Creatable":
792                if params is None or not params:
793                    raise IllegalArgumentException( "invoke with Creatable needs the name in params" )
794                if self.depth == 0:
795                    subFolderUrl = self.rootUrl + "/" + params[0]
796                    self.provCtx.sfa.createFolder( subFolderUrl )
797                    childNode = DirBrowseNode( self.provCtx, subFolderUrl[subFolderUrl.rfind("/")+1:len(subFolderUrl)], subFolderUrl, self.depth + 1 )
798                    return childNode, (), ()
799                else:
800                    scriptUrl = self.rootUrl + "/" + params[0] + ".py"
801                    # Creates an empty file
802                    self.provCtx.sfa.writeFile( scriptUrl, EmptyInputStream() )
803                    childNode = FileBrowseNode( self.provCtx, self, params[0] )
804                    return childNode, (), ()
805            elif name == "Deletable":
806                self.provCtx.sfa.kill( self.rootUrl )
807                return True, (), ()
808            elif name == "Renamable":
809                if params is None or not params:
810                    raise IllegalArgumentException( "invoke with Renamable needs the name in params" )
811                newUrl = self.rootUrl[0:self.rootUrl.rfind("/")+1] + params[0]
812                self.provCtx.sfa.move( self.rootUrl, newUrl )
813                self.rootUrl = newUrl
814                self.name = params[0]
815                return self, (), ()
816        except Exception as e:
817            log.error( "DirBrowseNode.invoke error: " + lastException2String())
818            raise
819        return None, (), ()
820
821    def setValue( self, name, value ):
822        return None
823
824    def getValue( self, name ):
825        log.debug( "DirBrowseNode.getValue() called" )
826        return None
827
828    def hasMethod( self, name ):
829        return False
830
831    def hasProperty( self, name ):
832        return False
833
834
835class ManifestHandler( XDocumentHandler, unohelper.Base ):
836    def __init__( self, rootUrl ):
837        self.rootUrl = rootUrl
838
839    def startDocument( self ):
840        self.urlList = []
841
842    def endDocument( self ):
843        pass
844
845    def startElement( self , name, attlist):
846        if name == "manifest:file-entry":
847            if attlist.getValueByName( "manifest:media-type" ) == "application/vnd.sun.star.framework-script":
848                self.urlList.append(
849                    self.rootUrl + "/" + attlist.getValueByName( "manifest:full-path" ) )
850
851    def endElement( self, name ):
852        pass
853
854    def characters ( self, chars ):
855        pass
856
857    def ignoreableWhitespace( self, chars ):
858        pass
859
860    def setDocumentLocator( self, locator ):
861        pass
862
863def isPyFileInPath( sfa, path ):
864    ret = False
865    contents = sfa.getFolderContents( path, True )
866    for i in contents:
867        if sfa.isFolder(i):
868            ret = isPyFileInPath(sfa,i)
869        else:
870            if i.endswith(".py"):
871                ret = True
872        if ret:
873            break
874    return ret
875
876# extracts META-INF directory from
877def getPathesFromPackage( rootUrl, sfa ):
878    ret = ()
879    try:
880        fileUrl = rootUrl + "/META-INF/manifest.xml"
881        inputStream = sfa.openFileRead( fileUrl )
882        parser = uno.getComponentContext().ServiceManager.createInstance( "com.sun.star.xml.sax.Parser" )
883        handler = ManifestHandler( rootUrl )
884        parser.setDocumentHandler( handler )
885        parser.parseStream( InputSource( inputStream , "", fileUrl, fileUrl ) )
886        for i in tuple(handler.urlList):
887            if not isPyFileInPath( sfa, i ):
888                handler.urlList.remove(i)
889        ret = tuple( handler.urlList )
890    except UnoException as e:
891        text = lastException2String()
892        log.debug( "getPathesFromPackage " + fileUrl + " Exception: " +text )
893        pass
894    return ret
895
896
897class Package:
898    def __init__( self, pathes, transientPathElement ):
899        self.pathes = pathes
900        self.transientPathElement = transientPathElement
901
902class DummyInteractionHandler( unohelper.Base, XInteractionHandler ):
903    def __init__( self ):
904        pass
905    def handle( self, event):
906        log.debug( "pythonscript: DummyInteractionHandler.handle " + str( event ) )
907
908class DummyProgressHandler( unohelper.Base, XProgressHandler ):
909    def __init__( self ):
910        pass
911
912    def push( self,status ):
913        log.debug( "pythonscript: DummyProgressHandler.push " + str( status ) )
914    def update( self,status ):
915        log.debug( "pythonscript: DummyProgressHandler.update " + str( status ) )
916    def pop( self ):
917        log.debug( "pythonscript: DummyProgressHandler.push " + str( event ) )
918
919class CommandEnvironment(unohelper.Base, XCommandEnvironment):
920    def __init__( self ):
921        self.progressHandler = DummyProgressHandler()
922        self.interactionHandler = DummyInteractionHandler()
923    def getInteractionHandler( self ):
924        return self.interactionHandler
925    def getProgressHandler( self ):
926        return self.progressHandler
927
928#maybe useful for debugging purposes
929#class ModifyListener( unohelper.Base, XModifyListener ):
930#    def __init__( self ):
931#        pass
932#    def modified( self, event ):
933#        log.debug( "pythonscript: ModifyListener.modified " + str( event ) )
934#    def disposing( self, event ):
935#        log.debug( "pythonscript: ModifyListener.disposing " + str( event ) )
936
937def getModelFromDocUrl(ctx, url):
938    """Get document model from document url."""
939    doc = None
940    args = ("Local", "Office")
941    ucb = ctx.getServiceManager().createInstanceWithArgumentsAndContext(
942        "com.sun.star.ucb.UniversalContentBroker", args, ctx)
943    identifier = ucb.createContentIdentifier(url)
944    content = ucb.queryContent(identifier)
945    p = Property()
946    p.Name = "DocumentModel"
947    p.Handle = -1
948
949    c = Command()
950    c.Handle = -1
951    c.Name = "getPropertyValues"
952    c.Argument = uno.Any("[]com.sun.star.beans.Property", (p,))
953
954    env = CommandEnvironment()
955    try:
956        ret = content.execute(c, 0, env)
957        doc = ret.getObject(1, None)
958    except Exception as e:
959        log.isErrorLevel() and log.error("getModelFromDocUrl: %s" % url)
960    return doc
961
962def mapStorageType2PackageContext( storageType ):
963    ret = storageType
964    if( storageType == "share:uno_packages" ):
965        ret = "shared"
966    if( storageType == "user:uno_packages" ):
967        ret = "user"
968    return ret
969
970def getPackageName2PathMap( sfa, storageType ):
971    ret = {}
972    packageManagerFactory = uno.getComponentContext().getValueByName(
973        "/singletons/com.sun.star.deployment.thePackageManagerFactory" )
974    packageManager = packageManagerFactory.getPackageManager(
975        mapStorageType2PackageContext(storageType))
976#    packageManager.addModifyListener( ModifyListener() )
977    log.debug( "pythonscript: getPackageName2PathMap start getDeployedPackages" )
978    packages = packageManager.getDeployedPackages(
979        packageManager.createAbortChannel(), CommandEnvironment( ) )
980    log.debug( "pythonscript: getPackageName2PathMap end getDeployedPackages (" + str(len(packages))+")" )
981
982    for i in packages:
983        log.debug( "inspecting package " + i.Name + "("+i.Identifier.Value+")" )
984        transientPathElement = penultimateElement( i.URL )
985        j = expandUri( i.URL )
986        pathes = getPathesFromPackage( j, sfa )
987        if len( pathes ) > 0:
988            # map package name to url, we need this later
989            log.isErrorLevel() and log.error( "adding Package " + transientPathElement + " " + str( pathes ) )
990            ret[ lastElement( j ) ] = Package( pathes, transientPathElement )
991    return ret
992
993def penultimateElement( aStr ):
994    lastSlash = aStr.rindex("/")
995    penultimateSlash = aStr.rindex("/",0,lastSlash-1)
996    return  aStr[ penultimateSlash+1:lastSlash ]
997
998def lastElement( aStr):
999    return aStr[ aStr.rfind( "/" )+1:len(aStr)]
1000
1001class PackageBrowseNode( unohelper.Base, XBrowseNode, XPropertySet, XInvocation ):
1002    def __init__( self, provCtx, name, rootUrl ):
1003        self.provCtx = provCtx
1004        self.name = name
1005        self.rootUrl = rootUrl
1006
1007    def getName( self ):
1008        return self.name
1009
1010    def getChildNodes( self ):
1011        items = list(self.provCtx.mapPackageName2Path.items())
1012        browseNodeList = []
1013        for i in items:
1014            if len( i[1].pathes ) == 1:
1015                browseNodeList.append(
1016                    DirBrowseNode( self.provCtx, i[0], i[1].pathes[0], 0 ))
1017            else:
1018                for j in i[1].pathes:
1019                    browseNodeList.append(
1020                        DirBrowseNode( self.provCtx, i[0]+"."+lastElement(j), j, 0 ) )
1021        return tuple( browseNodeList )
1022
1023    def hasChildNodes( self ):
1024        return len( self.mapPackageName2Path ) > 0
1025
1026    def getType( self ):
1027        return CONTAINER
1028
1029    def getScript( self, uri ):
1030        log.debug( "DirBrowseNode getScript " + uri + " invoked" )
1031        raise IllegalArgumentException( "PackageBrowseNode couldn't instantiate script " + uri , self , 0 )
1032
1033    # XPropertySet
1034
1035    def getPropertyValue( self, name ):
1036        ret = None
1037        log.debug( "PackageBrowseNode.getPropertyValue called for " + name + ", returning " + str(ret) )
1038        return ret
1039
1040    def setPropertyValue( self, name, value ):
1041        log.debug( "PackageBrowseNode.setPropertyValue " + name + "=" +str( value ) )
1042
1043    def getPropertySetInfo( self ):
1044        log.debug( "PackageBrowseNode.getPropertySetInfo called" )
1045        return None
1046
1047    # XInvocation
1048
1049    def getIntrospection( self ):
1050        log.debug( "PackageBrowseNode.getIntrospection() called" )
1051        return None
1052
1053    def invoke( self, name, params, outparamindex, outparams ):
1054        log.debug( "PackageBrowseNode.invoke called for " + name + "," + str( params ) + "," + str( outparamindex ) + "," + str( outparams ) )
1055        return None, (), ()
1056
1057    def setValue( self, name, value ):
1058        log.debug( "PackageBrowseNode.setValue" )
1059        return None
1060
1061    def getValue( self, name ):
1062        log.debug( "PackageBrowseNode.getValue" )
1063        return None
1064
1065    def hasMethod( self, name ):
1066        log.debug( "PackageBrowseNode.hasMethod" )
1067        return False
1068
1069    def hasProperty( self, name ):
1070        log.debug( "PackageBrowseNode.hasProperty" )
1071        return False
1072
1073
1074
1075class PythonScript( unohelper.Base, XScript ):
1076    def __init__( self, func, mod ):
1077        self.func = func
1078        self.mod = mod
1079    def invoke(self, args, out, outindex ):
1080        log.debug( "PythonScript.invoke " + str( args ) )
1081        try:
1082            ret = self.func( *args )
1083        except UnoException as e:
1084            # UNO Exception continue to fly ...
1085            text = lastException2String()
1086            complete = "Error during invoking function " + \
1087                str(self.func.__name__) + " in module " + \
1088                self.mod.__file__ + " (" + text + ")"
1089            log.debug( complete )
1090            # some people may beat me up for modifying the exception text,
1091            # but otherwise office just shows
1092            # the type name and message text with no more information,
1093            # this is really bad for most users.
1094            e.Message = e.Message + " (" + complete + ")"
1095            raise
1096        except Exception as e:
1097            # General python exception are converted to uno RuntimeException
1098            text = lastException2String()
1099            complete = "Error during invoking function " + \
1100                str(self.func.__name__) + " in module " + \
1101                self.mod.__file__ + " (" + text + ")"
1102            log.debug( complete )
1103            raise RuntimeException( complete , self )
1104        log.debug( "PythonScript.invoke ret = " + str( ret ) )
1105        return ret, (), ()
1106
1107def expandUri(  uri ):
1108    if uri.startswith( "vnd.sun.star.expand:" ):
1109        uri = uri.replace( "vnd.sun.star.expand:", "",1)
1110        uri = uno.getComponentContext().getByName(
1111                    "/singletons/com.sun.star.util.theMacroExpander" ).expandMacros( uri )
1112    if uri.startswith( "file:" ):
1113        uri = uno.absolutize("",uri)   # necessary to get rid of .. in uri
1114    return uri
1115
1116#--------------------------------------------------------------
1117class PythonScriptProvider( unohelper.Base, XBrowseNode, XScriptProvider, XNameContainer, XPropertySet, XInvocation):
1118    def __init__( self, ctx, *args ):
1119        if log.isDebugLevel():
1120            mystr = ""
1121            for i in args:
1122                if len(mystr) > 0:
1123                    mystr = mystr +","
1124                mystr = mystr + str(i)
1125            log.debug( "Entering PythonScriptProvider.ctor with args " + mystr )
1126
1127        doc = None
1128        inv = None
1129        storageType = ""
1130
1131        if isinstance(args[0],unicode ):
1132            storageType = args[0]
1133            if storageType.startswith( "vnd.sun.star.tdoc" ):
1134                doc = getModelFromDocUrl(ctx, storageType)
1135        else:
1136            inv = args[0]
1137            try:
1138                doc = inv.ScriptContainer
1139                content = ctx.getServiceManager().createInstanceWithContext(
1140                    "com.sun.star.frame.TransientDocumentsDocumentContentFactory",
1141                    ctx).createDocumentContent(doc)
1142                storageType = content.getIdentifier().getContentIdentifier()
1143            except Exception as e:
1144                text = lastException2String()
1145                log.error( text )
1146
1147        isPackage = storageType.endswith( ":uno_packages" )
1148
1149        try:
1150#            urlHelper = ctx.ServiceManager.createInstanceWithArgumentsAndContext(
1151#                "com.sun.star.script.provider.ScriptURIHelper", (LANGUAGENAME, storageType), ctx)
1152            urlHelper = MyUriHelper( ctx, storageType )
1153            log.debug( "got urlHelper " + str( urlHelper ) )
1154
1155            rootUrl = expandUri( urlHelper.getRootStorageURI() )
1156            log.debug( storageType + " transformed to " + rootUrl )
1157
1158            ucbService = "com.sun.star.ucb.SimpleFileAccess"
1159            sfa = ctx.ServiceManager.createInstanceWithContext( ucbService, ctx )
1160            if not sfa:
1161                log.debug("PythonScriptProvider couldn't instantiate " +ucbService)
1162                raise RuntimeException(
1163                    "PythonScriptProvider couldn't instantiate " +ucbService, self)
1164            self.provCtx = ProviderContext(
1165                storageType, sfa, urlHelper, ScriptContext( uno.getComponentContext(), doc, inv ) )
1166            if isPackage:
1167                mapPackageName2Path = getPackageName2PathMap( sfa, storageType )
1168                self.provCtx.setPackageAttributes( mapPackageName2Path , rootUrl )
1169                self.dirBrowseNode = PackageBrowseNode( self.provCtx, LANGUAGENAME, rootUrl )
1170            else:
1171                self.dirBrowseNode = DirBrowseNode( self.provCtx, LANGUAGENAME, rootUrl, 0 )
1172
1173        except Exception as e:
1174            text = lastException2String()
1175            log.debug( "PythonScriptProvider could not be instantiated because of : " + text )
1176            raise e
1177
1178    def getName( self ):
1179        return self.dirBrowseNode.getName()
1180
1181    def getChildNodes( self ):
1182        return self.dirBrowseNode.getChildNodes()
1183
1184    def hasChildNodes( self ):
1185        return self.dirBrowseNode.hasChildNodes()
1186
1187    def getType( self ):
1188        return self.dirBrowseNode.getType()
1189
1190    def getScript( self, uri ):
1191        log.debug( "DirBrowseNode getScript " + uri + " invoked" )
1192
1193        raise IllegalArgumentException( "DirBrowseNode couldn't instantiate script " + uri , self , 0 )
1194
1195    def getScript( self, scriptUri ):
1196        try:
1197            log.debug( "getScript " + scriptUri + " invoked")
1198
1199            storageUri = self.provCtx.getStorageUrlFromPersistentUrl(
1200                self.provCtx.uriHelper.getStorageURI(scriptUri) );
1201            log.debug( "getScript: storageUri = " + storageUri)
1202            fileUri = storageUri[0:storageUri.find( "$" )]
1203            funcName = storageUri[storageUri.find( "$" )+1:len(storageUri)]
1204
1205            mod = self.provCtx.getModuleByUrl( fileUri )
1206            log.debug( " got mod " + str(mod) )
1207
1208            func = mod.__dict__[ funcName ]
1209
1210            log.debug( "got func " + str( func ) )
1211            return PythonScript( func, mod )
1212        except Exception as e:
1213            text = lastException2String()
1214            log.error( text )
1215            raise ScriptFrameworkErrorException( text, self, scriptUri, LANGUAGENAME, 0 )
1216
1217    # XPropertySet
1218
1219    def getPropertyValue( self, name ):
1220        return self.dirBrowseNode.getPropertyValue( name )
1221
1222    def setPropertyValue( self, name, value ):
1223        return self.dirBrowseNode.setPropertyValue( name, value )
1224
1225    def getPropertySetInfo( self ):
1226        return self.dirBrowseNode.getPropertySetInfo()
1227
1228    # XInvocation
1229
1230    def getIntrospection( self ):
1231        return self.dirBrowseNode.getIntrospection()
1232
1233    def invoke( self, name, params, outparamindex, outparams ):
1234        return self.dirBrowseNode.invoke( name, params, outparamindex, outparams)
1235
1236    def setValue( self, name, value ):
1237        return self.dirBrowseNode.setValue( name, value )
1238
1239    def getValue( self, name ):
1240        return self.dirBrowseNode.getValue( name )
1241
1242    def hasMethod( self, name ):
1243        return self.dirBrowseNode.hasMethod( name )
1244
1245    def hasProperty( self, name ):
1246        return self.dirBrowseNode.hasProperty( name )
1247
1248    # XServiceInfo
1249    def getSupportedServices( self ):
1250        return g_ImplementationHelper.getSupportedServices(g_implName)
1251
1252    def supportsService( self, ServiceName ):
1253        return g_ImplementationHelper.supportsService( g_implName, ServiceName )
1254
1255    def getImplementationName(self):
1256        return g_implName
1257
1258    def getByName( self, name ):
1259        log.debug( "getByName called" + str( name ))
1260        return None
1261
1262
1263    def getElementNames( self ):
1264        log.debug( "getElementNames called")
1265        return ()
1266
1267    def hasByName( self, name ):
1268        try:
1269            log.debug( "hasByName called " + str( name ))
1270            uri = expandUri(name)
1271            ret = self.provCtx.isUrlInPackage( uri )
1272            log.debug( "hasByName " + uri + " " +str( ret ) )
1273            return ret
1274        except Exception as e:
1275            text = lastException2String()
1276            log.debug( "Error in hasByName:" +  text )
1277            return False
1278
1279    def removeByName( self, name ):
1280        log.debug( "removeByName called" + str( name ))
1281        uri = expandUri( name )
1282        if self.provCtx.isUrlInPackage( uri ):
1283            self.provCtx.removePackageByUrl( uri )
1284        else:
1285            log.debug( "removeByName unknown uri " + str( name ) + ", ignoring" )
1286            raise NoSuchElementException( uri + "is not in package" , self )
1287        log.debug( "removeByName called" + str( uri ) + " successful" )
1288
1289    def insertByName( self, name, value ):
1290        log.debug( "insertByName called " + str( name ) + " " + str( value ))
1291        uri = expandUri( name )
1292        if isPyFileInPath( self.provCtx.sfa, uri ):
1293            self.provCtx.addPackageByUrl( uri )
1294        else:
1295            # package is no python package ...
1296            log.debug( "insertByName: no python files in " + str( uri ) + ", ignoring" )
1297            raise IllegalArgumentException( uri + " does not contain .py files", self, 1 )
1298        log.debug( "insertByName called " + str( uri ) + " successful" )
1299
1300    def replaceByName( self, name, value ):
1301        log.debug( "replaceByName called " + str( name ) + " " + str( value ))
1302        removeByName( name )
1303        insertByName( name )
1304        log.debug( "replaceByName called" + str( uri ) + " successful" )
1305
1306    def getElementType( self ):
1307        log.debug( "getElementType called" )
1308        return uno.getTypeByName( "void" )
1309
1310    def hasElements( self ):
1311        log.debug( "hasElements got called")
1312        return False
1313
1314g_ImplementationHelper.addImplementation( \
1315        PythonScriptProvider,g_implName, \
1316    ("com.sun.star.script.provider.LanguageScriptProvider",
1317     "com.sun.star.script.provider.ScriptProviderFor"+ LANGUAGENAME,),)
1318
1319
1320log.debug( "pythonscript finished initializing" )
1321