/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.diagram.ui.layout;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
import org.teiid.designer.diagram.ui.connection.NodeConnectionModel;
import org.teiid.designer.diagram.ui.model.DiagramModelNode;
/**
* @since 8.0
*/
public class MmTreeLayout extends DiagramLayout {
static final String CLASS_NAME = "MmTreeLayout"; //$NON-NLS-1$
public static final int COMPACT_METHOD = 0;
public static final int SEPARATE_METHOD = 1;
public static final int LIST_ORDER = 0;
public static final int POSITION_ORDER = 1;
public static final int ORIENTATION_ROOT_LEFT = 0;
public static final int ORIENTATION_ROOT_TOP = 1;
public static final int ORIENTATION_ROOT_RIGHT = 2;
public static final int ORIENTATION_ROOT_BOTTOM = 3;
public static final int ERROR_TREE_HAS_NO_ROOT = 1;
public static final int ERROR_ROOT_NOT_MANAGED = 2;
public static final int ERROR_NOT_A_TREE = 3;
private DiagramModelNode modelRoot = null;
private int _depth = -1;
private int _order = 1;
private int _orientation = 0;
private int _method = 0;
private boolean _useObjectsSizes = false;
private boolean _fixedSpacing = true;
private double _fixedXSpacing = 500.0;
private double _fixedYSpacing = 400.0;
private transient Hashtable _compToNode;
private transient TreeNode[] rawTreeNodes;
public MmTreeLayout() {
_compToNode = new Hashtable();
rawTreeNodes = null;
}
@Override
protected int run() {
if (this.getComponentCount() == 0) return SUCCESSFUL;
int i = buildTree();
if (i != 0) return i;
TreeNode treenode = (TreeNode)_compToNode.get(modelRoot);
if (treenode == null) return ERROR_ROOT_NOT_MANAGED;
TreeNode[] treenodes = new TreeNode[_depth + 1];
treenode.setNeighbors(treenodes);
double d = 0.0;
double d_85_ = 0.0;
double d_86_ = 0.0;
double d_87_ = 1.0;
double d_88_ = 0.0;
double[] ds = new double[_depth + 1];
if (_method == 0) {
double[] ds_89_ = new double[_depth + 1];
double[] ds_90_ = new double[_depth + 1];
treenode.calculatePosition(ds_89_, ds_90_);
treenode.setEven();
for (int i_91_ = 0; i_91_ <= _depth; i_91_++)
d_86_ = Math.max(d_86_, ds_90_[i_91_]);
if (_useObjectsSizes) {
treenode.getMaximumWidths(ds);
for (int i_92_ = 0; i_92_ <= _depth; i_92_++) {
d_88_ = ds[i_92_];
ds[i_92_] += d - 0.5 * d_88_;
d += d_88_;
d_85_ = Math.max(d_85_, ds_89_[i_92_]);
}
}
} else {
double[] ds_93_ = new double[1];
double[] ds_94_ = new double[1];
treenode.calculateSeparatePosition(ds_93_, ds_94_);
d_86_ = ds_94_[0];
if (_useObjectsSizes) {
treenode.getMaximumWidths(ds);
for (int i_95_ = 0; i_95_ <= _depth; i_95_++) {
d_88_ = ds[i_95_];
ds[i_95_] += d - 0.5 * d_88_;
d += d_88_;
}
d_85_ = ds_93_[0];
}
}
double d_96_ = 0.0;
double d_97_ = 0.0;
double d_98_ = this.getWidth();
double d_99_ = this.getHeight();
double d_100_ = this.getXOrigin();
double d_101_ = this.getYOrigin();
if (_useObjectsSizes) {
d_96_ = 1.0;
d_97_ = 1.0;
}
if (_orientation == ORIENTATION_ROOT_TOP || _orientation == ORIENTATION_ROOT_BOTTOM) {
d_88_ = d_98_;
d_98_ = d_99_;
d_99_ = d_88_;
d_88_ = d_100_;
d_100_ = d_101_;
d_101_ = d_88_;
}
if (_orientation == ORIENTATION_ROOT_RIGHT || _orientation == ORIENTATION_ROOT_BOTTOM) {
d_100_ += d_98_;
d_101_ += d_99_;
d_96_ = -d_96_;
d_97_ = -d_97_;
d_87_ = -1.0;
}
if (_fixedSpacing) {
if (_orientation == ORIENTATION_ROOT_TOP || _orientation == ORIENTATION_ROOT_BOTTOM) {
d_98_ = d_87_ * _fixedYSpacing;
d_99_ = d_87_ * _fixedXSpacing;
} else {
d_98_ = d_87_ * _fixedXSpacing;
d_99_ = d_87_ * _fixedYSpacing;
}
} else {
d_98_ = d_87_ * (d_98_ - d) / (_depth + 1);
d_99_ = d_87_ * (d_99_ - d_85_) / d_86_;
}
d_100_ += 0.5 * d_98_;
d_101_ -= 0.5 * d_99_;
for (int i_102_ = 0; i_102_ <= _depth; i_102_++)
ds[i_102_] = d_100_ + d_96_ * ds[i_102_] + d_98_ * i_102_;
DiagramModelNode[] modelNodes = getNodeArray();
int i_103_ = modelNodes.length;
if (_orientation == ORIENTATION_ROOT_RIGHT || _orientation == ORIENTATION_ROOT_LEFT) {
for (int i_104_ = 0; i_104_ < i_103_; i_104_++) {
DiagramModelNode modelNode = modelNodes[i_104_];
treenode = rawTreeNodes[i_104_];
if (treenode._level != -1) {
int newX = (int)ds[treenode._level];
int newY = (int)(treenode._absolutePosition * d_97_ + treenode._relativePosition * d_99_ + d_101_);
modelNode.setCenterXY(newX, newY);
}
}
} else {
for (int i_105_ = 0; i_105_ < i_103_; i_105_++) {
DiagramModelNode modelNode = modelNodes[i_105_];
treenode = rawTreeNodes[i_105_];
if (treenode._level != -1) {
int newX = (int)ds[treenode._level];
int newY = (int)(treenode._absolutePosition * d_97_ + treenode._relativePosition * d_99_ + d_101_);
modelNode.setCenterXY(newX, newY);
}
}
}
// if (this.getPropagate())
// this.propagate();
return SUCCESSFUL;
}
private int buildTree() {
_compToNode.clear();
int i = this.getComponentCount();
if (i == 0) return 0;
DiagramModelNode[] modelNodes = getNodeArray();
rawTreeNodes = new TreeNode[i];
for (int iiNode = 0; iiNode < i; iiNode++) {
DiagramModelNode modelNode = modelNodes[iiNode];
rawTreeNodes[iiNode] = new TreeNode(modelNode);
_compToNode.put(modelNode, rawTreeNodes[iiNode]);
}
if (_order == LIST_ORDER) {
for (int i_107_ = 0; i_107_ < i; i_107_++)
rawTreeNodes[i_107_]._orderVar = i_107_;
} else if (_orientation == ORIENTATION_ROOT_LEFT) {
for (int i_108_ = 0; i_108_ < i; i_108_++)
rawTreeNodes[i_108_]._orderVar = modelNodes[i_108_].getCenterY();
} else if (_orientation == ORIENTATION_ROOT_TOP) {
for (int i_109_ = 0; i_109_ < i; i_109_++)
rawTreeNodes[i_109_]._orderVar = modelNodes[i_109_].getCenterX();
} else if (_orientation == ORIENTATION_ROOT_RIGHT) {
for (int i_110_ = 0; i_110_ < i; i_110_++)
rawTreeNodes[i_110_]._orderVar = -modelNodes[i_110_].getCenterY();
} else {
for (int i_111_ = 0; i_111_ < i; i_111_++)
rawTreeNodes[i_111_]._orderVar = -modelNodes[i_111_].getCenterX();
}
if (_orientation == ORIENTATION_ROOT_LEFT || _orientation == ORIENTATION_ROOT_RIGHT) {
for (int i_112_ = 0; i_112_ < i; i_112_++) {
rawTreeNodes[i_112_]._width = modelNodes[i_112_].getWidth();
rawTreeNodes[i_112_]._height = modelNodes[i_112_].getHeight();
}
} else {
for (int i_113_ = 0; i_113_ < i; i_113_++) {
rawTreeNodes[i_113_]._width = modelNodes[i_113_].getHeight();
rawTreeNodes[i_113_]._height = modelNodes[i_113_].getWidth();
}
}
for (int iiNode = 0; iiNode < i; iiNode++) {
DiagramModelNode sourceNode = modelNodes[iiNode];
Vector sourceConnections = sourceNode.getSourceConnections();
TreeNode sourceTreeNode = (TreeNode)_compToNode.get(sourceNode);
if (!sourceConnections.isEmpty()) {
Iterator iter = sourceConnections.iterator();
NodeConnectionModel nextConnection = null;
while (iter.hasNext()) {
nextConnection = (NodeConnectionModel)iter.next();
TreeNode targetTreeNode = (TreeNode)_compToNode.get(nextConnection.getTargetNode());
if (sourceTreeNode != null && targetTreeNode != null) {
sourceTreeNode.addLinkToNode(targetTreeNode);
targetTreeNode.addLinkToNode(sourceTreeNode);
}
}
}
}
if (modelRoot == null) return ERROR_TREE_HAS_NO_ROOT;
TreeNode treenode = (TreeNode)_compToNode.get(modelRoot);
if (treenode == null) return ERROR_ROOT_NOT_MANAGED;
_depth = -1;
try {
_depth = treenode.setParent(null);
} catch (NotATreeException notatreeexception) {
return ERROR_NOT_A_TREE;
}
return SUCCESSFUL;
}
public boolean getFixedSpacing() {
return _fixedSpacing;
}
public double getFixedXSpacing() {
return _fixedXSpacing;
}
public double getFixedYSpacing() {
return _fixedYSpacing;
}
public int getMethod() {
return _method;
}
public int getOrder() {
return _order;
}
public int getOrientation() {
return _orientation;
}
public DiagramModelNode getRoot() {
return modelRoot;
}
public boolean getUseObjectsSizes() {
return _useObjectsSizes;
}
public void setFixedSpacing( boolean bool ) {
_fixedSpacing = bool;
}
public void setFixedXSpacing( double d ) {
_fixedXSpacing = d;
}
public void setFixedYSpacing( double d ) {
_fixedYSpacing = d;
}
public void setMethod( int i ) {
_method = i;
}
public void setOrder( int i ) {
_order = i;
}
public void setOrientation( int i ) {
_orientation = i;
}
public void setRoot( DiagramModelNode modelNode ) {
modelRoot = modelNode;
}
public void setUseObjectsSizes( boolean bool ) {
_useObjectsSizes = bool;
}
private class TreeNode {
int _level;
double _orderVar;
double _width;
double _height;
double _absolutePosition;
private double _absoluteSpaceLeft;
double _relativePosition;
private double _relativeSpaceLeft;
// private final DiagramModelNode _modelNode;
private TreeNode _parent;
private final Vector _children;
private TreeNode _upNeighbor;
private TreeNode _downNeighbor;
private boolean _upSibling;
private boolean _downSibling;
public TreeNode( DiagramModelNode modelNode ) {
_level = -1;
_orderVar = 0.0;
_absolutePosition = 0.0;
_absoluteSpaceLeft = 0.0;
_relativePosition = 0.0;
_relativeSpaceLeft = 0.0;
// _modelNode = modelNode;
_parent = null;
_children = new Vector();
_upNeighbor = null;
_downNeighbor = null;
_upSibling = false;
_downSibling = false;
_width = 0.0;
_height = 0.0;
}
public void calculatePosition( double[] ds,
double[] ds_0_ ) {
int i = _children.size();
if (i == 0) {
_absolutePosition = ds[_level] + 0.5 * _height;
ds[_level] += _height;
_relativePosition = ds_0_[_level] + 1.0;
ds_0_[_level] = _relativePosition;
} else {
double d = 0.0;
double d_1_ = 0.0;
for (int i_2_ = 0; i_2_ < i; i_2_++) {
TreeNode treenode_3_ = (TreeNode)_children.get(i_2_);
treenode_3_.calculatePosition(ds, ds_0_);
d = treenode_3_._absolutePosition;
d_1_ = treenode_3_._relativePosition;
}
int[] is = new int[1];
double[] ds_4_ = new double[2];
for (int i_5_ = i - 2; i_5_ >= 0; i_5_--) {
TreeNode treenode_6_ = (TreeNode)_children.get(i_5_);
is[0] = _level;
treenode_6_.calculateSpaceDown(is, ds_4_);
double d_7_ = ds_4_[0];
double d_8_ = ds_4_[1] - 1.0;
if (d_7_ < 0.0) d_7_ = 0.0;
if (d_8_ < 0.0) d_8_ = 0.0;
if (d_7_ > 0.0 || d_8_ > 0.0) {
treenode_6_.shiftDown(ds, ds_0_, d_7_, d_8_);
treenode_6_._absoluteSpaceLeft = d_7_;
treenode_6_._relativeSpaceLeft = d_8_;
}
}
TreeNode treenode_9_ = (TreeNode)_children.get(0);
_absolutePosition = 0.5 * (treenode_9_._absolutePosition + d);
_relativePosition = 0.5 * (treenode_9_._relativePosition + d_1_);
double d_10_ = treenode_9_._absoluteSpaceLeft;
double d_11_ = treenode_9_._relativeSpaceLeft;
for (int i_12_ = 1; i_12_ < i && treenode_9_._absoluteSpaceLeft > 0.0; i_12_++) {
treenode_9_._absoluteSpaceLeft -= d_10_;
if (treenode_9_._absoluteSpaceLeft < 0.0) treenode_9_._absoluteSpaceLeft = 0.0;
treenode_9_ = (TreeNode)_children.get(i_12_);
}
treenode_9_ = (TreeNode)_children.get(0);
for (int i_13_ = 1; i_13_ < i && treenode_9_._relativeSpaceLeft > 0.0; i_13_++) {
treenode_9_._relativeSpaceLeft -= d_11_;
if (treenode_9_._relativeSpaceLeft < 0.0) treenode_9_._relativeSpaceLeft = 0.0;
treenode_9_ = (TreeNode)_children.get(i_13_);
}
double d_14_ = ds[_level] + 0.5 * _height - _absolutePosition;
double d_15_ = ds_0_[_level] + 1.0 - _relativePosition;
if (d_14_ < 0.0) d_14_ = 0.0;
if (d_15_ < 0.0) d_15_ = 0.0;
if (d_14_ > 0.0 || d_15_ > 0.0) shiftDown(ds, ds_0_, d_14_, d_15_);
else {
ds[_level] = _absolutePosition + 0.5 * _height;
ds_0_[_level] = _relativePosition;
}
}
}
public void calculateSeparatePosition( double[] ds,
double[] ds_16_ ) {
int i = _children.size();
if (i == 0) {
_absolutePosition = ds[0] + 0.5 * _height;
ds[0] += _height;
_relativePosition = ds_16_[0] + 1.0;
ds_16_[0] = _relativePosition;
} else {
double d = ds[0];
double d_17_ = 0.0;
double d_18_ = 0.0;
for (int i_19_ = 0; i_19_ < i; i_19_++) {
TreeNode treenode_20_ = (TreeNode)_children.get(i_19_);
treenode_20_.calculateSeparatePosition(ds, ds_16_);
d_17_ = treenode_20_._absolutePosition;
d_18_ = treenode_20_._relativePosition;
}
TreeNode treenode_21_ = (TreeNode)_children.get(0);
_absolutePosition = 0.5 * (treenode_21_._absolutePosition + d_17_);
_relativePosition = 0.5 * (treenode_21_._relativePosition + d_18_);
d -= _absolutePosition - 0.5 * _height;
if (d > 0.0) shiftSeparateDown(ds, d);
ds[0] = Math.max(_absolutePosition + 0.5 * _height, ds[0]);
}
}
private void calculateSpaceDown( int[] is,
double[] ds ) {
double d = -1.0;
double d_22_ = -1.0;
if (_level > is[0]) {
is[0] = _level;
if (_downNeighbor != null) {
d = (_downNeighbor._absolutePosition - _absolutePosition - 0.5 * (_height + _downNeighbor._height));
d_22_ = _downNeighbor._relativePosition - _relativePosition;
if (d <= 0.0 && d_22_ <= 1.0) {
ds[0] = d;
ds[1] = d_22_;
return;
}
}
}
int i = _children.size();
for (int i_23_ = i - 1; i_23_ >= 0; i_23_--) {
TreeNode treenode_24_ = (TreeNode)_children.get(i_23_);
treenode_24_.calculateSpaceDown(is, ds);
if (ds[0] >= 0.0 && (ds[0] < d || d < 0.0)) d = ds[0];
if (ds[1] >= 1.0 && (ds[1] < d_22_ || d_22_ < 0.0)) d_22_ = ds[1];
if (d <= 0.0 && d_22_ <= 1.0) {
ds[0] = d;
ds[1] = d_22_;
return;
}
}
ds[0] = d;
ds[1] = d_22_;
}
private double absoluteSetEven( double d,
int i ) {
double d_25_ = 0.0;
double d_26_ = Math.min(d, _absoluteSpaceLeft);
if (_downSibling && _downNeighbor._absoluteSpaceLeft > 0.0) d_25_ = _downNeighbor.absoluteSetEven(d_26_, i + 1);
d_25_ += (d_26_ - d_25_) / (i + 1);
if (d_25_ > 0.0) shiftUpAbsolute(d_25_);
_absoluteSpaceLeft = 0.0;
return d_25_;
}
private double relativeSetEven( double d,
int i ) {
double d_27_ = 0.0;
double d_28_ = Math.min(d, _relativeSpaceLeft);
if (_downSibling && _downNeighbor._relativeSpaceLeft > 0.0) d_27_ = _downNeighbor.relativeSetEven(d_28_, i + 1);
d_27_ += (d_28_ - d_27_) / (i + 1);
if (d_27_ > 0.0) shiftUpRelative(d_27_);
_relativeSpaceLeft = 0.0;
return d_27_;
}
void getMaximumWidths( double[] ds ) {
ds[_level] = Math.max(ds[_level], _width);
int i = _children.size();
for (int i_29_ = 0; i_29_ < i; i_29_++)
((TreeNode)_children.get(i_29_)).getMaximumWidths(ds);
}
public void setEven() {
int i = _children.size();
for (int i_30_ = 0; i_30_ < i; i_30_++) {
TreeNode treenode_31_ = (TreeNode)_children.get(i_30_);
treenode_31_.setEven();
if (treenode_31_._absoluteSpaceLeft > 0.0) treenode_31_.absoluteSetEven(treenode_31_._absoluteSpaceLeft, 1);
if (treenode_31_._relativeSpaceLeft > 0.0) treenode_31_.relativeSetEven(treenode_31_._relativeSpaceLeft, 1);
}
}
public void addLinkToNode( TreeNode treenode_32_ ) {
int i = _children.size();
int i_33_;
for (i_33_ = 0; i_33_ < i && (((TreeNode)_children.get(i_33_))._orderVar < treenode_32_._orderVar); i_33_++) {
/* empty */
}
if (i_33_ >= i || (TreeNode)_children.get(i_33_) != treenode_32_) _children.add(i_33_, treenode_32_);
}
public void setNeighbors( TreeNode[] treenodes ) {
if (treenodes[_level] != null) {
_upNeighbor = treenodes[_level];
_upSibling = _upNeighbor._parent == _parent;
_upNeighbor._downNeighbor = this;
_upNeighbor._downSibling = _upSibling;
}
treenodes[_level] = this;
int i = _children.size();
for (int i_34_ = 0; i_34_ < i; i_34_++)
((TreeNode)_children.get(i_34_)).setNeighbors(treenodes);
}
public int setParent( TreeNode treenode_35_ ) throws NotATreeException {
if (_parent != null) throw new NotATreeException();
_parent = treenode_35_;
if (treenode_35_ != null) _level = treenode_35_._level + 1;
else _level = 0;
_children.remove(treenode_35_);
int i = _children.size();
int i_36_ = _level;
for (int i_37_ = 0; i_37_ < i; i_37_++)
i_36_ = Math.max(i_36_, ((TreeNode)_children.get(i_37_)).setParent(this));
return i_36_;
}
private void shiftDown( double[] ds,
double[] ds_47_,
double d,
double d_48_ ) {
_absolutePosition += d;
_relativePosition += d_48_;
ds[_level] = Math.max(ds[_level], _absolutePosition + 0.5 * _height);
ds_47_[_level] = Math.max(ds_47_[_level], _relativePosition);
int i = _children.size();
for (int i_49_ = 0; i_49_ < i; i_49_++)
((TreeNode)_children.get(i_49_)).shiftDown(ds, ds_47_, d, d_48_);
}
private void shiftSeparateDown( double[] ds,
double d ) {
_absolutePosition += d;
ds[0] = Math.max(ds[0], _absolutePosition + 0.5 * _height);
int i = _children.size();
for (int i_50_ = 0; i_50_ < i; i_50_++)
((TreeNode)_children.get(i_50_)).shiftSeparateDown(ds, d);
}
private void shiftUpAbsolute( double d ) {
_absolutePosition -= d;
int i = _children.size();
for (int i_51_ = 0; i_51_ < i; i_51_++)
((TreeNode)_children.get(i_51_)).shiftUpAbsolute(d);
}
private void shiftUpRelative( double d ) {
_relativePosition -= d;
int i = _children.size();
for (int i_52_ = 0; i_52_ < i; i_52_++)
((TreeNode)_children.get(i_52_)).shiftUpRelative(d);
}
}
private static class NotATreeException extends Exception {
/**
*/
private static final long serialVersionUID = 1L;
public NotATreeException() {
/* empty */
}
}
}