LibreOffice5(100)埋め込みマクロを書きこむマクロの例

2017-12-03

旧ブログ

t f B! P L
OOoSF/Memo - ...?にある「ドキュメントにスクリプトを保存する」のBasicの例をCalc用にPythonに訳してそれをいじってみます。

前の関連記事:LibreOffice5(99)インプットストリーム、アウトプットストリーム、パイプの学習


ドキュメントにスクリプトを保存するPythonマクロの例

def macro(documentevent=None):  # 引数は文書のイベント駆動用。
 doc = XSCRIPTCONTEXT.getDocument() if documentevent is None else documentevent.Source  # ドキュメントのモデルを取得。
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。
 transientdocumentsdocumentcontentfactory = smgr.createInstanceWithContext("com.sun.star.frame.TransientDocumentsDocumentContentFactory", ctx)
 transientdocumentsdocumentcontent = transientdocumentsdocumentcontentfactory.createDocumentContent(doc)
 contentidentifierstring = transientdocumentsdocumentcontent.getIdentifier().getContentIdentifier()  # vnd.sun.star.tdoc:/IDを取得。
 simplefileaccess = smgr.createInstanceWithContext("com.sun.star.ucb.SimpleFileAccess", ctx)
 scriptsdir = "{}/Scripts".format(contentidentifierstring)
 if not simplefileaccess.exists(scriptsdir) and not simplefileaccess.isFolder(scriptsdir):  # scriptsdirというファイルもフォルダも存在しない時。
  simplefileaccess.createFolder(scriptsdir)
 if not simplefileaccess.exists(scriptsdir):
  print("failed to create Scripts directory.")
 pythondir = "{}/python".format(scriptsdir)
 if not simplefileaccess.exists(pythondir) and not simplefileaccess.isFolder(pythondir):  # pythondirというファイルもフォルダも存在しない時。
  simplefileaccess.createFolder(pythondir)
 if not simplefileaccess.exists(pythondir):
  print("failed to create python directory.")
 pythondir = "{}/".format(pythondir)
 scriptpath = "{}hello.py".format(pythondir)
 if simplefileaccess.exists(scriptpath):
  simplefileaccess.kill(scriptpath)
 pipe = smgr.createInstanceWithContext("com.sun.star.io.Pipe", ctx)
 textoutputstream = smgr.createInstanceWithContext("com.sun.star.io.TextOutputStream", ctx)
 textoutputstream.setOutputStream(pipe)
 script = """# -*- coding: utf-8 -*-
def macro():
 doc = XSCRIPTCONTEXT.getDocument()
 controller = doc.getCurrentController()  # コントローラーを取得。
 sheet = controller.getActiveSheet()  # アクティブなシートを取得。
 sheet["A1"].setString("Hello by the embedded script.")
"""
 textoutputstream.writeString(script)
 textoutputstream.flush()
 textoutputstream.closeOutput()
 simplefileaccess.writeFile(scriptpath, pipe)
 pipe.closeInput()
g_exportedScripts = macro, #マクロセレクターに限定表示させる関数をタプルで指定。
このマクロをCalcドキュメントで実行するとhello.pyというマクロファイルがそのドキュメントに埋め込まれます。


ドキュメントのセキュリティの制限のために、マクロセレクターでこのマクロを実行しようとしても何も反応がありません。


APSOで実行しようとするとセキュリティが原因で動かないと言われます。

この埋め込みマクロを実行するにはドキュメントのAllowMacroExecutionアトリビュートをFalseからTrueに変更しないといけませんが、readonlyなのでマクロでは変更できません。

埋め込みマクロを実行するにはファイルを閉じて保存してまた開きます。


「マクロを有効化」ボタンをクリックして、埋め込みマクロを実行するとA1シェルに文字列が出力されます。


ドキュメントにスクリプトを保存するPythonマクロの例: その2


SimpleFileAccessのcreateFolder()メソッドはパスを渡すとパス中の存在しないフォルダをすべて作成してくれました。

TextOutputStreamのflush()メソッドはcloseOutput()メソッドを実行するとデータを書き出してくれるので今回マクロの場合は実行する必要はありませんでした。

SimpleFileAccessのkill()メソッドで既にある埋め込みマクロファイルを削除しなくても、上書きできました。

ただ、埋め込みマクロファイルを削除したとしても、すでにあったファイル名で書き込みするときは一旦ドキュメントを閉じないといけませんでした。

