1 /*******************************************************************************
2 * Copyright (c) 2007, 2017 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 * Semantum Oy - (#7084) refactoring
12 *******************************************************************************/
13 package org.simantics.modeling.ui.pdf;
15 import java.util.concurrent.Semaphore;
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;
40 import com.lowagie.text.Rectangle;
41 import com.lowagie.text.pdf.FontMapper;
42 import com.lowagie.text.pdf.PdfWriter;
45 * Rasterizes diagram into a PDF document using the com.lowagie.text plug-in.
47 * @author Tuukka Lehtonen
49 public class PDFPainter {
51 public static void render(
52 final IThreadWorkQueue thread,
53 PDFExportPlan exportModel,
55 final PdfWriter writer,
56 final FontMapper mapper,
57 final Rectangle pageSize,
58 final PageDesc pageDesc,
59 final boolean fitDiagramContentsToPageMargins,
61 throws InterruptedException, DatabaseException
63 DatabaseException[] exception = { null };
64 ICanvasSceneGraphProvider[] sgProvider = { null };
66 CanvasContext ctx = new CanvasContext(thread);
67 ctx.getDefaultHintContext().setHint(Hints.KEY_DISABLE_GRAPH_MODIFICATIONS, Boolean.TRUE);
70 final Semaphore done = new Semaphore(0);
71 // IMPORTANT: Load diagram in a different thread than the canvas context thread!
72 ThreadUtils.getBlockingWorkExecutor().execute(() -> {
74 Session s = exportModel.sessionContext.getSession();
76 Pair<Resource, String> modelAndRVI = s.syncRequest( modelAndRVI(node) );
77 Boolean isSymbol = s.syncRequest( isSymbol(node) );
79 ICanvasSceneGraphProvider provider = DiagramNodeUtil.loadSceneGraphProvider(
82 node.getDiagramResource(),
85 sgProvider[0] = provider;
86 ctx.getDefaultHintContext().setHint(Hints.KEY_PAGE_DESC, pageDesc);
88 // System.err.println(NodeUtil.printTreeNodes(ctx.getCanvasNode(), new StringBuilder()).toString());
90 ThreadUtils.asyncExec(thread, () -> {
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);
100 } catch (DatabaseException e) {
103 } catch (Throwable e) {
105 exception[0] = new DatabaseException(e);
112 if (exception[0] != null)
115 if (sgProvider[0] != null)
116 sgProvider[0].dispose();
121 private static Read<Pair<Resource, String>> modelAndRVI(Node node) {
122 return new UniqueRead<Pair<Resource, String>>() {
124 public Pair<Resource, String> perform(ReadGraph graph) throws DatabaseException {
125 return Pair.make( resolveModel(graph, node), resolveRVI(graph, node) );
130 private static Read<Boolean> isSymbol(Node node) {
131 return new UniqueRead<Boolean>() {
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);
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));
146 throw new ValidationException("no model found for composite " + NameUtils.getSafeName(graph, composite));
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;