]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.interop.diagram/src/org/simantics/interop/diagram/Diagram.java
5695798e65946d0ffaa59918053f81dbfa933eb7
[simantics/interop.git] / org.simantics.interop.diagram / src / org / simantics / interop / diagram / Diagram.java
1 package org.simantics.interop.diagram;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashMap;
6 import java.util.HashSet;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10 import java.util.Stack;
11
12 import org.simantics.databoard.Bindings;
13 import org.simantics.db.ReadGraph;
14 import org.simantics.db.RequestProcessor;
15 import org.simantics.db.Resource;
16 import org.simantics.db.WriteGraph;
17 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
18 import org.simantics.db.common.request.ResourceRead;
19 import org.simantics.db.common.utils.OrderedSetUtils;
20 import org.simantics.db.exception.DatabaseException;
21 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
22 import org.simantics.db.exception.NoSingleResultException;
23 import org.simantics.db.exception.ServiceException;
24 import org.simantics.db.layer0.adapter.Template;
25 import org.simantics.diagram.stubs.DiagramResource;
26 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
27 import org.simantics.g2d.page.DiagramDesc;
28 import org.simantics.layer0.Layer0;
29 import org.simantics.modeling.ModelingResources;
30 import org.simantics.operation.Layer0X;
31 import org.simantics.simulation.ontology.SimulationResource;
32 import org.simantics.structural.stubs.StructuralResource2;
33 import org.simantics.utils.datastructures.Arrays;
34 import org.simantics.utils.page.PageDesc;
35
36
37 /**
38  * @author Marko Luukkainen
39  */
40 public abstract class Diagram<T extends Symbol> {
41         
42         public static boolean DO_NO_MIX_SECTION_NAMES = false;
43         public static boolean USE_MERGE_CONNECTS = true;
44         
45         private Resource composite;
46         private Resource diagram;
47                 
48         private Map<Resource,Integer> indexMap  = new HashMap<Resource, Integer>();
49         
50         private Map<Resource,T> elementToSymbolMap = new HashMap<Resource, T>();
51         
52         private Map<Resource,Diagram<T>> compositeToDiagramMap = new HashMap<Resource, Diagram<T>>();
53         
54         protected Diagram(ReadGraph g, Resource composite, Resource diagram) throws DatabaseException {
55                 this.composite = composite;
56                 this.diagram = diagram;
57         }
58         
59         protected abstract Diagram<T> construct(ReadGraph g, Resource composite, Resource diagram) throws DatabaseException;
60         protected abstract T constructSymbol(ReadGraph g, Resource element, Resource component) throws DatabaseException;
61         
62         public Resource getComposite() {
63                 return composite;
64         }
65         
66         public Resource getDiagram() {
67                 return diagram;
68         }
69         
70         
71         public void clearCaches() {
72                 for (Diagram<T> d : compositeToDiagramMap.values()) {
73                         for (T s : d.elementToSymbolMap.values())
74                                 s.dispose();
75                         d.elementToSymbolMap.clear();
76                 }
77                 compositeToDiagramMap.clear();
78         }
79         
80         
81         public String generateName(ReadGraph g, Resource type, String name) throws DatabaseException {
82                 Layer0 l0 = Layer0.getInstance(g);
83                 Layer0X l0x = Layer0X.getInstance(g);
84                 String prefix = g.getPossibleRelatedValue(type, l0x.HasGeneratedNamePrefix);
85                 if (prefix == null || prefix.length() == 0)
86                         prefix = g.getRelatedValue(type, l0.HasName);
87                 prefix += "_";          
88                 Set<String> reserved = null;
89                 if (name != null) {
90                         reserved = getAllModuleNamesForModel(g, composite);
91                         int index = 0;
92                         String realname = name + "_" + prefix;
93                         while (true) {
94                                 String toTry = realname + Integer.toString(index);
95                                 if (!reserved.contains(toTry))
96                                         break;
97                                 index++;
98                         }
99                         realname += Integer.toString(index);
100                         return realname;
101                 }
102                 Integer index = indexMap.get(type);
103                 if (index != null) {
104                         index++;        
105                 } else {
106                         if (reserved == null)
107                                 reserved = getAllModuleNamesForModel(g, composite);
108                         index = 0;
109                         while (true) {
110                                 String toTry = prefix + Integer.toString(index);
111                                 if (!reserved.contains(toTry))
112                                         break;
113                                 index++;
114                         }
115                         
116                 }
117                 indexMap.put(type, index);
118                 return prefix + index;
119         }
120         
121         private Set<String> getAllModuleNamesForModel(ReadGraph graph, final Resource res) throws DatabaseException {
122
123                 Resource model = DiagramUtils.getModel(graph, res);
124                 Resource configuration = DiagramUtils.getConfiguration(graph, model);
125                 Set<String> names = new HashSet<String>();
126                 Collection<Resource> composites = getAllComposites(graph, configuration);
127                 for (Resource composite : composites) {
128                         names.addAll(getAllModuleNamesForComposite(graph, composite));
129                 }
130                 return names;
131         }
132         
133         protected abstract Resource getGraphicalCompositeType(ReadGraph graph) throws DatabaseException;
134         protected abstract Resource getFolderType(ReadGraph graph) throws DatabaseException;
135         
136         @SuppressWarnings("unchecked")
137         private Collection<Resource> getAllComposites(RequestProcessor processor, Resource configuration) throws DatabaseException {
138                 return (Set<Resource>)processor.syncRequest(new ResourceRead<Object>(configuration) {
139                         @Override
140                         public Object perform(ReadGraph graph) throws DatabaseException {
141                                 Layer0 l0 = Layer0.getInstance(graph);
142                                 Set<Resource> composites = new HashSet<Resource>();
143                                 Stack<Resource> resources = new Stack<Resource>();
144                                 Resource graphicalCompositeType = getGraphicalCompositeType(graph);
145                                 Resource folderType = getFolderType(graph);
146                                 resources.add(resource);
147                                 while (!resources.isEmpty()) {
148                                         Resource r = resources.pop();
149                                         if (graph.isInstanceOf(r, graphicalCompositeType)) {
150                                                 composites.add(r);
151                                         } else if (folderType != null && graph.isInstanceOf(r, folderType)){
152                                                 resources.addAll(graph.getObjects(r, l0.ConsistsOf));
153                                         }
154                                 }
155                                 return composites;
156                         }
157                 }, TransientCacheListener.instance());
158         }
159         
160         @SuppressWarnings("unchecked")
161         private Set<String> getAllModuleNamesForComposite(RequestProcessor processor, Resource composite) throws DatabaseException {
162                 return (Set<String>)processor.syncRequest(new ResourceRead<Object>(composite) {
163                         @Override
164                         public Object perform(ReadGraph graph) throws DatabaseException {
165                                 Layer0 l0 = Layer0.getInstance(graph);
166                                 Set<String> names = new HashSet<String>();
167                                 Collection<Resource> components = graph.getObjects(resource, l0.ConsistsOf);
168                                 for (Resource component : components) {
169                                         String n = graph.getPossibleRelatedValue(component, l0.HasName, Bindings.STRING);
170                                         if (n != null)
171                                                 names.add(n);
172                                 }
173                                 return names;
174                         }
175                 }, TransientCacheListener.instance());
176                 
177         }
178         
179         public Diagram<T> createDiagram(WriteGraph g,String name, Resource compositeType, Resource parent) throws DatabaseException {
180                 return createDiagram(g, name, null, null,compositeType, parent);
181         }
182         
183         
184         
185         /**
186          * Creates a new Diagram
187          * @param g
188          * @param name name of the diagram
189          * @param compositeType composite type of the diagram
190          * @param parent resource where diagram is added
191          * @return
192          * @throws DatabaseException
193          */
194         @SuppressWarnings("deprecation")
195         public Diagram<T> createDiagram(WriteGraph g,String name, DiagramDesc desc, Template tpl, Resource compositeType, Resource parent) throws DatabaseException {
196                 Layer0 l0 = Layer0.getInstance(g);
197                 Layer0X l0x = Layer0X.getInstance(g);
198                 ModelingResources m = ModelingResources.getInstance(g);
199                 
200                 // create composite
201                 Resource composite = g.newResource();
202                 g.claim(composite, l0.InstanceOf, compositeType);
203                 
204                 // create diagram
205                 Resource diagramType = getDiagramFromComposite(g, compositeType);
206                 
207                 Resource diagram = OrderedSetUtils.create(g, diagramType);
208                 
209                 g.claim(composite, m.CompositeToDiagram, diagram);
210                 
211                 // link to parent and set name
212                 g.claimLiteral(composite, l0.HasName, name);
213                 g.claim(composite, l0.PartOf, parent);
214                 
215                 // activate mapping
216                 Resource mapping = g.newResource();
217         g.claim(mapping, l0.InstanceOf, m.DiagramToCompositeMapping);
218         g.claim(diagram, l0x.HasTrigger, mapping);
219         
220         if (tpl != null) {
221                 Map<String,Object> params = new HashMap<String, Object>();
222                 params.put("diagram", diagram);
223                 tpl.apply(g, params);
224         }
225         
226         
227         // Make diagram part of a dummy container library attached to the parent
228         // composite if it's not already part of something.
229         // This gives the diagram a proper URI without connecting it directly to the composite with ConsistsOf.
230         // This would cause problems because a diagram is a structural composite/component also.
231         g.claimLiteral(diagram, l0.HasName, name, Bindings.STRING);
232         Resource container = g.newResource();
233         g.claim(container, l0.InstanceOf, null, l0.Library);
234         g.addLiteral(container, l0.HasName, l0.NameOf, l0.String, "__CONTAINER__", Bindings.STRING);
235         g.claim(container, l0.ConsistsOf, diagram);
236         g.claim(composite, l0.ConsistsOf, container);
237         
238         if (desc != null)
239                 DiagramGraphUtil.setDiagramDesc(g, diagram, desc);
240                 
241                 Diagram<T> diag = construct(g, composite, diagram);
242                 diag.compositeToDiagramMap = compositeToDiagramMap;
243                 compositeToDiagramMap.put(composite, diag);
244                 return diag;
245         }
246         
247         public Diagram<T> fromExisting(ReadGraph g, Resource diagram) throws DatabaseException {
248                 ModelingResources m = ModelingResources.getInstance(g);
249                 StructuralResource2 s = StructuralResource2.getInstance(g);
250                 Resource composite = null;
251                 if (g.isInstanceOf(diagram, s.Composite)) {
252                         composite = diagram;
253                         diagram = g.getPossibleObject(composite, m.CompositeToDiagram);
254                         if (diagram == null)
255                                 return null;
256                 } else {
257                         composite = g.getPossibleObject(diagram, m.DiagramToComposite);
258                         if (composite == null)
259                                 return null;
260                 }
261                 
262                 Diagram<T> diag = compositeToDiagramMap.get(composite);
263                 if (diag != null)
264                         return diag;
265                 
266                 diag =  construct(g,composite, diagram);
267                 diag.compositeToDiagramMap = compositeToDiagramMap;
268                 compositeToDiagramMap.put(composite, diag);
269                 return diag;
270         }
271         
272         
273         
274         
275         
276         /**
277          * Returns diagram type from composite type
278          * @param g
279          * @param compositeType
280          * @return diagram type
281          * @throws NoSingleResultException
282          * @throws ManyObjectsForFunctionalRelationException
283          * @throws ServiceException
284          */
285         private static Resource getDiagramFromComposite(ReadGraph g, Resource compositeType) throws DatabaseException {
286                 ModelingResources m  = ModelingResources.getInstance(g);
287                 Collection<Resource> diagramTemplates = g.getAssertedObjects(compositeType, m.HasModelingTemplate);
288                 for (Resource diagramTemplate : diagramTemplates) {
289                         Resource diagramType = g.getPossibleObject(diagramTemplate, m.HasDiagramType);
290                         if (diagramType != null)
291                                 return diagramType;
292                                 
293                 }
294                 throw new RuntimeException("Cannot find diagramType for composite " + compositeType);
295         }
296         
297         
298
299         
300         /**
301          * Adds new symbol to a diagram
302          * @param g
303          * @param symbolType
304          * @return
305          * @throws DatabaseException
306          */
307         public T addSymbol(WriteGraph g, Resource symbolType) throws DatabaseException {
308                 return addSymbol(g, symbolType, 0, 0);
309         }
310         
311         /**
312          * Adds new symbol to a diagram
313          * @param g
314          * @param symbolType
315          * @param name
316          * @return
317          * @throws DatabaseException
318          */
319         public T addSymbol(WriteGraph g, Resource symbolType, String name) throws DatabaseException {
320                 return addSymbol(g, symbolType, name, 0, 0);
321         }
322         
323         /**
324          * Adds new symbol to a diagram
325          * @param g
326          * @param diagramConf Diagram configuration
327          * @param symbolType type of the new symbol
328          * @param x
329          * @param y
330          * @return configuration of the new Symbol
331          * @throws DatabaseException
332          */
333         public T addSymbol(WriteGraph g, Resource symbolType, double x, double y) throws DatabaseException {
334                 return addSymbol(g, symbolType,null,x,y);
335         }
336         
337         /**
338          * Adds new symbol to a diagram
339          * @param g
340          * @param elementType
341          * @param name
342          * @param x
343          * @param y
344          * @return
345          * @throws DatabaseException
346          */
347         public T addSymbol(WriteGraph g, Resource elementType, String name, double x, double y) throws DatabaseException {
348                 if (elementType == null)
349                         throw new NullPointerException("Element type is null");
350                 Layer0 l0 = Layer0.getInstance(g);
351
352                 DiagramResource d = DiagramResource.getInstance(g);
353                 ModelingResources m = ModelingResources.getInstance(g);
354                 
355                 Resource componentType = null;
356                 if (g.isInheritedFrom(elementType, d.DefinedElement))
357                         componentType = Symbol.getComponentTypeFromSymbolType(g, elementType);
358                 else {
359                         componentType = elementType;
360                         elementType = Symbol.getSymbolTypeFromComponentType(g,componentType);
361                 }
362                         
363                 
364                 Resource element = g.newResource();
365                 g.claim(element, l0.InstanceOf, elementType);
366
367                 Resource module = g.newResource();
368                 g.claim(module, l0.InstanceOf, componentType);
369                 
370                 g.claim(module, m.ComponentToElement, element);
371                 g.claim(module, m.Mapped, module);
372
373                 String id = generateName(g, componentType, name);
374                 g.claimLiteral(module, l0.HasName, id);
375                 g.claimLiteral(element, l0.HasName, id);
376                 
377                 OrderedSetUtils.add(g, this.diagram, element);
378                 g.claim(this.diagram, l0.ConsistsOf, element);
379                 g.claim(this.composite, l0.ConsistsOf, module);
380                 
381                 T s =  constructSymbol(g, element, module);
382                 s.setSymbolTranslation(g, x, y);
383                 
384                 elementToSymbolMap.put(element, s);
385                 return s;
386         }
387         
388         /**
389          * Returns a Symbol for given resource.
390          * @param g
391          * @param element Element or Component of the Symbol.
392          * @return
393          * @throws ManyObjectsForFunctionalRelationException
394          * @throws ServiceException
395          * @throws NoSingleResultException
396          */
397         public T getSymbol(ReadGraph g, Resource element) throws DatabaseException {
398                 ModelingResources mr = ModelingResources.getInstance(g);
399                 DiagramResource dr = DiagramResource.getInstance(g);
400                 if (g.isInstanceOf(element, dr.Element))
401                         return getSymbol(g, element, g.getPossibleObject(element, mr.ElementToComponent));
402                 else
403                         return getSymbol(g, g.getSingleObject(element, mr.ComponentToElement), element);
404         }
405         
406         /**
407          * Returns a Symbol for given resource.
408          * @param g
409          * @param element Element Resource of the Symbol.
410          * @param component Component  Resource of the symbol. 
411          * @return
412          */
413         public T getSymbol(ReadGraph g, Resource element, Resource component) throws DatabaseException {
414                 T s = elementToSymbolMap.get(element);
415                 if (s == null) {
416                         // TODO : check that symbol actually belongs to this diagram
417                         s = constructSymbol(g, element, component);
418                         elementToSymbolMap.put(element, s);
419                 } else {
420                         if (s.component == null)
421                                 s.component = component;
422                         else if (!s.component.equals(component)) {
423                                 // FIXME : ?
424                                 return constructSymbol(g, element, component);
425                         }
426                 }
427                 return s;
428         }
429         
430         /**
431          *  Adds new element to a diagram
432          * @param g
433          * @param symbolType type of the element.
434          * @param x
435          * @param y
436          * @return
437          * @throws DatabaseException
438          */
439         public T addElement(WriteGraph g, Resource symbolType, double x, double y) throws DatabaseException {
440                 Layer0 l0 = Layer0.getInstance(g);
441
442                 Resource element = g.newResource();
443                 g.claim(element, l0.InstanceOf, symbolType);
444                                 
445                 DiagramUtils.addElement(g, this, element);
446                 
447                 T s = constructSymbol(g,element,null);
448                 
449                 s.setSymbolTranslation(g, x, y);
450                 
451                 elementToSymbolMap.put(element, s);
452                 return s;
453         }
454         
455         public T getSingleSymbol(ReadGraph g, String symbolName) throws DatabaseException {
456                 List<T> matching = getSymbol(g, symbolName);
457                 if (matching.size() == 1)
458                         return matching.get(0);
459                 if (matching.size() == 0)
460                         return null;
461                 throw new NoSingleResultException("There are multiple symbols with name '" + symbolName);
462         }
463         
464         public T getPossibleSymbol(ReadGraph g, String symbolName) throws DatabaseException {
465                 List<T> matching = getSymbol(g, symbolName);
466                 if (matching.size() == 1)
467                         return matching.get(0);
468                 return null;
469         }
470         
471         /**
472          * Returns all symbols on the diagram
473          * @param g
474          * @return
475          * @throws DatabaseException
476          */
477         public List<T> getSymbols(ReadGraph g) throws DatabaseException {
478                 ModelingResources m = ModelingResources.getInstance(g);
479                 List<T> matching = new ArrayList<T>();
480                 for (Resource element : OrderedSetUtils.toList(g, diagram)) {
481                         Resource component = g.getPossibleObject(element, m.ElementToComponent);
482                         matching.add(getSymbol(g,element, component));
483                 }
484                 return matching;
485         }
486         
487         /**
488          * Returns symbols that have matching name.
489          * 
490          * Prioritizes L0.HasLabel over L0.HasName (If symbol has label, it is used for comparison).
491          * 
492          * ';' character acts as a splitter, allowing input parameter and a label contain multiple identifiers.
493          *
494          * All the splits  
495          * 
496          * @param g
497          * @param symbolName
498          * @return
499          * @throws DatabaseException
500          */
501         public List<T> getSymbol(ReadGraph g, String symbolName) throws DatabaseException {
502                 ModelingResources m = ModelingResources.getInstance(g);
503                 Layer0 b = Layer0.getInstance(g);
504                 List<T> matching = new ArrayList<T>();
505                 
506                 String splitId[] = symbolName.split(";");
507                 
508                 for (Resource element : OrderedSetUtils.toList(g, diagram)) {
509                         Resource component = g.getPossibleObject(element, m.ElementToComponent);
510                         if (component == null)
511                                 component = g.getPossibleObject(element, m.HasParentComponent);
512                         if (component == null)
513                                 continue;
514                         String label = g.getPossibleRelatedValue(component, b.HasLabel);
515                         String name = g.getRelatedValue(component, b.HasName);
516                         if (label != null) {
517                                 String splitLabel[] = label.split(";");
518                                 
519                                 boolean match = true;
520                                 for (int i = 0; i < splitId.length; i++) {
521                                         if(!Arrays.contains(splitLabel, splitId[i])) {
522                                                 match = false;
523                                                 break;
524                                         }
525                                 }
526                                 if (match) {
527                                         matching.add(getSymbol(g,element, component));
528                                 } else {
529                                         if (label.equals(symbolName) || name.equals(symbolName)) {
530                                                 matching.add(getSymbol(g,element, component));
531                                                 
532                                         }
533                                 }
534                                 
535                         } else {
536                                 for (String split : splitId) {
537                                         if (name.equals(split)) {
538                                                 matching.add(getSymbol(g,element, component));
539                                         }
540                                 }
541                                 
542                         }
543                 }
544                 return matching;
545         }
546         
547         /**
548          * Returns a single symbol matching given name and type. If matching symbol cannot be found, returns null.
549          * Throws a NoSingleResultException if the re are multiple symbols matching the criteria.
550          * 
551          * @param g
552          * @param symbolName
553          * @param symbolType
554          * @return 
555          * @throws DatabaseException
556          */
557         public T getSingleSymbol(ReadGraph g, String symbolName, Resource symbolType) throws DatabaseException {
558                 List<T> matching = getSymbol(g, symbolName, symbolType);
559                 if (matching.size() == 1)
560                         return matching.get(0);
561                 if (matching.size() == 0)
562                         return null;
563                 throw new NoSingleResultException("There are multiple symbols with name '" + symbolName + "' and type " + symbolType);
564         }
565         
566         public T getPossibleSymbol(ReadGraph g, String symbolName, Resource symbolType) throws DatabaseException {
567                 List<T> matching = getSymbol(g, symbolName, symbolType);
568                 if (matching.size() == 1)
569                         return matching.get(0);
570                 return null;
571         }
572         
573         /**
574          * Returns symbols matching given name and type. 
575          * 
576          * @param g
577          * @param symbolName
578          * @param symbolType
579          * @return 
580          * @throws DatabaseException
581          */
582         public List<T> getSymbol(ReadGraph g, String symbolName, Resource symbolType) throws DatabaseException {
583
584                 List<T> nameMatching = getSymbol(g, symbolName);
585                 List<T> matching = new ArrayList<T>();
586                 for (T s : nameMatching) {
587                         if ((g.isInstanceOf(s.getElement(), symbolType)||
588                                          g.isInstanceOf(s.getComponent(), symbolType))) {
589                                         matching.add(s);
590                                 }
591                 }
592                 return matching;
593         }
594         
595         public Symbol getFlag(ReadGraph g, Resource flagType, String symbolName, Resource symbolType) throws DatabaseException {
596                 Layer0 b = Layer0.getInstance(g);
597                 DiagramResource dr = DiagramResource.getInstance(g);
598                 List<Symbol> matching = new ArrayList<Symbol>();
599                 for (Resource flag : OrderedSetUtils.toList(g, diagram)) {
600                         if (!g.isInstanceOf(flag, dr.Flag))
601                                 continue;
602                         if (!g.getSingleObject(flag, dr.HasFlagType).equals(flagType))
603                                 continue;
604                         Symbol flagSymbol = getSymbol(g,flag, null);
605
606                         Symbol connectedSymbol = flagSymbol.getDiagramSingleConnected(g, dr.Flag_ConnectionPoint);
607                         Resource component = connectedSymbol.getComponent();
608                         if (component == null)
609                                 continue;
610                         String label = g.getPossibleRelatedValue(component, b.HasLabel);
611                         String name = g.getRelatedValue(component, b.HasName);
612                         if (label != null) {
613                                 String splitId[] = symbolName.split(";");
614                                 if (splitId.length > 1) {
615                                         String splitLabel[] = label.split(";");
616                                         boolean match = true;
617                                         for (int i = 0; i < splitId.length; i++) {
618                                                 if(!Arrays.contains(splitLabel, splitId[i])) {
619                                                         match = false;
620                                                         break;
621                                                 }
622                                         }
623                                         if (match) {
624                                                 if (g.isInstanceOf(connectedSymbol.getElement(), symbolType)||
625                                                         g.isInstanceOf(component, symbolType)) {
626                                                         matching.add(getSymbol(g,flag, null));
627                                                 }
628                                                 
629                                         }
630                                 } else {
631                                         if (label.equals(symbolName) || name.equals(symbolName)) {
632                                                 if (g.isInstanceOf(connectedSymbol.getElement(), symbolType)||
633                                                         g.isInstanceOf(component, symbolType)) {
634                                                         matching.add(getSymbol(g,flag, null));
635                                                 }
636                                                 
637                                         }
638                                 }
639                                 
640                         } else {
641                                 if (name.equals(symbolName)) {
642                                         if (g.isInstanceOf(connectedSymbol.getElement(), symbolType)||
643                                                         g.isInstanceOf(component, symbolType)) {
644                                                 matching.add(getSymbol(g,flag, null));
645                                         }
646                                 }
647                                 
648                         }
649                 }
650                 if (matching.size() == 1)
651                         return matching.get(0);
652                 if (matching.size() == 0)
653                         return null;
654                 throw new NoSingleResultException("There are multiple flags connecting symbol with name '" + symbolName + "' and type " + symbolType);
655                 
656         }
657         
658         public PageDesc getPageDesc(ReadGraph g) throws DatabaseException {
659                 PageDesc pDesc = DiagramGraphUtil.getPageDesc(g, diagram, PageDesc.DEFAULT);
660                 return pDesc;
661         }
662         
663         @Override
664         public boolean equals(Object o) {
665                 if (o == null)
666                         return false;
667                 if (this.getClass() != o.getClass())
668                         return false;
669                 Diagram other = (Diagram)o;
670                 return diagram.equals(other.diagram);
671         }
672         
673         @Override
674         public int hashCode() {
675                 return diagram.hashCode();
676         }
677         
678         void merge(Symbol to, Symbol from) {
679                 Resource element = from.getElement();
680                 for (Symbol s : elementToSymbolMap.values()) {
681                         if (s.element.equals(element)) {
682                                 s.element = to.element;
683                                 s.component = to.component;
684                         }
685                 }
686                 from.element = to.element;
687                 from.component = to.component;
688         }
689         
690         /**
691          * Returns a model containing the diagram.
692          * @param g
693          * @return
694          * @throws DatabaseException
695          */
696         public Resource getModel(ReadGraph g) throws DatabaseException {
697                 Layer0 l0 = Layer0.getInstance(g);
698                 SimulationResource sim = SimulationResource.getInstance(g);
699                 Resource r = composite;
700                 while (true) {
701                         Resource parent = g.getSingleObject(r, l0.PartOf);
702                         if (g.isInstanceOf(parent, sim.Model))
703                                 return parent;
704                         r = parent;
705                 }
706         }
707         
708         
709         
710 }
711