]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/DiagramGraphUtil.java
IConnectionPoint and canBeConnected-checking util to SCL
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / synchronization / graph / DiagramGraphUtil.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.diagram.synchronization.graph;
13
14 import gnu.trove.set.hash.THashSet;
15
16 import java.awt.geom.AffineTransform;
17 import java.lang.reflect.Array;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.Set;
24
25 import org.simantics.Simantics;
26 import org.simantics.databoard.Bindings;
27 import org.simantics.databoard.binding.Binding;
28 import org.simantics.datatypes.literal.Vec2d;
29 import org.simantics.db.AsyncReadGraph;
30 import org.simantics.db.ReadGraph;
31 import org.simantics.db.Resource;
32 import org.simantics.db.Statement;
33 import org.simantics.db.WriteGraph;
34 import org.simantics.db.common.CommentMetadata;
35 import org.simantics.db.common.primitiverequest.OrderedSet;
36 import org.simantics.db.common.request.IndexRoot;
37 import org.simantics.db.common.request.Queries;
38 import org.simantics.db.common.utils.NameUtils;
39 import org.simantics.db.common.utils.OrderedSetUtils;
40 import org.simantics.db.exception.DatabaseException;
41 import org.simantics.db.exception.DoesNotContainValueException;
42 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
43 import org.simantics.db.exception.NoSingleResultException;
44 import org.simantics.db.exception.ServiceException;
45 import org.simantics.db.exception.ValidationException;
46 import org.simantics.db.layer0.request.PossibleModel;
47 import org.simantics.db.procedure.AsyncProcedure;
48 import org.simantics.diagram.connection.ConnectionSegmentEnd;
49 import org.simantics.diagram.connection.ConnectionVisuals;
50 import org.simantics.diagram.content.ConnectionUtil;
51 import org.simantics.diagram.content.DesignatedTerminal;
52 import org.simantics.diagram.content.ElementContext;
53 import org.simantics.diagram.content.ResourceTerminal;
54 import org.simantics.diagram.content.TerminalMap;
55 import org.simantics.diagram.internal.DebugPolicy;
56 import org.simantics.diagram.query.DiagramRequests;
57 import org.simantics.diagram.stubs.DiagramResource;
58 import org.simantics.diagram.stubs.G2DResource;
59 import org.simantics.g2d.connection.EdgeVisualsConfigurer;
60 import org.simantics.g2d.diagram.IDiagram;
61 import org.simantics.g2d.diagram.handler.DataElementMap;
62 import org.simantics.g2d.diagram.handler.Topology.Terminal;
63 import org.simantics.g2d.element.ElementHints;
64 import org.simantics.g2d.element.IElement;
65 import org.simantics.g2d.element.handler.EdgeVisuals;
66 import org.simantics.g2d.element.handler.EdgeVisuals.ArrowType;
67 import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;
68 import org.simantics.g2d.element.handler.FillColor;
69 import org.simantics.g2d.element.handler.TerminalTopology;
70 import org.simantics.g2d.elementclass.FlagClass;
71 import org.simantics.g2d.elementclass.FlagClass.Type;
72 import org.simantics.g2d.page.DiagramDesc;
73 import org.simantics.g2d.routing.IRouter2;
74 import org.simantics.g2d.svg.LineCap;
75 import org.simantics.g2d.svg.LineJoin;
76 import org.simantics.g2d.utils.Alignment;
77 import org.simantics.layer0.Layer0;
78 import org.simantics.layer0.utils.binaryPredicates.OrderedSetElementsPredicate;
79 import org.simantics.modeling.ModelingResources;
80 import org.simantics.scl.commands.Commands;
81 import org.simantics.structural.stubs.StructuralResource2;
82 import org.simantics.structural2.modelingRules.CPTerminal;
83 import org.simantics.structural2.modelingRules.IAttachmentRelationMap;
84 import org.simantics.structural2.modelingRules.IConnectionPoint;
85 import org.simantics.structural2.modelingRules.IModelingRules;
86 import org.simantics.ui.selection.WorkbenchSelectionElement;
87 import org.simantics.utils.page.MarginUtils.Margin;
88 import org.simantics.utils.page.MarginUtils.Margins;
89 import org.simantics.utils.page.PageCentering;
90 import org.simantics.utils.page.PageDesc;
91 import org.simantics.utils.page.PageOrientation;
92 import org.simantics.utils.ui.ErrorLogger;
93
94 /**
95  * @author Tuukka Lehtonen
96  */
97 public final class DiagramGraphUtil {
98
99     public static double[] validateAffineTransform(Resource resource, double[] matrix) {
100         if (matrix != null) {
101             if (matrix.length < 4) {
102                 ErrorLogger.defaultLogError("resource " + resource + " matrix too small for AffineTransform: " + Arrays.toString(matrix), new Exception("trace"));
103                 return null;
104             }
105
106             // Validate scale/rotation part
107             if (DebugPolicy.DEBUG_TRANSFORM_LOAD) {
108                 double det = new AffineTransform(matrix).getDeterminant();
109                 double detabs = Math.abs(det);
110                 if (detabs < DebugPolicy.DETERMINANT_LIMIT_LOW)
111                     ErrorLogger.defaultLogWarning("resource " + resource + " transform determinant absolute value is close to zero: " + detabs + "(transform=" + Arrays.toString(matrix) + ")", new Exception("trace"));
112                 if (detabs > DebugPolicy.DETERMINANT_LIMIT_HIGH)
113                     ErrorLogger.defaultLogWarning("resource " + resource + " transform determinant absolute value is suspiciously large: " + detabs + "(transform=" + Arrays.toString(matrix) + ")", new Exception("trace"));
114             }
115
116             if (matrix.length > 5) {
117                 // Validate translation
118                 double xabs = Math.abs(matrix[4]);
119                 double yabs = Math.abs(matrix[5]);
120                 double limit = DebugPolicy.TRANSLATION_LIMIT_HIGH;
121                 boolean largeX = xabs > limit;
122                 boolean largeY = yabs > limit;
123                 if (largeX || largeY)
124                     ErrorLogger.defaultLogWarning("resource " + resource + " transform translation is suspiciously large: " + Arrays.toString(matrix), new Exception("trace"));
125                 return matrix;
126             }
127         }
128         return matrix;
129     }
130
131     public static AffineTransform getAffineTransform(ReadGraph graph, Resource resource) throws DatabaseException {
132         G2DResource g2d = G2DResource.getInstance(graph);
133         return getAffineTransform(graph, resource, g2d.HasTransform, true);
134     }
135
136     public static Vec2d getOffset(ReadGraph graph, Resource resource) throws DatabaseException {
137         DiagramResource DIA = DiagramResource.getInstance(graph);
138         Vec2d offset = graph.getPossibleRelatedValue(resource, DIA.Element_profileMonitorOffset, Vec2d.BINDING);
139         if(offset != null) return offset;
140         else return new Vec2d(0, 0);
141     }
142     
143     public static boolean getProfileMonitorsHidden(ReadGraph graph, Resource resource) throws DatabaseException {
144         DiagramResource DIA = DiagramResource.getInstance(graph);
145         Boolean value = graph.getPossibleRelatedValue(resource, DIA.Element_hideProfileMonitors, Bindings.BOOLEAN);
146         if(value == null) value = false;
147         return value;
148     }
149
150     public static boolean getProfileMonitorsUp(ReadGraph graph, Resource resource) throws DatabaseException {
151         DiagramResource DIA = DiagramResource.getInstance(graph);
152         Boolean value = graph.getPossibleRelatedValue(resource, DIA.Element_upProfileMonitors, Bindings.BOOLEAN);
153         if(value == null) value = true;
154         return value;
155     }
156
157     public static double getProfileMonitorSpacing(ReadGraph graph, Resource resource) throws DatabaseException {
158         DiagramResource DIA = DiagramResource.getInstance(graph);
159         Double value = graph.getPossibleRelatedValue(resource, DIA.Element_profileMonitorSpacing, Bindings.DOUBLE);
160         if(value == null) value = 0.0;
161         return value;
162     }
163
164     public static AffineTransform getDynamicAffineTransform(ReadGraph graph, Resource runtime, Resource element) throws DatabaseException {
165         DiagramResource DIA = DiagramResource.getInstance(graph);
166         return getDynamicAffineTransform(graph, runtime, element, DIA.HasDynamicTransform, true);
167     }
168
169     /**
170      * @param graph
171      * @param element
172      * @return
173      * @throws DatabaseException
174      */
175     public static AffineTransform getWorldTransform(ReadGraph graph, Resource element) throws DatabaseException {
176         ModelingResources MOD = ModelingResources.getInstance(graph);
177         AffineTransform result = DiagramGraphUtil.getAffineTransform(graph, element);
178         while (true) {
179             Resource parentComponent = graph.getPossibleObject(element, MOD.HasParentComponent);
180             if (parentComponent == null)
181                 return result;
182             element = graph.getPossibleObject(parentComponent, MOD.ComponentToElement);
183             if (element == null)
184                 return result;
185             AffineTransform tr = DiagramGraphUtil.getAffineTransform(graph, element);
186             tr.setToTranslation(tr.getTranslateX(), tr.getTranslateY());
187             result.preConcatenate(tr);
188         }
189     }
190
191     /**
192      * @param graph
193      * @param runtime
194      * @param element
195      * @return
196      * @throws DatabaseException
197      */
198     public static AffineTransform getDynamicWorldTransform(ReadGraph graph, Resource runtime, Resource element) throws DatabaseException {
199         ModelingResources MOD = ModelingResources.getInstance(graph);
200         AffineTransform result = DiagramGraphUtil.getDynamicAffineTransform(graph, runtime, element);
201         while (true) {
202             Resource parentComponent = graph.getPossibleObject(element, MOD.HasParentComponent);
203             if (parentComponent == null)
204                 return result;
205             element = graph.getPossibleObject(parentComponent, MOD.ComponentToElement);
206             if (element == null)
207                 return result;
208             AffineTransform tr = DiagramGraphUtil.getDynamicAffineTransform(graph, runtime, element);
209             tr.setToTranslation(tr.getTranslateX(), tr.getTranslateY());
210             result.preConcatenate(tr);
211         }
212     }
213
214     /**
215      * @param graph
216      * @param resource
217      * @param relation
218      * @param invalidAsIdentity true to return invalid transforms as identity
219      *        transforms, <code>false</code> to return <code>null</code>
220      * @return
221      * @throws DatabaseException
222      */
223     public static AffineTransform getAffineTransform(ReadGraph graph, Resource resource, Resource relation, boolean invalidAsIdentity) throws DatabaseException {
224         double mat[] = getPossibleRelatedDoubleArray(graph, resource, relation);
225         mat = validateAffineTransform(resource, mat);
226         return mat != null ? new AffineTransform(mat) :
227             invalidAsIdentity ? new AffineTransform() : null;
228     }
229
230     public static AffineTransform getDynamicAffineTransform(ReadGraph graph, Resource runtime, Resource element, Resource relation, boolean invalidAsIdentity) throws DatabaseException {
231         double mat[] = graph.getPossibleRelatedValue2(element, relation, new ElementContext(runtime, element), Bindings.DOUBLE_ARRAY);
232         mat = validateAffineTransform(element, mat);
233         return mat != null ? new AffineTransform(mat) :
234             invalidAsIdentity ? new AffineTransform() : null;
235     }
236     
237     public static double[] getPossibleRelatedDoubleArray(ReadGraph graph, Resource resource, Resource relation) throws DatabaseException {
238         Resource res = graph.getPossibleObject(resource, relation);
239         if (res == null)
240             return null;
241         return graph.getValue(res, Bindings.getBindingUnchecked(double[].class));
242     }
243     
244     public static AffineTransform getTransform(ReadGraph graph, Resource resource) throws DatabaseException {
245         DiagramResource DIA = DiagramResource.getInstance(graph);
246
247         double[] matrix = graph.getPossibleRelatedValue(resource, DIA.HasTransform, Bindings.DOUBLE_ARRAY);
248         if (matrix == null)
249             return new AffineTransform();
250         if (matrix.length < 4)
251             return new AffineTransform();
252         return new AffineTransform(matrix);
253     }
254
255     public static void setTransform(WriteGraph graph, Resource resource, AffineTransform at) throws DatabaseException {
256         double[] matrix = new double[6];
257         at.getMatrix(matrix);
258         changeTransform(graph, resource, matrix);
259     }
260     
261     public static void setTransform(WriteGraph graph, Resource resource, double[] matrix) throws DatabaseException {
262         DiagramResource DIA = DiagramResource.getInstance(graph);
263         G2DResource G2D = G2DResource.getInstance(graph);
264
265         setRelatedValue(graph, resource, DIA.HasTransform, G2D.Transform, matrix, Bindings.DOUBLE_ARRAY);
266     }
267     
268     public static void changeTransform(WriteGraph graph, Resource resource, AffineTransform at) throws DatabaseException {
269         double[] matrix = new double[6];
270         at.getMatrix(matrix);
271         changeTransform(graph, resource, matrix);
272     }
273     
274     public static void changeTransform(WriteGraph graph, Resource resource, double[] matrix) throws DatabaseException {
275         Commands.get(graph, "Simantics/Diagram/setTransform")
276                 .execute(graph, graph.syncRequest(new IndexRoot(resource)), resource, matrix);
277     }
278
279     public static void setRelatedValue(WriteGraph graph, Resource resource, Resource relation, Resource valueType, Object arrayValue, Binding binding) throws DatabaseException {
280         Statement stm = graph.getPossibleStatement(resource, relation);
281         if (stm == null) {
282             addRelatedValue(graph, resource, relation, valueType, arrayValue, binding);
283         } else {
284             // statement might be asserted, check this before overwriting
285             if (!stm.getSubject().equals(resource)) {
286                 // Asserted, just add a new related value
287                 addRelatedValue(graph, resource, relation, valueType, arrayValue, binding);
288             } else {
289                 //Object old = graph.getValue2(p);
290                 //if (!Arrays.equals(old, arrayValue))
291                 graph.claimValue(stm.getObject(), arrayValue, binding);
292             }
293         }
294     }
295
296     public static Resource addRelatedValue(WriteGraph graph, Resource resource, Resource relation, Resource valueType, Object arrayValue, Binding binding) throws DatabaseException {
297         Resource d = graph.newResource();
298         Layer0 b = Layer0.getInstance(graph);
299         graph.claim(d, b.InstanceOf, null, valueType);
300         graph.claimValue(d, arrayValue);
301         graph.claim(resource, relation, d);
302         return d;
303     }
304
305     public static <T> T getPossibleRelatedValue(ReadGraph graph, Resource r, Resource relation, Class<T> valueClass, T defaultValue) throws DatabaseException {
306         Resource object = graph.getPossibleObject(r, relation);
307         if (object == null)
308             return defaultValue;
309         T t = graph.getPossibleValue(object, Bindings.getBindingUnchecked(valueClass));
310         if (t != null && valueClass.isArray()) {
311             if (defaultValue != null) {
312                 int defaultValueLength = Array.getLength(defaultValue);
313                 int valueLength = Array.getLength(t);
314                 if (valueLength < defaultValueLength)
315                     return defaultValue;
316             }
317         }
318         return t == null ? defaultValue : t;
319     }
320
321     public static Resource getConnectionPointOfTerminal(ReadGraph g, Terminal forTerminal) throws DatabaseException {
322         if (forTerminal instanceof ResourceTerminal)
323             return getConnectionPointOfTerminal(g, ((ResourceTerminal) forTerminal).getResource());
324         return null;
325     }
326
327     public static Resource tryGetBindingRelation(ReadGraph g, Terminal forTerminal) throws DatabaseException {
328         if (forTerminal instanceof ResourceTerminal)
329             return getPossibleConnectionPointOfTerminal(g, ((ResourceTerminal) forTerminal).getResource());
330         return null;
331     }
332
333     public static LineJoin toLineJoin(G2DResource g2d, Resource lineJoin) {
334         if (lineJoin != null) {
335             if (lineJoin.equals(g2d.LineJoin_BevelJoin))
336                 return LineJoin.bevel;
337             if (lineJoin.equals(g2d.LineJoin_RoundJoin))
338                 return LineJoin.round;
339         }
340         return LineJoin.miter;
341     }
342
343     public static LineCap toLineCap(G2DResource g2d, Resource lineCap) {
344         if (lineCap != null) {
345             if (lineCap.equals(g2d.LineCap_ButtCap))
346                 return LineCap.butt;
347             if (lineCap.equals(g2d.LineCap_RoundCap))
348                 return LineCap.round;
349         }
350         return LineCap.square;
351     }
352
353     public static Resource toLineJoin(G2DResource g2d, LineJoin lineJoin) {
354         if (lineJoin != null) {
355             if (lineJoin.equals(LineJoin.bevel))
356                 return g2d.LineJoin_BevelJoin;
357             if (lineJoin.equals(LineJoin.round))
358                 return g2d.LineJoin_RoundJoin;
359         }
360         return g2d.LineJoin_MiterJoin;
361     }
362
363     public static Resource toLineCap(G2DResource g2d, LineCap lineCap) {
364         if (lineCap != null) {
365             if (lineCap.equals(LineCap.butt))
366                 return g2d.LineCap_ButtCap;
367             if (lineCap.equals(LineCap.round))
368                 return g2d.LineCap_RoundCap;
369         }
370         return g2d.LineCap_SquareCap;
371     }
372
373     public static Alignment toAlignment(Resource align, G2DResource g2d, Alignment defaultValue) {
374         if (align == null)
375             return defaultValue;
376         if (align.equals(g2d.Alignment_Leading))
377             return Alignment.LEADING;
378         if (align.equals(g2d.Alignment_Trailing))
379             return Alignment.TRAILING;
380         if (align.equals(g2d.Alignment_Center))
381             return Alignment.CENTER;
382         return defaultValue;
383     }
384
385     public static Alignment toVerticalAlignment(Resource align, G2DResource g2d, Alignment defaultValue) {
386         if (align == null)
387             return defaultValue;
388         if (align.equals(g2d.Alignment_Leading))
389             return Alignment.LEADING;
390         if (align.equals(g2d.Alignment_Trailing))
391             return Alignment.TRAILING;
392         if (align.equals(g2d.Alignment_Center))
393             return Alignment.CENTER;
394         if (align.equals(g2d.Alignment_Baseline))
395             return Alignment.BASELINE;
396         return defaultValue;
397     }
398
399
400     public static Resource toFlagTypeResource(DiagramResource dr, FlagClass.Type type) {
401         switch (type) {
402             case In: return dr.FlagType_InputFlag;
403             case Out: return dr.FlagType_OutputFlag;
404             default: throw new IllegalArgumentException("unsupported flag type: " + type);
405         }
406     }
407
408     public static FlagClass.Type toFlagType(DiagramResource dr, Resource type) {
409         return toFlagType(dr, type, Type.In);
410     }
411
412     public static FlagClass.Type toFlagType(DiagramResource dr, Resource type, FlagClass.Type defaultValue) {
413         if (type != null) {
414             if (dr.FlagType_InputFlag.equals(type))
415                 return Type.In;
416             if (dr.FlagType_OutputFlag.equals(type))
417                 return Type.Out;
418         }
419         return defaultValue;
420     }
421
422     public static void tag(WriteGraph g, Resource object, Resource tag, boolean set) throws DatabaseException {
423         if (set)
424             g.claim(object, tag, tag, object);
425         else
426             g.deny(object, tag, tag, object);
427     }
428
429     /**
430      * @param graph
431      * @param diagram the diagram from which to look for a page description
432      *        property
433      * @return if the diagram does not have a page desc definition,
434      *         <code>defaultValue</code> is returned
435      * @throws DatabaseException
436      */
437     public static PageDesc getPageDesc(ReadGraph graph, Resource diagram, PageDesc defaultValue) throws DatabaseException {
438         DiagramResource dr = DiagramResource.getInstance(graph);
439         Resource pd = graph.getPossibleObject(diagram, dr.HasPageDescription);
440         if (pd == null)
441             return defaultValue;
442         return readPageDesc(graph, pd);
443     }
444
445     /**
446      * @param graph
447      * @param diagram
448      *            the diagram from which to look for a page description property
449      * @return PageDesc for the specified diagram
450      * @throws DatabaseException
451      *             if DIA.HasPageDescription can't be read
452      */
453     public static PageDesc getPageDesc(ReadGraph graph, Resource diagram) throws DatabaseException {
454         DiagramResource dr = DiagramResource.getInstance(graph);
455         Resource pd = graph.getSingleObject(diagram, dr.HasPageDescription);
456         return readPageDesc(graph, pd);
457     }
458
459     public static PageDesc readPageDesc(ReadGraph graph, Resource pageDesc) throws DatabaseException {
460         Layer0 l0 = Layer0.getInstance(graph);
461         DiagramResource dr = DiagramResource.getInstance(graph);
462         Resource orientation = graph.getSingleObject(pageDesc, dr.PageDescription_Orientation);
463         double[] size = graph.getRelatedValue(pageDesc, dr.PageDescription_Size, Bindings.getBindingUnchecked(double[].class));
464         Resource margins = graph.getSingleObject(pageDesc, dr.PageDescription_Margins);
465         Margins m = readMargins(graph, margins);
466         //PageDesc pd = PageDesc.getDescription(toOrientation(orientation, dr), size[0], size[1]);
467         String name = graph.getPossibleRelatedValue(pageDesc, l0.HasName);
468         if (name == null)
469             name = "";
470         PageDesc pd = new PageDesc(name, toOrientation(orientation, dr), PageCentering.TopLeftAtOrigin, size[0], size[1], m);
471         return pd;
472     }
473
474     public static Margins readMargins(ReadGraph graph, Resource margins) throws NoSingleResultException, DoesNotContainValueException, ServiceException {
475         DiagramResource dr = DiagramResource.getInstance(graph);
476         double t = graph.getRelatedValue(margins, dr.PageDescription_Margins_Top);
477         double b = graph.getRelatedValue(margins, dr.PageDescription_Margins_Bottom);
478         double l = graph.getRelatedValue(margins, dr.PageDescription_Margins_Left);
479         double r = graph.getRelatedValue(margins, dr.PageDescription_Margins_Right);
480         Margin mt = new Margin(0, 0, t);
481         Margin mb = new Margin(0, 0, b);
482         Margin ml = new Margin(0, 0, l);
483         Margin mr = new Margin(0, 0, r);
484         return new Margins(mt, mb, ml, mr);
485     }
486
487     public static void setPageDesc(WriteGraph graph, Resource diagram, String pageDescRepr) throws DatabaseException {
488         setPageDesc(graph, diagram, PageDesc.fromRepr(pageDescRepr));
489     }
490     
491     public static void setPageDesc(WriteGraph graph, Resource diagram, PageDesc pageDesc) throws DatabaseException {
492         Layer0 b = Layer0.getInstance(graph);
493         G2DResource g2d = G2DResource.getInstance(graph);
494         DiagramResource dr = DiagramResource.getInstance(graph);
495         Resource pd = graph.getPossibleObject(diagram, dr.HasPageDescription);
496         if(pd != null && graph.isImmutable(pd)) {
497                 graph.deny(diagram, dr.HasPageDescription);
498                 pd = null;
499         }
500         if (pd == null) {
501             pd = graph.newResource();
502             graph.claim(pd, b.InstanceOf, null, dr.PageDescription);
503             graph.claim(diagram, dr.HasPageDescription, pd);
504         }
505         graph.deny(pd, dr.PageDescription_Size);
506         Resource pageSize = graph.newResource();
507         graph.claim(pageSize, b.InstanceOf, null, g2d.Point2D);
508         graph.claimValue(pageSize, new double[] { pageDesc.getWidth(), pageDesc.getHeight() });
509         graph.claim(pd, dr.PageDescription_Size, pageSize);
510         graph.deny(pd, dr.PageDescription_Orientation);
511         graph.claim(pd, dr.PageDescription_Orientation, toOrientationResource(pageDesc.getOrientation(), dr));
512         Resource margins = graph.getPossibleObject(pd, dr.PageDescription_Margins);
513         if (margins == null) {
514             margins = graph.newResource();
515             graph.claim(margins, b.InstanceOf, null, dr.Margins);
516             graph.claim(pd, dr.PageDescription_Margins, margins);
517         }
518         setMargins(graph,pageDesc.getMargins(),margins, dr);
519         graph.claimLiteral(pd, b.HasName,pageDesc.getText());
520     }
521
522     private static PageOrientation toOrientation(Resource orientation, DiagramResource dr) {
523         if (orientation != null) {
524             if (orientation.equals(dr.Orientation_Portrait))
525                 return PageOrientation.Portrait;
526             if (orientation.equals(dr.Orientation_Landscape))
527                 return PageOrientation.Landscape;
528         }
529         return PageOrientation.Portrait;
530     }
531
532     public static Resource toOrientationResource(PageOrientation orientation, DiagramResource dr) {
533         if (PageOrientation.Portrait.equals(orientation))
534             return dr.Orientation_Portrait;
535         if (PageOrientation.Landscape.equals(orientation))
536             return dr.Orientation_Landscape;
537         return dr.Orientation_Portrait;
538     }
539
540     private static void setMargins(WriteGraph g, Margins margins, Resource marginsR,DiagramResource dr) throws ServiceException, ManyObjectsForFunctionalRelationException {
541
542         g.claimLiteral(marginsR, dr.PageDescription_Margins_Top,margins.top.diagramAbsolute);
543         g.claimLiteral(marginsR, dr.PageDescription_Margins_Bottom,margins.bottom.diagramAbsolute);
544         g.claimLiteral(marginsR, dr.PageDescription_Margins_Left,margins.left.diagramAbsolute);
545         g.claimLiteral(marginsR, dr.PageDescription_Margins_Right,margins.right.diagramAbsolute);
546
547     }
548
549     public static Double getGridSize(ReadGraph graph, Resource diagram, Double defaultValue) throws ManyObjectsForFunctionalRelationException, ServiceException {
550         DiagramResource dr = DiagramResource.getInstance(graph);
551         Double gridSize = graph.getPossibleRelatedValue(diagram, dr.HasGridSize);
552         return gridSize == null ? defaultValue : gridSize;
553     }
554
555     public static void setGridSize(WriteGraph graph, Resource diagram, double gridSize) throws ManyObjectsForFunctionalRelationException, ServiceException {
556         DiagramResource dr = DiagramResource.getInstance(graph);
557         graph.claimLiteral(diagram, dr.HasGridSize, gridSize);
558     }
559
560     public static boolean isPageBordersVisible(ReadGraph graph, Resource diagram) throws DatabaseException {
561         DiagramResource dr = DiagramResource.getInstance(graph);
562         return graph.hasStatement(diagram, dr.DisplayPageSize);
563     }
564
565     public static boolean isMarginsVisible(ReadGraph graph, Resource diagram) throws DatabaseException {
566         DiagramResource dr = DiagramResource.getInstance(graph);
567         return graph.hasStatement(diagram, dr.DisplayMargins);
568     }
569
570     public static void setPageBordersVisible(WriteGraph graph, Resource diagram, boolean visible) throws DatabaseException {
571         DiagramResource dr = DiagramResource.getInstance(graph);
572         tag(graph, diagram, dr.DisplayPageSize, visible);
573     }
574
575     public static void setMarginsVisible(WriteGraph graph, Resource diagram, boolean visible) throws DatabaseException {
576         DiagramResource dr = DiagramResource.getInstance(graph);
577         tag(graph, diagram, dr.DisplayMargins, visible);
578     }
579
580     public static void setDiagramDesc(WriteGraph graph, Resource diagram, DiagramDesc desc) throws DatabaseException {
581         DiagramGraphUtil.setPageDesc(graph, diagram, desc.getPageDesc());
582         DiagramGraphUtil.setGridSize(graph, diagram, desc.getGridSize());
583         DiagramGraphUtil.setPageBordersVisible(graph, diagram, desc.isPageBordersVisible());
584         DiagramGraphUtil.setMarginsVisible(graph, diagram, desc.isMarginsVisible());
585         // Add comment to change set.
586         CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
587         graph.addMetadata(cm.add("Set diagram description for diagram resource " + diagram));
588     }
589
590     /**
591      * Potentially returns the connection connected to the element with the
592      * given connectionRelation.
593      */
594     public static Resource getRelatedConnection(ReadGraph g, Resource element, Resource connectionRelation) throws DatabaseException {
595         StructuralResource2 sr = StructuralResource2.getInstance(g);
596         for(Resource connector : g.getObjects(element, connectionRelation))
597             for(Resource connection : g.getObjects(connector, sr.Connects))
598                 if(!connection.equals(element))
599                     return connection;
600         return null;
601     }
602
603     /**
604      * Returns the connection type of a potential connection connected to the
605      * element with the given connectionRelation.
606      */
607     public static Resource getRelatedConnectionType(ReadGraph g, Resource element, Resource connectionRelation) throws DatabaseException {
608         StructuralResource2 sr = StructuralResource2.getInstance(g);
609         for(Resource connector : g.getObjects(element, connectionRelation))
610             for(Resource connection : g.getObjects(connector, sr.Connects))
611                 if(!connection.equals(element))
612                     for(Resource connectionType : g.getObjects(connection, sr.HasConnectionType))
613                         return connectionType;
614         return null;
615     }
616
617     /**
618      * Returns a flag that is joined to this flag with a ConnectionJoin.
619      */
620     public static Resource getJoinedFlag(ReadGraph g, Resource flag) throws DatabaseException {
621         DiagramResource dr = DiagramResource.getInstance(g);
622         for(Resource join : g.getObjects(flag, dr.FlagIsJoinedBy))
623             for(Resource otherFlag : g.getObjects(join, dr.JoinsFlag))
624                 if(!otherFlag.equals(flag))
625                     return otherFlag;
626         return null;
627     }
628
629     public static Resource getConnectionTypeForFlag(ReadGraph g, Resource flag) throws DatabaseException {
630         DiagramResource dr = DiagramResource.getInstance(g);
631
632         Resource connectionType = getRelatedConnectionType(g, flag, dr.Flag_ConnectionPoint);
633         if(connectionType != null)
634             return connectionType;
635
636         Resource otherFlag = getJoinedFlag(g, flag);
637         if(otherFlag == null)
638             return null;
639
640         return getRelatedConnectionType(g, otherFlag, dr.Flag_ConnectionPoint);
641     }
642
643     /**
644      * Checks if the two specified diagram elements exist on the same diagram.
645      */
646     public static boolean onSameDiagram(ReadGraph graph, Resource element1, Resource element2) throws DatabaseException {
647         return !Collections.disjoint(
648                 OrderedSetElementsPredicate.INSTANCE.getSubjects(graph, element1),
649                 OrderedSetElementsPredicate.INSTANCE.getSubjects(graph, element2));
650     }
651
652     /**
653      * Checks whether a diagram element has a <code>DIAGRAM.Routing</code> tag
654      * that is adaptable to {@link IRouter2}.
655      * 
656      * @param graph
657      * @param element
658      * @param procedure
659      */
660     public static void getPossibleRouter(AsyncReadGraph graph, final Resource element, final AsyncProcedure<IRouter2> procedure) {
661         DiagramResource dr = graph.getService(DiagramResource.class);
662         graph.forPossibleStatement(element, dr.Routing, new AsyncProcedure<Statement>() {
663             @Override
664             public void exception(AsyncReadGraph graph, Throwable throwable) {
665                 procedure.exception(graph, throwable);
666             }
667             @Override
668             public void execute(AsyncReadGraph graph, Statement result) {
669                 if (result != null)
670                     graph.forPossibleAdapted(result.getPredicate(), IRouter2.class, procedure);
671                 else
672                     procedure.execute(graph, null);
673             }
674         });
675     }
676
677     /**
678      * @param graph
679      * @param modelingRules
680      * @param connection
681      * @param diagram
682      * @param edge
683      * @param firstTerminal
684      * @param secondTerminal
685      * @throws DatabaseException
686      */
687     public static void loadConnectionVisuals(ReadGraph graph, IModelingRules modelingRules, Resource connection,
688             IDiagram diagram, IElement edge, DesignatedTerminal firstTerminal, DesignatedTerminal secondTerminal)
689     throws DatabaseException {
690         List<EdgeVisuals> evs = edge.getElementClass().getItemsByClass(EdgeVisuals.class);
691         if (evs.isEmpty())
692             return;
693
694         IAttachmentRelationMap attachmentRelations = modelingRules.getAttachmentRelations(graph, connection);
695
696         IConnectionPoint firstCp = ConnectionUtil.toConnectionPoint(graph, firstTerminal);
697         IConnectionPoint secondCp = ConnectionUtil.toConnectionPoint(graph, secondTerminal);
698
699         Resource firstAttachment = null;
700         Resource secondAttachment = null;
701
702         if (firstCp instanceof CPTerminal)
703             firstAttachment = attachmentRelations.get(graph, (CPTerminal) firstCp);
704         if (secondCp instanceof CPTerminal)
705             secondAttachment = attachmentRelations.get(graph, (CPTerminal) secondCp);
706
707         if (DebugPolicy.DEBUG_CONNECTION_VISUALS_LOAD) {
708             System.out.println("first attachment relation : " + NameUtils.getSafeName(graph, firstAttachment));
709             System.out.println("second attachment relation : " + NameUtils.getSafeName(graph, secondAttachment));
710         }
711
712         // 1. Configure edge ends
713         loadEdgeEnds(graph, modelingRules, connection, edge, firstAttachment, secondAttachment);
714
715         // 2. Configure edge line style
716         loadLineStyle(graph, modelingRules, connection, edge);
717     }
718
719     public static void loadEdgeEnds(ReadGraph graph, IModelingRules modelingRules, Resource connection, IElement edge,
720             Resource firstAttachment, Resource secondAttachment) throws DatabaseException {
721         EdgeVisualsConfigurer startConfig = (firstAttachment != null) ? graph.syncRequest(Queries.adapt(
722                 firstAttachment, EdgeVisualsConfigurer.class, true)) : null;
723         EdgeVisualsConfigurer endConfig = (secondAttachment != null) ? graph.syncRequest(Queries.adapt(
724                 secondAttachment, EdgeVisualsConfigurer.class, true)) : null;
725
726         for (EdgeVisuals ev : edge.getElementClass().getItemsByClass(EdgeVisuals.class)) {
727             if (startConfig != null)
728                 startConfig.configure(edge, ev, EdgeVisuals.BEGIN);
729             else
730                 ev.setArrowType(edge, EdgeEnd.Begin, ArrowType.None);
731             if (endConfig != null)
732                 endConfig.configure(edge, ev, EdgeVisuals.END);
733             else
734                 ev.setArrowType(edge, EdgeEnd.End, ArrowType.None);
735         }
736     }
737
738     public static void loadLineStyle(ReadGraph graph, IModelingRules modelingRules, Resource connection, IElement edge)
739     throws DatabaseException {
740         Resource connectionType = modelingRules.getConnectionType(graph, connection);
741         if (connectionType != null) {
742             loadLineStyleFromConnectionType(graph, modelingRules, connectionType, edge);
743         }
744     }
745
746     public static void loadLineStyleFromConnectionType(ReadGraph graph, IModelingRules modelingRules, Resource connectionType, IElement edge)
747     throws DatabaseException {
748         edge.setHint(ElementHints.KEY_CONNECTION_TYPE, connectionType);
749         if (DebugPolicy.DEBUG_CONNECTION_VISUALS_LOAD)
750             System.out.println("Connection type : " + NameUtils.getSafeName(graph, connectionType));
751
752         // Load standard visual aspects of the specified edge
753         ConnectionVisuals cv = graph.syncRequest(DiagramRequests.getConnectionVisuals(connectionType));
754
755         if (cv.color != null) {
756             for (FillColor fc : edge.getElementClass().getItemsByClass(FillColor.class)) {
757                 fc.setFillColor(edge, cv.toColor());
758             }
759         }
760         for (EdgeVisuals ev : edge.getElementClass().getItemsByClass(EdgeVisuals.class)) {
761             if (cv.stroke != null)
762                 ev.setStroke(edge, cv.stroke);
763             if (cv.strokeType != null)
764                 ev.setStrokeType(edge, cv.strokeType);
765         }
766     }
767
768     /**
769      * @param graph
770      * @param connectionPart
771      * @return
772      * @throws DatabaseException
773      */
774     public static ConnectionSegmentEnd resolveConnectionSegmentEnd(ReadGraph graph, Resource connectionPart)
775     throws DatabaseException {
776         BasicResources br = BasicResources.getInstance(graph);
777         if (graph.isInstanceOf(connectionPart, br.DIA.BranchPoint))
778             return ConnectionSegmentEnd.BRANCH;
779         if (graph.isInstanceOf(connectionPart, br.DIA.Connector))
780             return ConnectionSegmentEnd.CONNECTOR;
781         return null;
782     }
783
784     /**
785      * @param graph
786      * @param diagram
787      * @param segmentEnd
788      * @param endType
789      * @return
790      * @throws DatabaseException
791      */
792     public static DesignatedTerminal findDesignatedTerminal(ReadGraph graph, IDiagram diagram, Resource segmentEnd, ConnectionSegmentEnd endType)
793     throws DatabaseException {
794         if (DebugPolicy.DEBUG_TERMINAL_SEARCH)
795             System.out.println("findDesignatedTerminal: " + NameUtils.getSafeName(graph, segmentEnd) + " : " + endType);
796
797         BasicResources br = BasicResources.getInstance(graph);
798         DataElementMap dem = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
799
800         switch (endType) {
801             case CONNECTOR: {
802                 List<Terminal> ts = new ArrayList<Terminal>();
803                 for (Statement stm : graph.getStatements(segmentEnd, br.STR.Connects)) {
804                     // Ignore the Is Connector Of relation that goes to the
805                     // owner :Connection
806                     if (graph.isSubrelationOf(stm.getPredicate(), br.DIA.IsConnectorOf))
807                         continue;
808
809                     Resource connectionRelation = graph.getInverse(stm.getPredicate());
810                     if (DebugPolicy.DEBUG_TERMINAL_SEARCH)
811                         System.out.println("CONNECTION RELATION: " + NameUtils.getSafeName(graph, connectionRelation));
812                     Resource elementResource = stm.getObject();
813                     if (DebugPolicy.DEBUG_TERMINAL_SEARCH)
814                         System.out.println("ELEMENT RESOURCE: " + NameUtils.getSafeName(graph, elementResource));
815                     IElement e = dem.getElement(diagram, elementResource);
816                     if (e == null) {
817                         return null;
818 //                        throw new ValidationException("connector "
819 //                                + NameUtils.getSafeName(graph, segmentEnd)
820 //                                + " is connected to an entity that has not (yet) been loaded as an IElement: "
821 //                                + NameUtils.getSafeName(graph, elementResource));
822                     }
823
824                     TerminalTopology tt = e.getElementClass().getSingleItem(TerminalTopology.class);
825                     ts.clear();
826                     tt.getTerminals(e, ts);
827                     for (Terminal t : ts) {
828                         if (t instanceof ResourceTerminal) {
829                             ResourceTerminal rt = (ResourceTerminal) t;
830                             Resource binds = DiagramGraphUtil.getConnectionPointOfTerminal(graph, rt.getResource());
831                             if (DebugPolicy.DEBUG_TERMINAL_SEARCH) {
832                                 System.out.println("connection relation: "
833                                         + NameUtils.getSafeName(graph, connectionRelation) + " " + connectionRelation.getResourceId());
834                                 System.out.println("  terminal: " + NameUtils.getSafeName(graph, rt.getResource()) + " " + rt.getResource().getResourceId());
835                                 System.out.println("  binds:    " + NameUtils.getSafeName(graph, binds) + " " + binds.getResourceId());
836                             }
837                             if (graph.isSubrelationOf(connectionRelation, binds)) {
838                                 return new DesignatedTerminal(e, t);
839                             }
840                         }
841                     }
842
843                     throw new ValidationException("connector "
844                             + NameUtils.getSafeName(graph, segmentEnd)
845                             + " is connected using a relation that is not its own: "
846                             + NameUtils.getSafeName(graph, connectionRelation));
847                 }
848                 // throw new
849                 // ValidationException("connector " +
850                 // NameUtils.getSafeName(g, segmentEnd) +
851                 // " is not connected to anything");
852                 return null;
853             }
854             case BRANCH: {
855                 List<Terminal> ts = new ArrayList<Terminal>();
856                 IElement e = dem.getElement(diagram, segmentEnd);
857                 if (e == null) {
858 //                    throw new ValidationException("branch point "
859 //                            + NameUtils.getSafeName(graph, segmentEnd)
860 //                            + " has not (yet) been loaded as an IElement");
861                     return null;
862                 }
863
864                 TerminalTopology tt = e.getElementClass().getSingleItem(TerminalTopology.class);
865                 tt.getTerminals(e, ts);
866                 if (ts.size() != 1)
867                     throw new IllegalStateException("branch point element has " + ts.size()
868                             + " terminals, expected 1");
869                 return new DesignatedTerminal(e, ts.get(0));
870             }
871             default:
872                 throw new IllegalArgumentException("unexpected connection segment end: " + endType);
873         }
874     }
875
876     /**
877      * @param graph
878      * @param diagram
879      * @param terminalStm the statement that goes from the connection
880      *        connector to the node with inverse relation of the terminal
881      *        relation.
882      * @return
883      * @throws DatabaseException
884      */
885     public static DesignatedTerminal getDesignatedTerminalForConnector(ReadGraph graph, IDiagram diagram, Resource elementResource, Resource terminalRelation, Resource connector)
886     throws DatabaseException {
887         if (DebugPolicy.DEBUG_TERMINAL_SEARCH)
888             System.out.println("getDesignatedTerminalForConnector: ("
889                     + NameUtils.getSafeName(graph, elementResource) + ", "
890                     + NameUtils.getSafeName(graph, terminalRelation) + ", "
891                     + NameUtils.getSafeName(graph, connector) + ")"
892                     );
893
894         DataElementMap dem = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
895         IElement e = dem.getElement(diagram, elementResource);
896         if (e == null)
897             return null;
898
899         TerminalTopology tt = e.getElementClass().getSingleItem(TerminalTopology.class);
900         List<Terminal> ts = new ArrayList<Terminal>();
901         tt.getTerminals(e, ts);
902         for (Terminal t : ts) {
903             if (t instanceof ResourceTerminal) {
904                 ResourceTerminal rt = (ResourceTerminal) t;
905                 Resource binds = DiagramGraphUtil.getConnectionPointOfTerminal(graph, rt.getResource());
906                 if (DebugPolicy.DEBUG_TERMINAL_SEARCH) {
907                     System.out.println("connection relation: "
908                             + NameUtils.getSafeName(graph, terminalRelation, true));
909                     System.out.println("  terminal: " + NameUtils.getSafeName(graph, rt.getResource(), true));
910                     System.out.println("  binds:    " + NameUtils.getSafeName(graph, binds, true));
911                 }
912                 if (graph.isSubrelationOf(terminalRelation, binds)) {
913                     return new DesignatedTerminal(e, t);
914                 }
915             }
916         }
917
918         throw new ValidationException("terminal connection statement ("
919                 + NameUtils.getSafeName(graph, elementResource) + ", "
920                 + NameUtils.getSafeName(graph, terminalRelation) + ", "
921                 + NameUtils.getSafeName(graph, connector) + ")"
922                 + " is using using a terminal relation that is not its own: "
923                 + NameUtils.getSafeName(graph, terminalRelation));
924     }
925
926     /**
927      * @param graph
928      * @return
929      * @throws DatabaseException
930      */
931     public static TerminalMap getElementTerminals(ReadGraph graph, Resource element)
932     throws DatabaseException {
933         DiagramResource DIA = DiagramResource.getInstance(graph);
934         Resource elementType = graph.getPossibleType(element, DIA.Element);
935         return elementType != null ? getElementTypeTerminals(graph, elementType) : TerminalMap.EMPTY;
936     }
937
938     private static final boolean DEBUG_GET_ELEMENT_TYPE_TERMINALS = false;
939
940     /**
941      * @param graph
942      * @param elementType
943      * @return
944      * @throws DatabaseException
945      */
946     public static TerminalMap getElementTypeTerminals(ReadGraph graph, Resource elementType) throws DatabaseException {
947         StructuralResource2 STR = StructuralResource2.getInstance(graph);
948         DiagramResource DIA = DiagramResource.getInstance(graph);
949         if (DEBUG_GET_ELEMENT_TYPE_TERMINALS)
950             System.out.println("getElementTypeTerminals: " + NameUtils.getSafeName(graph, elementType));
951         Resource definedBy = graph.getSingleObject(elementType, STR.IsDefinedBy);
952         Collection<Resource> parts = OrderedSetUtils.toList(graph, definedBy);
953         if (DEBUG_GET_ELEMENT_TYPE_TERMINALS)
954             System.out.println("\tdefining part count: " + parts.size());
955         TerminalMap result = null;
956         for (Resource part : parts) {
957             if (DEBUG_GET_ELEMENT_TYPE_TERMINALS)
958                 System.out.println("\t\tpart: " + NameUtils.getSafeName(graph, part));
959             if (graph.isInstanceOf(part, DIA.Terminal)) {
960                 Resource binds = DiagramGraphUtil.getConnectionPointOfTerminal(graph, part);
961                 if (result == null)
962                     result = new TerminalMap(parts.size());
963                 if (DEBUG_GET_ELEMENT_TYPE_TERMINALS)
964                     System.out.println("\t\t\tFOUND TERMINAL <-> BINDING RELATION: " + NameUtils.getSafeName(graph, part) + " <-> " + NameUtils.getSafeName(graph, binds));
965                 result.put(part, binds);
966             }
967         }
968         return result != null ? result : TerminalMap.EMPTY;
969     }
970
971     /**
972      * Get the value of a specified on/off diagram preference setting (=tag)
973      * where the tag may be stored in:
974      * <ol>
975      * <li>The diagram itself</li>
976      * <li>The model</li>
977      * <li>The project</li>
978      * </ol>
979      * 
980      * @param graph database access
981      * @param diagram the diagram to look for the tag in
982      * @param preference the tag relation of the boolean preference to check for
983      * @return value of the preference
984      * @throws DatabaseException
985      */
986     public static boolean getDiagramTagPreference(ReadGraph graph, Resource diagram, Resource preference) throws DatabaseException {
987         boolean result = graph.hasStatement(diagram, preference);
988         if (!result) {
989             Resource model = graph.sync(new PossibleModel(diagram));
990             if (model != null)
991                 result = graph.hasStatement(model, preference);
992             if (!result)
993                 result = graph.hasStatement(Simantics.getProjectResource(), preference);
994         }
995         return result;
996     }
997
998     public static void rotateConnection(WriteGraph graph, Resource r, 
999             double cx, double cy, boolean clockwise) throws DatabaseException {
1000         DiagramResource DIA = DiagramResource.getInstance(graph);
1001         for(Resource node : graph.getObjects(r, DIA.HasInteriorRouteNode))
1002             if(graph.isInstanceOf(node, DIA.RouteLine)) {
1003                 boolean isHorizontal = (Boolean)graph.getRelatedValue(node, DIA.IsHorizontal);
1004                 double position = (Double)graph.getRelatedValue(node, DIA.HasPosition);
1005                 
1006                 if(isHorizontal) {
1007                     position -= cy;
1008                     if(clockwise)
1009                         position = -position;
1010                     position += cx;
1011                 }
1012                 else {
1013                     position -= cx;
1014                     if(!clockwise)
1015                         position = -position;
1016                     position += cy;
1017                 }
1018                 isHorizontal = !isHorizontal;                
1019                 
1020                 graph.claimLiteral(node, DIA.IsHorizontal, isHorizontal);
1021                 graph.claimLiteral(node, DIA.HasPosition, position);
1022             }
1023     }
1024
1025     public static void flipConnection(WriteGraph graph, Resource r,
1026             boolean xAxis, double c) throws DatabaseException {
1027         DiagramResource DIA = DiagramResource.getInstance(graph);
1028         for(Resource node : graph.getObjects(r, DIA.HasInteriorRouteNode))
1029             if(graph.isInstanceOf(node, DIA.RouteLine)) {
1030                 boolean isHorizontal = (Boolean)graph.getRelatedValue(node, DIA.IsHorizontal);
1031
1032                 if(isHorizontal == xAxis) {
1033                     double position = (Double)graph.getRelatedValue(node, DIA.HasPosition);
1034                     position = 2*c-position;
1035                     graph.claimLiteral(node, DIA.HasPosition, position);
1036                 }
1037             }
1038     }
1039     
1040     /*public static void addConnectionPoint(WriteGraph g, Resource symbol, Resource terminal, 
1041             Resource diagramConnectionRelation) throws DatabaseException {
1042         Layer0 L0 = Layer0.getInstance(g);
1043         StructuralResource2 STR = StructuralResource2.getInstance(g);
1044         DiagramResource DIA = DiagramResource.getInstance(g);
1045         
1046         Resource variable = g.newResource();
1047         g.claim(variable, L0.InstanceOf, null, STR.ConnectionVariable);
1048         g.claim(terminal, DIA.HasConnectionVariable, variable);
1049         g.claim(variable, STR.Binds, diagramConnectionRelation);
1050         g.claim(variable, STR.IsParameterOf, symbol);
1051     }
1052     
1053
1054     public static Resource getConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {
1055         return g.getSingleObject(
1056                 g.getSingleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionVariable),
1057                 StructuralResource2.getInstance(g).Binds);
1058     }
1059
1060     public static Resource getPossibleConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {
1061         Resource connectionVariable = g.getPossibleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionVariable);
1062         return (connectionVariable == null) ? null : g.getPossibleObject(connectionVariable, StructuralResource2.getInstance(g).Binds);
1063     }*/
1064     
1065     public static void addConnectionPoint(WriteGraph g, Resource symbol, Resource terminal, 
1066             Resource diagramConnectionRelation) throws DatabaseException {
1067         Layer0 L0 = Layer0.getInstance(g);
1068         DiagramResource DIA = DiagramResource.getInstance(g);
1069         
1070         g.claim(terminal, DIA.HasConnectionPoint, diagramConnectionRelation);
1071         g.claim(diagramConnectionRelation, L0.HasDomain, symbol);
1072     }
1073     
1074
1075     public static Resource getConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {
1076         return g.getSingleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionPoint);
1077     }
1078
1079     public static Resource getPossibleConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {
1080         return g.getPossibleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionPoint);
1081     }
1082
1083     public static Collection<Resource> getTerminals(ReadGraph g, Resource symbol) throws DatabaseException {
1084 //        Layer0 L0 = Layer0.getInstance(g);
1085         StructuralResource2 STR = StructuralResource2.getInstance(g);
1086         DiagramResource DIA = DiagramResource.getInstance(g);
1087         List<Resource> terminals = null;
1088         for (Resource definedBy : g.getObjects(symbol, STR.IsDefinedBy)) {
1089             Collection<Resource> elements = g.syncRequest( new OrderedSet(definedBy) );
1090             if (terminals == null)
1091                 terminals = new ArrayList<Resource>( elements.size() );
1092             for (Resource element : elements)
1093                 if (g.isInstanceOf(element, DIA.Terminal))
1094                     terminals.add(element);
1095         }
1096 //        Collection<Resource> definedBy = g.getObjects(symbol, STR.IsDefinedBy);
1097 //        if (!definedBy.isEmpty()) {
1098 //            Collection<Resource> relations = g.getObjects(symbol, L0.DomainOf);
1099 //            terminals = new ArrayList<Resource>(relations.size());
1100 //            for(Resource relation : relations) {
1101 //                for (Resource element : g.getObjects(relation, DIA.HasConnectionPoint_Inverse)) {
1102 //                    Collection<Resource> owners = OrderedSetUtils.getOwnerLists(g, element, DIA.Diagram);
1103 //                    if (!Collections.disjoint(definedBy, owners))
1104 //                        terminals.add(element);
1105 //                }
1106 //            }
1107 //        }
1108         return terminals == null ? Collections.<Resource>emptyList() : terminals;
1109     }
1110         
1111     /**
1112      * Determines the connection type of the given diagram connection. Uses the modeling rules
1113      * specified in the diagram the connection belongs to.
1114      */
1115         public static Resource determineConnectionType(ReadGraph graph, Resource diagramConnection) throws DatabaseException {
1116                 Layer0 L0 = Layer0.getInstance(graph);
1117                 Resource diagram = graph.getPossibleObject(diagramConnection, L0.PartOf);
1118                 if (diagram == null)
1119                         // Invalid diagram connection resource, not a part of any diagram.
1120                         return null;
1121                 IModelingRules modelingRules = graph.syncRequest(DiagramRequests.getModelingRules(diagram, null));
1122                 if (modelingRules == null)
1123                         return null;
1124                 return determineConnectionType(graph, diagramConnection, modelingRules);
1125         }
1126
1127         /**
1128      * Determines the connection type of the given diagram connection assuming the given modeling rules.
1129      */
1130         public static Resource determineConnectionType(ReadGraph graph, Resource diagramConnection, IModelingRules modelingRules) throws DatabaseException {
1131
1132                 Set<IConnectionPoint> cps = new THashSet<IConnectionPoint>();
1133                 DiagramRequests.expandConnections(graph, diagramConnection, new THashSet<Resource>(), cps);
1134                 return modelingRules.computeConnectionType(graph, cps);
1135                 
1136         }
1137         
1138         public static void defaultSymbolDropHandler(WriteGraph graph, List<WorkbenchSelectionElement> drop) throws DatabaseException {
1139                 System.err.println("dropped " + drop);
1140         }
1141
1142     public static IModelingRules getModelingRules(ReadGraph graph, Resource diagram, IModelingRules defaultValue) throws DatabaseException {
1143         StructuralResource2 sr = StructuralResource2.getInstance(graph);
1144         Resource rules = graph.getPossibleObject(diagram, sr.HasModelingRules);
1145         if (rules == null)
1146             return defaultValue;
1147         return graph.adapt(rules, IModelingRules.class);
1148     }
1149     
1150 }