]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
e7f29f1cae380fa217bcc3756f204a17765189c5
[simantics/sysdyn.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2010, 2012 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.sysdyn.ui.elements.connections;\r
13 \r
14 import java.awt.BasicStroke;\r
15 import java.awt.Color;\r
16 import java.awt.Font;\r
17 import java.awt.Shape;\r
18 import java.awt.Stroke;\r
19 import java.awt.geom.Path2D;\r
20 import java.awt.geom.Rectangle2D;\r
21 import java.beans.PropertyChangeEvent;\r
22 import java.beans.PropertyChangeListener;\r
23 import java.util.HashMap;\r
24 import java.util.Map;\r
25 \r
26 import org.eclipse.core.runtime.IStatus;\r
27 import org.eclipse.core.runtime.Status;\r
28 import org.simantics.Simantics;\r
29 import org.simantics.db.Resource;\r
30 import org.simantics.db.WriteGraph;\r
31 import org.simantics.db.common.request.WriteRequest;\r
32 import org.simantics.db.exception.DatabaseException;\r
33 import org.simantics.g2d.diagram.DiagramHints;\r
34 import org.simantics.g2d.diagram.IDiagram;\r
35 import org.simantics.g2d.diagram.handler.PickRequest.PickPolicy;\r
36 import org.simantics.g2d.diagram.handler.Topology;\r
37 import org.simantics.g2d.diagram.handler.Topology.Connection;\r
38 import org.simantics.g2d.element.ElementClass;\r
39 import org.simantics.g2d.element.ElementHints;\r
40 import org.simantics.g2d.element.ElementUtils;\r
41 import org.simantics.g2d.element.IElement;\r
42 import org.simantics.g2d.element.SceneGraphNodeKey;\r
43 import org.simantics.g2d.element.handler.EdgeVisuals;\r
44 import org.simantics.g2d.element.handler.EdgeVisuals.ArrowType;\r
45 import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;\r
46 import org.simantics.g2d.element.handler.Pick;\r
47 import org.simantics.g2d.element.handler.SceneGraph;\r
48 import org.simantics.g2d.element.handler.TerminalLayout;\r
49 import org.simantics.g2d.element.handler.Transform;\r
50 import org.simantics.g2d.element.handler.impl.ConfigurableEdgeVisuals;\r
51 import org.simantics.g2d.element.handler.impl.ConnectionSelectionOutline;\r
52 import org.simantics.g2d.element.handler.impl.FillColorImpl;\r
53 import org.simantics.g2d.element.handler.impl.ParentImpl;\r
54 import org.simantics.g2d.element.handler.impl.SimpleElementLayers;\r
55 import org.simantics.g2d.element.handler.impl.TextColorImpl;\r
56 import org.simantics.g2d.element.handler.impl.TextFontImpl;\r
57 import org.simantics.g2d.element.handler.impl.TextImpl;\r
58 import org.simantics.g2d.elementclass.connection.EdgeClass.EdgeHandler;\r
59 import org.simantics.g2d.elementclass.connection.EdgeClass.FixedTransform;\r
60 import org.simantics.g2d.utils.Alignment;\r
61 import org.simantics.scenegraph.g2d.G2DParentNode;\r
62 import org.simantics.scenegraph.utils.NodeUtil;\r
63 import org.simantics.sysdyn.ui.Activator;\r
64 import org.simantics.sysdyn.ui.editor.routing.DependencyRouter;\r
65 import org.simantics.utils.datastructures.Pair;\r
66 import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
67 \r
68 public class DependencyEdgeClass {\r
69         \r
70         public static final float DEFAULT_STROKE_WIDTH = 0.3f;\r
71 \r
72         private static class NodePick implements Pick {\r
73 \r
74             private static final long serialVersionUID = 1L;\r
75             \r
76             public static NodePick INSTANCE = new NodePick();\r
77 \r
78             @Override\r
79             public boolean pickTest(IElement e, Shape s, PickPolicy policy) {\r
80                 Rectangle2D pickRect = null;\r
81                 if (s instanceof Rectangle2D)\r
82                     pickRect = (Rectangle2D) s;\r
83                 else\r
84                     // FIXME: suboptimal, but works.\r
85                     pickRect = s.getBounds2D();\r
86 \r
87             DependencyNode node = e.getHint(SysdynEdgeSceneGraph.KEY_SG_NODE);\r
88             if(node == null) {\r
89                 return false;\r
90             }\r
91             return Arcs.hitTest(node.getBeginBounds(), node.getEndBounds(), node.getAngle(), pickRect.getCenterX(), pickRect.getCenterY(), 1.7);\r
92             \r
93             }\r
94 \r
95         }\r
96         \r
97     public static final ElementClass CLASS =\r
98         ElementClass.compile(\r
99                 SysdynEdgeSceneGraph.INSTANCE,\r
100                 EdgeHandler.INSTANCE,\r
101                 new ConfigurableEdgeVisuals(\r
102                         ArrowType.None, ArrowType.Fill, \r
103                         new BasicStroke(DEFAULT_STROKE_WIDTH,\r
104                                 BasicStroke.CAP_BUTT,\r
105                                 BasicStroke.JOIN_ROUND,\r
106                                 10.0f, null, 0.0f)\r
107                         , 1.0, 1.0),\r
108                 FillColorImpl.BLACK,\r
109                 FixedTransform.INSTANCE,\r
110                 TextImpl.INSTANCE,\r
111                 TextColorImpl.BLACK,\r
112                 TextFontImpl.DEFAULT,\r
113                 NodePick.INSTANCE,\r
114                 ConnectionSelectionOutline.INSTANCE,\r
115                 SimpleElementLayers.INSTANCE,\r
116                 ParentImpl.INSTANCE\r
117         ).setId("EdgeClass.STRAIGHT");\r
118 \r
119     public static class SysdynEdgeSceneGraph implements SceneGraph {\r
120 \r
121         private static final long serialVersionUID = 2914383071126238996L;\r
122 \r
123         public static final SysdynEdgeSceneGraph INSTANCE = new SysdynEdgeSceneGraph();\r
124 \r
125         public static final Stroke ARROW_STROKE = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);\r
126 \r
127         public static final Key KEY_SG_NODE = new SceneGraphNodeKey(DependencyNode.class, "EDGE_NODE");\r
128         \r
129         @Override\r
130         public void init(IElement e, G2DParentNode parent) {\r
131             DependencyNode node = ElementUtils.getOrCreateNode(e, parent, KEY_SG_NODE, "edge_" + e.hashCode(), DependencyNode.class);\r
132             \r
133             Font font = ElementUtils.getTextFont(e);\r
134             Color color = ElementUtils.getTextColor(e);\r
135             \r
136             HashMap<String, Object> properties = e.getHint(DiagramHints.PROPERTIES);\r
137             Pair<?, ?> polarityPair =  (Pair<?, ?>)properties.get("polarity");\r
138             Pair<?, ?> polarityLocationPair =  (Pair<?, ?>)properties.get("polarityLocation");\r
139             boolean delayMark = properties.containsKey("delayMark");\r
140             boolean arrowHead = !properties.containsKey("hideArrow");\r
141             \r
142             String location;\r
143             if(polarityLocationPair == null)\r
144                 location = DependencyNode.INSIDE;\r
145             else\r
146                 location = (String) polarityLocationPair.second;\r
147 \r
148             String text = polarityPair != null ? (String)  polarityPair.second : "";\r
149             node.init(text, location, delayMark, arrowHead, font, color, 0, 0, 0.235);\r
150             \r
151             update(e);\r
152         }\r
153 \r
154         @Override\r
155         public void cleanup(IElement e) {\r
156             ElementUtils.removePossibleNode(e, KEY_SG_NODE);\r
157         }\r
158         \r
159         public void update(final IElement e) {\r
160                 \r
161             DependencyNode node = e.getHint(KEY_SG_NODE);\r
162             if(node == null) return;\r
163             final IDiagram diagram = ElementUtils.peekDiagram(e);\r
164 \r
165             IElement edgeParent = ElementUtils.getParent(e);\r
166             Object edgeParentObject = edgeParent != null ? edgeParent.getHint(ElementHints.KEY_OBJECT) : null;\r
167             final Resource parentElement = edgeParentObject instanceof Resource ? (Resource) edgeParentObject : null;\r
168 \r
169             node.setFieldListener(new PropertyChangeListener() {\r
170 \r
171                 @Override\r
172                 public void propertyChange(final PropertyChangeEvent event) {\r
173                     if (parentElement == null)\r
174                         return;\r
175 \r
176                     String field = event.getPropertyName();\r
177                     Map<String, Pair<Resource, Object>> properties = e.getHint(DiagramHints.PROPERTIES);\r
178                     if(properties == null) return;\r
179                     final Pair<Resource, Object> property = properties.get(field);\r
180                     if(property == null) return;\r
181 \r
182                     try {\r
183                         Simantics.getSession().syncRequest(new WriteRequest() {\r
184                             @Override\r
185                             public void perform(WriteGraph graph) throws DatabaseException {\r
186                                 graph.claimLiteral((Resource) parentElement, property.first, event.getNewValue());\r
187                             }\r
188                         });\r
189                     } catch (DatabaseException ex) {\r
190                         Activator.getDefault().getLog().log(\r
191                                 new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Failed to synchronize property " + field + ".", ex)\r
192                                 );\r
193                         \r
194                     }\r
195                 }\r
196             });\r
197 \r
198 \r
199 \r
200             Shape beginTerminalShape = null;\r
201             Shape endTerminalShape = null;\r
202             if (diagram != null) {\r
203                 Topology topology = diagram.getDiagramClass().getAtMostOneItemOfClass(Topology.class);\r
204                 if (topology != null) {\r
205                     Connection beginConnection = topology.getConnection(e, EdgeEnd.Begin);\r
206                     Connection endConnection = topology.getConnection(e, EdgeEnd.End);\r
207                     beginTerminalShape = getCanvasTerminalShape(beginConnection);\r
208                     endTerminalShape = getCanvasTerminalShape(endConnection);\r
209                 }\r
210             }\r
211             \r
212             if(beginTerminalShape == null || endTerminalShape == null) return;\r
213             \r
214             EdgeVisuals vh = e.getElementClass().getSingleItem(EdgeVisuals.class);\r
215             Map<String, Pair<Resource, Object>> properties = e.getHint(DiagramHints.PROPERTIES);\r
216             Pair<Resource, Object> strokeWidthPair = properties.get("strokeWidth");\r
217             \r
218             float strokeWidth;\r
219             if(strokeWidthPair == null)\r
220                 strokeWidth = DEFAULT_STROKE_WIDTH;\r
221             else\r
222                 strokeWidth = (Float)strokeWidthPair.second;\r
223 \r
224             vh.setStroke(e, new BasicStroke(strokeWidth,\r
225                                 BasicStroke.CAP_BUTT,\r
226                                 BasicStroke.JOIN_MITER,\r
227                                 10.0f, null, 0.0f));\r
228             Stroke stroke = vh.getStroke(e);\r
229             Font font = ElementUtils.getTextFont(e);\r
230             Color color = ElementUtils.getTextColor(e);\r
231 //            Color fillColor = ElementUtils.getFillColor(e);\r
232             Color borderColor = ElementUtils.getBorderColor(e, Color.BLACK);\r
233 //            String text = ElementUtils.getText(e);\r
234             Alignment hAlign = ElementUtils.getHintOrDefault(e, ElementHints.KEY_HORIZONTAL_ALIGN, Alignment.CENTER);\r
235             node.setBackgroundColor(null);\r
236             node.setBorderColor(borderColor);\r
237             node.setHorizontalAlignment((byte) hAlign.ordinal());\r
238             node.setPadding(0, 0);\r
239             node.setBorderWidth((float) 0);\r
240             node.setEditable(false);\r
241             node.setFont(font);\r
242             \r
243             node.setBeginBounds(beginTerminalShape);\r
244             node.setEndBounds(endTerminalShape);\r
245             node.setStroke(stroke);\r
246             node.setColor(color);\r
247             node.setShapes(DependencyRouter.createArrowShape(node.getShapes(), node.getBeginBounds(), node.getEndBounds(), node.getAngle(), node.getStroke()));\r
248 \r
249             if(properties != null) {\r
250                         for(Map.Entry<String, Pair<Resource, Object>> entry : properties.entrySet()) {\r
251                                 NodeUtil.setPropertyIfSupported(entry.getKey(), entry.getValue().second, node);                         \r
252 //                              node.setProperty(entry.getKey(), entry.getValue().second);\r
253 //                              System.out.println("setProperty " + entry.getKey() + " => " + entry.getValue().second);\r
254                         }\r
255             }\r
256             EdgeHandler eh = e.getElementClass().getAtMostOneItemOfClass(EdgeHandler.class);\r
257             Path2D path = eh.getPath(e);\r
258             if(path == null)\r
259                 path = new Path2D.Double();\r
260             else\r
261                 path.reset();\r
262             path.append(node.getShapes().first, false);\r
263             eh.setPath(e, path);\r
264 \r
265         }\r
266 \r
267         private static Shape getCanvasTerminalShape(Connection connection) {\r
268             if (connection != null && connection.node != null && connection.terminal != null) {\r
269                 TerminalLayout layout = connection.node.getElementClass().getAtMostOneItemOfClass(TerminalLayout.class);\r
270                 if (layout != null) {\r
271                     //return layout.getTerminalShape(connection.node, connection.terminal);\r
272                     Shape shp = layout.getTerminalShape(connection.node, connection.terminal);\r
273                     Transform tr = connection.node.getElementClass().getAtMostOneItemOfClass(Transform.class);\r
274                     if (tr == null)\r
275                         return shp;\r
276 \r
277                     return tr.getTransform(connection.node).createTransformedShape(shp);\r
278                     \r
279                 }\r
280             }\r
281             return null;\r
282         }\r
283 \r
284     }\r
285   \r
286 }\r