ラベル UNO拡張機能(LibreOffice拡張機能またはApache OpenOffice拡張機能)を開発する の投稿を表示しています。 すべての投稿を表示
ラベル UNO拡張機能(LibreOffice拡張機能またはApache OpenOffice拡張機能)を開発する の投稿を表示しています。 すべての投稿を表示

2018年1月7日日曜日

31: UNO拡張機能(LibreOffice拡張機能またはApache OpenOffice拡張機能)内でSwing GUIを使う方法

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

本文 START

UNO拡張機能(LibreOffice拡張機能またはApache OpenOffice拡張機能)内でSwing GUIを使う方法を知る

話題: UNO (Universal Network Objects)

話題: LibreOffice

話題: Apache OpenOffice

話題: Javaプログラム言語

実のところ、UNO拡張機能では、GUIをただ使うというわけにはいかない

バイアス惑星の山あいの小川のほとりのある部屋で-Hypothesizerと-Rebutterがコンピュータースクリーンの前に座っている。

-Hypothesizer

UNO拡張機能の中でGUIを実装しようと思う。

-Rebutter

うーむ、 . . . それがどうした?JavaでUNO拡張機能を開発できるのだから、JavaFX、Swing、その他何でもただ使えばいいだけではないのか?

-Hypothesizer

実のところ、そういうわけではない。気をつけなければならないことがいくつかある。

-Rebutter

ほう?何だそれらは?

-Hypothesizer

最も重要なことは、Linux上では、UNO拡張機能で、JavaFXを使えないようだということだ。

-Rebutter

どうやら、Windows上では、UNO拡張機能で、JavaFXを使えると言っているようだな。

-Hypothesizer

Windows上でJavaFXの単純なダイアログを表示できることから、そのように私は推測している。我々のメインのマシンはLinuxなので、実際には、私はそれ以上調査していない。Windows上だけで使えるのでは我々の役には立たないから。

-Rebutter

Linux上ではなぜUNO拡張機能でJavaFXを使えないのか?

-Hypothesizer

以下が私の推測だ。JavaFXはGDKを使っている、LibreOfficeがそうであるように。JavaFXはGDKのメインループを作ろうとするのだが、このメインループは、LibreOfficeのGDKのメインループと同一プロセス内で共存できないようだ。

-Rebutter

ああ、JavaFXプログラムはFXプログラムインスタンスと指定して実行されるように想定されているので、LibreOfficeプログラムインスタンスの中で動くJVMでJavaFXを使えないのは自然かもしれない。

それで、Linux上、UNO拡張機能の中でJavaFXを使おうとすると、何がおきるのか?

-Hypothesizer

JavaFXの初期化が、受け取るべき一部のイベントを受け取ることができず、フリーズする。結果的に、LibreOfficeプログラムインスタンス全体がフリーズする。

-Rebutter

ふーむ、 . . . それでは、回避策は何もないのか?

-Hypothesizer

少なくとも、私は知らない。ただ、究極の解決策はある。

-Rebutter

それは何だ?

-Hypothesizer

GUIサーバーをUNOサーバーとして作ることができる。

-Rebutter

ああ、シリーズ、「外部JavaプログラムでUNOを使用する(LibreOfficeまたはApache OpenOfficeのドキュメントを操作する)方法」で話したように、UNOサーバーを作ることができる。UNOサーバーは独立したJavaプログラムなので、JavaFXだろうがJavaの他のどの機能だろうが、制限があるはずがない。

-Hypothesizer

Swingは問題なく使えるので(後で話すとおり、ある落とし穴はあるが)、その解決策を追求するのはまたの機会にしよう。

-Rebutter

いいだろう。

-Hypothesizer

言っておくが、UNO拡張機能の中で使うように推奨されているGUIライブラリがあるが、我々は従わない、なぜなら . . .

-Rebutter

. . . 我々の性格がゆがんでいるからか?

-Hypothesizer

それはここでの理由ではない、そのとおりではあるが、ある程度。理由は、そのライブラリがSwingやJavaFXほど便利だとも機能豊富だとも私は予想していないから。

-Rebutter

それは、何らかの事実に基づいているのか?

-Hypothesizer

当て推量と言うべきだろう。. . . 別の理由は、UNO拡張機能を開発するためだけのために、新たにGUIライブラリを学びたくないことだ。

-Rebutter

それは理解できる。

-Hypothesizer

必要であれば、GUIサーバーという解決策を選ぶだろう、そのGUIライブラリを使うというものではなく。

UNO拡張機能の中でSwingを使う前に、行なわければならない1つのことは何か?

前場と同じ。

-Hypothesizer

Swingは、UNO拡張機能の中で問題なく使えるが、Swingを使いはじめる前に行なわければならないことが1つある。

-Rebutter

それは何だ?

-Hypothesizerは、Javaのソースコードを開き、ある行を指差す。

-Hypothesizer

この行を呼ばなければならない。

@Java Source Code
  Thread.currentThread ().setContextClassLoader (ClassLoader.getSystemClassLoader ());

-Rebutter

うーむ、 . . . クラスローダーをカレントスレッドに登録しているのか?

-Hypothesizer

そうだ。Swingはそれを使うが、それは、LibreOfficeが用意したJVMには登録されていない、なぜだか。

-Rebutter

ふーむ。. . . それでは、それを行ないさえすれば、UNO拡張機能の中でSwingを何の問題なく使えるのか?

-Hypothesizer

私が知る限り、そうだ。

サンプルを作ろう

前場と同じ。

-Hypothesizer

サンプルを作ろう。

各ボタンが各機能を起動するボタン群を持つコントロールパネルはどうだろう?

-Rebutter

コントロールパネルは結構だが、どんな機能だ、例えば?

-Hypothesizer

うーむ、 . . . セルエディターはどうだろう?

-Rebutter

「セルエディター」というのは何だ?

-Hypothesizer

スプレッドシートはデータをグリッド状に整理するのに便利だが、セルに長いテキストを入れると、セルの中でテキストを見たり編集したりするのに難儀する。

-Rebutter

実際、数字や短いテキストだけを扱う限りは良いが、長いテキストも扱わなければならない場合、スプレッドシートは事実上使い物にならなくなる。

-Hypothesizer

もし、我々のセルエディターで長いテキストが扱えれば、そうした場合でもスプレッドシートを便利に使える。

-Rebutter

ふーむ . . .

-Hypothesizer

この記事では、コントロールパネルを作ることに集中しよう。この段階では、セルエディターはダミーだ。

-Rebutter

まあ、我々は既に、スプレッドシートセルから読んだりスプレッドシートセルに書いたりする方法を知っているので、セルエディターを作るのは、UNO拡張機能内でGUIを使う方法を知ってさえいれば、単にJavaプログラミングの問題だ。

-Hypothesizer

そのとおり。

コントロールパネルを表示するのは単にSwingプログラミングの問題だが、ここでは、コントロールパネルを、LibreOfficeのカレントフレームに対して相対的に適切な場所に表示しよう。

-Rebutter

ああ、それでは、我々は、コントロールパネルに、スクリーンのランダムな位置や固定の位置に表示されてほしくないわけだ。

-Hypothesizer

我々は、コントロールパネルを、LibreOfficeのカレントフレームの左境界の隣に表示しよう。

-Rebutter

そこにスペースがなかったらどうするのか?

-Hypothesizer

その場合は、LibreOfficeのカレントフレームの上に表示しなければならないだろう。

-Rebutter

どこに表示したいにしろ、問題は、LibreOfficeのカレントフレームの境界の位置をどのように得られるかということだ。

-Hypothesizer

以下のようにして得ることができる。

-Hypothesizerは、先程ののJavaソースファイルのあるセクションを選択する。

@Java Source Code
import com.sun.star.awt.XWindow;
import com.sun.star.frame.XDesktop;
import com.sun.star.frame.XFrame;
import thebiasplanet.unoutilities.constantsgroups.*;
import thebiasplanet.unoutilities.serviceshandling.UnoServiceHandler;

    XDesktop l_unoDesktopInXDesktop = (XDesktop) UnoServiceHandler.getServiceInstance (i_componentContextInXComponentContext, UnoServiceNamesConstantsGroup.c_com_sun_star_frame_Desktop, XDesktop.class);
    XFrame l_unoFrameInXFrame = l_unoDesktopInXDesktop.getCurrentFrame ();
    XWindow l_desktopContainerWindowInXWindow = l_unoFrameInXFrame.getContainerWindow ();
    com.sun.star.awt.Rectangle l_desktopContainerWindowBoundary = l_desktopContainerWindowInXWindow.getPosSize ();
    Rectangle l_applicationContainerWindowBoundary = new Rectangle (l_desktopContainerWindowBoundary.X, l_desktopContainerWindowBoundary.Y, l_desktopContainerWindowBoundary.Width, l_desktopContainerWindowBoundary.Height);

-Rebutter

ふむ、'thebiasplanet'パッケージ配下のクラス群は、我々のユーティリティクラスだ。

-Hypothesizer

過去の記事で既に説明したコードについては、我々は、また明示的に示すことはせず、我々のユーティリティクラスを使うかもしれない。ユーティリティクラスは我々の各種zipファイルに含まれているので、必要であれば、それらの中を見ればよい。

-Rebutter

いいだろう。

-Hypothesizer

我々のサンプルプログラムは、ここにある。.

-Rebutter

以前に引用したサンプルUNO拡張機能プロジェクトに実装したのか。

-Hypothesizer

そうだ。zipファイルの使い方は、そこに書いてある。我々はいくつかの記事で引用されているプロジェクトにコードを追加するので、ある記事で引用されているプロジェクトがその記事とは関係ないコードを含んでいることがあり得る。そうしたコードは、他の記事から来ている。

-Hypothesizerはgradleコマンドを実行し、 コマンドは正常終了する。-Hypothesizerは、'TestSpreadSheetsDocumentForExecutingTests.ods'スプレッドシートドキュメントを開く。

-Rebutter

シートに第2のボタンを追加したのか。

-Hypothesizer

そうだ。ボタンを押す前に、LibreOffice Basicライブラリをインポートしなければならない、過去の記事に記載されているように。

-Hypothesizerは、'Show Test Control Panel'ボタンをクリックし、小さなダイアログボックスが、LibreOfficeのカレントフレームの左境界の隣に表示される。

-Rebutter

. . . 「コントロールパネル」と呼ぶには印象の薄いしろものだな . . .

-Hypothesizer

印象が薄かろうがなかろうが、コントロールパネルだ。'Edit Cell'ボタンをクリックすると、セルエディターが表示される。

-Hypothesizerは'Edit Cell'ボタンをクリックし、ダミーウィンドウが開く。

-Rebutter

現時点では、このウィンドウはダミーであって、セルデータを表示はしない。

本文 END

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

2017年8月26日土曜日

30: ディスパッチメカニズムにUNOコマンドを送る

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

本文 START

他の方法ではLibreOfficeまたはApache OpenOfficeの外からアクセスできない一部の機能を呼び出す方法を知る

LibreOfficeまたはApache OpenOfficeの外からすべての機能が呼び出せるわけではない

-Hypothesizer

これまで、UNO拡張機能からいくつかの機能を呼んできたが、すべての機能がUNO拡張機能やスタンドアロンのUNOプログラムから呼べるわけではない。

-Rebutter

