1*9f22d7c2SAndrew Rist# *************************************************************
2*9f22d7c2SAndrew Rist#
3*9f22d7c2SAndrew Rist#  Licensed to the Apache Software Foundation (ASF) under one
4*9f22d7c2SAndrew Rist#  or more contributor license agreements.  See the NOTICE file
5*9f22d7c2SAndrew Rist#  distributed with this work for additional information
6*9f22d7c2SAndrew Rist#  regarding copyright ownership.  The ASF licenses this file
7*9f22d7c2SAndrew Rist#  to you under the Apache License, Version 2.0 (the
8*9f22d7c2SAndrew Rist#  "License"); you may not use this file except in compliance
9*9f22d7c2SAndrew Rist#  with the License.  You may obtain a copy of the License at
10*9f22d7c2SAndrew Rist#
11*9f22d7c2SAndrew Rist#    http://www.apache.org/licenses/LICENSE-2.0
12*9f22d7c2SAndrew Rist#
13*9f22d7c2SAndrew Rist#  Unless required by applicable law or agreed to in writing,
14*9f22d7c2SAndrew Rist#  software distributed under the License is distributed on an
15*9f22d7c2SAndrew Rist#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*9f22d7c2SAndrew Rist#  KIND, either express or implied.  See the License for the
17*9f22d7c2SAndrew Rist#  specific language governing permissions and limitations
18*9f22d7c2SAndrew Rist#  under the License.
19*9f22d7c2SAndrew Rist#
20*9f22d7c2SAndrew Rist# *************************************************************
21*9f22d7c2SAndrew Rist
22cdf0e10cSrcweir# XScript implementation for python
23cdf0e10cSrcweirimport uno
24cdf0e10cSrcweirimport unohelper
25cdf0e10cSrcweirimport sys
26cdf0e10cSrcweirimport os
27cdf0e10cSrcweirimport imp
28cdf0e10cSrcweirimport time
29cdf0e10cSrcweirimport compiler
30cdf0e10cSrcweir
31cdf0e10cSrcweirclass LogLevel:
32cdf0e10cSrcweir    NONE = 0
33cdf0e10cSrcweir    ERROR = 1
34cdf0e10cSrcweir    DEBUG = 2
35cdf0e10cSrcweir
36cdf0e10cSrcweir# Configuration ----------------------------------------------------
37cdf0e10cSrcweirLogLevel.use = LogLevel.NONE                # production level
38cdf0e10cSrcweir#LogLevel.use = LogLevel.ERROR               # for script developers
39cdf0e10cSrcweir#LogLevel.use = LogLevel.DEBUG               # for script framework developers
40cdf0e10cSrcweirLOG_STDOUT = True                           # True, writes to stdout (difficult on windows)
41cdf0e10cSrcweir                                            # False, writes to user/Scripts/python/log.txt
42cdf0e10cSrcweirENABLE_EDIT_DIALOG=False                    # offers a minimal editor for editing.
43cdf0e10cSrcweir#-------------------------------------------------------------------
44cdf0e10cSrcweir
45cdf0e10cSrcweirdef encfile(uni):
46cdf0e10cSrcweir    return uni.encode( sys.getfilesystemencoding())
47cdf0e10cSrcweir
48cdf0e10cSrcweirdef lastException2String():
49cdf0e10cSrcweir    (excType,excInstance,excTraceback) = sys.exc_info()
50cdf0e10cSrcweir    ret = str(excType) + ": "+str(excInstance) + "\n" + \
51cdf0e10cSrcweir          uno._uno_extract_printable_stacktrace( excTraceback )
52cdf0e10cSrcweir    return ret
53cdf0e10cSrcweir
54cdf0e10cSrcweirdef logLevel2String( level ):
55cdf0e10cSrcweir    ret = " NONE"
56cdf0e10cSrcweir    if level == LogLevel.ERROR:
57cdf0e10cSrcweir        ret = "ERROR"
58cdf0e10cSrcweir    elif level >= LogLevel.DEBUG:
59cdf0e10cSrcweir        ret = "DEBUG"
60cdf0e10cSrcweir    return ret
61cdf0e10cSrcweir
62cdf0e10cSrcweirdef getLogTarget():
63cdf0e10cSrcweir    ret = sys.stdout
64cdf0e10cSrcweir    if not LOG_STDOUT:
65cdf0e10cSrcweir        try:
66cdf0e10cSrcweir            pathSubst = uno.getComponentContext().ServiceManager.createInstance(
67cdf0e10cSrcweir                "com.sun.star.util.PathSubstitution" )
68cdf0e10cSrcweir            userInstallation =  pathSubst.getSubstituteVariableValue( "user" )
69cdf0e10cSrcweir            if len( userInstallation ) > 0:
70cdf0e10cSrcweir                systemPath = uno.fileUrlToSystemPath( userInstallation + "/Scripts/python/log.txt" )
71cdf0e10cSrcweir                ret = file( systemPath , "a" )
72cdf0e10cSrcweir        except Exception,e:
73cdf0e10cSrcweir            print "Exception during creation of pythonscript logfile: "+ lastException2String() + "\n, delagating log to stdout\n"
74cdf0e10cSrcweir    return ret
75cdf0e10cSrcweir
76cdf0e10cSrcweirclass Logger(LogLevel):
77cdf0e10cSrcweir    def __init__(self , target ):
78cdf0e10cSrcweir        self.target = target
79cdf0e10cSrcweir
80cdf0e10cSrcweir    def isDebugLevel( self ):
81cdf0e10cSrcweir        return self.use >= self.DEBUG
82cdf0e10cSrcweir
83cdf0e10cSrcweir    def debug( self, msg ):
84cdf0e10cSrcweir        if self.isDebugLevel():
85cdf0e10cSrcweir            self.log( self.DEBUG, msg )
86cdf0e10cSrcweir
87cdf0e10cSrcweir    def isErrorLevel( self ):
88cdf0e10cSrcweir        return self.use >= self.ERROR
89cdf0e10cSrcweir
90cdf0e10cSrcweir    def error( self, msg ):
91cdf0e10cSrcweir        if self.isErrorLevel():
92cdf0e10cSrcweir            self.log( self.ERROR, msg )
93cdf0e10cSrcweir
94cdf0e10cSrcweir    def log( self, level, msg ):
95cdf0e10cSrcweir        if self.use >= level:
96cdf0e10cSrcweir            try:
97cdf0e10cSrcweir                self.target.write(
98cdf0e10cSrcweir                    time.asctime() +
99cdf0e10cSrcweir                    " [" +
100cdf0e10cSrcweir                    logLevel2String( level ) +
101cdf0e10cSrcweir                    "] " +
102cdf0e10cSrcweir                    encfile(msg) +
103cdf0e10cSrcweir                    "\n" )
104cdf0e10cSrcweir                self.target.flush()
105cdf0e10cSrcweir            except Exception,e:
106cdf0e10cSrcweir                print "Error during writing to stdout: " +lastException2String() + "\n"
107cdf0e10cSrcweir
108cdf0e10cSrcweirlog = Logger( getLogTarget() )
109cdf0e10cSrcweir
110cdf0e10cSrcweirlog.debug( "pythonscript loading" )
111cdf0e10cSrcweir
112cdf0e10cSrcweir#from com.sun.star.lang import typeOfXServiceInfo, typeOfXTypeProvider
113cdf0e10cSrcweirfrom com.sun.star.uno import RuntimeException
114cdf0e10cSrcweirfrom com.sun.star.lang import XServiceInfo
115cdf0e10cSrcweirfrom com.sun.star.io import IOException
116cdf0e10cSrcweirfrom com.sun.star.ucb import CommandAbortedException, XCommandEnvironment, XProgressHandler
117cdf0e10cSrcweirfrom com.sun.star.task import XInteractionHandler
118cdf0e10cSrcweirfrom com.sun.star.beans import XPropertySet
119cdf0e10cSrcweirfrom com.sun.star.container import XNameContainer
120cdf0e10cSrcweirfrom com.sun.star.xml.sax import XDocumentHandler, InputSource
121cdf0e10cSrcweirfrom com.sun.star.uno import Exception as UnoException
122cdf0e10cSrcweirfrom com.sun.star.script import XInvocation
123cdf0e10cSrcweirfrom com.sun.star.awt import XActionListener
124cdf0e10cSrcweir
125cdf0e10cSrcweirfrom com.sun.star.script.provider import XScriptProvider, XScript, XScriptContext, ScriptFrameworkErrorException
126cdf0e10cSrcweirfrom com.sun.star.script.browse import XBrowseNode
127cdf0e10cSrcweirfrom com.sun.star.script.browse.BrowseNodeTypes import SCRIPT, CONTAINER, ROOT
128cdf0e10cSrcweirfrom com.sun.star.util import XModifyListener
129cdf0e10cSrcweir
130cdf0e10cSrcweirLANGUAGENAME = "Python"
131cdf0e10cSrcweirGLOBAL_SCRIPTCONTEXT_NAME = "XSCRIPTCONTEXT"
132cdf0e10cSrcweirCALLABLE_CONTAINER_NAME =  "g_exportedScripts"
133cdf0e10cSrcweir
134cdf0e10cSrcweir# pythonloader looks for a static g_ImplementationHelper variable
135cdf0e10cSrcweirg_ImplementationHelper = unohelper.ImplementationHelper()
136cdf0e10cSrcweirg_implName = "org.openoffice.pyuno.LanguageScriptProviderFor"+LANGUAGENAME
137cdf0e10cSrcweir
138cdf0e10cSrcweir
139cdf0e10cSrcweir
140cdf0e10cSrcweirBLOCK_SIZE = 65536
141cdf0e10cSrcweirdef readTextFromStream( inputStream ):
142cdf0e10cSrcweir    # read the file
143cdf0e10cSrcweir    code = uno.ByteSequence( "" )
144cdf0e10cSrcweir    while True:
145cdf0e10cSrcweir        read,out = inputStream.readBytes( None , BLOCK_SIZE )
146cdf0e10cSrcweir        code = code + out
147cdf0e10cSrcweir        if read < BLOCK_SIZE:
148cdf0e10cSrcweir           break
149cdf0e10cSrcweir    return code.value
150cdf0e10cSrcweir
151cdf0e10cSrcweirdef toIniName( str ):
152cdf0e10cSrcweir    # TODO: what is the official way to get to know whether i am on the windows platform ?
153cdf0e10cSrcweir    if( hasattr(sys , "dllhandle") ):
154cdf0e10cSrcweir        return str + ".ini"
155cdf0e10cSrcweir    return str + "rc"
156cdf0e10cSrcweir
157cdf0e10cSrcweir
158cdf0e10cSrcweir""" definition: storageURI is the system dependent, absolute file url, where the script is stored on disk
159cdf0e10cSrcweir                scriptURI is the system independent uri
160cdf0e10cSrcweir"""
161cdf0e10cSrcweirclass MyUriHelper:
162cdf0e10cSrcweir
163cdf0e10cSrcweir    def __init__( self, ctx, location ):
164cdf0e10cSrcweir        self.s_UriMap = \
165cdf0e10cSrcweir        { "share" : "vnd.sun.star.expand:${$BRAND_BASE_DIR/program/" +  toIniName( "bootstrap") + "::BaseInstallation}/share/Scripts/python" , \
166cdf0e10cSrcweir          "share:uno_packages" : "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/uno_packages", \
167cdf0e10cSrcweir          "user" : "vnd.sun.star.expand:${$BRAND_BASE_DIR/program/" + toIniName( "bootstrap") + "::UserInstallation}/user/Scripts/python" , \
168cdf0e10cSrcweir          "user:uno_packages" : "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages" }
169cdf0e10cSrcweir        self.m_uriRefFac = ctx.ServiceManager.createInstanceWithContext("com.sun.star.uri.UriReferenceFactory",ctx)
170cdf0e10cSrcweir        if location.startswith( "vnd.sun.star.tdoc" ):
171cdf0e10cSrcweir            self.m_baseUri = location + "/Scripts/python"
172cdf0e10cSrcweir            self.m_scriptUriLocation = "document"
173cdf0e10cSrcweir        else:
174cdf0e10cSrcweir            self.m_baseUri = expandUri( self.s_UriMap[location] )
175cdf0e10cSrcweir            self.m_scriptUriLocation = location
176cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "initialized urihelper with baseUri="+self.m_baseUri + ",m_scriptUriLocation="+self.m_scriptUriLocation )
177cdf0e10cSrcweir
178cdf0e10cSrcweir    def getRootStorageURI( self ):
179cdf0e10cSrcweir        return self.m_baseUri
180cdf0e10cSrcweir
181cdf0e10cSrcweir    def getStorageURI( self, scriptURI ):
182cdf0e10cSrcweir        return self.scriptURI2StorageUri(scriptURI)
183cdf0e10cSrcweir
184cdf0e10cSrcweir    def getScriptURI( self, storageURI ):
185cdf0e10cSrcweir        return self.storageURI2ScriptUri(storageURI)
186cdf0e10cSrcweir
187cdf0e10cSrcweir    def storageURI2ScriptUri( self, storageURI ):
188cdf0e10cSrcweir        if not storageURI.startswith( self.m_baseUri ):
189cdf0e10cSrcweir            message = "pythonscript: storage uri '" + storageURI + "' not in base uri '" + self.m_baseUri + "'"
190cdf0e10cSrcweir            log.isDebugLevel() and log.debug( message )
191cdf0e10cSrcweir            raise RuntimeException( message )
192cdf0e10cSrcweir
193cdf0e10cSrcweir        ret = "vnd.sun.star.script:" + \
194cdf0e10cSrcweir              storageURI[len(self.m_baseUri)+1:].replace("/","|") + \
195cdf0e10cSrcweir              "?language=" + LANGUAGENAME + "&location=" + self.m_scriptUriLocation
196cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "converting storageURI="+storageURI + " to scriptURI=" + ret )
197cdf0e10cSrcweir        return ret
198cdf0e10cSrcweir
199cdf0e10cSrcweir    def scriptURI2StorageUri( self, scriptURI ):
200cdf0e10cSrcweir        try:
201cdf0e10cSrcweir            myUri = self.m_uriRefFac.parse(scriptURI)
202cdf0e10cSrcweir            ret = self.m_baseUri + "/" + myUri.getName().replace( "|", "/" )
203cdf0e10cSrcweir            log.isDebugLevel() and log.debug( "converting scriptURI="+scriptURI + " to storageURI=" + ret )
204cdf0e10cSrcweir            return ret
205cdf0e10cSrcweir        except UnoException, e:
206cdf0e10cSrcweir            log.error( "error during converting scriptURI="+scriptURI + ": " + e.Message)
207cdf0e10cSrcweir            raise RuntimeException( "pythonscript:scriptURI2StorageUri: " +e.getMessage(), None )
208cdf0e10cSrcweir        except Exception, e:
209cdf0e10cSrcweir            log.error( "error during converting scriptURI="+scriptURI + ": " + str(e))
210cdf0e10cSrcweir            raise RuntimeException( "pythonscript:scriptURI2StorageUri: " + str(e), None )
211cdf0e10cSrcweir
212cdf0e10cSrcweir
213cdf0e10cSrcweirclass ModuleEntry:
214cdf0e10cSrcweir    def __init__( self, lastRead, module ):
215cdf0e10cSrcweir        self.lastRead = lastRead
216cdf0e10cSrcweir        self.module = module
217cdf0e10cSrcweir
218cdf0e10cSrcweirdef hasChanged( oldDate, newDate ):
219cdf0e10cSrcweir    return newDate.Year > oldDate.Year or \
220cdf0e10cSrcweir           newDate.Month > oldDate.Month or \
221cdf0e10cSrcweir           newDate.Day > oldDate.Day or \
222cdf0e10cSrcweir           newDate.Hours > oldDate.Hours or \
223cdf0e10cSrcweir           newDate.Minutes > oldDate.Minutes or \
224cdf0e10cSrcweir           newDate.Seconds > oldDate.Seconds or \
225cdf0e10cSrcweir           newDate.HundredthSeconds > oldDate.HundredthSeconds
226cdf0e10cSrcweir
227cdf0e10cSrcweirdef ensureSourceState( code ):
228cdf0e10cSrcweir    if not code.endswith( "\n" ):
229cdf0e10cSrcweir        code = code + "\n"
230cdf0e10cSrcweir    code = code.replace( "\r", "" )
231cdf0e10cSrcweir    return code
232cdf0e10cSrcweir
233cdf0e10cSrcweir
234cdf0e10cSrcweirdef checkForPythonPathBesideScript( url ):
235cdf0e10cSrcweir    if url.startswith( "file:" ):
236cdf0e10cSrcweir        path = unohelper.fileUrlToSystemPath( url+"/pythonpath.zip" );
237cdf0e10cSrcweir        log.log( LogLevel.DEBUG,  "checking for existence of " + path )
238cdf0e10cSrcweir        if 1 == os.access( encfile(path), os.F_OK) and not path in sys.path:
239cdf0e10cSrcweir            log.log( LogLevel.DEBUG, "adding " + path + " to sys.path" )
240cdf0e10cSrcweir            sys.path.append( path )
241cdf0e10cSrcweir
242cdf0e10cSrcweir        path = unohelper.fileUrlToSystemPath( url+"/pythonpath" );
243cdf0e10cSrcweir        log.log( LogLevel.DEBUG,  "checking for existence of " + path )
244cdf0e10cSrcweir        if 1 == os.access( encfile(path), os.F_OK) and not path in sys.path:
245cdf0e10cSrcweir            log.log( LogLevel.DEBUG, "adding " + path + " to sys.path" )
246cdf0e10cSrcweir            sys.path.append( path )
247cdf0e10cSrcweir
248cdf0e10cSrcweir
249cdf0e10cSrcweirclass ScriptContext(unohelper.Base):
250cdf0e10cSrcweir    def __init__( self, ctx, doc ):
251cdf0e10cSrcweir        self.ctx = ctx
252cdf0e10cSrcweir        self.doc = doc
253cdf0e10cSrcweir
254cdf0e10cSrcweir   # XScriptContext
255cdf0e10cSrcweir    def getDocument(self):
256cdf0e10cSrcweir        return self.getDesktop().getCurrentComponent()
257cdf0e10cSrcweir
258cdf0e10cSrcweir    def getDesktop(self):
259cdf0e10cSrcweir        return self.ctx.ServiceManager.createInstanceWithContext(
260cdf0e10cSrcweir            "com.sun.star.frame.Desktop", self.ctx )
261cdf0e10cSrcweir
262cdf0e10cSrcweir    def getComponentContext(self):
263cdf0e10cSrcweir        return self.ctx
264cdf0e10cSrcweir
265cdf0e10cSrcweir#----------------------------------
266cdf0e10cSrcweir# Global Module Administration
267cdf0e10cSrcweir# does not fit together with script
268cdf0e10cSrcweir# engine lifetime management
269cdf0e10cSrcweir#----------------------------------
270cdf0e10cSrcweir#g_scriptContext = ScriptContext( uno.getComponentContext(), None )
271cdf0e10cSrcweir#g_modules = {}
272cdf0e10cSrcweir#def getModuleByUrl( url, sfa ):
273cdf0e10cSrcweir#    entry =  g_modules.get(url)
274cdf0e10cSrcweir#    load = True
275cdf0e10cSrcweir#    lastRead = sfa.getDateTimeModified( url )
276cdf0e10cSrcweir#    if entry:
277cdf0e10cSrcweir#        if hasChanged( entry.lastRead, lastRead ):
278cdf0e10cSrcweir#            log.isDebugLevel() and log.debug("file " + url + " has changed, reloading")
279cdf0e10cSrcweir#        else:
280cdf0e10cSrcweir#            load = False
281cdf0e10cSrcweir#
282cdf0e10cSrcweir#    if load:
283cdf0e10cSrcweir#        log.isDebugLevel() and log.debug( "opening >" + url + "<" )
284cdf0e10cSrcweir#
285cdf0e10cSrcweir#        code = readTextFromStream( sfa.openFileRead( url ) )
286cdf0e10cSrcweir
287cdf0e10cSrcweir        # execute the module
288cdf0e10cSrcweir#        entry = ModuleEntry( lastRead, imp.new_module("ooo_script_framework") )
289cdf0e10cSrcweir#        entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = g_scriptContext
290cdf0e10cSrcweir#        entry.module.__file__ = url
291cdf0e10cSrcweir#        exec code in entry.module.__dict__
292cdf0e10cSrcweir#        g_modules[ url ] = entry
293cdf0e10cSrcweir#        log.isDebugLevel() and log.debug( "mapped " + url + " to " + str( entry.module ) )
294cdf0e10cSrcweir#    return entry.module
295cdf0e10cSrcweir
296cdf0e10cSrcweirclass ProviderContext:
297cdf0e10cSrcweir    def __init__( self, storageType, sfa, uriHelper, scriptContext ):
298cdf0e10cSrcweir        self.storageType = storageType
299cdf0e10cSrcweir        self.sfa = sfa
300cdf0e10cSrcweir        self.uriHelper = uriHelper
301cdf0e10cSrcweir        self.scriptContext = scriptContext
302cdf0e10cSrcweir        self.modules = {}
303cdf0e10cSrcweir        self.rootUrl = None
304cdf0e10cSrcweir        self.mapPackageName2Path = None
305cdf0e10cSrcweir
306cdf0e10cSrcweir    def getTransientPartFromUrl( self, url ):
307cdf0e10cSrcweir        rest = url.replace( self.rootUrl , "",1 ).replace( "/","",1)
308cdf0e10cSrcweir        return rest[0:rest.find("/")]
309cdf0e10cSrcweir
310cdf0e10cSrcweir    def getPackageNameFromUrl( self, url ):
311cdf0e10cSrcweir        rest = url.replace( self.rootUrl , "",1 ).replace( "/","",1)
312cdf0e10cSrcweir        start = rest.find("/") +1
313cdf0e10cSrcweir        return rest[start:rest.find("/",start)]
314cdf0e10cSrcweir
315cdf0e10cSrcweir
316cdf0e10cSrcweir    def removePackageByUrl( self, url ):
317cdf0e10cSrcweir        items = self.mapPackageName2Path.items()
318cdf0e10cSrcweir        for i in items:
319cdf0e10cSrcweir            if url in i[1].pathes:
320cdf0e10cSrcweir                self.mapPackageName2Path.pop(i[0])
321cdf0e10cSrcweir                break
322cdf0e10cSrcweir
323cdf0e10cSrcweir    def addPackageByUrl( self, url ):
324cdf0e10cSrcweir        packageName = self.getPackageNameFromUrl( url )
325cdf0e10cSrcweir        transientPart = self.getTransientPartFromUrl( url )
326cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "addPackageByUrl : " + packageName + ", " + transientPart + "("+url+")" + ", rootUrl="+self.rootUrl )
327cdf0e10cSrcweir        if self.mapPackageName2Path.has_key( packageName ):
328cdf0e10cSrcweir            package = self.mapPackageName2Path[ packageName ]
329cdf0e10cSrcweir            package.pathes = package.pathes + (url, )
330cdf0e10cSrcweir        else:
331cdf0e10cSrcweir            package = Package( (url,), transientPart)
332cdf0e10cSrcweir            self.mapPackageName2Path[ packageName ] = package
333cdf0e10cSrcweir
334cdf0e10cSrcweir    def isUrlInPackage( self, url ):
335cdf0e10cSrcweir        values = self.mapPackageName2Path.values()
336cdf0e10cSrcweir        for i in values:
337cdf0e10cSrcweir#	    print "checking " + url + " in " + str(i.pathes)
338cdf0e10cSrcweir            if url in i.pathes:
339cdf0e10cSrcweir               return True
340cdf0e10cSrcweir#        print "false"
341cdf0e10cSrcweir        return False
342cdf0e10cSrcweir
343cdf0e10cSrcweir    def setPackageAttributes( self, mapPackageName2Path, rootUrl ):
344cdf0e10cSrcweir        self.mapPackageName2Path = mapPackageName2Path
345cdf0e10cSrcweir        self.rootUrl = rootUrl
346cdf0e10cSrcweir
347cdf0e10cSrcweir    def getPersistentUrlFromStorageUrl( self, url ):
348cdf0e10cSrcweir        # package name is the second directory
349cdf0e10cSrcweir        ret = url
350cdf0e10cSrcweir        if self.rootUrl:
351cdf0e10cSrcweir            pos = len( self.rootUrl) +1
352cdf0e10cSrcweir            ret = url[0:pos]+url[url.find("/",pos)+1:len(url)]
353cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "getPersistentUrlFromStorageUrl " + url +  " -> "+ ret)
354cdf0e10cSrcweir        return ret
355cdf0e10cSrcweir
356cdf0e10cSrcweir    def getStorageUrlFromPersistentUrl( self, url):
357cdf0e10cSrcweir        ret = url
358cdf0e10cSrcweir        if self.rootUrl:
359cdf0e10cSrcweir            pos = len(self.rootUrl)+1
360cdf0e10cSrcweir            packageName = url[pos:url.find("/",pos+1)]
361cdf0e10cSrcweir            package = self.mapPackageName2Path[ packageName ]
362cdf0e10cSrcweir            ret = url[0:pos]+ package.transientPathElement + "/" + url[pos:len(url)]
363cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "getStorageUrlFromPersistentUrl " + url + " -> "+ ret)
364cdf0e10cSrcweir        return ret
365cdf0e10cSrcweir
366cdf0e10cSrcweir    def getFuncsByUrl( self, url ):
367cdf0e10cSrcweir        src = readTextFromStream( self.sfa.openFileRead( url ) )
368cdf0e10cSrcweir        checkForPythonPathBesideScript( url[0:url.rfind('/')] )
369cdf0e10cSrcweir        src = ensureSourceState( src )
370cdf0e10cSrcweir
371cdf0e10cSrcweir        code = compiler.parse( src )
372cdf0e10cSrcweir
373cdf0e10cSrcweir        allFuncs = []
374cdf0e10cSrcweir
375cdf0e10cSrcweir        if code == None:
376cdf0e10cSrcweir            return allFuncs
377cdf0e10cSrcweir
378cdf0e10cSrcweir        g_exportedScripts = []
379cdf0e10cSrcweir        for node in code.node.nodes:
380cdf0e10cSrcweir            if node.__class__.__name__ == 'Function':
381cdf0e10cSrcweir                allFuncs.append(node.name)
382cdf0e10cSrcweir            elif node.__class__.__name__ == 'Assign':
383cdf0e10cSrcweir                for assignee in node.nodes:
384cdf0e10cSrcweir                    if assignee.name == 'g_exportedScripts':
385cdf0e10cSrcweir                        for item in node.expr:
386cdf0e10cSrcweir                            if item.__class__.__name__ == 'Name':
387cdf0e10cSrcweir                                g_exportedScripts.append(item.name)
388cdf0e10cSrcweir                        return g_exportedScripts
389cdf0e10cSrcweir
390cdf0e10cSrcweir        return allFuncs
391cdf0e10cSrcweir
392cdf0e10cSrcweir    def getModuleByUrl( self, url ):
393cdf0e10cSrcweir        entry =  self.modules.get(url)
394cdf0e10cSrcweir        load = True
395cdf0e10cSrcweir        lastRead = self.sfa.getDateTimeModified( url )
396cdf0e10cSrcweir        if entry:
397cdf0e10cSrcweir            if hasChanged( entry.lastRead, lastRead ):
398cdf0e10cSrcweir                log.isDebugLevel() and log.debug( "file " + url + " has changed, reloading" )
399cdf0e10cSrcweir            else:
400cdf0e10cSrcweir                load = False
401cdf0e10cSrcweir
402cdf0e10cSrcweir        if load:
403cdf0e10cSrcweir            log.isDebugLevel() and log.debug( "opening >" + url + "<" )
404cdf0e10cSrcweir
405cdf0e10cSrcweir            src = readTextFromStream( self.sfa.openFileRead( url ) )
406cdf0e10cSrcweir            checkForPythonPathBesideScript( url[0:url.rfind('/')] )
407cdf0e10cSrcweir            src = ensureSourceState( src )
408cdf0e10cSrcweir
409cdf0e10cSrcweir            # execute the module
410cdf0e10cSrcweir            entry = ModuleEntry( lastRead, imp.new_module("ooo_script_framework") )
411cdf0e10cSrcweir            entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = self.scriptContext
412cdf0e10cSrcweir
413cdf0e10cSrcweir            code = None
414cdf0e10cSrcweir            if url.startswith( "file:" ):
415cdf0e10cSrcweir                code = compile( src, encfile(uno.fileUrlToSystemPath( url ) ), "exec" )
416cdf0e10cSrcweir            else:
417cdf0e10cSrcweir                code = compile( src, url, "exec" )
418cdf0e10cSrcweir            exec code in entry.module.__dict__
419cdf0e10cSrcweir            entry.module.__file__ = url
420cdf0e10cSrcweir            self.modules[ url ] = entry
421cdf0e10cSrcweir            log.isDebugLevel() and log.debug( "mapped " + url + " to " + str( entry.module ) )
422cdf0e10cSrcweir        return  entry.module
423cdf0e10cSrcweir
424cdf0e10cSrcweir#--------------------------------------------------
425cdf0e10cSrcweirdef isScript( candidate ):
426cdf0e10cSrcweir    ret = False
427cdf0e10cSrcweir    if isinstance( candidate, type(isScript) ):
428cdf0e10cSrcweir        ret = True
429cdf0e10cSrcweir    return ret
430cdf0e10cSrcweir
431cdf0e10cSrcweir#-------------------------------------------------------
432cdf0e10cSrcweirclass ScriptBrowseNode( unohelper.Base, XBrowseNode , XPropertySet, XInvocation, XActionListener ):
433cdf0e10cSrcweir    def __init__( self, provCtx, uri, fileName, funcName ):
434cdf0e10cSrcweir        self.fileName = fileName
435cdf0e10cSrcweir        self.funcName = funcName
436cdf0e10cSrcweir        self.provCtx = provCtx
437cdf0e10cSrcweir        self.uri = uri
438cdf0e10cSrcweir
439cdf0e10cSrcweir    def getName( self ):
440cdf0e10cSrcweir        return self.funcName
441cdf0e10cSrcweir
442cdf0e10cSrcweir    def getChildNodes(self):
443cdf0e10cSrcweir        return ()
444cdf0e10cSrcweir
445cdf0e10cSrcweir    def hasChildNodes(self):
446cdf0e10cSrcweir        return False
447cdf0e10cSrcweir
448cdf0e10cSrcweir    def getType( self):
449cdf0e10cSrcweir        return SCRIPT
450cdf0e10cSrcweir
451cdf0e10cSrcweir    def getPropertyValue( self, name ):
452cdf0e10cSrcweir        ret = None
453cdf0e10cSrcweir        try:
454cdf0e10cSrcweir            if name == "URI":
455cdf0e10cSrcweir                ret = self.provCtx.uriHelper.getScriptURI(
456cdf0e10cSrcweir                    self.provCtx.getPersistentUrlFromStorageUrl( self.uri + "$" + self.funcName ) )
457cdf0e10cSrcweir            elif name == "Editable" and ENABLE_EDIT_DIALOG:
458cdf0e10cSrcweir                ret = not self.provCtx.sfa.isReadOnly( self.uri )
459cdf0e10cSrcweir
460cdf0e10cSrcweir            log.isDebugLevel() and log.debug( "ScriptBrowseNode.getPropertyValue called for " + name + ", returning " + str(ret) )
461cdf0e10cSrcweir        except Exception,e:
462cdf0e10cSrcweir            log.error( "ScriptBrowseNode.getPropertyValue error " + lastException2String())
463cdf0e10cSrcweir            raise
464cdf0e10cSrcweir
465cdf0e10cSrcweir        return ret
466cdf0e10cSrcweir    def setPropertyValue( self, name, value ):
467cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "ScriptBrowseNode.setPropertyValue called " + name + "=" +str(value ) )
468cdf0e10cSrcweir    def getPropertySetInfo( self ):
469cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "ScriptBrowseNode.getPropertySetInfo called "  )
470cdf0e10cSrcweir        return None
471cdf0e10cSrcweir
472cdf0e10cSrcweir    def getIntrospection( self ):
473cdf0e10cSrcweir        return None
474cdf0e10cSrcweir
475cdf0e10cSrcweir    def invoke( self, name, params, outparamindex, outparams ):
476cdf0e10cSrcweir        if name == "Editable":
477cdf0e10cSrcweir            servicename = "com.sun.star.awt.DialogProvider"
478cdf0e10cSrcweir            ctx = self.provCtx.scriptContext.getComponentContext()
479cdf0e10cSrcweir            dlgprov = ctx.ServiceManager.createInstanceWithContext(
480cdf0e10cSrcweir                servicename, ctx )
481cdf0e10cSrcweir
482cdf0e10cSrcweir            self.editor = dlgprov.createDialog(
483cdf0e10cSrcweir                "vnd.sun.star.script:" +
484cdf0e10cSrcweir                "ScriptBindingLibrary.MacroEditor?location=application")
485cdf0e10cSrcweir
486cdf0e10cSrcweir            code = readTextFromStream(self.provCtx.sfa.openFileRead(self.uri))
487cdf0e10cSrcweir            code = ensureSourceState( code )
488cdf0e10cSrcweir            self.editor.getControl("EditorTextField").setText(code)
489cdf0e10cSrcweir
490cdf0e10cSrcweir            self.editor.getControl("RunButton").setActionCommand("Run")
491cdf0e10cSrcweir            self.editor.getControl("RunButton").addActionListener(self)
492cdf0e10cSrcweir            self.editor.getControl("SaveButton").setActionCommand("Save")
493cdf0e10cSrcweir            self.editor.getControl("SaveButton").addActionListener(self)
494cdf0e10cSrcweir
495cdf0e10cSrcweir            self.editor.execute()
496cdf0e10cSrcweir
497cdf0e10cSrcweir        return None
498cdf0e10cSrcweir
499cdf0e10cSrcweir    def actionPerformed( self, event ):
500cdf0e10cSrcweir        try:
501cdf0e10cSrcweir            if event.ActionCommand == "Run":
502cdf0e10cSrcweir                code = self.editor.getControl("EditorTextField").getText()
503cdf0e10cSrcweir                code = ensureSourceState( code )
504cdf0e10cSrcweir                mod = imp.new_module("ooo_script_framework")
505cdf0e10cSrcweir                mod.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = self.provCtx.scriptContext
506cdf0e10cSrcweir                exec code in mod.__dict__
507cdf0e10cSrcweir                values = mod.__dict__.get( CALLABLE_CONTAINER_NAME , None )
508cdf0e10cSrcweir                if not values:
509cdf0e10cSrcweir                    values = mod.__dict__.values()
510cdf0e10cSrcweir
511cdf0e10cSrcweir                for i in values:
512cdf0e10cSrcweir                    if isScript( i ):
513cdf0e10cSrcweir                        i()
514cdf0e10cSrcweir                        break
515cdf0e10cSrcweir
516cdf0e10cSrcweir            elif event.ActionCommand == "Save":
517cdf0e10cSrcweir                toWrite = uno.ByteSequence(
518cdf0e10cSrcweir                    str(
519cdf0e10cSrcweir                    self.editor.getControl("EditorTextField").getText().encode(
520cdf0e10cSrcweir                    sys.getdefaultencoding())) )
521cdf0e10cSrcweir                copyUrl = self.uri + ".orig"
522cdf0e10cSrcweir                self.provCtx.sfa.move( self.uri, copyUrl )
523cdf0e10cSrcweir                out = self.provCtx.sfa.openFileWrite( self.uri )
524cdf0e10cSrcweir                out.writeBytes( toWrite )
525cdf0e10cSrcweir                out.close()
526cdf0e10cSrcweir                self.provCtx.sfa.kill( copyUrl )
527cdf0e10cSrcweir#                log.isDebugLevel() and log.debug("Save is not implemented yet")
528cdf0e10cSrcweir#                text = self.editor.getControl("EditorTextField").getText()
529cdf0e10cSrcweir#                log.isDebugLevel() and log.debug("Would save: " + text)
530cdf0e10cSrcweir        except Exception,e:
531cdf0e10cSrcweir            # TODO: add an error box here !
532cdf0e10cSrcweir            log.error( lastException2String() )
533cdf0e10cSrcweir
534cdf0e10cSrcweir
535cdf0e10cSrcweir    def setValue( self, name, value ):
536cdf0e10cSrcweir        return None
537cdf0e10cSrcweir
538cdf0e10cSrcweir    def getValue( self, name ):
539cdf0e10cSrcweir        return None
540cdf0e10cSrcweir
541cdf0e10cSrcweir    def hasMethod( self, name ):
542cdf0e10cSrcweir        return False
543cdf0e10cSrcweir
544cdf0e10cSrcweir    def hasProperty( self, name ):
545cdf0e10cSrcweir        return False
546cdf0e10cSrcweir
547cdf0e10cSrcweir
548cdf0e10cSrcweir#-------------------------------------------------------
549cdf0e10cSrcweirclass FileBrowseNode( unohelper.Base, XBrowseNode ):
550cdf0e10cSrcweir    def __init__( self, provCtx, uri , name ):
551cdf0e10cSrcweir        self.provCtx = provCtx
552cdf0e10cSrcweir        self.uri = uri
553cdf0e10cSrcweir        self.name = name
554cdf0e10cSrcweir        self.funcnames = None
555cdf0e10cSrcweir
556cdf0e10cSrcweir    def getName( self ):
557cdf0e10cSrcweir        return self.name
558cdf0e10cSrcweir
559cdf0e10cSrcweir    def getChildNodes(self):
560cdf0e10cSrcweir        ret = ()
561cdf0e10cSrcweir        try:
562cdf0e10cSrcweir            self.funcnames = self.provCtx.getFuncsByUrl( self.uri )
563cdf0e10cSrcweir
564cdf0e10cSrcweir            scriptNodeList = []
565cdf0e10cSrcweir            for i in self.funcnames:
566cdf0e10cSrcweir                scriptNodeList.append(
567cdf0e10cSrcweir                    ScriptBrowseNode(
568cdf0e10cSrcweir                    self.provCtx, self.uri, self.name, i ))
569cdf0e10cSrcweir            ret = tuple( scriptNodeList )
570cdf0e10cSrcweir            log.isDebugLevel() and log.debug( "returning " +str(len(ret)) + " ScriptChildNodes on " + self.uri )
571cdf0e10cSrcweir        except Exception, e:
572cdf0e10cSrcweir            text = lastException2String()
573cdf0e10cSrcweir            log.error( "Error while evaluating " + self.uri + ":" + text )
574cdf0e10cSrcweir            raise
575cdf0e10cSrcweir        return ret
576cdf0e10cSrcweir
577cdf0e10cSrcweir    def hasChildNodes(self):
578cdf0e10cSrcweir        try:
579cdf0e10cSrcweir            return len(self.getChildNodes()) > 0
580cdf0e10cSrcweir        except Exception, e:
581cdf0e10cSrcweir            return False
582cdf0e10cSrcweir
583cdf0e10cSrcweir    def getType( self):
584cdf0e10cSrcweir        return CONTAINER
585cdf0e10cSrcweir
586cdf0e10cSrcweir
587cdf0e10cSrcweir
588cdf0e10cSrcweirclass DirBrowseNode( unohelper.Base, XBrowseNode ):
589cdf0e10cSrcweir    def __init__( self, provCtx, name, rootUrl ):
590cdf0e10cSrcweir        self.provCtx = provCtx
591cdf0e10cSrcweir        self.name = name
592cdf0e10cSrcweir        self.rootUrl = rootUrl
593cdf0e10cSrcweir
594cdf0e10cSrcweir    def getName( self ):
595cdf0e10cSrcweir        return self.name
596cdf0e10cSrcweir
597cdf0e10cSrcweir    def getChildNodes( self ):
598cdf0e10cSrcweir        try:
599cdf0e10cSrcweir            log.isDebugLevel() and log.debug( "DirBrowseNode.getChildNodes called for " + self.rootUrl )
600cdf0e10cSrcweir            contents = self.provCtx.sfa.getFolderContents( self.rootUrl, True )
601cdf0e10cSrcweir            browseNodeList = []
602cdf0e10cSrcweir            for i in contents:
603cdf0e10cSrcweir                if i.endswith( ".py" ):
604cdf0e10cSrcweir                    log.isDebugLevel() and log.debug( "adding filenode " + i )
605cdf0e10cSrcweir                    browseNodeList.append(
606cdf0e10cSrcweir                        FileBrowseNode( self.provCtx, i, i[i.rfind("/")+1:len(i)-3] ) )
607cdf0e10cSrcweir                elif self.provCtx.sfa.isFolder( i ) and not i.endswith("/pythonpath"):
608cdf0e10cSrcweir                    log.isDebugLevel() and log.debug( "adding DirBrowseNode " + i )
609cdf0e10cSrcweir                    browseNodeList.append( DirBrowseNode( self.provCtx, i[i.rfind("/")+1:len(i)],i))
610cdf0e10cSrcweir            return tuple( browseNodeList )
611cdf0e10cSrcweir        except Exception, e:
612cdf0e10cSrcweir            text = lastException2String()
613cdf0e10cSrcweir            log.error( "DirBrowseNode error: " + str(e) + " while evaluating " + self.rootUrl)
614cdf0e10cSrcweir            log.error( text)
615cdf0e10cSrcweir            return ()
616cdf0e10cSrcweir
617cdf0e10cSrcweir    def hasChildNodes( self ):
618cdf0e10cSrcweir        return True
619cdf0e10cSrcweir
620cdf0e10cSrcweir    def getType( self ):
621cdf0e10cSrcweir        return CONTAINER
622cdf0e10cSrcweir
623cdf0e10cSrcweir    def getScript( self, uri ):
624cdf0e10cSrcweir        log.debug( "DirBrowseNode getScript " + uri + " invoked" )
625cdf0e10cSrcweir        raise IllegalArgumentException( "DirBrowseNode couldn't instantiate script " + uri , self , 0 )
626cdf0e10cSrcweir
627cdf0e10cSrcweir
628cdf0e10cSrcweirclass ManifestHandler( XDocumentHandler, unohelper.Base ):
629cdf0e10cSrcweir    def __init__( self, rootUrl ):
630cdf0e10cSrcweir        self.rootUrl = rootUrl
631cdf0e10cSrcweir
632cdf0e10cSrcweir    def startDocument( self ):
633cdf0e10cSrcweir        self.urlList = []
634cdf0e10cSrcweir
635cdf0e10cSrcweir    def endDocument( self ):
636cdf0e10cSrcweir        pass
637cdf0e10cSrcweir
638cdf0e10cSrcweir    def startElement( self , name, attlist):
639cdf0e10cSrcweir        if name == "manifest:file-entry":
640cdf0e10cSrcweir            if attlist.getValueByName( "manifest:media-type" ) == "application/vnd.sun.star.framework-script":
641cdf0e10cSrcweir                self.urlList.append(
642cdf0e10cSrcweir                    self.rootUrl + "/" + attlist.getValueByName( "manifest:full-path" ) )
643cdf0e10cSrcweir
644cdf0e10cSrcweir    def endElement( self, name ):
645cdf0e10cSrcweir        pass
646cdf0e10cSrcweir
647cdf0e10cSrcweir    def characters ( self, chars ):
648cdf0e10cSrcweir        pass
649cdf0e10cSrcweir
650cdf0e10cSrcweir    def ignoreableWhitespace( self, chars ):
651cdf0e10cSrcweir        pass
652cdf0e10cSrcweir
653cdf0e10cSrcweir    def setDocumentLocator( self, locator ):
654cdf0e10cSrcweir        pass
655cdf0e10cSrcweir
656cdf0e10cSrcweirdef isPyFileInPath( sfa, path ):
657cdf0e10cSrcweir    ret = False
658cdf0e10cSrcweir    contents = sfa.getFolderContents( path, True )
659cdf0e10cSrcweir    for i in contents:
660cdf0e10cSrcweir        if sfa.isFolder(i):
661cdf0e10cSrcweir            ret = isPyFileInPath(sfa,i)
662cdf0e10cSrcweir        else:
663cdf0e10cSrcweir            if i.endswith(".py"):
664cdf0e10cSrcweir                ret = True
665cdf0e10cSrcweir        if ret:
666cdf0e10cSrcweir            break
667cdf0e10cSrcweir    return ret
668cdf0e10cSrcweir
669cdf0e10cSrcweir# extracts META-INF directory from
670cdf0e10cSrcweirdef getPathesFromPackage( rootUrl, sfa ):
671cdf0e10cSrcweir    ret = ()
672cdf0e10cSrcweir    try:
673cdf0e10cSrcweir        fileUrl = rootUrl + "/META-INF/manifest.xml"
674cdf0e10cSrcweir        inputStream = sfa.openFileRead( fileUrl )
675cdf0e10cSrcweir        parser = uno.getComponentContext().ServiceManager.createInstance( "com.sun.star.xml.sax.Parser" )
676cdf0e10cSrcweir        handler = ManifestHandler( rootUrl )
677cdf0e10cSrcweir        parser.setDocumentHandler( handler )
678cdf0e10cSrcweir        parser.parseStream( InputSource( inputStream , "", fileUrl, fileUrl ) )
679cdf0e10cSrcweir        for i in tuple(handler.urlList):
680cdf0e10cSrcweir            if not isPyFileInPath( sfa, i ):
681cdf0e10cSrcweir                handler.urlList.remove(i)
682cdf0e10cSrcweir        ret = tuple( handler.urlList )
683cdf0e10cSrcweir    except UnoException, e:
684cdf0e10cSrcweir        text = lastException2String()
685cdf0e10cSrcweir        log.debug( "getPathesFromPackage " + fileUrl + " Exception: " +text )
686cdf0e10cSrcweir        pass
687cdf0e10cSrcweir    return ret
688cdf0e10cSrcweir
689cdf0e10cSrcweir
690cdf0e10cSrcweirclass Package:
691cdf0e10cSrcweir    def __init__( self, pathes, transientPathElement ):
692cdf0e10cSrcweir        self.pathes = pathes
693cdf0e10cSrcweir        self.transientPathElement = transientPathElement
694cdf0e10cSrcweir
695cdf0e10cSrcweirclass DummyInteractionHandler( unohelper.Base, XInteractionHandler ):
696cdf0e10cSrcweir    def __init__( self ):
697cdf0e10cSrcweir        pass
698cdf0e10cSrcweir    def handle( self, event):
699cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "pythonscript: DummyInteractionHandler.handle " + str( event ) )
700cdf0e10cSrcweir
701cdf0e10cSrcweirclass DummyProgressHandler( unohelper.Base, XProgressHandler ):
702cdf0e10cSrcweir    def __init__( self ):
703cdf0e10cSrcweir        pass
704cdf0e10cSrcweir
705cdf0e10cSrcweir    def push( self,status ):
706cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "pythonscript: DummyProgressHandler.push " + str( status ) )
707cdf0e10cSrcweir    def update( self,status ):
708cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "pythonscript: DummyProgressHandler.update " + str( status ) )
709cdf0e10cSrcweir    def pop( self ):
710cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "pythonscript: DummyProgressHandler.push " + str( event ) )
711cdf0e10cSrcweir
712cdf0e10cSrcweirclass CommandEnvironment(unohelper.Base, XCommandEnvironment):
713cdf0e10cSrcweir    def __init__( self ):
714cdf0e10cSrcweir        self.progressHandler = DummyProgressHandler()
715cdf0e10cSrcweir        self.interactionHandler = DummyInteractionHandler()
716cdf0e10cSrcweir    def getInteractionHandler( self ):
717cdf0e10cSrcweir        return self.interactionHandler
718cdf0e10cSrcweir    def getProgressHandler( self ):
719cdf0e10cSrcweir        return self.progressHandler
720cdf0e10cSrcweir
721cdf0e10cSrcweir#maybe useful for debugging purposes
722cdf0e10cSrcweir#class ModifyListener( unohelper.Base, XModifyListener ):
723cdf0e10cSrcweir#    def __init__( self ):
724cdf0e10cSrcweir#        pass
725cdf0e10cSrcweir#    def modified( self, event ):
726cdf0e10cSrcweir#        log.isDebugLevel() and log.debug( "pythonscript: ModifyListener.modified " + str( event ) )
727cdf0e10cSrcweir#    def disposing( self, event ):
728cdf0e10cSrcweir#        log.isDebugLevel() and log.debug( "pythonscript: ModifyListener.disposing " + str( event ) )
729cdf0e10cSrcweir
730cdf0e10cSrcweirdef mapStorageType2PackageContext( storageType ):
731cdf0e10cSrcweir    ret = storageType
732cdf0e10cSrcweir    if( storageType == "share:uno_packages" ):
733cdf0e10cSrcweir        ret = "shared"
734cdf0e10cSrcweir    if( storageType == "user:uno_packages" ):
735cdf0e10cSrcweir        ret = "user"
736cdf0e10cSrcweir    return ret
737cdf0e10cSrcweir
738cdf0e10cSrcweirdef getPackageName2PathMap( sfa, storageType ):
739cdf0e10cSrcweir    ret = {}
740cdf0e10cSrcweir    packageManagerFactory = uno.getComponentContext().getValueByName(
741cdf0e10cSrcweir        "/singletons/com.sun.star.deployment.thePackageManagerFactory" )
742cdf0e10cSrcweir    packageManager = packageManagerFactory.getPackageManager(
743cdf0e10cSrcweir        mapStorageType2PackageContext(storageType))
744cdf0e10cSrcweir#    packageManager.addModifyListener( ModifyListener() )
745cdf0e10cSrcweir    log.isDebugLevel() and log.debug( "pythonscript: getPackageName2PathMap start getDeployedPackages" )
746cdf0e10cSrcweir    packages = packageManager.getDeployedPackages(
747cdf0e10cSrcweir        packageManager.createAbortChannel(), CommandEnvironment( ) )
748cdf0e10cSrcweir    log.isDebugLevel() and log.debug( "pythonscript: getPackageName2PathMap end getDeployedPackages (" + str(len(packages))+")" )
749cdf0e10cSrcweir
750cdf0e10cSrcweir    for i in packages:
751cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "inspecting package " + i.Name + "("+i.Identifier.Value+")" )
752cdf0e10cSrcweir        transientPathElement = penultimateElement( i.URL )
753cdf0e10cSrcweir        j = expandUri( i.URL )
754cdf0e10cSrcweir        pathes = getPathesFromPackage( j, sfa )
755cdf0e10cSrcweir        if len( pathes ) > 0:
756cdf0e10cSrcweir            # map package name to url, we need this later
757cdf0e10cSrcweir            log.isErrorLevel() and log.error( "adding Package " + transientPathElement + " " + str( pathes ) )
758cdf0e10cSrcweir            ret[ lastElement( j ) ] = Package( pathes, transientPathElement )
759cdf0e10cSrcweir    return ret
760cdf0e10cSrcweir
761cdf0e10cSrcweirdef penultimateElement( aStr ):
762cdf0e10cSrcweir    lastSlash = aStr.rindex("/")
763cdf0e10cSrcweir    penultimateSlash = aStr.rindex("/",0,lastSlash-1)
764cdf0e10cSrcweir    return  aStr[ penultimateSlash+1:lastSlash ]
765cdf0e10cSrcweir
766cdf0e10cSrcweirdef lastElement( aStr):
767cdf0e10cSrcweir    return aStr[ aStr.rfind( "/" )+1:len(aStr)]
768cdf0e10cSrcweir
769cdf0e10cSrcweirclass PackageBrowseNode( unohelper.Base, XBrowseNode ):
770cdf0e10cSrcweir    def __init__( self, provCtx, name, rootUrl ):
771cdf0e10cSrcweir        self.provCtx = provCtx
772cdf0e10cSrcweir        self.name = name
773cdf0e10cSrcweir        self.rootUrl = rootUrl
774cdf0e10cSrcweir
775cdf0e10cSrcweir    def getName( self ):
776cdf0e10cSrcweir        return self.name
777cdf0e10cSrcweir
778cdf0e10cSrcweir    def getChildNodes( self ):
779cdf0e10cSrcweir        items = self.provCtx.mapPackageName2Path.items()
780cdf0e10cSrcweir        browseNodeList = []
781cdf0e10cSrcweir        for i in items:
782cdf0e10cSrcweir            if len( i[1].pathes ) == 1:
783cdf0e10cSrcweir                browseNodeList.append(
784cdf0e10cSrcweir                    DirBrowseNode( self.provCtx, i[0], i[1].pathes[0] ))
785cdf0e10cSrcweir            else:
786cdf0e10cSrcweir                for j in i[1].pathes:
787cdf0e10cSrcweir                    browseNodeList.append(
788cdf0e10cSrcweir                        DirBrowseNode( self.provCtx, i[0]+"."+lastElement(j), j ) )
789cdf0e10cSrcweir        return tuple( browseNodeList )
790cdf0e10cSrcweir
791cdf0e10cSrcweir    def hasChildNodes( self ):
792cdf0e10cSrcweir        return len( self.mapPackageName2Path ) > 0
793cdf0e10cSrcweir
794cdf0e10cSrcweir    def getType( self ):
795cdf0e10cSrcweir        return CONTAINER
796cdf0e10cSrcweir
797cdf0e10cSrcweir    def getScript( self, uri ):
798cdf0e10cSrcweir        log.debug( "DirBrowseNode getScript " + uri + " invoked" )
799cdf0e10cSrcweir        raise IllegalArgumentException( "PackageBrowseNode couldn't instantiate script " + uri , self , 0 )
800cdf0e10cSrcweir
801cdf0e10cSrcweir
802cdf0e10cSrcweir
803cdf0e10cSrcweir
804cdf0e10cSrcweirclass PythonScript( unohelper.Base, XScript ):
805cdf0e10cSrcweir    def __init__( self, func, mod ):
806cdf0e10cSrcweir        self.func = func
807cdf0e10cSrcweir        self.mod = mod
808cdf0e10cSrcweir    def invoke(self, args, out, outindex ):
809cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "PythonScript.invoke " + str( args ) )
810cdf0e10cSrcweir        try:
811cdf0e10cSrcweir            ret = self.func( *args )
812cdf0e10cSrcweir        except UnoException,e:
813cdf0e10cSrcweir            # UNO Exception continue to fly ...
814cdf0e10cSrcweir            text = lastException2String()
815cdf0e10cSrcweir            complete = "Error during invoking function " + \
816cdf0e10cSrcweir                str(self.func.__name__) + " in module " + \
817cdf0e10cSrcweir                self.mod.__file__ + " (" + text + ")"
818cdf0e10cSrcweir            log.isDebugLevel() and log.debug( complete )
819cdf0e10cSrcweir            # some people may beat me up for modifying the exception text,
820cdf0e10cSrcweir            # but otherwise office just shows
821cdf0e10cSrcweir            # the type name and message text with no more information,
822cdf0e10cSrcweir            # this is really bad for most users.
823cdf0e10cSrcweir            e.Message = e.Message + " (" + complete + ")"
824cdf0e10cSrcweir            raise
825cdf0e10cSrcweir        except Exception,e:
826cdf0e10cSrcweir            # General python exception are converted to uno RuntimeException
827cdf0e10cSrcweir            text = lastException2String()
828cdf0e10cSrcweir            complete = "Error during invoking function " + \
829cdf0e10cSrcweir                str(self.func.__name__) + " in module " + \
830cdf0e10cSrcweir                self.mod.__file__ + " (" + text + ")"
831cdf0e10cSrcweir            log.isDebugLevel() and log.debug( complete )
832cdf0e10cSrcweir            raise RuntimeException( complete , self )
833cdf0e10cSrcweir        log.isDebugLevel() and log.debug( "PythonScript.invoke ret = " + str( ret ) )
834cdf0e10cSrcweir        return ret, (), ()
835cdf0e10cSrcweir
836cdf0e10cSrcweirdef expandUri(  uri ):
837cdf0e10cSrcweir    if uri.startswith( "vnd.sun.star.expand:" ):
838cdf0e10cSrcweir        uri = uri.replace( "vnd.sun.star.expand:", "",1)
839cdf0e10cSrcweir        uri = uno.getComponentContext().getByName(
840cdf0e10cSrcweir                    "/singletons/com.sun.star.util.theMacroExpander" ).expandMacros( uri )
841cdf0e10cSrcweir    if uri.startswith( "file:" ):
842cdf0e10cSrcweir        uri = uno.absolutize("",uri)   # necessary to get rid of .. in uri
843cdf0e10cSrcweir    return uri
844cdf0e10cSrcweir
845cdf0e10cSrcweir#--------------------------------------------------------------
846cdf0e10cSrcweirclass PythonScriptProvider( unohelper.Base, XBrowseNode, XScriptProvider, XNameContainer):
847cdf0e10cSrcweir    def __init__( self, ctx, *args ):
848cdf0e10cSrcweir        if log.isDebugLevel():
849cdf0e10cSrcweir            mystr = ""
850cdf0e10cSrcweir            for i in args:
851cdf0e10cSrcweir                if len(mystr) > 0:
852cdf0e10cSrcweir                    mystr = mystr +","
853cdf0e10cSrcweir                mystr = mystr + str(i)
854cdf0e10cSrcweir            log.debug( "Entering PythonScriptProvider.ctor" + mystr )
855cdf0e10cSrcweir
856cdf0e10cSrcweir        storageType = ""
857cdf0e10cSrcweir        if isinstance(args[0],unicode ):
858cdf0e10cSrcweir            storageType = args[0]
859cdf0e10cSrcweir        else:
860cdf0e10cSrcweir            storageType = args[0].SCRIPTING_DOC_URI
861cdf0e10cSrcweir        isPackage = storageType.endswith( ":uno_packages" )
862cdf0e10cSrcweir
863cdf0e10cSrcweir        try:
864cdf0e10cSrcweir#            urlHelper = ctx.ServiceManager.createInstanceWithArgumentsAndContext(
865cdf0e10cSrcweir#                "com.sun.star.script.provider.ScriptURIHelper", (LANGUAGENAME, storageType), ctx)
866cdf0e10cSrcweir            urlHelper = MyUriHelper( ctx, storageType )
867cdf0e10cSrcweir            log.isDebugLevel() and log.debug( "got urlHelper " + str( urlHelper ) )
868cdf0e10cSrcweir
869cdf0e10cSrcweir            rootUrl = expandUri( urlHelper.getRootStorageURI() )
870cdf0e10cSrcweir            log.isDebugLevel() and log.debug( storageType + " transformed to " + rootUrl )
871cdf0e10cSrcweir
872cdf0e10cSrcweir            ucbService = "com.sun.star.ucb.SimpleFileAccess"
873cdf0e10cSrcweir            sfa = ctx.ServiceManager.createInstanceWithContext( ucbService, ctx )
874cdf0e10cSrcweir            if not sfa:
875cdf0e10cSrcweir                log.debug("PythonScriptProvider couldn't instantiate " +ucbService)
876cdf0e10cSrcweir                raise RuntimeException(
877cdf0e10cSrcweir                    "PythonScriptProvider couldn't instantiate " +ucbService, self)
878cdf0e10cSrcweir            self.provCtx = ProviderContext(
879cdf0e10cSrcweir                storageType, sfa, urlHelper, ScriptContext( uno.getComponentContext(), None ) )
880cdf0e10cSrcweir            if isPackage:
881cdf0e10cSrcweir                mapPackageName2Path = getPackageName2PathMap( sfa, storageType )
882cdf0e10cSrcweir                self.provCtx.setPackageAttributes( mapPackageName2Path , rootUrl )
883cdf0e10cSrcweir                self.dirBrowseNode = PackageBrowseNode( self.provCtx, LANGUAGENAME, rootUrl )
884cdf0e10cSrcweir            else:
885cdf0e10cSrcweir                self.dirBrowseNode = DirBrowseNode( self.provCtx, LANGUAGENAME, rootUrl )
886cdf0e10cSrcweir
887cdf0e10cSrcweir        except Exception, e:
888cdf0e10cSrcweir            text = lastException2String()
889cdf0e10cSrcweir            log.debug( "PythonScriptProvider could not be instantiated because of : " + text )
890cdf0e10cSrcweir            raise e
891cdf0e10cSrcweir
892cdf0e10cSrcweir    def getName( self ):
893cdf0e10cSrcweir        return self.dirBrowseNode.getName()
894cdf0e10cSrcweir
895cdf0e10cSrcweir    def getChildNodes( self ):
896cdf0e10cSrcweir        return self.dirBrowseNode.getChildNodes()
897cdf0e10cSrcweir
898cdf0e10cSrcweir    def hasChildNodes( self ):
899cdf0e10cSrcweir        return self.dirBrowseNode.hasChildNodes()
900cdf0e10cSrcweir
901cdf0e10cSrcweir    def getType( self ):
902cdf0e10cSrcweir        return self.dirBrowseNode.getType()
903cdf0e10cSrcweir
904cdf0e10cSrcweir    def getScript( self, uri ):
905cdf0e10cSrcweir        log.debug( "DirBrowseNode getScript " + uri + " invoked" )
906cdf0e10cSrcweir
907cdf0e10cSrcweir        raise IllegalArgumentException( "DirBrowseNode couldn't instantiate script " + uri , self , 0 )
908cdf0e10cSrcweir
909cdf0e10cSrcweir    def getScript( self, scriptUri ):
910cdf0e10cSrcweir        try:
911cdf0e10cSrcweir            log.isDebugLevel() and log.debug( "getScript " + scriptUri + " invoked")
912cdf0e10cSrcweir
913cdf0e10cSrcweir            storageUri = self.provCtx.getStorageUrlFromPersistentUrl(
914cdf0e10cSrcweir                self.provCtx.uriHelper.getStorageURI(scriptUri) );
915cdf0e10cSrcweir            log.isDebugLevel() and log.debug( "getScript: storageUri = " + storageUri)
916cdf0e10cSrcweir            fileUri = storageUri[0:storageUri.find( "$" )]
917cdf0e10cSrcweir            funcName = storageUri[storageUri.find( "$" )+1:len(storageUri)]
918cdf0e10cSrcweir
919cdf0e10cSrcweir            mod = self.provCtx.getModuleByUrl( fileUri )
920cdf0e10cSrcweir            log.isDebugLevel() and log.debug( " got mod " + str(mod) )
921cdf0e10cSrcweir
922cdf0e10cSrcweir            func = mod.__dict__[ funcName ]
923cdf0e10cSrcweir
924cdf0e10cSrcweir            log.isDebugLevel() and log.debug( "got func " + str( func ) )
925cdf0e10cSrcweir            return PythonScript( func, mod )
926cdf0e10cSrcweir        except Exception, e:
927cdf0e10cSrcweir            text = lastException2String()
928cdf0e10cSrcweir            log.error( text )
929cdf0e10cSrcweir            raise ScriptFrameworkErrorException( text, self, scriptUri, LANGUAGENAME, 0 )
930cdf0e10cSrcweir
931cdf0e10cSrcweir
932cdf0e10cSrcweir    # XServiceInfo
933cdf0e10cSrcweir    def getSupportedServices( self ):
934cdf0e10cSrcweir        return g_ImplementationHelper.getSupportedServices(g_implName)
935cdf0e10cSrcweir
936cdf0e10cSrcweir    def supportsService( self, ServiceName ):
937cdf0e10cSrcweir        return g_ImplementationHelper.supportsService( g_implName, ServiceName )
938cdf0e10cSrcweir
939cdf0e10cSrcweir    def getImplementationName(self):
940cdf0e10cSrcweir        return g_implName
941cdf0e10cSrcweir
942cdf0e10cSrcweir    def getByName( self, name ):
943cdf0e10cSrcweir        log.debug( "getByName called" + str( name ))
944cdf0e10cSrcweir        return None
945cdf0e10cSrcweir
946cdf0e10cSrcweir
947cdf0e10cSrcweir    def getElementNames( self ):
948cdf0e10cSrcweir        log.debug( "getElementNames called")
949cdf0e10cSrcweir        return ()
950cdf0e10cSrcweir
951cdf0e10cSrcweir    def hasByName( self, name ):
952cdf0e10cSrcweir        try:
953cdf0e10cSrcweir            log.debug( "hasByName called " + str( name ))
954cdf0e10cSrcweir            uri = expandUri(name)
955cdf0e10cSrcweir            ret = self.provCtx.isUrlInPackage( uri )
956cdf0e10cSrcweir            log.debug( "hasByName " + uri + " " +str( ret ) )
957cdf0e10cSrcweir            return ret
958cdf0e10cSrcweir        except Exception, e:
959cdf0e10cSrcweir            text = lastException2String()
960cdf0e10cSrcweir            log.debug( "Error in hasByName:" +  text )
961cdf0e10cSrcweir            return False
962cdf0e10cSrcweir
963cdf0e10cSrcweir    def removeByName( self, name ):
964cdf0e10cSrcweir        log.debug( "removeByName called" + str( name ))
965cdf0e10cSrcweir        uri = expandUri( name )
966cdf0e10cSrcweir        if self.provCtx.isUrlInPackage( uri ):
967cdf0e10cSrcweir            self.provCtx.removePackageByUrl( uri )
968cdf0e10cSrcweir        else:
969cdf0e10cSrcweir            log.debug( "removeByName unknown uri " + str( name ) + ", ignoring" )
970cdf0e10cSrcweir            raise NoSuchElementException( uri + "is not in package" , self )
971cdf0e10cSrcweir        log.debug( "removeByName called" + str( uri ) + " successful" )
972cdf0e10cSrcweir
973cdf0e10cSrcweir    def insertByName( self, name, value ):
974cdf0e10cSrcweir        log.debug( "insertByName called " + str( name ) + " " + str( value ))
975cdf0e10cSrcweir        uri = expandUri( name )
976cdf0e10cSrcweir        if isPyFileInPath( self.provCtx.sfa, uri ):
977cdf0e10cSrcweir            self.provCtx.addPackageByUrl( uri )
978cdf0e10cSrcweir        else:
979cdf0e10cSrcweir            # package is no python package ...
980cdf0e10cSrcweir            log.debug( "insertByName: no python files in " + str( uri ) + ", ignoring" )
981cdf0e10cSrcweir            raise IllegalArgumentException( uri + " does not contain .py files", self, 1 )
982cdf0e10cSrcweir        log.debug( "insertByName called " + str( uri ) + " successful" )
983cdf0e10cSrcweir
984cdf0e10cSrcweir    def replaceByName( self, name, value ):
985cdf0e10cSrcweir        log.debug( "replaceByName called " + str( name ) + " " + str( value ))
986cdf0e10cSrcweir        removeByName( name )
987cdf0e10cSrcweir        insertByName( name )
988cdf0e10cSrcweir        log.debug( "replaceByName called" + str( uri ) + " successful" )
989cdf0e10cSrcweir
990cdf0e10cSrcweir    def getElementType( self ):
991cdf0e10cSrcweir        log.debug( "getElementType called" )
992cdf0e10cSrcweir        return uno.getTypeByName( "void" )
993cdf0e10cSrcweir
994cdf0e10cSrcweir    def hasElements( self ):
995cdf0e10cSrcweir        log.debug( "hasElements got called")
996cdf0e10cSrcweir        return False
997cdf0e10cSrcweir
998cdf0e10cSrcweirg_ImplementationHelper.addImplementation( \
999cdf0e10cSrcweir	PythonScriptProvider,g_implName, \
1000cdf0e10cSrcweir    ("com.sun.star.script.provider.LanguageScriptProvider",
1001cdf0e10cSrcweir     "com.sun.star.script.provider.ScriptProviderFor"+ LANGUAGENAME,),)
1002cdf0e10cSrcweir
1003cdf0e10cSrcweir
1004cdf0e10cSrcweirlog.debug( "pythonscript finished intializing" )
1005cdf0e10cSrcweir
1006