LibreOffice5(98)Javaの例:Universal Content Broker (UCB)をPythonにする:その1

2017-11-27

旧ブログ

t f B! P L
ストリームについて理解の足しになると思ってLibreOffice 6.0 SDK - Developer's Guide ExamplesのUCBのJavaの例をPythonにしました。まずはChildrenRetrieverをPythonにしました。

前の関連記事:LibreOffice5(97)SimpleFileAccess、TextOutputStream、TextInputStream、Pipeのサービスとインターフェイスの一覧


Javaの例:ChildrenRetrieverをPythonにする

import unohelper  # オートメーションには必須(必須なのはuno)。
from itertools import zip_longest
from com.sun.star.sheet import CellFlags as cf # 定数
from com.sun.star.beans import Property  # Struct
from com.sun.star.ucb import OpenCommandArgument2  # Struct
from com.sun.star.ucb import OpenMode  # 定数
from com.sun.star.ucb import Command  # Struct
def macro(documentevent=None):  # 引数は文書のイベント駆動用。 
 doc = XSCRIPTCONTEXT.getDocument() if documentevent is None else documentevent.Source  # ドキュメントのモデルを取得。 
 contenturl = "file:///"  # 子要素のプロパティを取得したい親要素のfileurl
 propnames = "Title", "IsDocument"  # 取得するプロパティのタプル。
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。
 ucb =  smgr.createInstanceWithContext("com.sun.star.ucb.UniversalContentBroker", ctx)  # UniversalContentBroker
 content = ucb.queryContent(ucb.createContentIdentifier(contenturl))  # fileurlを元にFile Contentsを取得。
 if content:  # File Contentsが取得できた時。
  props = [Property(Name=propname, Handle=-1) for propname in propnames]
  arg = OpenCommandArgument2(Mode=OpenMode.ALL, Priority=32768, Properties=props)
  command = Command(Name="open", Handle=-1, Argument=arg)  # NameとArgumentでexecute()の戻り値の型が決まる。
  dynamicresultset = content.execute(command, 0, None)  # XDynamicResultSet型が返る。
  resultset = dynamicresultset.getStaticResultSet()
  outputs = []
  flg = resultset.first()
  while flg:
   propsvalues = [resultset.queryContentIdentifierString()]
   for i in range(1, len(props)+1):
    propvalue = resultset.getObject(i, None)
    if isinstance(propvalue, bool):  # ブール型の時
     propvalue = str(propvalue)  # 文字列に変換する。シートに出力するため。
    elif propvalue is None:
     propvalue = "[ Property not found ]"
    propsvalues.append(propvalue)
   outputs.append(propsvalues)
   flg = resultset.next()
  sheet = getNewSheet(doc, "ChidrenRetriever")  # 新規シートの取得。 
  datarows = [("URL:", *["{}:".format(p) for p in propnames])]
  datarows.extend(outputs)
  rowsToSheet(sheet[2, 0], datarows)  # datarowsをシートに書き出し。代入範囲の列幅も最適化される。
  sheet[0, 0].setString("ChildrenRetriever - obtains the children of a folder resource")
  sheet[1, 0].setString("Children of resource {}".format(contenturl))  
  controller = doc.getCurrentController()  # コントローラの取得。
  controller.setActiveSheet(sheet)  # シートをアクティブにする。
def rowsToSheet(cellrange, datarows):  # 引数のセル範囲を左上端にして一括書き込みして列幅を最適化する。datarowsはタプルのタプル。
 datarows = tuple(zip(*zip_longest(*datarows, fillvalue="")))  # 一番長い行の長さに合わせて空文字を代入。
 sheet = cellrange.getSpreadsheet()  # セル範囲のあるシートを取得。
 cellcursor = sheet.createCursorByRange(cellrange)  # セル範囲のセルカーサーを取得。
 cellcursor.collapseToSize(len(datarows[0]), len(datarows))  # (列、行)で指定。セルカーサーの範囲をdatarowsに合せる。
 cellcursor.setDataArray(datarows)  # セルカーサーにdatarowsを代入。代入できるのは整数(int、ただしboolを除く)か文字列のみ。
 cellcursor.getColumns().setPropertyValue("OptimalWidth", True)  # セルカーサーのセル範囲の列幅を最適化する。行幅は限定サれない。  
