rm treelayout, add jar
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9150]
|
@ -1,169 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to configure the tree layout algorithm.
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
* @param <TreeNode>
|
|
||||||
*/
|
|
||||||
public interface Configuration<TreeNode> {
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// rootLocation
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Identifies the sides of a rectangle (top, left, ...)
|
|
||||||
*/
|
|
||||||
public enum Location {
|
|
||||||
Top, Left, Bottom, Right
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// alignmentInLevel
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the position of the root node in the diagram.
|
|
||||||
* <p>
|
|
||||||
* By default the root of the tree is located at the top of the diagram.
|
|
||||||
* However one may also put it at the left, right or bottom of the diagram.
|
|
||||||
* <p>
|
|
||||||
* <table border="1">
|
|
||||||
* <tr>
|
|
||||||
* <th>Top (Default)</th>
|
|
||||||
* <th>Left</th>
|
|
||||||
* <th>Right</th>
|
|
||||||
* <th>Bottom</th>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td style="padding:10px;"><img src="doc-files/TreeGraphView-Top.png"></td>
|
|
||||||
* <td style="padding:10px;"><img src="doc-files/TreeGraphView-Left.png"></td>
|
|
||||||
* <td style="padding:10px;"><img src="doc-files/TreeGraphView-Right.png"></td>
|
|
||||||
* <td style="padding:10px;"><img src="doc-files/TreeGraphView-Bottom.png"></td>
|
|
||||||
* </tr>
|
|
||||||
* </table>
|
|
||||||
*
|
|
||||||
* @return the position of the root node in the diagram
|
|
||||||
*/
|
|
||||||
Location getRootLocation();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Possible alignments of a node within a level (centered, towards or away
|
|
||||||
* from root)
|
|
||||||
*/
|
|
||||||
public enum AlignmentInLevel {
|
|
||||||
Center, TowardsRoot, AwayFromRoot
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the alignment of "smaller" nodes within a level.
|
|
||||||
* <p>
|
|
||||||
* By default all nodes of one level are centered in the level. However one
|
|
||||||
* may also align them "towards the root" or "away from the root". When the
|
|
||||||
* root is located at the top this means the nodes are aligned "to the top
|
|
||||||
* of the level" or "to the bottom of the level".
|
|
||||||
* <p>
|
|
||||||
* <table border="1">
|
|
||||||
* <tr>
|
|
||||||
* <th>Center (Default)</th>
|
|
||||||
* <th>TowardsRoot ("top of level")</th>
|
|
||||||
* <th>AwayFromRoot ("bottom of level")</th>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td style="padding:10px;"><img src="doc-files/TreeGraphView-Center.png"></td>
|
|
||||||
* <td style="padding:10px;"><img
|
|
||||||
* src="doc-files/TreeGraphView-TowardsRoot.png"></td>
|
|
||||||
* <td style="padding:10px;"><img
|
|
||||||
* src="doc-files/TreeGraphView-AwayFromRoot.png"></td>
|
|
||||||
* </tr>
|
|
||||||
* </table>
|
|
||||||
* <p>
|
|
||||||
* Alignment in level when root is at the left:
|
|
||||||
* </p>
|
|
||||||
* <table border="1">
|
|
||||||
* <tr>
|
|
||||||
* <th>Center (Default)</th>
|
|
||||||
* <th>TowardsRoot ("left of level")</th>
|
|
||||||
* <th>AwayFromRoot<br>
|
|
||||||
* ("right of level")</th>
|
|
||||||
* </tr>
|
|
||||||
* <tr>
|
|
||||||
* <td style="padding:10px;"><img
|
|
||||||
* src="doc-files/TreeGraphView-Center-RootLeft.png"></td>
|
|
||||||
* <td style="padding:10px;"><img
|
|
||||||
* src="doc-files/TreeGraphView-TowardsRoot-RootLeft.png"></td>
|
|
||||||
* <td style="padding:10px;"><img
|
|
||||||
* src="doc-files/TreeGraphView-AwayFromRoot-RootLeft.png"></td>
|
|
||||||
* </tr>
|
|
||||||
* </table>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Of cause the alignment also works when the root is at the bottom or at
|
|
||||||
* the right side.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return the alignment of "smaller" nodes within a level
|
|
||||||
*/
|
|
||||||
AlignmentInLevel getAlignmentInLevel();
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// gapBetweenLevels/Nodes
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the size of the gap between subsequent levels.
|
|
||||||
* <p>
|
|
||||||
* <img src="doc-files/gapBetweenLevels.png">
|
|
||||||
*
|
|
||||||
* @param nextLevel
|
|
||||||
* [nextLevel > 0]
|
|
||||||
*
|
|
||||||
* @return the size of the gap between level (nextLevel-1) and nextLevel
|
|
||||||
* [result >= 0]
|
|
||||||
*/
|
|
||||||
double getGapBetweenLevels(int nextLevel);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the size of the minimal gap of nodes within a level.
|
|
||||||
* <p>
|
|
||||||
* In the layout there will be a gap of at least the returned size between
|
|
||||||
* both given nodes.
|
|
||||||
* <p>
|
|
||||||
* <img src="doc-files/gapBetweenNodes.png">
|
|
||||||
* <p>
|
|
||||||
* node1 and node2 are at the same level and are placed next to each other.
|
|
||||||
*
|
|
||||||
* @param node1
|
|
||||||
* @param node2
|
|
||||||
* @return the minimal size of the gap between node1 and node2 [result >= 0]
|
|
||||||
*/
|
|
||||||
double getGapBetweenNodes(TreeNode node1, TreeNode node2);
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides the extent (width and height) of a tree node.
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
* @param <TreeNode>
|
|
||||||
*/
|
|
||||||
public interface NodeExtentProvider<TreeNode> {
|
|
||||||
/**
|
|
||||||
* Returns the width of the given treeNode.
|
|
||||||
*
|
|
||||||
* @param treeNode
|
|
||||||
* @return [result >= 0]
|
|
||||||
*/
|
|
||||||
double getWidth(TreeNode treeNode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the height of the given treeNode.
|
|
||||||
*
|
|
||||||
* @param treeNode
|
|
||||||
* @return [result >= 0]
|
|
||||||
*/
|
|
||||||
double getHeight(TreeNode treeNode);
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a tree to be used by the {@link TreeLayout}.
|
|
||||||
* <p>
|
|
||||||
* The TreeForTreeLayout interface is designed to best match the implemented
|
|
||||||
* layout algorithm and to ensure the algorithm's time complexity promises in
|
|
||||||
* all possible cases. However in most situation a client must not deal with all
|
|
||||||
* details of this interface and can directly use the
|
|
||||||
* {@link org.abego.treelayout.util.AbstractTreeForTreeLayout} to implement this
|
|
||||||
* interface or even use the
|
|
||||||
* {@link org.abego.treelayout.util.DefaultTreeForTreeLayout} class directly.
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
* @param <TreeNode>
|
|
||||||
*/
|
|
||||||
public interface TreeForTreeLayout<TreeNode> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the the root of the tree.
|
|
||||||
* <p>
|
|
||||||
* Time Complexity: O(1)
|
|
||||||
*
|
|
||||||
* @return the root of the tree
|
|
||||||
*/
|
|
||||||
TreeNode getRoot();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells if a node is a leaf in the tree.
|
|
||||||
* <p>
|
|
||||||
* Time Complexity: O(1)
|
|
||||||
*
|
|
||||||
* @param node
|
|
||||||
* @return true iff node is a leaf in the tree, i.e. has no children.
|
|
||||||
*/
|
|
||||||
boolean isLeaf(TreeNode node);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells if a node is a child of a given parentNode.
|
|
||||||
* <p>
|
|
||||||
* Time Complexity: O(1)
|
|
||||||
*
|
|
||||||
* @param node
|
|
||||||
* @param parentNode
|
|
||||||
* @return true iff the node is a child of the given parentNode
|
|
||||||
*/
|
|
||||||
boolean isChildOfParent(TreeNode node, TreeNode parentNode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the children of a parent node.
|
|
||||||
* <p>
|
|
||||||
* Time Complexity: O(1)
|
|
||||||
*
|
|
||||||
* @param parentNode
|
|
||||||
* [!isLeaf(parentNode)]
|
|
||||||
* @return the children of the given parentNode, from first to last
|
|
||||||
*/
|
|
||||||
Iterable<TreeNode> getChildren(TreeNode parentNode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the children of a parent node, in reverse order.
|
|
||||||
* <p>
|
|
||||||
* Time Complexity: O(1)
|
|
||||||
*
|
|
||||||
* @param parentNode
|
|
||||||
* [!isLeaf(parentNode)]
|
|
||||||
* @return the children of given parentNode, from last to first
|
|
||||||
*/
|
|
||||||
Iterable<TreeNode> getChildrenReverse(TreeNode parentNode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the first child of a parent node.
|
|
||||||
* <p>
|
|
||||||
* Time Complexity: O(1)
|
|
||||||
*
|
|
||||||
* @param parentNode
|
|
||||||
* [!isLeaf(parentNode)]
|
|
||||||
* @return the first child of the parentNode
|
|
||||||
*/
|
|
||||||
TreeNode getFirstChild(TreeNode parentNode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the last child of a parent node.
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* Time Complexity: O(1)
|
|
||||||
*
|
|
||||||
* @param parentNode
|
|
||||||
* [!isLeaf(parentNode)]
|
|
||||||
* @return the last child of the parentNode
|
|
||||||
*/
|
|
||||||
TreeNode getLastChild(TreeNode parentNode);
|
|
||||||
}
|
|
|
@ -1,732 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.abego.treelayout;
|
|
||||||
|
|
||||||
import static org.abego.treelayout.internal.util.Contract.checkArg;
|
|
||||||
|
|
||||||
import java.awt.geom.Point2D;
|
|
||||||
import java.awt.geom.Rectangle2D;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import org.abego.treelayout.Configuration.AlignmentInLevel;
|
|
||||||
import org.abego.treelayout.Configuration.Location;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements the actual tree layout algorithm.
|
|
||||||
* <p>
|
|
||||||
* The nodes with their final layout can be retrieved through
|
|
||||||
* {@link #getNodeBounds()}.
|
|
||||||
* <p>
|
|
||||||
* See <a href="package-summary.html">this summary</a> to get an overview how to
|
|
||||||
* use TreeLayout.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
* @param <TreeNode>
|
|
||||||
*/
|
|
||||||
public class TreeLayout<TreeNode> {
|
|
||||||
/*
|
|
||||||
* Differences between this implementation and original algorithm
|
|
||||||
* --------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* For easier reference the same names (or at least similar names) as in the
|
|
||||||
* paper of Buchheim, Jünger, and Leipert are used in this
|
|
||||||
* implementation. However in the external interface "first" and "last" are
|
|
||||||
* used instead of "left most" and "right most". The implementation also
|
|
||||||
* supports tree layouts with the root at the left (or right) side. In that
|
|
||||||
* case using "left most" would refer to the "top" child, i.e. using "first"
|
|
||||||
* is less confusing.
|
|
||||||
*
|
|
||||||
* Also the y coordinate is not the level but directly refers the y
|
|
||||||
* coordinate of a level, taking node's height and gapBetweenLevels into
|
|
||||||
* account. When the root is at the left or right side the y coordinate
|
|
||||||
* actually becomes an x coordinate.
|
|
||||||
*
|
|
||||||
* Instead of just using a constant "distance" to calculate the position to
|
|
||||||
* the next node we refer to the "size" (width or height) of the node and a
|
|
||||||
* "gapBetweenNodes".
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// tree
|
|
||||||
|
|
||||||
private final TreeForTreeLayout<TreeNode> tree;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Tree the layout is created for.
|
|
||||||
*/
|
|
||||||
public TreeForTreeLayout<TreeNode> getTree() {
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// nodeExtentProvider
|
|
||||||
|
|
||||||
private final NodeExtentProvider<TreeNode> nodeExtentProvider;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link NodeExtentProvider} used by this {@link TreeLayout}.
|
|
||||||
*/
|
|
||||||
public NodeExtentProvider<TreeNode> getNodeExtentProvider() {
|
|
||||||
return nodeExtentProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
private double getNodeHeight(TreeNode node) {
|
|
||||||
return nodeExtentProvider.getHeight(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
private double getNodeWidth(TreeNode node) {
|
|
||||||
return nodeExtentProvider.getWidth(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
private double getWidthOrHeightOfNode(TreeNode treeNode, boolean returnWidth) {
|
|
||||||
return returnWidth ? getNodeWidth(treeNode) : getNodeHeight(treeNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When the level changes in Y-axis (i.e. root location Top or Bottom) the
|
|
||||||
* height of a node is its thickness, otherwise the node's width is its
|
|
||||||
* thickness.
|
|
||||||
* <p>
|
|
||||||
* The thickness of a node is used when calculating the locations of the
|
|
||||||
* levels.
|
|
||||||
*
|
|
||||||
* @param treeNode
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private double getNodeThickness(TreeNode treeNode) {
|
|
||||||
return getWidthOrHeightOfNode(treeNode, !isLevelChangeInYAxis());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When the level changes in Y-axis (i.e. root location Top or Bottom) the
|
|
||||||
* width of a node is its size, otherwise the node's height is its size.
|
|
||||||
* <p>
|
|
||||||
* The size of a node is used when calculating the distance between two
|
|
||||||
* nodes.
|
|
||||||
*
|
|
||||||
* @param treeNode
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private double getNodeSize(TreeNode treeNode) {
|
|
||||||
return getWidthOrHeightOfNode(treeNode, isLevelChangeInYAxis());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// configuration
|
|
||||||
|
|
||||||
private final Configuration<TreeNode> configuration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Configuration used by this {@link TreeLayout}.
|
|
||||||
*/
|
|
||||||
public Configuration<TreeNode> getConfiguration() {
|
|
||||||
return configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isLevelChangeInYAxis() {
|
|
||||||
Location rootLocation = configuration.getRootLocation();
|
|
||||||
return rootLocation == Location.Top || rootLocation == Location.Bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getLevelChangeSign() {
|
|
||||||
Location rootLocation = configuration.getRootLocation();
|
|
||||||
return rootLocation == Location.Bottom
|
|
||||||
|| rootLocation == Location.Right ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// bounds
|
|
||||||
|
|
||||||
private double boundsLeft = Double.MAX_VALUE;
|
|
||||||
private double boundsRight = Double.MIN_VALUE;
|
|
||||||
private double boundsTop = Double.MAX_VALUE;
|
|
||||||
private double boundsBottom = Double.MIN_VALUE;
|
|
||||||
|
|
||||||
private void updateBounds(TreeNode node, double centerX, double centerY) {
|
|
||||||
double width = getNodeWidth(node);
|
|
||||||
double height = getNodeHeight(node);
|
|
||||||
double left = centerX - width / 2;
|
|
||||||
double right = centerX + width / 2;
|
|
||||||
double top = centerY - height / 2;
|
|
||||||
double bottom = centerY + height / 2;
|
|
||||||
if (boundsLeft > left) {
|
|
||||||
boundsLeft = left;
|
|
||||||
}
|
|
||||||
if (boundsRight < right) {
|
|
||||||
boundsRight = right;
|
|
||||||
}
|
|
||||||
if (boundsTop > top) {
|
|
||||||
boundsTop = top;
|
|
||||||
}
|
|
||||||
if (boundsBottom < bottom) {
|
|
||||||
boundsBottom = bottom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the bounds of the tree layout.
|
|
||||||
* <p>
|
|
||||||
* The bounds of a TreeLayout is the smallest rectangle containing the
|
|
||||||
* bounds of all nodes in the layout. It always starts at (0,0).
|
|
||||||
*
|
|
||||||
* @return the bounds of the tree layout
|
|
||||||
*/
|
|
||||||
public Rectangle2D getBounds() {
|
|
||||||
return new Rectangle2D.Double(0, 0, boundsRight - boundsLeft,
|
|
||||||
boundsBottom - boundsTop);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// size of level
|
|
||||||
|
|
||||||
private final List<Double> sizeOfLevel = new ArrayList<Double>();
|
|
||||||
|
|
||||||
private void calcSizeOfLevels(TreeNode node, int level) {
|
|
||||||
double oldSize;
|
|
||||||
if (sizeOfLevel.size() <= level) {
|
|
||||||
sizeOfLevel.add(Double.valueOf(0));
|
|
||||||
oldSize = 0;
|
|
||||||
} else {
|
|
||||||
oldSize = sizeOfLevel.get(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
double size = getNodeThickness(node);
|
|
||||||
// size = nodeExtentProvider.getHeight(node);
|
|
||||||
if (oldSize < size) {
|
|
||||||
sizeOfLevel.set(level, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tree.isLeaf(node)) {
|
|
||||||
for (TreeNode child : tree.getChildren(node)) {
|
|
||||||
calcSizeOfLevels(child, level + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of levels of the tree.
|
|
||||||
*
|
|
||||||
* @return [level > 0]
|
|
||||||
*/
|
|
||||||
public int getLevelCount() {
|
|
||||||
return sizeOfLevel.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the size of a level.
|
|
||||||
* <p>
|
|
||||||
* When the root is located at the top or bottom the size of a level is the
|
|
||||||
* maximal height of the nodes of that level. When the root is located at
|
|
||||||
* the left or right the size of a level is the maximal width of the nodes
|
|
||||||
* of that level.
|
|
||||||
*
|
|
||||||
* @param level
|
|
||||||
* @return the size of the level [level >= 0 && level < levelCount]
|
|
||||||
*/
|
|
||||||
public double getSizeOfLevel(int level) {
|
|
||||||
checkArg(level >= 0, "level must be >= 0");
|
|
||||||
checkArg(level < getLevelCount(), "level must be < levelCount");
|
|
||||||
|
|
||||||
return sizeOfLevel.get(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// NormalizedPosition
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The algorithm calculates the position starting with the root at 0. I.e.
|
|
||||||
* the left children will get negative positions. However we want the result
|
|
||||||
* to be normalized to (0,0).
|
|
||||||
* <p>
|
|
||||||
* {@link NormalizedPosition} will normalize the position (given relative to
|
|
||||||
* the root position), taking the current bounds into account. This way the
|
|
||||||
* left most node bounds will start at x = 0, the top most node bounds at y
|
|
||||||
* = 0.
|
|
||||||
*/
|
|
||||||
private class NormalizedPosition extends Point2D {
|
|
||||||
private double x_relativeToRoot;
|
|
||||||
private double y_relativeToRoot;
|
|
||||||
|
|
||||||
public NormalizedPosition(double x_relativeToRoot,
|
|
||||||
double y_relativeToRoot) {
|
|
||||||
setLocation(x_relativeToRoot, y_relativeToRoot);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getX() {
|
|
||||||
return x_relativeToRoot - boundsLeft;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getY() {
|
|
||||||
return y_relativeToRoot - boundsTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
// never called from outside
|
|
||||||
public void setLocation(double x_relativeToRoot, double y_relativeToRoot) {
|
|
||||||
this.x_relativeToRoot = x_relativeToRoot;
|
|
||||||
this.y_relativeToRoot = y_relativeToRoot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// The Algorithm
|
|
||||||
|
|
||||||
private final Map<TreeNode, Double> mod = new HashMap<TreeNode, Double>();
|
|
||||||
private final Map<TreeNode, TreeNode> thread = new HashMap<TreeNode, TreeNode>();
|
|
||||||
private final Map<TreeNode, Double> prelim = new HashMap<TreeNode, Double>();
|
|
||||||
private final Map<TreeNode, Double> change = new HashMap<TreeNode, Double>();
|
|
||||||
private final Map<TreeNode, Double> shift = new HashMap<TreeNode, Double>();
|
|
||||||
private final Map<TreeNode, TreeNode> ancestor = new HashMap<TreeNode, TreeNode>();
|
|
||||||
private final Map<TreeNode, Integer> number = new HashMap<TreeNode, Integer>();
|
|
||||||
private final Map<TreeNode, Point2D> positions = new HashMap<TreeNode, Point2D>();
|
|
||||||
|
|
||||||
private double getMod(TreeNode node) {
|
|
||||||
Double d = mod.get(node);
|
|
||||||
return d != null ? d.doubleValue() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setMod(TreeNode node, double d) {
|
|
||||||
mod.put(node, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TreeNode getThread(TreeNode node) {
|
|
||||||
TreeNode n = thread.get(node);
|
|
||||||
return n != null ? n : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setThread(TreeNode node, TreeNode thread) {
|
|
||||||
this.thread.put(node, thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TreeNode getAncestor(TreeNode node) {
|
|
||||||
TreeNode n = ancestor.get(node);
|
|
||||||
return n != null ? n : node;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setAncestor(TreeNode node, TreeNode ancestor) {
|
|
||||||
this.ancestor.put(node, ancestor);
|
|
||||||
}
|
|
||||||
|
|
||||||
private double getPrelim(TreeNode node) {
|
|
||||||
Double d = prelim.get(node);
|
|
||||||
return d != null ? d.doubleValue() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setPrelim(TreeNode node, double d) {
|
|
||||||
prelim.put(node, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
private double getChange(TreeNode node) {
|
|
||||||
Double d = change.get(node);
|
|
||||||
return d != null ? d.doubleValue() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setChange(TreeNode node, double d) {
|
|
||||||
change.put(node, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
private double getShift(TreeNode node) {
|
|
||||||
Double d = shift.get(node);
|
|
||||||
return d != null ? d.doubleValue() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setShift(TreeNode node, double d) {
|
|
||||||
shift.put(node, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The distance of two nodes is the distance of the centers of both noded.
|
|
||||||
* <p>
|
|
||||||
* I.e. the distance includes the gap between the nodes and half of the
|
|
||||||
* sizes of the nodes.
|
|
||||||
*
|
|
||||||
* @param v
|
|
||||||
* @param w
|
|
||||||
* @return the distance between node v and w
|
|
||||||
*/
|
|
||||||
private double getDistance(TreeNode v, TreeNode w) {
|
|
||||||
double sizeOfNodes = getNodeSize(v) + getNodeSize(w);
|
|
||||||
|
|
||||||
double distance = sizeOfNodes / 2
|
|
||||||
+ configuration.getGapBetweenNodes(v, w);
|
|
||||||
return distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TreeNode nextLeft(TreeNode v) {
|
|
||||||
return tree.isLeaf(v) ? getThread(v) : tree.getFirstChild(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TreeNode nextRight(TreeNode v) {
|
|
||||||
return tree.isLeaf(v) ? getThread(v) : tree.getLastChild(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param node
|
|
||||||
* [tree.isChildOfParent(node, parentNode)]
|
|
||||||
* @param parentNode
|
|
||||||
* parent of node
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private int getNumber(TreeNode node, TreeNode parentNode) {
|
|
||||||
Integer n = number.get(node);
|
|
||||||
if (n == null) {
|
|
||||||
int i = 1;
|
|
||||||
for (TreeNode child : tree.getChildren(parentNode)) {
|
|
||||||
number.put(child, i++);
|
|
||||||
}
|
|
||||||
n = number.get(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
return n.intValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param vIMinus
|
|
||||||
* @param v
|
|
||||||
* @param parentOfV
|
|
||||||
* @param defaultAncestor
|
|
||||||
* @return the greatest distinct ancestor of vIMinus and its right neighbor
|
|
||||||
* v
|
|
||||||
*/
|
|
||||||
private TreeNode ancestor(TreeNode vIMinus, TreeNode v, TreeNode parentOfV,
|
|
||||||
TreeNode defaultAncestor) {
|
|
||||||
TreeNode ancestor = getAncestor(vIMinus);
|
|
||||||
|
|
||||||
// when the ancestor of vIMinus is a sibling of v (i.e. has the same
|
|
||||||
// parent as v) it is also the greatest distinct ancestor vIMinus and
|
|
||||||
// v. Otherwise it is the defaultAncestor
|
|
||||||
|
|
||||||
return tree.isChildOfParent(ancestor, parentOfV) ? ancestor
|
|
||||||
: defaultAncestor;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void moveSubtree(TreeNode wMinus, TreeNode wPlus, TreeNode parent,
|
|
||||||
double shift) {
|
|
||||||
|
|
||||||
int subtrees = getNumber(wPlus, parent) - getNumber(wMinus, parent);
|
|
||||||
setChange(wPlus, getChange(wPlus) - shift / subtrees);
|
|
||||||
setShift(wPlus, getShift(wPlus) + shift);
|
|
||||||
setChange(wMinus, getChange(wMinus) + shift / subtrees);
|
|
||||||
setPrelim(wPlus, getPrelim(wPlus) + shift);
|
|
||||||
setMod(wPlus, getMod(wPlus) + shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In difference to the original algorithm we also pass in the leftSibling
|
|
||||||
* and the parent of v.
|
|
||||||
* <p>
|
|
||||||
* <b>Why adding the parameter 'parent of v' (parentOfV) ?</b>
|
|
||||||
* <p>
|
|
||||||
* In this method we need access to the parent of v. Not every tree
|
|
||||||
* implementation may support efficient (i.e. constant time) access to it.
|
|
||||||
* On the other hand the (only) caller of this method can provide this
|
|
||||||
* information with only constant extra time.
|
|
||||||
* <p>
|
|
||||||
* Also we need access to the "left most sibling" of v. Not every tree
|
|
||||||
* implementation may support efficient (i.e. constant time) access to it.
|
|
||||||
* On the other hand the "left most sibling" of v is also the "first child"
|
|
||||||
* of the parent of v. The first child of a parent node we can get in
|
|
||||||
* constant time. As we got the parent of v we can so also get the
|
|
||||||
* "left most sibling" of v in constant time.
|
|
||||||
* <p>
|
|
||||||
* <b>Why adding the parameter 'leftSibling' ?</b>
|
|
||||||
* <p>
|
|
||||||
* In this method we need access to the "left sibling" of v. Not every tree
|
|
||||||
* implementation may support efficient (i.e. constant time) access to it.
|
|
||||||
* However it is easy for the caller of this method to provide this
|
|
||||||
* information with only constant extra time.
|
|
||||||
* <p>
|
|
||||||
* <p>
|
|
||||||
* <p>
|
|
||||||
* In addition these extra parameters avoid the need for
|
|
||||||
* {@link TreeForTreeLayout} to include extra methods "getParent",
|
|
||||||
* "getLeftSibling", or "getLeftMostSibling". This keeps the interface
|
|
||||||
* {@link TreeForTreeLayout} small and avoids redundant implementations.
|
|
||||||
*
|
|
||||||
* @param v
|
|
||||||
* @param defaultAncestor
|
|
||||||
* @param leftSibling
|
|
||||||
* [nullable] the left sibling v, if there is any
|
|
||||||
* @param parentOfV
|
|
||||||
* the parent of v
|
|
||||||
* @return the (possibly changes) defaultAncestor
|
|
||||||
*/
|
|
||||||
private TreeNode apportion(TreeNode v, TreeNode defaultAncestor,
|
|
||||||
TreeNode leftSibling, TreeNode parentOfV) {
|
|
||||||
TreeNode w = leftSibling;
|
|
||||||
if (w == null) {
|
|
||||||
// v has no left sibling
|
|
||||||
return defaultAncestor;
|
|
||||||
}
|
|
||||||
// v has left sibling w
|
|
||||||
|
|
||||||
// The following variables "v..." are used to traverse the contours to
|
|
||||||
// the subtrees. "Minus" refers to the left, "Plus" to the right
|
|
||||||
// subtree. "I" refers to the "inside" and "O" to the outside contour.
|
|
||||||
TreeNode vOPlus = v;
|
|
||||||
TreeNode vIPlus = v;
|
|
||||||
TreeNode vIMinus = w;
|
|
||||||
// get leftmost sibling of vIPlus, i.e. get the leftmost sibling of
|
|
||||||
// v, i.e. the leftmost child of the parent of v (which is passed
|
|
||||||
// in)
|
|
||||||
TreeNode vOMinus = tree.getFirstChild(parentOfV);
|
|
||||||
|
|
||||||
Double sIPlus = getMod(vIPlus);
|
|
||||||
Double sOPlus = getMod(vOPlus);
|
|
||||||
Double sIMinus = getMod(vIMinus);
|
|
||||||
Double sOMinus = getMod(vOMinus);
|
|
||||||
|
|
||||||
TreeNode nextRightVIMinus = nextRight(vIMinus);
|
|
||||||
TreeNode nextLeftVIPlus = nextLeft(vIPlus);
|
|
||||||
|
|
||||||
while (nextRightVIMinus != null && nextLeftVIPlus != null) {
|
|
||||||
vIMinus = nextRightVIMinus;
|
|
||||||
vIPlus = nextLeftVIPlus;
|
|
||||||
vOMinus = nextLeft(vOMinus);
|
|
||||||
vOPlus = nextRight(vOPlus);
|
|
||||||
setAncestor(vOPlus, v);
|
|
||||||
double shift = (getPrelim(vIMinus) + sIMinus)
|
|
||||||
- (getPrelim(vIPlus) + sIPlus)
|
|
||||||
+ getDistance(vIMinus, vIPlus);
|
|
||||||
|
|
||||||
if (shift > 0) {
|
|
||||||
moveSubtree(ancestor(vIMinus, v, parentOfV, defaultAncestor),
|
|
||||||
v, parentOfV, shift);
|
|
||||||
sIPlus = sIPlus + shift;
|
|
||||||
sOPlus = sOPlus + shift;
|
|
||||||
}
|
|
||||||
sIMinus = sIMinus + getMod(vIMinus);
|
|
||||||
sIPlus = sIPlus + getMod(vIPlus);
|
|
||||||
sOMinus = sOMinus + getMod(vOMinus);
|
|
||||||
sOPlus = sOPlus + getMod(vOPlus);
|
|
||||||
|
|
||||||
nextRightVIMinus = nextRight(vIMinus);
|
|
||||||
nextLeftVIPlus = nextLeft(vIPlus);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextRightVIMinus != null && nextRight(vOPlus) == null) {
|
|
||||||
setThread(vOPlus, nextRightVIMinus);
|
|
||||||
setMod(vOPlus, getMod(vOPlus) + sIMinus - sOPlus);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextLeftVIPlus != null && nextLeft(vOMinus) == null) {
|
|
||||||
setThread(vOMinus, nextLeftVIPlus);
|
|
||||||
setMod(vOMinus, getMod(vOMinus) + sIPlus - sOMinus);
|
|
||||||
defaultAncestor = v;
|
|
||||||
}
|
|
||||||
return defaultAncestor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param v
|
|
||||||
* [!tree.isLeaf(v)]
|
|
||||||
*/
|
|
||||||
private void executeShifts(TreeNode v) {
|
|
||||||
double shift = 0;
|
|
||||||
double change = 0;
|
|
||||||
for (TreeNode w : tree.getChildrenReverse(v)) {
|
|
||||||
change = change + getChange(w);
|
|
||||||
setPrelim(w, getPrelim(w) + shift);
|
|
||||||
setMod(w, getMod(w) + shift);
|
|
||||||
shift = shift + getShift(w) + change;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In difference to the original algorithm we also pass in the leftSibling
|
|
||||||
* (see {@link #apportion(Object, Object, Object, Object)} for a
|
|
||||||
* motivation).
|
|
||||||
*
|
|
||||||
* @param v
|
|
||||||
* @param leftSibling
|
|
||||||
* [nullable] the left sibling v, if there is any
|
|
||||||
*/
|
|
||||||
private void firstWalk(TreeNode v, TreeNode leftSibling) {
|
|
||||||
if (tree.isLeaf(v)) {
|
|
||||||
// No need to set prelim(v) to 0 as the getter takes care of this.
|
|
||||||
|
|
||||||
TreeNode w = leftSibling;
|
|
||||||
if (w != null) {
|
|
||||||
// v has left sibling
|
|
||||||
|
|
||||||
setPrelim(v, getPrelim(w) + getDistance(v, w));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// v is not a leaf
|
|
||||||
|
|
||||||
TreeNode defaultAncestor = tree.getFirstChild(v);
|
|
||||||
TreeNode previousChild = null;
|
|
||||||
for (TreeNode w : tree.getChildren(v)) {
|
|
||||||
firstWalk(w, previousChild);
|
|
||||||
defaultAncestor = apportion(w, defaultAncestor, previousChild,
|
|
||||||
v);
|
|
||||||
previousChild = w;
|
|
||||||
}
|
|
||||||
executeShifts(v);
|
|
||||||
double midpoint = (getPrelim(tree.getFirstChild(v)) + getPrelim(tree
|
|
||||||
.getLastChild(v))) / 2.0;
|
|
||||||
TreeNode w = leftSibling;
|
|
||||||
if (w != null) {
|
|
||||||
// v has left sibling
|
|
||||||
|
|
||||||
setPrelim(v, getPrelim(w) + getDistance(v, w));
|
|
||||||
setMod(v, getPrelim(v) - midpoint);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// v has no left sibling
|
|
||||||
|
|
||||||
setPrelim(v, midpoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In difference to the original algorithm we also pass in extra level
|
|
||||||
* information.
|
|
||||||
*
|
|
||||||
* @param v
|
|
||||||
* @param m
|
|
||||||
* @param level
|
|
||||||
* @param levelStart
|
|
||||||
*/
|
|
||||||
private void secondWalk(TreeNode v, double m, int level, double levelStart) {
|
|
||||||
// construct the position from the prelim and the level information
|
|
||||||
|
|
||||||
// The rootLocation affects the way how x and y are changed and in what
|
|
||||||
// direction.
|
|
||||||
double levelChangeSign = getLevelChangeSign();
|
|
||||||
boolean levelChangeOnYAxis = isLevelChangeInYAxis();
|
|
||||||
double levelSize = getSizeOfLevel(level);
|
|
||||||
|
|
||||||
double x = getPrelim(v) + m;
|
|
||||||
|
|
||||||
double y;
|
|
||||||
AlignmentInLevel alignment = configuration.getAlignmentInLevel();
|
|
||||||
if (alignment == AlignmentInLevel.Center) {
|
|
||||||
y = levelStart + levelChangeSign * (levelSize / 2);
|
|
||||||
} else if (alignment == AlignmentInLevel.TowardsRoot) {
|
|
||||||
y = levelStart + levelChangeSign * (getNodeThickness(v) / 2);
|
|
||||||
} else {
|
|
||||||
y = levelStart + levelSize - levelChangeSign
|
|
||||||
* (getNodeThickness(v) / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!levelChangeOnYAxis) {
|
|
||||||
double t = x;
|
|
||||||
x = y;
|
|
||||||
y = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
positions.put(v, new NormalizedPosition(x, y));
|
|
||||||
|
|
||||||
// update the bounds
|
|
||||||
updateBounds(v, x, y);
|
|
||||||
|
|
||||||
// recurse
|
|
||||||
if (!tree.isLeaf(v)) {
|
|
||||||
double nextLevelStart = levelStart
|
|
||||||
+ (levelSize + configuration.getGapBetweenLevels(level + 1))
|
|
||||||
* levelChangeSign;
|
|
||||||
for (TreeNode w : tree.getChildren(v)) {
|
|
||||||
secondWalk(w, m + getMod(v), level + 1, nextLevelStart);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// nodeBounds
|
|
||||||
|
|
||||||
private Map<TreeNode, Rectangle2D.Double> nodeBounds;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the layout of the tree nodes by mapping each node of the tree to
|
|
||||||
* its bounds (position and size).
|
|
||||||
* <p>
|
|
||||||
* For each rectangle x and y will be >= 0. At least one rectangle will have
|
|
||||||
* an x == 0 and at least one rectangle will have an y == 0.
|
|
||||||
*
|
|
||||||
* @return maps each node of the tree to its bounds (position and size).
|
|
||||||
*/
|
|
||||||
public Map<TreeNode, Rectangle2D.Double> getNodeBounds() {
|
|
||||||
if (nodeBounds == null) {
|
|
||||||
nodeBounds = new HashMap<TreeNode, Rectangle2D.Double>();
|
|
||||||
for (Entry<TreeNode, Point2D> entry : positions.entrySet()) {
|
|
||||||
TreeNode node = entry.getKey();
|
|
||||||
Point2D pos = entry.getValue();
|
|
||||||
double w = getNodeWidth(node);
|
|
||||||
double h = getNodeHeight(node);
|
|
||||||
double x = pos.getX() - w / 2;
|
|
||||||
double y = pos.getY() - h / 2;
|
|
||||||
nodeBounds.put(node, new Rectangle2D.Double(x, y, w, h));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nodeBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// constructor
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a TreeLayout for a given tree.
|
|
||||||
* <p>
|
|
||||||
* In addition to the tree the {@link NodeExtentProvider} and the
|
|
||||||
* {@link Configuration} must be given.
|
|
||||||
*/
|
|
||||||
public TreeLayout(TreeForTreeLayout<TreeNode> tree,
|
|
||||||
NodeExtentProvider<TreeNode> nodeExtentProvider,
|
|
||||||
Configuration<TreeNode> configuration) {
|
|
||||||
this.tree = tree;
|
|
||||||
this.nodeExtentProvider = nodeExtentProvider;
|
|
||||||
this.configuration = configuration;
|
|
||||||
|
|
||||||
// No need to explicitly set mod, thread and ancestor as their getters
|
|
||||||
// are taking care of the initial values. This avoids a full tree walk
|
|
||||||
// through and saves some memory as no entries are added for
|
|
||||||
// "initial values".
|
|
||||||
|
|
||||||
TreeNode r = tree.getRoot();
|
|
||||||
firstWalk(r, null);
|
|
||||||
calcSizeOfLevels(r, 0);
|
|
||||||
secondWalk(r, -getPrelim(r), 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
[The "BSD license"]
|
|
||||||
Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from this
|
|
||||||
software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 17 KiB |
|
@ -1,46 +0,0 @@
|
||||||
<?xml version="1.0" standalone="no" ?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
|
||||||
<svg width="260" height="176" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
||||||
<line x1="177" y1="10" x2="110" y2="80" style="stroke:black; stroke-width:2px;" />
|
|
||||||
<line x1="110" y1="80" x2="40" y2="158" style="stroke:black; stroke-width:2px;" />
|
|
||||||
<line x1="110" y1="80" x2="110" y2="158" style="stroke:black; stroke-width:2px;" />
|
|
||||||
<line x1="110" y1="80" x2="180" y2="158" style="stroke:black; stroke-width:2px;" />
|
|
||||||
<line x1="177" y1="10" x2="245" y2="80" style="stroke:black; stroke-width:2px;" />
|
|
||||||
<line x1="245" y1="80" x2="245" y2="158" style="stroke:black; stroke-width:2px;" />
|
|
||||||
<rect x="91" y="149" width="38" height="18" style="fill:orange; stroke:rgb(0,0,0);" rx="10"/>
|
|
||||||
<text x="98" y="161" style="font-family:sans-serif;font-size:12px;">
|
|
||||||
n1.2
|
|
||||||
</text>
|
|
||||||
<rect x="1" y="141" width="78" height="34" style="fill:orange; stroke:rgb(0,0,0);" rx="10"/>
|
|
||||||
<text x="8" y="153" style="font-family:sans-serif;font-size:12px;">
|
|
||||||
n1.1
|
|
||||||
</text>
|
|
||||||
<text x="8" y="165" style="font-family:sans-serif;font-size:12px;">
|
|
||||||
(first node)
|
|
||||||
</text>
|
|
||||||
<rect x="231" y="71" width="28" height="18" style="fill:orange; stroke:rgb(0,0,0);" rx="10"/>
|
|
||||||
<text x="238" y="83" style="font-family:sans-serif;font-size:12px;">
|
|
||||||
n2
|
|
||||||
</text>
|
|
||||||
<rect x="158" y="1" width="38" height="18" style="fill:orange; stroke:rgb(0,0,0);" rx="10"/>
|
|
||||||
<text x="165" y="13" style="font-family:sans-serif;font-size:12px;">
|
|
||||||
root
|
|
||||||
</text>
|
|
||||||
<rect x="231" y="149" width="28" height="18" style="fill:orange; stroke:rgb(0,0,0);" rx="10"/>
|
|
||||||
<text x="238" y="161" style="font-family:sans-serif;font-size:12px;">
|
|
||||||
n2
|
|
||||||
</text>
|
|
||||||
<rect x="96" y="71" width="28" height="18" style="fill:orange; stroke:rgb(0,0,0);" rx="10"/>
|
|
||||||
<text x="103" y="83" style="font-family:sans-serif;font-size:12px;">
|
|
||||||
n1
|
|
||||||
</text>
|
|
||||||
<rect x="141" y="141" width="78" height="34" style="fill:orange; stroke:rgb(0,0,0);" rx="10"/>
|
|
||||||
<text x="148" y="153" style="font-family:sans-serif;font-size:12px;">
|
|
||||||
n1.3
|
|
||||||
</text>
|
|
||||||
<text x="148" y="165" style="font-family:sans-serif;font-size:12px;">
|
|
||||||
(last node)
|
|
||||||
</text>
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 2.1 KiB |
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout.internal.util;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A set of methods to support some sort of "Design by Contract" programming.
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class Contract {
|
|
||||||
|
|
||||||
public static void checkArg(boolean isOK, String s) {
|
|
||||||
if (!isOK) {
|
|
||||||
throw new IllegalArgumentException(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkState(boolean isOK, String s) {
|
|
||||||
if (!isOK) {
|
|
||||||
throw new IllegalStateException(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout.internal.util.java.lang;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.abego.treelayout.internal.util.java.util.IteratorUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Util (general purpose) methods dealing with {@link Iterable}.
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class IterableUtil {
|
|
||||||
private static class ReverseIterable<T> implements Iterable<T> {
|
|
||||||
private List<T> list;
|
|
||||||
|
|
||||||
public ReverseIterable(List<T> list) {
|
|
||||||
this.list = list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<T> iterator() {
|
|
||||||
return IteratorUtil.createReverseIterator(list);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an {@link Iterable} with an iterator iterating the given list
|
|
||||||
* from the end to the start.
|
|
||||||
* <p>
|
|
||||||
* I.e. the iterator does the reverse of the {@link List#iterator()}.
|
|
||||||
*
|
|
||||||
* @param <T>
|
|
||||||
* @param list
|
|
||||||
* @return a reverse {@link Iterable} of the list
|
|
||||||
*/
|
|
||||||
public static <T> Iterable<T> createReverseIterable(List<T> list) {
|
|
||||||
// When the list is empty we can use the "forward" iterable (i.e. the
|
|
||||||
// list itself) also as the reverseIterable as it will do nothing.
|
|
||||||
if (list.size() == 0) {
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ReverseIterable<T>(list);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internally used classes - subject to change without notice; client code must
|
|
||||||
* not use these classes.
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout.internal.util.java.lang;
|
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout.internal.util.java.util;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.ListIterator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Util (general purpose) methods dealing with {@link Iterator}.
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class IteratorUtil {
|
|
||||||
|
|
||||||
private static class ReverseIterator<T> implements Iterator<T> {
|
|
||||||
private ListIterator<T> listIterator;
|
|
||||||
|
|
||||||
public ReverseIterator(List<T> list) {
|
|
||||||
this.listIterator = list.listIterator(list.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasNext() {
|
|
||||||
return listIterator.hasPrevious();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T next() {
|
|
||||||
return listIterator.previous();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove() {
|
|
||||||
listIterator.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an {@link Iterator} iterating the given list from the end to the
|
|
||||||
* start.
|
|
||||||
* <p>
|
|
||||||
* I.e. the iterator does the reverse of the {@link List#iterator()}.
|
|
||||||
*
|
|
||||||
* @param <T>
|
|
||||||
* @param list
|
|
||||||
* @return a reverse {@link Iterator} of the list
|
|
||||||
*/
|
|
||||||
public static <T> Iterator<T> createReverseIterator(List<T> list) {
|
|
||||||
return new ReverseIterator<T>(list);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout.internal.util.java.util;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Util (general purpose) methods dealing with {@link List}.
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ListUtil {
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param <T>
|
|
||||||
* @param list [!list.isEmpty()]
|
|
||||||
* @return the last element of the list
|
|
||||||
*/
|
|
||||||
public static <T> T getLast(List<T> list) {
|
|
||||||
return list.get(list.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Internally used classes - subject to change without notice; client code must
|
|
||||||
* not use these classes.
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout.internal.util.java.util;
|
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Internally used classes - subject to change without notice; client code must
|
|
||||||
* not use these classes.
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout.internal.util;
|
|
||||||
|
|
|
@ -1,336 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
Efficiently create compact, highly customizable tree layouts.
|
|
||||||
|
|
||||||
|
|
||||||
<h2>Introduction</h2>
|
|
||||||
|
|
||||||
The TreeLayout creates tree layouts for arbitrary trees. It is not restricted
|
|
||||||
to a specific output or format, but can be used for any kind of two dimensional
|
|
||||||
diagram. Examples are Swing based components, SVG files, and many more. This is
|
|
||||||
possible because TreeLayout separates the layout of a tree from the actual
|
|
||||||
rendering.<p>
|
|
||||||
|
|
||||||
To use the TreeLayout you mainly need to supply an instance of the
|
|
||||||
{@link org.abego.treelayout.TreeLayout TreeLayout} class with the nodes of the tree (including "children"
|
|
||||||
links), together with the "size" of each node. In addition you can configure
|
|
||||||
the layout by specifying parameters like "gap between levels" etc..<p>
|
|
||||||
|
|
||||||
Based on this information TreeLayout creates a compact, nice looking layout.
|
|
||||||
The layout has the following properties [2]:
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>The layout displays the hierarchical structure of the tree, i.e. the
|
|
||||||
y-coordinate of a node is given by its level. (*)</li>
|
|
||||||
<li>The edges do not cross each other and nodes on the same level have a
|
|
||||||
minimal horizontal distance.</li>
|
|
||||||
<li>The drawing of a subtree does not depend on its position in the tree, i.e.
|
|
||||||
isomorphic subtrees are drawn identically up to translation.</li>
|
|
||||||
<li>The order of the children of a node is displayed in the drawing.</li>
|
|
||||||
<li>The algorithm works symmetrically, i.e. the drawing of the reflection of a
|
|
||||||
tree is the reflected drawing of the original tree.</li>
|
|
||||||
</ol>
|
|
||||||
<i> (*) When the root is at the left or right (see "Root Location") the
|
|
||||||
x-coordinate of a node is given by its level</i><p>
|
|
||||||
|
|
||||||
Here an example tree layout:<p>
|
|
||||||
<img src="doc-files/TreeGraphView-Top.png">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h2>Usage</h2>
|
|
||||||
|
|
||||||
To use the TreeLayout you will create a {@link org.abego.treelayout.TreeLayout TreeLayout} instance with:
|
|
||||||
<ul>
|
|
||||||
<li>a tree, accessible through the {@link org.abego.treelayout.TreeForTreeLayout TreeForTreeLayout} interface, </li>
|
|
||||||
<li>a {@link org.abego.treelayout.NodeExtentProvider NodeExtentProvider}, and</li>
|
|
||||||
<li>a {@link org.abego.treelayout.Configuration Configuration}.</li>
|
|
||||||
</ul>
|
|
||||||
Using these objects the TreeLayout will then calculate the layout and provide
|
|
||||||
the result through the method {@link org.abego.treelayout.TreeLayout#getNodeBounds() getNodeBounds}.
|
|
||||||
|
|
||||||
|
|
||||||
<h3>TreeForTreeLayout</h3>
|
|
||||||
|
|
||||||
The TreeLayout works on any kind of tree and uses the {@link org.abego.treelayout.TreeForTreeLayout TreeForTreeLayout}
|
|
||||||
interface to access such a tree.<p>
|
|
||||||
|
|
||||||
To use the TreeLayout you therefore need to provide it with a TreeForTreeLayout
|
|
||||||
implementation. In most situations you will not need to deal with all details
|
|
||||||
of that interface, but create an implementation by extending
|
|
||||||
{@link org.abego.treelayout.util.AbstractTreeForTreeLayout AbstractTreeForTreeLayout}, or even use the class
|
|
||||||
{@link org.abego.treelayout.util.DefaultTreeForTreeLayout DefaultTreeForTreeLayout} directly.
|
|
||||||
|
|
||||||
|
|
||||||
<h4>Example: Extending AbstractTreeForTreeLayout</h4>
|
|
||||||
|
|
||||||
Assume you have a tree consisting of nodes of type StringTreeNode:<p>
|
|
||||||
<img src="doc-files/StringTreeNodeUML.png"><p>
|
|
||||||
|
|
||||||
As StringTreeNode provides the children in a list and you can get the parent for
|
|
||||||
each node you can extend {@link org.abego.treelayout.util.AbstractTreeForTreeLayout AbstractTreeForTreeLayout} to create your
|
|
||||||
TreeForTreeLayout implementation. You only need to implement two methods and
|
|
||||||
the constructor:<p>
|
|
||||||
<pre>
|
|
||||||
public class StringTreeAsTreeForTreeLayout extends
|
|
||||||
AbstractTreeForTreeLayout<StringTreeNode> {
|
|
||||||
|
|
||||||
public StringTreeAsTreeForTreeLayout(StringTreeNode root) {
|
|
||||||
super(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringTreeNode getParent(StringTreeNode node) {
|
|
||||||
return node.getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<StringTreeNode> getChildrenList(StringTreeNode parentNode) {
|
|
||||||
return parentNode.getChildren();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
<i>(Make sure to check out the performance constraints of {@link org.abego.treelayout.util.AbstractTreeForTreeLayout#getChildrenList(Object) getChildrenList} and {@link org.abego.treelayout.util.AbstractTreeForTreeLayout#getParent(Object) getParent}.)</i>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h4>Example: Using the DefaultTreeForTreeLayout</h4>
|
|
||||||
|
|
||||||
Assume you want to create a tree with TextInBox items as nodes:<p>
|
|
||||||
<img src="doc-files/TextInBoxUML.png"><p>
|
|
||||||
|
|
||||||
As you have no own tree implementation yet you may as well use
|
|
||||||
{@link org.abego.treelayout.util.DefaultTreeForTreeLayout DefaultTreeForTreeLayout} to create the tree:<p>
|
|
||||||
<pre>
|
|
||||||
TextInBox root = new TextInBox("root", 40, 20);
|
|
||||||
TextInBox n1 = new TextInBox("n1", 30, 20);
|
|
||||||
TextInBox n1_1 = new TextInBox("n1.1\n(first node)", 80, 36);
|
|
||||||
TextInBox n1_2 = new TextInBox("n1.2", 40, 20);
|
|
||||||
TextInBox n1_3 = new TextInBox("n1.3\n(last node)", 80, 36);
|
|
||||||
TextInBox n2 = new TextInBox("n2", 30, 20);
|
|
||||||
TextInBox n2_1 = new TextInBox("n2", 30, 20);
|
|
||||||
|
|
||||||
DefaultTreeForTreeLayout<TextInBox> tree =
|
|
||||||
new DefaultTreeForTreeLayout<TextInBox>(root);
|
|
||||||
tree.addChild(root, n1);
|
|
||||||
tree.addChild(n1, n1_1);
|
|
||||||
tree.addChild(n1, n1_2);
|
|
||||||
tree.addChild(n1, n1_3);
|
|
||||||
tree.addChild(root, n2);
|
|
||||||
tree.addChild(n2, n2_1);
|
|
||||||
</pre><p>
|
|
||||||
This will create a tree like this:<p>
|
|
||||||
<img src="doc-files/svgdemo.png">
|
|
||||||
|
|
||||||
|
|
||||||
<h3>NodeExtentProvider</h3>
|
|
||||||
|
|
||||||
TreeLayout also needs to know the extent (width and height) of each node in the
|
|
||||||
tree. This information is provided through the {@link org.abego.treelayout.NodeExtentProvider NodeExtentProvider}.<p>
|
|
||||||
|
|
||||||
If all nodes have the same size you can use a {@link org.abego.treelayout.util.FixedNodeExtentProvider FixedNodeExtentProvider}
|
|
||||||
instance with the proper width and height.<p>
|
|
||||||
|
|
||||||
In general you will create your own NodeExtentProvider implementation.
|
|
||||||
<h4>Example</h4>
|
|
||||||
|
|
||||||
Assume you want to create a tree with TextInBox items as nodes:<p>
|
|
||||||
<img src="doc-files/TextInBoxUML.png"><p>
|
|
||||||
|
|
||||||
Here each node contains its width and height. So your NodeExtentProvider may
|
|
||||||
look like this:<p><pre>
|
|
||||||
public class TextInBoxNodeExtentProvider implements
|
|
||||||
NodeExtentProvider<TextInBox> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getWidth(TextInBox treeNode) {
|
|
||||||
return treeNode.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getHeight(TextInBox treeNode) {
|
|
||||||
return treeNode.height;
|
|
||||||
}
|
|
||||||
}</pre>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3>Configuration</h3>
|
|
||||||
|
|
||||||
You can use a {@link org.abego.treelayout.Configuration Configuration} to customize various aspects of the
|
|
||||||
TreeLayout:
|
|
||||||
<ul>
|
|
||||||
<li>the gap between levels,</li>
|
|
||||||
<li>the minimal gap between nodes,</li>
|
|
||||||
<li>the position of the root node,</li>
|
|
||||||
<li>the alignment of smaller nodes within a level.</li>
|
|
||||||
</ul>
|
|
||||||
Most of the times using the {@link org.abego.treelayout.util.DefaultConfiguration DefaultConfiguration} class will be sufficient.
|
|
||||||
|
|
||||||
<h4>Root Position</h4>
|
|
||||||
|
|
||||||
By default the root of the tree is located at the top of the diagram. However
|
|
||||||
one may also put it at the left, right or bottom of the diagram.
|
|
||||||
<p>
|
|
||||||
<table border="1">
|
|
||||||
<tr>
|
|
||||||
<th>Top (Default)</th>
|
|
||||||
<th>Left</th>
|
|
||||||
<th>Right</th>
|
|
||||||
<th>Bottom</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding:10px;"><img src="doc-files/TreeGraphView-Top.png"></td>
|
|
||||||
<td style="padding:10px;"><img src="doc-files/TreeGraphView-Left.png"></td>
|
|
||||||
<td style="padding:10px;"><img src="doc-files/TreeGraphView-Right.png"></td>
|
|
||||||
<td style="padding:10px;"><img src="doc-files/TreeGraphView-Bottom.png"></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
See {@link org.abego.treelayout.Configuration#getRootLocation() getRootLocation}.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h4>Alignment in Level</h4>
|
|
||||||
|
|
||||||
By default all nodes of one level are centered in the level. However
|
|
||||||
one may also align them "towards the root" or "away from the root". When the
|
|
||||||
root is located at the top this means the nodes are aligned "to the top of the
|
|
||||||
level" or "to the bottom of the level".
|
|
||||||
<p>
|
|
||||||
<table border="1">
|
|
||||||
<tr>
|
|
||||||
<th>Center (Default)</th>
|
|
||||||
<th>TowardsRoot ("top of level")</th>
|
|
||||||
<th>AwayFromRoot ("bottom of level")</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding:10px;"><img src="doc-files/TreeGraphView-Center.png"></td>
|
|
||||||
<td style="padding:10px;"><img src="doc-files/TreeGraphView-TowardsRoot.png"></td>
|
|
||||||
<td style="padding:10px;"><img src="doc-files/TreeGraphView-AwayFromRoot.png"></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>Alignment in level when root is at the left:</p>
|
|
||||||
<table border="1">
|
|
||||||
<tr>
|
|
||||||
<th>Center (Default)</th>
|
|
||||||
<th>TowardsRoot ("left of level")</th>
|
|
||||||
<th>AwayFromRoot<br>("right of level")</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="padding:10px;"><img src="doc-files/TreeGraphView-Center-RootLeft.png"></td>
|
|
||||||
<td style="padding:10px;"><img src="doc-files/TreeGraphView-TowardsRoot-RootLeft.png"></td>
|
|
||||||
<td style="padding:10px;"><img src="doc-files/TreeGraphView-AwayFromRoot-RootLeft.png"></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>Of cause the alignment also works when the root is at the bottom or at the right side.</p>
|
|
||||||
See {@link org.abego.treelayout.Configuration#getAlignmentInLevel() getAlignmentInLevel}.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h4 style="page-break-before:always">Gap between Levels and Nodes</h4>
|
|
||||||
|
|
||||||
The gap between subsequent levels and the minimal gap between nodes can be configured.
|
|
||||||
<p>
|
|
||||||
<img src="doc-files/gapsAndLevels.png">
|
|
||||||
<p>
|
|
||||||
See {@link org.abego.treelayout.Configuration#getGapBetweenLevels(int) getGapBetweenLevels} and
|
|
||||||
{@link org.abego.treelayout.Configuration#getGapBetweenNodes(Object, Object) getGapBetweenNodes}.
|
|
||||||
|
|
||||||
|
|
||||||
<h2>Examples</h2>
|
|
||||||
In the "demo" package you will find examples using the TreeLayout.
|
|
||||||
<ul>
|
|
||||||
<li>SVGDemo - Demonstrates how to use the TreeLayout to create a tree diagram with SVG (Scalable Vector Graphic)</li>
|
|
||||||
<li>SwingDemo - Demonstrates how to use the TreeLayout to render a tree in a Swing application</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
<h2 style="page-break-before:always">Performance</h2>
|
|
||||||
|
|
||||||
Based on Walker's algorithm [1] with enhancements suggested by Buchheim,
|
|
||||||
Jünger, and Leipert [2] the software builds tree layouts in linear time.
|
|
||||||
I.e. even trees with many nodes are built fast. Other than with the
|
|
||||||
Reingold–Tilford algorithm [3] one is not limited to binary trees.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The following figure show the results running the TreeLayout algorithm on a
|
|
||||||
MacBook Pro 2.4 GHz Intel Core 2 Duo (2 GB Memory (-Xmx2000m)). The variously
|
|
||||||
sized trees were created randomly.
|
|
||||||
<p>
|
|
||||||
<img src="doc-files/performance.png">
|
|
||||||
<p>
|
|
||||||
The picture illustrates the linear time behavior of the algorithm and shows
|
|
||||||
the applicability also for large number of nodes. In this setting it takes
|
|
||||||
approx. 5 µs to place one node.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h2>License</h2>
|
|
||||||
|
|
||||||
TreeLayout is distributed under a BSD license of
|
|
||||||
<a href="http://www.abego-software.de">abego Software</a>.
|
|
||||||
(<a href="doc-files/LICENSE.TXT">License text</a>)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h2>Sponsor</h2>
|
|
||||||
|
|
||||||
The development of TreeLayout was generously sponsored by Terence Parr
|
|
||||||
"The ANTLR Guy" (parrt at cs dot usfca dot edu).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h2>References</h2>
|
|
||||||
|
|
||||||
[1] Walker JQ II. A node-positioning algorithm for general trees.
|
|
||||||
<i>Software—Practice and Experience</i> 1990; <b>20</b>(7):685–705.
|
|
||||||
<p>
|
|
||||||
[2] Buchheim C, Jünger M, Leipert S. Drawing rooted trees in linear time.
|
|
||||||
<i>Software—Practice and Experience</i> 2006; <b>36</b>(6):651–665
|
|
||||||
<p>
|
|
||||||
[3] Reingold EM, Tilford JS. Tidier drawings of trees.
|
|
||||||
<i>IEEE Transactions on Software Engineering</i> 1981; <b>7</b>(2):223–228.
|
|
||||||
<p>
|
|
||||||
|
|
||||||
|
|
||||||
@author Udo Borkowski (ub@abego.org)
|
|
||||||
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout;
|
|
||||||
|
|
||||||
|
|
|
@ -1,122 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout.util;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.abego.treelayout.TreeForTreeLayout;
|
|
||||||
import org.abego.treelayout.internal.util.java.lang.IterableUtil;
|
|
||||||
import org.abego.treelayout.internal.util.java.util.ListUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides an easy way to implement the {@link TreeForTreeLayout} interface by
|
|
||||||
* defining just two simple methods and a constructor.
|
|
||||||
* <p>
|
|
||||||
* To use this class the underlying tree must provide the children as a list
|
|
||||||
* (see {@link #getChildrenList(Object)} and give direct access to the parent of
|
|
||||||
* a node (see {@link #getParent(Object)}).
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* See also {@link DefaultTreeForTreeLayout}.
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
* @param <TreeNode>
|
|
||||||
*/
|
|
||||||
abstract public class AbstractTreeForTreeLayout<TreeNode> implements
|
|
||||||
TreeForTreeLayout<TreeNode> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the parent of a node, if it has one.
|
|
||||||
* <p>
|
|
||||||
* Time Complexity: O(1)
|
|
||||||
*
|
|
||||||
* @param node
|
|
||||||
* @return [nullable] the parent of the node, or null when the node is a
|
|
||||||
* root.
|
|
||||||
*/
|
|
||||||
abstract public TreeNode getParent(TreeNode node);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the children of a node as a {@link List}.
|
|
||||||
* <p>
|
|
||||||
* Time Complexity: O(1)
|
|
||||||
* <p>
|
|
||||||
* Also the access to an item of the list must have time complexity O(1).
|
|
||||||
* <p>
|
|
||||||
* A client must not modify the returned list.
|
|
||||||
*
|
|
||||||
* @param node
|
|
||||||
* @return the children of the given node. When node is a leaf the list is
|
|
||||||
* empty.
|
|
||||||
*/
|
|
||||||
abstract public List<TreeNode> getChildrenList(TreeNode node);
|
|
||||||
|
|
||||||
private final TreeNode root;
|
|
||||||
|
|
||||||
public AbstractTreeForTreeLayout(TreeNode root) {
|
|
||||||
this.root = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TreeNode getRoot() {
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLeaf(TreeNode node) {
|
|
||||||
return getChildrenList(node).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isChildOfParent(TreeNode node, TreeNode parentNode) {
|
|
||||||
return getParent(node) == parentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterable<TreeNode> getChildren(TreeNode node) {
|
|
||||||
return getChildrenList(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterable<TreeNode> getChildrenReverse(TreeNode node) {
|
|
||||||
return IterableUtil.createReverseIterable(getChildrenList(node));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TreeNode getFirstChild(TreeNode parentNode) {
|
|
||||||
return getChildrenList(parentNode).get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TreeNode getLastChild(TreeNode parentNode) {
|
|
||||||
return ListUtil.getLast(getChildrenList(parentNode));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,135 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout.util;
|
|
||||||
|
|
||||||
import static org.abego.treelayout.internal.util.Contract.checkArg;
|
|
||||||
|
|
||||||
import org.abego.treelayout.Configuration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify a {@link Configuration} through configurable parameters, or falling
|
|
||||||
* back to some frequently used defaults.
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param <TreeNode>
|
|
||||||
*/
|
|
||||||
public class DefaultConfiguration<TreeNode> implements
|
|
||||||
Configuration<TreeNode> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies the constants to be used for this Configuration.
|
|
||||||
*
|
|
||||||
* @param gapBetweenLevels
|
|
||||||
* @param gapBetweenNodes
|
|
||||||
* @param location
|
|
||||||
* [default: {@link org.abego.treelayout.Configuration.Location#Top Top}]
|
|
||||||
* @param alignmentInLevel
|
|
||||||
* [default: {@link org.abego.treelayout.Configuration.AlignmentInLevel#Center Center}]
|
|
||||||
*/
|
|
||||||
public DefaultConfiguration(double gapBetweenLevels,
|
|
||||||
double gapBetweenNodes, Location location,
|
|
||||||
AlignmentInLevel alignmentInLevel) {
|
|
||||||
checkArg(gapBetweenLevels >= 0, "gapBetweenLevels must be >= 0");
|
|
||||||
checkArg(gapBetweenNodes >= 0, "gapBetweenNodes must be >= 0");
|
|
||||||
|
|
||||||
this.gapBetweenLevels = gapBetweenLevels;
|
|
||||||
this.gapBetweenNodes = gapBetweenNodes;
|
|
||||||
this.location = location;
|
|
||||||
this.alignmentInLevel = alignmentInLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience constructor, using a default for the alignmentInLevel.
|
|
||||||
* <p>
|
|
||||||
* see
|
|
||||||
* {@link #DefaultConfiguration(double, double, org.abego.treelayout.Configuration.Location, org.abego.treelayout.Configuration.AlignmentInLevel)}
|
|
||||||
*/
|
|
||||||
public DefaultConfiguration(double gapBetweenLevels,
|
|
||||||
double gapBetweenNodes, Location location) {
|
|
||||||
this(gapBetweenLevels, gapBetweenNodes, location,
|
|
||||||
AlignmentInLevel.Center);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience constructor, using a default for the rootLocation and the
|
|
||||||
* alignmentInLevel.
|
|
||||||
* <p>
|
|
||||||
* see
|
|
||||||
* {@link #DefaultConfiguration(double, double, org.abego.treelayout.Configuration.Location, org.abego.treelayout.Configuration.AlignmentInLevel)}
|
|
||||||
*/
|
|
||||||
public DefaultConfiguration(double gapBetweenLevels,
|
|
||||||
double gapBetweenNodes) {
|
|
||||||
this(gapBetweenLevels, gapBetweenNodes, Location.Top,
|
|
||||||
AlignmentInLevel.Center);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// gapBetweenLevels
|
|
||||||
|
|
||||||
private final double gapBetweenLevels;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getGapBetweenLevels(int nextLevel) {
|
|
||||||
return gapBetweenLevels;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// gapBetweenNodes
|
|
||||||
|
|
||||||
private final double gapBetweenNodes;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getGapBetweenNodes(TreeNode node1, TreeNode node2) {
|
|
||||||
return gapBetweenNodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// location
|
|
||||||
|
|
||||||
private final Location location;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Location getRootLocation() {
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
|
||||||
// alignmentInLevel
|
|
||||||
|
|
||||||
private AlignmentInLevel alignmentInLevel;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AlignmentInLevel getAlignmentInLevel() {
|
|
||||||
return alignmentInLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,128 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout.util;
|
|
||||||
|
|
||||||
import static org.abego.treelayout.internal.util.Contract.checkArg;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.abego.treelayout.TreeForTreeLayout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a generic implementation for the {@link TreeForTreeLayout}
|
|
||||||
* interface, applicable to any type of tree node.
|
|
||||||
* <p>
|
|
||||||
* It allows you to create a tree "from scratch", without creating any new
|
|
||||||
* class.
|
|
||||||
* <p>
|
|
||||||
* To create a tree you must provide the root of the tree (see
|
|
||||||
* {@link #DefaultTreeForTreeLayout(Object)}. Then you can incrementally
|
|
||||||
* construct the tree by adding children to the root or other nodes of the tree
|
|
||||||
* (see {@link #addChild(Object, Object)} and
|
|
||||||
* {@link #addChildren(Object, Object...)}).
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
* @param <TreeNode>
|
|
||||||
*/
|
|
||||||
public class DefaultTreeForTreeLayout<TreeNode> extends
|
|
||||||
AbstractTreeForTreeLayout<TreeNode> {
|
|
||||||
|
|
||||||
private List<TreeNode> emptyList;
|
|
||||||
|
|
||||||
private List<TreeNode> getEmptyList() {
|
|
||||||
if (emptyList == null) {
|
|
||||||
emptyList = new ArrayList<TreeNode>();
|
|
||||||
}
|
|
||||||
return emptyList;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<TreeNode, List<TreeNode>> childrenMap = new HashMap<TreeNode, List<TreeNode>>();
|
|
||||||
private Map<TreeNode, TreeNode> parents = new HashMap<TreeNode, TreeNode>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance with a given node as the root
|
|
||||||
*
|
|
||||||
* @param root
|
|
||||||
* the node to be used as the root.
|
|
||||||
*/
|
|
||||||
public DefaultTreeForTreeLayout(TreeNode root) {
|
|
||||||
super(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TreeNode getParent(TreeNode node) {
|
|
||||||
return parents.get(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<TreeNode> getChildrenList(TreeNode node) {
|
|
||||||
List<TreeNode> result = childrenMap.get(node);
|
|
||||||
return result == null ? getEmptyList() : result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param node
|
|
||||||
* @return true iff the node is in the tree
|
|
||||||
*/
|
|
||||||
public boolean hasNode(TreeNode node) {
|
|
||||||
return node == getRoot() || parents.containsKey(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param parentNode
|
|
||||||
* [hasNode(parentNode)]
|
|
||||||
* @param node
|
|
||||||
* [!hasNode(node)]
|
|
||||||
*/
|
|
||||||
public void addChild(TreeNode parentNode, TreeNode node) {
|
|
||||||
checkArg(hasNode(parentNode), "parentNode is not in the tree");
|
|
||||||
checkArg(!hasNode(node), "node is already in the tree");
|
|
||||||
|
|
||||||
List<TreeNode> list = childrenMap.get(parentNode);
|
|
||||||
if (list == null) {
|
|
||||||
list = new ArrayList<TreeNode>();
|
|
||||||
childrenMap.put(parentNode, list);
|
|
||||||
}
|
|
||||||
list.add(node);
|
|
||||||
parents.put(node, parentNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addChildren(TreeNode parentNode, TreeNode... nodes) {
|
|
||||||
for (TreeNode node : nodes) {
|
|
||||||
addChild(parentNode, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout.util;
|
|
||||||
|
|
||||||
import static org.abego.treelayout.internal.util.Contract.*;
|
|
||||||
|
|
||||||
import org.abego.treelayout.NodeExtentProvider;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link NodeExtentProvider} returning the same width and height for each
|
|
||||||
* node.
|
|
||||||
*
|
|
||||||
* @author Udo Borkowski (ub@abego.org)
|
|
||||||
*
|
|
||||||
* @param <T>
|
|
||||||
*/
|
|
||||||
public class FixedNodeExtentProvider<T> implements NodeExtentProvider<T> {
|
|
||||||
|
|
||||||
private final double width;
|
|
||||||
private final double height;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies the constants to be used as the width and height of the nodes.
|
|
||||||
*
|
|
||||||
* @param width
|
|
||||||
* [default=0]
|
|
||||||
*
|
|
||||||
* @param height
|
|
||||||
* [default=0]
|
|
||||||
*/
|
|
||||||
public FixedNodeExtentProvider(double width, double height) {
|
|
||||||
checkArg(width >= 0, "width must be >= 0");
|
|
||||||
checkArg(height >= 0, "height must be >= 0");
|
|
||||||
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* see {@link #FixedNodeExtentProvider(double, double)}
|
|
||||||
*/
|
|
||||||
public FixedNodeExtentProvider() {
|
|
||||||
this(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getWidth(T treeNode) {
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getHeight(T treeNode) {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 72 KiB |
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* [The "BSD license"]
|
|
||||||
* Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the abego Software GmbH nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Various utility classes to simplify usage of the
|
|
||||||
* {@link org.abego.treelayout.TreeLayout}.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package org.abego.treelayout.util;
|
|
||||||
|
|