如何从 python 脚本调用现有的 LibreOffice python 宏
How to call an existing LibreOffice python macro from a python script
目前我用这个调用现有的现有 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>
然而,当从命令行 运行 脚本不执行任何操作并且 scriptx 打印为:
scriptx pyuno object (com.sun.star.script.provider.XScript)0x1e749d8{, supportedInterfaces={com.sun.star.lang.XTypeProvider,com.sun.star.script.provider.XScript}}
所以没有为 getScriptProvider 或 getScript 提供它们所需的东西。我目前对缺少的东西一头雾水,但我从骨子里觉得我已经接近解决方案了。
谁能看出我错在哪里?
终于,我有了一个可行的解决方案。叮!东!
#!/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
,它包含 1(一个)定义为 def fs2_TimeStamp(*args):
的函数
查看行:
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
或
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"
或
nohup lowriter "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp" &
另请注意,您必须 运行 带有 python3
的脚本
这是第一个答案的更简单、更通用的版本,它非常适合我的特定问题,它称为宏,然后在插入通过 TCP 连接发送的文本之前通过 TCP 与另一个程序对话。
此版本将 运行 独立,应该可以立即复制。
和以前一样,您必须以侦听模式启动 LibreOffice writer(有关选项,请参阅之前的答案):
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
目前我用这个调用现有的现有 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>
然而,当从命令行 运行 脚本不执行任何操作并且 scriptx 打印为:
scriptx pyuno object (com.sun.star.script.provider.XScript)0x1e749d8{, supportedInterfaces={com.sun.star.lang.XTypeProvider,com.sun.star.script.provider.XScript}}
所以没有为 getScriptProvider 或 getScript 提供它们所需的东西。我目前对缺少的东西一头雾水,但我从骨子里觉得我已经接近解决方案了。
谁能看出我错在哪里?
终于,我有了一个可行的解决方案。叮!东!
#!/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
,它包含 1(一个)定义为 def fs2_TimeStamp(*args):
的函数
查看行:
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
或
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"
或
nohup lowriter "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp" &
另请注意,您必须 运行 带有 python3
的脚本这是第一个答案的更简单、更通用的版本,它非常适合我的特定问题,它称为宏,然后在插入通过 TCP 连接发送的文本之前通过 TCP 与另一个程序对话。
此版本将 运行 独立,应该可以立即复制。
和以前一样,您必须以侦听模式启动 LibreOffice writer(有关选项,请参阅之前的答案):
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