LibreOffice5(76)FilePickerのフィルターを作成: 失敗

2017-08-28

旧ブログ

t f B! P L
FilePickerのフィルターで「画像ファイルだけ」とか「Calcで開けるファイルだけ」とか一括してフィルターを指定したいのですが、そういう方法は用意されていないようです。LibreOffice5(68)画像フィルターリストの作成で画像フィルター一覧を作成しましたが、他のファイルについてもフィルター一覧を作成することにしました。結論としてはうまく活用できるものは作成できませんでした。

前の関連記事:LibreOffice5(75)thePathSettingsシングルトンで既定のパスを取得


フィルターのAPI NameはFilePickerのフィルターには使えない


(2017.11.12追記。この記事では「ファイルフィルター」と「表示フィルター」を混同しています。ここでいう「Filepickerのフィルター」とは「表示フィルター」のことです。LibreOffice5(93)ファイルフィルターのダイアログ(UIComponent)の一覧を取得参照。)

SDKのsdk/examples/DevelopersGuide/GUIフォルダにはLibreOffice 5.3 SDK - Developer's Guide Examplesには載っていませんが、FilePickerを使った例SystemDialog.javaが含まれています。

LibreOffice5(54)Javaの例:GUIを実行するでやったようにSystemDialog.javaはコンパイルしても動きませんが、SDKの例のなかで唯一FilePickerサービスを使っています。
            xFilterManager.appendFilter("OpenDocument Text Template", "writer8_template");
            xFilterManager.appendFilter("OpenDocument Text", "writer8");
appendFilterの引数をみるとファイルの選別に拡張子ではなく、Framework/Article/Filter/FilterList OOo 3 0 - Apache OpenOffice WikiにでてくるAPI Nameを使っています。

ところがこのフィルターではodsファイルもodtファイルも、htmlもxmlもjavaもどのファイルも選択できませんでした。
def macro():
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。
 doc = XSCRIPTCONTEXT.getDocument()
 if not doc.supportsService("com.sun.star.text.TextDocument"):  # Writerドキュメントに結果を出力するのでWriterドキュメントであることを確認する。
  raise RuntimeError("Please execute this macro with a Writer document.")
 configurationprovider = smgr.createInstanceWithContext("com.sun.star.configuration.ConfigurationProvider", ctx)  # ConfigurationProviderの取得。
 configreader = createConfigReader(configurationprovider)  # 読み込み専用の関数を取得。
 root = configreader("/org.openoffice.Office.UI/FilterClassification/GlobalFilters/Classes")  # org.openoffice.TypeDetectionパンケージのTypesコンポーネントのTypesノードを根ノードにする。
 props = "DisplayName", "Filters"  # 取得するプロパティ名のタプル。
 filters = {}  # フィルターの辞書。UINameをキー、拡張子のタプルを値とする。
 for childname in root.getElementNames():  # 子ノードの名前のタプルを取得。ノードオブジェクトの直接取得はできない模様。
  node = root.getByName(childname)  # ノードオブジェクトを取得。
  displayname, globalfilters = node.getPropertyValues(props)  # propの値を取得。displaynameは翻訳語のものが返ってくる。
  filters[displayname] = globalfilters
 print(filters)  # フィルターの辞書を出力。オートメーションのときのみ。
 doc.getText().setString(str(filters))  # Writerドキュメントに出力。    
 root.dispose()  # ConfigurationAccessサービスのインスタンスを破棄。
def createConfigReader(cp):  # ConfigurationProviderサービスのインスタンスを受け取る高階関数。
 def getRoot(path):  # ConfigurationAccessサービスのインスタンスを返す関数。
  node = PropertyValue(Name="nodepath", Value=path)
  return cp.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", (node,))
 return getRoot
g_exportedScripts = macro, #マクロセレクターに限定表示させる関数をタプルで指定。
このマクロを使って/opt/libreoffice5.2/share/registryにあるxcdファイルからAPI Nameを抽出しました。

