package yuku.atree;
import java.util.*;
public abstract class BaseMutableTreeNode implements MutableTreeNode {
protected MutableTreeNode parent;
protected List<TreeNode> children;
protected transient Object userObject;
private boolean expanded;
public BaseMutableTreeNode() {
this(null);
}
public BaseMutableTreeNode(final Object userObject) {
setUserObject(userObject);
}
@Override public void insert(final MutableTreeNode child, final int childIndex) {
if (child == null || isNodeAncestor(child)) {
throw new IllegalArgumentException("invalid child to insert"); //$NON-NLS-1$
}
if (child.getParent() instanceof MutableTreeNode) {
child.<MutableTreeNode> getParent().remove(child);
}
child.setParent(this);
getChildren().add(childIndex, child);
}
@Override public void remove(final int childIndex) {
MutableTreeNode child = (MutableTreeNode) getChildren().remove(childIndex);
child.setParent(null);
}
@Override public void setParent(final MutableTreeNode parent) {
this.parent = parent;
}
@SuppressWarnings("unchecked") @Override public <T extends TreeNode> T getParent() {
return (T) parent;
}
@SuppressWarnings("unchecked") @Override public <T extends TreeNode> T getChildAt(final int index) {
return (T) getChildren().get(index);
}
@Override public int getChildCount() {
return children != null ? children.size() : 0;
}
@Override public int getIndex(final TreeNode child) {
return children != null ? children.indexOf(child) : -1;
}
public List<TreeNode> children() {
return children;
}
@Override public void setUserObject(final Object userObject) {
this.userObject = userObject;
}
@SuppressWarnings("unchecked") @Override public <T> T getUserObject() {
return (T) userObject;
}
@Override public void removeFromParent() {
if (parent != null) {
parent.remove(this);
}
}
@Override public void remove(final MutableTreeNode child) {
int index = -1;
if (child == null || children == null || (index = children.indexOf(child)) == -1) {
throw new IllegalArgumentException("child null or not found"); //$NON-NLS-1$
}
remove(index);
}
public void removeAllChildren() {
if (children == null) {
return;
}
for (Iterator<TreeNode> it = children.iterator(); it.hasNext();) {
MutableTreeNode child = (MutableTreeNode) it.next();
child.setParent(null);
it.remove();
}
}
public void add(final MutableTreeNode child) {
insert(child, getChildCount() - (isNodeChild(child) ? 1 : 0));
}
public boolean isNodeAncestor(final TreeNode anotherNode) {
if (anotherNode == null) {
return false;
}
TreeNode currentParent = this;
while (currentParent != null) {
if (currentParent == anotherNode) {
return true;
}
currentParent = currentParent.getParent();
}
return false;
}
public boolean isNodeDescendant(final BaseMutableTreeNode anotherNode) {
return anotherNode != null ? anotherNode.isNodeAncestor(this) : false;
}
public TreeNode getSharedAncestor(final BaseMutableTreeNode anotherNode) {
TreeNode currentParent = anotherNode;
while (currentParent != null) {
if (isNodeAncestor(currentParent)) {
return currentParent;
}
currentParent = currentParent.getParent();
}
return null;
}
public boolean isNodeRelated(final BaseMutableTreeNode node) {
return getSharedAncestor(node) != null;
}
@Override public int getDepth() {
if (children == null || children.size() == 0) {
return 0;
}
int childrenDepth = 0;
for (Iterator<TreeNode> it = children.iterator(); it.hasNext();) {
TreeNode child = it.next();
int childDepth = child.getDepth();
if (childDepth > childrenDepth) {
childrenDepth = childDepth;
}
}
return childrenDepth + 1;
}
@Override public int getLevel() {
int result = 0;
TreeNode currentParent = getParent();
while (currentParent != null) {
currentParent = currentParent.getParent();
result++;
}
return result;
}
public TreeNode[] getPath() {
return getPathToRoot(this, 0);
}
public Object[] getUserObjectPath() {
TreeNode[] path = getPath();
Object[] result = new Object[path.length];
for (int i = 0; i < path.length; i++) {
result[i] = ((BaseMutableTreeNode) path[i]).getUserObject();
}
return result;
}
public TreeNode getRoot() {
TreeNode currentNode = this;
while (currentNode.getParent() != null) {
currentNode = currentNode.getParent();
}
return currentNode;
}
public boolean isRoot() {
return getParent() == null;
}
public boolean isNodeChild(final TreeNode child) {
return child != null && children != null ? children.contains(child) : false;
}
@Override public boolean isLeaf() {
return children == null || children.isEmpty();
}
@Override public String toString() {
return getUserObject() != null ? getUserObject().toString() : null;
}
protected TreeNode[] getPathToRoot(final TreeNode node, final int depth) {
if (node == null) {
return new TreeNode[depth];
}
TreeNode[] result = getPathToRoot(node.getParent(), depth + 1);
result[result.length - 1 - depth] = node;
return result;
}
private List<TreeNode> getChildren() {
if (children == null) {
children = new ArrayList<TreeNode>();
}
return children;
}
// including me
@Override public int getRowCount() {
if (!expanded) {
return 1;
}
int res = 1;
for (TreeNode node: getChildren()) {
res += node.getRowCount();
}
return res;
}
@Override public boolean getExpanded() {
return expanded;
}
@Override public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
}