2019年12月29日日曜日

24: UNOディスパッチコマンドを実行し、全情報を取得する(Basic編)

<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>

LibreOfficeまたはApache OpenOffice Basicで。あなたの怠惰な方法は、実行から入手可能な一部の有用な情報を逃しているかもしれません。

話題


About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: LibreOffice Basic
About: Apache OpenOffice Basic

この記事の目次


開始コンテキスト



ターゲットコンテキスト



  • 読者は、LibreOfficeまたはApache OpenOffice BasicでUNOディスパッチコマンドを実行してその結果情報および関連情報を取得する方法を知る。
ト書き
Hypothesizer 7、Objector 24A、Objector 24Bがコンピューターの前にいる。


オリエンテーション


Hypothesizer 7
この記事では、LibreOfficeまたはApache OpenOffice BasicでUNOディスパッチコマンドを実行してその結果情報および関連情報を取得する方法を知ることになります。

Objector 24B
私はどんなUNOディスパッチコマンドも実行できる方法を知ってるけど、あなたがUNOディスパッチコマンドの説明で「関連情報」と言ってるものを取得する方法を知らないのよ。実行してもそんな情報返ってきませんよ!

Hypothesizer 7
ああ、マダム、UNOディスパッチコマンドを'com.sun.star.frame.DispatchHelper'を使って実行なさっているように推測いたします。

Objector 24B
もちろん。そうするもんだと聞いたわよ。

Hypothesizer 7
実のところ、それは、簡略化された方法でして、一部の情報しか提供しません。

Objector 24B
...それじゃあ、UNOディスパッチコマンドを実行する方法を変えないといけないの?

Hypothesizer 7
はい、いけません。

Objector 24A
「関連情報」なるものが私に本当に必要なのかね?

Hypothesizer 7
サー、あなたが何を必要とするか私には決められませんが、UNOディスパッチコマンドによって有用な情報が提供される場合、それは大抵、関連情報として提供されます。


本体


1: UNOディスパッチコマンドを関連情報を取得することなく実行する容易な方法


Hypothesizer 7
最初に、UNOディスパッチコマンドを関連情報を取得することなく実行する方法を知っておきましょう。

この方法は既にご存知かもしれませんが、次セクション(UNOディスパッチコマンドを実行し、その実行から入手可能な全情報を取得することについてのもの)のための予備的情報が本セクションにて開示されます。

Objector 24A
...どうやら、私は本セクションをとばすべきではないとあなたはほのめかしているようだな...

Hypothesizer 7
「ほのめかし」?ああ、地球人の術策ですね。...実のところ、あなたが何をなさろうが私は一向に構わないのですが、しかるべき情報を適宜に提供するという責務を果たすことが私には重要なのです。

Objector 24A
どうでもいいが...

Hypothesizer 7
とにかく、いかなるUNOディスパッチコマンドもあるフレームに対して実行されるので、まず、私たちは、そのフレームを取得しなければなりません。もし、UNOディスパッチコマンドをあるドキュメントに対して実行したいのであれば、そのドキュメントを格納しているフレームを取得しなければならないでしょうし、そうでなければ、UNOデスクトップフレームを使用することになるでしょう。

ドキュメントを格納するフレームを取得するためには、まず、ドキュメントUNOオブジェクトへのアクセスを得なければなりません。

カレントではないどのドキュメントのUNOオブジェクトへもアクセスを取得できますが、そうする方法に立ち入ることは本記事ではしません(ある以降の記事でそうするでしょう)。その代わりに、本記事では、カレントドキュメントを使いますが、それは、'ThisComponent'というグローバルビルトイン変数によってアクセスできます。

フレームUNOオブジェクトは、以下のようにして取得します。

@LibreOffice or Apache OpenOffice Basic ソースコード
	Dim l_controller As Object
	l_controller = ThisComponent.getCurrentController ()
	Dim l_frame As Object
	l_frame = l_controller.getFrame ()

Objector 24A
知ってる。

Hypothesizer 7
実のところ、そのフレームは'com.sun.star.frame.XDispatchProvider'インスタンスです。

Objector 24A
はあ?どういう意味だ?フレームはフレームだろう?

Hypothesizer 7
...はい、そうです、そして、それはUNOディスパッチャー群プロバイダーでもあります。

Objector 24A
ばかげてる...。あるものがソックスでありキッチンスポンジでもあるというようなものだ。

