如何从python脚本调用现有的LibreOffice python宏

时间:2015-04-02 15:46:41

标签: python macros wxpython libreoffice

目前我用以下方法调用现有的现有LibreOffice宏:

def OnLOtimestamp(self):
        try:
            pid= Popen(['lowriter '"'"'vnd.sun.star.script:fs2TimeStamp.py$fs2_TimeStamp?language=Python&location=user'"'"],shell=True).pid
        except OSError, e:
            self.notify_show("Timestamp Error",str(e))
        self.ma2.SetLabel("Macro timestamp")
        self.database['Time_stamp'] = self.database['Time_stamp'] + 1

关键位是Popen调用,其中宏名称是fs2TimeStamp.py,函数是fs2_TimeStamp,但这感觉就像一个警察,我宁愿通过Uno执行直接调用。 我的研究表明,我可能需要使用MasterScriptProvider,XscriptProvider和XscriptInvocation,但试图破解Uno API就像游过糖蜜一样。 有没有人使用Uno?

获得了在Libreoffice中调用现有宏的代码示例

编辑:
到目前为止,答案似乎是否定的! 这是目前的状态。

#!/usr/bin/python3
# -*- coding: utf-8 -*-
##
# a python script to run a libreoffice python macro externally
#
import uno
from com.sun.star.connection import NoConnectException
from com.sun.star.uno  import RuntimeException
from com.sun.star.uno  import Exception
from com.sun.star.lang import IllegalArgumentException
def test2(*args):
    localContext = uno.getComponentContext()
    localsmgr = localContext.ServiceManager
    resolver = localsmgr.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext )
    try:
        ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
    except NoConnectException as e:
        print ("LibreOffice is not running or not listening on the port given - ("+e.Message+")")
        return
    except IllegalArgumentException as e:
        print ("Invalid argument given - ( "+ e.Message+ ")")
        return
    except RuntimeException as e:
        print ("An unknown error occurred: " + e.Message)
        return

    servmgr = ctx.ServiceManager
    desktop = servmgr.createInstanceWithContext( "com.sun.star.frame.Desktop",ctx)
    model = desktop.getCurrentComponent()
#    scriptP = model.getScriptProvider()
#    print("scriptP", scriptP)
    scriptx = model.getScriptProvider().getScript('vnd.sun.star.script:fs2TimeStamp.py$fs2_TimeStamp?language=Python&location=user')
    print("scriptx", scriptx)
    try:
        scriptx.invoke("",0,0)
    except IllegalArgumentException as e:
        print ("The command given is invalid ( "+ e.Message+ ")")
        return
    except RuntimeException as e:
        print("An unknown error occurred: " + e.Message)
        return
    except Exception as e:
        print ("Script error ( "+ e.Message+ ")")
        print(e)
        return
    except:
        print("Error")
    return(None)

test2()

当在Libreoffice中作为宏调用并且scriptx打印出来时,此代码可以很好地工作:

scriptx <pythonscript.PythonScript object at 0x7fa2879c42e8>

然而,当从命令行运行时,脚本什么也不做,脚本x打印出来:

scriptx pyuno object (com.sun.star.script.provider.XScript)0x1e749d8{, supportedInterfaces={com.sun.star.lang.XTypeProvider,com.sun.star.script.provider.XScript}}

因此,没有为getScriptProvider或getScript提供他们需要的东西。我目前对于缺少的东西感到茫然,但我觉得我的骨子里有一个接近解决方案。

谁能看到我犯了错误?

2 个答案:

答案 0 :(得分:1)

最后,我有一个有效的解决方案。丁!董!

#!/usr/bin/python3
# -*- coding: utf-8 -*-
##
# a python script to run a libreoffice python macro externally
#
import uno
from com.sun.star.connection import NoConnectException
from com.sun.star.uno  import RuntimeException
from com.sun.star.uno  import Exception
from com.sun.star.lang import IllegalArgumentException
def test2(*args):
    localContext = uno.getComponentContext()
    localsmgr = localContext.ServiceManager
    resolver =  localsmgr.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext )
    try:
        ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
    except NoConnectException as e:
        print ("LibreOffice is not running or not listening on the port given - ("+e.Message+")")
        return
    msp = ctx.getValueByName("/singletons/com.sun.star.script.provider.theMasterScriptProviderFactory")
    sp = msp.createScriptProvider("")
    scriptx = sp.getScript('vnd.sun.star.script:fs2TimeStamp.py$fs2_TimeStamp?language=Python&location=user')
    try:
        scriptx.invoke((), (), ())
    except IllegalArgumentException as e:
        print ("The command given is invalid ( "+ e.Message+ ")")
        return
    except RuntimeException as e:
        print("An unknown error occurred: " + e.Message)
        return
    except Exception as e:
        print ("Script error ( "+ e.Message+ ")")

