LibreOffice5(53)Javaの例:ConfigExamplesをPythonにする その6

リスナーとなるXChangesListenerインターフェイスのchangesOccurred()メソッドの引数に渡されるChangesEvent Structについて調べます。さらにresetGroupExample()とresetGroupExample()をPythonに翻訳しようとしましたが、これらは無理でした。

前の関連記事:LibreOffice5(52)Javaの例:ConfigExamplesをPythonにする その5


changesOccurred()メソッドの引数ChangesEvent Struct


ConfigExamples/configexamples.py at b63b6c61f33476e21584bba267252035e8ef12b9 · p--q/ConfigExamples

XChangesListenerインターフェイスを継承しているこのChangesListenerクラスのchangesOccurred()メソッドの引数に入るものを調べます。

デバッガで調べたいところですが、PyDevではブレークできませんでした。

リスナーはLibreOfficeの中から呼ばれるからということでしょうか?

Java版ではブレークできるのですが、ちょっと変数の内容の意味がよくわかりません。
        base = event.Base
        print("Base: {}".format(base))  # Base
        print("Base.getName(): {}".format(base.getName()))
        print("Changes:")
        for c in event.Changes:
            print("Accessor: {}, Element: {}, ReplacedElement: {}".format(c.Accessor, c.Element, c.ReplacedElement))
        source = event.Source
        print("Source: {}".format(source)) 
        print("Source.getName(): {}".format(source.getName()))
Structはプロパティ名で値を取り出せるのでAPIリファレンスをたどりながらこのコードをchangesOccurred()メソッドの中で実行してすべて出力してみました。
Base: pyuno object (com.sun.star.uno.XInterface)0x9d3b0d4{implementationName=configmgr.RootAccess, supportedServices={com.sun.star.configuration.ConfigurationAccess,com.sun.star.configuration.ConfigurationUpdateAccess,com.sun.star.configuration.HierarchyAccess,com.sun.star.configuration.HierarchyElement,com.sun.star.configuration.GroupAccess,com.sun.star.configuration.PropertyHierarchy,com.sun.star.configuration.GroupUpdate,com.sun.star.configuration.AccessRootElement,com.sun.star.configuration.UpdateRootElement}, supportedInterfaces={com.sun.star.uno.XInterface,com.sun.star.uno.XWeak,com.sun.star.lang.XTypeProvider,com.sun.star.lang.XServiceInfo,com.sun.star.lang.XComponent,com.sun.star.container.XContainer,com.sun.star.beans.XExactName,com.sun.star.container.XHierarchicalName,com.sun.star.container.XNamed,com.sun.star.beans.XProperty,com.sun.star.container.XElementAccess,com.sun.star.container.XNameAccess,com.sun.star.beans.XPropertySetInfo,com.sun.star.beans.XPropertySet,com.sun.star.beans.XMultiPropertySet,com.sun.star.beans.XHierarchicalPropertySet,com.sun.star.beans.XMultiHierarchicalPropertySet,com.sun.star.beans.XHierarchicalPropertySetInfo,com.sun.star.container.XNameReplace,com.sun.star.container.XHierarchicalNameReplace,com.sun.star.util.XChangesNotifier,com.sun.star.util.XChangesBatch}}
Base.getName(): Grid
Changes:
Accessor: Subdivision/YAxis, Element: 9998, ReplacedElement: None
Accessor: Subdivision/XAxis, Element: 9998, ReplacedElement: None
Source: pyuno object (com.sun.star.uno.XInterface)0x9d3b0d4{implementationName=configmgr.RootAccess, supportedServices={com.sun.star.configuration.ConfigurationAccess,com.sun.star.configuration.ConfigurationUpdateAccess,com.sun.star.configuration.HierarchyAccess,com.sun.star.configuration.HierarchyElement,com.sun.star.configuration.GroupAccess,com.sun.star.configuration.PropertyHierarchy,com.sun.star.configuration.GroupUpdate,com.sun.star.configuration.AccessRootElement,com.sun.star.configuration.UpdateRootElement}, supportedInterfaces={com.sun.star.uno.XInterface,com.sun.star.uno.XWeak,com.sun.star.lang.XTypeProvider,com.sun.star.lang.XServiceInfo,com.sun.star.lang.XComponent,com.sun.star.container.XContainer,com.sun.star.beans.XExactName,com.sun.star.container.XHierarchicalName,com.sun.star.container.XNamed,com.sun.star.beans.XProperty,com.sun.star.container.XElementAccess,com.sun.star.container.XNameAccess,com.sun.star.beans.XPropertySetInfo,com.sun.star.beans.XPropertySet,com.sun.star.beans.XMultiPropertySet,com.sun.star.beans.XHierarchicalPropertySet,com.sun.star.beans.XMultiHierarchicalPropertySet,com.sun.star.beans.XHierarchicalPropertySetInfo,com.sun.star.container.XNameReplace,com.sun.star.container.XHierarchicalNameReplace,com.sun.star.util.XChangesNotifier,com.sun.star.util.XChangesBatch}}
Source.getName(): Grid

