]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
4ee1d2e92ff79d280745212188d535058928d5d7
[simantics/sysdyn.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2011 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.jfreechart.chart.element;\r
13 \r
14 import java.awt.BasicStroke;\r
15 import java.awt.Shape;\r
16 import java.awt.geom.AffineTransform;\r
17 import java.awt.geom.Path2D;\r
18 import java.awt.geom.QuadCurve2D;\r
19 import java.awt.geom.Rectangle2D;\r
20 \r
21 import org.jfree.chart.JFreeChart;\r
22 import org.simantics.db.ReadGraph;\r
23 import org.simantics.db.Resource;\r
24 import org.simantics.db.WriteGraph;\r
25 import org.simantics.db.common.request.WriteRequest;\r
26 import org.simantics.db.exception.DatabaseException;\r
27 import org.simantics.diagram.adapter.ElementFactory;\r
28 import org.simantics.diagram.adapter.ElementFactoryUtil;\r
29 import org.simantics.diagram.adapter.SyncElementFactory;\r
30 import org.simantics.diagram.elements.ElementPropertySetter;\r
31 import org.simantics.diagram.synchronization.CompositeHintSynchronizer;\r
32 import org.simantics.diagram.synchronization.IHintSynchronizer;\r
33 import org.simantics.diagram.synchronization.ISynchronizationContext;\r
34 import org.simantics.diagram.synchronization.SynchronizationHints;\r
35 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;\r
36 import org.simantics.diagram.synchronization.graph.RemoveElement;\r
37 import org.simantics.diagram.synchronization.graph.TransformSynchronizer;\r
38 import org.simantics.g2d.canvas.ICanvasContext;\r
39 import org.simantics.g2d.diagram.IDiagram;\r
40 import org.simantics.g2d.element.ElementClass;\r
41 import org.simantics.g2d.element.ElementUtils;\r
42 import org.simantics.g2d.element.IElement;\r
43 import org.simantics.g2d.element.handler.LifeCycle;\r
44 import org.simantics.g2d.element.handler.impl.DefaultTransform;\r
45 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;\r
46 import org.simantics.g2d.element.handler.impl.StaticSymbolImageInitializer;\r
47 import org.simantics.g2d.element.handler.impl.StaticSymbolImpl;\r
48 import org.simantics.g2d.image.Image;\r
49 import org.simantics.g2d.image.impl.ShapeImage;\r
50 import org.simantics.jfreechart.chart.IJFreeChart;\r
51 import org.simantics.sysdyn.JFreeChartResource;\r
52 import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
53 import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;\r
54 \r
55 /**\r
56  * Element factory for creating chart elements to diagrams\r
57  * \r
58  * @author Teemu Lempinen\r
59  *\r
60  */\r
61 public class ChartElementFactory extends SyncElementFactory {\r
62 \r
63     private static final String         CLASS_ID            = "Chart";\r
64     public  static final ElementFactory INSTANCE            = new ChartElementFactory();\r
65     public  static final Image          STATIC_IMAGE        = new ShapeImage(getChartShape(), null, new BasicStroke(1f), true);\r
66     public  static final double         SYMBOL_CHART_SIZE   = 10.0;\r
67     public  static final Key            KEY_CHART_COMPONENT = new KeyOf(Resource.class, "CHART_COMPONENT");     \r
68     public  static final Key            KEY_CHART           = new KeyOf(JFreeChart.class, "CHART");       \r
69     \r
70     static Shape getChartShape() {\r
71         \r
72         Path2D path = new Path2D.Double();\r
73         // First create the axis for a chart symbol\r
74         path.moveTo(-SYMBOL_CHART_SIZE, -SYMBOL_CHART_SIZE);\r
75         path.lineTo(-SYMBOL_CHART_SIZE,  SYMBOL_CHART_SIZE);\r
76         path.lineTo( SYMBOL_CHART_SIZE,  SYMBOL_CHART_SIZE);\r
77 \r
78         // Then a curve to the chart\r
79         QuadCurve2D curve = new QuadCurve2D.Double(\r
80                 -SYMBOL_CHART_SIZE + 1,  SYMBOL_CHART_SIZE - 1,\r
81                 SYMBOL_CHART_SIZE - 5,  SYMBOL_CHART_SIZE - 5,\r
82                 SYMBOL_CHART_SIZE - 1, -SYMBOL_CHART_SIZE + 3);\r
83 \r
84         // Connect shapes\r
85         path.append(curve, false);\r
86         return path;\r
87     }\r
88 \r
89     // Hint synchronizer for synchronizing transform and bounds\r
90     private static final IHintSynchronizer HINT_SYNCHRONIZER = new CompositeHintSynchronizer(\r
91             TransformSynchronizer.INSTANCE);\r
92 \r
93     public static ElementClass create(ReadGraph graph, Resource chart) throws DatabaseException {\r
94         return ElementClass.compile(\r
95                 new ChartSceneGraph(),\r
96                 new Initializer(chart),\r
97                 new StaticObjectAdapter(JFreeChartResource.getInstance(graph).ChartElement),\r
98                 DefaultTransform.INSTANCE,\r
99                 StaticSymbolImageInitializer.INSTANCE,\r
100                 new StaticSymbolImpl(STATIC_IMAGE),\r
101                 new ChartBoundsOutline(new Rectangle2D.Double(-20, -20, 60, 40)),\r
102                 new ElementPropertySetter(ChartSceneGraph.KEY_SG_NODE)\r
103                 ).setId(CLASS_ID);\r
104     }\r
105 \r
106     public ElementClass create(ReadGraph graph, ICanvasContext canvas, IDiagram diagram, Resource elementType) throws DatabaseException {\r
107         return create(graph, null);\r
108     }\r
109 \r
110     @Override\r
111     public void load(ReadGraph g, ICanvasContext canvas, final IDiagram diagram, Resource element, final IElement e) throws DatabaseException {\r
112 \r
113         Resource chartResource;\r
114         ElementPropertySetter ps = e.getElementClass().getSingleItem(ElementPropertySetter.class);\r
115         ps.loadProperties(e, element, g);\r
116         \r
117         AffineTransform at = DiagramGraphUtil.getAffineTransform(g, element);\r
118         // Hack for disabling all rotations in chart elements\r
119         double x = at.getTranslateX();\r
120         double y = at.getTranslateY();\r
121         at.setToRotation(0);\r
122         at.setToTranslation(x, y);\r
123         ElementUtils.setTransform(e, at); // Set hint transform without rotations\r
124         ps.overrideProperty(e, "Transform", at); // Set property Transform without rotations\r
125         \r
126         e.setHint(SynchronizationHints.HINT_SYNCHRONIZER, HINT_SYNCHRONIZER);\r
127         \r
128 \r
129         Object o = e.getHint(KEY_CHART_COMPONENT);\r
130         if(o == null || !(o instanceof Resource)) {\r
131             chartResource = g.getPossibleObject(element, JFreeChartResource.getInstance(g).ChartElement_component);\r
132         } else {\r
133             chartResource = (Resource)o;\r
134         }\r
135 \r
136         if(chartResource == null || !g.hasStatement(chartResource))  {\r
137             // Remove element if there is no chart resource for it        \r
138             final ISynchronizationContext syncContext = ElementFactoryUtil.getContextChecked(diagram); \r
139             g.asyncRequest(new WriteRequest() {\r
140                 \r
141                 @Override\r
142                 public void perform(WriteGraph graph) throws DatabaseException {\r
143                     new RemoveElement(syncContext, diagram, e).perform(graph);                    \r
144                 }\r
145             });\r
146             return;\r
147         }\r
148 \r
149         IJFreeChart ichart = g.adapt(chartResource, IJFreeChart.class);\r
150 \r
151         if(ichart != null) {\r
152             JFreeChart chart = ichart.getChart();\r
153             e.setHint(KEY_CHART, chart);\r
154         }\r
155 \r
156     }\r
157 \r
158 \r
159     /**\r
160      * Initializer for setting a chart component for element\r
161      * @author Teemu Lempinen\r
162      *\r
163      */\r
164     static class Initializer implements LifeCycle {\r
165         private static final long serialVersionUID = -5822080013184271204L;\r
166         Object component;\r
167 \r
168         Initializer(Object component) {\r
169             this.component = component;\r
170         }\r
171 \r
172         @Override\r
173         public void onElementCreated(IElement e) {\r
174             if(component != null) e.setHint(KEY_CHART_COMPONENT, component);\r
175         }\r
176 \r
177         @Override\r
178         public void onElementActivated(IDiagram d, IElement e) {}\r
179         @Override\r
180         public void onElementDeactivated(IDiagram d, IElement e) {}\r
181         @Override\r
182         public void onElementDestroyed(IElement e) {}\r
183     };\r
184 }\r