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