知っている。あるUNOオブジェクトに属する機能を呼ぶためには、そのUNOオブジェクトへの参照(厳密に言えば、そのUNOオブジェクトのUNOプロキシへの参照)を得なければならないが、その参照を得られるという保証はない。

-Hypothesizer

我々は、以下のプロセスで、UNOオブジェクトへの参照を得ることができる。

コンポーネントコンテキストを得る。コンポーネントコンテキストに格納されたUNOオブジェクト(グローバルUNOサービスマネージャーはその一つ)を得る。グローバルUNOサービスマネージャーからUNOオブジェクトを得る。既にリファレンスを得ているUNOオブジェクトのメソッドの戻り値や出力引数としてUNOオブジェクトを得る。既にリファレンスを得ているUNOオブジェクトのプロパティとしてUNOオブジェクトを得る。

-Rebutter

UNOオブジェクトは、戻りstruct値のメンバーや出力struct引数のメンバーなどとしても得られるが、それは言うまでもないだろう。

-Hypothesizer

このプロセスで露出されないUNOオブジェクトは、LibreOfficeやApache OpenOfficeの外からはアクセスできない。

-Rebutter

勿論。それに、機能は、UNOコンポーネントのメソッドとして実装されてすらいないかもしれない。

-Hypothesizer

そう。LibreOfficeはほとんどがC++で実装されており、すべてのC++クラスがUNOコンポーネントだというわけではない。

-Rebutter

したがって、呼びたいが呼べないという機能が一部あり得る。

「ディスパッチ」というメカニズムがある

-Hypothesizer

しかし、一部の機能を呼べる別のメカニズムがあって、これが、ディスパッチメカニズムだ。

-Rebutter

それはどんなものなのか?

-Hypothesizer

あらかじめ定められたコマンド群があって、これらはそれぞれのURLによって識別され、それらのうちの1つを、そのURLとそのコマンドに特有のいくつかの引数を指定することで呼ぶことができる。

-Rebutter

それらのコマンドは、すべて呼ぶことができるのか?

-Hypothesizer

その保証はない。コマンドを呼ぶための引数として必要なUNOオブジェクトへのリファレンスを得られないかもしれないし、コマンドが正常に呼ばれるために満たされなければならない何らかの特別な条件があるかもしれない。

-Rebutter

特別な条件?

-Hypothesizer

例えば、コマンドを呼ぶ時に、あるダイアログウィンドウが開いていなければならないかもしれない。

-Rebutter

ふーむ . . .

-Hypothesizer

それはただ私が思いついた例というにすぎない。実際にはそんなケースはないかもしれない。

-Rebutter

ははあ . . .

そうしたURLやその引数はどうすれば知ることができるのか?

-Hypothesizer

それが問題だ。. . . それを包括的に説明する文書は私には見つけられなかった。

-Rebutter

ふーむ。

-Hypothesizer

今のところ、私の最良の方法は、LibreOfficeのソースコードを見ることだ。どこをどう見るべきなのかというのが次の問題だが、今はそれには立ち入らないことにする。

-Rebutter

オーケー。

-Hypothesizer

マクロを記録することで、コマンドを呼ぶ一部の例を見ることができるが、それらは、常に完全だとは言えない。

-Rebutter

どのように不完全であり得るのか。

-Hypothesizer

例えば、ドキュメントをPDFファイルとしてエクスポートする時、PDFファイルに署名することができるが、記録されたマクロはPDFファイルに署名しない。

-Rebutter

それでは、一部の引数はただ省かれるのか?

-Hypothesizer

または、一部の引数には値がセットされない。

-Rebutter

なるほど。それで、実際には、どうすればコマンドを呼べるのか?

-Hypothesizer

'com.sun.star.frame.DispatchHelper'というグローバルUNOサービスがあり、このUNOサービスのインスタンスをグローバルUNOサービスマネージャーから生成することができる。このインスタンスのUNOコンポーネントはUNOインターフェース、'com.sun.star.frame.XDispatchHelper'を実装しており、このUNOインターフェースには'executeDispatch'というメソッドがあり、このメソッドは、ディスパッチプロバイダ、コマンドURL、コマンド引数を受け取る。

-Rebutter

ディスパッチプロバイダというのは何だ?

-Hypothesizer

コマンドは神秘として実行されるわけではなく、ある実体が受け取って対処するが、私の理解では、この実体がディスパッチプロバイダだ。

-Rebutter

ディスパッチプロバイダはどのように得られるのか?

-Hypothesizer

それはもちろんコマンドによって違うが、今我々が関心を持つほとんどのケースでは、ドキュメントを格納しているフレームがディスパッチプロバイダだ。

-Rebutter

そのフレームはどのように得られるのか?

-Hypothesizer

フレームは、ドキュメントのコントローラーから、コントローラーが実装する'com.sun.star.frame.XController'UNOインターフェースを使って得られる。

-Rebutter

なるほど。

-Hypothesizer

結局、以下のサンプルコードを書いた。ここで、 'componentContext'は'com.sun.star.uno.XComponentContext'のコンポーネントコンテキスト(それをどのように得たかを知るには、この以前の記事を参照)、'l_currentSpreadSheetsDocumentModel'は'com.sun.star.frame.XModel'のスプレッドシートドキュメントUNOオブジェクト(それをどのように得たかを知るには、この以前の記事を参照)。

@ Source Code
import com.sun.star.frame.XFrame;
import com.sun.star.frame.XController;
import com.sun.star.frame.XDispatchHelper;
import com.sun.star.frame.XDispatchProvider;
import com.sun.star.beans.PropertyValue;

  XDispatchHelper l_dispatchHelperInXDispatchHelper = (XDispatchHelper) UnoRuntime.queryInterface (XDispatchHelper .class, componentContext.getServiceManager ().createInstanceWithContext ("com.sun.star.frame.DispatchHelper", componentContext));
  XController l_controllerInXController = (XController) UnoRuntime.queryInterface (XController.class, l_currentSpreadSheetsDocumentModel.getCurrentController ());
  l_frameInXDispatchProvider = (XDispatchProvider) UnoRuntime.queryInterface (XDispatchProvider.class, l_controllerInXController.getFrame ());
  PropertyValue [] l_commandProperties = new PropertyValue [1];
  l_commandProperties [0] = new PropertyValue ();
  l_commandProperties [0].Name = "ToPoint";
  l_commandProperties [0].Value = "$B$2";
  l_dispatchHelperInXDispatchHelper.executeDispatch (l_frameInXDispatchProvider, ".uno:GoToCell", "", 0, l_commandProperties);
-Rebutter

このコマンドは何だ?

-Hypothesizer

これは、セルのカレント位置をB2セルに移動するコマンドだ。

-Rebutter

それは、セルを選択するのとは違うのか?

-Hypothesizer

違う、少なくとも、見た目の上で。セルが選択されたとき、セルには色がつくが、セルがただカレントのときはセルには色がつかない。

-Rebutter

うーむ、それは微妙な違いだ。

-Hypothesizer

それに、スプレッドシートドキュメントをPDFファイルとしてエクスポートするとき、選択されたセルは選択箇所として認識されるが、ただのカレントセルはそうではない。

-Rebutter

「選択箇所として認識される」というのはどういう意味なのか?

-Hypothesizer

スプレッドシートドキュメントをPDFファイルとしてエクスポートするとき、ドキュメント内の選択された箇所のみをエクスポートすることができる。

-Rebutter

なるほど。

本文 END

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

2017年8月12日土曜日

29: スプレッドシートの行領域、列領域、セル群四角領域を挿入したり削除したりする

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

Main body START

LibreOfficeまたはApache OpenOfficeのCalcスプレッドシートを拡張機能を通してJavaまたはマクロプログラムから操作する(読むまたは書く)方法を知る

スプレッドシートの行範囲または列範囲をどのように挿入できるか?

-Hypothesizer

別の頻繁に遭遇するユースケースとして、スプレッドシートの行および列の範囲を挿入および削除することがあるだろう。

-Rebutter

そうだろうね。同じことを、スプレッドシートのセルデータを移動および削除することでも達成できるが、多くのセルにデータがある場合、それは面倒すぎるし、遅すぎるだろう。

-Hypothesizer

そうだろう。

スプレッドシートUNOオブジェクトのUNOコンポーネントは、UNOインターフェース、'com.sun.star.sheet.XCellRangeMovement'を実装しており、これによって、スプレッドシートの行範囲や列範囲を挿入および削除できる。

-Rebutter

なるほど。

-Hypothesizer

行範囲および列範囲は、このUNOインターフェースの'insertCells'メソッドを呼ぶことで挿入できる。

-Rebutter

ふむ?'insertCells'?行範囲や列範囲よりももっと一般的な形のセルグループを挿入できるかのように聞こえる名前だ。

-Hypothesizer

事実、四角なセル群領域を挿入することができる。

-Rebutter

ふーむ、すると、四角領域がシートに挿入されて、それで、シートの残りの部分はどうなる?

-Hypothesizer

既存の指定された領域とその右側を右に移動させるか、既存の指定された領域とその下側を下に移動させることができる。

-Rebutter

それでは、そのどちらかを指定できるのか?

-Hypothesizer

そう。それは我々の関心事ではなかったが、それもあとで試してみよう。

-Rebutter

オーケー。

-Hypothesizer

このメソッドは2つの引数を取る。挿入するべき領域と挿入のモードだ。 第1の引数はstruct(Javaではクラスにマッピングされる)だ。行領域を挿入する時は、シートのインデックス、挿入する領域の開始行インデックスおよび終了行インデックスを指定する。第2の引数はenum(Javaではクラスにマッピングされる)だ。行領域を挿入する時は、'com.sun.star.sheet.CellInsertMode.ROWS'を指定する。

-Rebutter

ははあ。

-Hypothesizer

列領域を挿入する時は、シートのインデックス、挿入する領域の開始列インデックスおよび終了列インデックス、'com.sun.star.sheet.CellInsertMode.COLUMNS'を指定する。

-Rebutter

このstructはそれら5つのメンバーを持っているわけだ。例えば、行領域を挿入する時、他の意味のないメンバーには特定の値をセットしなければならないのか?

-Hypothesizer

いや、そうではない。意味のないメンバーはただ無視される。

-Rebutter

なるほど。

スプレッドシートの行範囲または列範囲をどのように削除できるか?

-Hypothesizer

行範囲および列範囲は、先程のUNOインターフェースの'removeRange'メソッドを呼ぶことで削除できる。

-Rebutter

ああ、これも四角なセル群領域を操作できるわけだ。

-Hypothesizer

そうだ。指定された領域の右側を左に移動させるか、指定された領域の下側を上に移動させることができる。

-Rebutter

なるほど。

-Hypothesizer

このメソッドは2つの引数を取る。削除するべき領域と削除のモードだ。 第1の引数は先程と同じstructだ。行領域を削除する時は、シートのインデックス、削除する領域の開始行インデックスおよび終了行インデックスを指定する。第2の引数は別のenumだ。行領域を削除する時は、'com.sun.star.sheet.CellDeleteMode.ROWS'を指定する。

-Rebutter

ははあ。

-Hypothesizer

列領域を削除する時は、シートのインデックス、削除する領域の開始列インデックスおよび終了列インデックス、'com.sun.star.sheet.CellDeleteMode.COLUMNS'を指定する。

-Rebutter

