]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/Node.java
Merge "Documented difference of RuntimeEnvironmentRequest and Runti...quest2"
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / org / simantics / scenegraph / Node.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.scenegraph;
13
14 import java.beans.PropertyChangeListener;
15
16 import org.simantics.scenegraph.utils.NodeUtil;
17
18 /**
19  * @author J-P
20  */
21 public abstract class Node implements INode {
22
23     private static final long                  serialVersionUID       = -5540999051056414851L;
24
25     /**
26      * The scene graph is essentially single-threaded, meaning nodes should be
27      * created in one thread only. For this reason, we are not using AtomicLong
28      * here.
29      */
30     public transient static long               IDCOUNTER              = 1;
31     protected long                             id                     = IDCOUNTER++;
32
33     protected transient ParentNode<?>          parent                 = null;
34     protected transient Location               location               = Location.LOCAL;
35
36     // This is for internal server communications. Do not touch.
37     // Support for only one listener should be enough, thus we don't need PropertyChangeSupport
38     protected transient PropertyChangeListener propertyChangeListener = null;
39
40     /**
41      * @see org.simantics.scenegraph.INode#getId()
42      */
43     public long getId() {
44         return id;
45     }
46
47     /**
48      * @see org.simantics.scenegraph.INode#getParent()
49      */
50     public ParentNode<?> getParent() {
51         return parent;
52     }
53
54     /**
55      * @see org.simantics.scenegraph.INode#setParent(org.simantics.scenegraph.ParentNode)
56      */
57     public void setParent(ParentNode<?> parent) {
58         this.parent = parent;
59     }
60
61     /**
62      * The default implementation of {@link #getRootNode()} always asks for the
63      * root node from the parent. Scene graph leaf nodes are never considered to
64      * be real scene graph root nodes, although they are can be thought of as
65      * such when they are not attached to any scene graph. This implementation
66      * prevents the need to have a separate rootNodeCache field in all nodes.
67      * 
68      * @see org.simantics.scenegraph.INode#getRootNode()
69      */
70     public ParentNode<?> getRootNode() {
71         return parent != null ? parent.getRootNode() : null;
72     }
73
74     public void remove() {
75         if (parent != null) {
76             parent.asyncRemoveNode(this);
77         }
78     }
79
80     /**
81      * @see org.simantics.scenegraph.INode#init()
82      */
83     public void init() {
84     }
85
86     /**
87      * @see org.simantics.scenegraph.INode#cleanup()
88      */
89     public void cleanup() {
90         retractMapping();
91     }
92
93     /**
94      * @see org.simantics.scenegraph.INode#delete()
95      */
96     public void delete() {
97         // 1. Remove this node from parent
98         parent.asyncRemoveNode(this);
99     }
100
101     /**
102      * Remove any ID<->Node mapping this node might have in the scene graph's
103      * {@link LookupService}.
104      */
105     protected void retractMapping() {
106         NodeUtil.tryUnmap(this);
107     }
108
109     public <TC> TC appendParent(String id, Class<TC> nc) {
110         assert(parent != null);
111
112         // 0. Find identifier from parent
113         String identifier = null;
114         for(String s : parent.children.keySet()) { // FIXME: should not be this complicated
115             if(parent.children.get(s) == this) { // Find this from parent child list
116                 identifier = s;
117                 break;
118             }
119         }
120         if (identifier == null)
121             identifier = "" + this.id;
122
123         // 1. Remove this node from original parent
124         parent.unlinkChild(this);
125
126         // 2. Add new node under parent
127         TC instance = parent.addNode(id, nc);
128
129         // 3. Add this node under new parent
130         ((ParentNode<?>)instance).appendChild(identifier, this);
131
132         return instance;
133     }
134
135     @Override
136     public String toString() {
137         return getSimpleClassName() + " (" + id + ")";
138     }
139
140     public String getSimpleClassName() {
141         return getSimpleClassName(getClass());
142     }
143
144     public static String getSimpleClassName(Class<?> clazz) {
145         String name = clazz.getSimpleName();
146         int pos = name.indexOf("$$");
147         if (pos >= 0)
148             name = name.substring(0, pos);
149         return name;
150     }
151
152     /**
153      * Associates this node with the specified ID in the {@link ILookupService}
154      * that must be offered by the scene graph root node. After this
155      * association, one can use {@link NodeUtil#lookup(INode, String)} to lookup
156      * this node from the scene graph by its ID.
157      * 
158      * @param id
159      * @throws UnsupportedOperationException if no ILookupService is available
160      *         for this node
161      */
162     @ClientSide
163     public void setLookupId(String id) {
164         NodeUtil.getLookupService(this).map(id, this);
165     }
166
167     /**
168      * A shorthand utility for {@link NodeUtil#lookup(INode, String, Class)}.
169      * 
170      * @param id
171      * @param clazz
172      * @return
173      */
174     protected <T extends INode> T lookupNode(String id, Class<T> clazz) {
175         return NodeUtil.lookup(this, id, clazz);
176     }
177
178     /**
179      * A shorthand utility for {@link NodeUtil#lookupId(INode)}).
180      * 
181      * @param node
182      * @return
183      */
184     protected String lookupId(INode node) {
185         return NodeUtil.lookupId(node);
186     }
187
188 }