/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.scenegraph; import java.beans.PropertyChangeListener; import org.simantics.scenegraph.utils.NodeUtil; /** * @author J-P */ public abstract class Node implements INode { private static final long serialVersionUID = -5540999051056414851L; public transient static long IDCOUNTER = 1; protected transient ParentNode parent = null; protected transient Location location = Location.LOCAL; // This is for internal server communications. Do not touch. // Support for only one listener should be enough, thus we don't need PropertyChangeSupport protected transient PropertyChangeListener propertyChangeListener = null; protected Long id = IDCOUNTER++; /** * @see org.simantics.scenegraph.INode#getId() */ public Long getId() { return id; } /** * @see org.simantics.scenegraph.INode#getParent() */ public ParentNode getParent() { return parent; } /** * @see org.simantics.scenegraph.INode#setParent(org.simantics.scenegraph.ParentNode) */ public void setParent(ParentNode parent) { this.parent = parent; } /** * The default implementation of {@link #getRootNode()} always asks for the * root node from the parent. Scene graph leaf nodes are never considered to * be real scene graph root nodes, although they are can be thought of as * such when they are not attached to any scene graph. This implementation * prevents the need to have a separate rootNodeCache field in all nodes. * * @see org.simantics.scenegraph.INode#getRootNode() */ public ParentNode getRootNode() { return parent != null ? parent.getRootNode() : null; } public void remove() { if (parent != null) { parent.asyncRemoveNode(this); } } /** * @see org.simantics.scenegraph.INode#init() */ public void init() { } public void attach() { } /** * @see org.simantics.scenegraph.INode#cleanup() */ public void cleanup() { retractMapping(); } /** * @see org.simantics.scenegraph.INode#delete() */ public void delete() { // 1. Remove this node from parent parent.asyncRemoveNode(this); } /** * Remove any ID<->Node mapping this node might have in the scene graph's * {@link LookupService}. */ protected void retractMapping() { NodeUtil.tryUnmap(this); } public TC appendParent(String id, Class nc) { assert(parent != null); // 0. Find identifier from parent String identifier = null; for(String s : parent.children.keySet()) { // FIXME: should not be this complicated if(parent.children.get(s) == this) { // Find this from parent child list identifier = s; break; } } if (identifier == null) identifier = "" + this.id; // 1. Remove this node from original parent parent.unlinkChild(this); // 2. Add new node under parent TC instance = parent.addNode(id, nc); // 3. Add this node under new parent ((ParentNode)instance).appendChild(identifier, this); return instance; } @Override public String toString() { return getSimpleClassName() + " (" + id + ")"; } public String getSimpleClassName() { return getSimpleClassName(getClass()); } public static String getSimpleClassName(Class clazz) { String name = clazz.getSimpleName(); int pos = name.indexOf("$$"); if (pos >= 0) name = name.substring(0, pos); return name; } /** * Associates this node with the specified ID in the {@link ILookupService} * that must be offered by the scene graph root node. After this * association, one can use {@link NodeUtil#lookup(INode, String)} to lookup * this node from the scene graph by its ID. * * @param id * @throws UnsupportedOperationException if no ILookupService is available * for this node */ @ClientSide public void setLookupId(String id) { NodeUtil.getLookupService(this).map(id, this); } /** * A shorthand utility for {@link NodeUtil#lookup(INode, String, Class)}. * * @param id * @param clazz * @return */ protected T lookupNode(String id, Class clazz) { return NodeUtil.lookup(this, id, clazz); } /** * A shorthand utility for {@link NodeUtil#lookupId(INode)}). * * @param node * @return */ protected String lookupId(INode node) { return NodeUtil.lookupId(node); } }