This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch python-editing-embedding in repository https://gitbox.apache.org/repos/asf/openoffice.git
commit 511d7659d6d13792e95e05cf645b3a92ce011e4c Author: Damjan Jovanovic <[email protected]> AuthorDate: Sun Apr 26 11:42:44 2026 +0200 Get Python file editing working. Patch by: me --- main/scripting/source/pyprov/pythonscript.py | 192 +++++++++++++++++++++++---- 1 file changed, 166 insertions(+), 26 deletions(-) diff --git a/main/scripting/source/pyprov/pythonscript.py b/main/scripting/source/pyprov/pythonscript.py index 9052e3daa2..77346bec1f 100644 --- a/main/scripting/source/pyprov/pythonscript.py +++ b/main/scripting/source/pyprov/pythonscript.py @@ -52,7 +52,7 @@ elif os.environ.get(PYSCRIPT_LOG_ENV) == "DEBUG": # False, writes to user/Scripts/python/log.txt LOG_STDOUT = os.environ.get(PYSCRIPT_LOG_STDOUT_ENV, "1") != "0" -ENABLE_EDIT_DIALOG=False # offers a minimal editor for editing. +ENABLE_EDIT_DIALOG=True # offers a minimal editor for editing. #------------------------------------------------------------------- def encfile(uni): @@ -174,24 +174,51 @@ def toIniName( str ): return str + "rc" class EmptyInputStream( unohelper.Base, XInputStream ): - def __init__( self ): - pass + def __init__( self ): + pass + + def closeInput(self): + pass + + def readBytes( self, seq, n ): + return 0, "" + + def readSomeBytes( self, seq, n ): + return 0, "" - def closeInput(self): - pass + def skipBytes( self, n ): + pass + + def available( self ): + return 0 + +class BytesInputStream( unohelper.Base, XInputStream ): + def __init__( self, bytes ): + self.bytes = bytes + self.position = 0 - def readBytes( self, seq, n ): - return 0, "" + def closeInput(self): + pass - def readSomeBytes( self, seq, n ): - return 0, "" + def readBytes( self, seq, n ): + size = self.available() + if n < size: + size = n + curr = self.position + self.position += size + return size, uno.ByteSequence( self.bytes[curr:curr+size] ) - def skipBytes( self, n ): - pass + def readSomeBytes( self, seq, n ): + return self.readBytes( seq, n ) - def available( self ): - return 0 + def skipBytes( self, n ): + size = self.available() + if n < size: + size = n + self.position += size + def available( self ): + return len( self.bytes ) - self.position """ definition: storageURI is the system dependent, absolute file url, where the script is stored on disk scriptURI is the system independent uri @@ -476,6 +503,78 @@ class ProviderContext: log.debug( "mapped " + url + " to " + str( entry.module ) ) return entry.module +def createEditorDialog( ctx ): + smgr = ctx.ServiceManager + + dialogModel = smgr.createInstanceWithContext( + "com.sun.star.awt.UnoControlDialogModel", ctx) + dialogModel.PositionX = 105 + dialogModel.PositionY = 117 + dialogModel.Width = 240 + dialogModel.Height = 320 + dialogModel.Closeable = True + dialogModel.Moveable = True + dialogModel.Title = "Python Macro Editor" + + runButtonModel = dialogModel.createInstance( + "com.sun.star.awt.UnoControlButtonModel" ) + runButtonModel.PositionX = 57 + runButtonModel.PositionY = 300 + runButtonModel.Width = 40 + runButtonModel.Height = 14 + runButtonModel.TabIndex = 0 + runButtonModel.Label = "Run" + + saveButtonModel = dialogModel.createInstance( + "com.sun.star.awt.UnoControlButtonModel" ) + saveButtonModel.PositionX = 100 + saveButtonModel.PositionY = 300 + saveButtonModel.Width = 40 + saveButtonModel.Height = 14 + saveButtonModel.TabIndex = 1 + saveButtonModel.Label = "Save" + + closeButtonModel = dialogModel.createInstance( + "com.sun.star.awt.UnoControlButtonModel" ) + closeButtonModel.PositionX = 143 + closeButtonModel.PositionY = 300 + closeButtonModel.Width = 40 + closeButtonModel.Height = 14 + closeButtonModel.TabIndex = 2 + closeButtonModel.PushButtonType = 2 # CANCEL + closeButtonModel.Label = "Close" + + textFieldModel = dialogModel.createInstance( + "com.sun.star.awt.UnoControlEditModel" ) + textFieldModel.PositionX = 6 + textFieldModel.PositionY = 6 + textFieldModel.Width = 228 + textFieldModel.Height = 288 + textFieldModel.TabIndex = 3 + textFieldModel.HScroll = True + textFieldModel.VScroll = True + textFieldModel.MultiLine = True + + dialogModel.insertByName( "RunButton", runButtonModel ) + dialogModel.insertByName( "SaveButton", saveButtonModel ) + dialogModel.insertByName( "CloseButton", closeButtonModel ) + dialogModel.insertByName( "EditorTextField", textFieldModel ) + + # create the dialog control and set the model + controlContainer = smgr.createInstanceWithContext( + "com.sun.star.awt.UnoControlDialog", ctx); + controlContainer.setModel(dialogModel); + + # create a peer + toolkit = smgr.createInstanceWithContext( + "com.sun.star.awt.ExtToolkit", ctx); + + controlContainer.setVisible(False); + controlContainer.createPeer(toolkit, None); + + return controlContainer + + #-------------------------------------------------- def isScript( candidate ): ret = False @@ -532,14 +631,9 @@ class ScriptBrowseNode( unohelper.Base, XBrowseNode , XPropertySet, XInvocation, def invoke( self, name, params, outparamindex, outparams ): if name == "Editable": - servicename = "com.sun.star.awt.DialogProvider" ctx = self.provCtx.scriptContext.getComponentContext() - dlgprov = ctx.ServiceManager.createInstanceWithContext( - servicename, ctx ) - self.editor = dlgprov.createDialog( - "vnd.sun.star.script:" + - "ScriptBindingLibrary.MacroEditor?location=application") + self.editor = createEditorDialog( ctx ) code = readTextFromStream(self.provCtx.sfa.openFileRead(self.uri())) code = ensureSourceState( code ) @@ -573,14 +667,12 @@ class ScriptBrowseNode( unohelper.Base, XBrowseNode , XPropertySet, XInvocation, elif event.ActionCommand == "Save": toWrite = uno.ByteSequence( - str( self.editor.getControl("EditorTextField").getText().encode( - sys.getdefaultencoding())) ) + sys.getdefaultencoding())) copyUrl = self.uri() + ".orig" self.provCtx.sfa.move( self.uri(), copyUrl ) - out = self.provCtx.sfa.openFileWrite( self.uri() ) - out.writeBytes( toWrite ) - out.close() + log.debug( "Saving Python macro to URI " + self.uri() ) + self.provCtx.sfa.writeFile( self.uri(), BytesInputStream( toWrite.value ) ) self.provCtx.sfa.kill( copyUrl ) # log.debug("Save is not implemented yet") # text = self.editor.getControl("EditorTextField").getText() @@ -604,7 +696,7 @@ class ScriptBrowseNode( unohelper.Base, XBrowseNode , XPropertySet, XInvocation, #------------------------------------------------------- -class FileBrowseNode( unohelper.Base, XBrowseNode, XPropertySet, XInvocation ): +class FileBrowseNode( unohelper.Base, XBrowseNode, XPropertySet, XInvocation, XActionListener ): def __init__( self, provCtx, parent, name ): self.provCtx = provCtx self.parent = parent @@ -679,7 +771,20 @@ class FileBrowseNode( unohelper.Base, XBrowseNode, XPropertySet, XInvocation ): log.debug("FileBrowseNode.invoke called for " + name + "," + str(params) + "," + str(outparamindex) + "," + str(outparams)) try: if name == "Editable": - log.error("Editable not implemented") + ctx = self.provCtx.scriptContext.getComponentContext() + + self.editor = createEditorDialog( ctx ) + + code = readTextFromStream(self.provCtx.sfa.openFileRead(self.uri())) + code = ensureSourceState( code ) + self.editor.getControl("EditorTextField").setText(code) + + self.editor.getControl("RunButton").setActionCommand("Run") + self.editor.getControl("RunButton").addActionListener(self) + self.editor.getControl("SaveButton").setActionCommand("Save") + self.editor.getControl("SaveButton").addActionListener(self) + + self.editor.execute() elif name == "Deletable": self.provCtx.sfa.kill( self.uri() ) return True, (), () @@ -708,6 +813,41 @@ class FileBrowseNode( unohelper.Base, XBrowseNode, XPropertySet, XInvocation ): def hasProperty( self, name ): return False + # XActionListener + + def actionPerformed( self, event ): + try: + if event.ActionCommand == "Run": + code = self.editor.getControl("EditorTextField").getText() + code = ensureSourceState( code ) + mod = imp.new_module("ooo_script_framework") + mod.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = self.provCtx.scriptContext + exec(code, mod.__dict__) + values = mod.__dict__.get( CALLABLE_CONTAINER_NAME , None ) + if not values: + values = list(mod.__dict__.values()) + + for i in values: + if isScript( i ): + i() + break + + elif event.ActionCommand == "Save": + toWrite = uno.ByteSequence( + self.editor.getControl("EditorTextField").getText().encode( + sys.getdefaultencoding())) + copyUrl = self.uri() + ".orig" + self.provCtx.sfa.move( self.uri(), copyUrl ) + log.debug( "Saving Python macro to URI " + self.uri() ) + self.provCtx.sfa.writeFile( self.uri(), BytesInputStream( toWrite.value ) ) + self.provCtx.sfa.kill( copyUrl ) +# log.debug("Save is not implemented yet") +# text = self.editor.getControl("EditorTextField").getText() +# log.debug("Would save: " + text) + except Exception as e: + # TODO: add an error box here ! + log.error( lastException2String() ) + class DirBrowseNode( unohelper.Base, XBrowseNode, XPropertySet, XInvocation ): def __init__( self, provCtx, name, rootUrl, depth ):
