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));
}
コンテキストメニューにアクションを追加してみた。
(グループをどこにすればいいか迷う^^;)