/*******************************************************************************
* Copyright (c) 2008 Scott Stanchfield
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package com.javadude.dependencies.editparts;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.draw2d.AbstractLayout;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.graph.CompoundDirectedGraph;
import org.eclipse.draw2d.graph.CompoundDirectedGraphLayout;
import org.eclipse.draw2d.graph.Edge;
import org.eclipse.draw2d.graph.Node;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.gef.editparts.AbstractConnectionEditPart;
class GraphLayoutManager extends AbstractLayout {
private EditPart editPart;
GraphLayoutManager(EditPart editPart) {
this.editPart = editPart;
}
@Override
protected Dimension calculatePreferredSize(IFigure container, int wHint, int hHint) {
// if (state == PLAYBACK)
// return container.getSize();
container.validate();
@SuppressWarnings("unchecked")
List<IFigure> children = container.getChildren();
Rectangle result = new Rectangle().setLocation(container.getClientArea().getLocation());
for (IFigure f : children) {
result.union(f.getBounds());
}
result.resize(container.getInsets().getWidth(), container.getInsets().getHeight());
return result.getSize();
}
@SuppressWarnings("unchecked")
public void layout(IFigure container) {
CompoundDirectedGraph graph = new CompoundDirectedGraph();
Map<GraphicalEditPart,Node> nodes = new HashMap<GraphicalEditPart, Node>();
Node dummyNode = new Node(null);
graph.nodes.add(dummyNode);
List<AbstractConnectionEditPart> sourceConnections = new ArrayList<AbstractConnectionEditPart>();
for (Iterator<GraphicalEditPart> i = editPart.getChildren().iterator(); i.hasNext();) {
GraphicalEditPart part = i.next();
Node n = new Node(part);
Rectangle bounds = part.getFigure().getBounds();
n.width = bounds.width;
n.height = bounds.height;
nodes.put(part, n);
graph.nodes.add(n);
// keep track of connections for edge setup
if (part instanceof NodeEditPart) {
NodeEditPart nodeEditPart = (NodeEditPart) part;
sourceConnections.addAll(nodeEditPart.getSourceConnections());
// add any nodes without target dependencies to the dummy node
if (nodeEditPart.getTargetConnections().isEmpty()) {
graph.edges.add(new Edge(null, dummyNode, n));
}
}
}
for (Iterator<AbstractConnectionEditPart> i = sourceConnections.iterator(); i.hasNext();) {
AbstractConnectionEditPart part = i.next();
Node m = (Node) nodes.get(part.getSource());
Node e = (Node) nodes.get(part.getTarget());
graph.edges.add(new Edge(part, m, e));
}
// layout the graph
new CompoundDirectedGraphLayout().visit(graph);
int dummyY = 0;
for (Iterator<Node> i = graph.nodes.iterator(); i.hasNext();) {
Node node = i.next();
if (node.data == null) {
dummyY = node.y;
}
}
int minGap = Integer.MAX_VALUE;
for (Iterator<Node> i = graph.nodes.iterator(); i.hasNext();) {
Node node = i.next();
if (node.data != null) {
minGap = Math.min(minGap, node.y - dummyY);
}
}
// update the positions of the figures
for (Iterator<Node> i = graph.nodes.iterator(); i.hasNext();) {
Node node = i.next();
if (node.data == null) {
continue;
}
GraphicalEditPart part = (GraphicalEditPart) node.data;
Dimension size = part.getFigure().getPreferredSize();
Rectangle rectangle = new Rectangle(node.x, node.y - minGap, size.width, size.height);
part.getFigure().setBounds(rectangle);
}
}
}