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