// 下階層用テンプレート #topicpath ---- #contents **ここまでで [#j466e50d] //ここにコンテンツを記述します。 [[Eclipse/プラグイン開発のTIPS集/org.eclipse.core.runtime.IAdaptable(cont.)]]まで数回、IAdaptableについて学んできました。最後に org.eclipse.core.runtime.IAdaptable インタフェース org.eclipse.core.runtime.PlatformObject オブジェクト org.eclipse.core.runtime.IAdapterFactory ファクトリ の機構のまとめとその応用をまとめたいと思います。 [[Viewerへのモデルオブジェクトの表示>Eclipse/プラグイン開発のTIPS集/org.eclipse.core.runtime.IAdaptable#r6a0a2c1]]で、PlatformObjectを用いた方法を示しました。さらにモデルオブジェクトがPlatformObjectでないモデル群に対して、[[動的にgetAdapterする拡張ポイントの仕組み>Eclipse/プラグイン開発のTIPS集/org.eclipse.core.runtime.IAdaptable(cont.)]]の学習をしました。 次の題材は[[Eclipse/プラグイン開発のTIPS集/プロパティシートを使う]]でやったモデルオブジェクトのプロパティビューへの表示をやりたいと思います。 このプロパティビューへの表示ですが、一般的には -モデルのオブジェクトがIPropertySourceを実装していること -モデルのオブジェクトがIAdaptableを実装していて、IPropertySourceを返すこと を要求されています。が、これって動的にやることでモデルオブジェクトにEclipseの型を導入しなくてもいけるんでないの?というところを確認したいと思います。 **プロパティビューのまとめ [#a415cb53] 詳細は[[Eclipse/プラグイン開発のTIPS集/プロパティシートを使う]]に記載しましたが、いわゆるビュー(ViewPartのサブクラス)で、 public Object getAdapter(Class adapter) { if (adapter.equals(IPropertySheetPage.class)) { return new PropertySheetPage(); } return super.getAdapter(adapter); } とOverrideしておくと、ビュー内のモデルとなるオブジェクトを選択するとプロパティビューが反応して、プロパティビューに値が表示される仕組みです。 PropertySheetクラス(まさにプロパティビュー)は public void init(IViewSite site) throws PartInitException { site.getPage().addSelectionListener(this); super.init(site); } と初期化時にpageにaddSelectionListenerされ、 public void dispose() { // run super. super.dispose(); // remove ourselves as a selection listener getSite().getPage().removeSelectionListener(this); } とdispose時にpageからremoveSelectionListenerされてます。このようにして、ビュー内の選択を検知しています。 さてあるビューでモデルオブジェクトを選択したときに、モデルオブジェクトから値をとりだしてプロパティビューに値がセットされますが、この処理はPropertySheetEntryというクラスの protected IPropertySource getPropertySource(Object object); というメソッドが行っています。何とかしてIPropertySourceを返す、そんなメソッドです。 具体的には ↓ViewPart(id: org.eclipse.ui.views.PropertySheet まさにプロパティビュー) PropertySheet#selectionChanged -> PropertySheetPage#selectionChanged -> PropertySheetViewer#setInput -> PropertySheetEntry#setValues -> PropertySheetEntry#getPropertySource <-このメソッドの返り値がIPropertySource という流れ。なげー。((ちなみにPropertySheetはISelectionListenerを実装しています)) このメソッドでIPropertySourceを取得し、プロパティビューへの描画が行われます。 **プロパティビューの処理の詳細 [#edc2ceff] ***なぜモデルがIAdaptableだったりIPropertySourceを実装しないといけないのか [#xcb0142f] さて、 モデルオブジェクトはIAdaptableだったりIPropertySourceを実装することが必要だったわけですが、実はこのPropertySheetEntry#getPropertySourceメソッドで protected IPropertySource getPropertySource(Object object) { if (sources.containsKey(object)) return (IPropertySource) sources.get(object); IPropertySource result = null; if (propertySourceProvider != null) result = propertySourceProvider.getPropertySource(object); else if (object instanceof IPropertySource) result = (IPropertySource) object; else if (object instanceof IAdaptable) result = (IPropertySource) ((IAdaptable) object) .getAdapter(IPropertySource.class); sources.put(object, result); return result; } などとやってるからなんですね。モデル(objectインスタンス)からデータを取り出すときに、モデルがIPropertySourceだったらそのまま返す、もしくはモデルがIAdaptableの場合はgetAdapter(IPropertySource.class);して返す、などなどして、IPropertySourceインスタンスを取得しています。 ***IAdaptableでもIPropertySourceでもないモデルに対しては [#z94d8e3b] さて今回の目的は、IAdaptableでもIPropertySourceでもないモデルオブジェクトをビューにセットして、プロパティビューを反応させることでした。残る道は先のメソッドの IPropertySource result = null; if (propertySourceProvider != null) result = propertySourceProvider.getPropertySource(object); ですね。 ではこのpropertySourceProviderのセンで調べてみます。Eclipseのソースを見てるとどうやら、ビューのgetAdapterで何気なしに返していた、org.eclipse.ui.views.properties.PropertySheetPage の public void setPropertySourceProvider(IPropertySourceProvider newProvider); でこのpropertySourceProviderを設定できそうです。これを呼ぶと巡り巡ってPropertySheetEntryクラスのフィールドpropertySourceProviderにnewProviderがセットされます。つまりビューのgetAdapterでreturn new PropertySheetPage();しているところで、このセッタメソッドsetPropertySourceProvider()を呼んで、IPropertySourceProviderのインスタンスをPropertySheetEntryにセットすれば良さそうです。 **で、IAdaptableの話 [#y1ae2f56] ここまでで、ビューのgetAdapterメソッドを public Object getAdapter(Class adapter) { if (adapter.equals(IPropertySheetPage.class)) { // return new PropertySheetPage(); PropertySheetPage page = new PropertySheetPage(); page.setPropertySourceProvider(hogehoge); return page; } return super.getAdapter(adapter); } などと実装すれば、モデルオブジェクトをIAdaptableやIPropertySourceにしなくともhogehogeというIPropertySourceProviderからIPropertySourceを取得してくれそう、というところまでわかりました。 ここでようやく、IAdaptableをいろいろ調べてた苦労が実りそうです。 public Object getAdapter(Class adapter) { if (adapter.equals(IPropertySheetPage.class)) { // return new PropertySheetPage(); PropertySheetPage page = new PropertySheetPage(); page.setPropertySourceProvider(new IPropertySourceProvider() { public IPropertySource getPropertySource(Object object) { if (object instanceof Model) { Model model = (Model) object; IPropertySource adapter = (IPropertySource) Platform .getAdapterManager().loadAdapter(model, IPropertySource.class.getName()); ↑ ModelのインスタンスmodelとIPropertySource.class ↑ の組み合わせでオブジェクトをローディング ↑ adapterの拡張ポイントで登録が必要。 return adapter; } return null; } }); return page; } return super.getAdapter(adapter); } このように実装し((ここではModel型かどうかとかやってますが、本当はModelかどうかなんて意識する必要なしですね。拡張ポイントでクラスとファクトリがペアで登録されるし、ファクトリ内でちゃんと型チェックを行えば、ここはさらにポータブルにできる。というかそうした方がよいと思う。))、さらにorg.eclipse.core.runtime.adapters 拡張ポイントとIAdapterFactoryの実装クラスを定義しておきます。 ***拡張ポイント [#l9655303] <extension point="org.eclipse.core.runtime.adapters"> <factory adaptableType="nu.mine.kino.plugin.samples.model.Model" class="nu.mine.kino.plugin.samples.model.PropertySourceAdapterFactory"> <adapter type="org.eclipse.ui.views.properties.IPropertySource"/> </factory> </extension> ***IAdapterFactoryの実装クラス [#i39ffccf] public class PropertySourceAdapterFactory implements IAdapterFactory { private static final Class[] Types = new Class[] { IPropertySource.class }; public Object getAdapter(Object adaptableObject, Class adapterType) { if (adapterType == Types[0] && adaptableObject instanceof Model) { final Model model = (Model) adaptableObject; IPropertySource source = new IPropertySource() { public IPropertyDescriptor[] getPropertyDescriptors() { IPropertyDescriptor[] descriptor = new IPropertyDescriptor[] { new TextPropertyDescriptor("id", "コード"), new TextPropertyDescriptor("name", "名前"), new TextPropertyDescriptor("mail", "メール") }; return descriptor; } public Object getPropertyValue(Object id) { if (id.equals("id")) { return model.getId(); } if (id.equals("name")) { return model.getName(); } if (id.equals("mail")) { return model.getMail(); } return null; } public boolean isPropertySet(Object id) {return false;} public void resetPropertyValue(Object id) {} public void setPropertyValue(Object id, Object value) {} public Object getEditableValue() {return null;} }; return source; } return null; } public Class[] getAdapterList() { return Types; } } 以上で完成です。ビュー上で、モデルオブジェクトを選択すると、プロパティビューが反応して、値を表示してくれることがわかります。モデルオブジェクトは[[プロパティシートを使う>Eclipse/プラグイン開発のTIPS集/プロパティシートを使う#cd2098e7]]で使用したModelクラスです。これはIAdaptableでもないし、PlatformObjectを拡張もしていないいわゆるPOJOです。 #ref(pic02.png) **よくよく考えたら、この例ではこんなややこしいこと必要なしだった。。。 [#d9f8be71] 今回の場合はこんなややこしいこと必要なかったです。 public IPropertySource getPropertySource(Object object) { if (object instanceof Model) { Model model = (Model) object; IPropertySource adapter = (IPropertySource) Platform .getAdapterManager().loadAdapter(model, IPropertySource.class.getName()); ↑ ModelのインスタンスmodelとIPropertySource.class ↑ の組み合わせでオブジェクトをローディング ↑ adapterの拡張ポイントで登録が必要。 return adapter; } return null; } なんてことをやりましたが、ここは public IPropertySource getPropertySource(Object object) { if (object instanceof Model) { Model model = (Model) object; return new IPropertySourceImpl(model); } return null; } などとしておくだけで十分でした。IPropertySourceImplは適当に private class IPropertySourceImpl implements IPropertySource { private Model model; public IPropertySourceImpl(Model model) { this.model = model; } public IPropertyDescriptor[] getPropertyDescriptors() { IPropertyDescriptor[] descriptor = new IPropertyDescriptor[] { new TextPropertyDescriptor("id", "コード"), new TextPropertyDescriptor("name", "名前"), new TextPropertyDescriptor("mail", "メール") }; return descriptor; } public Object getPropertyValue(Object id) { if (id.equals("id")) { return model.getId(); } if (id.equals("name")) { return model.getName(); } if (id.equals("mail")) { return model.getMail(); } return null; } public boolean isPropertySet(Object id) {return false;} public void resetPropertyValue(Object id) {} public void setPropertyValue(Object id, Object value) {} public Object getEditableValue() {return null;} }; でOKです。これでorg.eclipse.core.runtime.adapters 拡張ポイントやIAdapterFactoryの実装クラスも必要なかったです。 。。。何やっってたんだー(´д`;)。。。。まあ、org.eclipse.core.runtime.adapters拡張ポイントの使い方もわかったし、まあよしとするか。。 ---- この記事は #vote(おもしろかった[9],そうでもない[0]) #comment #topicpath SIZE(10){現在のアクセス:&counter;}