なるほど。

スプレッドシートのセル群四角領域をどのように挿入または削除できるか?

-Hypothesizer

セル群四角領域を挿入するには、第1引数に、シートのインデックス、挿入する領域の開始行インデックス、終了行インデックス、開始列インデックス、終了列インデックスを指定する。第2引数には、既存の指定された領域とその右側を右に移動させるには、'com.sun.star.sheet.CellInsertMode.RIGHT'を指定する。既存の指定された領域とその下側を下に移動させるには、'com.sun.star.sheet.CellInsertMode.DOWN'を指定する。

-Rebutter

ははあ。

-Hypothesizer

セル群四角領域を削除するには、第1引数に、シートのインデックス、削除する領域の開始行インデックス、終了行インデックス、開始列インデックス、終了列インデックスを指定する。第2引数には、指定された領域の右側を左に移動させるには、'com.sun.star.sheet.CellDeleteMode.LEFT'を指定する。指定された領域の下側を上に移動させるには、'com.sun.star.sheet.CellDeleteMode.UP'を指定する。

-Rebutter

なるほど。

-Hypothesizer

結局、前記事のコードの後に以下のコードを書いた。

   XCellRangeMovement l_currentSpreadSheetInXCellRangeMovement = (XCellRangeMovement) UnoRuntime.queryInterface (XCellRangeMovement .class, l_currentSpreadSheet );
   CellRangeAddress l_cellRangeAddress = new CellRangeAddress ();
   l_cellRangeAddress.Sheet = (short) 2;
   l_cellRangeAddress.StartRow = 17;
   l_cellRangeAddress.EndRow = 18;
   l_currentSpreadSheetInXCellRangeMovement. insertCells (l_cellRangeAddress, CellInsertMode.ROWS);
   l_cellRangeAddress.StartColumn = 3;
   l_cellRangeAddress.EndColumn = 3;
   l_currentSpreadSheetInXCellRangeMovement. insertCells (l_cellRangeAddress, CellInsertMode.COLUMNS);
   l_cellRangeAddress.StartRow = 24;
   l_cellRangeAddress.EndRow = 25;
   l_currentSpreadSheetInXCellRangeMovement. removeRange (l_cellRangeAddress, CellDeleteMode.ROWS);
   l_cellRangeAddress.StartColumn = 8;
   l_cellRangeAddress.EndColumn = 9;
   l_currentSpreadSheetInXCellRangeMovement. removeRange (l_cellRangeAddress, CellDeleteMode.COLUMNS);
   l_cellRangeAddress.StartRow = 36;
   l_cellRangeAddress.EndRow = 37;
   l_cellRangeAddress.StartColumn = 2;
   l_cellRangeAddress.EndColumn = 3;
   l_currentSpreadSheetInXCellRangeMovement. insertCells (l_cellRangeAddress, CellInsertMode.RIGHT);
   l_cellRangeAddress.StartRow = 41;
   l_cellRangeAddress.EndRow = 42;
   l_cellRangeAddress.StartColumn = 2;
   l_cellRangeAddress.EndColumn = 3;
   l_currentSpreadSheetInXCellRangeMovement. insertCells (l_cellRangeAddress, CellInsertMode.DOWN);
   l_cellRangeAddress.StartRow = 36;
   l_cellRangeAddress.EndRow = 37;
   l_cellRangeAddress.StartColumn = 2;
   l_cellRangeAddress.EndColumn = 3;
   l_currentSpreadSheetInXCellRangeMovement. removeRange (l_cellRangeAddress, CellDeleteMode.LEFT);
   l_cellRangeAddress.StartRow = 41;
   l_cellRangeAddress.EndRow = 42;
   l_cellRangeAddress.StartColumn = 2;
   l_cellRangeAddress.EndColumn = 3;
   l_currentSpreadSheetInXCellRangeMovement. removeRange (l_cellRangeAddress, CellDeleteMode.UP);

以下のインポート命令も追加した。

import com.sun.star.sheet.XCellRangeMovement;
import com.sun.star.table.CellRangeAddress;
import com.sun.star.sheet.CellInsertMode;
import com.sun.star.sheet.CellDeleteMode;
-Rebutter

なるほど。

Main body END

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

2017年7月29日土曜日

28: スプレッドシートセル文字列フォーマット(フォーマットプロパティ)を得たりセットしたりする

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

Main body START

LibreOfficeまたはApache OpenOfficeのCalcスプレッドシートを拡張機能を通してJavaまたはマクロプログラムから操作する(読むまたは書く)方法を知る

スプレッドシートセル文字列フォーマットをどのように得たりセットしたりできるか?

-Hypothesizer

スプレッドシートセルフォーマットプロパティをいくつかセットしたのと同じように、スプレッドシートセル内の部分文字列にもいくつかのフォーマットプロパティをセットすることができる。

-Rebutter

なるほど。

-Hypothesizer

ここでも、すべてのフォーマットプロパティを列挙することには私は興味がなく、我々にとって役立つと思われるいくつかのフォーマットプロパティのみについて話す。

-Rebutter

オーケー。

-Hypothesizer

我々は以下のプロパティのみを扱う。

  • フォント色
  • フォント名
  • フォントサイズ
  • フォントの姿勢
  • フォントの太さ
  • テキストアンダーライン(下線)のスタイル
  • テキストアンダーライン(下線)の色が自動かどうか
  • テキストアンダーライン(下線)の色
  • テキストオーバーライン(上線)のスタイル
  • テキストオーバーライン(上線)の色が自動かどうか
  • テキストオーバーライン(上線)の色
  • テキスト取り消し線のスタイル
-Rebutter

以上のものは、スプレッドシートセルフォーマットプロパティ群の部分集合だな。当然ながら、部分文字列にはボーダーラインといったプロパティがない。

-Hypothesizer

そう。名称とセットする値はスプレッドシートセルフォーマットプロパティのものと同じだからここには挙げない。

-Rebutter

いいだろう。

-Hypothesizer

スプレッドシートセル文字列フォーマットプロパティは、セルUNOオブジェクトから得た'com.sun.star.text.XTextCursor'インスタンスを使って操作できる。

-Rebutter

なるほど。

-Hypothesizer

このカーソルUNOオブジェクトのUNOコンポーネントは'com.sun.star.beans.XPropertySet'UNOインターフェースを実装しており、このUNOインターフェース用のUNOプロキシを得て、スプレッドシートセルフォーマットプロパティについて行なったのと同じことをすればよい。

しかしながら、実は、なぜだか分からないが、 テキストアンダーライン色はうまくセットできなかった。

-Rebutter

どのようにできなかったのか?

-Hypothesizer

不思議に。

-Rebutter

テキストアンダーライン色をセットしようとすると何が起きるのかを聞いている。

-Hypothesizer

どんな色をセットしようとも、アンダーラインは白になる。

-Rebutter

オーバーライン色はうまくセットできるのにか?

-Hypothesizer

そう。アンダーラインだけが白になる。

-Rebutter

それは不思議だ。

-Hypothesizer

白だと普通見えないので、当面は、テキストアンダーラインの色は自動にすることにする。アンダーラインに色を付ける必要性は我々には全然ないので、問題はないだろう。

-Rebutter

オーケー。

-Hypothesizer

結局、前記事のコードの後に以下のコードを書いた。

   l_textCursor.gotoStart (false);
   l_textCursor.goRight ( (short) 1,false);
   l_textCursor.goRight ( (short) 2,true);
   XPropertySet l_textCursorInXPropertySet = (XPropertySet) UnoRuntime.queryInterface (XPropertySet.class, l_textCursor);
   l_textCursorInXPropertySet.setPropertyValue ("CharColor", new Integer ( (new Color (0, 255, 0)).getRGB ()));
   l_textCursorInXPropertySet.setPropertyValue ("CharFontName", "Liberation Mono");
   l_textCursorInXPropertySet.setPropertyValue ("CharHeight", new Float (16.0F));
   l_textCursorInXPropertySet.setPropertyValue ("CharPosture", FontSlant.ITALIC);
   l_textCursorInXPropertySet.setPropertyValue ("CharWeight", new Float (FontWeight.BOLD));
   l_textCursorInXPropertySet.setPropertyValue ("CharUnderline", new Short (FontUnderline.DOTTED));
   l_textCursorInXPropertySet.setPropertyValue ("CharUnderlineHasColor", new Boolean (false));
   //l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CharUnderlineColor", new Integer ( (new Color (0, 0, 255)).getRGB ()));
   l_textCursorInXPropertySet.setPropertyValue ("CharOverline", new Short (FontUnderline.BOLDDOTTED));
   l_textCursorInXPropertySet.setPropertyValue ("CharOverlineHasColor", new Boolean (true));
   l_textCursorInXPropertySet.setPropertyValue ("CharOverlineColor", new Integer ( (new Color (255, 0, 0)).getRGB ()));
   l_textCursorInXPropertySet.setPropertyValue ("CharStrikeout", new Short (FontStrikeout.DOUBLE));
-Rebutter

いいだろう。

Main body END

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

27: スプレッドシートセルフォーマット(フォーマットプロパティ)を得たりセットしたりする

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

Main body START

LibreOfficeまたはApache OpenOfficeのCalcスプレッドシートを拡張機能を通してJavaまたはマクロプログラムから操作する(読むまたは書く)方法を知る

スプレッドシートセルフォーマットをどのように得たりセットしたりできるか?

-Hypothesizer

我々はスプレッドシートをデータを管理する目的で使うので、ファンシーなビジュアルを作ることには特に興味がない。しかし、一部のデータを強調するために、ある種のスプレッドシートセルフォーマットプロパティをセットするのは役に立つかもしれない。

-Rebutter

「スプレッドシートセルフォーマット」および「スプレッドシートセルフォーマットプロパティ」という用語を君がどのように使用しているのか説明してほしい。

-Hypothesizer

私は、スプレッドシートセルフォーマットの1つの属性を「スプレッドシートセルフォーマットプロパティ」と呼び、スプレッドシートセルフォーマットの全属性の総体を「スプレッドシートセルフォーマット」と呼んでいる。例えば、スプレッドシートセルの背景色はスプレッドシートセルフォーマットプロパティであり、背景色、前景色、フォント名、などの総体がスプレッドシートセルフォーマットだ。

-Rebutter

ははあ。

-Hypothesizer

実際には、多くのスプレッドシートフォーマットプロパティがあり、それらの全てを挙げることには私は興味がない。我々は以下のプロパティのみを扱う。

  • 背景色
  • 背景色が透明かどうか
  • フォント色
  • フォント名
  • フォントサイズ
  • フォントの姿勢
  • フォントの太さ
  • テキストアンダーライン(下線)のスタイル
  • テキストアンダーライン(下線)の色が自動かどうか
  • テキストアンダーライン(下線)の色
  • テキストオーバーライン(上線)のスタイル
  • テキストオーバーライン(上線)の色が自動かどうか
  • テキストオーバーライン(上線)の色
  • テキスト取り消し線のスタイル
  • テキストをラップするかどうか
  • テキストの水平方向位置合わせ(横配置)
  • テキストの垂直方向位置合わせ(縦配置)
  • 左ボーダーライン(枠線)
  • 右ボーダーライン(枠線)
  • 上ボーダーライン(枠線)
  • 下ボーダーライン(枠線)
-Rebutter

