/* * Moonlight|3D Copyright (C) 2005 The Moonlight|3D team * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Created on Jan 5, 2005 */ package ml.backend.sg; /** * \package ml.backend.sg * * This is the backend scene graph. It contains classes for * editable representations of all data in the Moonlight|3D * scenes. * * This package is part of the core program. */ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import ml.backend.selection.PathElement; import ml.core.exceptions.Exception; import ml.core.helper.NamePool; import ml.core.helper.NamedObject; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** * This is the abstract base class for all scene graph nodes. * * @author gregor */ public abstract class Node implements Cloneable, PathElement, NamedObject { /** * Name of this node */ private String name; /** * Parent of this node */ private Node parent; /** * List of all children of this node */ protected ArrayList children; protected HashMap childrenMap; /** * Name pool for this node, used to prevent generation of duplicate node names */ private NamePool namePool; /** * Create an empty scene graph nodes. Cannot be used directly because * this class is abstract. * */ public Node() { children=new ArrayList(); childrenMap=new HashMap(); namePool=new NamePool(); } /** * Set the name of this scene graph node * @param name new name of this node */ public void setName(String name) { this.name=name; } /** * Get the name if this scene graph node * @return name of this node */ public String getName() { return name; } /** * Get the the name of this node with the full path * (the topmost root node is omitted as it does not have a name). */ public String getFullName() { if(parent==null) { return ""; } else if(parent.parent==null) { return getName(); } return parent.getFullName() + "/" + getName(); } /** * Set a parent for this scene graph node * * @param node new parent for this node */ public void setParent(Node node) { this.parent=node; } /** * Get parent of this scene graph node * @return parent of this node */ public Node getParent() { return parent; } /** * Generate a unique child name from the given base node name. * * @param nodeName the proposed node name to generate a unique name from * @return the unique name */ public String generateUniqueChildName(String nodeName) { return namePool.generateUniqueName(nodeName); } /** * Add the given node as a new child to the current scene graph node * * @param child the node to be added * @throws Exception */ public void addChild(Node child) throws Exception { if(!namePool.isNameUnique(child.getName())) { throw new ml.core.exceptions.Exception("a child node with the given name already exists"); } children.add(child); childrenMap.put(child.getName(),child); namePool.add(child); child.setParent(this); } /** * Return the child of this scene node with the given name * @param name name of the scene node to be queried for * @return the node with the requested name * @throws ml.core.exceptions.Exception if the requested node does not exist. */ public Node getChildByName(String name) throws ml.core.exceptions.Exception { Node child=childrenMap.get(name); if(child!=null) { return child; } throw new ml.core.exceptions.Exception("unable to find child with given name"); } /** * @return a copy of the list of children */ public List getChildren() { return (ArrayList)children.clone(); } /** * Remove a child with a given name if it exists * * @param name The name of the child to be removed */ public void removeChild(String name) { Node child=childrenMap.get(name); if(child==null) { return; } children.remove(child); childrenMap.remove(child); } /** * Return a string describing the type of this node. * * @return the type of this node */ public abstract String getType(); /** * Load the scene graph node data from the given XML tree. * Each class that wants to add new data to its serialised * form must overload this function and always call the * superclass implementation as well. * * @param dataElement the parent element of the XML data for this node * @throws Exception */ protected void loadXMLData(Element dataElement) throws Exception { // nothing to do here } /** * Load the scene graph node from the given XML tree. This * does the general setup work and calls loadXMLData() for * loading the actual object data. * * @param parentElement the parent element of the XML tree * @throws Exception */ public final void loadFromXML(Manager manager, Element parentElement) throws Exception { // load name setName(parentElement.getAttribute("name")); // load data NodeList dataList = parentElement.getElementsByTagName("data"); loadXMLData((Element) dataList.item(0)); // load children NodeList childrenList=((Element) parentElement.getElementsByTagName("children").item(0)).getChildNodes(); for(int i=0;i(); copy.children = new ArrayList(); for (Node child : children) { Node copiedChild = child.deepCopy(); copiedChild.setParent(copy); copy.addChild(copiedChild); } return copy; } public PathElement findChildElement(String path) { try { return getChildByName(path); } catch(Exception e) { return null; } } }