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