Hypothesizer 7
...それよりは、ある人物が大統領でありまぬけでもあるというのに近いでしょう。

Objector 24A
ああ、それはありえる。

Hypothesizer 7
実際、そのフレームは'com.sun.star.frame.XDispatchProvider' UNOインターフェイスを実装しています、インターフェイスはBasicコード中に全然現れませんが。

Objector 24A
...何だかよくわからんが...

Hypothesizer 7
他方で、UNOデスクトップフレームUNOオブジェクトは、'StarDesktop'というグローバルビルトイン変数によってアクセスできます。

Objector 24A
ははあ。

Hypothesizer 7
そして、そのフレームは'com.sun.star.frame.XDispatchProvider'インスタンスです。

Objector 24A
ある大統領がまぬけであるように。

Hypothesizer 7
どちらのフレームへのアクセスを取得したにしろ、次に、UNOディスパッチャーヘルパーUNOオブジェクトを以下のようにして取得します。ここで、'l_unoObjectsContext'はUNOオブジェクト群コンテキスト(大抵、'GetProcessServiceManager ().getPropertyValue ("DefaultContext")'が使われます)です。

@LibreOffice or Apache OpenOffice Basic ソースコード
	Dim l_dispatchHelper As Object
	l_dispatchHelper = l_unoObjectsContext.getServiceManager ().createInstanceWithContext ("com.sun.star.frame.DispatchHelper", l_unoObjectsContext)

Objector 24A
うん?私は'GetProcessServiceManager ().createInstance ("com.sun.star.frame.DispatchHelper")'とやったが。何が違うんだ?

Hypothesizer 7
デフォルトのUNOオブジェクト群コンテキストをお使いになる限り、何の違いもありません。私の上記コードは、非デフォルトのUNOオブジェクト群コンテキストを使用する場合にも妥当です。

Objector 24A
ふーむ...

Hypothesizer 7
最後に、UNOディスパッチコマンドを実行します、コマンドURLおよびコマンド引数群を指定して、以下のように。

@LibreOffice or Apache OpenOffice Basic ソースコード
	Dim l_dispatchArgumentPropertiesArray (0) As New com.sun.star.beans.PropertyValue
	l_dispatchArgumentPropertiesArray (0).Name = "ToPoint"
	l_dispatchArgumentPropertiesArray (0).Value = "$B$2"
	Dim l_commandResult As Object
	l_commandResult = l_dispatchHelper.executeDispatch (l_frame, ".uno:GoToCell", "_self", -1, l_dispatchArgumentPropertiesArray)

Objector 24A
実は、"_self"がそこで何をしてるのか理解したことがない。一体、何が何のselfなんだ?

Hypothesizer 7
実は、ターゲットフレームが、指定したフレーム('l_frame')のselfなのです。

Objector 24A
おお...、それは、ターゲットフレームを指定する必要はないということらしいな。

Hypothesizer 7
その必要はありません。例えば、ある子フレームおよび'_parent'というターゲットフレーム名を指定することができます。

Objector 24A
それは、全フレームが1つの階層を成しているということらしいな。

Hypothesizer 7
実際には、どのフレームも1つのフレーム群階層に属しますが、どの階層もルートフレーム(デスクトップです)配下にあります。

Objector 24A
はあ?それは妙な言説だぞ。私なら、「単一の階層があって、そのトップがデスクトップだ」と言うが。

Hypothesizer 7
しかしながら、指定したフレームの'_top'フレームはデスクトップではなく、デスクトップ直下のフレームなのです。

Objector 24A
はあ?あなた、言葉しゃべれますか?

Hypothesizer 7
えーと、そういう用語を私が定義したのではありません。

Objector 24A
それでは、'_top'フレームの'_parent'フレームがデスクトップなのか?

Hypothesizer 7
はい。

Objector 24A
...他にどんなフレーム名を使えるのか?

Hypothesizer 7
'_blank'を使えます、新たなトップフレームを意味して。

Objector 24A
それでは、上記コードの「-1」は何を意味するのだ?

Hypothesizer 7
「-1」は何も意味していません、指定したターゲット名が'_self'のような特殊フレーム名である場合は、その引数(ターゲットフレーム検索フラグを指定するためのものです)は無視されるので。

Objector 24A
ははあ。