一部のプロパティ、例えばフォント名は、セル毎でなく文字ごとにセットするものではないのか?

-Hypothesizer

セル毎にも文字毎にもセットできる。今は、セル毎の設定について話している。文字毎の設定については次の記事で話そう。

-Rebutter

左ボーダーラインといったプロパティは漠然としすぎているのではないか?ボーダーラインスタイル、ボーダーライン色、などがあるはずだ。

-Hypothesizer

ああ、上に挙げたプロパティは、スプレッドシートセルUNOオブジェクトのプロパティに応じている。実のところ、スプレッドシートセルプロパティは、スプレッドシートセルUNOオブジェクトのプロパティだ。そうしたボーダーライン関連プロパティについては、それぞれ、ボーダーラインスタイル、ボーダーライン色、などを保持するstruct(Javaではクラスにマッピングされる)がセットされる。

-Rebutter

それらのボーダーライン関連プロパティがstructにまとめられ、テキストアンダーライン関連プロパティがまとめられないのはなぜなのだろうか。

-Hypothesizer

正直言って、私にも分からない。プロパティの粒度が一様でないように私には思われる。

-Rebutter

「背景色が透明かどうか」の意味合いが私には理解できない。透明な背景色というのはどう役に立つのか?

-Hypothesizer

正直なところ、私は知らない。我々が使う限りでは、背景色が必要なときは「透明でない」、不要なときは「透明である」にセットする。

-Rebutter

「テキストアンダーライン(下線)の色が自動かどうか」というのはどういう意味なのか?

-Hypothesizer

自動の場合、フォントの色と同じになる。

-Rebutter

テキスト取り消し線の色はなぜ指定できないのか?

-Hypothesizer

正直なところ、私は知らない。ともかく、その色は必ず自動になる。

-Rebutter

いいだろう。

-Hypothesizer

スプレッドシートセルプロパティは、セルUNOオブジェクトのUNOコンポーネントが実装している'com.sun.star.beans.XPropertySet'UNOインターフェースを使って操作できる。

-Rebutter

なるほど。

-Hypothesizer

以下が、セットするプロパティの名称と値だ。

  • 背景色 −> CellBackColor: integerのピクセル値
  • 背景色が透明かどうか −> IsCellBackgroundTransparent: booleanのtrue(透明である)またはfalse(透明でない)
  • フォント色 −> CharColor: integerのピクセル値
  • フォント名 −> CharFontName: フォント名string
  • フォントサイズ −> CharHeight: floatのフォントポイントサイズ
  • フォントの姿勢 −> CharPosture: enumのcom.sun.star.awt.FontSlant.(NONE、OBLIQUE、ITALIC、DONTKNOW、REVERSE_OBLIQUE、REVERSE_ITALIC)
  • フォントの太さ −> CharWeight: floatのcom.sun.star.awt.FontWeight.(DONTKNOW、THIN、ULTRALIGHT、LIGHT、SEMILIGHT、NORMAL、SEMIBOLD、BOLD、ULTRABOLD、BLACK)
  • テキストアンダーライン(下線)のスタイル −> CharUnderline: shortのcom.sun.star.awt.FontUnderline.(NONE、SINGLE、DOUBLE、DOTTED、DONTKNOW、DASH、LONGDASH、DASHDOT、DASHDOTDOT、SMALLWAVE、WAVE、DOUBLEWAVE、BOLD、BOLDDOTTED、BOLDDASH、BOLDLONGDASH、BOLDDASHDOT、BOLDDASHDOTDOT、BOLDWAVE)
  • テキストアンダーライン(下線)の色が自動かどうか −> CharUnderlineHasColor: booleanのtrue(自動である)またはfalse(自動でない)
  • テキストアンダーライン(下線)の色 −> CharUnderlineColor: integerのピクセル値
  • テキストオーバーライン(上線)のスタイル −> CharOverline: shortのcom.sun.star.awt.FontUnderline.(NONE、SINGLE、DOUBLE、DOTTED、DONTKNOW、DASH、LONGDASH、DASHDOT、DASHDOTDOT、SMALLWAVE、WAVE、DOUBLEWAVE、BOLD、BOLDDOTTED、BOLDDASH、BOLDLONGDASH、BOLDDASHDOT、BOLDDASHDOTDOT、BOLDWAVE)
  • テキストオーバーライン(上線)の色が自動かどうか −> CharOverlineHasColor: booleanのtrue(自動である)またはfalse(自動でない)
  • テキストオーバーライン(上線)の色 −> CharOverlineColor: integerのピクセル値
  • テキスト取り消し線のスタイル −> CharStrikeout: shortのcom.sun.star.awt.FontStrikeout.(NONE、SINGLE、DOUBLE、DONTKNOW、BOLD、SLASH、X)
  • テキストをラップするかどうか −> IsTextWrapped: booleanのtrue(ラップする)またはfalse(ラップしない)
  • テキストの水平方向位置合わせ(横配置) −> HoriJustify: enumのcom.sun.star.table.CellHoriJustify.(STANDARD、LEFT、CENTER、RIGHT、BLOCK、REPEAT)
  • テキストの垂直方向位置合わせ(縦配置) −> VertJustify: enumのcom.sun.star.table.CellVertJustify.(STANDARD、TOP、CENTER、BOTTOM)
  • 左ボーダーライン −> LeftBorder: com.sun.star.table.BorderLine2のインスタンス
  • 右ボーダーライン −> RightBorder: com.sun.star.table.BorderLine2のインスタンス
  • 上ボーダーライン −> TopBorder: com.sun.star.table.BorderLine2のインスタンス
  • 下ボーダーライン −> BottomBorder: com.sun.star.table.BorderLine2のインスタンス

'com.sun.star.table.BorderLine2'structは以下のメンバーを持ち、各メンバーは以下の値を持つ。

  • LineStyle: shortのcom.sun.star.table.BorderLineStyle.(NONE、SOLID、DOTTED、DASHED、DOUBLE、THINTHICK_SMALLGAP、THINTHICK_MEDIUMGAP、THINTHICK_LARGEGAP、THICKTHIN_SMALLGAP、THICKTHIN_MEDIUMGAP、THICKTHIN_LARGEGAP、EMBOSSED、ENGRAVED、OUTSET、INSET、FINE_DASHED、DOUBLE_THIN、DASH_DOT、DASH_DOT_DOT、BORDER_LINE_STYLE_MAX)
  • LineWidth: integerの線幅(1/100 mm)
  • Color: integerのピクセル値
-Rebutter

integerのピクセル値はどうすれば得られるのか?

-Hypothesizer

'java.awt.Color'の'getRGB'メソッドの戻り値として得ることができる。

-Rebutter

いいだろう。

-Hypothesizer

結局、前記事のコードの後に以下のコードを書いた。

   XPropertySet l_currentSpreadSheetCellInXPropertySet = (XPropertySet) UnoRuntime.queryInterface (XPropertySet.class, l_currentSpreadSheetCell);
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CellBackColor", new Integer ( (new Color (255, 255, 0)).getRGB ()));
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("IsCellBackgroundTransparent", new Boolean (false));
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CharColor", new Integer ( (new Color (0, 255, 0)).getRGB ()));
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CharFontName", "Liberation Mono");
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CharHeight", new Float (16.0F));
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CharPosture", FontSlant.ITALIC);
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CharWeight", new Float (FontWeight.BOLD));
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CharUnderline", new Short (FontUnderline.DOTTED));
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CharUnderlineHasColor", new Boolean (true));
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CharUnderlineColor", new Integer ( (new Color (255, 0, 0)).getRGB ()));
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CharOverline", new Short (FontUnderline.BOLDDOTTED));
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CharOverlineHasColor", new Boolean (true));
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CharOverlineColor", new Integer ( (new Color (255, 0, 0)).getRGB ()));
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("CharStrikeout", new Short (FontStrikeout.DOUBLE));
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("IsTextWrapped", new Boolean (true));
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("HoriJustify", CellHoriJustify.RIGHT);
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("VertJustify", CellVertJustify.BOTTOM);
   BorderLine2 l_leftBorderline = new BorderLine2 ();
   l_leftBorderline.LineStyle = BorderLineStyle.DOTTED;
   l_leftBorderline.LineWidth = 34;
   l_leftBorderline.Color = (new Color (255, 0, 0)).getRGB ();
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("LeftBorder2", l_leftBorderline);
   BorderLine2 l_rightBorderline = new BorderLine2 ();
   l_rightBorderline.LineStyle = BorderLineStyle.DASHED;
   l_rightBorderline.LineWidth = 26;
   l_rightBorderline.Color = (new Color (0, 255, 0)).getRGB ();
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("RightBorder2", l_rightBorderline);
   BorderLine2 l_topBorderline = new BorderLine2 ();
   l_topBorderline.LineStyle = BorderLineStyle.FINE_DASHED;
   l_topBorderline.LineWidth = 18;
   l_topBorderline.Color = (new Color (0, 0, 255)).getRGB ();
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("TopBorder2", l_topBorderline);
   BorderLine2 l_bottomBorderline = new BorderLine2 ();
   l_bottomBorderline.LineStyle = BorderLineStyle.DASH_DOT;
   l_bottomBorderline.LineWidth = 52;
   l_bottomBorderline.Color = (new Color (255, 0, 255)).getRGB ();
   l_currentSpreadSheetCellInXPropertySet.setPropertyValue ("BottomBorder2", l_bottomBorderline);

また、以下のimport命令を追加した。

import java.awt.Color;
import com.sun.star.table.CellHoriJustify;
import com.sun.star.table.CellVertJustify;
import com.sun.star.table.BorderLine2;
import com.sun.star.table.BorderLineStyle;
import com.sun.star.awt.FontSlant;
import com.sun.star.awt.FontWeight;
import com.sun.star.awt.FontUnderline;
import com.sun.star.awt.FontStrikeout;
-Rebutter

プロパティをセットはしたが、得てはいない。プロパティを得たい場合は、'getPropertyValue'メソッドを呼べばよいだけか?

-Hypothesizer

そうだ。

Main body END

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

2017年7月22日土曜日

26: スプレッドシートセルから読んだりスプレッドシートセルに書いたりする、パート4

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

Main body START

LibreOfficeまたはApache OpenOfficeのCalcスプレッドシートを拡張機能を通してJavaまたはマクロプログラムから操作する(読むまたは書く)方法を知る

スプレッドシートセルの文字列をどのように操作できるか?

-Hypothesizer

前は、我々は、スプレッドシートセルの文字列を、既存の文字列を消去し、新たな文字列をセットすることでセットした。

-Rebutter

確かにそうした。

-Hypothesizer

既存の文字列の任意の位置に文字列を挿入したり、既存の文字列の任意の領域をある文字列で置き換えたり、既存の文字列の任意の領域を消去したりすることもできる。

-Rebutter

それは、既存の文字列を取得して、得た文字列をJava内で操作し、既存の文字列を消去し、操作した文字列をセットすることでも行なえる。どちらが効率が良いのか?

-Hypothesizer

既存の文字列がとても長い場合、後者のほうがはるかに効率が良い。なぜだか知らないが、長い既存文字列を前者の方法で操作するのは、不思議に多くのCPUリソースを必要とする。

-Rebutter

どの程度の長さのことを言っているのか?

-Hypothesizer

数千文字だ。我々の極度に低速なコンピューターでは、1文字追加するのに約20秒かかる。