{'プレゼンテーション': ('Impress MS PowerPoint 2007 XML', 'Impress MS PowerPoint 2007 XML AutoPlay', 'Impress MS PowerPoint 2007 XML Template', 'impress_StarOffice_XML_Draw', 'impress_StarOffice_XML_Impress_Template', 'impress8', 'impress8_template', 'MS PowerPoint 97', 'MS PowerPoint 97 AutoPlay', 'MS PowerPoint 97 Vorlage', 'OpenDocument Presentation Flat XML'), '文書ドキュメント': ('AportisDoc Palm DB', 'HTML (StarWriter)', 'LotusWordPro', 'MS Word 2003 XML', 'MS Word 2007 XML', 'MS Word 2007 XML Template', 'MS Word 97', 'MS Word 97 Vorlage', 'MS_Works', 'Office Open XML Text', 'Office Open XML Text Template', 'OpenDocument Text Flat XML', 'PocketWord File', 'Rich Text Format', 'StarOffice XML (Writer)', 'Text', 'WordPerfect', 'WordPerfect', 'writer_MIZI_Hwp_97', 'writer_StarOffice_XML_Writer_Template', 'writer8', 'writer8_template', 'writerglobal8', 'writerweb8_writer_template'), '数式': ('MathML XML (Math)', 'MathType 3.x', 'StarOffice XML (Math)', 'math8'), '図形描画': ('draw_StarOffice_XML_Draw_Template', 'StarOffice XML (Draw)', 'draw8', 'draw8_template', 'Visio Document', 'SVG - Scalable Vector Graphics', 'Corel Draw Document', 'Publisher Document'), 'データベースドキュメント': ('StarOffice XML (Base)',), '表計算ドキュメント': ('Calc MS Excel 2007 Binary', 'Calc MS Excel 2007 XML', 'Calc MS Excel 2007 XML Template', 'calc_StarOffice_XML_Calc_Template', 'calc8', 'calc8_template', 'chart8', 'DIF', 'Lotus', 'MiniCalc (Palm)', 'MS Excel 2003 XML', 'MS Excel 97', 'MS Excel 97 Vorlage/Template', 'OpenDocument Spreadsheet Flat XML', 'Pocket Excel', 'Quattro Pro 6.0', 'StarOffice XML (Calc)', 'StarOffice XML (Chart)', 'Text - txt - csv (StarCalc)'), 'マスタードキュメント': ('writer_globaldocument_StarOffice_XML_Writer_GlobalDocument', 'writerglobal8'), 'Webページ': ('HTML', 'writer_web_StarOffice_XML_Writer_Web_Template', 'writerweb8_writer_template')}

想定外のことにDisplayNameは翻訳したものが返ってきています。

これらのフィルターで選択できたファイルはhtmlファイルだけでした。

ということでフィルターのファイルの選別はやはり拡張子を使った方法しかダメなようです。

xcdファイルから拡張子一覧を抽出する方法を考える


画像ファイルだけ」とか「Calcで開けるファイルだけ」とか一括してフィルターを指定しする方法をみつけることはできなかったので、とりあえずLibreOffice5(68)画像フィルターリストの作成のときと同様にして拡張子を抽出することにしました。

/opt/libreoffice5.2/share/registryにあるxcdファイルを眺めてみるとファイルの拡張子はpropの「oor:name="Extensions"」の値になっていることがわかりました。

ということで使えるかどうかわかりませんが、とりあえず各xcdファイルから拡張子の一覧を抜き出すマクロを作成することにしました。

ConfigurationProviderサービスを使うのでまず走査するノード名を調べます。

「oor:name="Extensions"」を含むファイルを/opt/libreoffice5.2/share/registryから検索しました。


これらのファイルから「oor:name="Extensions"」を定義しているコンポーネントデータを調べました。

ファイル名: base.xcd
ルート: org.openoffice.TypeDetection.Types/Types

ファイル名: calc.xcd
ルート: org.openoffice.TypeDetection.Types/Types

ファイル名: draw.xcd
ルート: org.openoffice.TypeDetection.Types/Types

ファイル名: graphicfilter.xcd
ルート:  org.openoffice.TypeDetection.Types/Types

ファイル名: main.xcd
ルート:  org.openoffice.TypeDetection.Types/Types

ここまで探してすべてのルートが同じと悟りました、、、

