]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFPainter.java
Listen to changes in page settings in DiagramSceneGraphProvider
[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                             boolean fitToContent = fitDiagramContentsToPageMargins || isSymbol;
93                             if (!fitToContent) {
94                                 // Prevent PDF printing from drawing page borders if the
95                                 // print area is fitted directly to the page size.
96                                 // This avoids unwanted black half-visible edges.
97                                 ctx.getDefaultHintContext().setHint(Hints.KEY_DISPLAY_PAGE, false);
98                             }
99
100                             PDFBuilder chassis = new PDFBuilder(writer, mapper, pageSize, pageDesc, fitToContent);
101                             chassis.paint(ctx, true);
102                         } catch (Throwable e) {
103                             exception[0] = new DatabaseException(e);
104                         } finally {
105                             done.release();
106                         }
107                     });
108                 } catch (DatabaseException e) {
109                     done.release();
110                     exception[0] = e;
111                 } catch (Throwable e) {
112                     done.release();
113                     exception[0] = new DatabaseException(e);
114                 } finally {
115                     done.release();
116                 }
117             });
118
119             done.acquire(2);
120             if (exception[0] != null)
121                 throw exception[0];
122         } finally {
123             if (sgProvider[0] != null)
124                 sgProvider[0].dispose();
125             ctx.dispose();
126         }
127     }
128
129     private static Read<Pair<Resource, String>> modelAndRVI(Node node) {
130         return new UniqueRead<Pair<Resource, String>>() {
131             @Override
132             public Pair<Resource, String> perform(ReadGraph graph) throws DatabaseException {
133                 return Pair.make( resolveModel(graph, node), resolveRVI(graph, node) );
134             }
135         };
136     }
137
138     private static Read<Boolean> isSymbol(Node node) {
139         return new UniqueRead<Boolean>() {
140             @Override
141             public Boolean perform(ReadGraph graph) throws DatabaseException {
142                 StructuralResource2 STR = StructuralResource2.getInstance(graph);
143                 DiagramResource DIA = DiagramResource.getInstance(graph);
144                 Resource possibleSymbol = graph.getPossibleObject(node.getDiagramResource(), STR.Defines);
145                 return possibleSymbol != null && graph.isInstanceOf(possibleSymbol, DIA.ElementClass);
146             }
147         };
148     }
149
150     private static Resource resolveModel(ReadGraph graph, Node node) throws DatabaseException {
151         Resource composite = node.getDefiningResources().head();
152         Resource model = graph.syncRequest(new PossibleIndexRoot(composite));
153         if (model == null)
154             throw new ValidationException("no model found for composite " + NameUtils.getSafeName(graph, composite));
155         return model;
156     }
157
158     private static String resolveRVI(ReadGraph graph, final Node node) throws DatabaseException {
159         String RVI = node.getRVI();
160         if (RVI != null) return RVI;
161         Resource composite = node.getDefiningResources().head();
162         Variable var = Variables.getVariable(graph, composite);
163         org.simantics.db.layer0.variable.RVI rvi = var.getPossibleRVI(graph);
164         return rvi != null ? rvi.toString() : null;
165     }
166
167 }