/** * Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ package org.python.pydev.shared_core.structure; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.core.runtime.IAdaptable; import org.python.pydev.shared_core.callbacks.ICallback; import org.python.pydev.shared_core.string.FastStringBuffer; /** * Note: equals and hashCode are identity based (i.e.: Object implementation). */ @SuppressWarnings({ "unchecked", "rawtypes" }) public class TreeNode<T> implements IAdaptable { public T data; /** * Note: children of a class don't necessarily have the same type as the parent. */ protected final LowMemoryArrayList<TreeNode> children = new LowMemoryArrayList<TreeNode>(); private Object parent; public TreeNode(Object parent, T data) { this.parent = parent; if (parent instanceof TreeNode) { ((TreeNode) parent).addChild(this); } setData(data); } public void setParent(Object parent) { if (this.parent != null) { this.detachFromParent(); } this.parent = parent; if (parent instanceof TreeNode) { ((TreeNode) parent).addChild(this); } } public List<TreeNode> getChildren() { return this.children; } public T getData() { return this.data; } public void setData(T data) { this.data = data; } private void addChild(TreeNode treeNode) { this.children.add(treeNode); } public Object getParent() { return parent; } public boolean hasChildren() { return this.children.size() > 0; } @Override public String toString() { return super.toString(); } // To use while debugging public String toStringRepr() { FastStringBuffer buf = new FastStringBuffer(); fillBuf(this, buf, 0); return buf.toString(); } protected void fillBuf(TreeNode<T> treeNode, FastStringBuffer buf, int level) { buf.appendN(" ", level).append("TreeNode:").appendObject(treeNode.data).append('\n'); for (TreeNode<T> child : treeNode.children) { fillBuf(child, buf, level + 1); } } /** * Note that it collects only children (the root node is not considered). */ public <Y> List<TreeNode<Y>> flattenChildren() { ArrayList<TreeNode<Y>> array = new ArrayList<TreeNode<Y>>(this.getChildren().size() + 10); collectChildren(array); return array; } private <Y> void collectChildren(ArrayList<TreeNode<Y>> array) { List<TreeNode> c = this.getChildren(); int size = c.size(); array.ensureCapacity(array.size() + size); for (int i = 0; i < size; i++) { TreeNode<Y> next = c.get(i); array.add(next); next.collectChildren(array); } } /** * Note that it visits only children (the root node is not visited). */ public <Y> void visitChildrenRecursive(ICallback<Object, TreeNode<Y>> onChild) { List<TreeNode> c = this.getChildren(); for (Iterator<TreeNode> iterator = c.iterator(); iterator.hasNext();) { TreeNode treeNode = iterator.next(); onChild.call(treeNode); treeNode.visitChildrenRecursive(onChild); } } public void clear() { this.children.clear(); } @Override public <Z> Z getAdapter(Class<Z> adapter) { if (data instanceof IAdaptable) { return ((IAdaptable) data).getAdapter(adapter); } return null; } public void detachFromParent() { if (parent instanceof TreeNode<?>) { TreeNode<?> parentNode = (TreeNode<?>) parent; ((TreeNode) parent).children.remove(this); this.parent = null; } } }