19f22d7c2SAndrew Rist# ************************************************************* 29f22d7c2SAndrew Rist# 39f22d7c2SAndrew Rist# Licensed to the Apache Software Foundation (ASF) under one 49f22d7c2SAndrew Rist# or more contributor license agreements. See the NOTICE file 59f22d7c2SAndrew Rist# distributed with this work for additional information 69f22d7c2SAndrew Rist# regarding copyright ownership. The ASF licenses this file 79f22d7c2SAndrew Rist# to you under the Apache License, Version 2.0 (the 89f22d7c2SAndrew Rist# "License"); you may not use this file except in compliance 99f22d7c2SAndrew Rist# with the License. You may obtain a copy of the License at 109f22d7c2SAndrew Rist# 119f22d7c2SAndrew Rist# http://www.apache.org/licenses/LICENSE-2.0 129f22d7c2SAndrew Rist# 139f22d7c2SAndrew Rist# Unless required by applicable law or agreed to in writing, 149f22d7c2SAndrew Rist# software distributed under the License is distributed on an 159f22d7c2SAndrew Rist# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 169f22d7c2SAndrew Rist# KIND, either express or implied. See the License for the 179f22d7c2SAndrew Rist# specific language governing permissions and limitations 189f22d7c2SAndrew Rist# under the License. 199f22d7c2SAndrew Rist# 209f22d7c2SAndrew Rist# ************************************************************* 219f22d7c2SAndrew Rist 22cdf0e10cSrcweir# XScript implementation for python 23cdf0e10cSrcweirimport uno 24cdf0e10cSrcweirimport unohelper 25cdf0e10cSrcweirimport sys 26cdf0e10cSrcweirimport os 27cdf0e10cSrcweirimport imp 28cdf0e10cSrcweirimport time 2913cfd8dfSPedro Giffuniimport ast 30cdf0e10cSrcweir 3115745147SPedro Giffunitry: 3215745147SPedro Giffuni unicode 3315745147SPedro Giffuniexcept NameError: 3415745147SPedro Giffuni unicode = str 3515745147SPedro Giffuni 36cdf0e10cSrcweirclass LogLevel: 37*b5f289e3SHerbert Dürr NONE = 0 # production level 38*b5f289e3SHerbert Dürr ERROR = 1 # for script developers 39*b5f289e3SHerbert Dürr DEBUG = 2 # for script framework developers 40*b5f289e3SHerbert Dürr 41*b5f289e3SHerbert DürrPYSCRIPT_LOG_ENV = "PYSCRIPT_LOG_LEVEL" 42*b5f289e3SHerbert DürrPYSCRIPT_LOG_STDOUT_ENV = "PYSCRIPT_LOG_STDOUT" 43cdf0e10cSrcweir 44cdf0e10cSrcweir# Configuration ---------------------------------------------------- 45*b5f289e3SHerbert DürrLogLevel.use = LogLevel.NONE 46*b5f289e3SHerbert Dürrif os.environ.get(PYSCRIPT_LOG_ENV) == "ERROR": 47*b5f289e3SHerbert Dürr LogLevel.use = LogLevel.ERROR 48*b5f289e3SHerbert Dürrelif os.environ.get(PYSCRIPT_LOG_ENV) == "DEBUG": 49*b5f289e3SHerbert Dürr LogLevel.use = LogLevel.DEBUG 50*b5f289e3SHerbert Dürr 51*b5f289e3SHerbert Dürr# True, writes to stdout (difficult on windows) 52*b5f289e3SHerbert Dürr# False, writes to user/Scripts/python/log.txt 53*b5f289e3SHerbert DürrLOG_STDOUT = os.environ.get(PYSCRIPT_LOG_STDOUT_ENV, "1") != "0" 54*b5f289e3SHerbert Dürr 55cdf0e10cSrcweirENABLE_EDIT_DIALOG=False # offers a minimal editor for editing. 56cdf0e10cSrcweir#------------------------------------------------------------------- 57cdf0e10cSrcweir 58cdf0e10cSrcweirdef encfile(uni): 59cdf0e10cSrcweir return uni.encode( sys.getfilesystemencoding()) 60cdf0e10cSrcweir 61cdf0e10cSrcweirdef lastException2String(): 62cdf0e10cSrcweir (excType,excInstance,excTraceback) = sys.exc_info() 63cdf0e10cSrcweir ret = str(excType) + ": "+str(excInstance) + "\n" + \ 64cdf0e10cSrcweir uno._uno_extract_printable_stacktrace( excTraceback ) 65cdf0e10cSrcweir return ret 66cdf0e10cSrcweir 67cdf0e10cSrcweirdef logLevel2String( level ): 68cdf0e10cSrcweir ret = " NONE" 69cdf0e10cSrcweir if level == LogLevel.ERROR: 70cdf0e10cSrcweir ret = "ERROR" 71cdf0e10cSrcweir elif level >= LogLevel.DEBUG: 72cdf0e10cSrcweir ret = "DEBUG" 73cdf0e10cSrcweir return ret 74cdf0e10cSrcweir 75cdf0e10cSrcweirdef getLogTarget(): 76cdf0e10cSrcweir ret = sys.stdout 77cdf0e10cSrcweir if not LOG_STDOUT: 78cdf0e10cSrcweir try: 79cdf0e10cSrcweir pathSubst = uno.getComponentContext().ServiceManager.createInstance( 80cdf0e10cSrcweir "com.sun.star.util.PathSubstitution" ) 81cdf0e10cSrcweir userInstallation = pathSubst.getSubstituteVariableValue( "user" ) 82cdf0e10cSrcweir if len( userInstallation ) > 0: 83cdf0e10cSrcweir systemPath = uno.fileUrlToSystemPath( userInstallation + "/Scripts/python/log.txt" ) 84cdf0e10cSrcweir ret = file( systemPath , "a" ) 8515745147SPedro Giffuni except Exception as e: 8615745147SPedro Giffuni print("Exception during creation of pythonscript logfile: "+ lastException2String() + "\n, delagating log to stdout\n") 87cdf0e10cSrcweir return ret 8813cfd8dfSPedro Giffuni 89cdf0e10cSrcweirclass Logger(LogLevel): 90cdf0e10cSrcweir def __init__(self , target ): 91cdf0e10cSrcweir self.target = target 92cdf0e10cSrcweir 93cdf0e10cSrcweir def isDebugLevel( self ): 94cdf0e10cSrcweir return self.use >= self.DEBUG 9513cfd8dfSPedro Giffuni 96cdf0e10cSrcweir def debug( self, msg ): 97cdf0e10cSrcweir if self.isDebugLevel(): 98cdf0e10cSrcweir self.log( self.DEBUG, msg ) 9913cfd8dfSPedro Giffuni 100cdf0e10cSrcweir def isErrorLevel( self ): 101cdf0e10cSrcweir return self.use >= self.ERROR 102cdf0e10cSrcweir 103cdf0e10cSrcweir def error( self, msg ): 104cdf0e10cSrcweir if self.isErrorLevel(): 105cdf0e10cSrcweir self.log( self.ERROR, msg ) 106cdf0e10cSrcweir 107cdf0e10cSrcweir def log( self, level, msg ): 108cdf0e10cSrcweir if self.use >= level: 109cdf0e10cSrcweir try: 110cdf0e10cSrcweir self.target.write( 111cdf0e10cSrcweir time.asctime() + 112cdf0e10cSrcweir " [" + 113cdf0e10cSrcweir logLevel2String( level ) + 114cdf0e10cSrcweir "] " + 115cdf0e10cSrcweir encfile(msg) + 116cdf0e10cSrcweir "\n" ) 117cdf0e10cSrcweir self.target.flush() 11815745147SPedro Giffuni except Exception as e: 11915745147SPedro Giffuni print("Error during writing to stdout: " +lastException2String() + "\n") 120cdf0e10cSrcweir 121cdf0e10cSrcweirlog = Logger( getLogTarget() ) 122cdf0e10cSrcweir 123cdf0e10cSrcweirlog.debug( "pythonscript loading" ) 124cdf0e10cSrcweir 125cdf0e10cSrcweir#from com.sun.star.lang import typeOfXServiceInfo, typeOfXTypeProvider 126cdf0e10cSrcweirfrom com.sun.star.uno import RuntimeException 127cdf0e10cSrcweirfrom com.sun.star.lang import XServiceInfo 128cdf0e10cSrcweirfrom com.sun.star.io import IOException 12961c9e2f8SAriel Constenla-Hailefrom com.sun.star.ucb import CommandAbortedException, XCommandEnvironment, XProgressHandler, Command 130cdf0e10cSrcweirfrom com.sun.star.task import XInteractionHandler 13161c9e2f8SAriel Constenla-Hailefrom com.sun.star.beans import XPropertySet, Property 132cdf0e10cSrcweirfrom com.sun.star.container import XNameContainer 133cdf0e10cSrcweirfrom com.sun.star.xml.sax import XDocumentHandler, InputSource 134cdf0e10cSrcweirfrom com.sun.star.uno import Exception as UnoException 135cdf0e10cSrcweirfrom com.sun.star.script import XInvocation 136cdf0e10cSrcweirfrom com.sun.star.awt import XActionListener 137cdf0e10cSrcweir 138cdf0e10cSrcweirfrom com.sun.star.script.provider import XScriptProvider, XScript, XScriptContext, ScriptFrameworkErrorException 139cdf0e10cSrcweirfrom com.sun.star.script.browse import XBrowseNode 140cdf0e10cSrcweirfrom com.sun.star.script.browse.BrowseNodeTypes import SCRIPT, CONTAINER, ROOT 141cdf0e10cSrcweirfrom com.sun.star.util import XModifyListener 142cdf0e10cSrcweir 143cdf0e10cSrcweirLANGUAGENAME = "Python" 144cdf0e10cSrcweirGLOBAL_SCRIPTCONTEXT_NAME = "XSCRIPTCONTEXT" 145cdf0e10cSrcweirCALLABLE_CONTAINER_NAME = "g_exportedScripts" 146cdf0e10cSrcweir 147cdf0e10cSrcweir# pythonloader looks for a static g_ImplementationHelper variable 148cdf0e10cSrcweirg_ImplementationHelper = unohelper.ImplementationHelper() 149cdf0e10cSrcweirg_implName = "org.openoffice.pyuno.LanguageScriptProviderFor"+LANGUAGENAME 150cdf0e10cSrcweir 151cdf0e10cSrcweir 152cdf0e10cSrcweir 153cdf0e10cSrcweirBLOCK_SIZE = 65536 154cdf0e10cSrcweirdef readTextFromStream( inputStream ): 155cdf0e10cSrcweir # read the file 156cdf0e10cSrcweir code = uno.ByteSequence( "" ) 157cdf0e10cSrcweir while True: 158cdf0e10cSrcweir read,out = inputStream.readBytes( None , BLOCK_SIZE ) 159cdf0e10cSrcweir code = code + out 160cdf0e10cSrcweir if read < BLOCK_SIZE: 16113cfd8dfSPedro Giffuni break 162cdf0e10cSrcweir return code.value 16313cfd8dfSPedro Giffuni 164cdf0e10cSrcweirdef toIniName( str ): 165cdf0e10cSrcweir # TODO: what is the official way to get to know whether i am on the windows platform ? 166cdf0e10cSrcweir if( hasattr(sys , "dllhandle") ): 167cdf0e10cSrcweir return str + ".ini" 168cdf0e10cSrcweir return str + "rc" 169cdf0e10cSrcweir 170cdf0e10cSrcweir 171cdf0e10cSrcweir""" definition: storageURI is the system dependent, absolute file url, where the script is stored on disk 172cdf0e10cSrcweir scriptURI is the system independent uri 173cdf0e10cSrcweir""" 174cdf0e10cSrcweirclass MyUriHelper: 175cdf0e10cSrcweir 176cdf0e10cSrcweir def __init__( self, ctx, location ): 177cdf0e10cSrcweir self.s_UriMap = \ 178910823aeSJürgen Schmidt { "share" : "vnd.sun.star.expand:${$OOO_BASE_DIR/program/" + toIniName( "bootstrap") + "::BaseInstallation}/share/Scripts/python" , \ 179cdf0e10cSrcweir "share:uno_packages" : "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/uno_packages", \ 180910823aeSJürgen Schmidt "user" : "vnd.sun.star.expand:${$OOO_BASE_DIR/program/" + toIniName( "bootstrap") + "::UserInstallation}/user/Scripts/python" , \ 18113cfd8dfSPedro Giffuni "user:uno_packages" : "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages" } 182cdf0e10cSrcweir self.m_uriRefFac = ctx.ServiceManager.createInstanceWithContext("com.sun.star.uri.UriReferenceFactory",ctx) 183cdf0e10cSrcweir if location.startswith( "vnd.sun.star.tdoc" ): 184cdf0e10cSrcweir self.m_baseUri = location + "/Scripts/python" 185cdf0e10cSrcweir self.m_scriptUriLocation = "document" 186cdf0e10cSrcweir else: 187cdf0e10cSrcweir self.m_baseUri = expandUri( self.s_UriMap[location] ) 188cdf0e10cSrcweir self.m_scriptUriLocation = location 189735dd73bSPedro Giffuni log.debug( "initialized urihelper with baseUri="+self.m_baseUri + ",m_scriptUriLocation="+self.m_scriptUriLocation ) 19013cfd8dfSPedro Giffuni 191cdf0e10cSrcweir def getRootStorageURI( self ): 192cdf0e10cSrcweir return self.m_baseUri 19313cfd8dfSPedro Giffuni 194cdf0e10cSrcweir def getStorageURI( self, scriptURI ): 195cdf0e10cSrcweir return self.scriptURI2StorageUri(scriptURI) 196cdf0e10cSrcweir 197cdf0e10cSrcweir def getScriptURI( self, storageURI ): 198cdf0e10cSrcweir return self.storageURI2ScriptUri(storageURI) 199cdf0e10cSrcweir 200cdf0e10cSrcweir def storageURI2ScriptUri( self, storageURI ): 201cdf0e10cSrcweir if not storageURI.startswith( self.m_baseUri ): 202cdf0e10cSrcweir message = "pythonscript: storage uri '" + storageURI + "' not in base uri '" + self.m_baseUri + "'" 203735dd73bSPedro Giffuni log.debug( message ) 204cdf0e10cSrcweir raise RuntimeException( message ) 205cdf0e10cSrcweir 206cdf0e10cSrcweir ret = "vnd.sun.star.script:" + \ 207cdf0e10cSrcweir storageURI[len(self.m_baseUri)+1:].replace("/","|") + \ 208cdf0e10cSrcweir "?language=" + LANGUAGENAME + "&location=" + self.m_scriptUriLocation 209735dd73bSPedro Giffuni log.debug( "converting storageURI="+storageURI + " to scriptURI=" + ret ) 210cdf0e10cSrcweir return ret 21113cfd8dfSPedro Giffuni 212cdf0e10cSrcweir def scriptURI2StorageUri( self, scriptURI ): 213cdf0e10cSrcweir try: 214cdf0e10cSrcweir myUri = self.m_uriRefFac.parse(scriptURI) 215cdf0e10cSrcweir ret = self.m_baseUri + "/" + myUri.getName().replace( "|", "/" ) 216735dd73bSPedro Giffuni log.debug( "converting scriptURI="+scriptURI + " to storageURI=" + ret ) 217cdf0e10cSrcweir return ret 21815745147SPedro Giffuni except UnoException as e: 219cdf0e10cSrcweir log.error( "error during converting scriptURI="+scriptURI + ": " + e.Message) 220cdf0e10cSrcweir raise RuntimeException( "pythonscript:scriptURI2StorageUri: " +e.getMessage(), None ) 22115745147SPedro Giffuni except Exception as e: 222cdf0e10cSrcweir log.error( "error during converting scriptURI="+scriptURI + ": " + str(e)) 223cdf0e10cSrcweir raise RuntimeException( "pythonscript:scriptURI2StorageUri: " + str(e), None ) 22413cfd8dfSPedro Giffuni 225cdf0e10cSrcweir 226cdf0e10cSrcweirclass ModuleEntry: 227cdf0e10cSrcweir def __init__( self, lastRead, module ): 228cdf0e10cSrcweir self.lastRead = lastRead 229cdf0e10cSrcweir self.module = module 230cdf0e10cSrcweir 231cdf0e10cSrcweirdef hasChanged( oldDate, newDate ): 232cdf0e10cSrcweir return newDate.Year > oldDate.Year or \ 233cdf0e10cSrcweir newDate.Month > oldDate.Month or \ 234cdf0e10cSrcweir newDate.Day > oldDate.Day or \ 235cdf0e10cSrcweir newDate.Hours > oldDate.Hours or \ 236cdf0e10cSrcweir newDate.Minutes > oldDate.Minutes or \ 237cdf0e10cSrcweir newDate.Seconds > oldDate.Seconds or \ 238cdf0e10cSrcweir newDate.HundredthSeconds > oldDate.HundredthSeconds 239cdf0e10cSrcweir 240cdf0e10cSrcweirdef ensureSourceState( code ): 241cdf0e10cSrcweir if not code.endswith( "\n" ): 242cdf0e10cSrcweir code = code + "\n" 243cdf0e10cSrcweir code = code.replace( "\r", "" ) 244cdf0e10cSrcweir return code 245cdf0e10cSrcweir 246cdf0e10cSrcweir 247cdf0e10cSrcweirdef checkForPythonPathBesideScript( url ): 248cdf0e10cSrcweir if url.startswith( "file:" ): 249cdf0e10cSrcweir path = unohelper.fileUrlToSystemPath( url+"/pythonpath.zip" ); 250cdf0e10cSrcweir log.log( LogLevel.DEBUG, "checking for existence of " + path ) 251cdf0e10cSrcweir if 1 == os.access( encfile(path), os.F_OK) and not path in sys.path: 252cdf0e10cSrcweir log.log( LogLevel.DEBUG, "adding " + path + " to sys.path" ) 253cdf0e10cSrcweir sys.path.append( path ) 254cdf0e10cSrcweir 255cdf0e10cSrcweir path = unohelper.fileUrlToSystemPath( url+"/pythonpath" ); 256cdf0e10cSrcweir log.log( LogLevel.DEBUG, "checking for existence of " + path ) 257cdf0e10cSrcweir if 1 == os.access( encfile(path), os.F_OK) and not path in sys.path: 258cdf0e10cSrcweir log.log( LogLevel.DEBUG, "adding " + path + " to sys.path" ) 259cdf0e10cSrcweir sys.path.append( path ) 26013cfd8dfSPedro Giffuni 26113cfd8dfSPedro Giffuni 262cdf0e10cSrcweirclass ScriptContext(unohelper.Base): 26361c9e2f8SAriel Constenla-Haile def __init__( self, ctx, doc, inv ): 264cdf0e10cSrcweir self.ctx = ctx 265cdf0e10cSrcweir self.doc = doc 26661c9e2f8SAriel Constenla-Haile self.inv = inv 26713cfd8dfSPedro Giffuni 268cdf0e10cSrcweir # XScriptContext 269cdf0e10cSrcweir def getDocument(self): 27061c9e2f8SAriel Constenla-Haile if self.doc: 27161c9e2f8SAriel Constenla-Haile return self.doc 272cdf0e10cSrcweir return self.getDesktop().getCurrentComponent() 273cdf0e10cSrcweir 274cdf0e10cSrcweir def getDesktop(self): 275cdf0e10cSrcweir return self.ctx.ServiceManager.createInstanceWithContext( 276cdf0e10cSrcweir "com.sun.star.frame.Desktop", self.ctx ) 277cdf0e10cSrcweir 278cdf0e10cSrcweir def getComponentContext(self): 279cdf0e10cSrcweir return self.ctx 280cdf0e10cSrcweir 28161c9e2f8SAriel Constenla-Haile def getInvocationContext(self): 28261c9e2f8SAriel Constenla-Haile return self.inv 28361c9e2f8SAriel Constenla-Haile 284cdf0e10cSrcweir#---------------------------------- 285cdf0e10cSrcweir# Global Module Administration 286cdf0e10cSrcweir# does not fit together with script 287cdf0e10cSrcweir# engine lifetime management 288cdf0e10cSrcweir#---------------------------------- 289cdf0e10cSrcweir#g_scriptContext = ScriptContext( uno.getComponentContext(), None ) 290cdf0e10cSrcweir#g_modules = {} 291cdf0e10cSrcweir#def getModuleByUrl( url, sfa ): 292cdf0e10cSrcweir# entry = g_modules.get(url) 293cdf0e10cSrcweir# load = True 294cdf0e10cSrcweir# lastRead = sfa.getDateTimeModified( url ) 295cdf0e10cSrcweir# if entry: 296cdf0e10cSrcweir# if hasChanged( entry.lastRead, lastRead ): 297735dd73bSPedro Giffuni# log.debug("file " + url + " has changed, reloading") 298cdf0e10cSrcweir# else: 299cdf0e10cSrcweir# load = False 30013cfd8dfSPedro Giffuni# 301cdf0e10cSrcweir# if load: 302735dd73bSPedro Giffuni# log.debug( "opening >" + url + "<" ) 303cdf0e10cSrcweir# 304cdf0e10cSrcweir# code = readTextFromStream( sfa.openFileRead( url ) ) 30513cfd8dfSPedro Giffuni 306cdf0e10cSrcweir # execute the module 307cdf0e10cSrcweir# entry = ModuleEntry( lastRead, imp.new_module("ooo_script_framework") ) 308cdf0e10cSrcweir# entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = g_scriptContext 309cdf0e10cSrcweir# entry.module.__file__ = url 310cdf0e10cSrcweir# exec code in entry.module.__dict__ 311cdf0e10cSrcweir# g_modules[ url ] = entry 312735dd73bSPedro Giffuni# log.debug( "mapped " + url + " to " + str( entry.module ) ) 313cdf0e10cSrcweir# return entry.module 314cdf0e10cSrcweir 315cdf0e10cSrcweirclass ProviderContext: 316cdf0e10cSrcweir def __init__( self, storageType, sfa, uriHelper, scriptContext ): 317cdf0e10cSrcweir self.storageType = storageType 318cdf0e10cSrcweir self.sfa = sfa 319cdf0e10cSrcweir self.uriHelper = uriHelper 320cdf0e10cSrcweir self.scriptContext = scriptContext 321cdf0e10cSrcweir self.modules = {} 322cdf0e10cSrcweir self.rootUrl = None 323cdf0e10cSrcweir self.mapPackageName2Path = None 324cdf0e10cSrcweir 325cdf0e10cSrcweir def getTransientPartFromUrl( self, url ): 326cdf0e10cSrcweir rest = url.replace( self.rootUrl , "",1 ).replace( "/","",1) 327cdf0e10cSrcweir return rest[0:rest.find("/")] 32813cfd8dfSPedro Giffuni 329cdf0e10cSrcweir def getPackageNameFromUrl( self, url ): 330cdf0e10cSrcweir rest = url.replace( self.rootUrl , "",1 ).replace( "/","",1) 331cdf0e10cSrcweir start = rest.find("/") +1 332cdf0e10cSrcweir return rest[start:rest.find("/",start)] 33313cfd8dfSPedro Giffuni 33413cfd8dfSPedro Giffuni 335cdf0e10cSrcweir def removePackageByUrl( self, url ): 33615745147SPedro Giffuni items = list(self.mapPackageName2Path.items()) 337cdf0e10cSrcweir for i in items: 338cdf0e10cSrcweir if url in i[1].pathes: 339cdf0e10cSrcweir self.mapPackageName2Path.pop(i[0]) 340cdf0e10cSrcweir break 341cdf0e10cSrcweir 342cdf0e10cSrcweir def addPackageByUrl( self, url ): 343cdf0e10cSrcweir packageName = self.getPackageNameFromUrl( url ) 344cdf0e10cSrcweir transientPart = self.getTransientPartFromUrl( url ) 345735dd73bSPedro Giffuni log.debug( "addPackageByUrl : " + packageName + ", " + transientPart + "("+url+")" + ", rootUrl="+self.rootUrl ) 34615745147SPedro Giffuni if packageName in self.mapPackageName2Path: 347cdf0e10cSrcweir package = self.mapPackageName2Path[ packageName ] 348cdf0e10cSrcweir package.pathes = package.pathes + (url, ) 349cdf0e10cSrcweir else: 350cdf0e10cSrcweir package = Package( (url,), transientPart) 351cdf0e10cSrcweir self.mapPackageName2Path[ packageName ] = package 35213cfd8dfSPedro Giffuni 353cdf0e10cSrcweir def isUrlInPackage( self, url ): 35415745147SPedro Giffuni values = list(self.mapPackageName2Path.values()) 355cdf0e10cSrcweir for i in values: 35613cfd8dfSPedro Giffuni# print "checking " + url + " in " + str(i.pathes) 357cdf0e10cSrcweir if url in i.pathes: 35813cfd8dfSPedro Giffuni return True 359cdf0e10cSrcweir# print "false" 360cdf0e10cSrcweir return False 36113cfd8dfSPedro Giffuni 362cdf0e10cSrcweir def setPackageAttributes( self, mapPackageName2Path, rootUrl ): 363cdf0e10cSrcweir self.mapPackageName2Path = mapPackageName2Path 364cdf0e10cSrcweir self.rootUrl = rootUrl 36513cfd8dfSPedro Giffuni 366cdf0e10cSrcweir def getPersistentUrlFromStorageUrl( self, url ): 367cdf0e10cSrcweir # package name is the second directory 368cdf0e10cSrcweir ret = url 369cdf0e10cSrcweir if self.rootUrl: 370cdf0e10cSrcweir pos = len( self.rootUrl) +1 371cdf0e10cSrcweir ret = url[0:pos]+url[url.find("/",pos)+1:len(url)] 372735dd73bSPedro Giffuni log.debug( "getPersistentUrlFromStorageUrl " + url + " -> "+ ret) 373cdf0e10cSrcweir return ret 374cdf0e10cSrcweir 375cdf0e10cSrcweir def getStorageUrlFromPersistentUrl( self, url): 376cdf0e10cSrcweir ret = url 377cdf0e10cSrcweir if self.rootUrl: 378cdf0e10cSrcweir pos = len(self.rootUrl)+1 379cdf0e10cSrcweir packageName = url[pos:url.find("/",pos+1)] 380cdf0e10cSrcweir package = self.mapPackageName2Path[ packageName ] 381cdf0e10cSrcweir ret = url[0:pos]+ package.transientPathElement + "/" + url[pos:len(url)] 382735dd73bSPedro Giffuni log.debug( "getStorageUrlFromPersistentUrl " + url + " -> "+ ret) 383cdf0e10cSrcweir return ret 384cdf0e10cSrcweir 385cdf0e10cSrcweir def getFuncsByUrl( self, url ): 386cdf0e10cSrcweir src = readTextFromStream( self.sfa.openFileRead( url ) ) 387cdf0e10cSrcweir checkForPythonPathBesideScript( url[0:url.rfind('/')] ) 388cdf0e10cSrcweir src = ensureSourceState( src ) 389cdf0e10cSrcweir 390cdf0e10cSrcweir allFuncs = [] 391cdf0e10cSrcweir g_exportedScripts = [] 392cdf0e10cSrcweir 39313cfd8dfSPedro Giffuni a = ast.parse(src, url) 39413cfd8dfSPedro Giffuni 39513cfd8dfSPedro Giffuni if isinstance(a, ast.Module): 39613cfd8dfSPedro Giffuni for node in a.body: 39713cfd8dfSPedro Giffuni if isinstance(node, ast.FunctionDef): 39813cfd8dfSPedro Giffuni allFuncs.append(node.name) 39913cfd8dfSPedro Giffuni elif isinstance(node, ast.Assign): 40013cfd8dfSPedro Giffuni is_exported = False 40113cfd8dfSPedro Giffuni for subnode in node.targets: 40213cfd8dfSPedro Giffuni if isinstance(subnode, ast.Name) and \ 40313cfd8dfSPedro Giffuni subnode.id == "g_exportedScripts": 40413cfd8dfSPedro Giffuni is_exported = True 40513cfd8dfSPedro Giffuni break 40613cfd8dfSPedro Giffuni if is_exported: 40713cfd8dfSPedro Giffuni value_node = node.value 40813cfd8dfSPedro Giffuni if isinstance(value_node, ast.List) or \ 40913cfd8dfSPedro Giffuni isinstance(value_node, ast.Tuple): 41013cfd8dfSPedro Giffuni for elt in value_node.elts: 41113cfd8dfSPedro Giffuni if isinstance(elt, ast.Str): 41213cfd8dfSPedro Giffuni g_exportedScripts.append(elt.s) 41313cfd8dfSPedro Giffuni elif isinstance(elt, ast.Name): 41413cfd8dfSPedro Giffuni g_exportedScripts.append(elt.id) 41513cfd8dfSPedro Giffuni elif isinstance(value_node, ast.Str): 41613cfd8dfSPedro Giffuni g_exportedScripts.append(value_node.s) 41713cfd8dfSPedro Giffuni elif isinstance(value_node, ast.Name): 41813cfd8dfSPedro Giffuni g_exportedScripts.append(value_node.id) 41913cfd8dfSPedro Giffuni return g_exportedScripts 420cdf0e10cSrcweir return allFuncs 42113cfd8dfSPedro Giffuni 422cdf0e10cSrcweir def getModuleByUrl( self, url ): 423cdf0e10cSrcweir entry = self.modules.get(url) 424cdf0e10cSrcweir load = True 425cdf0e10cSrcweir lastRead = self.sfa.getDateTimeModified( url ) 426cdf0e10cSrcweir if entry: 427cdf0e10cSrcweir if hasChanged( entry.lastRead, lastRead ): 428735dd73bSPedro Giffuni log.debug( "file " + url + " has changed, reloading" ) 429cdf0e10cSrcweir else: 430cdf0e10cSrcweir load = False 43113cfd8dfSPedro Giffuni 432cdf0e10cSrcweir if load: 433735dd73bSPedro Giffuni log.debug( "opening >" + url + "<" ) 43413cfd8dfSPedro Giffuni 435cdf0e10cSrcweir src = readTextFromStream( self.sfa.openFileRead( url ) ) 436cdf0e10cSrcweir checkForPythonPathBesideScript( url[0:url.rfind('/')] ) 43713cfd8dfSPedro Giffuni src = ensureSourceState( src ) 43813cfd8dfSPedro Giffuni 439cdf0e10cSrcweir # execute the module 440cdf0e10cSrcweir entry = ModuleEntry( lastRead, imp.new_module("ooo_script_framework") ) 441cdf0e10cSrcweir entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = self.scriptContext 442cdf0e10cSrcweir 443cdf0e10cSrcweir code = None 444cdf0e10cSrcweir if url.startswith( "file:" ): 445cdf0e10cSrcweir code = compile( src, encfile(uno.fileUrlToSystemPath( url ) ), "exec" ) 446cdf0e10cSrcweir else: 447cdf0e10cSrcweir code = compile( src, url, "exec" ) 44815745147SPedro Giffuni exec(code, entry.module.__dict__) 449cdf0e10cSrcweir entry.module.__file__ = url 450cdf0e10cSrcweir self.modules[ url ] = entry 451735dd73bSPedro Giffuni log.debug( "mapped " + url + " to " + str( entry.module ) ) 452cdf0e10cSrcweir return entry.module 45313cfd8dfSPedro Giffuni 454cdf0e10cSrcweir#-------------------------------------------------- 455cdf0e10cSrcweirdef isScript( candidate ): 456cdf0e10cSrcweir ret = False 457cdf0e10cSrcweir if isinstance( candidate, type(isScript) ): 458cdf0e10cSrcweir ret = True 459cdf0e10cSrcweir return ret 46013cfd8dfSPedro Giffuni 461cdf0e10cSrcweir#------------------------------------------------------- 462cdf0e10cSrcweirclass ScriptBrowseNode( unohelper.Base, XBrowseNode , XPropertySet, XInvocation, XActionListener ): 463cdf0e10cSrcweir def __init__( self, provCtx, uri, fileName, funcName ): 464cdf0e10cSrcweir self.fileName = fileName 465cdf0e10cSrcweir self.funcName = funcName 466cdf0e10cSrcweir self.provCtx = provCtx 467cdf0e10cSrcweir self.uri = uri 46813cfd8dfSPedro Giffuni 469cdf0e10cSrcweir def getName( self ): 470cdf0e10cSrcweir return self.funcName 471cdf0e10cSrcweir 472cdf0e10cSrcweir def getChildNodes(self): 473cdf0e10cSrcweir return () 474cdf0e10cSrcweir 475cdf0e10cSrcweir def hasChildNodes(self): 476cdf0e10cSrcweir return False 47713cfd8dfSPedro Giffuni 478cdf0e10cSrcweir def getType( self): 479cdf0e10cSrcweir return SCRIPT 480cdf0e10cSrcweir 481cdf0e10cSrcweir def getPropertyValue( self, name ): 482cdf0e10cSrcweir ret = None 483cdf0e10cSrcweir try: 484cdf0e10cSrcweir if name == "URI": 485cdf0e10cSrcweir ret = self.provCtx.uriHelper.getScriptURI( 486cdf0e10cSrcweir self.provCtx.getPersistentUrlFromStorageUrl( self.uri + "$" + self.funcName ) ) 487cdf0e10cSrcweir elif name == "Editable" and ENABLE_EDIT_DIALOG: 488cdf0e10cSrcweir ret = not self.provCtx.sfa.isReadOnly( self.uri ) 48913cfd8dfSPedro Giffuni 490735dd73bSPedro Giffuni log.debug( "ScriptBrowseNode.getPropertyValue called for " + name + ", returning " + str(ret) ) 49115745147SPedro Giffuni except Exception as e: 492cdf0e10cSrcweir log.error( "ScriptBrowseNode.getPropertyValue error " + lastException2String()) 493cdf0e10cSrcweir raise 49413cfd8dfSPedro Giffuni 495cdf0e10cSrcweir return ret 496cdf0e10cSrcweir def setPropertyValue( self, name, value ): 497735dd73bSPedro Giffuni log.debug( "ScriptBrowseNode.setPropertyValue called " + name + "=" +str(value ) ) 498cdf0e10cSrcweir def getPropertySetInfo( self ): 499735dd73bSPedro Giffuni log.debug( "ScriptBrowseNode.getPropertySetInfo called " ) 500cdf0e10cSrcweir return None 50113cfd8dfSPedro Giffuni 502cdf0e10cSrcweir def getIntrospection( self ): 503cdf0e10cSrcweir return None 504cdf0e10cSrcweir 505cdf0e10cSrcweir def invoke( self, name, params, outparamindex, outparams ): 506cdf0e10cSrcweir if name == "Editable": 507cdf0e10cSrcweir servicename = "com.sun.star.awt.DialogProvider" 508cdf0e10cSrcweir ctx = self.provCtx.scriptContext.getComponentContext() 509cdf0e10cSrcweir dlgprov = ctx.ServiceManager.createInstanceWithContext( 510cdf0e10cSrcweir servicename, ctx ) 511cdf0e10cSrcweir 512cdf0e10cSrcweir self.editor = dlgprov.createDialog( 513cdf0e10cSrcweir "vnd.sun.star.script:" + 514cdf0e10cSrcweir "ScriptBindingLibrary.MacroEditor?location=application") 515cdf0e10cSrcweir 516cdf0e10cSrcweir code = readTextFromStream(self.provCtx.sfa.openFileRead(self.uri)) 517cdf0e10cSrcweir code = ensureSourceState( code ) 518cdf0e10cSrcweir self.editor.getControl("EditorTextField").setText(code) 519cdf0e10cSrcweir 520cdf0e10cSrcweir self.editor.getControl("RunButton").setActionCommand("Run") 521cdf0e10cSrcweir self.editor.getControl("RunButton").addActionListener(self) 522cdf0e10cSrcweir self.editor.getControl("SaveButton").setActionCommand("Save") 523cdf0e10cSrcweir self.editor.getControl("SaveButton").addActionListener(self) 524cdf0e10cSrcweir 525cdf0e10cSrcweir self.editor.execute() 526cdf0e10cSrcweir 527cdf0e10cSrcweir return None 528cdf0e10cSrcweir 529cdf0e10cSrcweir def actionPerformed( self, event ): 530cdf0e10cSrcweir try: 531cdf0e10cSrcweir if event.ActionCommand == "Run": 532cdf0e10cSrcweir code = self.editor.getControl("EditorTextField").getText() 533cdf0e10cSrcweir code = ensureSourceState( code ) 534cdf0e10cSrcweir mod = imp.new_module("ooo_script_framework") 535cdf0e10cSrcweir mod.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = self.provCtx.scriptContext 53615745147SPedro Giffuni exec(code, mod.__dict__) 537cdf0e10cSrcweir values = mod.__dict__.get( CALLABLE_CONTAINER_NAME , None ) 538cdf0e10cSrcweir if not values: 53915745147SPedro Giffuni values = list(mod.__dict__.values()) 54013cfd8dfSPedro Giffuni 541cdf0e10cSrcweir for i in values: 542cdf0e10cSrcweir if isScript( i ): 543cdf0e10cSrcweir i() 544cdf0e10cSrcweir break 54513cfd8dfSPedro Giffuni 546cdf0e10cSrcweir elif event.ActionCommand == "Save": 547cdf0e10cSrcweir toWrite = uno.ByteSequence( 548cdf0e10cSrcweir str( 549cdf0e10cSrcweir self.editor.getControl("EditorTextField").getText().encode( 550cdf0e10cSrcweir sys.getdefaultencoding())) ) 551cdf0e10cSrcweir copyUrl = self.uri + ".orig" 552cdf0e10cSrcweir self.provCtx.sfa.move( self.uri, copyUrl ) 553cdf0e10cSrcweir out = self.provCtx.sfa.openFileWrite( self.uri ) 554cdf0e10cSrcweir out.writeBytes( toWrite ) 555cdf0e10cSrcweir out.close() 556cdf0e10cSrcweir self.provCtx.sfa.kill( copyUrl ) 557735dd73bSPedro Giffuni# log.debug("Save is not implemented yet") 558cdf0e10cSrcweir# text = self.editor.getControl("EditorTextField").getText() 559735dd73bSPedro Giffuni# log.debug("Would save: " + text) 56015745147SPedro Giffuni except Exception as e: 561cdf0e10cSrcweir # TODO: add an error box here ! 562cdf0e10cSrcweir log.error( lastException2String() ) 56313cfd8dfSPedro Giffuni 564cdf0e10cSrcweir 565cdf0e10cSrcweir def setValue( self, name, value ): 566cdf0e10cSrcweir return None 567cdf0e10cSrcweir 568cdf0e10cSrcweir def getValue( self, name ): 569cdf0e10cSrcweir return None 570cdf0e10cSrcweir 571cdf0e10cSrcweir def hasMethod( self, name ): 572cdf0e10cSrcweir return False 573cdf0e10cSrcweir 574cdf0e10cSrcweir def hasProperty( self, name ): 575cdf0e10cSrcweir return False 576cdf0e10cSrcweir 57713cfd8dfSPedro Giffuni 578cdf0e10cSrcweir#------------------------------------------------------- 579cdf0e10cSrcweirclass FileBrowseNode( unohelper.Base, XBrowseNode ): 580cdf0e10cSrcweir def __init__( self, provCtx, uri , name ): 581cdf0e10cSrcweir self.provCtx = provCtx 582cdf0e10cSrcweir self.uri = uri 583cdf0e10cSrcweir self.name = name 584cdf0e10cSrcweir self.funcnames = None 58513cfd8dfSPedro Giffuni 586cdf0e10cSrcweir def getName( self ): 587cdf0e10cSrcweir return self.name 58813cfd8dfSPedro Giffuni 589cdf0e10cSrcweir def getChildNodes(self): 590cdf0e10cSrcweir ret = () 591cdf0e10cSrcweir try: 592cdf0e10cSrcweir self.funcnames = self.provCtx.getFuncsByUrl( self.uri ) 59313cfd8dfSPedro Giffuni 594cdf0e10cSrcweir scriptNodeList = [] 595cdf0e10cSrcweir for i in self.funcnames: 596cdf0e10cSrcweir scriptNodeList.append( 597cdf0e10cSrcweir ScriptBrowseNode( 598cdf0e10cSrcweir self.provCtx, self.uri, self.name, i )) 599cdf0e10cSrcweir ret = tuple( scriptNodeList ) 600735dd73bSPedro Giffuni log.debug( "returning " +str(len(ret)) + " ScriptChildNodes on " + self.uri ) 60115745147SPedro Giffuni except Exception as e: 602cdf0e10cSrcweir text = lastException2String() 603cdf0e10cSrcweir log.error( "Error while evaluating " + self.uri + ":" + text ) 604cdf0e10cSrcweir raise 605cdf0e10cSrcweir return ret 606cdf0e10cSrcweir 607cdf0e10cSrcweir def hasChildNodes(self): 608cdf0e10cSrcweir try: 609cdf0e10cSrcweir return len(self.getChildNodes()) > 0 61015745147SPedro Giffuni except Exception as e: 611cdf0e10cSrcweir return False 61213cfd8dfSPedro Giffuni 613cdf0e10cSrcweir def getType( self): 614cdf0e10cSrcweir return CONTAINER 615cdf0e10cSrcweir 61613cfd8dfSPedro Giffuni 617cdf0e10cSrcweir 618cdf0e10cSrcweirclass DirBrowseNode( unohelper.Base, XBrowseNode ): 619cdf0e10cSrcweir def __init__( self, provCtx, name, rootUrl ): 620cdf0e10cSrcweir self.provCtx = provCtx 621cdf0e10cSrcweir self.name = name 622cdf0e10cSrcweir self.rootUrl = rootUrl 623cdf0e10cSrcweir 624cdf0e10cSrcweir def getName( self ): 625cdf0e10cSrcweir return self.name 626cdf0e10cSrcweir 627cdf0e10cSrcweir def getChildNodes( self ): 628cdf0e10cSrcweir try: 629735dd73bSPedro Giffuni log.debug( "DirBrowseNode.getChildNodes called for " + self.rootUrl ) 630cdf0e10cSrcweir contents = self.provCtx.sfa.getFolderContents( self.rootUrl, True ) 631cdf0e10cSrcweir browseNodeList = [] 632cdf0e10cSrcweir for i in contents: 633cdf0e10cSrcweir if i.endswith( ".py" ): 634735dd73bSPedro Giffuni log.debug( "adding filenode " + i ) 635cdf0e10cSrcweir browseNodeList.append( 636cdf0e10cSrcweir FileBrowseNode( self.provCtx, i, i[i.rfind("/")+1:len(i)-3] ) ) 637cdf0e10cSrcweir elif self.provCtx.sfa.isFolder( i ) and not i.endswith("/pythonpath"): 638735dd73bSPedro Giffuni log.debug( "adding DirBrowseNode " + i ) 639cdf0e10cSrcweir browseNodeList.append( DirBrowseNode( self.provCtx, i[i.rfind("/")+1:len(i)],i)) 640cdf0e10cSrcweir return tuple( browseNodeList ) 64115745147SPedro Giffuni except Exception as e: 642cdf0e10cSrcweir text = lastException2String() 643cdf0e10cSrcweir log.error( "DirBrowseNode error: " + str(e) + " while evaluating " + self.rootUrl) 644cdf0e10cSrcweir log.error( text) 645cdf0e10cSrcweir return () 646cdf0e10cSrcweir 647cdf0e10cSrcweir def hasChildNodes( self ): 648cdf0e10cSrcweir return True 649cdf0e10cSrcweir 650cdf0e10cSrcweir def getType( self ): 651cdf0e10cSrcweir return CONTAINER 652cdf0e10cSrcweir 653cdf0e10cSrcweir def getScript( self, uri ): 654cdf0e10cSrcweir log.debug( "DirBrowseNode getScript " + uri + " invoked" ) 655cdf0e10cSrcweir raise IllegalArgumentException( "DirBrowseNode couldn't instantiate script " + uri , self , 0 ) 656cdf0e10cSrcweir 657cdf0e10cSrcweir 658cdf0e10cSrcweirclass ManifestHandler( XDocumentHandler, unohelper.Base ): 659cdf0e10cSrcweir def __init__( self, rootUrl ): 660cdf0e10cSrcweir self.rootUrl = rootUrl 66113cfd8dfSPedro Giffuni 662cdf0e10cSrcweir def startDocument( self ): 663cdf0e10cSrcweir self.urlList = [] 66413cfd8dfSPedro Giffuni 665cdf0e10cSrcweir def endDocument( self ): 666cdf0e10cSrcweir pass 66713cfd8dfSPedro Giffuni 668cdf0e10cSrcweir def startElement( self , name, attlist): 669cdf0e10cSrcweir if name == "manifest:file-entry": 670cdf0e10cSrcweir if attlist.getValueByName( "manifest:media-type" ) == "application/vnd.sun.star.framework-script": 671cdf0e10cSrcweir self.urlList.append( 672cdf0e10cSrcweir self.rootUrl + "/" + attlist.getValueByName( "manifest:full-path" ) ) 673cdf0e10cSrcweir 674cdf0e10cSrcweir def endElement( self, name ): 675cdf0e10cSrcweir pass 676cdf0e10cSrcweir 677cdf0e10cSrcweir def characters ( self, chars ): 678cdf0e10cSrcweir pass 679cdf0e10cSrcweir 680cdf0e10cSrcweir def ignoreableWhitespace( self, chars ): 681cdf0e10cSrcweir pass 682cdf0e10cSrcweir 683cdf0e10cSrcweir def setDocumentLocator( self, locator ): 684cdf0e10cSrcweir pass 685cdf0e10cSrcweir 686cdf0e10cSrcweirdef isPyFileInPath( sfa, path ): 687cdf0e10cSrcweir ret = False 688cdf0e10cSrcweir contents = sfa.getFolderContents( path, True ) 689cdf0e10cSrcweir for i in contents: 690cdf0e10cSrcweir if sfa.isFolder(i): 691cdf0e10cSrcweir ret = isPyFileInPath(sfa,i) 692cdf0e10cSrcweir else: 693cdf0e10cSrcweir if i.endswith(".py"): 694cdf0e10cSrcweir ret = True 695cdf0e10cSrcweir if ret: 696cdf0e10cSrcweir break 697cdf0e10cSrcweir return ret 698cdf0e10cSrcweir 69913cfd8dfSPedro Giffuni# extracts META-INF directory from 700cdf0e10cSrcweirdef getPathesFromPackage( rootUrl, sfa ): 701cdf0e10cSrcweir ret = () 702cdf0e10cSrcweir try: 70313cfd8dfSPedro Giffuni fileUrl = rootUrl + "/META-INF/manifest.xml" 704cdf0e10cSrcweir inputStream = sfa.openFileRead( fileUrl ) 705cdf0e10cSrcweir parser = uno.getComponentContext().ServiceManager.createInstance( "com.sun.star.xml.sax.Parser" ) 706cdf0e10cSrcweir handler = ManifestHandler( rootUrl ) 707cdf0e10cSrcweir parser.setDocumentHandler( handler ) 708cdf0e10cSrcweir parser.parseStream( InputSource( inputStream , "", fileUrl, fileUrl ) ) 709cdf0e10cSrcweir for i in tuple(handler.urlList): 710cdf0e10cSrcweir if not isPyFileInPath( sfa, i ): 711cdf0e10cSrcweir handler.urlList.remove(i) 712cdf0e10cSrcweir ret = tuple( handler.urlList ) 71315745147SPedro Giffuni except UnoException as e: 714cdf0e10cSrcweir text = lastException2String() 715cdf0e10cSrcweir log.debug( "getPathesFromPackage " + fileUrl + " Exception: " +text ) 716cdf0e10cSrcweir pass 717cdf0e10cSrcweir return ret 71813cfd8dfSPedro Giffuni 719cdf0e10cSrcweir 720cdf0e10cSrcweirclass Package: 721cdf0e10cSrcweir def __init__( self, pathes, transientPathElement ): 722cdf0e10cSrcweir self.pathes = pathes 723cdf0e10cSrcweir self.transientPathElement = transientPathElement 724cdf0e10cSrcweir 725cdf0e10cSrcweirclass DummyInteractionHandler( unohelper.Base, XInteractionHandler ): 726cdf0e10cSrcweir def __init__( self ): 727cdf0e10cSrcweir pass 728cdf0e10cSrcweir def handle( self, event): 729735dd73bSPedro Giffuni log.debug( "pythonscript: DummyInteractionHandler.handle " + str( event ) ) 730cdf0e10cSrcweir 731cdf0e10cSrcweirclass DummyProgressHandler( unohelper.Base, XProgressHandler ): 732cdf0e10cSrcweir def __init__( self ): 733cdf0e10cSrcweir pass 73413cfd8dfSPedro Giffuni 73513cfd8dfSPedro Giffuni def push( self,status ): 736735dd73bSPedro Giffuni log.debug( "pythonscript: DummyProgressHandler.push " + str( status ) ) 73713cfd8dfSPedro Giffuni def update( self,status ): 738735dd73bSPedro Giffuni log.debug( "pythonscript: DummyProgressHandler.update " + str( status ) ) 73913cfd8dfSPedro Giffuni def pop( self ): 740735dd73bSPedro Giffuni log.debug( "pythonscript: DummyProgressHandler.push " + str( event ) ) 741cdf0e10cSrcweir 742cdf0e10cSrcweirclass CommandEnvironment(unohelper.Base, XCommandEnvironment): 743cdf0e10cSrcweir def __init__( self ): 744cdf0e10cSrcweir self.progressHandler = DummyProgressHandler() 745cdf0e10cSrcweir self.interactionHandler = DummyInteractionHandler() 746cdf0e10cSrcweir def getInteractionHandler( self ): 747cdf0e10cSrcweir return self.interactionHandler 748cdf0e10cSrcweir def getProgressHandler( self ): 749cdf0e10cSrcweir return self.progressHandler 750cdf0e10cSrcweir 751cdf0e10cSrcweir#maybe useful for debugging purposes 752cdf0e10cSrcweir#class ModifyListener( unohelper.Base, XModifyListener ): 753cdf0e10cSrcweir# def __init__( self ): 754cdf0e10cSrcweir# pass 755cdf0e10cSrcweir# def modified( self, event ): 756735dd73bSPedro Giffuni# log.debug( "pythonscript: ModifyListener.modified " + str( event ) ) 757cdf0e10cSrcweir# def disposing( self, event ): 758735dd73bSPedro Giffuni# log.debug( "pythonscript: ModifyListener.disposing " + str( event ) ) 75961c9e2f8SAriel Constenla-Haile 76061c9e2f8SAriel Constenla-Hailedef getModelFromDocUrl(ctx, url): 76161c9e2f8SAriel Constenla-Haile """Get document model from document url.""" 76261c9e2f8SAriel Constenla-Haile doc = None 76361c9e2f8SAriel Constenla-Haile args = ("Local", "Office") 76461c9e2f8SAriel Constenla-Haile ucb = ctx.getServiceManager().createInstanceWithArgumentsAndContext( 76561c9e2f8SAriel Constenla-Haile "com.sun.star.ucb.UniversalContentBroker", args, ctx) 76661c9e2f8SAriel Constenla-Haile identifier = ucb.createContentIdentifier(url) 76761c9e2f8SAriel Constenla-Haile content = ucb.queryContent(identifier) 76861c9e2f8SAriel Constenla-Haile p = Property() 76961c9e2f8SAriel Constenla-Haile p.Name = "DocumentModel" 77061c9e2f8SAriel Constenla-Haile p.Handle = -1 77113cfd8dfSPedro Giffuni 77261c9e2f8SAriel Constenla-Haile c = Command() 77361c9e2f8SAriel Constenla-Haile c.Handle = -1 77461c9e2f8SAriel Constenla-Haile c.Name = "getPropertyValues" 77561c9e2f8SAriel Constenla-Haile c.Argument = uno.Any("[]com.sun.star.beans.Property", (p,)) 77613cfd8dfSPedro Giffuni 77761c9e2f8SAriel Constenla-Haile env = CommandEnvironment() 77861c9e2f8SAriel Constenla-Haile try: 77961c9e2f8SAriel Constenla-Haile ret = content.execute(c, 0, env) 78061c9e2f8SAriel Constenla-Haile doc = ret.getObject(1, None) 78115745147SPedro Giffuni except Exception as e: 78261c9e2f8SAriel Constenla-Haile log.isErrorLevel() and log.error("getModelFromDocUrl: %s" % url) 78361c9e2f8SAriel Constenla-Haile return doc 78461c9e2f8SAriel Constenla-Haile 785cdf0e10cSrcweirdef mapStorageType2PackageContext( storageType ): 786cdf0e10cSrcweir ret = storageType 787cdf0e10cSrcweir if( storageType == "share:uno_packages" ): 788cdf0e10cSrcweir ret = "shared" 789cdf0e10cSrcweir if( storageType == "user:uno_packages" ): 790cdf0e10cSrcweir ret = "user" 791cdf0e10cSrcweir return ret 792cdf0e10cSrcweir 793cdf0e10cSrcweirdef getPackageName2PathMap( sfa, storageType ): 794cdf0e10cSrcweir ret = {} 795cdf0e10cSrcweir packageManagerFactory = uno.getComponentContext().getValueByName( 796cdf0e10cSrcweir "/singletons/com.sun.star.deployment.thePackageManagerFactory" ) 797cdf0e10cSrcweir packageManager = packageManagerFactory.getPackageManager( 798cdf0e10cSrcweir mapStorageType2PackageContext(storageType)) 799cdf0e10cSrcweir# packageManager.addModifyListener( ModifyListener() ) 800735dd73bSPedro Giffuni log.debug( "pythonscript: getPackageName2PathMap start getDeployedPackages" ) 801cdf0e10cSrcweir packages = packageManager.getDeployedPackages( 802cdf0e10cSrcweir packageManager.createAbortChannel(), CommandEnvironment( ) ) 803735dd73bSPedro Giffuni log.debug( "pythonscript: getPackageName2PathMap end getDeployedPackages (" + str(len(packages))+")" ) 804cdf0e10cSrcweir 805cdf0e10cSrcweir for i in packages: 806735dd73bSPedro Giffuni log.debug( "inspecting package " + i.Name + "("+i.Identifier.Value+")" ) 807cdf0e10cSrcweir transientPathElement = penultimateElement( i.URL ) 808cdf0e10cSrcweir j = expandUri( i.URL ) 809cdf0e10cSrcweir pathes = getPathesFromPackage( j, sfa ) 810cdf0e10cSrcweir if len( pathes ) > 0: 811cdf0e10cSrcweir # map package name to url, we need this later 812cdf0e10cSrcweir log.isErrorLevel() and log.error( "adding Package " + transientPathElement + " " + str( pathes ) ) 813cdf0e10cSrcweir ret[ lastElement( j ) ] = Package( pathes, transientPathElement ) 814cdf0e10cSrcweir return ret 815cdf0e10cSrcweir 816cdf0e10cSrcweirdef penultimateElement( aStr ): 817cdf0e10cSrcweir lastSlash = aStr.rindex("/") 818cdf0e10cSrcweir penultimateSlash = aStr.rindex("/",0,lastSlash-1) 819cdf0e10cSrcweir return aStr[ penultimateSlash+1:lastSlash ] 820cdf0e10cSrcweir 821cdf0e10cSrcweirdef lastElement( aStr): 822cdf0e10cSrcweir return aStr[ aStr.rfind( "/" )+1:len(aStr)] 823cdf0e10cSrcweir 824cdf0e10cSrcweirclass PackageBrowseNode( unohelper.Base, XBrowseNode ): 825cdf0e10cSrcweir def __init__( self, provCtx, name, rootUrl ): 826cdf0e10cSrcweir self.provCtx = provCtx 827cdf0e10cSrcweir self.name = name 828cdf0e10cSrcweir self.rootUrl = rootUrl 829cdf0e10cSrcweir 830cdf0e10cSrcweir def getName( self ): 831cdf0e10cSrcweir return self.name 832cdf0e10cSrcweir 833cdf0e10cSrcweir def getChildNodes( self ): 83415745147SPedro Giffuni items = list(self.provCtx.mapPackageName2Path.items()) 835cdf0e10cSrcweir browseNodeList = [] 836cdf0e10cSrcweir for i in items: 837cdf0e10cSrcweir if len( i[1].pathes ) == 1: 838cdf0e10cSrcweir browseNodeList.append( 839cdf0e10cSrcweir DirBrowseNode( self.provCtx, i[0], i[1].pathes[0] )) 840cdf0e10cSrcweir else: 841cdf0e10cSrcweir for j in i[1].pathes: 842cdf0e10cSrcweir browseNodeList.append( 843cdf0e10cSrcweir DirBrowseNode( self.provCtx, i[0]+"."+lastElement(j), j ) ) 844cdf0e10cSrcweir return tuple( browseNodeList ) 845cdf0e10cSrcweir 846cdf0e10cSrcweir def hasChildNodes( self ): 847cdf0e10cSrcweir return len( self.mapPackageName2Path ) > 0 848cdf0e10cSrcweir 849cdf0e10cSrcweir def getType( self ): 850cdf0e10cSrcweir return CONTAINER 851cdf0e10cSrcweir 852cdf0e10cSrcweir def getScript( self, uri ): 853cdf0e10cSrcweir log.debug( "DirBrowseNode getScript " + uri + " invoked" ) 854cdf0e10cSrcweir raise IllegalArgumentException( "PackageBrowseNode couldn't instantiate script " + uri , self , 0 ) 855cdf0e10cSrcweir 856cdf0e10cSrcweir 857cdf0e10cSrcweir 858cdf0e10cSrcweir 859cdf0e10cSrcweirclass PythonScript( unohelper.Base, XScript ): 860cdf0e10cSrcweir def __init__( self, func, mod ): 861cdf0e10cSrcweir self.func = func 862cdf0e10cSrcweir self.mod = mod 863cdf0e10cSrcweir def invoke(self, args, out, outindex ): 864735dd73bSPedro Giffuni log.debug( "PythonScript.invoke " + str( args ) ) 865cdf0e10cSrcweir try: 866cdf0e10cSrcweir ret = self.func( *args ) 86715745147SPedro Giffuni except UnoException as e: 868cdf0e10cSrcweir # UNO Exception continue to fly ... 869cdf0e10cSrcweir text = lastException2String() 870cdf0e10cSrcweir complete = "Error during invoking function " + \ 871cdf0e10cSrcweir str(self.func.__name__) + " in module " + \ 872cdf0e10cSrcweir self.mod.__file__ + " (" + text + ")" 873735dd73bSPedro Giffuni log.debug( complete ) 874cdf0e10cSrcweir # some people may beat me up for modifying the exception text, 875cdf0e10cSrcweir # but otherwise office just shows 876cdf0e10cSrcweir # the type name and message text with no more information, 87713cfd8dfSPedro Giffuni # this is really bad for most users. 878cdf0e10cSrcweir e.Message = e.Message + " (" + complete + ")" 879cdf0e10cSrcweir raise 88015745147SPedro Giffuni except Exception as e: 881cdf0e10cSrcweir # General python exception are converted to uno RuntimeException 882cdf0e10cSrcweir text = lastException2String() 883cdf0e10cSrcweir complete = "Error during invoking function " + \ 884cdf0e10cSrcweir str(self.func.__name__) + " in module " + \ 885cdf0e10cSrcweir self.mod.__file__ + " (" + text + ")" 886735dd73bSPedro Giffuni log.debug( complete ) 887cdf0e10cSrcweir raise RuntimeException( complete , self ) 888735dd73bSPedro Giffuni log.debug( "PythonScript.invoke ret = " + str( ret ) ) 889cdf0e10cSrcweir return ret, (), () 890cdf0e10cSrcweir 891cdf0e10cSrcweirdef expandUri( uri ): 892cdf0e10cSrcweir if uri.startswith( "vnd.sun.star.expand:" ): 893cdf0e10cSrcweir uri = uri.replace( "vnd.sun.star.expand:", "",1) 894cdf0e10cSrcweir uri = uno.getComponentContext().getByName( 895cdf0e10cSrcweir "/singletons/com.sun.star.util.theMacroExpander" ).expandMacros( uri ) 896cdf0e10cSrcweir if uri.startswith( "file:" ): 897cdf0e10cSrcweir uri = uno.absolutize("",uri) # necessary to get rid of .. in uri 898cdf0e10cSrcweir return uri 89913cfd8dfSPedro Giffuni 900cdf0e10cSrcweir#-------------------------------------------------------------- 901cdf0e10cSrcweirclass PythonScriptProvider( unohelper.Base, XBrowseNode, XScriptProvider, XNameContainer): 902cdf0e10cSrcweir def __init__( self, ctx, *args ): 903cdf0e10cSrcweir if log.isDebugLevel(): 904cdf0e10cSrcweir mystr = "" 905cdf0e10cSrcweir for i in args: 906cdf0e10cSrcweir if len(mystr) > 0: 907cdf0e10cSrcweir mystr = mystr +"," 908cdf0e10cSrcweir mystr = mystr + str(i) 909cdf0e10cSrcweir log.debug( "Entering PythonScriptProvider.ctor" + mystr ) 910cdf0e10cSrcweir 91161c9e2f8SAriel Constenla-Haile doc = None 91261c9e2f8SAriel Constenla-Haile inv = None 913cdf0e10cSrcweir storageType = "" 91461c9e2f8SAriel Constenla-Haile 915cdf0e10cSrcweir if isinstance(args[0],unicode ): 916cdf0e10cSrcweir storageType = args[0] 91761c9e2f8SAriel Constenla-Haile if storageType.startswith( "vnd.sun.star.tdoc" ): 91861c9e2f8SAriel Constenla-Haile doc = getModelFromDocUrl(ctx, storageType) 919cdf0e10cSrcweir else: 92061c9e2f8SAriel Constenla-Haile inv = args[0] 92161c9e2f8SAriel Constenla-Haile try: 92261c9e2f8SAriel Constenla-Haile doc = inv.ScriptContainer 92361c9e2f8SAriel Constenla-Haile content = ctx.getServiceManager().createInstanceWithContext( 92413cfd8dfSPedro Giffuni "com.sun.star.frame.TransientDocumentsDocumentContentFactory", 92561c9e2f8SAriel Constenla-Haile ctx).createDocumentContent(doc) 92661c9e2f8SAriel Constenla-Haile storageType = content.getIdentifier().getContentIdentifier() 92715745147SPedro Giffuni except Exception as e: 92861c9e2f8SAriel Constenla-Haile text = lastException2String() 92961c9e2f8SAriel Constenla-Haile log.error( text ) 93061c9e2f8SAriel Constenla-Haile 931cdf0e10cSrcweir isPackage = storageType.endswith( ":uno_packages" ) 932cdf0e10cSrcweir 933cdf0e10cSrcweir try: 934cdf0e10cSrcweir# urlHelper = ctx.ServiceManager.createInstanceWithArgumentsAndContext( 935cdf0e10cSrcweir# "com.sun.star.script.provider.ScriptURIHelper", (LANGUAGENAME, storageType), ctx) 936cdf0e10cSrcweir urlHelper = MyUriHelper( ctx, storageType ) 937735dd73bSPedro Giffuni log.debug( "got urlHelper " + str( urlHelper ) ) 93813cfd8dfSPedro Giffuni 939cdf0e10cSrcweir rootUrl = expandUri( urlHelper.getRootStorageURI() ) 940735dd73bSPedro Giffuni log.debug( storageType + " transformed to " + rootUrl ) 941cdf0e10cSrcweir 942cdf0e10cSrcweir ucbService = "com.sun.star.ucb.SimpleFileAccess" 943cdf0e10cSrcweir sfa = ctx.ServiceManager.createInstanceWithContext( ucbService, ctx ) 944cdf0e10cSrcweir if not sfa: 945cdf0e10cSrcweir log.debug("PythonScriptProvider couldn't instantiate " +ucbService) 946cdf0e10cSrcweir raise RuntimeException( 947cdf0e10cSrcweir "PythonScriptProvider couldn't instantiate " +ucbService, self) 948cdf0e10cSrcweir self.provCtx = ProviderContext( 94961c9e2f8SAriel Constenla-Haile storageType, sfa, urlHelper, ScriptContext( uno.getComponentContext(), doc, inv ) ) 950cdf0e10cSrcweir if isPackage: 951cdf0e10cSrcweir mapPackageName2Path = getPackageName2PathMap( sfa, storageType ) 952cdf0e10cSrcweir self.provCtx.setPackageAttributes( mapPackageName2Path , rootUrl ) 953cdf0e10cSrcweir self.dirBrowseNode = PackageBrowseNode( self.provCtx, LANGUAGENAME, rootUrl ) 954cdf0e10cSrcweir else: 955cdf0e10cSrcweir self.dirBrowseNode = DirBrowseNode( self.provCtx, LANGUAGENAME, rootUrl ) 95613cfd8dfSPedro Giffuni 95715745147SPedro Giffuni except Exception as e: 958cdf0e10cSrcweir text = lastException2String() 959cdf0e10cSrcweir log.debug( "PythonScriptProvider could not be instantiated because of : " + text ) 960cdf0e10cSrcweir raise e 961cdf0e10cSrcweir 962cdf0e10cSrcweir def getName( self ): 963cdf0e10cSrcweir return self.dirBrowseNode.getName() 964cdf0e10cSrcweir 965cdf0e10cSrcweir def getChildNodes( self ): 96613cfd8dfSPedro Giffuni return self.dirBrowseNode.getChildNodes() 967cdf0e10cSrcweir 968cdf0e10cSrcweir def hasChildNodes( self ): 969cdf0e10cSrcweir return self.dirBrowseNode.hasChildNodes() 970cdf0e10cSrcweir 971cdf0e10cSrcweir def getType( self ): 972cdf0e10cSrcweir return self.dirBrowseNode.getType() 973cdf0e10cSrcweir 974cdf0e10cSrcweir def getScript( self, uri ): 975cdf0e10cSrcweir log.debug( "DirBrowseNode getScript " + uri + " invoked" ) 97613cfd8dfSPedro Giffuni 977cdf0e10cSrcweir raise IllegalArgumentException( "DirBrowseNode couldn't instantiate script " + uri , self , 0 ) 978cdf0e10cSrcweir 979cdf0e10cSrcweir def getScript( self, scriptUri ): 980cdf0e10cSrcweir try: 981735dd73bSPedro Giffuni log.debug( "getScript " + scriptUri + " invoked") 98213cfd8dfSPedro Giffuni 983cdf0e10cSrcweir storageUri = self.provCtx.getStorageUrlFromPersistentUrl( 984cdf0e10cSrcweir self.provCtx.uriHelper.getStorageURI(scriptUri) ); 985735dd73bSPedro Giffuni log.debug( "getScript: storageUri = " + storageUri) 986cdf0e10cSrcweir fileUri = storageUri[0:storageUri.find( "$" )] 98713cfd8dfSPedro Giffuni funcName = storageUri[storageUri.find( "$" )+1:len(storageUri)] 98813cfd8dfSPedro Giffuni 989cdf0e10cSrcweir mod = self.provCtx.getModuleByUrl( fileUri ) 990735dd73bSPedro Giffuni log.debug( " got mod " + str(mod) ) 99113cfd8dfSPedro Giffuni 992cdf0e10cSrcweir func = mod.__dict__[ funcName ] 993cdf0e10cSrcweir 994735dd73bSPedro Giffuni log.debug( "got func " + str( func ) ) 995cdf0e10cSrcweir return PythonScript( func, mod ) 99615745147SPedro Giffuni except Exception as e: 997cdf0e10cSrcweir text = lastException2String() 998cdf0e10cSrcweir log.error( text ) 999cdf0e10cSrcweir raise ScriptFrameworkErrorException( text, self, scriptUri, LANGUAGENAME, 0 ) 100013cfd8dfSPedro Giffuni 1001cdf0e10cSrcweir 1002cdf0e10cSrcweir # XServiceInfo 1003cdf0e10cSrcweir def getSupportedServices( self ): 1004cdf0e10cSrcweir return g_ImplementationHelper.getSupportedServices(g_implName) 1005cdf0e10cSrcweir 1006cdf0e10cSrcweir def supportsService( self, ServiceName ): 1007cdf0e10cSrcweir return g_ImplementationHelper.supportsService( g_implName, ServiceName ) 1008cdf0e10cSrcweir 1009cdf0e10cSrcweir def getImplementationName(self): 1010cdf0e10cSrcweir return g_implName 1011cdf0e10cSrcweir 1012cdf0e10cSrcweir def getByName( self, name ): 1013cdf0e10cSrcweir log.debug( "getByName called" + str( name )) 1014cdf0e10cSrcweir return None 1015cdf0e10cSrcweir 101613cfd8dfSPedro Giffuni 1017cdf0e10cSrcweir def getElementNames( self ): 1018cdf0e10cSrcweir log.debug( "getElementNames called") 1019cdf0e10cSrcweir return () 102013cfd8dfSPedro Giffuni 1021cdf0e10cSrcweir def hasByName( self, name ): 1022cdf0e10cSrcweir try: 1023cdf0e10cSrcweir log.debug( "hasByName called " + str( name )) 1024cdf0e10cSrcweir uri = expandUri(name) 1025cdf0e10cSrcweir ret = self.provCtx.isUrlInPackage( uri ) 1026cdf0e10cSrcweir log.debug( "hasByName " + uri + " " +str( ret ) ) 1027cdf0e10cSrcweir return ret 102815745147SPedro Giffuni except Exception as e: 1029cdf0e10cSrcweir text = lastException2String() 1030cdf0e10cSrcweir log.debug( "Error in hasByName:" + text ) 1031cdf0e10cSrcweir return False 1032cdf0e10cSrcweir 1033cdf0e10cSrcweir def removeByName( self, name ): 1034cdf0e10cSrcweir log.debug( "removeByName called" + str( name )) 1035cdf0e10cSrcweir uri = expandUri( name ) 1036cdf0e10cSrcweir if self.provCtx.isUrlInPackage( uri ): 1037cdf0e10cSrcweir self.provCtx.removePackageByUrl( uri ) 1038cdf0e10cSrcweir else: 1039cdf0e10cSrcweir log.debug( "removeByName unknown uri " + str( name ) + ", ignoring" ) 1040cdf0e10cSrcweir raise NoSuchElementException( uri + "is not in package" , self ) 1041cdf0e10cSrcweir log.debug( "removeByName called" + str( uri ) + " successful" ) 104213cfd8dfSPedro Giffuni 1043cdf0e10cSrcweir def insertByName( self, name, value ): 1044cdf0e10cSrcweir log.debug( "insertByName called " + str( name ) + " " + str( value )) 1045cdf0e10cSrcweir uri = expandUri( name ) 1046cdf0e10cSrcweir if isPyFileInPath( self.provCtx.sfa, uri ): 1047cdf0e10cSrcweir self.provCtx.addPackageByUrl( uri ) 1048cdf0e10cSrcweir else: 1049cdf0e10cSrcweir # package is no python package ... 1050cdf0e10cSrcweir log.debug( "insertByName: no python files in " + str( uri ) + ", ignoring" ) 1051cdf0e10cSrcweir raise IllegalArgumentException( uri + " does not contain .py files", self, 1 ) 1052cdf0e10cSrcweir log.debug( "insertByName called " + str( uri ) + " successful" ) 1053cdf0e10cSrcweir 1054cdf0e10cSrcweir def replaceByName( self, name, value ): 1055cdf0e10cSrcweir log.debug( "replaceByName called " + str( name ) + " " + str( value )) 1056cdf0e10cSrcweir removeByName( name ) 1057cdf0e10cSrcweir insertByName( name ) 1058cdf0e10cSrcweir log.debug( "replaceByName called" + str( uri ) + " successful" ) 1059cdf0e10cSrcweir 1060cdf0e10cSrcweir def getElementType( self ): 1061cdf0e10cSrcweir log.debug( "getElementType called" ) 1062cdf0e10cSrcweir return uno.getTypeByName( "void" ) 106313cfd8dfSPedro Giffuni 1064cdf0e10cSrcweir def hasElements( self ): 1065cdf0e10cSrcweir log.debug( "hasElements got called") 1066cdf0e10cSrcweir return False 106713cfd8dfSPedro Giffuni 1068cdf0e10cSrcweirg_ImplementationHelper.addImplementation( \ 106913cfd8dfSPedro Giffuni PythonScriptProvider,g_implName, \ 1070cdf0e10cSrcweir ("com.sun.star.script.provider.LanguageScriptProvider", 1071cdf0e10cSrcweir "com.sun.star.script.provider.ScriptProviderFor"+ LANGUAGENAME,),) 1072cdf0e10cSrcweir 1073cdf0e10cSrcweir 1074cdf0e10cSrcweirlog.debug( "pythonscript finished intializing" ) 1075