blob: 6e235ef5f76536acd7d0f91a69022fcea67bc0de [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2010 IBM Corporation and others.
* 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.draw2d.graph;
import org.eclipse.draw2d.geometry.Insets;
/**
* Converts a compound directed graph into a simple directed graph.
*
* @author Randy Hudson
* @since 2.1.2
*/
class ConvertCompoundGraph extends GraphVisitor {
private void addContainmentEdges(CompoundDirectedGraph graph) {
// For all nested nodes, connect to head and/or tail of containing
// subgraph if present
for (int i = 0; i < graph.nodes.size(); i++) {
Node node = graph.nodes.getNode(i);
Subgraph parent = node.getParent();
if (parent == null)
continue;
if (node instanceof Subgraph) {
Subgraph sub = (Subgraph) node;
connectHead(graph, sub.head, parent);
connectTail(graph, sub.tail, parent);
} else {
connectHead(graph, node, parent);
connectTail(graph, node, parent);
}
}
}
int buildNestingTreeIndices(NodeList nodes, int base) {
for (int i = 0; i < nodes.size(); i++) {
Node node = (Node) nodes.get(i);
if (node instanceof Subgraph) {
Subgraph s = (Subgraph) node;
s.nestingTreeMin = base;
base = buildNestingTreeIndices(s.members, base);
}
node.nestingIndex = base++;
}
return base++;
}
private void connectHead(CompoundDirectedGraph graph, Node node,
Subgraph parent) {
boolean connectHead = true;
for (int j = 0; connectHead && j < node.incoming.size(); j++) {
Node ancestor = node.incoming.getEdge(j).source;
if (parent.isNested(ancestor))
connectHead = false;
}
if (connectHead) {
Edge e = new Edge(parent.head, node);
e.weight = 0;
graph.edges.add(e);
graph.containment.add(e);
}
}
private void connectTail(CompoundDirectedGraph graph, Node node,
Subgraph parent) {
boolean connectTail = true;
for (int j = 0; connectTail && j < node.outgoing.size(); j++) {
Node ancestor = node.outgoing.getEdge(j).target;
if (parent.isNested(ancestor))
connectTail = false;
}
if (connectTail) {
Edge e = new Edge(node, parent.tail);
e.weight = 0;
graph.edges.add(e);
graph.containment.add(e);
}
}
private void convertSubgraphEndpoints(CompoundDirectedGraph graph) {
for (int i = 0; i < graph.edges.size(); i++) {
Edge edge = (Edge) graph.edges.get(i);
if (edge.source instanceof Subgraph) {
Subgraph s = (Subgraph) edge.source;
Node newSource;
if (s.isNested(edge.target))
newSource = s.head;
else
newSource = s.tail;
// s.outgoing.remove(edge);
edge.source = newSource;
newSource.outgoing.add(edge);
}
if (edge.target instanceof Subgraph) {
Subgraph s = (Subgraph) edge.target;
Node newTarget;
if (s.isNested(edge.source))
newTarget = s.tail;
else
newTarget = s.head;
// s.incoming.remove(edge);
edge.target = newTarget;
newTarget.incoming.add(edge);
}
}
}
private void replaceSubgraphsWithBoundaries(CompoundDirectedGraph graph) {
for (int i = 0; i < graph.subgraphs.size(); i++) {
Subgraph s = (Subgraph) graph.subgraphs.get(i);
graph.nodes.add(s.head);
graph.nodes.add(s.tail);
graph.nodes.remove(s);
}
}
void revisit(DirectedGraph g) {
for (int i = 0; i < g.edges.size(); i++) {
Edge e = g.edges.getEdge(i);
if (e.source instanceof SubgraphBoundary) {
e.source.outgoing.remove(e);
e.source = e.source.getParent();
}
if (e.target instanceof SubgraphBoundary) {
e.target.incoming.remove(e);
e.target = e.target.getParent();
}
}
}
/**
* @see GraphVisitor#visit(org.eclipse.draw2d.graph.DirectedGraph)
*/
public void visit(DirectedGraph dg) {
CompoundDirectedGraph graph = (CompoundDirectedGraph) dg;
NodeList roots = new NodeList();
// Find all subgraphs and root subgraphs
for (int i = 0; i < graph.nodes.size(); i++) {
Object node = graph.nodes.get(i);
if (node instanceof Subgraph) {
Subgraph s = (Subgraph) node;
Insets padding = dg.getPadding(s);
s.head = new SubgraphBoundary(s, padding, 0);
s.tail = new SubgraphBoundary(s, padding, 2);
Edge headToTail = new Edge(s.head, s.tail);
headToTail.weight = 10;
graph.edges.add(headToTail);
graph.containment.add(headToTail);
graph.subgraphs.add(s);
if (s.getParent() == null)
roots.add(s);
if (s.members.size() == 2) // The 2 being the head and tail only
graph.edges.add(new Edge(s.head, s.tail));
}
}
buildNestingTreeIndices(roots, 0);
convertSubgraphEndpoints(graph);
addContainmentEdges(graph);
replaceSubgraphsWithBoundaries(graph);
}
}