S-JIS[2013-03-09/2013-12-29] 変更履歴

Eclipse GEF Palette

Eclipseプラグイン開発GEFのパレットについて。


概要

パレットは図形の一覧(メニュー)で、そこから図形を選択してエディター上に図形を置くことが出来るようにするもの。

パレットを使う場合は、GraphicalEditorとしてGraphicalEditorWithPaletteあるいはGraphicalEditorWithFlyoutPaletteを使用する。


パレットに図形の選択肢を表示しておき、そこからエディター上に図形を生成する例。

GraphicalEditorクラス:

import org.eclipse.gef.palette.CreationToolEntry;
import org.eclipse.gef.palette.PaletteDrawer;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.requests.SimpleFactory;
public class MyEditor extends GraphicalEditorWithFlyoutPalette {
〜
	@Override
	protected PaletteRoot getPaletteRoot() {
		PaletteRoot root = new PaletteRoot();

		PaletteDrawer drawer = new PaletteDrawer("描画ツール");
		drawer.add(new CreationToolEntry("モデル名", "モデルの説明", new SimpleFactory(MyModel.class), null, null));
		root.add(drawer);

		return root;
	}

CreationToolEntryにより、パレットにモデル(図形)の行が表示される。
(パレット上でその行を選択してからエディター上で置きたい場所をクリックすると図形が配置される。ドラッグ&ドロップではないので注意。
 →ドラッグ&ドロップで配置する方法

CreationToolEntryは、EditPartのポリシーに書かれている図形生成コマンドを使って図形を生成する。
わざわざコマンドになっているのは、Ctrl+ZによるUNDO(取り消し)やCtrl+YにとるREDOが出来るようにする為。
(とは言っても、Ctrl+ZやCtrl+Yの処理は自前で書かないと駄目だが^^;)

drawer.add(new PaletteSeparator());」でセパレーターを追加することも出来る。[2013-12-29]

DiagramEditPart.java:

import org.eclipse.gef.EditPolicy;
public class DiagramEditPart extends AbstractModelEditPart {
〜
	@Override
	protected void createEditPolicies() {
		installEditPolicy(EditPolicy.LAYOUT_ROLE, new DiagramLayoutEditPolicy());
	}

DiagramLayoutEditPolicy.java

import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.XYLayoutEditPolicy;
import org.eclipse.gef.requests.ChangeBoundsRequest;
import org.eclipse.gef.requests.CreateRequest;
public class DiagramLayoutEditPolicy extends XYLayoutEditPolicy {
	@Override
	protected Command getCreateCommand(CreateRequest request) {
		Point point = request.getLocation();
		MyModel element = (MyModel) request.getNewObject();
		Diagram diagram = (Diagram) getHost().getModel();
		return new CreateElementCommand(diagram, element, point.x, point.y);
	}
}

CreateElementCommand.java

import org.eclipse.gef.commands.Command;
public class CreateElementCommand extends Command {
	private Diagram parent;
	private MyModel element;
	private int x;
	private int y;
	public CreateElementCommand(Diagram parent, MyModel element, int x, int y) {
		this.parent = parent;
		this.element = element;
		this.x = x;
		this.y = y;
	}
	@Override
	public void execute() {
		element.setX(x);
		element.setY(y);
		parent.addContent(element);
	}
	@Override
	public void undo() {
		parent.removeContent(element);
	}
}

ドラッグ&ドロップの例

上記の方法では、図形を配置するには、パレットで図形を選択し、エディター上で配置したい場所をクリックする。
よくある操作では、パレットから図形をドラッグして、配置したい場所にドロップする。これを実現してみる。[2013-03-12]

参考: stackoverflowのHow to drag and drop figures from palette into GEF editor?

GraphicalEditorクラス:

import org.eclipse.gef.dnd.TemplateTransferDragSourceListener;
import org.eclipse.gef.dnd.TemplateTransferDropTargetListener;
import org.eclipse.gef.palette.CombinedTemplateCreationEntry;
import org.eclipse.gef.ui.palette.PaletteViewer;
public class MyEditor extends GraphicalEditorWithFlyoutPalette {
〜
	@Override
	protected void initializeGraphicalViewer() {
		super.initializeGraphicalViewer();

		GraphicalViewer viewer = getGraphicalViewer();

		Diagram diagram = new Diagram();
		viewer.setContents(diagram);

		// パレットのドラッグのリスナーを登録
		PaletteViewer paletteViewer = getPaletteViewerProvider().getEditDomain().getPaletteViewer();
		paletteViewer.addDragSourceListener(new TemplateTransferDragSourceListener(paletteViewer));

		// エディターのドロップのリスナーを登録
		viewer.addDropTargetListener(new TemplateTransferDropTargetListener(viewer));
	}
	@Override
	protected PaletteRoot getPaletteRoot() {
		PaletteRoot root = new PaletteRoot();

		PaletteDrawer drawer = new PaletteDrawer("描画ツール");
		drawer.add(new CombinedTemplateCreationEntry("モデル名", "モデルの説明", new SimpleFactory(MyModel.class), null, null));
		root.add(drawer);

		return root;
	}

これで、パレットからドラッグ&ドロップで図形を配置できるようになる。
(クリックによる配置も従来通り出来る)


コピー&ペーストの例

パレット上の図形を選んでCtrl+Cでコピーし、エディター上にCtrl+Vで貼り付けて新しい図形を作ることが出来る。[2013-12-04]

参考: LogicEditor

CopyTemplateActionは、パレット上で図形を選択すると、その図形のテンプレート(CombinedTemplateCreationEntryから取得する)をAction内部に保持する。
そこでCtrl+Cが押されると、そのテンプレートをクリップボードにコピーする。
Ctrl+Vが押されるとPasteTemplateActionが呼ばれ、クリップボードからテンプレートを取得してそれを使って新しい図形を生成する。
なお、PasteTemplateActionでは貼り付け先の座標は(10,10)になっている。つまりエディター上で選択中の図形内の左上に配置される。
その図形内に新しい図形を生成できない場合は、何も生成されない。

図形の生成は、エディター上で選択されている図形のEditPartに対してCREATEイベントが送られることによって実現されている。
つまり、通常の図形生成と同じ仕組みが使われている。

GraphicalEditorクラス:

import org.eclipse.gef.ui.actions.CopyTemplateAction;
import org.eclipse.gef.ui.actions.PasteTemplateAction;

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.ui.actions.ActionFactory;
public class MyEditor extends GraphicalEditorWithFlyoutPalette {
〜
	@SuppressWarnings("unchecked")
	@Override
	protected void createActions() {
		super.createActions();
		ActionRegistry registry = getActionRegistry();
		{
			IAction action = new CopyTemplateAction(this);
			registry.registerAction(action);
			//PaletterViewerに登録するので、selectionActionsには登録しない
		}
		{
			IAction action = new PasteTemplateAction(this);
			registry.registerAction(action);
			getSelectionActions().add(action.getId());
		}
		〜
	}
	@Override
	protected void initializeGraphicalViewer() {
		super.initializeGraphicalViewer();
〜
		// palette drag
		PaletteViewer paletteViewer = getPaletteViewerProvider().getEditDomain().getPaletteViewer();
		paletteViewer.addDragSourceListener(new TemplateTransferDragSourceListener(paletteViewer));
		// palette copy
		final CopyTemplateAction copy = (CopyTemplateAction) getActionRegistry().getAction(ActionFactory.COPY.getId());
		paletteViewer.addSelectionChangedListener(copy);
		// palette context-menu
		paletteViewer.getContextMenu().addMenuListener(new IMenuListener() {
			@Override
			public void menuAboutToShow(IMenuManager manager) {
				manager.appendToGroup(GEFActionConstants.GROUP_COPY, copy);
			}
		});

		// editor drop
		viewer.addDropTargetListener(new TemplateTransferDropTargetListener(viewer));
	}

ActionBarContributorクラス:

import org.eclipse.ui.actions.ActionFactory;
public class MyActionBarContributor extends ActionBarContributor {
〜
	@Override
	protected void declareGlobalActionKeys() {
		addGlobalActionKey(ActionFactory.COPY.getId());
		addGlobalActionKey(ActionFactory.PASTE.getId());
	}
}

ちなみに、Eclipse4.3で開発してEclipse3.7にインストールすると、PasteTemplateActionが存在しないので例外が発生する。[2013-03-10]

java.lang.NoClassDefFoundError: org/eclipse/gef/ui/actions/PasteTemplateAction
〜
Caused by: java.lang.ClassNotFoundException: org.eclipse.gef.ui.actions.PasteTemplateAction
〜

CopyTemplateActionはGEF3.7に存在しているが、PasteTemplateActionは何故かGEF3.8で追加されたらしい。
したがってPasteTemplateActionはGEF3.7に存在しないのでエラーになる。


パレットの初期値(初期配置)

デフォルトでは、エディターを開いた直後はパレットが閉じた状態になっている。[2013-12-29]

そういった初期状態(初期値)(パレットの開閉有無やパレットの幅、配置場所(エディターの右か左か))を変更する例。

GraphicalEditorクラス:

import org.eclipse.draw2d.PositionConstants;

import org.eclipse.gef.ui.palette.FlyoutPaletteComposite;
import org.eclipse.gef.ui.palette.FlyoutPaletteComposite.FlyoutPreferences;
public class MyEditor extends GraphicalEditorWithFlyoutPalette {
〜
	@Override
	protected FlyoutPreferences getPalettePreferences() {
		FlyoutPreferences pref = super.getPalettePreferences();
		if (pref.getPaletteWidth() <= 0) {
			pref.setDockLocation(PositionConstants.EAST);
			pref.setPaletteState(FlyoutPaletteComposite.STATE_PINNED_OPEN);
			pref.setPaletteWidth(160);
		}
		return pref;
	}

メソッド名を見れば分かる通り、preferences(設定)で状態(値)を保持している。


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