それについては次にやります。
def macro(documentevent=None):  # 引数は文書のイベント駆動用。
 doc = XSCRIPTCONTEXT.getDocument() if documentevent is None else documentevent.Source  # ドキュメントのモデルを取得。 
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。 
 pipe = smgr.createInstanceWithContext("com.sun.star.io.Pipe", ctx)  # Pipe
 textoutputstream = smgr.createInstanceWithContext("com.sun.star.io.TextOutputStream", ctx)  # TextOutputStream
 textoutputstream.setOutputStream(pipe)  # アウトプットストリームを設定。
 script = """# -*- coding: utf-8 -*-
def macro():
 doc = XSCRIPTCONTEXT.getDocument()
 controller = doc.getCurrentController()  # コントローラーを取得。
 sheet = controller.getActiveSheet()  # アクティブなシートを取得。
 sheet["A1"].setString("Hello by the embedded script.")
"""  # 書き込むテキストデータ。
 textoutputstream.writeString(script)  # テキストデータをアウトプットストリームに設定。
#  textoutputstream.flush()  # アウトプットストリームを送り出す。
 textoutputstream.closeOutput()  # アウトプットストリームを閉じる。flushもする。
 transientdocumentsdocumentcontentfactory = smgr.createInstanceWithContext("com.sun.star.frame.TransientDocumentsDocumentContentFactory", ctx)  # TransientDocumentsDocumentContentFactory
 documentcontent = transientdocumentsdocumentcontentfactory.createDocumentContent(doc)  # ドキュメントのコンテントを取得。
 contentidentifierstring = documentcontent.getIdentifier().getContentIdentifier()  # ドキュメントコンテントのルートパス、vnd.sun.star.tdoc:/IDを取得。IDは一時的な整数。
 simplefileaccess = smgr.createInstanceWithContext("com.sun.star.ucb.SimpleFileAccess", ctx)  # SimpleFileAccess
 embeddedmacropath = "{}/Scripts/python".format(contentidentifierstring)  # 埋め込みマクロフォルダのパス。
 if not simplefileaccess.exists(embeddedmacropath):  # 埋め込みマクロフォルダが存在しないとき。
  simplefileaccess.createFolder(embeddedmacropath)  # 埋め込みマクロフォルダを作成する。urlの最後に/がついていても、途中のフォルダがなくても作成してくれる。ただし、中身を入れないとmanifest.xmlに記録されるだけ。
 scriptpath = "{}/hello.py".format(embeddedmacropath)  # 埋め込みマクロファイルのパス。
#  if simplefileaccess.exists(scriptpath):  # マクロファイルがあるとき。
#   simplefileaccess.kill(scriptpath)  # すでにあるファイルを削除。
 simplefileaccess.writeFile(scriptpath, pipe)  # pipeをインプットストリームとしてマクロファイルに書き込む。
 pipe.closeInput()  # pipeのインプットストリームを閉じる。
g_exportedScripts = macro, #マクロセレクターに限定表示させる関数をタプルで指定。

ドキュメントにスクリプトを保存するPythonマクロの例: その3


上の例ではPipeをアウトプットストリームとして書き込みを行い(Pipeからみると書き込まれる)、ファイルにはインプットストリームとして書き出しています(Pipeからみると読み込まれる)。

SimpleFileAccessのopenFileWrite()メソッドは引数のfileurlのファイルをアウトプットストリームとして開きます(つまり書き込まれる対象)。

これでPipeを介さず直接ファイルに書き込みできますが、writeFile()メソッドがファイルが存在しなければ新規に作成してくれるの対して、openFileWrite()メソッドは引数のファイルが存在しないとエラーになります。
def macro(documentevent=None):  # 引数は文書のイベント駆動用。
 doc = XSCRIPTCONTEXT.getDocument() if documentevent is None else documentevent.Source  # ドキュメントのモデルを取得。 
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。 
 transientdocumentsdocumentcontentfactory = smgr.createInstanceWithContext("com.sun.star.frame.TransientDocumentsDocumentContentFactory", ctx)  # TransientDocumentsDocumentContentFactory
 documentcontent = transientdocumentsdocumentcontentfactory.createDocumentContent(doc)  # ドキュメントのコンテントを取得。
 contentidentifierstring = documentcontent.getIdentifier().getContentIdentifier()  # ドキュメントコンテントのルートパス、vnd.sun.star.tdoc:/IDを取得。IDは一時的な整数。
 simplefileaccess = smgr.createInstanceWithContext("com.sun.star.ucb.SimpleFileAccess", ctx)  # SimpleFileAccess
 embeddedmacropath = "{}/Scripts/python".format(contentidentifierstring)  # 埋め込みマクロフォルダのパス。
 if not simplefileaccess.exists(embeddedmacropath):  # 埋め込みマクロフォルダが存在しないとき。
  simplefileaccess.createFolder(embeddedmacropath)  # 埋め込みマクロフォルダを作成する。urlの最後に/がついていても、途中のフォルダがなくても作成してくれる。ただし、中身を入れないとmanifest.xmlに記録されるだけ。
 scriptpath = "{}/hello.py".format(embeddedmacropath)  # 埋め込みマクロファイルのパス。
 outputstream = simplefileaccess.openFileWrite(scriptpath)  # ファイルのアウトプットストリームを取得。ファイルが存在しないとエラーになる。
 textoutputstream = smgr.createInstanceWithContext("com.sun.star.io.TextOutputStream", ctx)  # TextOutputStream
 textoutputstream.setOutputStream(outputstream)  # アウトプットストリームを設定。
 script = """# -*- coding: utf-8 -*-
def macro():
 doc = XSCRIPTCONTEXT.getDocument()
 controller = doc.getCurrentController()  # コントローラーを取得。
 sheet = controller.getActiveSheet()  # アクティブなシートを取得。
 sheet["A2"].setString("Hello by the embedded script.")
"""  # 書き込むテキストデータ。
 textoutputstream.writeString(script)  # テキストデータをアウトプットストリームに設定。
 textoutputstream.closeOutput()  # アウトプットストリームを閉じる。  