ということで/org.openoffice.TypeDetection.Types/Typesをルートにして、その下のノードからUIName、Extensions、MediaTypeの3つのpropを取得することにしました。

xcdファイルからTypesノードの拡張子を抽出


GUI/getextensionsfilters.py at 7e536193e0cfab42cf128f9db289e950477fba0e · p--q/GUI
def macro():
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。
 doc = XSCRIPTCONTEXT.getDocument()  # ドキュメントモデルを取得。
 if not doc.supportsService("com.sun.star.sheet.SpreadsheetDocument"):  # Calcドキュメントに結果を出力するのでCalcドキュメントであることを確認する。
  raise RuntimeError("Please execute this macro with a Calc document.")
 sheets = doc.getSheets()  # シート列を取得。
 sheet = sheets[0]  # 最初のシートを取得。 
 if sheet.queryContentCells(VALUE+DATETIME+STRING):  # シートにデータがあるとき
  docframe = doc.getCurrentController().getFrame()  # モデル→コントローラ→フレーム、でドキュメントのフレームを取得。
  docwindow = docframe.getContainerWindow()  # ドキュメントのウィンドウ(コンテナウィンドウ=ピア)を取得。
  toolkit = docwindow.getToolkit()  # ピアからツールキットを取得。 
  msgbox = toolkit.createMessageBox(docwindow, QUERYBOX, BUTTONS_OK_CANCEL, "Overwrite", 'The data already exists in "{}".\nDo you want to replace it?'.format(sheet.Name))
  if msgbox.execute()==MessageBoxResults_CANCEL:  # メッセージボックスを表示してキャンセルボタンがクリックされたとき。
   sys.exit()  # 終了する。
  msgbox.dispose()  # メッセージボックスを破棄。
 sheet.clearContents(VALUE+DATETIME+STRING+ANNOTATION+FORMULA+HARDATTR)  # シートの全内容をクリア。 
 configreader = createConfigReader(ctx, smgr)  # 読み込み専用の関数を取得。
 root = configreader("/org.openoffice.TypeDetection.Types/Types")  # org.openoffice.TypeDetectionパンケージのTypesコンポーネントのTypesノードを根ノードにする。
 props = "UIName", "Extensions", "MediaType"  # 取得するプロパティ名のタプル。
 filters = []  # フィルターのタプル。
 for childname in root.getElementNames():  # 子ノードの名前のタプルを取得。ノードオブジェクトの直接取得はできない模様。
  uiname, extensions, mediatype = root.getByName(childname).getPropertyValues(props)  # extentionsはタプルで返ってくる。
  extensions = "*.{}".format(";*.".join(extensions))
  filters.append((uiname, extensions, mediatype))
 r = len(filters)
 c = len(filters[0])
 cellrange = sheet[:r,:c]  # 代入するセルの範囲を指定する。
 cellrange.setDataArray(filters)
 cellrange.getColumns().OptimalWidth = True  # セルの幅を最適化する。実行時に入っているデータに合わせる。
 root.dispose() # ConfigurationAccessサービスのインスタンスを破棄。
関数createConfigReader()は最初のマクロのものと同じです。
(2017.9.2追記。ConfigurationProviderのインスタンス化はcreateConfigReader()の中でやるように変更しました。)

if __name__ == "__main__"以降のオートメーションで起動する部分はLibreOffice5(69)Javaの例:GUIをPythonにする その2をCalcのドキュメントでも開くように変えたものです。

シートを上書きするかを確認するメッセージボックスを表示させるコードを追加して、OKボタンがクリックされたときはシートの内容をクリアしています。

このマクロでCalcファイルに167種類のUIName、Extensions、MediaTypeを取得出来ました。

https://docs.google.com/spreadsheets/d/e/2PACX-1vT_ha-Yg3qDMW6lDZmSpzoVRyc1VjA7j2rH_I-2RWjYW8knvrKVP82wtSzTVbsDapOi2lWBpbzwLFoL/pubhtml?gid=0&single=true

作成したものの私には活用方法は思いつきませんが、、、

次の関連記事:LibreOffice5(77)FilePickerのTemplateDescriptionを実行してみる

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