1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
\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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.jfreechart.chart.element;
\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
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
56 * Element factory for creating chart elements to diagrams
\r
58 * @author Teemu Lempinen
\r
61 public class ChartElementFactory extends SyncElementFactory {
\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
70 static Shape getChartShape() {
\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
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
85 path.append(curve, false);
\r
89 // Hint synchronizer for synchronizing transform and bounds
\r
90 private static final IHintSynchronizer HINT_SYNCHRONIZER = new CompositeHintSynchronizer(
\r
91 TransformSynchronizer.INSTANCE);
\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
106 public ElementClass create(ReadGraph graph, ICanvasContext canvas, IDiagram diagram, Resource elementType) throws DatabaseException {
\r
107 return create(graph, null);
\r
111 public void load(ReadGraph g, ICanvasContext canvas, final IDiagram diagram, Resource element, final IElement e) throws DatabaseException {
\r
113 Resource chartResource;
\r
114 ElementPropertySetter ps = e.getElementClass().getSingleItem(ElementPropertySetter.class);
\r
115 ps.loadProperties(e, element, g);
\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
126 e.setHint(SynchronizationHints.HINT_SYNCHRONIZER, HINT_SYNCHRONIZER);
\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
133 chartResource = (Resource)o;
\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
142 public void perform(WriteGraph graph) throws DatabaseException {
\r
143 new RemoveElement(syncContext, diagram, e).perform(graph);
\r
149 IJFreeChart ichart = g.adapt(chartResource, IJFreeChart.class);
\r
151 if(ichart != null) {
\r
152 JFreeChart chart = ichart.getChart();
\r
153 e.setHint(KEY_CHART, chart);
\r
160 * Initializer for setting a chart component for element
\r
161 * @author Teemu Lempinen
\r
164 static class Initializer implements LifeCycle {
\r
165 private static final long serialVersionUID = -5822080013184271204L;
\r
168 Initializer(Object component) {
\r
169 this.component = component;
\r
173 public void onElementCreated(IElement e) {
\r
174 if(component != null) e.setHint(KEY_CHART_COMPONENT, component);
\r
178 public void onElementActivated(IDiagram d, IElement e) {}
\r
180 public void onElementDeactivated(IDiagram d, IElement e) {}
\r
182 public void onElementDestroyed(IElement e) {}
\r