Base: pyuno object (com.sun.star.uno.XInterface)0x9d3b0d4{implementationName=configmgr.RootAccess, supportedServices={com.sun.star.configuration.ConfigurationAccess,com.sun.star.configuration.ConfigurationUpdateAccess,com.sun.star.configuration.HierarchyAccess,com.sun.star.configuration.HierarchyElement,com.sun.star.configuration.GroupAccess,com.sun.star.configuration.PropertyHierarchy,com.sun.star.configuration.GroupUpdate,com.sun.star.configuration.AccessRootElement,com.sun.star.configuration.UpdateRootElement}, supportedInterfaces={com.sun.star.uno.XInterface,com.sun.star.uno.XWeak,com.sun.star.lang.XTypeProvider,com.sun.star.lang.XServiceInfo,com.sun.star.lang.XComponent,com.sun.star.container.XContainer,com.sun.star.beans.XExactName,com.sun.star.container.XHierarchicalName,com.sun.star.container.XNamed,com.sun.star.beans.XProperty,com.sun.star.container.XElementAccess,com.sun.star.container.XNameAccess,com.sun.star.beans.XPropertySetInfo,com.sun.star.beans.XPropertySet,com.sun.star.beans.XMultiPropertySet,com.sun.star.beans.XHierarchicalPropertySet,com.sun.star.beans.XMultiHierarchicalPropertySet,com.sun.star.beans.XHierarchicalPropertySetInfo,com.sun.star.container.XNameReplace,com.sun.star.container.XHierarchicalNameReplace,com.sun.star.util.XChangesNotifier,com.sun.star.util.XChangesBatch}}
Base.getName(): Grid
Changes:
Accessor: Option/VisibleGrid, Element: True, ReplacedElement: None
Source: pyuno object (com.sun.star.uno.XInterface)0x9d3b0d4{implementationName=configmgr.RootAccess, supportedServices={com.sun.star.configuration.ConfigurationAccess,com.sun.star.configuration.ConfigurationUpdateAccess,com.sun.star.configuration.HierarchyAccess,com.sun.star.configuration.HierarchyElement,com.sun.star.configuration.GroupAccess,com.sun.star.configuration.PropertyHierarchy,com.sun.star.configuration.GroupUpdate,com.sun.star.configuration.AccessRootElement,com.sun.star.configuration.UpdateRootElement}, supportedInterfaces={com.sun.star.uno.XInterface,com.sun.star.uno.XWeak,com.sun.star.lang.XTypeProvider,com.sun.star.lang.XServiceInfo,com.sun.star.lang.XComponent,com.sun.star.container.XContainer,com.sun.star.beans.XExactName,com.sun.star.container.XHierarchicalName,com.sun.star.container.XNamed,com.sun.star.beans.XProperty,com.sun.star.container.XElementAccess,com.sun.star.container.XNameAccess,com.sun.star.beans.XPropertySetInfo,com.sun.star.beans.XPropertySet,com.sun.star.beans.XMultiPropertySet,com.sun.star.beans.XHierarchicalPropertySet,com.sun.star.beans.XMultiHierarchicalPropertySet,com.sun.star.beans.XHierarchicalPropertySetInfo,com.sun.star.container.XNameReplace,com.sun.star.container.XHierarchicalNameReplace,com.sun.star.util.XChangesNotifier,com.sun.star.util.XChangesBatch}}
Source.getName(): Grid
リスナーは2回呼ばれているので2回出力が得られます。