-Rebutter

そのコンピューターが極度に、極度に低速なことは知っているが、内部アルゴリズムが何か不適当ではないか?

-Hypothesizer

たぶん、そんなに長い文字列がスプレッドシートセルにセットされるとは想定されていないのだろう。長い文字列を考慮に入れれば、もっと良いアルゴリズムがあるはずだと思う。

-Rebutter

既存文字列がそれほど長くなかったらどうなのか?

-Hypothesizer

そうした場合の正確なパフォーマンスは計測していない。大量データを処理していなければ、感知できるような違いはないだろう。

-Rebutter

まあ、必要に直面したときに判断すればよいだろう。どちらにしろ、セル文字列を前者の方法で操作する必要性はあるのか?

-Hypothesizer

ああ、前者の方法が必要とされるケースはある。既存の文字列がその部分によって異なったフォーマットになっている場合、文字列全体をただ置き換えるというわけにはいかない。

-Rebutter

例えば、文字列中の1つの単語だけがイタリックという場合か?

-Hypothesizer

そうだ。もちろん、文字列全体を置き換えてフォーマットをセットしなおすことはできるが、それは面倒かもしれない。文字列全体の既存のフォーマット情報を取得して、そのフォーマットを再適用しなければならない。

-Rebutter

ふーむ、それが本当に面倒かどうかは知らないが、文字列がそれほど長くない場合、前者の方法で既存文字列を操作するのが自然そうだ。

-Hypothesizer

長いセル文字列をその部分ごとにフォーマット適用したい場合には、何か方法を考えなければならないだろう。

-Rebutter

ワードプロセッサーを扱っているわけではないので、込み入ったフォーマットが必要になるとは思わないが、文字列中の特定の単語を示すマーカーが欲しいということはあるかもしれない。

-Hypothesizer

ああ、そうかもしれない。しかし、今、そこに深入りするのはやめておこう。

-Rebutter

オーケー。

-Hypothesizer

前の記事で行なったように、セルUNOオブジェクトから、'com.sun.star.text.XText'UNOインターフェースを使って、'com.sun.star.text.XTextCursor'インスタンスを得る。UNOインターフェース、'com.sun.star.text.XTextCursor'は、'com.sun.star.text.XTextRange'のサブインターフェースであり、セルの文字列のある選択された領域を代表する。

-Rebutter

それでは、'com.sun.star.text.XTextCursor'インスタンスはただの単点カーソルではないわけだ。

-Hypothesizer

選択された領域が縮んで文字が一つも選択されていない状態になれば、この'com.sun.star.text.XTextCursor'インスタンスは単点カーソルになる。

-Rebutter

なるほど。

-Hypothesizer

メソッド、'createTextCursor'で'com.sun.star.text.XTextCursor'インスタンスを得た場合、初期状態では文字列全体が選択されている。メソッド、'createTextCursorByRange'を使えば、カーソルが文字列の先頭か終端に置かれた'com.sun.star.text.XTextCursor'インスタンスを得ることができる。

-Rebutter

おお。

-Hypothesizer

カーソルは、メソッド、'goRight'か'goLeft'によって、それぞれ右か左に移動することができる。これらのメソッドでは、カーソルを何文字分移動させるかを指定できる。

カーソルは、'gotoStart'か'gotoEnd'によって、それぞれ文字列の先頭か終端に移動することができる。

-Rebutter

文字列の領域はどのように選択できるのか?

-Hypothesizer

上記4メソッドは、選択されている領域を拡張するかどうかを指定する引数を持っている。

-Rebutter

ふーむ、察するに、ある領域を選択したい場合、その引数をオフにしてカーソルをその領域の左端に移動し、次に、その引数をオンにしてカーソルをその領域の右端まで移動すればよいわけだ。

-Hypothesizer

そう。もちろん、反対方向に、カーソルを領域の右端に位置させ、左へ拡張することでも同じことができる。

-Rebutter

なるほど。

-Hypothesizer

カーソルの状態を調整した後、'com.sun.star.text.XText'UNOインターフェースの'insertString'メソッドを呼んで文字列を挿入する。'com.sun.star.text.XTextCursor'インスタンスと挿入するべき文字列を、それぞれ第1、第2引数として渡す。. 第3引数には、選択された領域を置換するかどうかを指定する。しない場合は、新たな文字列は選択された領域の前に挿入される。

-Rebutter

文字列が挿入された後、カーソルの状態はどうなるのか?

-Hypothesizer

選択された領域が置換されるか否かにかかわらず、カーソルは、挿入された文字列の後ろに、単点カーソルとして位置する。

-Rebutter

ははあ。

-Hypothesizer

選択された領域を消去したい場合は、空文字列で領域を置換するようにメソッド、'insertString'を呼べばよい。

-Rebutter

なるほど。

-Hypothesizer

結局、前記事のコードの後に以下のコードを書いた。

   l_spreadSheetCell = l_currentSpreadSheetInXSpreadsheet.getCellByPosition (0, 8);
   l_spreadSheetCellInXPropertySet = (XPropertySet) UnoRuntime.queryInterface (XPropertySet.class, l_spreadSheetCell);
   l_spreadSheetCellInXText = (XText) UnoRuntime.queryInterface (XText.class, l_spreadSheetCell);
   l_spreadSheetCellInXPropertySet.setPropertyValue("NumberFormat", new Integer (l_textFormatIdentification));
   l_string = "0123456789";
   l_spreadSheetCell.setFormula ("");
   l_textCursor = l_spreadSheetCellInXText.createTextCursor ();
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor = l_spreadSheetCellInXText.createTextCursorByRange (l_spreadSheetCellInXText.getEnd ());
   l_textCursor.gotoStart (false);
   l_string = "A";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor.goRight ( (short) 1,false);
   l_string = "B";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor.goRight ( (short) 1, false);
   l_textCursor.goRight ( (short) 1, true);
   l_string = "C";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_string = "D";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor.gotoEnd (false);
   l_string = "E";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor.goLeft ( (short) 2, false);
   l_string = "F";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor.goLeft ( (short) 2, false);
   l_textCursor.goLeft ( (short) 1, true);
   l_string = "G";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   l_textCursor.goLeft ( (short) 2, false);
   l_textCursor.goLeft ( (short) 1, true);
   l_string = "";
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
-Rebutter

カーソルを、既存文字列の終端に位置させた初期状態で取得し、文字列の先頭に移動した。

-Hypothesizer

そう。もちろん、既存文字列の先頭に位置させた初期状態で取得することもできる。上記のようにしたのは、'gotoStart'メソッドの呼び出しを実証するためだ。

-Rebutter

分かっている。

-Hypothesizer

最終的なセル文字列は"A0B1CD346G8F9E"のはずだ。

Main body END

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

25: スプレッドシートセルから読んだりスプレッドシートセルに書いたりする、パート3

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

Main body START

LibreOfficeまたはApache OpenOfficeのCalcスプレッドシートを拡張機能を通してJavaまたはマクロプログラムから操作する(読むまたは書く)方法を知る

スプレッドシートセルに値をどのようにセットできるか?

-Hypothesizer

スプレッドシートセルに値をセットしよう。

-Rebutter

オーケー。

-Hypothesizer

セルに値が内部的にどのように保持されているかから推測できるように、値が文字列でも式でもない場合、値は、doubleの値としてセットできる。しかし、そうするためには、例えば、日付値をその日付値を表わすdouble値へと変換しなければならない。この変換ルールを我々は知らないので、我々は、別の方法で値をセットすることにする。

-Rebutter

いいだろう。

-Hypothesizer

日付値は、セルUNOオブジェクトのUNOコンポーネントが実装している'com.sun.star.table.XCell'UNOインターフェースの'setFormula'メソッドを使ってセットすることができる。

-Rebutter

式をセットするわけでもないのに、'setFormula'メソッドを使うのか?

-Hypothesizer

変だと思うかもしれないが、そう、そうする。セル値表現フォーマット(数値フォーマットと呼ばれているもの)をセットした後、'setFormula'メソッドを、引数にセル値表現文字列を渡して呼び出す。

-Rebutter

ふーむ。

-Hypothesizer

日付値、時刻値、日付時刻値、真偽値について、我々は、値をこの同じ方法でセットする。

-Rebutter

整数値と小数値はどうする?

-Hypothesizer

それらも同じ方法でセットできるが、それらは、直接、double値をセットすることにしよう。そうすれば、セル値表現文字列を作らなくてもよいから。

-Rebutter

まあ、整数値と小数値については、それがより面倒でない方法だということは理解できる。

-Hypothesizer

文字列値については、値を、セルUNOオブジェクトのUNOコンポーネントが実装している'com.sun.star.text.XText'UNOインターフェースの'insertString'メソッドを呼んでセットする。このメソッドを呼ぶためには、まず、セルUNOオブジェクトから、'com.sun.star.text.XText'UNOインターフェースを使って'com.sun.star.text.XTextCursor'インスタンス得る。

-Rebutter

新たな文字列値を挿入する前に、まず、既存の値を取り除く必要はないのか?

-Hypothesizer

既存のdouble値は自動的に破棄されるようだ。既存の文字列値については、我々は、'setFormula'メソッドを、引数に""を渡して呼んで、文字列を消去する。

-Rebutter

文字列値を'setFormula'メソッドで直接セットできないのか?

-Hypothesizer

文字列値が式として解釈できる場合(例えば、"= A8 + 1")、それは、文字列値としてではなく、式としてセットされるだろう。だから、我々は、文字列値を'setFormula'メソッドでセットしない。

-Rebutter

ははあ。

doubleベースの値がセットされる場合も、文字列値は自動的に破棄されるのか?

-Hypothesizer

そのようだ。

-Rebutter

なるほど。

-Hypothesizer

式は、'setFormula'メソッドを使ってセットできる。

-Rebutter

ははあ。

-Hypothesizer

