ここまでで †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へのモデルオブジェクトの表示で、PlatformObject?を用いた方法を示しました。さらにモデルオブジェクトがPlatformObject?でないモデル群に対して、動的にgetAdapterする拡張ポイントの仕組みの学習をしました。 次の題材はEclipse/プラグイン開発のTIPS集/プロパティシートを使うでやったモデルオブジェクトのプロパティビューへの表示をやりたいと思います。 このプロパティビューへの表示ですが、一般的には を要求されています。が、これって動的にやることでモデルオブジェクトにEclipseの型を導入しなくてもいけるんでないの?というところを確認したいと思います。 プロパティビューのまとめ †詳細は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 という流れ。なげー。*1 このメソッドでIPropertySource?を取得し、プロパティビューへの描画が行われます。 プロパティビューの処理の詳細 †なぜモデルがIAdaptableだったりIPropertySource?を実装しないといけないのか †さて、 モデルオブジェクトは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?でもないモデルに対しては †さて今回の目的は、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の話 †ここまでで、ビューの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);
}
このように実装し*2、さらにorg.eclipse.core.runtime.adapters 拡張ポイントとIAdapterFactory?の実装クラスを定義しておきます。 拡張ポイント †<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?の実装クラス †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;
}
}
以上で完成です。ビュー上で、モデルオブジェクトを選択すると、プロパティビューが反応して、値を表示してくれることがわかります。モデルオブジェクトはプロパティシートを使うで使用したModelクラスです。これはIAdaptableでもないし、PlatformObject?を拡張もしていないいわゆるPOJOです。 よくよく考えたら、この例ではこんなややこしいこと必要なしだった。。。 †今回の場合はこんなややこしいこと必要なかったです。 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拡張ポイントの使い方もわかったし、まあよしとするか。。 この記事は 現在のアクセス:12643 |