BaseとSourceには同じConfigurationUpdateAccessサービスのインスタンスが入っていました。

Changesには変更点の情報が入っています。

Accessorには変更した値までの相対パス、Elementには変更後の値が入っていますが、変更前の値は入ってませんでした。

disposing()メソッドの引数はchangesOccurred()メソッドと違ってSourceだけでした。

resetGroupExample()とresetGroupExample()は動かない


resetGroupExample()では変更した値をデフォルト値に戻してます。

しかしLibreOffice5(48)Javaの例:ConfigExamplesをPythonにする その1の最初にみたようにJavaの例でもエラーがでて動きません。

Pythonでやってみても同じことでsetPropertyToDefault()メソッドがない、と言われます。

Updating Configuration Data - Apache OpenOffice Wiki
にはグループノードには現在のところsetPropertyToDefault()メソッドには対応していないと書いてあります。

 LibreOffice5(52)Javaの例:ConfigExamplesをPythonにする その5で調べたcom.sun.star.configuration.ConfigurationUpdateAccessのメソッド一覧にはsetPropertyToDefault()メソッドが出ています。

でもPyDevのデバッガでみるとインスタンスには setPropertyToDefault()メソッドはでてきません。

subject:"configuration provider doesn't implement setPropertyToDefault anymore"

これにも書いてあるように setPropertyToDefault()は今のところ実装されていないようです。

このほかDefaultという名前がつくメソッドは一つも実装されていませんでした。

ということで resetGroupExample()は動きません。

updateSetExample()もまたデータ構造の変更があったので現行のLibreOfficeでは動きません。

ConfigurationUpdateAccessの置換可能なメソッド


XNameReplaceインターフェイスのreplaceByName()メソッドをXPropertySetインターフェイスのsetPropertyValue()メソッドに置き換えても同じ結果が得られました。

XNameAccessインターフェイスのgetByName()メソッドはXPropertySetインターフェイスのgetPropertyValue()メソッドに置換できました。

どのメソッドに置換可能かはLibreOffice5(52)Javaの例:ConfigExamplesをPythonにする その5で出力したConfigurationUpdateAccessのメソッド一覧で戻り値の型が同じもののなかで同じ働きをしそうな名前であたりをつけました。

XHierarchicalPropertySetインターフェイスのsetHierarchicalPropertyValue()メソッドはXHierarchicalNameReplaceインターフェイスのreplaceByHierarchicalName()メソッドに置換できました。

XHierarchicalPropertySetインターフェイスのgetHierarchicalPropertyValue()メソッドはXHierarchicalNameAccessインターフェイスのgetByHierarchicalName()メソッドに置換可能でした。

置換しても動くことは確認できましたが、どっちを使った方がよいのかはよくわかりません。

ConfigExamplesではXPropertySetインターフェイスではない方のメソッドと、XHierarchicalPropertySetインターフェイスのメソッドを使っています。

XChangesListenerインターフェイスのchangesOccurred()メソッドが呼ばれるタイミング


ConfigurationUpdateAccessサービスのインスタンスの値を変更したときは、そのcommitChanges()メソッドを実行したときにchangesOccurred()メソッドが呼ばれます。

ところがこのインスタンスからgetByName()メソッドで得たサブノードに対して値を変更したときは値を変更した時点でchangesOccurred()メソッドが呼ばれます。

 setHierarchicalPropertyValue()やreplaceByHierarchicalName()でも逐一changesOccurred()が呼ばれます。