return(None)

test2()

注意:为了清楚起见,现有的python脚本称为fs2TimeStamp.py,它包含定义为def fs2_TimeStamp(*args):的1(一)个函数。 见行:

scriptx = sp.getScript('vnd.sun.star.script:fs2TimeStamp.py$fs2_TimeStamp?language=Python&location=user')   

并存储在$HOME/.config/libreoffice/4/user/Scripts/python

要使此解决方案正常工作,libreoffice 必须在侦听模式下运行,因此请使用以下命令启动libreoffice:

soffice "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;" --writer --norestore

OR

nohup soffice "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;" --writer --norestore &

或者你可以使用更直接的方法(对于这个例子中的writer):

lowriter "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp"

OR

nohup lowriter "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp" &

另请注意您必须使用 python3

运行脚本

答案 1 :(得分:1)

这是第一个答案的更简单和更通用的版本,它非常倾向于我的特定问题,它称为宏,然后在插入通过TCP连接发送的文本之前通过TCP与另一个程序进行通信。 /> 此版本将独立运行,应立即可复制 和以前一样,你必须在监听模式下启动LibreOffice编写器(参见前面的选项答案):

lowriter "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp"

这是外部python例程,必须与python3

一起运行
#!/usr/bin/python3
# -*- coding: utf-8 -*-
##
# a python script to run a libreoffice python macro externally
# NOTE: for this to run start libreoffice in the following manner
# soffice "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;" --writer --norestore
# OR
# nohup soffice "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;" --writer --norestore &
#
import uno
from com.sun.star.connection import NoConnectException
from com.sun.star.uno  import RuntimeException
from com.sun.star.uno  import Exception
from com.sun.star.lang import IllegalArgumentException
def uno_directmacro(*args):
    localContext = uno.getComponentContext()
    localsmgr = localContext.ServiceManager
    resolver = localsmgr.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext )
    try:
        ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
    except NoConnectException as e:
        print ("LibreOffice is not running or not listening on the port given - ("+e.Message+")")
        return
    msp = ctx.getValueByName("/singletons/com.sun.star.script.provider.theMasterScriptProviderFactory")
    sp = msp.createScriptProvider("")
    scriptx = sp.getScript('vnd.sun.star.script:directmacro.py$directmacro?language=Python&location=user')
    try:
        scriptx.invoke((), (), ())
    except IllegalArgumentException as e:
        print ("The command given is invalid ( "+ e.Message+ ")")
        return
    except RuntimeException as e:
        print("An unknown error occurred: " + e.Message)
        return
    except Exception as e:
        print ("Script error ( "+ e.Message+ ")")
        print(e)
        return
    return(None)

uno_directmacro()

这是LibreOffice python宏directmacro.py,它应位于:

$HOME/.config/libreoffice/4/user/Scripts/python

(假设在这里使用LibreOffice第4版)

directmacro.py宏:

#!/usr/bin/python
class FontSlant():
    from com.sun.star.awt.FontSlant import (NONE, ITALIC,)

def directmacro(*args):
#get the doc from the scripting context which is made available to all scripts
    desktop = XSCRIPTCONTEXT.getDesktop()
    model = desktop.getCurrentComponent()
    text = model.Text
    tRange = text.End
    cursor = desktop.getCurrentComponent().getCurrentController().getViewCursor()
    doc = XSCRIPTCONTEXT.getDocument()
    parentwindow = doc.CurrentController.Frame.ContainerWindow

# your cannot insert simple text and text into a table with the same method
# so we have to know if we are in a table or not.
# oTable and oCurCell will be null if we are not in a table
    oTable = cursor.TextTable
    oCurCell = cursor.Cell
    insert_text = "This is text inserted into a LibreOffice Document\ndirectly from a macro called externally"
    Text_Italic = FontSlant.ITALIC
    Text_None = FontSlant.NONE
    cursor.CharPosture=Text_Italic
    if oCurCell == None: # Are we inserting into a table or not?
        text.insertString(cursor, insert_text, 0)
    else:
        cell = oTable.getCellByName(oCurCell.CellName)
        cell.insertString(cursor, insert_text, False)
    cursor.CharPosture=Text_None
    return None