/*
* Copyright (C) Yutaka Matsuno 2010-2012 All rights reserved.
*/
package net.dependableos.dcase.diagram.editor.layout;
import java.util.Stack;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.graph.Node;
import org.eclipse.draw2d.graph.NodeList;
/**
* This class locates nodes.
*/
public class LocateNodeGraphVisitor extends DcaseGraphVisitor {
/**
* the stack to check the looped link.
*/
private Stack<NodeEx> stack = new Stack<NodeEx>();
/**
* the stack to check the looped link adjusting location of nodes.
*/
private Stack<NodeEx> adjustStack = new Stack<NodeEx>();
/**
* Locates the nodes.
*
* @param graph the direct graph.
*/
@Override
protected void visit(DcaseDirectedGraph graph) {
super.visit(graph);
locateNode();
}
/**
* Locates the nodes.
*/
private void locateNode() {
int xPoint = BASE_POINT_X;
int yPoint = BASE_POINT_Y;
NodeList baseNodeList = getGraph().getBaseNodeList();
for (int i = 0; i < baseNodeList.size(); i++) {
Node node = baseNodeList.getNode(i);
NodeEx nodeEx = getNodeEx(node);
Rectangle rect = nodeEx.getBlockBounds();
locateNode(nodeEx, xPoint, yPoint);
if (ArrangeAngle.createInstance().getAngle() == ArrangeAngle.Direction.Vertical) {
xPoint += rect.width + HORIZONTAL_SPACING;
} else {
yPoint += rect.height + VERTICAL_SPACING;
}
}
}
/**
* Locates a node.
*
* @param nodeEx a node.
* @param xPoint x coordinate.
* @param yPoint y coordinate.
*/
private void locateNode(NodeEx nodeEx, int xPoint, int yPoint) {
if (stack.contains(nodeEx)) {
return;
}
stack.push(nodeEx);
if (ArrangeAngle.createInstance().getAngle() == ArrangeAngle.Direction.Vertical) {
localNodeByVertical(nodeEx, xPoint, yPoint);
} else {
localNodeByHorizontal(nodeEx, xPoint, yPoint);
}
stack.pop();
}
/**
* Locate node by vertical layout.
*
* @param nodeEx a node.
* @param xPoint x coordinate.
* @param yPoint y coordinate.
*/
private void localNodeByVertical(NodeEx nodeEx, int xPoint, int yPoint) {
Node node = nodeEx.getNode();
Rectangle blockRect = nodeEx.getBlockBounds();
blockRect.x = xPoint;
blockRect.y = yPoint;
Dimension bottomDim = getSouthSize(nodeEx);
Dimension rightDim = getEastSize(nodeEx);
int x = xPoint;
int y = yPoint;
// locates the children in the south.
NodeList childListBottom = nodeEx.getSouthNodes();
if (childListBottom.size() > 0) {
if (node.width > bottomDim.width) {
x += ((node.width - bottomDim.width) / 2);
}
if (node.height > rightDim.height) {
y += node.height;
} else if (bottomDim.width > bottomDim.width / 2 + node.width / 2
+ VERTICAL_SPACING) {
y += rightDim.height;
} else {
y += node.height;
}
y += VERTICAL_SPACING;
}
for (int i = 0; i < childListBottom.size(); i++) {
Node child = childListBottom.getNode(i);
NodeEx childEx = getNodeEx(child);
if (nodeEx.getDepth() < childEx.getDepth()) {
Rectangle childRect = childEx.getBlockBounds();
localNodeByVertical(childEx, x, y);
x += childRect.width + HORIZONTAL_SPACING;
}
}
x = xPoint;
y = yPoint;
// locates the children in the east.
NodeList childListRight = nodeEx.getEastNodes();
if (childListRight.size() > 0) {
if (node.width > bottomDim.width) {
x += node.width;
} else {
x += node.width / 2 + bottomDim.width / 2;
}
x += HORIZONTAL_CONTEXT_SPACING;
if (node.height > rightDim.height) {
y += ((node.height - rightDim.height) / 2);
}
}
for (int i = 0; i < childListRight.size(); i++) {
Node child = childListRight.getNode(i);
NodeEx childEx = getNodeEx(child);
if (nodeEx.getDepth() < childEx.getDepth()) {
Rectangle childRect = childEx.getBlockBounds();
localNodeByVertical(childEx, x, y);
y += childRect.height + VERTICAL_CONTEXT_SPACING;
}
}
// adjusts the position of the parent.
x = xPoint;
y = yPoint;
if (childListBottom.size() > 0) {
Node first = getWestOfSouth(nodeEx);
Node last = getEastOfSouth(nodeEx);
if (first != null) {
x = (first.x + last.x + last.width - node.width) / 2;
}
}
if (childListRight.size() > 0) {
Node first = getNorthOfEast(nodeEx);
Node last = getSouthOfEast(nodeEx);
if (first != null) {
y = (first.y + last.y + last.height - node.height) / 2;
}
}
node.x = x;
node.y = y;
// adjusts the position of the children in the south.
if (childListBottom.size() > 0) {
if (y > yPoint) {
for (int i = 0; i < childListBottom.size(); i++) {
Node childNode = childListBottom.getNode(i);
NodeEx childEx = getNodeEx(childNode);
if (childNode.y > node.y + node.height + HORIZONTAL_SPACING) {
break;
}
int yAdjust = y - yPoint;
adjustLocation(childEx, 0, yAdjust);
}
}
}
// adjusts the position of the children in the east.
if (childListRight.size() > 0) {
x = node.x + node.width + HORIZONTAL_CONTEXT_SPACING;
for (int i = 0; i < childListRight.size(); i++) {
Node childNode = childListRight.getNode(i);
NodeEx childEx = getNodeEx(childNode);
Rectangle dim = childEx.getBlockBounds();
int xAdjust = Math.max(x - childNode.x, x - dim.x);
adjustLocation(childEx, xAdjust, 0);
}
}
}
/**
* Locate node by horizontal layout.
*
* @param nodeEx a node.
* @param xPoint x coordinate.
* @param yPoint y coordinate.
*/
private void localNodeByHorizontal(NodeEx nodeEx, int xPoint, int yPoint) {
Node node = nodeEx.getNode();
Rectangle blockRect = nodeEx.getBlockBounds();
blockRect.x = xPoint;
blockRect.y = yPoint;
Dimension bottomDim = getSouthSize(nodeEx);
Dimension rightDim = getEastSize(nodeEx);
int x = xPoint;
int y = yPoint;
// locates the children in the south.
NodeList childListBottom = nodeEx.getSouthNodes();
if (childListBottom.size() > 0) {
if (node.height > bottomDim.height) {
y += ((node.height - bottomDim.height) / 2);
}
x += Math.max(node.width, rightDim.width);
x += HORIZONTAL_SPACING;
}
for (int i = 0; i < childListBottom.size(); i++) {
Node child = childListBottom.getNode(i);
NodeEx childEx = getNodeEx(child);
if (nodeEx.getDepth() < childEx.getDepth()) {
Rectangle childRect = childEx.getBlockBounds();
localNodeByHorizontal(childEx, x, y);
y += childRect.height + VERTICAL_SPACING;
}
}
x = xPoint;
y = yPoint;
// locates the children in the east.
NodeList childListRight = nodeEx.getEastNodes();
if (childListRight.size() > 0) {
y += node.height;
y += VERTICAL_CONTEXT_SPACING;
if (node.width > rightDim.width) {
x += ((node.width - rightDim.width) / 2);
}
}
for (int i = 0; i < childListRight.size(); i++) {
Node child = childListRight.getNode(i);
NodeEx childEx = getNodeEx(child);
if (nodeEx.getDepth() < childEx.getDepth()) {
Rectangle childRect = childEx.getBlockBounds();
localNodeByHorizontal(childEx, x, y);
x += childRect.width + HORIZONTAL_CONTEXT_SPACING;
}
}
// adjusts the position of the parent.
x = xPoint;
y = yPoint;
if (childListBottom.size() > 0) {
Node first = getWestOfSouth(nodeEx);
Node last = getEastOfSouth(nodeEx);
if (first != null) {
y = (first.y + last.y + last.height - node.height) / 2;
}
}
if (childListRight.size() > 0) {
Node first = getNorthOfEast(nodeEx);
Node last = getSouthOfEast(nodeEx);
if (first != null) {
x = (first.x + last.x + last.width - node.width) / 2;
}
}
node.x = x;
node.y = y;
// adjusts the position of the children in the east.
if (childListRight.size() > 0) {
if (y > yPoint) {
for (int i = 0; i < childListRight.size(); i++) {
Node childNode = childListRight.getNode(i);
NodeEx childEx = getNodeEx(childNode);
if (childNode.y > node.y + node.height + VERTICAL_CONTEXT_SPACING) {
break;
}
int yAdjust = y - yPoint;
adjustLocation(childEx, 0, yAdjust);
}
}
}
}
/**
* Returns the first node that should be locate in south.
*
* @param nodeEx a node.
* @return the first node that should be locate in south.
*/
private Node getWestOfSouth(NodeEx nodeEx) {
Node node = null;
NodeList list = nodeEx.getSouthNodes();
for (int i = 0; i < list.size(); i++) {
Node child = (Node) list.get(i);
NodeEx childEx = getNodeEx(child);
if (nodeEx.getDepth() < childEx.getDepth()) {
node = child;
break;
}
}
return node;
}
/**
* Returns the last child that should be locate in south.
*
* @param nodeEx a node.
* @return the last child that should be locate in south.
*/
private Node getEastOfSouth(NodeEx nodeEx) {
Node node = null;
NodeList list = nodeEx.getSouthNodes();
for (int i = list.size() - 1; i >= 0; i--) {
Node child = (Node) list.get(i);
NodeEx childEx = getNodeEx(child);
if (nodeEx.getDepth() < childEx.getDepth()) {
node = child;
break;
}
}
return node;
}
/**
* Returns the first child that should be locate in east.
*
* @param nodeEx a node.
* @return the first child that should be locate in east.
*/
private Node getNorthOfEast(NodeEx nodeEx) {
Node node = null;
NodeList list = nodeEx.getEastNodes();
for (int i = 0; i < list.size(); i++) {
Node child = (Node) list.get(i);
NodeEx childEx = getNodeEx(child);
if (nodeEx.getDepth() < childEx.getDepth()) {
node = child;
break;
}
}
return node;
}
/**
* Returns the last child that should be locate in east.
*
* @param nodeEx a node.
* @return the last child that should be locate in east.
*/
private Node getSouthOfEast(NodeEx nodeEx) {
Node node = null;
NodeList list = nodeEx.getEastNodes();
for (int i = list.size() - 1; i >= 0; i--) {
Node child = (Node) list.get(i);
NodeEx childEx = getNodeEx(child);
if (nodeEx.getDepth() < childEx.getDepth()) {
node = child;
break;
}
}
return node;
}
/**
* Adjusts the position of a node.
*
* @param nodeEx a node.
* @param x x axis movement.
* @param y y axis movement.
*/
private void adjustLocation(NodeEx nodeEx, int x, int y) {
if (adjustStack.contains(nodeEx)) {
return;
}
if (stack.contains(nodeEx)) {
return;
}
adjustStack.push(nodeEx);
nodeEx.getNode().x += x;
nodeEx.getBlockBounds().x += x;
nodeEx.getNode().y += y;
nodeEx.getBlockBounds().y += y;
NodeList childList = nodeEx.getChildren();
for (int i = 0; i < childList.size(); i++) {
adjustLocation(getNodeEx(childList.getNode(i)), x, y);
}
adjustStack.pop();
}
/**
* Returns the size of the south.
*
* @param nodeEx a node.
* @return the size of the south.
*/
public Dimension getSouthSize(NodeEx nodeEx) {
Dimension dim = new Dimension();
NodeList list = nodeEx.getSouthNodes();
int count = 0;
for (int i = 0; i < list.size(); i++) {
Node child = list.getNode(i);
NodeEx childEx = getNodeEx(child);
if (nodeEx.getDepth() < childEx.getDepth()) {
Rectangle childRect = childEx.getBlockBounds();
if (ArrangeAngle.createInstance().getAngle() == ArrangeAngle.Direction.Vertical) {
dim.width += childRect.width;
dim.height = Math.max(dim.height, childRect.height);
} else {
dim.width = Math.max(dim.width, childRect.width);
dim.height += childRect.height;
}
count++;
}
}
if (count > 1) {
if (ArrangeAngle.createInstance().getAngle() == ArrangeAngle.Direction.Vertical) {
dim.width += (HORIZONTAL_SPACING * (count - 1));
} else {
dim.height += (VERTICAL_SPACING * (count - 1));
}
}
return dim;
}
/**
* Returns the size of the east.
*
* @param nodeEx a node.
* @return the size of the east.
*/
public Dimension getEastSize(NodeEx nodeEx) {
Dimension dim = new Dimension();
NodeList list = nodeEx.getEastNodes();
int count = 0;
for (int i = 0; i < list.size(); i++) {
Node child = list.getNode(i);
NodeEx childEx = getNodeEx(child);
if (nodeEx.getDepth() < childEx.getDepth()) {
Rectangle childRect = childEx.getBlockBounds();
if (ArrangeAngle.createInstance().getAngle() == ArrangeAngle.Direction.Vertical) {
dim.width = Math.max(dim.width, childRect.width);
dim.height += childRect.height;
} else {
dim.width += childRect.width;
dim.height = Math.max(dim.height, childRect.height);
}
count++;
}
}
if (count > 1) {
if (ArrangeAngle.createInstance().getAngle() == ArrangeAngle.Direction.Vertical) {
dim.height += (VERTICAL_CONTEXT_SPACING * (count - 1));
} else {
dim.width += (HORIZONTAL_CONTEXT_SPACING * (count - 1));
}
}
return dim;
}
}