]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFPainter.java
Improved Copy Visible Data usability in time series chart editor
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / pdf / PDFPainter.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2017 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  *     Semantum Oy - (#7084) refactoring
12  *******************************************************************************/
13 package org.simantics.modeling.ui.pdf;
14
15 import java.util.concurrent.Semaphore;
16
17 import org.simantics.db.ReadGraph;
18 import org.simantics.db.Resource;
19 import org.simantics.db.Session;
20 import org.simantics.db.common.request.PossibleIndexRoot;
21 import org.simantics.db.common.request.UniqueRead;
22 import org.simantics.db.common.utils.NameUtils;
23 import org.simantics.db.exception.DatabaseException;
24 import org.simantics.db.exception.ValidationException;
25 import org.simantics.db.layer0.variable.Variable;
26 import org.simantics.db.layer0.variable.Variables;
27 import org.simantics.db.request.Read;
28 import org.simantics.diagram.elements.DiagramNodeUtil;
29 import org.simantics.diagram.stubs.DiagramResource;
30 import org.simantics.g2d.canvas.Hints;
31 import org.simantics.g2d.canvas.impl.CanvasContext;
32 import org.simantics.g2d.scenegraph.ICanvasSceneGraphProvider;
33 import org.simantics.modeling.requests.Node;
34 import org.simantics.structural.stubs.StructuralResource2;
35 import org.simantics.utils.datastructures.Pair;
36 import org.simantics.utils.page.PageDesc;
37 import org.simantics.utils.threads.IThreadWorkQueue;
38 import org.simantics.utils.threads.ThreadUtils;
39
40 import com.lowagie.text.Rectangle;
41 import com.lowagie.text.pdf.FontMapper;
42 import com.lowagie.text.pdf.PdfWriter;
43
44 /**
45  * Rasterizes diagram into a PDF document using the com.lowagie.text plug-in.
46  * 
47  * @author Tuukka Lehtonen
48  */
49 public class PDFPainter {
50
51     public static void render(
52             final IThreadWorkQueue thread,
53             PDFExportPlan exportModel,
54             final Node node,
55             final PdfWriter writer,
56             final FontMapper mapper,
57             final Rectangle pageSize,
58             final PageDesc pageDesc,
59             final boolean fitDiagramContentsToPageMargins,
60             long timeout)
61                     throws InterruptedException, DatabaseException
62     {
63         DatabaseException[] exception = { null };
64         ICanvasSceneGraphProvider[] sgProvider = { null };
65
66         CanvasContext ctx = new CanvasContext(thread);
67         ctx.getDefaultHintContext().setHint(Hints.KEY_DISABLE_GRAPH_MODIFICATIONS, Boolean.TRUE);
68
69         try {
70             final Semaphore done = new Semaphore(0);
71             // IMPORTANT: Load diagram in a different thread than the canvas context thread!
72             ThreadUtils.getBlockingWorkExecutor().execute(() -> {
73                 try {
74                     Session s = exportModel.sessionContext.getSession();
75
76                     Pair<Resource, String> modelAndRVI = s.syncRequest( modelAndRVI(node) );
77                     Boolean isSymbol = s.syncRequest( isSymbol(node) ); 
78
79                     ICanvasSceneGraphProvider provider = DiagramNodeUtil.loadSceneGraphProvider(
80                             ctx,
81                             modelAndRVI.first,
82                             node.getDiagramResource(),
83                             modelAndRVI.second,
84                             5000);
85                     sgProvider[0] = provider;
86                     ctx.getDefaultHintContext().setHint(Hints.KEY_PAGE_DESC, pageDesc);
87
88 //                    System.err.println(NodeUtil.printTreeNodes(ctx.getCanvasNode(), new StringBuilder()).toString());
89
90                     ThreadUtils.asyncExec(thread, () -> {
91                         try {
92                             PDFBuilder chassis = new PDFBuilder(writer, mapper, pageSize, pageDesc, fitDiagramContentsToPageMargins || isSymbol);
93                             chassis.paint(ctx, true);
94                         } catch (Throwable e) {
95                             exception[0] = new DatabaseException(e);
96                         } finally {
97                             done.release();
98                         }
99                     });
100                 } catch (DatabaseException e) {
101                     done.release();
102                     exception[0] = e;
103                 } catch (Throwable e) {
104                     done.release();
105                     exception[0] = new DatabaseException(e);
106                 } finally {
107                     done.release();
108                 }
109             });
110
111             done.acquire(2);
112             if (exception[0] != null)
113                 throw exception[0];
114         } finally {
115             if (sgProvider[0] != null)
116                 sgProvider[0].dispose();
117             ctx.dispose();
118         }
119     }
120
121     private static Read<Pair<Resource, String>> modelAndRVI(Node node) {
122         return new UniqueRead<Pair<Resource, String>>() {
123             @Override
124             public Pair<Resource, String> perform(ReadGraph graph) throws DatabaseException {
125                 return Pair.make( resolveModel(graph, node), resolveRVI(graph, node) );
126             }
127         };
128     }
129
130     private static Read<Boolean> isSymbol(Node node) {
131         return new UniqueRead<Boolean>() {
132             @Override
133             public Boolean perform(ReadGraph graph) throws DatabaseException {
134                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
135                 DiagramResource DIA = DiagramResource.getInstance(graph);
136                 Resource possibleSymbol = graph.getPossibleObject(node.getDiagramResource(), STR.Defines);
137                 return possibleSymbol != null && graph.isInstanceOf(possibleSymbol, DIA.ElementClass);
138             }
139         };
140     }
141
142     private static Resource resolveModel(ReadGraph graph, Node node) throws DatabaseException {
143         Resource composite = node.getDefiningResources().head();
144         Resource model = graph.syncRequest(new PossibleIndexRoot(composite));
145         if (model == null)
146             throw new ValidationException("no model found for composite " + NameUtils.getSafeName(graph, composite));
147         return model;
148     }
149
150     private static String resolveRVI(ReadGraph graph, final Node node) throws DatabaseException {
151         String RVI = node.getRVI();
152         if (RVI != null) return RVI;
153         Resource composite = node.getDefiningResources().head();
154         Variable var = Variables.getVariable(graph, composite);
155         org.simantics.db.layer0.variable.RVI rvi = var.getPossibleRVI(graph);
156         return rvi != null ? rvi.toString() : null;
157     }
158
159 }