Eclipseのプラグイン開発のGEFでマーカーを扱う方法。
マーカー自身はGEFでなくEclipseの機能なので、GEFだと言ってもマーカー(エラーマーカー)を作る部分についてはあまり違いは無い。
ただし、問題ビューに表示されたマーカーをダブルクリックして該当箇所(図形)へジャンプする、という仕組みについては自分で作り込まないといけない。
(TextEditorであれば、行番号やファイルの先頭からのオフセットでエラー箇所を示すことが出来るが、GEFだと図形を扱うので、そういった汎用的な方法が無い)
TextEditorのマーカーであれば、エラー箇所はIMarker.LINE_NUMBERやCHAR_START/CHAR_ENDで指定する。
GEFでは図形を扱うので、これらの属性は使えない。
こういった場合の為にIMarker.SOURCE_IDがあるようなので、それを使う。
マーカーで図形を特定する為には、ModelクラスかEditPartクラスにIDを持たせ、それを指定するのが手っ取り早そう。
図形を選択する際にはEditPartを使うので、EditPartにIDを持たせておくと楽そうである。
ただしEclipseを再起動してもマーカーは消えないので、図形のIDも復元できないといけない。そういった永続データを持つのはModelの役割なので、ModelにIDを持たせる方が良さそうでもある。
しかし、EditPartからModelは取得できるが、ModelからEditPartを取得する方法は提供されていないので、ModelにIDを持たせる場合はModelからEditPartを探す部分を自分で作り込む必要があって、ちょっと面倒。
ここでは、各Modelが固有のIDを持っているという前提でマーカーを作ってみる。
import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.runtime.CoreException;
public void createMarker(IFile file, MyModel model, String message) throws CoreException { IMarker marker = file.createMarker(IMarker.PROBLEM); marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR); marker.setAttribute(IMarker.MESSAGE, message); marker.setAttribute(IMarker.LOCATION, model.getName()); marker.setAttribute(IMarker.SOURCE_ID, model.getId()); }
LOCATIONにはユーザーの目に見えるような「場所」を示す文字列を指定する。
SOURCE_IDにはGEFエディター内部で「場所(model)」を特定する文字列を指定する。
問題ビュー(Problem view)上に表示されているマーカーをダブルクリックして、そのマーカーが示す図形を選択する例。
TextEditorであればIGotoMarkerが実装されているので、マーカーをダブルクリックした際の処理がデフォルトで実装されている。
GEFのエディターにはそういった機能が無いので、自分で作る必要がある。
import org.eclipse.core.resources.IMarker; import org.eclipse.gef.EditPart; import org.eclipse.gef.EditPartViewer; import org.eclipse.ui.ide.IGotoMarker;
public class MyEditor extends GraphicalEditorWithFlyoutPalette implements IGotoMarker { 〜
@Override public void gotoMarker(IMarker marker) { String id = marker.getAttribute(IMarker.SOURCE_ID, null); if (id == null) { return; } EditPartViewer viewer = super.getGraphicalViewer(); EditPart editPart = viewer.getContents(); EditPart found = findById(editPart, id); if (found == null) { return; } // 見つかった図形を選択 viewer.select(found); viewer.reveal(found); }
private EditPart findById(EditPart editPart, String id) { MyModel model = (MyModel)editPart.getModel(); if (model.getId().equals(id)) { return editPart; } for (Object obj : editPart.getChildren()) { EditPart child = (EditPart)obj; EditPart found = findById(child, id); if (found != null) { return found; } } return null; }
@Override public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { 〜 if (adapter == IGotoMarker.class) { return this; } return super.getAdapter(adapter); } }
問題ビュー上のマーカーをダブルクリックすると、IGotoMarkerを探す為にエディターのgetAdapter()が呼ばれる。
そしてIGotoMarker#gotoMarker()が呼ばれる。
そこで、自分のエディターでIGotoMarkerを実装し、getAdapter()でIGotoMarkerのときに自分自身を返すようにする。
そしてIGotoMarkerのgotoMarker()を実装し、SOURCE_IDを元にEditPartを見つけて、その図形を選択する。