]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/elementclass/connection/EdgeClass.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / elementclass / connection / EdgeClass.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in 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.g2d.elementclass.connection;\r
13 \r
14 import java.awt.Shape;\r
15 import java.awt.geom.AffineTransform;\r
16 import java.awt.geom.Path2D;\r
17 import java.awt.geom.Point2D;\r
18 import java.awt.geom.Rectangle2D;\r
19 import java.util.ArrayList;\r
20 import java.util.List;\r
21 \r
22 import org.simantics.g2d.diagram.IDiagram;\r
23 import org.simantics.g2d.element.ElementClass;\r
24 import org.simantics.g2d.element.ElementHints;\r
25 import org.simantics.g2d.element.IElement;\r
26 import org.simantics.g2d.element.handler.BendsHandler;\r
27 import org.simantics.g2d.element.handler.InternalSize;\r
28 import org.simantics.g2d.element.handler.LifeCycle;\r
29 import org.simantics.g2d.element.handler.Move;\r
30 import org.simantics.g2d.element.handler.Outline;\r
31 import org.simantics.g2d.element.handler.Parent;\r
32 import org.simantics.g2d.element.handler.Transform;\r
33 import org.simantics.g2d.element.handler.impl.ConfigurableEdgeVisuals;\r
34 import org.simantics.g2d.element.handler.impl.ConnectionSelectionOutline;\r
35 import org.simantics.g2d.element.handler.impl.FillColorImpl;\r
36 import org.simantics.g2d.element.handler.impl.ParentImpl;\r
37 import org.simantics.g2d.element.handler.impl.ShapePick;\r
38 import org.simantics.g2d.element.handler.impl.SimpleElementLayers;\r
39 import org.simantics.g2d.elementclass.PlainElementPropertySetter;\r
40 import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
41 import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;\r
42 \r
43 /**\r
44  * @author Toni Kalajainen\r
45  */\r
46 public class EdgeClass {\r
47 \r
48     /**\r
49      * A {@link Transform} and {@link Move} implementation suitable for edges\r
50      * which are connected to nodes and cannot be moved by themselves.\r
51      * \r
52      * <p>\r
53      * The {@link Transform} implementation is a simple one with support for a\r
54      * parent element through {@link ElementHints#KEY_PARENT_ELEMENT}. The\r
55      * {@link Move} implementation in turn is a stub which does nothing to make\r
56      * edges immovable.\r
57      * \r
58      * <p>\r
59      * FIXME: The more correct solution would be not to have a {@link Move}\r
60      * handler at all but much the current participant code is very highly\r
61      * dependent on having a single {@link Move} handler available that this\r
62      * workaround seems better at this point.\r
63      * \r
64      * @author Tuukka Lehtonen\r
65      */\r
66     public static class FixedTransform implements Transform, Move {\r
67 \r
68         private static final long serialVersionUID = 2287402413442694915L;\r
69 \r
70         public static final FixedTransform INSTANCE = new FixedTransform();\r
71         public static final AffineTransform IDENTITY = new AffineTransform();\r
72 \r
73         @Override\r
74         public AffineTransform getTransform(IElement e) {\r
75             AffineTransform local = e.getHint(ElementHints.KEY_TRANSFORM);\r
76             if (local == null)\r
77                 local = IDENTITY;\r
78 \r
79             Parent p = e.getElementClass().getAtMostOneItemOfClass(Parent.class);\r
80             if (p == null)\r
81                 return local;\r
82 \r
83             IElement parentElement = p.getParent(e);\r
84             if (parentElement == null)\r
85                 return local;\r
86 \r
87             AffineTransform parentTransform = parentElement.getElementClass().getSingleItem(Transform.class).getTransform(parentElement);\r
88             if (parentTransform.isIdentity())\r
89                 return local;\r
90 \r
91             AffineTransform result = new AffineTransform(local);\r
92             result.preConcatenate(parentTransform);\r
93             return result;\r
94         }\r
95 \r
96         @Override\r
97         public void setTransform(IElement e, AffineTransform at) {\r
98             assert at != null;\r
99             e.setHint(ElementHints.KEY_TRANSFORM, at);\r
100         }\r
101 \r
102         @Override\r
103         public Point2D getPosition(IElement e) {\r
104             AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM);\r
105             if (at == null)\r
106                 return new Point2D.Double();\r
107             return new Point2D.Double(at.getTranslateX(), at.getTranslateY());\r
108         }\r
109 \r
110         @Override\r
111         public void moveTo(IElement e, double x, double y) {\r
112             // Don't allow moving.\r
113         }\r
114     }\r
115 \r
116     // TODO scale, rotate, move, transform\r
117     public static final ElementClass STRAIGHT =\r
118         ElementClass.compile(\r
119                 EdgeSceneGraph.INSTANCE,\r
120                 EdgeHandler.INSTANCE,\r
121                 ConfigurableEdgeVisuals.DEFAULT,\r
122                 FillColorImpl.RED,\r
123                 FixedTransform.INSTANCE,\r
124                 ShapePick.INSTANCE,\r
125                 ConnectionSelectionOutline.INSTANCE,\r
126                 SimpleElementLayers.INSTANCE,\r
127                 ParentImpl.INSTANCE,\r
128                 new PlainElementPropertySetter(EdgeSceneGraph.KEY_SG_NODE)\r
129         ).setId("EdgeClass.STRAIGHT");\r
130 \r
131 \r
132     public static class EdgeHandler implements BendsHandler, Outline, LifeCycle, InternalSize {\r
133 \r
134         private static final long serialVersionUID = -5949432471958957382L;\r
135 \r
136         public static final EdgeHandler INSTANCE = new EdgeHandler();\r
137 \r
138         public static final Key KEY_PATH = new KeyOf(Path2D.class, "PATH");\r
139         public static final Key KEY_BOUNDS = new KeyOf(Rectangle2D.class, "BOUNDS");\r
140         public static final Key KEY_ANGLETYPE = new KeyOf(AngleType.class);\r
141         public static final Key KEY_BENDS = new KeyOf(ArrayList.class, "BENDS");\r
142 \r
143         public static class BendImpl implements Bend {\r
144             Point2D pos;\r
145         }\r
146 \r
147         /**\r
148          * Reads bends, builds path, and writes it to KEY_PATH\r
149          * @param e\r
150          */\r
151         /*\r
152                 private void buildPath(IElement e)\r
153                 {\r
154                         ArrayList<Point2D> points = new ArrayList<Point2D>();\r
155                         ElementUtils.getBends(e, points);\r
156                         Path2D path = GeometryUtils.buildPath(points);\r
157                         e.setHint(KEY_PATH, path);\r
158                         e.setHint(KEY_BOUNDS, path.getBounds2D());\r
159                 }*/\r
160 \r
161         @Override\r
162         public void setAngleType(IElement e, AngleType angleType) {\r
163             e.setHint(KEY_ANGLETYPE, angleType);\r
164         }\r
165 \r
166         @Override\r
167         public AngleType getAngleType(IElement e) {\r
168             return e.getHint(KEY_ANGLETYPE);\r
169         }\r
170 \r
171         @Override\r
172         public Shape getElementShape(IElement e) {\r
173             // Path2DOutlineShape no longer needed with ConnectionSelectionOutline\r
174             // that uses Stroke.createStrokedShape.\r
175             //return new Path2DOutlineShape((Path2D)e.getHint(KEY_PATH));\r
176             return e.getHint(KEY_PATH);\r
177         }\r
178 /*\r
179                 @Override\r
180                 public AffineTransform getTransform(IElement e) {\r
181                         AffineTransform at = GeometryUtils.IDENTITY;\r
182                         assert(at.isIdentity());\r
183                         return at;\r
184                 }\r
185 \r
186                 @Override\r
187                 public void setTransform(IElement e, AffineTransform at) {\r
188                         Path2D path = e.getHint(KEY_PATH);\r
189                         if (path==null) return;\r
190                         ArrayList<BendImpl> list = e.getHint(KEY_BENDS);\r
191                         for (BendImpl bi : list)\r
192                                 at.transform(bi.pos, bi.pos);\r
193                         buildPath(e);\r
194                 }\r
195 \r
196                 @Override\r
197                 public Point2D getPosition(IElement e) {\r
198                         return new Point2D.Double(0, 0);\r
199                 }\r
200 \r
201                 @Override\r
202                 public void moveTo(IElement e, double x, double y) {\r
203                         AffineTransform at = new AffineTransform();\r
204                         at.setToTranslation(x, y);\r
205                         setTransform(e, at);\r
206                 }\r
207 \r
208                 @Override\r
209                 public double getAngle(IElement e, ICanvasContext ctx) {\r
210                         return 0;\r
211                 }\r
212 \r
213                 @Override\r
214                 public void rotate(IElement e, ICanvasContext ctx, double theta, Point2D origo) {\r
215                         AffineTransform at = new AffineTransform();\r
216                         at.setToRotation(theta, origo.getX(), origo.getY());\r
217                         setTransform(e, at);\r
218                 }\r
219 \r
220                 @Override\r
221                 public Double getFixedAspectRatio(IElement e) {\r
222                         return null;\r
223                 }\r
224 \r
225                 @Override\r
226                 public Point2D getMaximumScale(IElement e) {\r
227                         return null;\r
228                 }\r
229 \r
230                 @Override\r
231                 public Point2D getMinimumScale(IElement e) {\r
232                         return null;\r
233                 }\r
234 \r
235                 @Override\r
236                 public Point2D getScale(IElement e) {\r
237                         return new Point2D.Double(1, 1);\r
238                 }\r
239 \r
240                 @Override\r
241                 public void setScale(IElement e, Point2D newScale) {\r
242                         AffineTransform at = new AffineTransform();\r
243                         at.setToScale(newScale.getX(), newScale.getY());\r
244                         setTransform(e, at);\r
245                 }\r
246  */\r
247         @Override\r
248         public void onElementActivated(IDiagram d, IElement e) {\r
249             update(e);\r
250         }\r
251 \r
252         @Override\r
253         public void onElementCreated(IElement e) {\r
254             e.setHint(KEY_PATH, new Path2D.Double(Path2D.WIND_NON_ZERO, 2));\r
255             e.setHint(KEY_ANGLETYPE, AngleType.RightAngled);\r
256             e.setHint(KEY_BOUNDS, new Rectangle2D.Double());\r
257             e.setHint(KEY_BENDS, new ArrayList<BendImpl>(2));\r
258         }\r
259         @Override\r
260         public void onElementDestroyed(IElement e) {\r
261 //                      EdgeSGNode sg = e.getElementClass().getAtMostOneItemOfClass(EdgeSGNode.class);\r
262 //                      if(sg != null)\r
263 //                              sg.cleanup(e);\r
264         }\r
265 \r
266         private void update(IElement e) {\r
267             EdgeSceneGraph sg = e.getElementClass().getAtMostOneItemOfClass(EdgeSceneGraph.class);\r
268             if(sg != null)\r
269                 sg.update(e);\r
270         }\r
271 \r
272         @Override\r
273         public void onElementDeactivated(IDiagram d, IElement e) {\r
274         }\r
275 \r
276         @Override\r
277         public Rectangle2D getBounds(IElement e, Rectangle2D size) {\r
278             Rectangle2D rect = e.getHint(KEY_BOUNDS);\r
279             if (size==null) size = new Rectangle2D.Double();\r
280             if (rect != null)\r
281                 size.setFrame(rect);\r
282             return rect;\r
283         }\r
284 \r
285         @Override\r
286         public Bend addBend(IElement e, int index, Point2D pos) {\r
287             ArrayList<BendImpl> list = e.getHint(KEY_BENDS);\r
288             BendImpl b = new BendImpl();\r
289             b.pos = new Point2D.Double(pos.getX(), pos.getY());\r
290             list.add(index, b);\r
291 //                      buildPath(e);\r
292             update(e);\r
293             return b;\r
294         }\r
295 \r
296         @Override\r
297         public void getBendPosition(IElement e, Bend b, Point2D pos) {\r
298             pos.setLocation( ((BendImpl)b).pos );\r
299         }\r
300 \r
301         @Override\r
302         public int getBendsCount(IElement e) {\r
303             ArrayList<BendImpl> list = e.getHint(KEY_BENDS);\r
304             return list.size();\r
305         }\r
306 \r
307         @Override\r
308         public void getBends(IElement e, List<Bend> bends) {\r
309             ArrayList<BendImpl> list = e.getHint(KEY_BENDS);\r
310             bends.addAll(list);\r
311         }\r
312 \r
313         @Override\r
314         public boolean removeBend(IElement e, Bend b) {\r
315             ArrayList<BendImpl> list = e.getHint(KEY_BENDS);\r
316             if (!list.remove(b)) return false;\r
317 //                      buildPath(e);\r
318             return true;\r
319         }\r
320 \r
321         @Override\r
322         public Path2D getPath(IElement e) {\r
323             return e.getHint(KEY_PATH);\r
324         }\r
325 \r
326         @Override\r
327         public void setPath(IElement e, Path2D path) {\r
328             e.setHint(KEY_PATH, path);\r
329             e.setHint(KEY_BOUNDS, path.getBounds2D());\r
330             /*\r
331                         ArrayList<BendImpl> list = e.getHint(KEY_BENDS);\r
332                         ArrayList<Point2D> positions = new ArrayList<Point2D>();\r
333                         GeometryUtils.getPoints(path, positions);\r
334                         list.clear();\r
335                         for (Point2D p : positions) {\r
336                                 BendImpl bi = new BendImpl();\r
337                                 bi.pos = p;\r
338                                 list.add(bi);\r
339                         }*/\r
340             update(e);\r
341         }\r
342 \r
343         @Override\r
344         public void moveBend(IElement e, Bend b, Point2D pos) {\r
345             BendImpl bi = ((BendImpl)b);\r
346             if (bi.pos.equals(pos)) return;\r
347             bi.pos.setLocation(pos);\r
348 //                      buildPath(e);\r
349             update(e);\r
350         }\r
351     }\r
352 \r
353     public static class ControlPointKey extends Key {\r
354         public final int index;\r
355         final int hash;\r
356         public ControlPointKey(int index)\r
357         {\r
358             super();\r
359             this.index = index;\r
360             hash = getClass().hashCode() ^ index ^ 54392439;\r
361         }\r
362         @Override\r
363         public boolean isValueAccepted(Object value) {\r
364             return IElement.class.isInstance(value);\r
365         }\r
366         @Override\r
367         public int hashCode() {\r
368             return hash;\r
369         }\r
370         @Override\r
371         public boolean equals(Object obj) {\r
372             if (obj == null)\r
373                 return false;\r
374             if (getClass() != obj.getClass())\r
375                 return false;\r
376             ControlPointKey other = (ControlPointKey) obj;\r
377             return other.index == index;\r
378         }\r
379     }\r
380 \r
381 }\r