結局、前記事のtryブロックの最後の位置に以下を書いた。

   XPropertySet l_spreadSheetCellInXPropertySet = null;
   XText l_spreadSheetCellInXText = null;
   // set a formula to the cell 0, 0
   l_spreadSheetCell = l_currentSpreadSheetInXSpreadsheet.getCellByPosition (0, 0);
   String l_formula = "= A8 + 1";
   l_spreadSheetCell.setFormula (l_formula);
   // set a date to the cell 0, 1
   l_spreadSheetCell = l_currentSpreadSheetInXSpreadsheet.getCellByPosition (0, 1);
   l_spreadSheetCellInXPropertySet = (XPropertySet) UnoRuntime.queryInterface (XPropertySet.class, l_spreadSheetCell);
   LocalDate l_date = LocalDate.parse ("2017-01-01", DateTimeFormatter.ISO_LOCAL_DATE);
   String l_dateString = l_date.format (DateTimeFormatter.ISO_LOCAL_DATE);
   l_spreadSheetCellInXPropertySet.setPropertyValue("NumberFormat", new Integer (l_dateFormatIdentification));
   l_spreadSheetCell.setFormula (l_dateString);
   // set a time to the cell 0, 2
   l_spreadSheetCell = l_currentSpreadSheetInXSpreadsheet.getCellByPosition (0, 2);
   l_spreadSheetCellInXPropertySet = (XPropertySet) UnoRuntime.queryInterface (XPropertySet.class, l_spreadSheetCell);
   LocalTime l_time = LocalTime.parse ("01:02:03", DateTimeFormatter.ISO_LOCAL_TIME);
   String l_timeString = l_time.format (DateTimeFormatter.ISO_LOCAL_TIME);
   l_spreadSheetCellInXPropertySet.setPropertyValue("NumberFormat", new Integer (l_timeFormatIdentification));
   l_spreadSheetCell.setFormula (l_timeString);
   // set a date time to the cell 0, 3
   l_spreadSheetCell = l_currentSpreadSheetInXSpreadsheet.getCellByPosition (0, 3);
   l_spreadSheetCellInXPropertySet = (XPropertySet) UnoRuntime.queryInterface (XPropertySet.class, l_spreadSheetCell);
   LocalDateTime l_dateTime = LocalDateTime.parse ("2017-01-01T01:02:03", DateTimeFormatter.ISO_LOCAL_DATE_TIME);
   String l_dateTimeString = l_dateTime.format (DateTimeFormatter.ISO_LOCAL_DATE_TIME);
   l_spreadSheetCellInXPropertySet.setPropertyValue("NumberFormat", new Integer (l_dateTimeFormatIdentification));
   l_spreadSheetCell.setFormula (l_dateTimeString);
   // set a boolean to the cell 0, 4
   l_spreadSheetCell = l_currentSpreadSheetInXSpreadsheet.getCellByPosition (0, 4);
   l_spreadSheetCellInXPropertySet = (XPropertySet) UnoRuntime.queryInterface (XPropertySet.class, l_spreadSheetCell);
   Boolean l_boolean = new Boolean (true);
   l_spreadSheetCellInXPropertySet.setPropertyValue("NumberFormat", new Integer (l_booleanFormatIdentification));
   l_spreadSheetCell.setFormula (l_boolean.toString ());
   // set a string to the cell 0, 5
   l_spreadSheetCell = l_currentSpreadSheetInXSpreadsheet.getCellByPosition (0, 5);
   l_spreadSheetCellInXPropertySet = (XPropertySet) UnoRuntime.queryInterface (XPropertySet.class, l_spreadSheetCell);
   l_spreadSheetCellInXText = (XText) UnoRuntime.queryInterface (XText.class, l_spreadSheetCell);
   String l_string = "= A8 + 1";
   l_spreadSheetCellInXPropertySet.setPropertyValue("NumberFormat", new Integer (l_textFormatIdentification));
   l_spreadSheetCell.setFormula ("");
   XTextCursor l_textCursor = l_spreadSheetCellInXText.createTextCursor();
   l_spreadSheetCellInXText.insertString (l_textCursor, l_string, true);
   // set a double to the cell 0, 6
   l_spreadSheetCell = l_currentSpreadSheetInXSpreadsheet.getCellByPosition (0, 6);
   l_spreadSheetCellInXPropertySet = (XPropertySet) UnoRuntime.queryInterface (XPropertySet.class, l_spreadSheetCell);
   Double l_double = new Double (1.1);
   l_spreadSheetCellInXPropertySet.setPropertyValue("NumberFormat", new Integer (l_doubleFormatIdentification));
   l_spreadSheetCell.setValue (l_double.doubleValue ());
   // set an integer to the cell 0, 7
   l_spreadSheetCell = l_currentSpreadSheetInXSpreadsheet.getCellByPosition (0, 7);
   l_spreadSheetCellInXPropertySet = (XPropertySet) UnoRuntime.queryInterface (XPropertySet.class, l_spreadSheetCell);
   Integer l_integer = new Integer (1);
   l_spreadSheetCellInXPropertySet.setPropertyValue("NumberFormat", new Integer (l_integerFormatIdentification));
   l_spreadSheetCell.setValue (l_integer.intValue ());

また、以下のimportを追加した。

import com.sun.star.text.XTextCursor;
import com.sun.star.beans.PropertyVetoException;

それに、catchブロックに、以下の例外タイプを追加した。

com.sun.star.lang.IndexOutOfBoundsException
PropertyVetoException
-Rebutter

ふーむ、第1列の上方のセル群に値をセットしている。

文字列値を'java.time.LocalDate'値に変換して、さらにこの'java.time.LocalDate'値を元の文字列に変換し直しているのはなぜなのか?

-Hypothesizer

ああ、それは、将来のスプレッドシートセルラッパークラスで行なうことのシミュレーションだ。'java.time.LocalDate'の値を受け取り、この値をセルにセットする。

-Rebutter

値を'java.lang.Object'として受け取り、データタイプを判定し、値をそのデータタイプに応じてセットするんだろう。

-Hypothesizer

そうだ。

Main body END

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

2017年7月15日土曜日

24: スプレッドシートセルから読んだりスプレッドシートセルに書いたりする、パート2

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

Main body START

LibreOfficeまたはApache OpenOfficeのCalcスプレッドシートを拡張機能を通してJavaまたはマクロプログラムから操作する(読むまたは書く)方法を知る

スプレッドシートセルの値はどのように得られるか?

-Hypothesizer

スプレッドシートセルへのリファレンスを得たので、スプレッドシートセルの値を得たい。

-Rebutter

オーケー。

-Hypothesizer

実のところ、それはあまり単純ではない。セルUNOオブジェクトが実装している'com.sun.star.table.XCell'UNOインスタンスにはメソッド、'getValue'があるが、このメソッドの戻りタイプは'double'だ。

-Rebutter

ふむ?どういうことだ?

-Hypothesizer

セルが文字列値を保持していれば、メソッドは0.0を戻す。セルが日付値を保持していれば、メソッドはある種の内部値を戻す(例えば、2017-01-01には42736.0)。セルが真偽値を保持していれば、メソッドは、TRUEには1.0、FALSEには0.0を戻す。セルが式を保持していれば、式の結果が文字列値ならば0.0を戻し、それ以外ならば式の結果に対応する値を戻す。

-Rebutter

それでは、文字列値はどうすれば得られるのか?

-Hypothesizer

セルが文字列値を保持しているときは、式の結果が文字列値である場合も含め、この文字列値を、'com.sun.star.text.XText'インターフェースのメソッド、'getString'で得ることができる。

-Rebutter

セルUNOコンポーネントは'com.sun.star.text.XText'インターフェースを実装している。

-Hypothesizer

そう。実は、この'getString'メソッドは、セルの値が何であれ、その表現文字列を戻す。

-Rebutter

「表現文字列」というのは、セル上に表示される文字列のことか?

-Hypothesizer

そう。例えば、真偽値の'TRUE'や小数値の'1.23'だ。

-Rebutter

ふーむ、とにかく、セルの値を'getValue'メソッドで得るとき、戻りが、例えば、1.0だった場合、その値が何なのかが分からない。それは、整数の1なのか、小数の1.0なのか、真偽のTRUEなのか、それとも何かの日付なのか?

-Hypothesizer

スプレッドシートセルの値が文字列でない場合、セルの内部値は常に'double'なのだと思われる。セルの表現は、セル値表現フォーマットによって制御されている。

-Rebutter

「セル値表現フォーマット」というのは . . . 何だ?

-Hypothesizer

セル上でマウスを右クリックし、'Formating Cells...(セルの書式設定...)'を選択して、'Numbers(数値)'タブで設定できるものだ。「数値フォーマット」と呼ばれているようだが、命名が変だと思われる。それには文字列に対するフォーマットも含まれていて、これは数値ではない。

-Rebutter

なるほど。とにかく、セルのセル値表現フォーマットを得なければならないことになる。

-Hypothesizer

セル値表現フォーマットは、セルUNOオブジェクトのプロパティ値として得ることができる。具体的には、セルUNOコンポーネントが実装している'com.sun.star.beans.XPropertySet'インターフェースのメソッド、'getPropertyValue'で得ることができる。プロパティ名は'NumberFormat'であり、プロパティ値は、整数であるセル値表現フォーマットキーだ。

-Rebutter

それで、その整数のプロパティ値が何を意味するかをどうやって知ることができるのか?

-Hypothesizer

スプレッドシートドキュメントUNOオブジェクトから'com.sun.star.util.XNumberFormats'インターフェースのインスタンスを得ることができ、そのインスタンスから、セル値表現フォーマットキー群とキー毎のフォーマット文字列を得ることができる。

-Rebutter

それらが、そのドキュメントに登録されたセル値表現フォーマットキー群とそのフォーマット文字列なわけだ。

-Hypothesizer

そう。

セル値表現フォーマットとセル値を得るから、我々は、セル値を、望みどおりに解釈することができる。

-Rebutter

いいだろう。

-Hypothesizer

我々がやりたいのは、セルのセル値表現フォーマットに応じて、セル値を適切なデータタイプで得ることだ。我々は、'getString'メソッドからセル値表現文字列を得て、この文字列を適切なデータタイプに変換することにする。具体的には、セル値表現フォーマットに応じて、java.time.LocalDate、java.time.LocalTime、java.time.LocalDateTime、java.lang.Boolean、java.lang.String、java.lang.Integer、java.lang.Doubleのインスタンスを得ることにする。. . . 我々の方法がパフォーマンスの観点から最適だとは私は特に主張しない。

-Rebutter

いいだろう。

-Hypothesizer

セル値表現フォーマットについて、あらゆる可能な表現フォーマットに対処することはここではしない。我々は、自分で使うつもりの特定の表現フォーマットだけに対処する。我々はそうした特定の表現フォーマットだけを使うつもりなので、実用的にはそれで十分だ。

-Rebutter

特定の表現フォーマットというのは具体的には何なのか?

-Hypothesizer

日付には'YYYY-MM-DD'、時刻には'HH:MM:SS'、日付時刻には'YYYY-MM-DD\"T\"HH:MM:SS'、真偽には'BOOLEAN'、文字列には'@'、整数には'0'、小数には'Global'または'Standard'だ。

-Rebutter

'Global'または'Standard'というのはどういう意味だ?

-Hypothesizer

なぜだか分からないが、LibreOfficeのロケール設定が'日本語'に設定されていると、'Standard'が使われる。他のほとんどの場合、'Global'が使われる。

-Rebutter

ふーむ。

'YYYY-MM-DD\"T\"HH:MM:SS'などの表現フォーマットがドキュメント中に存在しなかったらどうなるのか?

-Hypothesizer

存在しなければ、我々のプログラムが登録する。

-Rebutter

おう。

-Hypothesizer

セルに式が保持されている場合、式自体は、'com.sun.star.table.XCell'インターフェースのメソッド、'getFormula'で得ることができる。

-Rebutter

なるほど。

-Hypothesizer