Hypothesizer 7
Calcドキュメントについて言うと、私たちが取得したフレームがトップフレームであり、子はありません。

Objector 24A
なるほど。


2: UNOディスパッチコマンドを実行してその結果情報および関連情報を取得する方法


Hypothesizer 7
関連情報を取得するには、本セクションで論じられる方法を取らなければなりません。

結果情報および関連情報はそれぞれ'com.sun.star.frame.XDispatchResultListener'および'com.sun.star.frame.XStatusListener'に通知されるので、普通は、'com.sun.star.frame.XDispatchResultListener'を実装するクラス1つおよび'com.sun.star.frame.XStatusListener'を実装するクラス1つ以上を作成します。

しかし、不運なことに、LibreOfficeまたはApache OpenOffice Basicは、クラスなるものを作成させてくれません。

しかし、幸運なことに、LibreOfficeまたはApache OpenOffice Basicは、リスナークラスを作成することなくリスナーオブジェクトを作成させてくれます。

不運なことに、そのリスナーオブジェクト作成機能はかなり制限的です(複数のUNOインターフェイスを実装するリスナーオブジェクトを作成できない、リスナーオブジェクトにメンバー変数を追加できない、等)、しかし幸運なことに、だからといって、不可欠な事をできないわけではありません、理想的ではないコードを書かざるをえなくなるかもしれませんが、不運なことに。

例えば、以下は、'com.sun.star.frame.XDispatchResultListener'オブジェクトおよび'com.sun.star.frame.XStatusListener'オブジェクトです。

@LibreOffice or Apache OpenOffice Basic ソースコード
Private Sub UnoDispatchingResultListener_dispatchFinished (a_dispatchResultEvent As com.sun.star.frame.DispatchResultEvent)
	MsgBox ("### The dispatch execution is finished.")
End Sub

Private Sub	UnoDispatchingResultListener_disposing (a_eventSource As com.sun.star.lang.EventObject)
End Sub

Private Sub UnoDispatchingRelatedInformationPieceListener_statusChanged (a_relatedInformationPiece As com.sun.star.frame.FeatureStateEvent)
	MsgBox ("### A dispatch execution related information piece is offered.")
End Sub

Private Sub UnoDispatchingRelatedInformationPieceListener_disposing (a_eventSource As com.sun.star.lang.EventObject)
End Sub
	
	Dim l_unoDispatchingResultListener As Object
	l_unoDispatchingResultListener = CreateUnoListener ("UnoDispatchingResultListener_", "com.sun.star.frame.XDispatchResultListener")
	Dim l_unoDispatchingRelatedInformationPieceListener As Object
	l_unoDispatchingRelatedInformationPieceListener = CreateUnoListener ("UnoDispatchingRelatedInformationPieceListener_", "com.sun.star.frame.XStatusListener")

それらのイベントクラスは、UNO APIドキュメント('com.sun.star.frame.DispatchResultEvent'は、ここ、'com.sun.star.lang.EventObject'は、ここ、'com.sun.star.frame.FeatureStateEvent'は、ここ)で調べてください。

Objector 24A
えーと、名前が、ある接頭子プラス実装されるインターフェイスのメソッド名であるサブルーチン群を作り、その接頭子とインターフェイス名を指定して'CreateUnoListener'ファンクションを呼べということだな。

Hypothesizer 7
そして、もちろん、各メソッドの引数タイプ群は、対応するインターフェイスメソッドのものと一致しなければなりません。

Objector 24A
もちろん。

Hypothesizer 7
フレームUNOオブジェクトは、前セクションで説明されたのと同じ方法で取得します。

次に、'com.sun.star.util.URL'オブジェクト('非UNO'オブジェクト)を以下のようにセットアップします。ここで、'l_unoObjectsContext'はUNOオブジェクト群コンテキスト(大抵、'GetProcessServiceManager ().getPropertyValue ("DefaultContext")'が使われます)です。

@LibreOfficeまたはApache OpenOffice Basic ソースコード
	Dim l_urlInURL As New com.sun.star.util.URL
	l_urlInURL.Complete = ".uno:GoToCell"
	Dim l_urlTransformer As Object
	l_urlTransformer = l_unoObjectsContext.getServiceManager ().createInstanceWithContext ("com.sun.star.util.URLTransformer", l_unoObjectsContext)
	l_urlTransformer.parseStrict (l_urlInURL)

