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を見つけて、その図形を選択する。