変更した値の保存はcommitChanges()メソッドを実行しないといけません。
    def changeSomeData(self, root):
        try:          
            itemnames = root.getElementNames()
            for itemname in itemnames:
                item = root.getByName(itemname)  # getPropertyValue()メソッドで置換可能。
                if isinstance(item, bool):
                    print("Replacing boolean value: {}".format(itemname))
                    root.replaceByName(itemname, False if item else True)  # setPropertyValue()メソッドで置換可能。
                elif isinstance(item, int):
                    item = 9999-item
                    print("Replacing integer value: {}".format(itemname))
                    root.replaceByName(itemname, item)  # setPropertyValue()メソッドで置換可能。
            root.commitChanges()  # この実行後にXChangesListenerが呼び出される。
            root.dispose()
        except:
            print("Could not change some data in a different view. An exception occurred:")
            traceback.print_exc()     
このchangeSomeData()メソッドは引数のrootでConfigurationUpdateAccessサービスのインスタンスを受け取ってその値を2つ変更したあとにrootのcommitChanges()を呼び出しています。

これを実行すると以下のような結果が出力されます。
Grid options editor: data=[ Grid is VISIBLE; resolution = (1000,1000); subdivision = (9998,9998) ]
Replacing integer value: XAxis
Replacing integer value: YAxis
GridEditor - Listener received changes event containing 2 change(s).
これに対してrootをその上のノードからサブノードとして取得して同じコードを実行します。
    def changeSomeData(self, root):
        try:       
            root = self.model.getByName("Subdivision")
            itemnames = root.getElementNames()
            for itemname in itemnames:
                item = root.getByName(itemname)
                if isinstance(item, bool):
                    print("Replacing boolean value: {}".format(itemname))
                    root.replaceByName(itemname, False if item else True)
                elif isinstance(item, int):
                    item = 9999-item
                    print("Replacing integer value: {}".format(itemname))
                    root.replaceByName(itemname, item)    
#             self.model.commitChanges()
#             self.model.dispose()
        except:
            print("Could not change some data in a different view. An exception occurred:")
            traceback.print_exc()      
3行目でrootをConfigurationUpdateAccessサービスのインスタンスのサブノードに置換しています。
Grid options editor: data=[ Grid is HIDDEN; resolution = (1000,1000); subdivision = (1,1) ]
Replacing integer value: XAxis
GridEditor - Listener received changes event containing 1 change(s).
Grid options editor: data=[ Grid is HIDDEN; resolution = (1000,1000); subdivision = (9998,1) ]
Replacing integer value: YAxis
GridEditor - Listener received changes event containing 1 change(s).
commitChanges()を呼び出す前にchangesOccurred()が逐一呼ばれていることがわかります。

14行目のcommitChanges()をコメントアウトしていますが、プログラムが終わるまでにcommitChanges()を実行すれば変更した値が保存されます。

15行目でdispose()を実行してしまうともうこのインスタンスは使えません。

ConfigurationUpdateAccessサービスのインスタンスとそのサブノードのインスタンスの違い


とりあえずPyDevのデバッガで表示される値をみて気が付いたことを記録しておきます。

まず実装名が異なります。

ConfigurationUpdateAccessサービスのインスタンスの実装名はconfigmgr.RootAccessなのに対して、そのサブノードの実装名はorg.openoffice-configmgr::Accessになっていました。

ちなみにConfigurationProviderのcreateInstanceWithArguments()メソッドではこの実装名でインスタンス化することはできませんでした。

configmgr.RootAccessはPendingChangesプロパティをもっていてそのタプルにcommitChanges()する前の変更点がcom.sun.star.util.ElementChangeのstructの要素が入っています。

それに対してorg.openoffice-configmgr::AccessはPendingChangesプロパティがありません。

p--q/ConfigExamples

これでConfigExamplesをPythonに翻訳するのは完了です。

参考にしたサイト


Updating Configuration Data - Apache OpenOffice Wiki
グループノードには現在のところsetPropertyToDefault()メソッドには対応していないそうです。

subject:"configuration provider doesn't implement setPropertyToDefault anymore"
setPropertyToDefault()メソッドが実装されていない話題。

次の関連記事:LibreOffice5(54)Javaの例:GUIを実行する

PR

0 件のコメント:

コメントを投稿