/*******************************************************************************
* SuperWaba Virtual Machine, version 4 *
* Copyright (C) 2003-2004 Guilherme Campos Hazan <support@superwaba.com.br> *
* Copyright (C) 2001 Daniel Tauchke *
* All Rights Reserved *
* *
* This library and virtual machine is free software; you can redistribute *
* it and/or modify it under the terms of the Amended GNU Lesser General *
* Public License distributed with this software. *
* *
* This library and virtual machine is distributed in the hope that it will *
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* *
* For the purposes of the SuperWaba software we request that software using *
* or linking to the SuperWaba virtual machine or its libraries display the *
* following notice: *
* *
* Created with SuperWaba *
* http://www.superwaba.org *
* *
* Please see the software license located at SuperWabaSDK/license.txt *
* for more details. *
* *
* You should have received a copy of the License along with this software; *
* if not, write to *
* *
* Guilherme Campos Hazan *
* Av. Nossa Senhora de Copacabana 728 apto 605 - Copacabana *
* Rio de Janeiro / RJ - Brazil *
* Cep: 22050-000 *
* E-mail: support@superwaba.com.br *
* *
*******************************************************************************/
import waba.util.Vector;
/*******************************************************************************
*
* File: Node.java
* Date: August 26,2004.
* Last Modified: September 5, 2004.
* Author: Tri (Trev) Quang Nguyen.
* Version: 0.9
* Email: tnguyen@ceb.nlm.nih.gov
*
* Description: This class defines the requirements for an object that can
* be used as a tree node in a Tree.
*
* Note: Some methods are still unimplemented.
*
********************************************************************************/
public class Node {
private static final int BEFORE = 0; // used in getChildBefore()
private static final int AFTER = 1; // used in getChildAfter()
protected Node parent = null; // this node parent (root node is when the parent node = null)
protected Vector children = null; // this node children
protected Object userObject = null; // user object
protected Vector userIcons =new Vector(); // Icons user associates with this node.
protected int wicons=0; // Width of combined icons (used by highlighting)
public boolean allowsChildren = false; // flag to determine if this node can have children
public boolean visited = true; // flag to determine if the leaf node has been clicked before
/***************************************************************************
* Default constructor to creates a tree node that has no parent and no
* children, but which allows children.
***************************************************************************/
public Node(){ this(""); }
/***************************************************************************
* Default constructor to creates a tree node with no parent, no children,
* but which allows children, and initializes it with the specified user object.
* @param userObject the user object.
***************************************************************************/
public Node(Object userObject){
this.children = new Vector();
this.userObject = userObject;
allowsChildren = false;
visited = false;
}
/***************************************************************************
* Method to remove newChild from its parent and makes it a child of this
* node by adding it to the end of this node's child vector.
* @param newChild the new child node to add to the end of the child vector.
***************************************************************************/
public void add(Node newChild){
remove(newChild);
newChild.setParent(this);
children.add(newChild);
}
/***************************************************************************
* Method to create and return a vector that traverses the subtree rooted at
* this node in breadth-first order.
* @return the children vector of this node.
***************************************************************************/
public Vector breathFirstVector(){
Vector v = new Vector();
breathFirst(v, this);
return v;
}
/***************************************************************************
* Method used by breathFirstVector() to create the breath first vector.
* @param v the vector to hold tree nodes.
* @param node the node to traverse
***************************************************************************/
private void breathFirst(Vector v, Node node){
v.add(node);
if (node.getChildCount() > 0){
Node childs[] = node.childrenArray();
for(int i = 0; i < childs.length; i++){
breathFirst(v, childs[i]);
}
}
}
/***************************************************************************
* Method to return the children vector of this node.
* @return the children vector of this node.
***************************************************************************/
public Vector children(){ return children; }
/***************************************************************************
* Method to return the children vector as an array of Nodes.
* @return the children array of Nodes.
***************************************************************************/
public Node[] childrenArray(){
Node[] childs = new Node[children.size()];
for (int i = 0; i < children.size(); i++)
childs[i] = (Node) children.items[i];
return childs;
}
/***************************************************************************
* NOT IMPLEMENTED !!!!!!!!!!!!!!
* Method to create and return a vector that traverses the subtree rooted at
* this node in breadth-first order.
* @return the children vector of this node.
***************************************************************************/
public Vector depthFirstVector(){
return null;
// TODO
}
/***************************************************************************
* Method to return true if this node is allowed to have children.
* @return true if this node is allowed to have children.
***************************************************************************/
public boolean getAllowsChildren(){ return allowsChildren; }
/***************************************************************************
* Method to returns the child in this node's child array that immediately
* follows aChild, which must be a child of this node; otherwise, retrun null.
* @return the child node that immediately follows aChild node.
***************************************************************************/
public Node getChildAfter(Node aChild){ return getChild(aChild, AFTER); }
/***************************************************************************
* Method to returns the child in this node's child array that immediately
* precedes aChild, which must be a child of this node; otherwise, retrun null.
* @return the child node that immediately precede aChild node.
***************************************************************************/
public Node getChildBefore(Node aChild){ return getChild(aChild, BEFORE); }
/***************************************************************************
* Method to returns the child in this node's child array that immediately
* precedes or follows aChild (based on the specified position. aChild must
* be a child of this node; otherwise, retrun null.
* @return the child node that immediately precede aChild node.
***************************************************************************/
private Node getChild(Node aChild, int position){
int pos = children.find(aChild);
if (position == BEFORE && pos > 0) return (Node) children.items[pos-1];
else if (position == AFTER && pos < children.size() - 1) return (Node) children.items[pos+1];
return null;
}
/***************************************************************************
* Method to return the child at the specified index in this node's children
* vector. Returns null if index is out of bound.
* @return the child at the specified index. Returns null is index out of bound.
***************************************************************************/
private Node getChildAt(int index){
if (index > -1 && index < children.size())
return (Node) children.items[index];
else return null;
}
/***************************************************************************
* Method to return the number of children of this node.
* @return the number of children of this node.
***************************************************************************/
public int getChildCount(){ return children.size(); }
/***************************************************************************
* Method to return this node's first child.
* @return this node's first child.
***************************************************************************/
public Node getFirstChild(){ return getChildAt(0); }
/***************************************************************************
* Method to return this node's last child.
* @return this node's last child.
***************************************************************************/
public Node getLastChild(){ return getChildAt(children.size()-1); }
/***************************************************************************
* Method to return the number of levels above this node -- the distance
* from the root to this node.
* @return the number of levels above this node -- the distance from the
* root to this node
***************************************************************************/
public int getLevel(){
int lvl = 0;
if (this.isRoot()) return lvl;
Node node = getParent();
lvl++;
while (!node.isRoot()){
node = node.getParent();
lvl++;
}
return lvl;
}
/***************************************************************************
* Method to return the node name of this node.
* @return the node name of this node.
***************************************************************************/
public String getNodeName(){ return (userObject == null)? "": userObject.toString(); }
/***************************************************************************
* Method to return the next sibling of this node in the parent's children
* array. Returns null if this node has no parent or is the parent's last
* child. This method performs a linear search that is O(n) where n is the
* number of children
* @return the next sibling of this node in the parent's children array.
* Returns null if this node has no parent or is the parent's last child.
***************************************************************************/
public Node getNextSibling(){
return (parent != null)? parent.getChildAfter(this): null;
}
/***************************************************************************
* Method to return the previous sibling of this node in the parent's
* children array. Returns null if this node has no parent or is the parent's
* first child. This method performs a linear search that is O(n) where n is
* the number of children
* @return the previous sibling of this node in the parent's children array.
* Returns null if this node has no parent or is the parent's in the tree.
***************************************************************************/
public Node getPreviousSibling(){
if (parent == null) return null;
return parent.getChildBefore(this);
}
/***************************************************************************
* Method to return this node's parent or null if this node has no parent.
***************************************************************************/
public Node getParent(){ return parent; }
/***************************************************************************
* Method to return the path from the root, to get to this node.
* @return the path from the root, to get to this node.
***************************************************************************/
public Node[] getPath(){
Vector v = new Vector();
pathFromRootToNode(v, this);
Node p[] = new Node[v.size()];
for (int i = 0; i < p.length; i++)
p[i] = (Node) v.items[i];
return p;
}
/***************************************************************************
* Method to builds the parents of node up to and including the root node,
* where the original node is the last element in the returned array.
* @return the path from this node to the root node, including the root node.
***************************************************************************/
protected Node[] getPathToRoot() {
Vector v = new Vector();
pathFromNodeToRoot(v, this);
Node p[] = new Node[v.size()];
for (int i = 0; i < p.length; i++)
p[i] = (Node) v.items[i];
return p;
}
/***************************************************************************
* Method to get the path from the root to the specified node.
* @param v the vector to hold the path.
* @param node the specified node.
***************************************************************************/
private void pathFromRootToNode(Vector v, Node node){
if (node == null) return;
pathFromRootToNode(v, node.getParent());
v.add(node);
}
/***************************************************************************
* Method to get the path from the specified node to the root node.
* @param v the vector to hold the path.
* @param node the specified node.
***************************************************************************/
private void pathFromNodeToRoot(Vector v, Node node){
if (node == null) return;
v.add(node);
pathFromNodeToRoot(v, node.getParent());
}
/***************************************************************************
* Method to return the root of the tree that contains this node.
* @return the root of the tree that contains this node.
***************************************************************************/
public Node getRoot(){
Node node = this;
while (!node.isRoot())
node = node.getParent();
return node;
}
/***************************************************************************
* Method to return this node's user object.
* @return this node's user object.
***************************************************************************/
public Object getUserObject(){ return userObject; }
/***************************************************************************
* Method to return the user object path, from the root, to get to this node.
* @return the user object path, from the root, to get to this node.
***************************************************************************/
public Object[] getUserObjectPath(){
Node nodes[] = getPath();
Object obj[] = new Object[nodes.length];
for (int i = 0; i < obj.length; i++)
obj[i] = nodes[i].getUserObject();
return obj;
}
/***************************************************************************
* Method to removes newChild from its present parent (if it has a parent),
* sets the child's parent to this node, and then adds the child to this
* node's child array at index childIndex. If childINdex is out of bound,
* newChild will be inserted at the end of the children vector
* @param newChild the new child to remove from this subtree and add to
* this node children vector at the specified index.
* @param childIndex the position in the children vector to insert newChild.
* @return the child index.
***************************************************************************/
public int insert(Node newChild, int childIndex){
remove(newChild);
try {
children.insert(childIndex, newChild);
newChild.setParent(this);
return children.find(newChild);
}
catch (Exception e){
waba.sys.Vm.debug("insert: Exception "+e.getMessage());
children.add(newChild);
newChild.setParent(this);
return children.size() - 1;
}
}
/***************************************************************************
* Method to return true if this node has been visited
* @return true if this node has been visited.
***************************************************************************/
public boolean isVisited(){ return visited; }
/***************************************************************************
* Method to return true if this node has no children.
* @return true if this node has no children.
***************************************************************************/
public boolean isLeaf(){ return (children.size() == 0); }
/***************************************************************************
* Method to return true if this node has no children.
* @return true if this node has no children.
***************************************************************************/
public boolean isLeaf(boolean useAllowsChildren){
if (useAllowsChildren)
return (children.size() == 0 && !this.allowsChildren);
else return (children.size() == 0);
}
/***************************************************************************
* Method to return true if this node is a root. Root node is node that
* has a null parent node.
***************************************************************************/
public boolean isRoot(){ return (parent == null); }
/***************************************************************************
* Method to return true if aNode is a child of this node.
* @param aNode the node to deterimine if it's a shild of this node.
* @return true if aNode is a child of this node.
***************************************************************************/
public boolean isNodeChild(Node aNode){
for (int i = 0; i < children.size(); i++){
if (aNode == (Node) children.items[i])
return true;
}
return false;
}
/***************************************************************************
* Method to return true if anotherNode is a sibling of (has the same parent
* as) this node.
* @return true if anotherNode is a sibling of (has the same parent as) this node.
***************************************************************************/
public boolean isNodeSibling(Node anotherNode){
if (parent == null) return false;
return (parent == anotherNode.parent);
}
/***************************************************************************
* Method to remove the child at the specified index from this node's
* children and sets that node's parent to null.
* @param childIndex the index of the this node's children to be removed
***************************************************************************/
public void remove(int childIndex){
if (childIndex > -1 && childIndex < children.size()){
Node child = (Node) children.items[childIndex];
child.setParent(null);
children.del(childIndex);
}
}
/***************************************************************************
* Method to move this node up the list. Do nothing if this is the root node,
* already at the top, or the only node in the list.
***************************************************************************/
public void moveUp(){
if (parent==null) return;
if (parent.children.size()<2) return;
int me=parent.children.find(this);
if (me<1) return;
/* OK, it looks safe to swap this entry and the one above it. */
Object tmp=parent.children.items[me];
parent.children.items[me]=parent.children.items[me-1];
parent.children.items[me-1]=tmp;
}
/***************************************************************************
* Method to move this node down the list. Do nothing if this is the root node,
* already at the botton, or the only node in the list.
***************************************************************************/
public void moveDown(){
if (parent==null) return;
if (parent.children.size()<2) return;
if (this==parent.getLastChild()) return;
/* OK, it looks safe to swap this entry and the one below it. */
int me=parent.children.find(this);
Object tmp=parent.children.items[me];
parent.children.items[me]=parent.children.items[me+1];
parent.children.items[me+1]=tmp;
}
/***************************************************************************
* Method to remove aChild from this node's child array, giving it a null parent.
* @param aChild the child node to remove.
***************************************************************************/
public void remove(Node aChild){
for (int i = 0; i < children.size(); i++){
if (aChild == (Node) children.items[i]){
aChild.setParent(null);
children.del(i);
return;
}
}
}
/***************************************************************************
* Method to remove all of this node's children, setting their parents to null.
***************************************************************************/
public void removeAllChildren(){
for (int i = 0; i < children.size(); i++){
Node node = (Node) children.items[i];
node.setParent(null);
}
children.clear();
}
/***************************************************************************
* Method to remove the subtree rooted at this node from the tree, giving
* this node a null parent.
***************************************************************************/
public void removeFromParent(){ parent.remove(this); }
/***************************************************************************
* Method to determine whether or not this node is allowed to have children.
* @param allows determine whether or not this node is allowed to have children.
***************************************************************************/
public void setAllowsChildren(boolean allows){ allowsChildren = allows; }
/***************************************************************************
* Method to sets this node's parent to newParent but does not change the
* parent's child array.
* @param parent the newParent node
***************************************************************************/
public void setParent(Node parent){ this.parent = parent; }
/***************************************************************************
* Method to set the user object for this node to userObject.
* @param userObject the user object of this node.
***************************************************************************/
public void setUserObject(Object userObject){ this.userObject = userObject; }
/***************************************************************************
* Method to set the node visited property.
* @param visited the new visited property.
***************************************************************************/
public void setVisited(boolean visited){ this.visited = visited; }
/***************************************************************************
* Method to return the result of sending toString() to this node's user
* object, or null if this node has no user object.
* @return the result of sending toString() to this node's user object,
* or null if this node has no user object.
***************************************************************************/
public String toString(){ return getNodeName(); }
/***************************************************************************
* Add this image to the list of user icons.
* @param img
*/
public void addIcon(NodeIcon ni) {
userIcons.add(ni);
}
/***************************************************************************
* Eliminate tthe existing list of user icons.
* @param img
*/
public void deleteIcons() {
userIcons=new Vector();
}
/***************************************************************************
* Method to display the root structor to the console.
* For debugging - Check what the node structure looks like
***************************************************************************/
public void display(Node node, String indent){
//Vm.debug(indent + node.toString() + " [" + node.getLevel() + "] - " + node.isLeaf());
Node childs[] = node.childrenArray();
for (int i = 0; i < childs.length; i++)
display(childs[i], indent + " ");
}
}