結局、以下のコードを書いた。

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import com.sun.star.lang.Locale;
import com.sun.star.util.XNumberFormatsSupplier;
import com.sun.star.util.XNumberFormats;
import com.sun.star.util.MalformedNumberFormatException;
import com.sun.star.beans.XPropertySet;
import com.sun.star.beans.UnknownPropertyException;
import com.sun.star.text.XText;
import com.sun.star.table.CellContentType;

  try {
   String l_dateFormatString = "YYYY-MM-DD";
   String l_timeFormatString = "HH:MM:SS";
   String l_dateTimeFormatString = "YYYY-MM-DD\"T\"HH:MM:SS";
   String l_booleanFormatString = "BOOLEAN";
   String l_textFormatString = "@";
   String l_integerFormatString = "0";
   String l_doubleFormatString = "Global";
   Locale l_locale = new Locale ();
   XNumberFormatsSupplier l_numberFormatsSupplier = UnoRuntime.queryInterface (XNumberFormatsSupplier.class, l_currentSpreadSheetsDocument);
   XNumberFormats l_numberFormats = l_numberFormatsSupplier.getNumberFormats ();
   int l_dateFormatIdentification = -1;
   int l_timeFormatIdentification = -1;
   int l_dateTimeFormatIdentification = -1;
   int l_booleanFormatIdentification = -1;
   int l_textFormatIdentification = -1;
   int l_integerFormatIdentification = -1;
   int l_doubleFormatIdentification = -1;
   l_dateFormatIdentification = l_numberFormats.queryKey (l_dateFormatString, l_locale, false);
   if (l_dateFormatIdentification == -1) {
    l_dateFormatIdentification = l_numberFormats.addNew (l_dateFormatString, l_locale);
   }
   l_timeFormatIdentification = l_numberFormats.queryKey (l_timeFormatString, l_locale, false);
   if (l_timeFormatIdentification == -1) {
    l_timeFormatIdentification = l_numberFormats.addNew (l_timeFormatString, l_locale);
   }
   l_dateTimeFormatIdentification = l_numberFormats.queryKey (l_dateTimeFormatString, l_locale, false);
   if (l_dateTimeFormatIdentification == -1) {
    l_dateTimeFormatIdentification = l_numberFormats.addNew (l_dateTimeFormatString, l_locale);
   }
   l_booleanFormatIdentification = l_numberFormats.queryKey (l_booleanFormatString, l_locale, false);
   if (l_booleanFormatIdentification == -1) {
    l_booleanFormatIdentification = l_numberFormats.addNew (l_booleanFormatString, l_locale);
   }
   l_textFormatIdentification = l_numberFormats.queryKey (l_textFormatString, l_locale, false);
   if (l_textFormatIdentification == -1) {
    l_textFormatIdentification = l_numberFormats.addNew (l_textFormatString, l_locale);
   }
   l_integerFormatIdentification = l_numberFormats.queryKey (l_integerFormatString, l_locale, false);
   if (l_integerFormatIdentification == -1) {
    l_integerFormatIdentification = l_numberFormats.addNew (l_integerFormatString, l_locale);
   }
   l_doubleFormatIdentification = l_numberFormats.queryKey (l_doubleFormatString, l_locale, false);
   if (l_doubleFormatIdentification == -1) {
    l_doubleFormatString = "Standard";
    l_doubleFormatIdentification = l_numberFormats.queryKey (l_doubleFormatString, locale, false);
    if (l_doubleFormatIdentification == -1) {
     // If your locale setting has a different default decimal fraction format string, you should use it.
    }
   }
   CellContentType l_cellContentType = l_currentSpreadSheetCell.getType ();
   if (l_cellContentType == CellContentType.EMPTY) {
   }
   else {
    if (l_cellContentType == CellContentType.FORMULA) {
     Publisher.show (l_currentSpreadSheetCell.getFormula ());
    }
    XPropertySet l_currentSpreadSheetCellInXPropertySet = (XPropertySet) UnoRuntime.queryInterface (XPropertySet.class, l_currentSpreadSheetCell);
    XText l_currentSpreadSheetCellInXText = (XText) UnoRuntime.queryInterface (XText.class, l_currentSpreadSheetCell);
    int l_numberFormat = ((Integer) l_currentSpreadSheetCellInXPropertySet.getPropertyValue ("NumberFormat")).intValue ();
    String l_cellString = l_currentSpreadSheetCellInXText.getString ();
    if (l_numberFormat == l_dateFormatIdentification) {
     LocalDate l_date = LocalDate.parse (l_cellString, DateTimeFormatter.ISO_LOCAL_DATE);
     Publisher.show (l_date.toString ());
    }
    else if (l_numberFormat == l_timeFormatIdentification) {
     LocalTime l_time = LocalTime.parse (l_cellString, DateTimeFormatter.ISO_LOCAL_TIME);
     Publisher.show (l_time.toString ());
    }
    else if (l_numberFormat == l_dateTimeFormatIdentification) {
     LocalDateTime l_dateTime = LocalDateTime.parse (l_cellString, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
     Publisher.show (l_dateTime.toString ());
    }
    else if (l_numberFormat == l_booleanFormatIdentification) {
     Boolean l_boolean = Boolean.valueOf (l_cellString);
     Publisher.show (l_boolean.toString ());
    }
    else if (l_numberFormat == l_textFormatIdentification) {
     Publisher.show (l_cellString);
    }
    else {
     Matcher l_matcher = Pattern.compile ("^(\\d*|\\d{1,3}(,\\d{3})*)(\\.\\d+)?([eE][-+]?\\d+)?$").matcher (l_cellString);
     if (l_matcher.find ()) {
      if (l_matcher.group (3) != null) {
       Double l_double = Double.valueOf (l_cellString.replaceAll (",", ""));
       Publisher.show (l_double.toString ());
      }
      else {
       Integer l_integer = Integer.valueOf (l_cellString.replaceAll (",", ""));
       Publisher.show (l_integer.toString ());
      }
     }
     else {
      Publisher.show (l_cellString);
     }
    }
   }
  }
  catch (MalformedNumberFormatException | UnknownPropertyException | WrappedTargetException l_exception) {
   Publisher.show (l_exception.toString ());
  }
-Hypothesizer

上記コードを毎回書くのは面倒なので、もちろん、これらの処理はラッパークラスに行なわせることにする。

-Rebutter

それでは、そのラッパークラスを使えば、スプレッドシートセルの値を単一のメソッドで得られるのか?

-Hypothesizer

そう。

Main body END

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

23: スプレッドシートセルから読んだりスプレッドシートセルに書いたりする、パート1

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

Main body START

LibreOfficeまたはApache OpenOfficeのCalcスプレッドシートを拡張機能を通してJavaまたはマクロプログラムから操作する(読むまたは書く)方法を知る

スプレッドシートセルから読んだりスプレッドシートセルに書いたりしたい

-Hypothesizer

今や、我々は、UNO拡張機能を開発する方法を知っている。しかし、おそらくは、LibreOfficeドキュメントとやり取りしたいだろう。

-Rebutter

おそらくは、そうだろう。LibreOfficeドキュメントとやり取りする必要がないのであれば、普通、通常のJavaプログラムを開発すればよい。

-Hypothesizer

典型的な要件は、スプレッドシートセルから読んだりスプレッドシートセルに書いたりすることだ。

-Rebutter

そうする方法を学べば、スプレッドシートドキュメントを操作することが可能になってくるだろう。

-Hypothesizer

スプレッドシートドキュメントは特定のUNOコンポーネント群のインスタンス群で構成されているので、これらのUNOコンポーネントが何で、これらのUNOコンポーネントのインスタンスをどのように操作すればよいかを学ばなければならない。

-Rebutter

いいだろう。

スプレッドシートドキュメントとは何か?スプレッドシートとは何か?スプレッドシートセルとは何か?

-Hypothesizer

スプレッドシートドキュメントは、スプレッドシートドキュメントを新規作成したり、スプレッドシートドキュメントファイルを開いたときに、開くものだ。

-Rebutter

ははあ。スプレッドシートドキュメントを新規作成すると、一つのウィンドウが開き、デフォルト設定では、それは1つのスプレッドシートを持っている。

-Hypothesizer

そう。スプレッドシートドキュメントは、スプレッドシート群のコンテナだ。

スプレッドシートドキュメントコンポーネントは、以下のUNOインターフェースを実装している。

com.sun.star.container.XChild
com.sun.star.document.XDocumentPropertiesSupplier
com.sun.star.document.XCmisDocument
com.sun.star.rdf.XDocumentMetadataAccess
com.sun.star.document.XDocumentRecovery
com.sun.star.document.XUndoManagerSupplier
com.sun.star.document.XEventBroadcaster
com.sun.star.document.XDocumentEventBroadcaster
com.sun.star.lang.XEventListener
com.sun.star.document.XEventsSupplier
com.sun.star.document.XEmbeddedScripts
com.sun.star.document.XScriptInvocationContext
com.sun.star.frame.XModel2
com.sun.star.util.XModifiable2
com.sun.star.view.XPrintable
com.sun.star.view.XPrintJobBroadcaster
com.sun.star.frame.XStorable2
com.sun.star.frame.XLoadable
com.sun.star.script.XStarBasicAccess
com.sun.star.document.XViewDataSupplier
com.sun.star.util.XCloseable
com.sun.star.datatransfer.XTransferable
com.sun.star.document.XDocumentSubStorageSupplier
com.sun.star.document.XStorageBasedDocument
com.sun.star.script.provider.XScriptProviderSupplier
com.sun.star.ui.XUIConfigurationManagerSupplier
com.sun.star.embed.XVisualObject
com.sun.star.lang.XUnoTunnel
com.sun.star.frame.XModule
com.sun.star.frame.XTitle
com.sun.star.frame.XTitleChangeBroadcaster
com.sun.star.frame.XUntitledNumbers
com.sun.star.lang.XTypeProvider
com.sun.star.uno.XWeak
com.sun.star.sheet.XSpreadsheetDocument
com.sun.star.document.XActionLockable
com.sun.star.sheet.XCalculatable
com.sun.star.util.XProtectable
com.sun.star.drawing.XDrawPagesSupplier
com.sun.star.sheet.XGoalSeek
com.sun.star.sheet.XConsolidatable
com.sun.star.sheet.XDocumentAuditing
com.sun.star.style.XStyleFamiliesSupplier
com.sun.star.view.XRenderable
com.sun.star.document.XLinkTargetSupplier
com.sun.star.beans.XPropertySet
com.sun.star.lang.XMultiServiceFactory
com.sun.star.lang.XServiceInfo
com.sun.star.util.XChangesNotifier
com.sun.star.sheet.opencl.XOpenCLSelection
com.sun.star.util.XNumberFormatsSupplier
com.sun.star.lang.XUnoTunnel
com.sun.star.lang.XTypeProvider
com.sun.star.uno.XWeak
com.sun.star.uno.XAggregation
-Rebutter

うーん、多くのUNOインターフェースを実装しているな . . .

-Hypothesizer

UNOコンポーネントがどのUNOインターフェースを実装しているかを知ることが重要だ。それを知らなければ、UNOコンポーネントのメソッドを呼ぶことができない。

-Rebutter

UNOコンポーネントに実装されているUNOインターフェースを我々はどのように知ることができるのか?

-Hypothesizer

一般的に言って、どのオフィシャル文書からもそれを知ることができない。あるメソッドの戻りとしてあるUNOオブジェクトを得るとき、そのUNOオブジェクトのUNOコンポーネントがその戻りタイプのUNOインターフェースを実装していることしか、我々は知らない。そのUNOコンポーネントは他にどんなUNOインターフェースを実装しているのか?オフィシャル文書からは我々はそれを知ることができない。

-Rebutter

ふーむ。

-Hypothesizer

我々は、上記UNOインターフェースを、実行時にスプレッドシートドキュメントUNOオブジェクトを調べることで知った。

-Rebutter

ふーむ、ここでは、どのようにそうしたかに深入りするのはやめよう。話が脱線するから。

-Hypothesizer

スプレッドシートは、スプレッドシートドキュメントのスプレッドシートタブをクリックしたときに表示されるシートだ。スプレッドシートは、スプレッドシートセル群を持っている。

スプレッドシートコンポーネントは以下のUNOインターフェースを実装している。

com.sun.star.beans.XPropertySet
com.sun.star.beans.XMultiPropertySet
com.sun.star.beans.XPropertyState
com.sun.star.sheet.XSheetOperation
com.sun.star.chart.XChartDataArray
com.sun.star.util.XIndent
com.sun.star.sheet.XCellRangesQuery
com.sun.star.sheet.XFormulaQuery
com.sun.star.util.XReplaceable
com.sun.star.util.XModifyBroadcaster
com.sun.star.lang.XServiceInfo
com.sun.star.lang.XUnoTunnel
com.sun.star.lang.XTypeProvider
com.sun.star.sheet.XCellRangeAddressable
com.sun.star.sheet.XSheetCellRange
com.sun.star.sheet.XArrayFormulaRange
com.sun.star.sheet.XArrayFormulaTokens
com.sun.star.sheet.XCellRangeData
com.sun.star.sheet.XCellRangeFormula
com.sun.star.sheet.XMultipleOperation
com.sun.star.util.XMergeable
com.sun.star.sheet.XCellSeries
com.sun.star.table.XAutoFormattable
com.sun.star.util.XSortable
com.sun.star.sheet.XSheetFilterableEx
com.sun.star.sheet.XSubTotalCalculatable
com.sun.star.table.XColumnRowRange
com.sun.star.util.XImportable
com.sun.star.sheet.XCellFormatRangesSupplier
com.sun.star.sheet.XUniqueCellFormatRangesSupplier
com.sun.star.sheet.XSpreadsheet
com.sun.star.container.XNamed
com.sun.star.sheet.XSheetPageBreak
com.sun.star.sheet.XCellRangeMovement
com.sun.star.table.XTableChartsSupplier
com.sun.star.sheet.XDataPilotTablesSupplier
com.sun.star.sheet.XScenariosSupplier
com.sun.star.sheet.XSheetAnnotationsSupplier
com.sun.star.drawing.XDrawPageSupplier
com.sun.star.sheet.XPrintAreas
com.sun.star.sheet.XSheetAuditing
com.sun.star.sheet.XSheetOutline
com.sun.star.util.XProtectable
com.sun.star.sheet.XScenario
com.sun.star.sheet.XScenarioEnhanced
com.sun.star.sheet.XSheetLinkable
com.sun.star.sheet.XExternalSheetName
com.sun.star.document.XEventsSupplier
-Rebutter

ははあ。

-Hypothesizer

そして、スプレッドシートセルは、スプレッドシートにグリッド状に置かれているセル群の中の1つだ。

スプレッドシートセルコンポーネントは以下のUNOインターフェースを実装している。

com.sun.star.beans.XPropertySet
com.sun.star.beans.XMultiPropertySet
com.sun.star.beans.XPropertyState
com.sun.star.sheet.XSheetOperation
com.sun.star.chart.XChartDataArray
com.sun.star.util.XIndent
com.sun.star.sheet.XCellRangesQuery
com.sun.star.sheet.XFormulaQuery
com.sun.star.util.XReplaceable
com.sun.star.util.XModifyBroadcaster
com.sun.star.lang.XServiceInfo
com.sun.star.lang.XUnoTunnel
com.sun.star.lang.XTypeProvider
com.sun.star.sheet.XCellRangeAddressable
com.sun.star.sheet.XSheetCellRange
com.sun.star.sheet.XArrayFormulaRange
com.sun.star.sheet.XArrayFormulaTokens
com.sun.star.sheet.XCellRangeData
com.sun.star.sheet.XCellRangeFormula
com.sun.star.sheet.XMultipleOperation
com.sun.star.util.XMergeable
com.sun.star.sheet.XCellSeries
com.sun.star.table.XAutoFormattable
com.sun.star.util.XSortable
com.sun.star.sheet.XSheetFilterableEx
com.sun.star.sheet.XSubTotalCalculatable
com.sun.star.table.XColumnRowRange
com.sun.star.util.XImportable
com.sun.star.sheet.XCellFormatRangesSupplier
com.sun.star.sheet.XUniqueCellFormatRangesSupplier
com.sun.star.table.XCell
com.sun.star.sheet.XCellAddressable
com.sun.star.text.XText
com.sun.star.container.XEnumerationAccess
com.sun.star.sheet.XSheetAnnotationAnchor
com.sun.star.text.XTextFieldsSupplier
com.sun.star.document.XActionLockable
com.sun.star.sheet.XFormulaTokens
com.sun.star.table.XCell2
-Rebutter

ははあ。

カレントスプレッドシートはどのように得られるか?

-Hypothesizer

これで、これらのUNOコンポーネントがどのUNOインターフェースを実装しているかを知ったが、まず、UNOオブジェクトへのリファレンスを得ることが必要だ。

-Rebutter

勿論。

-Hypothesizer

典型的なユースケースは、カレントスプレッドシートへのリファレンスを得ることだろう。

-Rebutter

「カレント」というのは、現在フォーカスされているスプレッドシートのことか?

-Hypothesizer

そう。それは、以下のようにしてできる。ここで、'componentContext'はコンポーネントコンテキストだ。

import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import com.sun.star.frame.XDesktop;
import com.sun.star.frame.XModel;
import com.sun.star.sheet.XSpreadsheetDocument;
import com.sun.star.sheet.XSpreadsheet;
import com.sun.star.sheet.XSpreadsheetView;
import thebiasplanet.coreutilities.messaging.Publisher;

  XDesktop l_unoDesktop = null;
  try {
   l_unoDesktop = (XDesktop) UnoRuntime.queryInterface (XDesktop.class, componentContext.getServiceManager ().createInstanceWithContext ("com.sun.star.frame.Desktop", componentContext));
  }
  catch (com.sun.star.uno.Exception l_exception) {
   Publisher.show (l_exception.toString ());
  }
  XSpreadsheetDocument l_currentSpreadSheetsDocument = (XSpreadsheetDocument) UnoRuntime.queryInterface (XSpreadsheetDocument.class, l_unoDesktop.getCurrentComponent ());
  Publisher.show (l_currentSpreadSheetsDocument.toString ());
  XModel l_currentSpreadSheetsDocumentModel = (XModel) UnoRuntime.queryInterface (XModel.class, l_currentSpreadSheetsDocument);
  XSpreadsheetView  l_currentSpreadSheetsDocumentView = (XSpreadsheetView) UnoRuntime.queryInterface (XSpreadsheetView.class, l_currentSpreadSheetsDocumentModel.getCurrentController ());
  Object l_currentSpreadSheet = l_currentSpreadSheetsDocumentView .getActiveSheet ();
  Publisher.show (l_currentSpreadSheet.toString ());
-Rebutter

'l_currentSpreadSheet'がカレントスプレッドシートで、カレントスプレッドシートドキュメントは既に'l_currentSpreadSheetsDocument'として得られている。

それにしても、ただカレントスプレッドシートを得るだけなのに面倒だな。

-Hypothesizer

基本的に、UNOオブジェクトを操作するのは面倒だ。というのは、1つのUNOオブジェクトが多くのUNOインターフェースを実装しており、使おうとする各UNOインターフェース毎にUNOプロキシを得なければならないから。面倒だから、便利なように、我々は、後に、ユーティリティクラスやラッパークラスを作るだろう。

-Rebutter

いいだろう。

ところで、我々は、サービス、'com.sun.star.frame.Desktop'のインスタンスを生成した。これはシングルトンではないのか?つまり、デスクトップは、1個しかないはずで、既に存在しているはずだ。複数のデスクトップを生成するのは妙に思える。

-Hypothesizer

うーん、 . . . 私が知る限りでは、それはシングルトンであるようだ。2つのUNOプロキシが参照するUNOオブジェクトの同一性を、メソッド、'UnoRuntime.areSame'でチェックできるが、'componentContext.getServiceManager ().createInstanceWithContext ("com.sun.star.frame.Desktop", componentContext)' を2度呼んで得られる2つのUNOプロキシは同一のUNOオブジェクトを参照しているようだ。'createInstanceWithContext'メソッドがどのようにこのシングルトンを戻しているのか?私には分からない。

-Rebutter

ふーむ . . .、我々のサンプルUNO拡張機能を開発した方法からすると、どのようにそれが可能なのか、私には理解できない。

-Hypothesizer

参考文書には、それについての説明を見つけられなかった。. . . これは、将来、調査することにしよう。

-Rebutter

いいだろう。

-Hypothesizer

同じスプレッドシートドキュメントの別のスプレッドシートへのリファレンスを得たければ、それは以下のようにして得ることができる。

import com.sun.star.sheet.XSpreadsheets;
import com.sun.star.container.NoSuchElementException;
import com.sun.star.lang.WrappedTargetException;

  XSpreadsheets l_currentSpreadSheets = l_currentSpreadSheetsDocument.getSheets ();
  Object l_anotherSpreadSheet = null;
  try {
   l_anotherSpreadSheet = l_currentSpreadSheets .getByName ("Sheet2");
   Publisher.show (l_anotherSpreadSheet.toString ());
  }
  catch (NoSuchElementException | WrappedTargetException l_exception) {
   Publisher.show (l_exception.toString ());
  }}