def getNewSheet(doc, sheetname):  # docに名前sheetnameのシートを返す。sheetnameがすでにあれば連番名を使う。
 cellflags = cf.VALUE+cf.DATETIME+cf.STRING+cf.ANNOTATION+cf.FORMULA+cf.HARDATTR+cf.STYLES
 sheets = doc.getSheets()  # シートコレクションを取得。
 c = 1  # 連番名の最初の番号。
 newname = sheetname
 while newname in sheets: # 同名のシートがあるとき。sheets[newname]ではFalseのときKeyErrorになる。
  if not sheets[newname].queryContentCells(cellflags):  # シートが未使用のとき
   return sheets[newname]  # 未使用の同名シートを返す。
  newname = "{}{}".format(sheetname, c)  # 連番名を作成。
  c += 1 
 sheets.insertNewByName(newname, len(sheets))   # 新しいシートを挿入。同名のシートがあるとRuntimeExceptionがでる。
 if "Sheet1" in sheets:  # デフォルトシートがあるとき。
  if not sheets["Sheet1"].queryContentCells(cellflags):  # シートが未使用のとき
   del sheets["Sheet1"]  # シートを削除する。
 return sheets[newname]
g_exportedScripts = macro, #マクロセレクターに限定表示させる関数をタプルで指定。
結果はCalcに出力しています。

ChildrenRetriever.ods

このマクロを埋め込んだCalcドキュメントです。

linuxBeanで実行すると以下のような出力が得られました。

10行目でfileurlで指定しているフォルダの子要素のプロパティのTitleとIsDocumentの結果を取得して出力しています。


Windows10で実行すると次のようになりました。


LibreOffice 6.0 SDK - Developer's Guide Examplesの例はUCBの実装するための例のようで、実際に応用して使う機会はなさそうです、、、と思ったのですが、LibreOffice5(109)子要素にフォルダしか持たないドキュメント内フォルダでサブフォルダの要素まで再帰的に求めるマクロを作成しました。

UniversalContentBrokerのサービスとインターフェイスの一覧

def macro():
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。 
 tcu = smgr.createInstanceWithContext("pq.Tcu", ctx)  # サービス名か実装名でインスタンス化。
 ucb = smgr.createInstanceWithContext("com.sun.star.ucb.UniversalContentBroker", ctx)
 tcu.wtree(ucb)

├─.ucb.UniversalContentBroker
│   └─.ucb.XUniversalContentBroker
│     ├─.lang.XComponent
│     │     void  addEventListener( [in] .lang.XEventListener xListener)
│     │     void  dispose()
│     │     void  removeEventListener( [in] .lang.XEventListener aListener)
│     ├─.ucb.XCommandProcessor2
│     │   │   void  releaseCommandIdentifier( [in] long CommandId)
│     │   └─.ucb.XCommandProcessor
│     │        void  abort( [in] long CommandId)
│     │        long  createCommandIdentifier()
│     │         any  execute( [in]             .ucb.Command aCommand,
│     │                       [in]                     long CommandId,
│     │                       [in] .ucb.XCommandEnvironment Environment
│     │            ) raises ( .ucb.CommandAbortedException,
│     │                       .uno.Exception)
│     ├─.ucb.XContentIdentifierFactory
│     │     .ucb.XContentIdentifier  createContentIdentifier( [in] string ContentId)
│     ├─.ucb.XContentProvider
│     │              long  compareContentIds( [in] .ucb.XContentIdentifier Id1,
│     │                                       [in] .ucb.XContentIdentifier Id2)
│     │     .ucb.XContent  queryContent( [in] .ucb.XContentIdentifier Identifier
│     │                       ) raises ( .ucb.IllegalIdentifierException)
│     └─.ucb.XContentProviderManager
│                                 void  deregisterContentProvider( [in] .ucb.XContentProvider Provider,
│                                                                  [in]                string Scheme)
│                .ucb.XContentProvider  queryContentProvider( [in] string Identifier)
│           [.ucb.ContentProviderInfo]  queryContentProviders()
│                .ucb.XContentProvider  registerContentProvider( [in] .ucb.XContentProvider Provider,
│                                                                [in]                string Scheme,
│                                                                [in]               boolean ReplaceExisting
│                                                     ) raises ( .ucb.DuplicateProviderException)
└─.lang.XInitialization
     void  initialize( [in] [any] aArguments
            ) raises ( .uno.Exception)

参考にしたサイト


LibreOffice 6.0 SDK - Developer's Guide Examples
Javaの例:Universal Content Broker (UCB) examplesのChildrenRetrieverをPythonにしました。

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

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