//----------------------------------------------------------------------------//
// //
// T r e e N o d e //
// //
//----------------------------------------------------------------------------//
// <editor-fold defaultstate="collapsed" desc="hdr"> //
// Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. //
// This software is released under the GNU General Public License. //
// Goto http://kenai.com/projects/audiveris to report bugs or suggestions. //
//----------------------------------------------------------------------------//
// </editor-fold>
package omr.util;
import omr.Main;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* Class {@code TreeNode} handles a node in a tree hierarchy,
* which is typically the tree organization of a score entity.
* <p/>
* A TreeNode has : <ul> <li> A parent (which may be null) to which the TreeNode
* belongs <li> A list (which may be empty) of contained chidren, for which the
* TreeNode is the parent. </ul>
*
* @author Hervé Bitteur
*/
public abstract class TreeNode
{
//~ Static fields/initializers ---------------------------------------------
/** Usual logger utility */
private static final Logger logger = LoggerFactory.getLogger(TreeNode.class);
//~ Instance fields --------------------------------------------------------
/**
* Children : the list of nodes just below in the tree
*/
protected final List<TreeNode> children = new ArrayList<>();
/**
* Container : the node just above in the tree
*/
@Navigable(false)
protected TreeNode parent;
//~ Constructors -----------------------------------------------------------
//----------//
// TreeNode //
//----------//
/**
* Create a node in the tree, given its parent.
*
* @param parent the containing node, or null otherwise
*/
public TreeNode (TreeNode parent)
{
logger.debug("new TreeNode parent={}", parent);
if (parent != null) {
parent.addChild(this);
}
}
//~ Methods ----------------------------------------------------------------
//----------//
// addChild //
//----------//
/**
* Add a child in the list of node children.
*
* @param node the child to include
*/
public synchronized void addChild (TreeNode node)
{
logger.debug("addChild {} for {}", node, this);
children.add(node);
node.setParent(this);
}
//--------------//
// dumpChildren //
//--------------//
/**
* Utility to dump recursively all the children of this node,
* with no starting indentation.
*/
public void dumpChildren ()
{
dumpChildren(0);
}
//--------------//
// dumpChildren //
//--------------//
/**
* Utility to dump recursively all the children of this node,
* with the starting indentation specified.
*
* @param level the starting indentation level
*/
public void dumpChildren (final int level)
{
for (TreeNode node : children) {
if (node.dumpNode(level)) {
node.dumpChildren(level + 1);
}
}
}
//----------//
// dumpNode //
//----------//
/**
* Utility to dump the current node, with no indentation.
*
* @return true, so that processing continues
*/
public boolean dumpNode ()
{
return dumpNode(0);
}
//----------//
// dumpNode //
//----------//
/**
* Utility to dump the current node, with the specified level of
* indentation.
*
* @param level the desired indentation level
* @return true, so that processing continues
*/
public boolean dumpNode (int level)
{
Main.dumping.dump(this, level);
return true; // Let computation continue down the tree
}
//---------------//
// getChildIndex //
//---------------//
/**
* Report the index (counted from 0) of this node within the
* children sequence of its parent.
*
* @return the child index (or -1 if there is no parent)
*/
public int getChildIndex ()
{
if (parent != null) {
return parent.children.indexOf(this);
} else {
return -1;
}
}
//-------------//
// getChildren //
//-------------//
/**
* Report the list of (direct) children.
*
* @return the children
*/
public List<TreeNode> getChildren ()
{
logger.debug("getChildren of {}", this);
return children;
}
//-------------//
// getChildren //
//-------------//
/**
* Report the list of (direct) children.
*
* @return the children
*/
@SuppressWarnings("unchecked")
public synchronized List<TreeNode> getChildrenCopy ()
{
logger.debug("getChildrenCopy of {}", this);
return new ArrayList<TreeNode>(children);
}
//----------------//
// getNextSibling //
//----------------//
/**
* Report the next node in the children of this node parent.
*
* @return the next sibling node, or null if none
*/
public TreeNode getNextSibling ()
{
if (parent != null) {
int index = parent.children.indexOf(this);
if (index < (parent.children.size() - 1)) {
return parent.children.get(index + 1);
}
}
return null;
}
//-----------//
// getParent //
//-----------//
/**
* Report the parent of this node.
*
* @return the node just higher in the tree, or null if none
*/
public TreeNode getParent ()
{
return parent;
}
//--------------------//
// getPreviousSibling //
//--------------------//
/**
* Report the previous node in the children of this node parent.
*
* @return the previous sibling node, or null if none
*/
public TreeNode getPreviousSibling ()
{
if (parent != null) {
int index = parent.children.indexOf(this);
if (index > 0) {
return parent.children.get(index - 1);
}
}
return null;
}
//-------------------//
// setChildrenParent //
//-------------------//
/**
* Register this node as the parent of all its children.
*/
public void setChildrenParent ()
{
logger.debug("setChildrenParent of {}", this);
// Make all children point to this node as parent
for (TreeNode node : children) {
node.setParent(this);
node.setChildrenParent(); // Recursively
}
}
//-----------//
// setParent //
//-----------//
/**
* Modify the link to the parent of this node.
*
* @param parent the (new) parent
*/
public void setParent (TreeNode parent)
{
logger.debug("setParent parent={} for {}", parent, this);
this.parent = parent;
}
}