Objector 24A
...UNO APIは少し不親切すぎると気付かざるを得ないな。たった1つのURLをセットアップするためだけに、それだけのコードが必要とは...

Hypothesizer 7
ユーティリティクラス群を作成したくなるでしょうね。

Objector 24A
それが自然な行動だろうな。

Hypothesizer 7
どちらにしろ、次に、ディスパッチャーUNOオブジェクトを以下のように取得します。

@LibreOffice or Apache OpenOffice Basic ソースコード
	Dim l_dispatcher As Object
	l_dispatcher = l_frame.queryDispatch (l_urlInURL, "_self", -1)

Objector 24A
...ディスパッチをクエリーしたのか、それとも「ディスパッチャー」をか?

Hypothesizer 7
いくつかの辞書によれば、名詞としての'dispatch'は送る行為であり、私たちは送る行為をクエリーした(それが、いかなる意味であるにせよ)のではなく、送ることの面倒を見るものをクエリーしたのであって、それは、私の考えでは、ディスパッチャーと呼ばれるべきです。

Objector 24A
そのディスパッチャーを得るのにURLを指定したという事実から判断すると、そのディスパッチャーはそのURLにのみ有効のようだな。

Hypothesizer 7
そのディスパッチャーはそのURLに責任を持つことのみが保証されている、そのディスパッチャーが一部の他のURLにも責任を持っている可能性もあるが、と私なら言うでしょう。

Objector 24A
ああ、それでは、あるディスパッチャーは一部複数のURLの面倒を見るかもしれないが、それがどのURLかを知らない限り、私はそのディスパッチャーを、'queryDispatch'呼び出しで指定したURLにしか使用できないと。

Hypothesizer 7
次に、関連情報リスナー(複数可能)をディスパッチャーに登録し、最後に、私たちのコマンドをディスパッチしてくれるようにディスパッチャーに依頼します、以下のように。

@LibreOfficeまたはApache OpenOffice Basic ソースコード
	l_dispatcher.addStatusListener (l_unoDispatchingRelatedInformationPieceListener, l_urlInURL)
	Dim l_dispatchArgumentPropertiesArray (1) As New com.sun.star.beans.PropertyValue
	l_dispatchArgumentPropertiesArray (0).Name = "SynchronMode"
	l_dispatchArgumentPropertiesArray (0).Value = true
	l_dispatchArgumentPropertiesArray (1).Name = "ToPoint"
	l_dispatchArgumentPropertiesArray (1).Value = "$B$2"
	l_dispatcher.dispatchWithNotification (l_urlInURL, l_dispatchArgumentPropertiesArray, l_unoDispatchingResultListener)
	l_dispatcher.removeStatusListener (l_unoDispatchingRelatedInformationPieceListener, l_urlInURL)

非同期にしたいのであれば、「SynchronMode」プロパティを指定する必要はありません。

Objector 24A
ははあ。

Hypothesizer 7
'statusChanged'メソッドは複数回呼ばれる可能性があり(または、全然呼ばれないかもしれない)、'dispatchFinished'メソッドが最後に1度呼ばれます。


3: 結びとその先


Hypothesizer 7
これで、LibreOfficeまたはApache OpenOffice BasicでUNOディスパッチコマンドを実行してその結果情報および関連情報を取得する方法を知りました。

もちろん、UNOディスパッチコマンドは、他のプログラミング言語(Java、C++、Microsoft .NET Framework (C#およびVisual Basic.NET)、Python、BeanShell、JavaScript)で実行することもできます。JavaC++C#でそうする方法を以前の記事で学びましたし、Pythonでそうする方法を以降の記事で学びます。

LibreOffice基盤のためのUNOディスパッチコマンドの未完の(今のところ)リストとリストされたコマンドの仕様説明および LibreOffice CalcのためのUNOディスパッチコマンドの未完の(今のところ)リストとリストされたコマンドの仕様説明があります。

UNOディスパッチコマンドを実行するのは、LibreOfficeまたはApache OpenOfficeのインスタンスを操作する1つの方法ですが、LibreOfficeまたはApache OpenOfficeのインスタンスの操作で私たちができることの全てをカバーしているわけではありません: UNOオブジェクトを直接操作することでもっと多くのことを行なえます(本シリーズの目次を御参照ください)。


参考資料


<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>