/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.ui.layout;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.draw2d.AbsoluteBendpoint;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.graph.CompoundDirectedGraph;
import org.eclipse.draw2d.graph.CompoundDirectedGraphLayout;
import org.eclipse.draw2d.graph.DirectedGraph;
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.draw2d.graph.Subgraph;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.GraphicalEditPart;
/**
* @author Riccardo Solmi
*/
public class GraphLayoutStrategy implements ILayoutStrategy {
protected boolean translated = false; //true = leftRight; false = topDown
public void layout(GraphicalEditPart containerPart) {
CompoundDirectedGraph graph = new CompoundDirectedGraph();
List<?> parts = containerPart.getChildren();
buildGraph(graph, parts);
calculateLayout(graph);
applyLayout(graph); //TODO optional command based
}
public void calculateLayout(DirectedGraph graph) {
new CompoundDirectedGraphLayout().visit(graph);
}
public void applyLayout(DirectedGraph graph) {
NodeList nodes = graph.nodes;
for (int i=0; i<nodes.size(); i++) {
Node node = (Node) nodes.get(i);
GraphicalEditPart part = (GraphicalEditPart) node.data;
part.getFigure().setBounds(new Rectangle(node.x, node.y, node.width, node.height));
}
EdgeList edges = graph.edges;
for (int i=0; i<edges.size(); i++) {
Edge edge = (Edge) edges.get(i);
ConnectionEditPart connectionPart = (ConnectionEditPart) edge.data;
nodes = edge.vNodes;
PolylineConnection conn = (PolylineConnection) connectionPart.getFigure();
if (nodes != null) {
List<AbsoluteBendpoint> bends = new ArrayList<AbsoluteBendpoint>();
for (int j=0; j<nodes.size(); j++) {
Node vn = nodes.getNode(j);
if (edge.isFeedback) {
bends.add(new AbsoluteBendpoint(vn.x, vn.y+vn.height));
bends.add(new AbsoluteBendpoint(vn.x, vn.y));
} else {
bends.add(new AbsoluteBendpoint(vn.x, vn.y));
bends.add(new AbsoluteBendpoint(vn.x, vn.y+vn.height));
}
}
conn.setRoutingConstraint(bends);
} else
conn.setRoutingConstraint(Collections.EMPTY_LIST);
}
}
// public void applyLayout(Map partNodeMap, List parts) {
// for (Iterator i = parts.iterator(); i.hasNext();) {
// GraphicalEditPart part = (GraphicalEditPart) i.next();
// Node node = (Node) partNodeMap.get(part);
//
// part.getFigure().setBounds(new Rectangle(node.x, node.y, node.width, node.height));
//
// List connectionParts = part.getSourceConnections();
// for (Iterator j = connectionParts.iterator(); j.hasNext();) {
// ConnectionEditPart connectionPart = (ConnectionEditPart) j.next();
// Edge edge = (Edge) partNodeMap.get(connectionPart);
// NodeList nodes = edge.vNodes;
//
// PolylineConnection conn = (PolylineConnection) connectionPart.getFigure();
// if (nodes != null) {
// List bends = new ArrayList();
// for (int k=0; k<nodes.size(); k++) {
// Node vn = nodes.getNode(k);
// if (edge.isFeedback) {
// bends.add(new AbsoluteBendpoint(vn.x, vn.y+vn.height));
// bends.add(new AbsoluteBendpoint(vn.x, vn.y));
// } else {
// bends.add(new AbsoluteBendpoint(vn.x, vn.y));
// bends.add(new AbsoluteBendpoint(vn.x, vn.y+vn.height));
// }
// }
// conn.setRoutingConstraint(bends);
// } else
// conn.setRoutingConstraint(Collections.EMPTY_LIST);
// }
//
// if (isStructuredPart(part))
// applyLayout(partNodeMap, part.getChildren());
// }
// }
public void buildGraph(DirectedGraph graph, List parts) {
Map partNodeMap = new HashMap(1024);
buildNodes(graph, null, parts, partNodeMap);
buildEdges(graph, parts, partNodeMap);
}
public void buildNodes(DirectedGraph graph, Subgraph subgraph, List<GraphicalEditPart> parts, Map partNodeMap) {
for (Iterator<GraphicalEditPart> i = parts.iterator(); i.hasNext();) {
GraphicalEditPart part = i.next();
if (isStructuredPart(part)) {
Subgraph node = createSubgraph(part, subgraph);
partNodeMap.put(part, node);
graph.nodes.add(node);
buildNodes(graph, node, part.getChildren(), partNodeMap);
} else {
Node node = createNode(part, subgraph);
partNodeMap.put(part, node);
graph.nodes.add(node);
}
}
}
protected boolean isStructuredPart(GraphicalEditPart part) {
return part.getContentPane() != part.getFigure();
}
protected Subgraph createSubgraph(GraphicalEditPart part, Subgraph subgraph) {
Subgraph node = new Subgraph(part, subgraph);
//TODO padding and bounds
return node;
}
protected Node createNode(GraphicalEditPart part, Subgraph subgraph) {
final int NODE_PADDING = 30;
Node node = new Node(part, subgraph);
node.setPadding(new Insets(NODE_PADDING));
setNodeBounds(node, part.getFigure().getBounds());
return node;
}
protected void setNodeBounds(Node node, Rectangle bounds) {
if (translated) {
node.x = bounds.y;
node.y = bounds.x;
node.width = bounds.height;
node.height = bounds.width;
} else {
node.x = bounds.x;
node.y = bounds.y;
node.width = bounds.width;
node.height = bounds.height;
}
}
//TODO supporto edges without parts (ex. intra Sequence connections)
public void buildEdges(DirectedGraph graph, List parts, Map partNodeMap) {
for (int i=0; i<parts.size(); i++) {
GraphicalEditPart part = (GraphicalEditPart) parts.get(i);
List<?> connectionParts = part.getSourceConnections();
for (int j=0; j<connectionParts.size(); j++) {
ConnectionEditPart connectionPart = (ConnectionEditPart) connectionParts.get(j);
Node source = (Node) partNodeMap.get(connectionPart.getSource());
Node target = (Node) partNodeMap.get(connectionPart.getTarget());
Edge edge = createEdge(connectionPart, source, target);
partNodeMap.put(connectionPart, edge);
graph.edges.add(edge);
}
buildEdges(graph, part.getChildren(), partNodeMap);
}
}
protected Edge createEdge(ConnectionEditPart part, Node source, Node target) {
Edge edge = new Edge(part, source, target);
//TODO weight
return edge;
}
}