1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.diagram.synchronization.graph;
14 import gnu.trove.set.hash.THashSet;
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;
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;
95 * @author Tuukka Lehtonen
97 public final class DiagramGraphUtil {
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"));
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"));
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"));
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);
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);
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;
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;
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;
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);
173 * @throws DatabaseException
175 public static AffineTransform getWorldTransform(ReadGraph graph, Resource element) throws DatabaseException {
176 ModelingResources MOD = ModelingResources.getInstance(graph);
177 AffineTransform result = DiagramGraphUtil.getAffineTransform(graph, element);
179 Resource parentComponent = graph.getPossibleObject(element, MOD.HasParentComponent);
180 if (parentComponent == null)
182 element = graph.getPossibleObject(parentComponent, MOD.ComponentToElement);
185 AffineTransform tr = DiagramGraphUtil.getAffineTransform(graph, element);
186 tr.setToTranslation(tr.getTranslateX(), tr.getTranslateY());
187 result.preConcatenate(tr);
196 * @throws DatabaseException
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);
202 Resource parentComponent = graph.getPossibleObject(element, MOD.HasParentComponent);
203 if (parentComponent == null)
205 element = graph.getPossibleObject(parentComponent, MOD.ComponentToElement);
208 AffineTransform tr = DiagramGraphUtil.getDynamicAffineTransform(graph, runtime, element);
209 tr.setToTranslation(tr.getTranslateX(), tr.getTranslateY());
210 result.preConcatenate(tr);
218 * @param invalidAsIdentity true to return invalid transforms as identity
219 * transforms, <code>false</code> to return <code>null</code>
221 * @throws DatabaseException
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;
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;
237 public static double[] getPossibleRelatedDoubleArray(ReadGraph graph, Resource resource, Resource relation) throws DatabaseException {
238 Resource res = graph.getPossibleObject(resource, relation);
241 return graph.getValue(res, Bindings.getBindingUnchecked(double[].class));
244 public static AffineTransform getTransform(ReadGraph graph, Resource resource) throws DatabaseException {
245 DiagramResource DIA = DiagramResource.getInstance(graph);
247 double[] matrix = graph.getPossibleRelatedValue(resource, DIA.HasTransform, Bindings.DOUBLE_ARRAY);
249 return new AffineTransform();
250 if (matrix.length < 4)
251 return new AffineTransform();
252 return new AffineTransform(matrix);
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);
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);
265 setRelatedValue(graph, resource, DIA.HasTransform, G2D.Transform, matrix, Bindings.DOUBLE_ARRAY);
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);
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);
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);
282 addRelatedValue(graph, resource, relation, valueType, arrayValue, binding);
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);
289 //Object old = graph.getValue2(p);
290 //if (!Arrays.equals(old, arrayValue))
291 graph.claimValue(stm.getObject(), arrayValue, binding);
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);
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);
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)
318 return t == null ? defaultValue : t;
321 public static Resource getConnectionPointOfTerminal(ReadGraph g, Terminal forTerminal) throws DatabaseException {
322 if (forTerminal instanceof ResourceTerminal)
323 return getConnectionPointOfTerminal(g, ((ResourceTerminal) forTerminal).getResource());
327 public static Resource tryGetBindingRelation(ReadGraph g, Terminal forTerminal) throws DatabaseException {
328 if (forTerminal instanceof ResourceTerminal)
329 return getPossibleConnectionPointOfTerminal(g, ((ResourceTerminal) forTerminal).getResource());
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;
340 return LineJoin.miter;
343 public static LineCap toLineCap(G2DResource g2d, Resource lineCap) {
344 if (lineCap != null) {
345 if (lineCap.equals(g2d.LineCap_ButtCap))
347 if (lineCap.equals(g2d.LineCap_RoundCap))
348 return LineCap.round;
350 return LineCap.square;
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;
360 return g2d.LineJoin_MiterJoin;
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;
370 return g2d.LineCap_SquareCap;
373 public static Alignment toAlignment(Resource align, G2DResource g2d, Alignment 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;
385 public static Alignment toVerticalAlignment(Resource align, G2DResource g2d, Alignment 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;
400 public static Resource toFlagTypeResource(DiagramResource dr, FlagClass.Type type) {
402 case In: return dr.FlagType_InputFlag;
403 case Out: return dr.FlagType_OutputFlag;
404 default: throw new IllegalArgumentException("unsupported flag type: " + type);
408 public static FlagClass.Type toFlagType(DiagramResource dr, Resource type) {
409 return toFlagType(dr, type, Type.In);
412 public static FlagClass.Type toFlagType(DiagramResource dr, Resource type, FlagClass.Type defaultValue) {
414 if (dr.FlagType_InputFlag.equals(type))
416 if (dr.FlagType_OutputFlag.equals(type))
422 public static void tag(WriteGraph g, Resource object, Resource tag, boolean set) throws DatabaseException {
424 g.claim(object, tag, tag, object);
426 g.deny(object, tag, tag, object);
431 * @param diagram the diagram from which to look for a page description
433 * @return if the diagram does not have a page desc definition,
434 * <code>defaultValue</code> is returned
435 * @throws DatabaseException
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);
442 return readPageDesc(graph, pd);
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
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);
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);
470 PageDesc pd = new PageDesc(name, toOrientation(orientation, dr), PageCentering.TopLeftAtOrigin, size[0], size[1], m);
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);
487 public static void setPageDesc(WriteGraph graph, Resource diagram, String pageDescRepr) throws DatabaseException {
488 setPageDesc(graph, diagram, PageDesc.fromRepr(pageDescRepr));
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);
501 pd = graph.newResource();
502 graph.claim(pd, b.InstanceOf, null, dr.PageDescription);
503 graph.claim(diagram, dr.HasPageDescription, pd);
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);
518 setMargins(graph,pageDesc.getMargins(),margins, dr);
519 graph.claimLiteral(pd, b.HasName,pageDesc.getText());
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;
529 return PageOrientation.Portrait;
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;
540 private static void setMargins(WriteGraph g, Margins margins, Resource marginsR,DiagramResource dr) throws ServiceException, ManyObjectsForFunctionalRelationException {
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);
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;
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);
560 public static boolean isPageBordersVisible(ReadGraph graph, Resource diagram) throws DatabaseException {
561 DiagramResource dr = DiagramResource.getInstance(graph);
562 return graph.hasStatement(diagram, dr.DisplayPageSize);
565 public static boolean isMarginsVisible(ReadGraph graph, Resource diagram) throws DatabaseException {
566 DiagramResource dr = DiagramResource.getInstance(graph);
567 return graph.hasStatement(diagram, dr.DisplayMargins);
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);
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);
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));
591 * Potentially returns the connection connected to the element with the
592 * given connectionRelation.
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))
604 * Returns the connection type of a potential connection connected to the
605 * element with the given connectionRelation.
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;
618 * Returns a flag that is joined to this flag with a ConnectionJoin.
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))
629 public static Resource getConnectionTypeForFlag(ReadGraph g, Resource flag) throws DatabaseException {
630 DiagramResource dr = DiagramResource.getInstance(g);
632 Resource connectionType = getRelatedConnectionType(g, flag, dr.Flag_ConnectionPoint);
633 if(connectionType != null)
634 return connectionType;
636 Resource otherFlag = getJoinedFlag(g, flag);
637 if(otherFlag == null)
640 return getRelatedConnectionType(g, otherFlag, dr.Flag_ConnectionPoint);
644 * Checks if the two specified diagram elements exist on the same diagram.
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));
653 * Checks whether a diagram element has a <code>DIAGRAM.Routing</code> tag
654 * that is adaptable to {@link IRouter2}.
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>() {
664 public void exception(AsyncReadGraph graph, Throwable throwable) {
665 procedure.exception(graph, throwable);
668 public void execute(AsyncReadGraph graph, Statement result) {
670 graph.forPossibleAdapted(result.getPredicate(), IRouter2.class, procedure);
672 procedure.execute(graph, null);
679 * @param modelingRules
683 * @param firstTerminal
684 * @param secondTerminal
685 * @throws DatabaseException
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);
694 IAttachmentRelationMap attachmentRelations = modelingRules.getAttachmentRelations(graph, connection);
696 IConnectionPoint firstCp = ConnectionUtil.toConnectionPoint(graph, firstTerminal);
697 IConnectionPoint secondCp = ConnectionUtil.toConnectionPoint(graph, secondTerminal);
699 Resource firstAttachment = null;
700 Resource secondAttachment = null;
702 if (firstCp instanceof CPTerminal)
703 firstAttachment = attachmentRelations.get(graph, (CPTerminal) firstCp);
704 if (secondCp instanceof CPTerminal)
705 secondAttachment = attachmentRelations.get(graph, (CPTerminal) secondCp);
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));
712 // 1. Configure edge ends
713 loadEdgeEnds(graph, modelingRules, connection, edge, firstAttachment, secondAttachment);
715 // 2. Configure edge line style
716 loadLineStyle(graph, modelingRules, connection, edge);
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;
726 for (EdgeVisuals ev : edge.getElementClass().getItemsByClass(EdgeVisuals.class)) {
727 if (startConfig != null)
728 startConfig.configure(edge, ev, EdgeVisuals.BEGIN);
730 ev.setArrowType(edge, EdgeEnd.Begin, ArrowType.None);
731 if (endConfig != null)
732 endConfig.configure(edge, ev, EdgeVisuals.END);
734 ev.setArrowType(edge, EdgeEnd.End, ArrowType.None);
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);
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));
752 // Load standard visual aspects of the specified edge
753 ConnectionVisuals cv = graph.syncRequest(DiagramRequests.getConnectionVisuals(connectionType));
755 if (cv.color != null) {
756 for (FillColor fc : edge.getElementClass().getItemsByClass(FillColor.class)) {
757 fc.setFillColor(edge, cv.toColor());
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);
770 * @param connectionPart
772 * @throws DatabaseException
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;
790 * @throws DatabaseException
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);
797 BasicResources br = BasicResources.getInstance(graph);
798 DataElementMap dem = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
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
806 if (graph.isSubrelationOf(stm.getPredicate(), br.DIA.IsConnectorOf))
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);
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));
824 TerminalTopology tt = e.getElementClass().getSingleItem(TerminalTopology.class);
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());
837 if (graph.isSubrelationOf(connectionRelation, binds)) {
838 return new DesignatedTerminal(e, t);
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));
849 // ValidationException("connector " +
850 // NameUtils.getSafeName(g, segmentEnd) +
851 // " is not connected to anything");
855 List<Terminal> ts = new ArrayList<Terminal>();
856 IElement e = dem.getElement(diagram, segmentEnd);
858 // throw new ValidationException("branch point "
859 // + NameUtils.getSafeName(graph, segmentEnd)
860 // + " has not (yet) been loaded as an IElement");
864 TerminalTopology tt = e.getElementClass().getSingleItem(TerminalTopology.class);
865 tt.getTerminals(e, ts);
867 throw new IllegalStateException("branch point element has " + ts.size()
868 + " terminals, expected 1");
869 return new DesignatedTerminal(e, ts.get(0));
872 throw new IllegalArgumentException("unexpected connection segment end: " + endType);
879 * @param terminalStm the statement that goes from the connection
880 * connector to the node with inverse relation of the terminal
883 * @throws DatabaseException
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) + ")"
894 DataElementMap dem = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
895 IElement e = dem.getElement(diagram, elementResource);
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));
912 if (graph.isSubrelationOf(terminalRelation, binds)) {
913 return new DesignatedTerminal(e, t);
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));
929 * @throws DatabaseException
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;
938 private static final boolean DEBUG_GET_ELEMENT_TYPE_TERMINALS = false;
944 * @throws DatabaseException
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);
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);
968 return result != null ? result : TerminalMap.EMPTY;
972 * Get the value of a specified on/off diagram preference setting (=tag)
973 * where the tag may be stored in:
975 * <li>The diagram itself</li>
977 * <li>The project</li>
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
986 public static boolean getDiagramTagPreference(ReadGraph graph, Resource diagram, Resource preference) throws DatabaseException {
987 boolean result = graph.hasStatement(diagram, preference);
989 Resource model = graph.sync(new PossibleModel(diagram));
991 result = graph.hasStatement(model, preference);
993 result = graph.hasStatement(Simantics.getProjectResource(), preference);
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);
1009 position = -position;
1015 position = -position;
1018 isHorizontal = !isHorizontal;
1020 graph.claimLiteral(node, DIA.IsHorizontal, isHorizontal);
1021 graph.claimLiteral(node, DIA.HasPosition, position);
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);
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);
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);
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);
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);
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);
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);
1070 g.claim(terminal, DIA.HasConnectionPoint, diagramConnectionRelation);
1071 g.claim(diagramConnectionRelation, L0.HasDomain, symbol);
1075 public static Resource getConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {
1076 return g.getSingleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionPoint);
1079 public static Resource getPossibleConnectionPointOfTerminal(ReadGraph g, Resource forTerminal) throws DatabaseException {
1080 return g.getPossibleObject(forTerminal, DiagramResource.getInstance(g).HasConnectionPoint);
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);
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);
1108 return terminals == null ? Collections.<Resource>emptyList() : terminals;
1112 * Determines the connection type of the given diagram connection. Uses the modeling rules
1113 * specified in the diagram the connection belongs to.
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.
1121 IModelingRules modelingRules = graph.syncRequest(DiagramRequests.getModelingRules(diagram, null));
1122 if (modelingRules == null)
1124 return determineConnectionType(graph, diagramConnection, modelingRules);
1128 * Determines the connection type of the given diagram connection assuming the given modeling rules.
1130 public static Resource determineConnectionType(ReadGraph graph, Resource diagramConnection, IModelingRules modelingRules) throws DatabaseException {
1132 Set<IConnectionPoint> cps = new THashSet<IConnectionPoint>();
1133 DiagramRequests.expandConnections(graph, diagramConnection, new THashSet<Resource>(), cps);
1134 return modelingRules.computeConnectionType(graph, cps);
1138 public static void defaultSymbolDropHandler(WriteGraph graph, List<WorkbenchSelectionElement> drop) throws DatabaseException {
1139 System.err.println("dropped " + drop);
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);
1146 return defaultValue;
1147 return graph.adapt(rules, IModelingRules.class);