1 # XScript implementation for python
14 # Configuration ----------------------------------------------------
15 LogLevel
.use
= LogLevel
.NONE
# production level
16 #LogLevel.use = LogLevel.ERROR # for script developers
17 #LogLevel.use = LogLevel.DEBUG # for script framework developers
18 LOG_STDOUT
= True # True, writes to stdout (difficult on windows)
19 # False, writes to user/Scripts/python/log.txt
20 ENABLE_EDIT_DIALOG
=False # offers a minimal editor for editing.
21 #-------------------------------------------------------------------
24 return uni
.encode( sys
.getfilesystemencoding())
26 def lastException2String():
27 (excType
,excInstance
,excTraceback
) = sys
.exc_info()
28 ret
= str(excType
) + ": "+str(excInstance
) + "\n" + \
29 uno
._uno
_extract
_printable
_stacktrace
( excTraceback
)
32 def logLevel2String( level
):
34 if level
== LogLevel
.ERROR
:
36 elif level
>= LogLevel
.DEBUG
:
44 pathSubst
= uno
.getComponentContext().ServiceManager
.createInstance(
45 "com.sun.star.util.PathSubstitution" )
46 userInstallation
= pathSubst
.getSubstituteVariableValue( "user" )
47 if len( userInstallation
) > 0:
48 systemPath
= uno
.fileUrlToSystemPath( userInstallation
+ "/Scripts/python/log.txt" )
49 ret
= file( systemPath
, "a" )
51 print "Exception during creation of pythonscript logfile: "+ lastException2String() + "\n, delagating log to stdout\n"
54 class Logger(LogLevel
):
55 def __init__(self
, target
):
58 def isDebugLevel( self
):
59 return self
.use
>= self
.DEBUG
61 def debug( self
, msg
):
62 if self
.isDebugLevel():
63 self
.log( self
.DEBUG
, msg
)
65 def isErrorLevel( self
):
66 return self
.use
>= self
.ERROR
68 def error( self
, msg
):
69 if self
.isErrorLevel():
70 self
.log( self
.ERROR
, msg
)
72 def log( self
, level
, msg
):
78 logLevel2String( level
) +
84 print "Error during writing to stdout: " +lastException2String() + "\n"
86 log
= Logger( getLogTarget() )
88 log
.debug( "pythonscript loading" )
90 #from com.sun.star.lang import typeOfXServiceInfo, typeOfXTypeProvider
91 from com
.sun
.star
.uno
import RuntimeException
92 from com
.sun
.star
.lang
import XServiceInfo
93 from com
.sun
.star
.io
import IOException
94 from com
.sun
.star
.ucb
import CommandAbortedException
, XCommandEnvironment
, XProgressHandler
95 from com
.sun
.star
.task
import XInteractionHandler
96 from com
.sun
.star
.beans
import XPropertySet
97 from com
.sun
.star
.container
import XNameContainer
98 from com
.sun
.star
.xml
.sax
import XDocumentHandler
, InputSource
99 from com
.sun
.star
.uno
import Exception as UnoException
100 from com
.sun
.star
.script
import XInvocation
101 from com
.sun
.star
.awt
import XActionListener
103 from com
.sun
.star
.script
.provider
import XScriptProvider
, XScript
, XScriptContext
, ScriptFrameworkErrorException
104 from com
.sun
.star
.script
.browse
import XBrowseNode
105 from com
.sun
.star
.script
.browse
.BrowseNodeTypes
import SCRIPT
, CONTAINER
, ROOT
106 from com
.sun
.star
.util
import XModifyListener
108 LANGUAGENAME
= "Python"
109 GLOBAL_SCRIPTCONTEXT_NAME
= "XSCRIPTCONTEXT"
110 CALLABLE_CONTAINER_NAME
= "g_exportedScripts"
112 # pythonloader looks for a static g_ImplementationHelper variable
113 g_ImplementationHelper
= unohelper
.ImplementationHelper()
114 g_implName
= "org.openoffice.pyuno.LanguageScriptProviderFor"+LANGUAGENAME
119 def readTextFromStream( inputStream
):
121 code
= uno
.ByteSequence( "" )
123 read
,out
= inputStream
.readBytes( None , BLOCK_SIZE
)
125 if read
< BLOCK_SIZE
:
129 def toIniName( str ):
130 # TODO: what is the official way to get to know whether i am on the windows platform ?
131 if( hasattr(sys
, "dllhandle") ):
136 """ definition: storageURI is the system dependent, absolute file url, where the script is stored on disk
137 scriptURI is the system independent uri
141 def __init__( self
, ctx
, location
):
143 { "share" : "vnd.sun.star.expand:${$BRAND_BASE_DIR/program/" + toIniName( "bootstrap") + "::BaseInstallation}/share/Scripts/python" , \
144 "share:uno_packages" : "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/uno_packages", \
145 "user" : "vnd.sun.star.expand:${$BRAND_BASE_DIR/program/" + toIniName( "bootstrap") + "::UserInstallation}/user/Scripts/python" , \
146 "user:uno_packages" : "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages" }
147 self
.m_uriRefFac
= ctx
.ServiceManager
.createInstanceWithContext("com.sun.star.uri.UriReferenceFactory",ctx
)
148 if location
.startswith( "vnd.sun.star.tdoc" ):
149 self
.m_baseUri
= location
+ "/Scripts/python"
150 self
.m_scriptUriLocation
= "document"
152 self
.m_baseUri
= expandUri( self
.s_UriMap
[location
] )
153 self
.m_scriptUriLocation
= location
154 log
.isDebugLevel() and log
.debug( "initialized urihelper with baseUri="+self
.m_baseUri
+ ",m_scriptUriLocation="+self
.m_scriptUriLocation
)
156 def getRootStorageURI( self
):
157 return self
.m_baseUri
159 def getStorageURI( self
, scriptURI
):
160 return self
.scriptURI2StorageUri(scriptURI
)
162 def getScriptURI( self
, storageURI
):
163 return self
.storageURI2ScriptUri(storageURI
)
165 def storageURI2ScriptUri( self
, storageURI
):
166 if not storageURI
.startswith( self
.m_baseUri
):
167 message
= "pythonscript: storage uri '" + storageURI
+ "' not in base uri '" + self
.m_baseUri
+ "'"
168 log
.isDebugLevel() and log
.debug( message
)
169 raise RuntimeException( message
)
171 ret
= "vnd.sun.star.script:" + \
172 storageURI
[len(self
.m_baseUri
)+1:].replace("/","|") + \
173 "?language=" + LANGUAGENAME
+ "&location=" + self
.m_scriptUriLocation
174 log
.isDebugLevel() and log
.debug( "converting storageURI="+storageURI
+ " to scriptURI=" + ret
)
177 def scriptURI2StorageUri( self
, scriptURI
):
179 myUri
= self
.m_uriRefFac
.parse(scriptURI
)
180 ret
= self
.m_baseUri
+ "/" + myUri
.getName().replace( "|", "/" )
181 log
.isDebugLevel() and log
.debug( "converting scriptURI="+scriptURI
+ " to storageURI=" + ret
)
183 except UnoException
, e
:
184 log
.error( "error during converting scriptURI="+scriptURI
+ ": " + e
.Message
)
185 raise RuntimeException( "pythonscript:scriptURI2StorageUri: " +e
.getMessage(), None )
187 log
.error( "error during converting scriptURI="+scriptURI
+ ": " + str(e
))
188 raise RuntimeException( "pythonscript:scriptURI2StorageUri: " + str(e
), None )
192 def __init__( self
, lastRead
, module
):
193 self
.lastRead
= lastRead
196 def hasChanged( oldDate
, newDate
):
197 return newDate
.Year
> oldDate
.Year
or \
198 newDate
.Month
> oldDate
.Month
or \
199 newDate
.Day
> oldDate
.Day
or \
200 newDate
.Hours
> oldDate
.Hours
or \
201 newDate
.Minutes
> oldDate
.Minutes
or \
202 newDate
.Seconds
> oldDate
.Seconds
or \
203 newDate
.HundredthSeconds
> oldDate
.HundredthSeconds
205 def ensureSourceState( code
):
206 if not code
.endswith( "\n" ):
208 code
= code
.replace( "\r", "" )
212 def checkForPythonPathBesideScript( url
):
213 if url
.startswith( "file:" ):
214 path
= unohelper
.fileUrlToSystemPath( url
+"/pythonpath.zip" );
215 log
.log( LogLevel
.DEBUG
, "checking for existence of " + path
)
216 if 1 == os
.access( encfile(path
), os
.F_OK
) and not path
in sys
.path
:
217 log
.log( LogLevel
.DEBUG
, "adding " + path
+ " to sys.path" )
218 sys
.path
.append( path
)
220 path
= unohelper
.fileUrlToSystemPath( url
+"/pythonpath" );
221 log
.log( LogLevel
.DEBUG
, "checking for existence of " + path
)
222 if 1 == os
.access( encfile(path
), os
.F_OK
) and not path
in sys
.path
:
223 log
.log( LogLevel
.DEBUG
, "adding " + path
+ " to sys.path" )
224 sys
.path
.append( path
)
227 class ScriptContext(unohelper
.Base
):
228 def __init__( self
, ctx
, doc
):
233 def getDocument(self
):
234 return self
.getDesktop().getCurrentComponent()
236 def getDesktop(self
):
237 return self
.ctx
.ServiceManager
.createInstanceWithContext(
238 "com.sun.star.frame.Desktop", self
.ctx
)
240 def getComponentContext(self
):
243 #----------------------------------
244 # Global Module Administration
245 # does not fit together with script
246 # engine lifetime management
247 #----------------------------------
248 #g_scriptContext = ScriptContext( uno.getComponentContext(), None )
250 #def getModuleByUrl( url, sfa ):
251 # entry = g_modules.get(url)
253 # lastRead = sfa.getDateTimeModified( url )
255 # if hasChanged( entry.lastRead, lastRead ):
256 # log.isDebugLevel() and log.debug("file " + url + " has changed, reloading")
261 # log.isDebugLevel() and log.debug( "opening >" + url + "<" )
263 # code = readTextFromStream( sfa.openFileRead( url ) )
266 # entry = ModuleEntry( lastRead, imp.new_module("ooo_script_framework") )
267 # entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = g_scriptContext
268 # entry.module.__file__ = url
269 # exec code in entry.module.__dict__
270 # g_modules[ url ] = entry
271 # log.isDebugLevel() and log.debug( "mapped " + url + " to " + str( entry.module ) )
272 # return entry.module
274 class ProviderContext
:
275 def __init__( self
, storageType
, sfa
, uriHelper
, scriptContext
):
276 self
.storageType
= storageType
278 self
.uriHelper
= uriHelper
279 self
.scriptContext
= scriptContext
282 self
.mapPackageName2Path
= None
284 def getTransientPartFromUrl( self
, url
):
285 rest
= url
.replace( self
.rootUrl
, "",1 ).replace( "/","",1)
286 return rest
[0:rest
.find("/")]
288 def getPackageNameFromUrl( self
, url
):
289 rest
= url
.replace( self
.rootUrl
, "",1 ).replace( "/","",1)
290 start
= rest
.find("/") +1
291 return rest
[start
:rest
.find("/",start
)]
294 def removePackageByUrl( self
, url
):
295 items
= self
.mapPackageName2Path
.items()
297 if url
in i
[1].pathes
:
298 self
.mapPackageName2Path
.pop(i
[0])
301 def addPackageByUrl( self
, url
):
302 packageName
= self
.getPackageNameFromUrl( url
)
303 transientPart
= self
.getTransientPartFromUrl( url
)
304 log
.isDebugLevel() and log
.debug( "addPackageByUrl : " + packageName
+ ", " + transientPart
+ "("+url
+")" + ", rootUrl="+self
.rootUrl
)
305 if self
.mapPackageName2Path
.has_key( packageName
):
306 package
= self
.mapPackageName2Path
[ packageName
]
307 package
.pathes
= package
.pathes
+ (url
, )
309 package
= Package( (url
,), transientPart
)
310 self
.mapPackageName2Path
[ packageName
] = package
312 def isUrlInPackage( self
, url
):
313 values
= self
.mapPackageName2Path
.values()
315 # print "checking " + url + " in " + str(i.pathes)
321 def setPackageAttributes( self
, mapPackageName2Path
, rootUrl
):
322 self
.mapPackageName2Path
= mapPackageName2Path
323 self
.rootUrl
= rootUrl
325 def getPersistentUrlFromStorageUrl( self
, url
):
326 # package name is the second directory
329 pos
= len( self
.rootUrl
) +1
330 ret
= url
[0:pos
]+url
[url
.find("/",pos
)+1:len(url
)]
331 log
.isDebugLevel() and log
.debug( "getPersistentUrlFromStorageUrl " + url
+ " -> "+ ret
)
334 def getStorageUrlFromPersistentUrl( self
, url
):
337 pos
= len(self
.rootUrl
)+1
338 packageName
= url
[pos
:url
.find("/",pos
+1)]
339 package
= self
.mapPackageName2Path
[ packageName
]
340 ret
= url
[0:pos
]+ package
.transientPathElement
+ "/" + url
[pos
:len(url
)]
341 log
.isDebugLevel() and log
.debug( "getStorageUrlFromPersistentUrl " + url
+ " -> "+ ret
)
344 def getModuleByUrl( self
, url
):
345 entry
= self
.modules
.get(url
)
347 lastRead
= self
.sfa
.getDateTimeModified( url
)
349 if hasChanged( entry
.lastRead
, lastRead
):
350 log
.isDebugLevel() and log
.debug( "file " + url
+ " has changed, reloading" )
355 log
.isDebugLevel() and log
.debug( "opening >" + url
+ "<" )
357 src
= readTextFromStream( self
.sfa
.openFileRead( url
) )
358 checkForPythonPathBesideScript( url
[0:url
.rfind('/')] )
359 src
= ensureSourceState( src
)
362 entry
= ModuleEntry( lastRead
, imp
.new_module("ooo_script_framework") )
363 entry
.module
.__dict
__[GLOBAL_SCRIPTCONTEXT_NAME
] = self
.scriptContext
366 if url
.startswith( "file:" ):
367 code
= compile( src
, encfile(uno
.fileUrlToSystemPath( url
) ), "exec" )
369 code
= compile( src
, url
, "exec" )
370 exec code
in entry
.module
.__dict
__
371 entry
.module
.__file
__ = url
372 self
.modules
[ url
] = entry
373 log
.isDebugLevel() and log
.debug( "mapped " + url
+ " to " + str( entry
.module
) )
376 #--------------------------------------------------
377 def isScript( candidate
):
379 if isinstance( candidate
, type(isScript
) ):
383 #-------------------------------------------------------
384 class ScriptBrowseNode( unohelper
.Base
, XBrowseNode
, XPropertySet
, XInvocation
, XActionListener
):
385 def __init__( self
, provCtx
, uri
, fileName
, funcName
, func
):
386 self
.fileName
= fileName
387 self
.funcName
= funcName
388 self
.provCtx
= provCtx
395 def getChildNodes(self
):
398 def hasChildNodes(self
):
404 def getPropertyValue( self
, name
):
408 ret
= self
.provCtx
.uriHelper
.getScriptURI(
409 self
.provCtx
.getPersistentUrlFromStorageUrl( self
.uri
+ "$" + self
.funcName
) )
410 elif name
== "Description":
411 ret
= getattr( self
.func
, "__doc__", None )
412 elif name
== "Editable" and ENABLE_EDIT_DIALOG
:
413 ret
= not self
.provCtx
.sfa
.isReadOnly( self
.uri
)
415 log
.isDebugLevel() and log
.debug( "ScriptBrowseNode.getPropertyValue called for " + name
+ ", returning " + str(ret
) )
417 log
.error( "ScriptBrowseNode.getPropertyValue error " + lastException2String())
421 def setPropertyValue( self
, name
, value
):
422 log
.isDebugLevel() and log
.debug( "ScriptBrowseNode.setPropertyValue called " + name
+ "=" +str(value
) )
423 def getPropertySetInfo( self
):
424 log
.isDebugLevel() and log
.debug( "ScriptBrowseNode.getPropertySetInfo called " )
427 def getIntrospection( self
):
430 def invoke( self
, name
, params
, outparamindex
, outparams
):
431 if name
== "Editable":
432 servicename
= "com.sun.star.awt.DialogProvider"
433 ctx
= self
.provCtx
.scriptContext
.getComponentContext()
434 dlgprov
= ctx
.ServiceManager
.createInstanceWithContext(
437 self
.editor
= dlgprov
.createDialog(
438 "vnd.sun.star.script:" +
439 "ScriptBindingLibrary.MacroEditor?location=application")
441 code
= readTextFromStream(self
.provCtx
.sfa
.openFileRead(self
.uri
))
442 code
= ensureSourceState( code
)
443 self
.editor
.getControl("EditorTextField").setText(code
)
445 self
.editor
.getControl("RunButton").setActionCommand("Run")
446 self
.editor
.getControl("RunButton").addActionListener(self
)
447 self
.editor
.getControl("SaveButton").setActionCommand("Save")
448 self
.editor
.getControl("SaveButton").addActionListener(self
)
450 self
.editor
.execute()
454 def actionPerformed( self
, event
):
456 if event
.ActionCommand
== "Run":
457 code
= self
.editor
.getControl("EditorTextField").getText()
458 code
= ensureSourceState( code
)
459 mod
= imp
.new_module("ooo_script_framework")
460 mod
.__dict
__[GLOBAL_SCRIPTCONTEXT_NAME
] = self
.provCtx
.scriptContext
461 exec code
in mod
.__dict
__
462 values
= mod
.__dict
__.get( CALLABLE_CONTAINER_NAME
, None )
464 values
= mod
.__dict
__.values()
471 elif event
.ActionCommand
== "Save":
472 toWrite
= uno
.ByteSequence(
474 self
.editor
.getControl("EditorTextField").getText().encode(
475 sys
.getdefaultencoding())) )
476 copyUrl
= self
.uri
+ ".orig"
477 self
.provCtx
.sfa
.move( self
.uri
, copyUrl
)
478 out
= self
.provCtx
.sfa
.openFileWrite( self
.uri
)
479 out
.writeBytes( toWrite
)
481 self
.provCtx
.sfa
.kill( copyUrl
)
482 # log.isDebugLevel() and log.debug("Save is not implemented yet")
483 # text = self.editor.getControl("EditorTextField").getText()
484 # log.isDebugLevel() and log.debug("Would save: " + text)
486 # TODO: add an error box here !
487 log
.error( lastException2String() )
490 def setValue( self
, name
, value
):
493 def getValue( self
, name
):
496 def hasMethod( self
, name
):
499 def hasProperty( self
, name
):
503 #-------------------------------------------------------
504 class FileBrowseNode( unohelper
.Base
, XBrowseNode
):
505 def __init__( self
, provCtx
, uri
, name
):
506 self
.provCtx
= provCtx
514 def getChildNodes(self
):
517 self
.module
= self
.provCtx
.getModuleByUrl( self
.uri
)
518 values
= self
.module
.__dict
__.get( CALLABLE_CONTAINER_NAME
, None )
520 # no g_exportedScripts, export every function
521 if not isinstance(values
, type(())):
522 values
= self
.module
.__dict
__.values()
527 scriptNodeList
.append(
529 self
.provCtx
, self
.uri
, self
.name
, i
.__name
__, i
))
530 ret
= tuple( scriptNodeList
)
532 log
.isDebugLevel() and log
.debug( "returning " +str(len(ret
)) + " ScriptChildNodes on " + self
.uri
)
534 text
= lastException2String()
535 log
.error( "Error while evaluating " + self
.uri
+ ":" + text
)
539 def hasChildNodes(self
):
541 return len(self
.getChildNodes()) > 0
550 class DirBrowseNode( unohelper
.Base
, XBrowseNode
):
551 def __init__( self
, provCtx
, name
, rootUrl
):
552 self
.provCtx
= provCtx
554 self
.rootUrl
= rootUrl
559 def getChildNodes( self
):
561 log
.isDebugLevel() and log
.debug( "DirBrowseNode.getChildNodes called for " + self
.rootUrl
)
562 contents
= self
.provCtx
.sfa
.getFolderContents( self
.rootUrl
, True )
565 if i
.endswith( ".py" ):
566 log
.isDebugLevel() and log
.debug( "adding filenode " + i
)
567 browseNodeList
.append(
568 FileBrowseNode( self
.provCtx
, i
, i
[i
.rfind("/")+1:len(i
)-3] ) )
569 elif self
.provCtx
.sfa
.isFolder( i
) and not i
.endswith("/pythonpath"):
570 log
.isDebugLevel() and log
.debug( "adding DirBrowseNode " + i
)
571 browseNodeList
.append( DirBrowseNode( self
.provCtx
, i
[i
.rfind("/")+1:len(i
)],i
))
572 return tuple( browseNodeList
)
574 text
= lastException2String()
575 log
.error( "DirBrowseNode error: " + str(e
) + " while evaluating " + self
.rootUrl
)
579 def hasChildNodes( self
):
585 def getScript( self
, uri
):
586 log
.debug( "DirBrowseNode getScript " + uri
+ " invoked" )
587 raise IllegalArgumentException( "DirBrowseNode couldn't instantiate script " + uri
, self
, 0 )
590 class ManifestHandler( XDocumentHandler
, unohelper
.Base
):
591 def __init__( self
, rootUrl
):
592 self
.rootUrl
= rootUrl
594 def startDocument( self
):
597 def endDocument( self
):
600 def startElement( self
, name
, attlist
):
601 if name
== "manifest:file-entry":
602 if attlist
.getValueByName( "manifest:media-type" ) == "application/vnd.sun.star.framework-script":
604 self
.rootUrl
+ "/" + attlist
.getValueByName( "manifest:full-path" ) )
606 def endElement( self
, name
):
609 def characters ( self
, chars
):
612 def ignoreableWhitespace( self
, chars
):
615 def setDocumentLocator( self
, locator
):
618 def isPyFileInPath( sfa
, path
):
620 contents
= sfa
.getFolderContents( path
, True )
623 ret
= isPyFileInPath(sfa
,i
)
625 if i
.endswith(".py"):
631 # extracts META-INF directory from
632 def getPathesFromPackage( rootUrl
, sfa
):
635 fileUrl
= rootUrl
+ "/META-INF/manifest.xml"
636 inputStream
= sfa
.openFileRead( fileUrl
)
637 parser
= uno
.getComponentContext().ServiceManager
.createInstance( "com.sun.star.xml.sax.Parser" )
638 handler
= ManifestHandler( rootUrl
)
639 parser
.setDocumentHandler( handler
)
640 parser
.parseStream( InputSource( inputStream
, "", fileUrl
, fileUrl
) )
641 for i
in tuple(handler
.urlList
):
642 if not isPyFileInPath( sfa
, i
):
643 handler
.urlList
.remove(i
)
644 ret
= tuple( handler
.urlList
)
645 except UnoException
, e
:
646 text
= lastException2String()
647 log
.debug( "getPathesFromPackage " + fileUrl
+ " Exception: " +text
)
653 def __init__( self
, pathes
, transientPathElement
):
655 self
.transientPathElement
= transientPathElement
657 class DummyInteractionHandler( unohelper
.Base
, XInteractionHandler
):
658 def __init__( self
):
660 def handle( self
, event
):
661 log
.isDebugLevel() and log
.debug( "pythonscript: DummyInteractionHandler.handle " + str( event
) )
663 class DummyProgressHandler( unohelper
.Base
, XProgressHandler
):
664 def __init__( self
):
667 def push( self
,status
):
668 log
.isDebugLevel() and log
.debug( "pythonscript: DummyProgressHandler.push " + str( status
) )
669 def update( self
,status
):
670 log
.isDebugLevel() and log
.debug( "pythonscript: DummyProgressHandler.update " + str( status
) )
672 log
.isDebugLevel() and log
.debug( "pythonscript: DummyProgressHandler.push " + str( event
) )
674 class CommandEnvironment(unohelper
.Base
, XCommandEnvironment
):
675 def __init__( self
):
676 self
.progressHandler
= DummyProgressHandler()
677 self
.interactionHandler
= DummyInteractionHandler()
678 def getInteractionHandler( self
):
679 return self
.interactionHandler
680 def getProgressHandler( self
):
681 return self
.progressHandler
683 #maybe useful for debugging purposes
684 #class ModifyListener( unohelper.Base, XModifyListener ):
685 # def __init__( self ):
687 # def modified( self, event ):
688 # log.isDebugLevel() and log.debug( "pythonscript: ModifyListener.modified " + str( event ) )
689 # def disposing( self, event ):
690 # log.isDebugLevel() and log.debug( "pythonscript: ModifyListener.disposing " + str( event ) )
692 def mapStorageType2PackageContext( storageType
):
694 if( storageType
== "share:uno_packages" ):
696 if( storageType
== "user:uno_packages" ):
700 def getPackageName2PathMap( sfa
, storageType
):
702 packageManagerFactory
= uno
.getComponentContext().getValueByName(
703 "/singletons/com.sun.star.deployment.thePackageManagerFactory" )
704 packageManager
= packageManagerFactory
.getPackageManager(
705 mapStorageType2PackageContext(storageType
))
706 # packageManager.addModifyListener( ModifyListener() )
707 log
.isDebugLevel() and log
.debug( "pythonscript: getPackageName2PathMap start getDeployedPackages" )
708 packages
= packageManager
.getDeployedPackages(
709 packageManager
.createAbortChannel(), CommandEnvironment( ) )
710 log
.isDebugLevel() and log
.debug( "pythonscript: getPackageName2PathMap end getDeployedPackages (" + str(len(packages
))+")" )
713 log
.isDebugLevel() and log
.debug( "inspecting package " + i
.Name
+ "("+i
.Identifier
.Value
+")" )
714 transientPathElement
= penultimateElement( i
.URL
)
715 j
= expandUri( i
.URL
)
716 pathes
= getPathesFromPackage( j
, sfa
)
717 if len( pathes
) > 0:
718 # map package name to url, we need this later
719 log
.isErrorLevel() and log
.error( "adding Package " + transientPathElement
+ " " + str( pathes
) )
720 ret
[ lastElement( j
) ] = Package( pathes
, transientPathElement
)
723 def penultimateElement( aStr
):
724 lastSlash
= aStr
.rindex("/")
725 penultimateSlash
= aStr
.rindex("/",0,lastSlash
-1)
726 return aStr
[ penultimateSlash
+1:lastSlash
]
728 def lastElement( aStr
):
729 return aStr
[ aStr
.rfind( "/" )+1:len(aStr
)]
731 class PackageBrowseNode( unohelper
.Base
, XBrowseNode
):
732 def __init__( self
, provCtx
, name
, rootUrl
):
733 self
.provCtx
= provCtx
735 self
.rootUrl
= rootUrl
740 def getChildNodes( self
):
741 items
= self
.provCtx
.mapPackageName2Path
.items()
744 if len( i
[1].pathes
) == 1:
745 browseNodeList
.append(
746 DirBrowseNode( self
.provCtx
, i
[0], i
[1].pathes
[0] ))
748 for j
in i
[1].pathes
:
749 browseNodeList
.append(
750 DirBrowseNode( self
.provCtx
, i
[0]+"."+lastElement(j
), j
) )
751 return tuple( browseNodeList
)
753 def hasChildNodes( self
):
754 return len( self
.mapPackageName2Path
) > 0
759 def getScript( self
, uri
):
760 log
.debug( "DirBrowseNode getScript " + uri
+ " invoked" )
761 raise IllegalArgumentException( "PackageBrowseNode couldn't instantiate script " + uri
, self
, 0 )
766 class PythonScript( unohelper
.Base
, XScript
):
767 def __init__( self
, func
, mod
):
770 def invoke(self
, args
, out
, outindex
):
771 log
.isDebugLevel() and log
.debug( "PythonScript.invoke " + str( args
) )
773 ret
= self
.func( *args
)
774 except UnoException
,e
:
775 # UNO Exception continue to fly ...
776 text
= lastException2String()
777 complete
= "Error during invoking function " + \
778 str(self
.func
.__name
__) + " in module " + \
779 self
.mod
.__file
__ + " (" + text
+ ")"
780 log
.isDebugLevel() and log
.debug( complete
)
781 # some people may beat me up for modifying the exception text,
782 # but otherwise office just shows
783 # the type name and message text with no more information,
784 # this is really bad for most users.
785 e
.Message
= e
.Message
+ " (" + complete
+ ")"
788 # General python exception are converted to uno RuntimeException
789 text
= lastException2String()
790 complete
= "Error during invoking function " + \
791 str(self
.func
.__name
__) + " in module " + \
792 self
.mod
.__file
__ + " (" + text
+ ")"
793 log
.isDebugLevel() and log
.debug( complete
)
794 raise RuntimeException( complete
, self
)
795 log
.isDebugLevel() and log
.debug( "PythonScript.invoke ret = " + str( ret
) )
798 def expandUri( uri
):
799 if uri
.startswith( "vnd.sun.star.expand:" ):
800 uri
= uri
.replace( "vnd.sun.star.expand:", "",1)
801 uri
= uno
.getComponentContext().getByName(
802 "/singletons/com.sun.star.util.theMacroExpander" ).expandMacros( uri
)
805 #--------------------------------------------------------------
806 class PythonScriptProvider( unohelper
.Base
, XBrowseNode
, XScriptProvider
, XNameContainer
):
807 def __init__( self
, ctx
, *args
):
808 if log
.isDebugLevel():
813 mystr
= mystr
+ str(i
)
814 log
.debug( "Entering PythonScriptProvider.ctor" + mystr
)
817 if isinstance(args
[0],unicode ):
818 storageType
= args
[0]
820 storageType
= args
[0].SCRIPTING_DOC_URI
821 isPackage
= storageType
.endswith( ":uno_packages" )
824 # urlHelper = ctx.ServiceManager.createInstanceWithArgumentsAndContext(
825 # "com.sun.star.script.provider.ScriptURIHelper", (LANGUAGENAME, storageType), ctx)
826 urlHelper
= MyUriHelper( ctx
, storageType
)
827 log
.isDebugLevel() and log
.debug( "got urlHelper " + str( urlHelper
) )
829 rootUrl
= expandUri( urlHelper
.getRootStorageURI() )
830 log
.isDebugLevel() and log
.debug( storageType
+ " transformed to " + rootUrl
)
832 ucbService
= "com.sun.star.ucb.SimpleFileAccess"
833 sfa
= ctx
.ServiceManager
.createInstanceWithContext( ucbService
, ctx
)
835 log
.debug("PythonScriptProvider couldn't instantiate " +ucbService
)
836 raise RuntimeException(
837 "PythonScriptProvider couldn't instantiate " +ucbService
, self
)
838 self
.provCtx
= ProviderContext(
839 storageType
, sfa
, urlHelper
, ScriptContext( uno
.getComponentContext(), None ) )
841 mapPackageName2Path
= getPackageName2PathMap( sfa
, storageType
)
842 self
.provCtx
.setPackageAttributes( mapPackageName2Path
, rootUrl
)
843 self
.dirBrowseNode
= PackageBrowseNode( self
.provCtx
, LANGUAGENAME
, rootUrl
)
845 self
.dirBrowseNode
= DirBrowseNode( self
.provCtx
, LANGUAGENAME
, rootUrl
)
848 text
= lastException2String()
849 log
.debug( "PythonScriptProvider could not be instantiated because of : " + text
)
853 return self
.dirBrowseNode
.getName()
855 def getChildNodes( self
):
856 return self
.dirBrowseNode
.getChildNodes()
858 def hasChildNodes( self
):
859 return self
.dirBrowseNode
.hasChildNodes()
862 return self
.dirBrowseNode
.getType()
864 def getScript( self
, uri
):
865 log
.debug( "DirBrowseNode getScript " + uri
+ " invoked" )
867 raise IllegalArgumentException( "DirBrowseNode couldn't instantiate script " + uri
, self
, 0 )
869 def getScript( self
, scriptUri
):
871 log
.isDebugLevel() and log
.debug( "getScript " + scriptUri
+ " invoked")
873 storageUri
= self
.provCtx
.getStorageUrlFromPersistentUrl(
874 self
.provCtx
.uriHelper
.getStorageURI(scriptUri
) );
875 log
.isDebugLevel() and log
.debug( "getScript: storageUri = " + storageUri
)
876 fileUri
= storageUri
[0:storageUri
.find( "$" )]
877 funcName
= storageUri
[storageUri
.find( "$" )+1:len(storageUri
)]
879 mod
= self
.provCtx
.getModuleByUrl( fileUri
)
880 log
.isDebugLevel() and log
.debug( " got mod " + str(mod
) )
882 func
= mod
.__dict
__[ funcName
]
884 log
.isDebugLevel() and log
.debug( "got func " + str( func
) )
885 return PythonScript( func
, mod
)
887 text
= lastException2String()
889 raise ScriptFrameworkErrorException( text
, self
, scriptUri
, LANGUAGENAME
, 0 )
893 def getSupportedServices( self
):
894 return g_ImplementationHelper
.getSupportedServices(g_implName
)
896 def supportsService( self
, ServiceName
):
897 return g_ImplementationHelper
.supportsService( g_implName
, ServiceName
)
899 def getImplementationName(self
):
902 def getByName( self
, name
):
903 log
.debug( "getByName called" + str( name
))
907 def getElementNames( self
):
908 log
.debug( "getElementNames called")
911 def hasByName( self
, name
):
913 log
.debug( "hasByName called " + str( name
))
914 uri
= expandUri(name
)
915 ret
= self
.provCtx
.isUrlInPackage( uri
)
916 log
.debug( "hasByName " + uri
+ " " +str( ret
) )
919 text
= lastException2String()
920 log
.debug( "Error in hasByName:" + text
)
923 def removeByName( self
, name
):
924 log
.debug( "removeByName called" + str( name
))
925 uri
= expandUri( name
)
926 if self
.provCtx
.isUrlInPackage( uri
):
927 self
.provCtx
.removePackageByUrl( uri
)
929 log
.debug( "removeByName unknown uri " + str( name
) + ", ignoring" )
930 raise NoSuchElementException( uri
+ "is not in package" , self
)
931 log
.debug( "removeByName called" + str( uri
) + " successful" )
933 def insertByName( self
, name
, value
):
934 log
.debug( "insertByName called " + str( name
) + " " + str( value
))
935 uri
= expandUri( name
)
936 if isPyFileInPath( self
.provCtx
.sfa
, uri
):
937 self
.provCtx
.addPackageByUrl( uri
)
939 # package is no python package ...
940 log
.debug( "insertByName: no python files in " + str( uri
) + ", ignoring" )
941 raise IllegalArgumentException( uri
+ " does not contain .py files", self
, 1 )
942 log
.debug( "insertByName called " + str( uri
) + " successful" )
944 def replaceByName( self
, name
, value
):
945 log
.debug( "replaceByName called " + str( name
) + " " + str( value
))
948 log
.debug( "replaceByName called" + str( uri
) + " successful" )
950 def getElementType( self
):
951 log
.debug( "getElementType called" )
952 return uno
.getTypeByName( "void" )
954 def hasElements( self
):
955 log
.debug( "hasElements got called")
958 g_ImplementationHelper
.addImplementation( \
959 PythonScriptProvider
,g_implName
, \
960 ("com.sun.star.script.provider.LanguageScriptProvider",
961 "com.sun.star.script.provider.ScriptProviderFor"+ LANGUAGENAME
,),)
964 log
.debug( "pythonscript finished intializing" )