/* * funCKit - functional Circuit Kit * Copyright (C) 2013 Lukas Elsner <open@mindrunner.de> * Copyright (C) 2013 Peter Dahlberg <catdog2@tuxzone.org> * Copyright (C) 2013 Julian Stier <mail@julian-stier.de> * Copyright (C) 2013 Sebastian Vetter <mail@b4sti.eu> * Copyright (C) 2013 Thomas Poxrucker <poxrucker_t@web.de> * Copyright (C) 2013 Alexander Treml <alex.treml@directbox.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.sep2011.funckit.view.projecttreemodel; import de.sep2011.funckit.util.Pair; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; /** * This class represents a tree node used by {@link ProjectTreeModel}. It * represents an object of type T. * * @param <T> * The type of the content this tree node represents. */ public abstract class ProjectTreeNode<T> { /** The list of children of this node. null if no children generated. */ List<ProjectTreeNode<?>> children; /** The {@link ProjectTreeModel} this node corresponds to. */ ProjectTreeModel treeModel; /** The parent of this node. */ ProjectTreeNode<?> parent; /** Stores the content of this node. */ T nodeContent; /** * Returns true if this Node is a leaf of the tree. * * @return true if this Node is a leaf of the tree. */ public abstract boolean isLeaf(); /** * Returns the parent of this node, null if this node has no parent. * * @return the parent of this node, null if this node has no parent. */ public ProjectTreeNode<?> getParent() { return parent; } /** * Returns the object the node represents. * * @return the object the node represents */ public T getContent() { return nodeContent; } /** * Tests if one of the direct children of this node contains the given * object as content. * * @param content * object to test * @return true if found, else false */ boolean childContainsContent(Object content) { for (ProjectTreeNode<?> node : children) { if (node.getContent().equals(content)) { return true; } } return false; } /** * Returns the node inside the list of children at the given index. * * @param index * the index of the node * @return the child node, null if the internal children list is null. */ public ProjectTreeNode<?> getChild(int index) { return children == null ? null : children.get(index); } /** * Returns the number of children this node has. * * @return the number of children this node has. */ public int getChildCount() { return children == null ? 0 : children.size(); } /** * Calling this method triggers the lazy creation of the nodes Children. * * @return true if the creation of the children succeeded, false if the node * could not generate its children. */ public abstract boolean generateChildren(); /** * Disposes all children. */ public void disposeChildren() { disposeChildren(true); } /** * Calls {@link #dispose()} on all children recursively. * * @param root * set this to true if this is the topmost node to dispose. */ void disposeChildren(boolean root) { if (children != null) { for (ProjectTreeNode<?> node : children) { node.disposeChildren(false); node.dispose(); } children = null; if (root) { treeModel.fireTreeStructureChanged(getAbsolutePath()); } } } /** * Returns the first child node inside the list of children which has the * given object as content. * * @param content * the content object of the node to find. * @return the found node, null is none is found. */ public ProjectTreeNode<?> getChildNodeByContent(Object content) { for (ProjectTreeNode<?> child : children) { if (child.getContent().equals(content)) { return child; } } return null; } /** * Get all child node which have one of the given object as content. * * @param contents * the content objects to get the nodes for * @return left: an array of indices of the corresponding child nodes <br> * right: an array of the corresponding child nodes as * {@link Object}s */ Pair<int[], Object[]> getChildNodesByContent(Collection<?> contents) { if (children == null) { return null; } LinkedList<Integer> idxes = new LinkedList<Integer>(); int idxCnt = 0; List<Object> affectedChildren = new LinkedList<Object>(); for (ProjectTreeNode<?> child : children) { for (Object cont : contents) { if (cont.equals(child.getContent())) { idxes.add(idxCnt); affectedChildren.add(child); break; } } idxCnt++; } int[] retArr = new int[idxes.size()]; int retCnt = 0; for (int idx : idxes) { retArr[retCnt] = idx; retCnt++; } return new Pair<int[], Object[]>(retArr, affectedChildren.toArray()); } /** * Returns the path from the root node to this node. * * @return the path from the root node to this node. */ public ProjectTreeNode<?>[] getAbsolutePath() { LinkedList<ProjectTreeNode<?>> path = new LinkedList<ProjectTreeNode<?>>(); for (ProjectTreeNode<?> parent = this; parent != null; parent = parent .getParent()) { path.addFirst(parent); } return path.toArray(new ProjectTreeNode<?>[0]); } /** * Simpler version for removeChildrenByContent with only one content object. * * @param content * the object to remove. * @return left: an array of indices of the removed child nodes <br> * right: an array of the removed child nodes as {@link Object}s */ Pair<int[], Object[]> removeChildrenByContent(Object content) { Object[] contents = { content }; return removeChildrenByContent(contents); } /** * This method removes all children which have one of the given content * objects as content. * * @param contents * the content objects for the corresponding children to remove, * @return */ Pair<int[], Object[]> removeChildrenByContent(Object[] contents) { if (children == null) { return null; } LinkedList<Integer> idxes = new LinkedList<Integer>(); int idxCnt = 0; List<ProjectTreeNode<?>> removedChildren = new LinkedList<ProjectTreeNode<?>>(); for (Iterator<ProjectTreeNode<?>> it = children.iterator(); it .hasNext();) { ProjectTreeNode<?> next = it.next(); for (Object cnt : contents) { if (next.getContent().equals(cnt)) { idxes.add(idxCnt); next.disposeChildren(); next.dispose(); it.remove(); removedChildren.add(next); break; } } idxCnt++; } int[] retArr = new int[idxes.size()]; int retCnt = 0; for (int idx : idxes) { retArr[retCnt] = idx; retCnt++; } return new Pair<int[], Object[]>(retArr, removedChildren.toArray()); } /** * Does everything to dispose this node (e.g. unregister as observer). */ protected abstract void dispose(); /** * Subclasses need to implement this and call visitor.visit(this). * * @param visitor * The visitor to accept. */ public abstract void accept(ProjectTreeNodeVisitor visitor); /** * Returns the index of the given child node. * * @param child * the child to get the index for. * @return the index of the given child node, -1 if the given node is not a * child of this node. */ int getIndexOfChild(ProjectTreeNode<?> child) { return children == null ? -1 : children.indexOf(child); } }