Top > OOobbs2 > 106

OOobbs2/106 Edit

  • サマリ: loadComponentFromURLとcloseメソッドについて(ドキュメント間のセル範囲コピー)
  • 環境: Calc
  • 状態: 解決
  • 投稿者: ponkan?
  • 投稿日: 2008-05-18 (日) 13:33:45

質問 Edit

異なるドキュメント間のセル範囲コピーについて、下記のようなものを組んでみました。
個々の名称は、ユニーク(一意)なものという事で他意はありません。

Sub tetugin28(B,C,D,E,F) rem ドキュメント間のコピー
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
sframe = ThisComponent.CurrentController.Frame
JunpTo(B,C)
dispatcher.executeDispatch(sframe, ".uno:Copy", "", 0, Array())
ddoc = StarDesktop.loadComponentFromURL(D,"_hidden", 0, Array())   rem ←疑問2 第2引数、"_hidden"
dframe = ThisComponent.CurrentController.Frame
hanicount(E,F)
dispatcher.executeDispatch(dframe, ".uno:Paste", "", 0, Array())
ddoc.storeAsURL(D,Array())
ddoc.close(imifumei)                                               rem ←疑問1 closeメソッドの引数
sframe.getContainerWindow().toFront()
end sub
sub hanicount(A,B) rem シートと列を指定して最終行へ移動(シート名ByName,列ByName)
cont = ThisComponent.getCurrentController()
hani = ThisComponent.getSheets().getByName(A).getCellRangeByName(B+"1:"+B+"1000")
ichi = B+(hani.computeFunction(com.sun.star.sheet.GeneralFunction.COUNT)+1)
cont.select(ThisComponent.getSheets().getByName(A).getCellRangeByName(ichi)
end sub
Sub JunpTo(A,B) rem シートと範囲を指定して移動(シート名ByName・セル範囲ByName)
cont = ThisComponent.getCurrentController()
cont.select(ThisComponent.getSheets().getByName(A).getCellRangeByName(B))
End Sub


call tetugin28("表1","B3:J3","file:///E:/test2.ods","表1","C")

等のように使いますが、実際にはもう少し細かくサブルーチン化しエラー処理をしています。
疑問点を洗う為に、ベタで書いては有りますが動作は致します。

疑問1、closeの引数にTrueを指定してもFalseを指定しても動作が変わらないのですが
こんなものなんでしょうか? 例えば上記でも動作し、"意味不明"とか入れると
例外が発生します。 型は確かにブールのようではありますが、意味不明なのです。
困った事にドキュメントの変更の有無に関わらず、保存例外が発生しないままcloseします。

疑問2、loadComponentFromURLの第二引数に"_hidden"を指定すると、非表示になる。
と、製品版ガイドに書いてあったように思いますが、非表示にならないように思います。

しかしよくよく考えてみるとOOoは、SDI(SingleDocumentInterface)だったのですね
今を去る20年程前、表計算ソフト黎明期にどちらがどうだとか誰かと議論したような
懐かしい記憶が有ります。 しかし今更苦労するとは・・・
それにしても、もう少し簡潔に記述出来ないものかと、つくづく思います。

回答 Edit

  • ドキュメント間でのセル範囲のコピーですね。最近はドキュメント間でのコピーは com.sun.star.datatransfer.XTransferable インターフェースでできることが知られています。

その前に、疑問点から。

  • 疑問1: close の引数。

OwnerShip をどうするか、という問題ですがフレームオブジェクトおよびドキュメントモデル自体が Owner なので Basic でしていしても問題点がない場合には挙動は同じようになるんだと思います。(True にする必要がある状況があったような気がするけど、あれは dispose の話だったか…な(?)。)

「変更を保存しますか」といったダイアログが出ないのは、 DevGuide Closing Documents によると、データを失いたくなければ XModifiableXStorable を利用して自分で処理しろ、みたいなことが書いてあります。

上記のインターフェースを利用する場合には次のような感じにします。

oDoc = ThisComponent
If oDoc.isModified() Then
  If oDoc.hasLocation() Then
    oDoc.store()
  Else
    oDoc.storeAsURL("file:///home/......", Array())
  End If
End If

Hidden モードで開いていないドキュメントであればコマンドでドキュメントを閉じればダイアログが表示されます。.uno:CloseDoc を利用します。(dispatch helper を利用したほうが記述が楽です。

 oController = ThisComponent.getCurrentController()
 aURL = CreateUnoStruct("com.sun.star.util.URL")
 aURL.Complete = ".uno:CloseDoc"
 CreateUnoService("com.sun.star.util.URLTransformer")._
   parseStrict(aURL)
 oDisp = oController.queryDispatch(aURL,"_self",0)
 If NOT IsNull(oDisp) Then
   oDisp.dispatch(aURL,Array())
 End If
  • 疑問2: loadComponentFromURL のターゲットフレーム名

利用可能なフレーム名は、普通のフレーム名以外に次のものがあります。

特殊フレーム名説明
_blank空の新規フレーム
_default特殊。空のドキュメントがあると利用される
_self自身のフレーム (現在のドキュメントの更新などが無視される)
_parent親フレーム
_topフレームツリーでの最上位フレーム
_beamerサブフレーム

_hidden は IDL ガイドに記載がありませんが、ドキュメントを非表示状態で開くには loadComponentFromURL メソッドの最後の引数に MediaDescriptor で Hidden パラメータを指定します。

Dim aArgs(0) As New com.sun.star.beans.PropertyValue
aArgs(0).Name = "Hidden"
aArgs(0).Value = True

StarDesktop.loadComponentFromURL("private:factory/scalc","_blank",0, aArgs)
  • はにゃ? 2008-05-18 (日) 14:12:06
  • XTransferable インターフェースを利用する方法です。

コントローラの com.sun.star.datatransfer.XTransferableSupplier インターフェースを利用します。

一方の (コピー元) ドキュメントのコントローラから getTransferable メソッドで XTransferable インターフェースを取得します。(このとき、選択範囲に相当するコンテンツが含まれていることに注意。) そして、もう一方のドキュメント (貼り付け先) のコントローラから insertTransferable メソッドで先のドキュメントから取得した XTransferable インターフェースを与えます。このメソッドは呼び出すとすぐに挿入されます。(このときも、セルカーソルのある位置に貼り付けられることに注意。)

Sub Copy_Transferable_1
 oDoc = ThisComponent
 oController = oDoc.getCurrentController()
 ' コピーする範囲を選択
 oController.select( _
     oDoc.getSheets().getByIndex(0).getCellRangeByPosition(0,0,1,2) )
 
 oTransferable = oController.getTransferable()
 
 Dim aArgs(0) As New com.sun.star.beans.PropertyValue
 aArgs(0).Name = "Hidden"
 aArgs(0).Value = False'True
 oNewDoc = StarDesktop.loadComponentFromURL( _
     "private:factory/scalc", "_blank", 0, aArgs )
 
 oNewDoc_Controller = oNewDoc.getCurrentController()
 ' 貼り付け先範囲を指定
 oNewDoc_Controller.select( _
     oNewDoc.getSheets().getByIndex(0).getCellByPosition(1,1) )
 
 oNewDoc_Controller.insertTransferable( oTransferable )
 
 oNewDoc.storeAsURL("file:///C:/usr/out.ods",Array())
 oNewDoc.close(True)
End Sub

Hidden = True だとセルの選択がうまくいかないかと思っていましが、そんなことありませんでした。

シートを丸ごとコピーするのであればシートのリンクが利用できるんですけどねぇ。

  • はにゃ? 2008-05-18 (日) 15:18:01
  • 素早い回答を有難う御座います。 -- ponkan 2008-05-18 (日) 16:50:56
    「変更を保存しますか」といったダイアログが出ない・・・自分で処理しろみたいなことが書いてあります。
    やはり、そうなんですねぇ。.....λ

    loadComponentFromURL メソッドの最後の引数に・・・については今まではそれで処理していましたが
    StarSuite 8 Basic プログラミングガイドのP83によれば、第二引数で可能見たいに書かれていましたので
    物は試しと、使ってみたのですが・・・。

Hidden = True だとセルの選択がうまくいかない・・・loadCの第4引数ですよね?
XTransferable インターフェースだと巧く行くのですか?・・・美味しそうですね。
シートリンクは下記のようにして使ってます。例によってものぐさ太郎コマンドです。

Sub shon (A,B) rem シート呼出(ファイル名・シート名)
s = ThisComponent.getSheets().getByIndex(6)                         rem シート番号固定
s.link(A,B,"","",com.sun.star.sheet.SheetLinkMode.NORMAL)
s.setLinkMode(com.sun.star.sheet.SheetLinkMode.NONE)                rem or NORMAL
End Sub
  • 閉じるときの保存処理は、.uno:CloseDoc などの場合には内部で保存処理などを行ってるようですから仕方ありません。

Hidden のときにセルカーソルをあまり動かしたことがなかったもので。Copy_Transferable_1 は一応動作確認しました。そういえば、Hidden = True で開いた時にはコマンドによる処理が動作しないんじゃなかったかな、と。

  • はにゃ? 2008-05-18 (Sun) 18:08:30
  • Hidden = True だとコントローラも、コンポーネントも、フレームも取得できないと思います。

因みに、前述のガイドではloadCの第4引数について次の様な記述があります

AsTemplate (ブール値) – これがTrue の場合、指定URLからドキュメントを読み込み
	新規の無題ドキュメントとして表示します。False の場合は、テンプレートファイルを編集モードで読み込みます。
CharacterSet (文字列) – ドキュメントで使用する文字列コードを指定します。
FilterName (文字列) – loadComponentFromURL メソッドで使用する特殊なフィルタを指定します。
	指定可能なフィルタ名は ファイル\share\config\registry\instance\org\openoffice\office\TypeDetection.xml
	に定義されています。
FilterOptions (文字列) – フィルタの追加オプションを指定します。
JumpMark (文字列) – ドキュメントのオープン後に、JumpMark の指定位置にジャンプさせます。
Password (文字列) – パスワード保護したファイル用のパスワードを与えます。
ReadOnly (ブール値) – 読み取り専用ドキュメントとして開くかを指定します。


JumpMarkのところが美味しそうな感じがしますが、なにせ製品版のガイドだと言う事で・・
話は1/25ぐらいに思ってます。
忘れていましたが、取敢えず完了にしておきます。

  • ponkan 2008-05-18 (日) 20:59:59
  • 上記のコードは Hidden のところを True にしても正しく動作しますが…。headless だと分かりませんが。

loadComponentFromURL メソッドの四番目の引数は MediaDescriptor に指定されているものを利用します。

MediaDescriptor はページを作ることにします。OOoBasic/Generic/MediaDescriptor

JumpMark を指定するとはドキュメントのブックマークの位置を表示します。URL のアンカー部分に相当します。

aArg = CreateUnoStruct("com.sun.star.beans.PropertyValue")
aArg.Name = "JumpMark"
aArg.Value = "bookmark"

StarDesktop.loadComponentFromURL( "file:///home/user/Doc.odt", "_blank", 0, Array( aArg ) )

上記は次のものと同じ動作をします。

StarDesktop.loadComponentFromURL( "file:///home/user/Doc.odt#anchor", ...

"#" で指定する方法は昨日、Writer のページに書いた気がします。

  • はにゃ? 2008-05-18 (Sun) 21:22:36
  • 取敢えず -- ponkan 2008-05-29 (木) 20:33:46
    hiddenモードでtxtファイルをcsvフィルタのscalcで開き、コンポーネントを退避して
    セルを選択させて見ました。

    sub test40
    csvinp2("file:///E:/test.txt","32,0,60,1",doc)
    JunpTo2(doc,"表1","A1:B3")
    cellpul2(doc,0,"B3",tes)
    msgbox tes
    end sub
    
    sub csvinp2(A,B,doc) rem csv読込
    Dim tes(2) As New com.sun.star.beans.PropertyValue
    tes(0).Name = "FilterName"
    tes(0).Value = "Text - txt - csv (StarCalc)"
    tes(1).Name = "FilterOptions"
    tes(1).Value = B
    tes(2).Name = "Hidden"
    tes(2).Value = True
    doc = StarDesktop.loadComponentFromURL(A, " ", 0,tes)
    end Sub
    
    sub JunpTo2(doc,A,B) rem シート・セル移動name
    cont = doc.getCurrentController()
    cont.select(doc.getSheets().getByName(A).getCellRangeByName(B))
    end Sub
    
    sub cellpul2(doc,A,B,C) rem セルの文字を取出すname
    C = doc.Sheets(A).getCellRangeByName(B).string
    end sub

    なんだか、何も出ないと寂しい気持ちになったりします。

    test.txtの内容

    a1 b1 c1 d1
    a2 b2 c2 d2
    a3 b3 c3 d3
    a4 b4 c4 d4

  • なるほど。Hidden 状態でも選択はうまく動作しているみたいです (ちょっといじりましたが)。soffice -headless macro:///Standard.Module1.test40() だとやっぱり何も表示されませんけど。 -- はにゃ? 2008-05-29 (Thu) 22:15:23
  • cmdインタープリタの話だとすれば -- ponkan 2008-05-30 (金) 08:30:36
    start /w /min soffice macro:///ponkan.A10.test40("")
    start soffice -headless macro:///ponkan.A10.test40("")

    だと動作しませんか?
    すみません、-headlessに興味が無くて前は意味が判らなかったです。
    sofficeのコマンドラインオプションだったのですね。
    効用が何かは知らないですが、動作しましたよ。
    • headless は GUI が一切表示されないモードです。このモードだとダイアログも出ません。「何も出ないと・・・」とあったので、headless だと何も表示されないなぁ・・・と。Linux などサーバー用途で GUI が特にいらない PC では -headless で。以前は Xvfb のようなものが必要だったらしいですが、2.3.0 付近からは -headless で不要になったようです。 -- はにゃ? 2008-05-30 (金) 11:07:16
  • 気になって試してみました -- ponkan 2008-05-30 (金) 20:23:55
    rem Option Explicit
    dim dlg As Object
    dim buzai As string
    
    sub test30
    dim iList(10) As String
    csvinp2("file:///E:/test.txt","",doc)
    dlg = CreateUnoDialog(DialogLibraries.       ponkan     .Dialog1)
    blist = dlg.getControl("ListBox1")
    for cou1 = 0 To 10 
    iList(cou1) = doc.Sheets(0).getCellByPosition(0,cou1).getString
    next cou1
    blist.model.StringItemList = iList()
    dlg.Execute
    doc.close(true)
    end sub
    
    sub ShowItem
    buzai = dlg.getControl("ListBox1").SelectedItem
    msgbox buzai
    dlg.endExecute
    end Sub

    ひとつのダイアログにひとつのリストボックスです。
    トリガーのbatは下記です。

    rem start soffice -headless macro:///ponkan.A07.test30("")

    編集しました。21:35
  • headless だとやはり実行時に作成したダイアログを setVisible(True) とせずに execute したような動作になりますねぇ。( Momonga Linux 4 OOo 2.4) -- はにゃ? 2008-05-30 (金) 22:33:59
  • 追記:クイック起動、若しくはIDE起動状態でないとうまく動かないですね。 -- ponkan 2008-05-30 (金) 22:41:30
  • ダイアログの execute で停止しないので、コードが終わってしまうんですよね。-headless での正しい動作ですね。エラーのあるコードを実行したらフリーズしましたけどね。 -- はにゃ? 2008-05-30 (Fri) 23:36:08

感想,コメント,メモ Edit



Reload   New Lower page making Edit Freeze Diff Upload Copy Rename   Front page List of pages Search Recent changes Backup   Help   RSS of recent changes