--- /dev/null
+package org.simantics.scenegraph.loader;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.Map;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.binding.mutable.Variant;\r
+import org.simantics.databoard.util.ObjectUtils;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.variable.ConstantPropertyVariable;\r
+import org.simantics.db.layer0.variable.StandardGraphChildVariable;\r
+import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.db.layer0.variable.Variables;\r
+import org.simantics.scenegraph.INode;\r
+\r
+public class ScenegraphVariable extends StandardGraphChildVariable {\r
+\r
+ final private SceneGraphContext context;\r
+ final private Map<String, Variant> originalProperties;\r
+ final private Map<String, Variable> properties;\r
+ \r
+ public ScenegraphVariable(Variable parent, Resource resource, final Resource runtime, final INode root) {\r
+ this(parent, resource, runtime, root, Collections.<String, Variant>emptyMap());\r
+ }\r
+\r
+ public static class SceneGraphContextImpl implements SceneGraphContext {\r
+\r
+ final private ScenegraphVariable parent;\r
+ final private Resource runtime;\r
+ final private INode root;\r
+ \r
+ public SceneGraphContextImpl(ScenegraphVariable parent, Resource runtime, INode root) {\r
+ assert(root != null);\r
+ this.parent = parent;\r
+ this.runtime = runtime;\r
+ this.root = root;\r
+ }\r
+\r
+ @Override\r
+ public INode getRoot() {\r
+ return root;\r
+ }\r
+ \r
+ @Override\r
+ public Resource getRuntime() {\r
+ return runtime;\r
+ }\r
+ \r
+ @Override\r
+ public Variable getRuntimeVariable() {\r
+ return new ScenegraphVariable(parent, runtime, runtime, root, parent.originalProperties);\r
+ }\r
+ \r
+ @Override\r
+ public int hashCode() {\r
+ \r
+ return runtime.hashCode() ^ ObjectUtils.hashCode(root);\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public boolean equals(Object obj) {\r
+ \r
+ if(this == obj) return true;\r
+ \r
+ SceneGraphContextImpl other = (SceneGraphContextImpl)obj;\r
+ \r
+ if(!runtime.equals(other.runtime)) return false;\r
+ if(!ObjectUtils.objectEquals(root, other.root)) return false;\r
+ \r
+ return true;\r
+ \r
+ }\r
+ \r
+ \r
+ }\r
+ \r
+ public ScenegraphVariable(Variable parent, Resource resource, final Resource runtime, final INode root, final Map<String, Variant> properties) {\r
+ \r
+ super(parent, null, resource);\r
+\r
+ if(runtime != null) {\r
+ this.context = new SceneGraphContextImpl(this, runtime, root);\r
+ } else {\r
+ this.context = null;\r
+ }\r
+ this.originalProperties = properties;\r
+ if(properties.isEmpty()) this.properties = Collections.<String, Variable>emptyMap();\r
+ else {\r
+ this.properties = new THashMap<String, Variable>();\r
+ for(Map.Entry<String, Variant> p : properties.entrySet()) {\r
+ this.properties.put(p.getKey(), new ConstantPropertyVariable(parent, p.getKey(), p.getValue().getValue(), p.getValue().getBinding()));\r
+ }\r
+ }\r
+ \r
+ }\r
+\r
+ @Override\r
+ public String getName(ReadGraph graph) throws DatabaseException {\r
+ if(parent instanceof ScenegraphVariable) {\r
+ return super.getName(graph);\r
+ } else {\r
+ return "" + System.identityHashCode(this);\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public Variable getNameVariable(ReadGraph graph) throws DatabaseException {\r
+ if(parent instanceof ScenegraphVariable) {\r
+ return super.getNameVariable(graph);\r
+ } else {\r
+ return new ConstantPropertyVariable(parent, Variables.NAME, "" + System.identityHashCode(this), Bindings.STRING);\r
+ }\r
+ }\r
+\r
+ protected <T> T tryAdapt(ReadGraph graph, Class<T> clazz) throws DatabaseException {\r
+ if(SceneGraphContext.class == clazz) return (T)context;\r
+ else if(INode.class == clazz) return (T)context.getRoot();\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ public <T> T adapt(ReadGraph graph, Class<T> clazz) throws DatabaseException {\r
+ T t = tryAdapt(graph, clazz);\r
+ return t != null ? t : super.adapt(graph, clazz);\r
+ }\r
+\r
+ @Override\r
+ public <T> T adaptPossible(ReadGraph graph, Class<T> clazz) throws DatabaseException {\r
+ T t = tryAdapt(graph, clazz);\r
+ return t != null ? t : super.adaptPossible(graph, clazz);\r
+ }\r
+\r
+ @Override\r
+ public boolean equals(Object obj) {\r
+ \r
+ // First check \r
+ if(!super.equals(obj)) return false;\r
+ \r
+ ScenegraphVariable other = (ScenegraphVariable)obj;\r
+ SceneGraphContext otherContext = other.context;\r
+\r
+ return ObjectUtils.objectEquals(context, otherContext);\r
+ \r
+ }\r
+\r
+ @Override\r
+ public int hashCode() {\r
+ int s = super.hashCode();\r
+ if(context != null) s ^= context.getRuntime().hashCode();\r
+ return s;\r
+ }\r
+ \r
+ @Override\r
+ public Collection<Variable> getChildren(ReadGraph graph) throws DatabaseException {\r
+ return ScenegraphLoaderUtils.computeChildren(graph, this);\r
+ }\r
+ \r
+ @Override\r
+ public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException {\r
+ for(Variable child : getChildren(graph)) {\r
+ if(child.getName(graph).equals(name)) return child;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ public void collectExtraProperties(ReadGraph graph, Map<String, Variable> properties) throws DatabaseException {\r
+ properties.putAll(this.properties);\r
+ }\r
+ \r
+ @Override\r
+ public Variable getPossibleExtraProperty(ReadGraph graph, String name) throws DatabaseException {\r
+ return properties.get(name);\r
+ }\r
+ \r
+}\r