-Rebutter

スプレッドシート名によってそれを得ることができる。

-Hypothesizer

スプレッドシート上のあるスプレッドシートセルへのリファレンスを得たければ、以下のようにしてそれを得ることができる。ここで、2は列のインデックスで、0は行のインデックスだ。

import com.sun.star.table.XCell;

  XSpreadsheet l_currentSpreadSheetInXSpreadsheet = (XSpreadsheet) UnoRuntime.queryInterface (XSpreadsheet .class, l_currentSpreadSheet );
   XCell l_spreadSheetCell = null;
  try {
   l_spreadSheetCell = l_currentSpreadSheetInXSpreadsheet.getCellByPosition (2, 0);
   Publisher.show (l_spreadSheetCell.toString ());
  }
  catch (com.sun.star.lang.IndexOutOfBoundsException l_exception) {
   Publisher.show (l_exception.toString ());
  }
-Rebutter

列インデックスや行インデックスは0から開始するわけだ。

カレントスプレッドシートセルはどのように得られるか?

-Hypothesizer

スプレッドシートセルの列インデックスと行インデックスによって、スプレッドシート上の任意のスプレッドシートセルへの参照を得ることができるが、場合によっては、カレントスプレッドシートセルへの参照を得たいと思うだろう。

-Rebutter

それは、予期できる要求だ。

-Hypothesizer

それは、以下のようにして得られる。

import com.sun.star.table.XCellRange;
  
  XCellRange l_currentCells = (XCellRange) UnoRuntime.queryInterface (XCellRange.class, l_currentSpreadSheetsDocumentModel.getCurrentSelection ());
   XCell l_currentSpreadSheetCell = null;
  try {
   l_currentSpreadSheetCell = l_currentCells.getCellByPosition (0, 0);
   Publisher.show (l_currentSpreadSheetCell.toString ());
  }
  catch (com.sun.star.lang.IndexOutOfBoundsException l_exception) {
   Publisher.show (l_exception.toString ());
  }
-Rebutter

なるほど。

Main body END

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