]> gerrit.simantics Code Review - simantics/interop.git/blobdiff - org.simantics.interop.diagram/src/org/simantics/interop/diagram/Diagram.java
Java API for diagrams, work in progress
[simantics/interop.git] / org.simantics.interop.diagram / src / org / simantics / interop / diagram / Diagram.java
diff --git a/org.simantics.interop.diagram/src/org/simantics/interop/diagram/Diagram.java b/org.simantics.interop.diagram/src/org/simantics/interop/diagram/Diagram.java
new file mode 100644 (file)
index 0000000..5695798
--- /dev/null
@@ -0,0 +1,711 @@
+package org.simantics.interop.diagram;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.RequestProcessor;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.procedure.adapter.TransientCacheListener;
+import org.simantics.db.common.request.ResourceRead;
+import org.simantics.db.common.utils.OrderedSetUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
+import org.simantics.db.exception.NoSingleResultException;
+import org.simantics.db.exception.ServiceException;
+import org.simantics.db.layer0.adapter.Template;
+import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
+import org.simantics.g2d.page.DiagramDesc;
+import org.simantics.layer0.Layer0;
+import org.simantics.modeling.ModelingResources;
+import org.simantics.operation.Layer0X;
+import org.simantics.simulation.ontology.SimulationResource;
+import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.utils.datastructures.Arrays;
+import org.simantics.utils.page.PageDesc;
+
+
+/**
+ * @author Marko Luukkainen
+ */
+public abstract class Diagram<T extends Symbol> {
+       
+       public static boolean DO_NO_MIX_SECTION_NAMES = false;
+       public static boolean USE_MERGE_CONNECTS = true;
+       
+       private Resource composite;
+       private Resource diagram;
+               
+       private Map<Resource,Integer> indexMap  = new HashMap<Resource, Integer>();
+       
+       private Map<Resource,T> elementToSymbolMap = new HashMap<Resource, T>();
+       
+       private Map<Resource,Diagram<T>> compositeToDiagramMap = new HashMap<Resource, Diagram<T>>();
+       
+       protected Diagram(ReadGraph g, Resource composite, Resource diagram) throws DatabaseException {
+               this.composite = composite;
+               this.diagram = diagram;
+       }
+       
+       protected abstract Diagram<T> construct(ReadGraph g, Resource composite, Resource diagram) throws DatabaseException;
+       protected abstract T constructSymbol(ReadGraph g, Resource element, Resource component) throws DatabaseException;
+       
+       public Resource getComposite() {
+               return composite;
+       }
+       
+       public Resource getDiagram() {
+               return diagram;
+       }
+       
+       
+       public void clearCaches() {
+               for (Diagram<T> d : compositeToDiagramMap.values()) {
+                       for (T s : d.elementToSymbolMap.values())
+                               s.dispose();
+                       d.elementToSymbolMap.clear();
+               }
+               compositeToDiagramMap.clear();
+       }
+       
+       
+       public String generateName(ReadGraph g, Resource type, String name) throws DatabaseException {
+               Layer0 l0 = Layer0.getInstance(g);
+               Layer0X l0x = Layer0X.getInstance(g);
+               String prefix = g.getPossibleRelatedValue(type, l0x.HasGeneratedNamePrefix);
+               if (prefix == null || prefix.length() == 0)
+                       prefix = g.getRelatedValue(type, l0.HasName);
+               prefix += "_";          
+               Set<String> reserved = null;
+               if (name != null) {
+                       reserved = getAllModuleNamesForModel(g, composite);
+                       int index = 0;
+                       String realname = name + "_" + prefix;
+                       while (true) {
+                               String toTry = realname + Integer.toString(index);
+                               if (!reserved.contains(toTry))
+                                       break;
+                               index++;
+                       }
+                       realname += Integer.toString(index);
+                       return realname;
+               }
+               Integer index = indexMap.get(type);
+               if (index != null) {
+                       index++;        
+               } else {
+                       if (reserved == null)
+                               reserved = getAllModuleNamesForModel(g, composite);
+                       index = 0;
+                       while (true) {
+                               String toTry = prefix + Integer.toString(index);
+                               if (!reserved.contains(toTry))
+                                       break;
+                               index++;
+                       }
+                       
+               }
+               indexMap.put(type, index);
+               return prefix + index;
+       }
+       
+       private Set<String> getAllModuleNamesForModel(ReadGraph graph, final Resource res) throws DatabaseException {
+
+               Resource model = DiagramUtils.getModel(graph, res);
+               Resource configuration = DiagramUtils.getConfiguration(graph, model);
+               Set<String> names = new HashSet<String>();
+               Collection<Resource> composites = getAllComposites(graph, configuration);
+               for (Resource composite : composites) {
+                       names.addAll(getAllModuleNamesForComposite(graph, composite));
+               }
+               return names;
+       }
+       
+       protected abstract Resource getGraphicalCompositeType(ReadGraph graph) throws DatabaseException;
+       protected abstract Resource getFolderType(ReadGraph graph) throws DatabaseException;
+       
+       @SuppressWarnings("unchecked")
+       private Collection<Resource> getAllComposites(RequestProcessor processor, Resource configuration) throws DatabaseException {
+               return (Set<Resource>)processor.syncRequest(new ResourceRead<Object>(configuration) {
+                       @Override
+                       public Object perform(ReadGraph graph) throws DatabaseException {
+                               Layer0 l0 = Layer0.getInstance(graph);
+                               Set<Resource> composites = new HashSet<Resource>();
+                               Stack<Resource> resources = new Stack<Resource>();
+                               Resource graphicalCompositeType = getGraphicalCompositeType(graph);
+                               Resource folderType = getFolderType(graph);
+                               resources.add(resource);
+                               while (!resources.isEmpty()) {
+                                       Resource r = resources.pop();
+                                       if (graph.isInstanceOf(r, graphicalCompositeType)) {
+                                               composites.add(r);
+                                       } else if (folderType != null && graph.isInstanceOf(r, folderType)){
+                                               resources.addAll(graph.getObjects(r, l0.ConsistsOf));
+                                       }
+                               }
+                               return composites;
+                       }
+               }, TransientCacheListener.instance());
+       }
+       
+       @SuppressWarnings("unchecked")
+       private Set<String> getAllModuleNamesForComposite(RequestProcessor processor, Resource composite) throws DatabaseException {
+               return (Set<String>)processor.syncRequest(new ResourceRead<Object>(composite) {
+                       @Override
+                       public Object perform(ReadGraph graph) throws DatabaseException {
+                               Layer0 l0 = Layer0.getInstance(graph);
+                               Set<String> names = new HashSet<String>();
+                               Collection<Resource> components = graph.getObjects(resource, l0.ConsistsOf);
+                               for (Resource component : components) {
+                                       String n = graph.getPossibleRelatedValue(component, l0.HasName, Bindings.STRING);
+                                       if (n != null)
+                                               names.add(n);
+                               }
+                               return names;
+                       }
+               }, TransientCacheListener.instance());
+               
+       }
+       
+       public Diagram<T> createDiagram(WriteGraph g,String name, Resource compositeType, Resource parent) throws DatabaseException {
+               return createDiagram(g, name, null, null,compositeType, parent);
+       }
+       
+       
+       
+       /**
+        * Creates a new Diagram
+        * @param g
+        * @param name name of the diagram
+        * @param compositeType composite type of the diagram
+        * @param parent resource where diagram is added
+        * @return
+        * @throws DatabaseException
+        */
+       @SuppressWarnings("deprecation")
+       public Diagram<T> createDiagram(WriteGraph g,String name, DiagramDesc desc, Template tpl, Resource compositeType, Resource parent) throws DatabaseException {
+               Layer0 l0 = Layer0.getInstance(g);
+               Layer0X l0x = Layer0X.getInstance(g);
+               ModelingResources m = ModelingResources.getInstance(g);
+               
+               // create composite
+               Resource composite = g.newResource();
+               g.claim(composite, l0.InstanceOf, compositeType);
+               
+               // create diagram
+               Resource diagramType = getDiagramFromComposite(g, compositeType);
+               
+               Resource diagram = OrderedSetUtils.create(g, diagramType);
+               
+               g.claim(composite, m.CompositeToDiagram, diagram);
+               
+               // link to parent and set name
+               g.claimLiteral(composite, l0.HasName, name);
+               g.claim(composite, l0.PartOf, parent);
+               
+               // activate mapping
+               Resource mapping = g.newResource();
+        g.claim(mapping, l0.InstanceOf, m.DiagramToCompositeMapping);
+        g.claim(diagram, l0x.HasTrigger, mapping);
+        
+        if (tpl != null) {
+               Map<String,Object> params = new HashMap<String, Object>();
+               params.put("diagram", diagram);
+               tpl.apply(g, params);
+        }
+        
+        
+        // Make diagram part of a dummy container library attached to the parent
+        // composite if it's not already part of something.
+        // This gives the diagram a proper URI without connecting it directly to the composite with ConsistsOf.
+        // This would cause problems because a diagram is a structural composite/component also.
+        g.claimLiteral(diagram, l0.HasName, name, Bindings.STRING);
+        Resource container = g.newResource();
+        g.claim(container, l0.InstanceOf, null, l0.Library);
+        g.addLiteral(container, l0.HasName, l0.NameOf, l0.String, "__CONTAINER__", Bindings.STRING);
+        g.claim(container, l0.ConsistsOf, diagram);
+        g.claim(composite, l0.ConsistsOf, container);
+        
+        if (desc != null)
+               DiagramGraphUtil.setDiagramDesc(g, diagram, desc);
+               
+               Diagram<T> diag = construct(g, composite, diagram);
+               diag.compositeToDiagramMap = compositeToDiagramMap;
+               compositeToDiagramMap.put(composite, diag);
+               return diag;
+       }
+       
+       public Diagram<T> fromExisting(ReadGraph g, Resource diagram) throws DatabaseException {
+               ModelingResources m = ModelingResources.getInstance(g);
+               StructuralResource2 s = StructuralResource2.getInstance(g);
+               Resource composite = null;
+               if (g.isInstanceOf(diagram, s.Composite)) {
+                       composite = diagram;
+                       diagram = g.getPossibleObject(composite, m.CompositeToDiagram);
+                       if (diagram == null)
+                               return null;
+               } else {
+                       composite = g.getPossibleObject(diagram, m.DiagramToComposite);
+                       if (composite == null)
+                               return null;
+               }
+               
+               Diagram<T> diag = compositeToDiagramMap.get(composite);
+               if (diag != null)
+                       return diag;
+               
+               diag =  construct(g,composite, diagram);
+               diag.compositeToDiagramMap = compositeToDiagramMap;
+               compositeToDiagramMap.put(composite, diag);
+               return diag;
+       }
+       
+       
+       
+       
+       
+       /**
+        * Returns diagram type from composite type
+        * @param g
+        * @param compositeType
+        * @return diagram type
+        * @throws NoSingleResultException
+        * @throws ManyObjectsForFunctionalRelationException
+        * @throws ServiceException
+        */
+       private static Resource getDiagramFromComposite(ReadGraph g, Resource compositeType) throws DatabaseException {
+               ModelingResources m  = ModelingResources.getInstance(g);
+               Collection<Resource> diagramTemplates = g.getAssertedObjects(compositeType, m.HasModelingTemplate);
+               for (Resource diagramTemplate : diagramTemplates) {
+                       Resource diagramType = g.getPossibleObject(diagramTemplate, m.HasDiagramType);
+                       if (diagramType != null)
+                               return diagramType;
+                               
+               }
+               throw new RuntimeException("Cannot find diagramType for composite " + compositeType);
+       }
+       
+       
+
+       
+       /**
+        * Adds new symbol to a diagram
+        * @param g
+        * @param symbolType
+        * @return
+        * @throws DatabaseException
+        */
+       public T addSymbol(WriteGraph g, Resource symbolType) throws DatabaseException {
+               return addSymbol(g, symbolType, 0, 0);
+       }
+       
+       /**
+        * Adds new symbol to a diagram
+        * @param g
+        * @param symbolType
+        * @param name
+        * @return
+        * @throws DatabaseException
+        */
+       public T addSymbol(WriteGraph g, Resource symbolType, String name) throws DatabaseException {
+               return addSymbol(g, symbolType, name, 0, 0);
+       }
+       
+       /**
+        * Adds new symbol to a diagram
+        * @param g
+        * @param diagramConf Diagram configuration
+        * @param symbolType type of the new symbol
+        * @param x
+        * @param y
+        * @return configuration of the new Symbol
+        * @throws DatabaseException
+        */
+       public T addSymbol(WriteGraph g, Resource symbolType, double x, double y) throws DatabaseException {
+               return addSymbol(g, symbolType,null,x,y);
+       }
+       
+       /**
+        * Adds new symbol to a diagram
+        * @param g
+        * @param elementType
+        * @param name
+        * @param x
+        * @param y
+        * @return
+        * @throws DatabaseException
+        */
+       public T addSymbol(WriteGraph g, Resource elementType, String name, double x, double y) throws DatabaseException {
+               if (elementType == null)
+                       throw new NullPointerException("Element type is null");
+               Layer0 l0 = Layer0.getInstance(g);
+
+               DiagramResource d = DiagramResource.getInstance(g);
+               ModelingResources m = ModelingResources.getInstance(g);
+               
+               Resource componentType = null;
+               if (g.isInheritedFrom(elementType, d.DefinedElement))
+                       componentType = Symbol.getComponentTypeFromSymbolType(g, elementType);
+               else {
+                       componentType = elementType;
+                       elementType = Symbol.getSymbolTypeFromComponentType(g,componentType);
+               }
+                       
+               
+               Resource element = g.newResource();
+               g.claim(element, l0.InstanceOf, elementType);
+
+               Resource module = g.newResource();
+               g.claim(module, l0.InstanceOf, componentType);
+               
+               g.claim(module, m.ComponentToElement, element);
+               g.claim(module, m.Mapped, module);
+
+               String id = generateName(g, componentType, name);
+               g.claimLiteral(module, l0.HasName, id);
+               g.claimLiteral(element, l0.HasName, id);
+               
+               OrderedSetUtils.add(g, this.diagram, element);
+               g.claim(this.diagram, l0.ConsistsOf, element);
+               g.claim(this.composite, l0.ConsistsOf, module);
+               
+               T s =  constructSymbol(g, element, module);
+               s.setSymbolTranslation(g, x, y);
+               
+               elementToSymbolMap.put(element, s);
+               return s;
+       }
+       
+       /**
+        * Returns a Symbol for given resource.
+        * @param g
+        * @param element Element or Component of the Symbol.
+        * @return
+        * @throws ManyObjectsForFunctionalRelationException
+        * @throws ServiceException
+        * @throws NoSingleResultException
+        */
+       public T getSymbol(ReadGraph g, Resource element) throws DatabaseException {
+               ModelingResources mr = ModelingResources.getInstance(g);
+               DiagramResource dr = DiagramResource.getInstance(g);
+               if (g.isInstanceOf(element, dr.Element))
+                       return getSymbol(g, element, g.getPossibleObject(element, mr.ElementToComponent));
+               else
+                       return getSymbol(g, g.getSingleObject(element, mr.ComponentToElement), element);
+       }
+       
+       /**
+        * Returns a Symbol for given resource.
+        * @param g
+        * @param element Element Resource of the Symbol.
+        * @param component Component  Resource of the symbol. 
+        * @return
+        */
+       public T getSymbol(ReadGraph g, Resource element, Resource component) throws DatabaseException {
+               T s = elementToSymbolMap.get(element);
+               if (s == null) {
+                       // TODO : check that symbol actually belongs to this diagram
+                       s = constructSymbol(g, element, component);
+                       elementToSymbolMap.put(element, s);
+               } else {
+                       if (s.component == null)
+                               s.component = component;
+                       else if (!s.component.equals(component)) {
+                               // FIXME : ?
+                               return constructSymbol(g, element, component);
+                       }
+               }
+               return s;
+       }
+       
+       /**
+        *  Adds new element to a diagram
+        * @param g
+        * @param symbolType type of the element.
+        * @param x
+        * @param y
+        * @return
+        * @throws DatabaseException
+        */
+       public T addElement(WriteGraph g, Resource symbolType, double x, double y) throws DatabaseException {
+               Layer0 l0 = Layer0.getInstance(g);
+
+               Resource element = g.newResource();
+               g.claim(element, l0.InstanceOf, symbolType);
+                               
+               DiagramUtils.addElement(g, this, element);
+               
+               T s = constructSymbol(g,element,null);
+               
+               s.setSymbolTranslation(g, x, y);
+               
+               elementToSymbolMap.put(element, s);
+               return s;
+       }
+       
+       public T getSingleSymbol(ReadGraph g, String symbolName) throws DatabaseException {
+               List<T> matching = getSymbol(g, symbolName);
+               if (matching.size() == 1)
+                       return matching.get(0);
+               if (matching.size() == 0)
+                       return null;
+               throw new NoSingleResultException("There are multiple symbols with name '" + symbolName);
+       }
+       
+       public T getPossibleSymbol(ReadGraph g, String symbolName) throws DatabaseException {
+               List<T> matching = getSymbol(g, symbolName);
+               if (matching.size() == 1)
+                       return matching.get(0);
+               return null;
+       }
+       
+       /**
+        * Returns all symbols on the diagram
+        * @param g
+        * @return
+        * @throws DatabaseException
+        */
+       public List<T> getSymbols(ReadGraph g) throws DatabaseException {
+               ModelingResources m = ModelingResources.getInstance(g);
+               List<T> matching = new ArrayList<T>();
+               for (Resource element : OrderedSetUtils.toList(g, diagram)) {
+                       Resource component = g.getPossibleObject(element, m.ElementToComponent);
+                       matching.add(getSymbol(g,element, component));
+               }
+               return matching;
+       }
+       
+       /**
+        * Returns symbols that have matching name.
+        * 
+        * Prioritizes L0.HasLabel over L0.HasName (If symbol has label, it is used for comparison).
+        * 
+        * ';' character acts as a splitter, allowing input parameter and a label contain multiple identifiers.
+        *
+        * All the splits  
+        * 
+        * @param g
+        * @param symbolName
+        * @return
+        * @throws DatabaseException
+        */
+       public List<T> getSymbol(ReadGraph g, String symbolName) throws DatabaseException {
+               ModelingResources m = ModelingResources.getInstance(g);
+               Layer0 b = Layer0.getInstance(g);
+               List<T> matching = new ArrayList<T>();
+               
+               String splitId[] = symbolName.split(";");
+               
+               for (Resource element : OrderedSetUtils.toList(g, diagram)) {
+                       Resource component = g.getPossibleObject(element, m.ElementToComponent);
+                       if (component == null)
+                               component = g.getPossibleObject(element, m.HasParentComponent);
+                       if (component == null)
+                               continue;
+                       String label = g.getPossibleRelatedValue(component, b.HasLabel);
+                       String name = g.getRelatedValue(component, b.HasName);
+                       if (label != null) {
+                               String splitLabel[] = label.split(";");
+                               
+                               boolean match = true;
+                               for (int i = 0; i < splitId.length; i++) {
+                                       if(!Arrays.contains(splitLabel, splitId[i])) {
+                                               match = false;
+                                               break;
+                                       }
+                               }
+                               if (match) {
+                                       matching.add(getSymbol(g,element, component));
+                               } else {
+                                       if (label.equals(symbolName) || name.equals(symbolName)) {
+                                               matching.add(getSymbol(g,element, component));
+                                               
+                                       }
+                               }
+                               
+                       } else {
+                               for (String split : splitId) {
+                                       if (name.equals(split)) {
+                                               matching.add(getSymbol(g,element, component));
+                                       }
+                               }
+                               
+                       }
+               }
+               return matching;
+       }
+       
+       /**
+        * Returns a single symbol matching given name and type. If matching symbol cannot be found, returns null.
+        * Throws a NoSingleResultException if the re are multiple symbols matching the criteria.
+        * 
+        * @param g
+        * @param symbolName
+        * @param symbolType
+        * @return 
+        * @throws DatabaseException
+        */
+       public T getSingleSymbol(ReadGraph g, String symbolName, Resource symbolType) throws DatabaseException {
+               List<T> matching = getSymbol(g, symbolName, symbolType);
+               if (matching.size() == 1)
+                       return matching.get(0);
+               if (matching.size() == 0)
+                       return null;
+               throw new NoSingleResultException("There are multiple symbols with name '" + symbolName + "' and type " + symbolType);
+       }
+       
+       public T getPossibleSymbol(ReadGraph g, String symbolName, Resource symbolType) throws DatabaseException {
+               List<T> matching = getSymbol(g, symbolName, symbolType);
+               if (matching.size() == 1)
+                       return matching.get(0);
+               return null;
+       }
+       
+       /**
+        * Returns symbols matching given name and type. 
+        * 
+        * @param g
+        * @param symbolName
+        * @param symbolType
+        * @return 
+        * @throws DatabaseException
+        */
+       public List<T> getSymbol(ReadGraph g, String symbolName, Resource symbolType) throws DatabaseException {
+
+               List<T> nameMatching = getSymbol(g, symbolName);
+               List<T> matching = new ArrayList<T>();
+               for (T s : nameMatching) {
+                       if ((g.isInstanceOf(s.getElement(), symbolType)||
+                                        g.isInstanceOf(s.getComponent(), symbolType))) {
+                                       matching.add(s);
+                               }
+               }
+               return matching;
+       }
+       
+       public Symbol getFlag(ReadGraph g, Resource flagType, String symbolName, Resource symbolType) throws DatabaseException {
+               Layer0 b = Layer0.getInstance(g);
+               DiagramResource dr = DiagramResource.getInstance(g);
+               List<Symbol> matching = new ArrayList<Symbol>();
+               for (Resource flag : OrderedSetUtils.toList(g, diagram)) {
+                       if (!g.isInstanceOf(flag, dr.Flag))
+                               continue;
+                       if (!g.getSingleObject(flag, dr.HasFlagType).equals(flagType))
+                               continue;
+                       Symbol flagSymbol = getSymbol(g,flag, null);
+
+                       Symbol connectedSymbol = flagSymbol.getDiagramSingleConnected(g, dr.Flag_ConnectionPoint);
+                       Resource component = connectedSymbol.getComponent();
+                       if (component == null)
+                               continue;
+                       String label = g.getPossibleRelatedValue(component, b.HasLabel);
+                       String name = g.getRelatedValue(component, b.HasName);
+                       if (label != null) {
+                               String splitId[] = symbolName.split(";");
+                               if (splitId.length > 1) {
+                                       String splitLabel[] = label.split(";");
+                                       boolean match = true;
+                                       for (int i = 0; i < splitId.length; i++) {
+                                               if(!Arrays.contains(splitLabel, splitId[i])) {
+                                                       match = false;
+                                                       break;
+                                               }
+                                       }
+                                       if (match) {
+                                               if (g.isInstanceOf(connectedSymbol.getElement(), symbolType)||
+                                                       g.isInstanceOf(component, symbolType)) {
+                                                       matching.add(getSymbol(g,flag, null));
+                                               }
+                                               
+                                       }
+                               } else {
+                                       if (label.equals(symbolName) || name.equals(symbolName)) {
+                                               if (g.isInstanceOf(connectedSymbol.getElement(), symbolType)||
+                                                       g.isInstanceOf(component, symbolType)) {
+                                                       matching.add(getSymbol(g,flag, null));
+                                               }
+                                               
+                                       }
+                               }
+                               
+                       } else {
+                               if (name.equals(symbolName)) {
+                                       if (g.isInstanceOf(connectedSymbol.getElement(), symbolType)||
+                                                       g.isInstanceOf(component, symbolType)) {
+                                               matching.add(getSymbol(g,flag, null));
+                                       }
+                               }
+                               
+                       }
+               }
+               if (matching.size() == 1)
+                       return matching.get(0);
+               if (matching.size() == 0)
+                       return null;
+               throw new NoSingleResultException("There are multiple flags connecting symbol with name '" + symbolName + "' and type " + symbolType);
+               
+       }
+       
+       public PageDesc getPageDesc(ReadGraph g) throws DatabaseException {
+               PageDesc pDesc = DiagramGraphUtil.getPageDesc(g, diagram, PageDesc.DEFAULT);
+               return pDesc;
+       }
+       
+       @Override
+       public boolean equals(Object o) {
+               if (o == null)
+                       return false;
+               if (this.getClass() != o.getClass())
+                       return false;
+               Diagram other = (Diagram)o;
+               return diagram.equals(other.diagram);
+       }
+       
+       @Override
+       public int hashCode() {
+               return diagram.hashCode();
+       }
+       
+       void merge(Symbol to, Symbol from) {
+               Resource element = from.getElement();
+               for (Symbol s : elementToSymbolMap.values()) {
+                       if (s.element.equals(element)) {
+                               s.element = to.element;
+                               s.component = to.component;
+                       }
+               }
+               from.element = to.element;
+               from.component = to.component;
+       }
+       
+       /**
+        * Returns a model containing the diagram.
+        * @param g
+        * @return
+        * @throws DatabaseException
+        */
+       public Resource getModel(ReadGraph g) throws DatabaseException {
+               Layer0 l0 = Layer0.getInstance(g);
+               SimulationResource sim = SimulationResource.getInstance(g);
+               Resource r = composite;
+               while (true) {
+                       Resource parent = g.getSingleObject(r, l0.PartOf);
+                       if (g.isInstanceOf(parent, sim.Model))
+                               return parent;
+                       r = parent;
+               }
+       }
+       
+       
+       
+}
+