/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.modeling.ui.pdf; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicReference; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.request.PossibleIndexRoot; import org.simantics.db.common.request.UniqueRead; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.ValidationException; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; import org.simantics.db.management.ISessionContext; import org.simantics.diagram.elements.DiagramNodeUtil; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.g2d.canvas.Hints; import org.simantics.g2d.canvas.impl.CanvasContext; import org.simantics.g2d.scenegraph.ICanvasSceneGraphProvider; import org.simantics.modeling.requests.Node; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.utils.DataContainer; import org.simantics.utils.datastructures.Pair; import org.simantics.utils.page.PageDesc; import org.simantics.utils.threads.IThreadWorkQueue; import org.simantics.utils.threads.ThreadUtils; import com.lowagie.text.Rectangle; import com.lowagie.text.pdf.FontMapper; import com.lowagie.text.pdf.PdfWriter; /** * Rasterizes diagram into a PDF document using the com.lowagie.text plug-in. * * @author Tuukka Lehtonen */ public class PDFPainter { public static boolean render( final IThreadWorkQueue thread, final ISessionContext sessionContext, PDFExportPlan exportModel, final Node node, final PdfWriter writer, final FontMapper mapper, final Rectangle pageSize, final PageDesc pageDesc, final boolean fitDiagramContentsToPageMargins, long timeout) throws InterruptedException, DatabaseException { final DataContainer result = new DataContainer(false); final DataContainer exception = new DataContainer(); final CanvasContext ctx = new CanvasContext(thread); final AtomicReference sgProvider = new AtomicReference(); try { final Semaphore done = new Semaphore(0); // IMPORTANT: Load diagram in a different thread than the canvas context thread! ThreadUtils.getBlockingWorkExecutor().execute(new Runnable() { @Override public void run() { try { Pair modelAndRVI = sessionContext.getSession().syncRequest(new UniqueRead>() { @Override public Pair perform(ReadGraph graph) throws DatabaseException { return new Pair( resolveModel(graph, node), resolveRVI(graph, node) ); } }); final Boolean isSymbol = sessionContext.getSession().syncRequest(new UniqueRead() { @Override public Boolean perform(ReadGraph graph) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(graph); DiagramResource DIA = DiagramResource.getInstance(graph); Resource possibleSymbol = graph.getPossibleObject(node.getDiagramResource(), STR.Defines); return possibleSymbol != null && graph.isInstanceOf(possibleSymbol, DIA.ElementClass); } }); ICanvasSceneGraphProvider provider = DiagramNodeUtil.loadSceneGraphProvider(ctx, modelAndRVI.first, node.getDiagramResource(), modelAndRVI.second, 5000); sgProvider.set( provider ); ctx.getDefaultHintContext().setHint(Hints.KEY_PAGE_DESC, pageDesc); // StringBuilder b = new StringBuilder(); // NodeUtil.printTreeNodes(ctx.getCanvasNode(), b); // System.err.println(b.toString()); ThreadUtils.asyncExec(thread, new Runnable() { @Override public void run() { try { PDFBuilder chassis = new PDFBuilder(writer, mapper, pageSize, pageDesc, fitDiagramContentsToPageMargins || isSymbol); chassis.paint(ctx, true); } finally { done.release(); } } }); } catch (DatabaseException e) { done.release(); exception.set(e); } catch (Throwable e) { done.release(); exception.set(new DatabaseException(e)); } finally { done.release(); } } }); done.acquire(2); if (exception.get() != null) throw exception.get(); return result.get(); } finally { if (sgProvider.get() != null) sgProvider.get().dispose(); ctx.dispose(); } } private static Resource resolveModel(ReadGraph graph, Node node) throws DatabaseException { Resource composite = node.getDefiningResources().head(); Resource model = graph.syncRequest(new PossibleIndexRoot(composite)); // Resource model = StructuralVariables.getModel(graph, composite); if (model == null) throw new ValidationException("no model found for composite " + NameUtils.getSafeName(graph, composite)); return model; } // private static String resolveModelURI(ReadGraph graph, final Node node) throws DatabaseException { // return graph.getURI(resolveModel(graph, node)); // } private static String resolveRVI(ReadGraph graph, final Node node) throws DatabaseException { String RVI = node.getRVI(); if(RVI != null) return RVI; Resource composite = node.getDefiningResources().head(); Variable var = Variables.getVariable(graph, composite); org.simantics.db.layer0.variable.RVI rvi = var.getPossibleRVI(graph); if(rvi == null) return null; return rvi.toString(); // final ResourceArray compositePath = StructuralVariables.getCompositeArray(graph, composite); // final ResourceArray variablePath = compositePath.removeFromBeginning(1); // return StructuralVariables.getRVI(graph, variablePath); } }