S-JIS[2013-10-29] 変更履歴

Eclipse GEF マーカー

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を持っているという前提でマーカーを作ってみる。

マーカーを作る処理.java:

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のエディターにはそういった機能が無いので、自分で作る必要がある。

MyEditor.java:

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


GEFへ戻る / Eclipseプラグインへ戻る / Eclipseへ戻る / 技術メモへ戻る
メールの送信先:ひしだま