Eclipseのプラグイン開発のGEFの図形の自動レイアウトについて。
|
GEFでは、図形の配置を自動的に整列させることが出来る。
あんまり思った通りの並び順になってくれないけど(苦笑)
横向きに並べたい場合に、上下(行)が入れ替わってしまったりするのがなぁ。(初期位置を指定できないので、入れ替わるというのはこちらの主観なんだけど)
選択された図形を自動整列させる例。
まず、自動整列を実行するアクションを定義する。
import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Insets; import org.eclipse.draw2d.graph.DirectedGraph; import org.eclipse.draw2d.graph.DirectedGraphLayout; import org.eclipse.draw2d.graph.Edge; import org.eclipse.draw2d.graph.EdgeList; import org.eclipse.draw2d.graph.Node; import org.eclipse.draw2d.graph.NodeList; import org.eclipse.gef.commands.CompoundCommand; import org.eclipse.gef.ui.actions.SelectionAction; import org.eclipse.ui.IWorkbenchPart;
public class AutoLayoutAction extends SelectionAction { public static final String ID = "MY_AUTO_LAYOUT";
public AutoLayoutAction(IWorkbenchPart part) { super(part); }
@Override protected void init() { super.init(); setText("auto layout"); setToolTipText("auto layout"); setId(ID); }
@Override
protected boolean calculateEnabled() {
@SuppressWarnings("unchecked")
List<Object> list = getSelectedObjects();
int count = 0;
for (Object obj : list) {
if (obj instanceof NodeElementEditPart) {
if (++count >= 2) { // 要素が2個以上選択されている場合だけ実行可能
return true;
}
}
}
return false;
}
@Override public void run() { NodeList nodeList = new NodeList(); EdgeList edgeList = new EdgeList(); collect(nodeList, edgeList); calculateLayout(nodeList, edgeList); layout(nodeList); }
// 選択された要素から、Node(頂点)とEdge(辺)を収集する @SuppressWarnings("unchecked") private void collect(NodeList nodeList, EdgeList edgeList) { Map<NodeElement, Node> map = new HashMap<NodeElement, Node>(); { List<Object> list = getSelectedObjects(); for (Object obj : list) { if (obj instanceof NodeElementEditPart) { NodeElementEditPart part = (NodeElementEditPart) obj; NodeElement model = part.getModel(); Node node = new Node(part); map.put(model, node); IFigure figure = part.getFigure(); Dimension size = figure.getSize(); node.setSize(size); // 初期位置を与えても考慮されない // node.x = model.getX(); // node.y = model.getY(); } } } Set<Connection> set = new HashSet<Connection>(); for (Entry<NodeElement, Node> entry : map.entrySet()) { NodeElement model = entry.getKey(); Node node = entry.getValue(); nodeList.add(node); for (Connection c : model.getOutgoings()) { Node target = map.get(c.getTarget()); if (target != null && !set.contains(c)) { Edge edge = new Edge(node, target); edgeList.add(edge); set.add(c); } } for (Connection c : model.getIncomings()) { Node source = map.get(c.getSource()); if (source != null && !set.contains(c)) { Edge edge = new Edge(source, node); edgeList.add(edge); set.add(c); } } } }
// 自動レイアウトを実施する
private void calculateLayout(NodeList nodeList, EdgeList edgeList) {
DirectedGraph graph = new DirectedGraph();
graph.setDirection(PositionConstants.EAST); // 左から右の方向へ配置する
graph.edges = edgeList;
graph.nodes = nodeList;
graph.setDefaultPadding(new Insets(16)); // Node間の間隔
DirectedGraphLayout layout = new DirectedGraphLayout();
layout.visit(graph); //これにより、nodeListに座標が設定される
}
// 算出された位置へ図形を移動させる private void layout(NodeList nodeList) { CompoundCommand command = new CompoundCommand(); for (Object obj : nodeList) { Node node = (Node) obj; NodeElementEditPart part = (NodeElementEditPart) node.data; NodeElement model = part.getModel(); MoveElementCommand c = new MoveElementCommand(model, node.x, node.y); command.add(c); } getCommandStack().execute(command); } }
public class MyEditor extends GraphicalEditorWithFlyoutPalette
@SuppressWarnings("unchecked")
@Override
protected void createActions() {
super.createActions();
ActionRegistry registry = getActionRegistry();
〜
IAction action = new AutoLayoutAction(this);
registry.registerAction(action);
getSelectionActions().add(action.getId());
}
public class MyContextMenuProvider extends ContextMenuProvider {
@Override public void buildContextMenu(IMenuManager menu) { GEFActionConstants.addStandardActionGroups(menu); 〜 menu.appendToGroup(GEFActionConstants.GROUP_EDIT, registry.getAction(AutoLayoutAction.ID)); }
コンテキストメニューにアクションを追加してみた。
(グループをどこにすればいいか迷う^^;)