g_exportedScripts = macro, #マクロセレクターに限定表示させる関数をタプルで指定。 
すでにhello.pyが埋め込まれているドキュメントでこのマクロを実行すると"Hello by the embedded script."をA2セルに出力するhello.pyに書き換えられます。

ドキュメントにスクリプトを保存するPythonマクロの例: その4


TempFileはXInputStreamとXOutputStreamをもっておりPipeと同様にして使えますが、次の例ではドキュメントに書き込むときはインプットストリームとしてではななく、ファイルとしてSimpleFileAccessのcopy()メソッドを使っています。
def macro(documentevent=None):  # 引数は文書のイベント駆動用。
 doc = XSCRIPTCONTEXT.getDocument() if documentevent is None else documentevent.Source  # ドキュメントのモデルを取得。 
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。 
 transientdocumentsdocumentcontentfactory = smgr.createInstanceWithContext("com.sun.star.frame.TransientDocumentsDocumentContentFactory", ctx)
 documentcontent = transientdocumentsdocumentcontentfactory.createDocumentContent(doc)  # ドキュメントのコンテントを取得。
 contentidentifierstring = documentcontent.getIdentifier().getContentIdentifier()  # ドキュメントコンテントのルートパス、vnd.sun.star.tdoc:/IDを取得。IDは一時的な整数。
 simplefileaccess = smgr.createInstanceWithContext("com.sun.star.ucb.SimpleFileAccess", ctx)   
 embeddedmacropath = "{}/Scripts/python".format(contentidentifierstring)  # 埋め込みマクロフォルダのパス。
 if not simplefileaccess.exists(embeddedmacropath):  # 埋め込みマクロフォルダが存在しないとき。
  simplefileaccess.createFolder(embeddedmacropath)  # 埋め込みマクロフォルダを作成する。urlの最後に/がついていても、途中のフォルダがなくても作成してくれる。ただし、中身を入れないとmanifest.xmlに記録されるだけ。
 scriptpath = "{}/hello.py".format(embeddedmacropath)  # 埋め込みマクロファイルのパス。
 tempfile = smgr.createInstanceWithContext("com.sun.star.io.TempFile", ctx) # TempFile
 outputstream = simplefileaccess.openFileWrite(tempfile.Uri)  # 一時ファイルのアウトプットストリームを取得。
 textoutputstream = smgr.createInstanceWithContext("com.sun.star.io.TextOutputStream", ctx)  # TextOutputStream
 textoutputstream.setOutputStream(outputstream)  # アウトプットストリームを設定。
 script = """# -*- coding: utf-8 -*-
def macro():
 doc = XSCRIPTCONTEXT.getDocument()
 controller = doc.getCurrentController()  # コントローラーを取得。
 sheet = controller.getActiveSheet()  # アクティブなシートを取得。
 sheet["A1"].setString("Hello by the embedded script.")
"""  # 書き込むテキストデータ。
 textoutputstream.writeString(script)  # テキストデータをアウトプットストリームに設定。
 textoutputstream.closeOutput()  # アウトプットストリームを閉じる。  
 simplefileaccess.copy(tempfile.Uri, scriptpath)  # 一時ファイルをドキュメント内にコピーする。
g_exportedScripts = macro, #マクロセレクターに限定表示させる関数をタプルで指定。 

参考にしたサイト


OOoSF/Memo - ...?
ドキュメントにスクリプトを保存するBasicの例。

次の関連記事:LibreOffice5(101)埋め込みマクロの更新とマクロセレクターとAPSO

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