]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/SVGElementClassFactory.java
Support for dynamic transforms for both elements and terminals
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / adapter / SVGElementClassFactory.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.diagram.adapter;
13
14 import java.awt.Point;
15 import java.awt.geom.Rectangle2D;
16
17 import org.simantics.Simantics;
18 import org.simantics.databoard.Bindings;
19 import org.simantics.db.AsyncReadGraph;
20 import org.simantics.db.ReadGraph;
21 import org.simantics.db.Resource;
22 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
23 import org.simantics.db.common.procedure.guarded.GuardedAsyncProcedureWrapper;
24 import org.simantics.db.common.request.ReadRequest;
25 import org.simantics.db.common.request.UnaryAsyncRead;
26 import org.simantics.db.common.utils.NameUtils;
27 import org.simantics.db.exception.DatabaseException;
28 import org.simantics.db.procedure.AsyncProcedure;
29 import org.simantics.diagram.stubs.G2DResource;
30 import org.simantics.diagram.synchronization.SynchronizationHints;
31 import org.simantics.diagram.synchronization.graph.TransformSynchronizer;
32 import org.simantics.g2d.canvas.ICanvasContext;
33 import org.simantics.g2d.diagram.DiagramHints;
34 import org.simantics.g2d.diagram.IDiagram;
35 import org.simantics.g2d.element.ElementClass;
36 import org.simantics.g2d.element.ElementHints;
37 import org.simantics.g2d.element.IElement;
38 import org.simantics.g2d.element.handler.impl.DefaultTransform;
39 import org.simantics.g2d.element.handler.impl.SimpleElementLayers;
40 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;
41 import org.simantics.g2d.element.handler.impl.StaticSymbolImageInitializer;
42 import org.simantics.g2d.element.handler.impl.StaticSymbolImpl;
43 import org.simantics.g2d.element.handler.impl.TextImpl;
44 import org.simantics.g2d.elementclass.ImageClass.ImageElementHandler;
45 import org.simantics.g2d.image.DefaultImages;
46 import org.simantics.g2d.image.Image;
47 import org.simantics.g2d.image.ProviderUtils;
48 import org.simantics.g2d.svg.SVGImage;
49 import org.simantics.scenegraph.g2d.nodes.SVGNode;
50 import org.simantics.utils.Development;
51 import org.simantics.utils.datastructures.cache.IFactory;
52 import org.simantics.utils.datastructures.cache.ProvisionException;
53 import org.simantics.utils.ui.ErrorLogger;
54
55 /**
56  * An {@link ElementFactory} for DIA.SVGElement instances.
57  * 
58  * <p>
59  * Loads element layers, transform and SVG document.
60  * 
61  * @author Tuukka Lehtonen
62  */
63 public class SVGElementClassFactory extends ElementFactoryAdapter {
64
65     public static final ElementFactory INSTANCE = new SVGElementClassFactory();
66
67     private static final StaticSymbolImpl STATIC_SYMBOL = new StaticSymbolImpl(DefaultImages.SVG.get());
68
69     static class ClassRequest extends UnaryAsyncRead<Resource, ElementClass> {
70
71         public ClassRequest(Resource elementType) {
72             super(elementType);
73         }
74
75         @Override
76         public void perform(AsyncReadGraph graph, AsyncProcedure<ElementClass> procedure) {
77             createClass(graph, parameter, procedure);
78         }
79
80     }
81
82     @Override
83     public void create(AsyncReadGraph graph, ICanvasContext canvas, IDiagram diagram,
84             final Resource elementType, final AsyncProcedure<ElementClass> procedure) {
85
86         graph.asyncRequest(new ClassRequest(elementType), new TransientCacheAsyncListener<ElementClass>() {
87
88             @Override
89             public void exception(AsyncReadGraph graph, Throwable t) {
90                 procedure.exception(graph, t);
91             }
92
93             @Override
94             public void execute(AsyncReadGraph graph, ElementClass result) {
95                 procedure.execute(graph, result);
96             }
97
98         });
99
100     }
101
102     static void createClass(AsyncReadGraph graph, final Resource elementType, final AsyncProcedure<ElementClass> procedure) {
103         String id = "SVGElement: " + elementType.getResourceId();
104         procedure.execute(graph, ElementClass.compile(
105                 TextImpl.INSTANCE,
106                 new StaticObjectAdapter(elementType),
107                 DefaultTransform.INSTANCE,
108                 StaticSymbolImageInitializer.INSTANCE,
109                 STATIC_SYMBOL,
110                 ImageElementHandler.INSTANCE,
111                 SimpleElementLayers.INSTANCE)
112                 .setId(id));
113     }
114
115     @Override
116     public void load(AsyncReadGraph graph, final ICanvasContext canvas, final IDiagram diagram, final Resource element, final IElement e, final AsyncProcedure<IElement> procedure) {
117         e.setHint(SynchronizationHints.HINT_SYNCHRONIZER, TransformSynchronizer.INSTANCE);
118
119         final GuardedAsyncProcedureWrapper<IElement> guard = new GuardedAsyncProcedureWrapper<IElement>(procedure, 3);
120
121         loadSVG(graph, diagram, element, e, guard);
122         ElementFactoryUtil.loadLayersForElement(graph, diagram, e, element, guard);
123         ElementFactoryUtil.readTransform(graph, element, e, guard);
124     }
125
126     private void loadSVG(AsyncReadGraph graph, final IDiagram diagram, final Resource element, final IElement e, final AsyncProcedure<IElement> guard) {
127         G2DResource G2D = graph.getService(G2DResource.class);
128
129         graph.forPossibleRelatedValue(element, G2D.HasSVGDocument, Bindings.STRING, new AsyncProcedure<String>() {
130             @Override
131             public void exception(AsyncReadGraph graph, Throwable throwable) {
132                 guard.exception(graph, throwable);
133             }
134
135             @Override
136             public void execute(AsyncReadGraph graph, final String svgDocument) {
137                 if (svgDocument != null) {
138
139                     if(Development.DEVELOPMENT) {
140                         Rectangle2D bounds = SVGNode.getRealBounds(svgDocument);
141                         if(bounds != null && bounds.isEmpty()) {
142                             Simantics.async(new ReadRequest() {
143                                 @Override 
144                                 public void run(ReadGraph graph) throws DatabaseException {
145                                     System.err.println("Graphics for element " + NameUtils.getSafeName(graph, element) + " are empty.");
146                                 }
147                             });
148                         }
149                     }
150
151                     Point referenceSize = diagram.getHint(DiagramHints.KEY_ELEMENT_RASTER_TARGET_SIZE);
152                     IFactory<Image> img = SVGImage.createFactoryFromString(String.valueOf(element.getResourceId()), svgDocument, referenceSize);
153                     try {
154                         img = ProviderUtils.rasterize(img);
155                         e.setHint(ElementHints.KEY_IMAGE, img.get());
156                         guard.execute(graph, e);
157                     } catch (ProvisionException ex) {
158                         ErrorLogger.defaultLogError(ex);
159                         e.setHint(ElementHints.KEY_IMAGE, DefaultImages.SVG.get());
160                         guard.execute(graph, e);
161                     }
162                 } else {
163                     e.setHint(ElementHints.KEY_IMAGE, DefaultImages.UNKNOWN.get());
164                     guard.execute(graph, e);
165                 }
166             }
167         });
168     }
169
170 }