X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fexport%2FExportDiagramPdf.java;h=23cb9f970f36acd3761e1ee009b3375250125b6d;hb=a96e5125d72579c43abd70eb5c23de835324eaad;hp=31f54042e6c7607c5a4ad189dbc661186441c4a7;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/export/ExportDiagramPdf.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/export/ExportDiagramPdf.java index 31f54042e..23cb9f970 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/export/ExportDiagramPdf.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/export/ExportDiagramPdf.java @@ -1,379 +1,379 @@ -package org.simantics.diagram.export; - -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.geom.Rectangle2D; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.OperationCanceledException; -import org.osgi.service.prefs.Preferences; -import org.simantics.databoard.Accessors; -import org.simantics.databoard.accessor.RecordAccessor; -import org.simantics.databoard.accessor.UnionAccessor; -import org.simantics.databoard.accessor.error.AccessorConstructionException; -import org.simantics.databoard.accessor.error.AccessorException; -import org.simantics.databoard.accessor.reference.ChildReference; -import org.simantics.databoard.accessor.reference.LabelReference; -import org.simantics.databoard.binding.mutable.Variant; -import org.simantics.databoard.type.RecordType; -import org.simantics.databoard.type.UnionType; -import org.simantics.db.Resource; -import org.simantics.db.common.ResourceArray; -import org.simantics.db.common.primitiverequest.SingleObject; -import org.simantics.db.common.request.Queries; -import org.simantics.db.exception.DatabaseException; -import org.simantics.db.layer0.request.PossibleModel; -import org.simantics.db.layer0.util.SessionGarbageCollection; -import org.simantics.diagram.elements.DiagramNodeUtil; -import org.simantics.diagram.query.DiagramRequests; -import org.simantics.diagram.stubs.DiagramResource; -import org.simantics.export.core.ExportContext; -import org.simantics.export.core.error.ExportException; -import org.simantics.export.core.intf.ExportClass; -import org.simantics.export.core.manager.Content; -import org.simantics.export.core.pdf.ExportPdfWriter; -import org.simantics.export.core.pdf.ExportPdfWriter.Page; -import org.simantics.export.core.util.ExportQueries; -import org.simantics.export.core.util.ExporterUtils; -import org.simantics.g2d.canvas.Hints; -import org.simantics.g2d.canvas.ICanvasContext; -import org.simantics.g2d.canvas.impl.CanvasContext; -import org.simantics.g2d.diagram.DiagramHints; -import org.simantics.g2d.diagram.DiagramUtils; -import org.simantics.g2d.diagram.IDiagram; -import org.simantics.g2d.participant.TransformUtil; -import org.simantics.g2d.scenegraph.ICanvasSceneGraphProvider; -import org.simantics.layer0.Layer0; -import org.simantics.modeling.ModelingResources; -import org.simantics.modeling.template2d.ontology.Template2dResource; -import org.simantics.scenegraph.g2d.G2DPDFRenderingHints; -import org.simantics.scenegraph.g2d.G2DRenderingHints; -import org.simantics.scenegraph.utils.QualityHints; -import org.simantics.simulation.ontology.SimulationResource; -import org.simantics.structural.stubs.StructuralResource2; -import org.simantics.structural2.StructuralVariables; -import org.simantics.utils.datastructures.MapList; -import org.simantics.utils.page.MarginUtils; -import org.simantics.utils.page.MarginUtils.Margins; -import org.simantics.utils.page.PageDesc; -import org.simantics.utils.threads.ThreadUtils; -import org.simantics.utils.threads.WorkerThread; - -import com.kitfox.svg.SVGCache; - -public class ExportDiagramPdf implements ExportClass { - - public static LabelReference P_DIAGRAM_OPTIONS = new LabelReference("Diagram Options"); - public static String S_CONTENT_FIT = "Content Fit"; - public static ChildReference P_CONTENT_FIT = ChildReference.parsePath("Diagram Options/"+S_CONTENT_FIT); - public static String S_PAGE_SIZE = "Page Size"; - public static ChildReference P_PAGE_SIZE = ChildReference.parsePath("Diagram Options/"+S_PAGE_SIZE); - - // Diagram export options - RecordType deo, options; - UnionType contentUt, pageUt; - - public ExportDiagramPdf() { - options = new RecordType(); - deo = new RecordType(); - contentUt = UnionType.newEnum("Use the diagram specific borders", "Fit page by its contents"); - pageUt = UnionType.newEnum("Use the page size from this wizard", "Use diagram specific page sizes"); - deo.addComponent(S_CONTENT_FIT, contentUt); - deo.addComponent(S_PAGE_SIZE, pageUt); - options.addComponent(P_DIAGRAM_OPTIONS.label, deo); - } - - @Override - public RecordType options(ExportContext context, Collection content) throws ExportException { - return options; - } - - @Override - public void fillDefaultPrefs(ExportContext ctx, Variant options) throws ExportException { - try { - RecordAccessor ra = Accessors.getAccessor(options); - ExporterUtils.setUnionValue(ra, P_CONTENT_FIT, 0); - ExporterUtils.setUnionValue(ra, P_PAGE_SIZE, 1); - } catch (AccessorConstructionException e) { - } - } - - @Override - public void export(List contents, - Object handle, - ExportContext ctx, - Variant options, - IProgressMonitor monitor, - MapList attachmentMap - ) throws ExportException { - - final ExportPdfWriter writer = (ExportPdfWriter) handle; - - WorkerThread workerThread = new WorkerThread("Diagram PDF Painter"); - workerThread.start(); - - Page page = null; - try { - ModelingResources MOD = ModelingResources.getInstance( ctx.session ); - SimulationResource SIMU = SimulationResource.getInstance( ctx.session ); - StructuralResource2 STR = StructuralResource2.getInstance( ctx.session ); - DiagramResource DIA = DiagramResource.getInstance( ctx.session ); - final Template2dResource TMPL = Template2dResource.getInstance( ctx.session ); - Layer0 L0 = Layer0.getInstance( ctx.session ); - - for ( Content content : contents ) { - if (monitor.isCanceled()) - throw new OperationCanceledException(); - - // Diagram's composite resource - Resource resource = ctx.session.syncRequest( ExportQueries.toResource(content.url) ); - boolean isComposite = ctx.session.syncRequest( Queries.isInstanceOf(resource, STR.Composite) ); - if ( !isComposite ) { - resource = ctx.session.syncRequest( Queries.possibleObjectWithType(resource, L0.ConsistsOf, STR.Composite) ); - isComposite = ctx.session.syncRequest( Queries.isInstanceOf(resource, STR.Composite) ); - } - if ( !isComposite ) { - throw new ExportException(content.url+" doesnt contain a diagram."); - } - final Resource composite = resource; - final Resource diagram = ctx.session.syncRequest( new SingleObject( composite, MOD.CompositeToDiagram ) ); - final Resource drawingTemplate = ctx.session.syncRequest( Queries.possibleObject( diagram, TMPL.HasDrawingTemplate ) ); - final Resource activeProfile = ctx.session.syncRequest( Queries.possibleObject( diagram, DIA.HasActiveProfile ) ); - final Collection activeProfileEntries = activeProfile != null ? ctx.session.syncRequest( Queries.objects(activeProfile, SIMU.IsActive) ) : Collections.emptyList(); - final Resource model = ctx.session.syncRequest( new PossibleModel( composite ) ); - if ( model==null ) throw new ExportException("Cannot export diagram. Model was not found."); - final String diagramName = content.label; - - ResourceArray compositePath = StructuralVariables.getCompositeArray(ctx.session, composite); - ResourceArray variablePath = compositePath.removeFromBeginning(1); - final String modelRVI = StructuralVariables.getRVI(ctx.session, variablePath); - - // PageDesc, Read page desc from the graph - int tag = getPageFitArea(options); - PageDesc diagramPageDesc = ctx.session.syncRequest( DiagramRequests.getPageDesc(diagram, writer.defaultPageDesc)); - PageDesc wizardPageDesc = writer.defaultPageDesc; - PageDesc marginaaliViiva = diagramPageDesc; - - // Close previous page before starting a new one. - if (page != null) { - page.close(); - page = null; - } - - if ( tag == 0 ) { - // top,left margin translation is applied to G2D on createGraphics(..) - page = writer.createPage( wizardPageDesc ); - marginaaliViiva = diagramPageDesc; - } else { - marginaaliViiva = diagramPageDesc; - page = writer.createPage( diagramPageDesc ); - } - final PageDesc _marginaaliViiva = marginaaliViiva; - final PageDesc _diagramPageDesc = diagramPageDesc; - final Page _page = page; - final boolean fitDiagramContentsToPageMargins = getContentFitArea(options) == 1; - - final CanvasContext cctx = new CanvasContext( workerThread ); - final Exception[] errors = new Exception[1]; - final ICanvasSceneGraphProvider provider = DiagramNodeUtil.loadSceneGraphProvider(cctx, model, diagram, modelRVI); - - ThreadUtils.syncExec(workerThread, new Runnable() { - @Override - public void run() { - try { - cctx.getDefaultHintContext().setHint(Hints.KEY_PAGE_DESC, _marginaaliViiva); - - String bottomLabel = diagramName; - if ( drawingTemplate != null && activeProfileEntries.contains(TMPL.DrawingTemplate) ) bottomLabel = null; - - paint(cctx, writer, _page, fitDiagramContentsToPageMargins, bottomLabel, _diagramPageDesc); -// } catch (DatabaseException e) { -// errors[0] = e; -// } catch (InterruptedException e) { -// errors[0] = e; - } finally { - provider.dispose(); - cctx.dispose(); - } - } - }); - if ( errors[0] != null ) { - throw new ExportException( errors[0] ); - } - - - // Add page specific attachments - if ( attachmentMap!=null ) { - List ats = attachmentMap.getValues(content); - if ( ats != null ) for ( Content at : ats ) page.addAttachment(at); - } - } - - // These still have to be done to keep memory consumption down - // and avoid OOMs. - SVGCache.getSVGUniverse().clearUnreferenced(); - SessionGarbageCollection.gc(null, writer.ctx.session, true, null); - System.gc(); - - } catch (DatabaseException e) { - throw new ExportException( e.getClass().getName()+": "+e.getMessage(), e ); - } catch (InterruptedException e) { - throw new ExportException( e.getClass().getName()+": "+e.getMessage(), e ); - } finally { - if ( workerThread!=null ) workerThread.stopDispatchingEvents(true); - if ( page!=null ) page.close(); - } - - } - - - public void paint(ICanvasContext canvasContext, ExportPdfWriter writer, Page page, boolean fitDiagramContentsToPageMargins, String diagramName, PageDesc diagramPageDesc) { - // Specify rendering template size in points. - Graphics2D g2 = page.createGraphics(false); - try { - QualityHints.HIGH_QUALITY_HINTS.setQuality(g2); - g2.setRenderingHint(G2DPDFRenderingHints.KEY_EXPORT_PDF_WRITER, writer); - g2.setRenderingHint(G2DPDFRenderingHints.KEY_PDF_WRITER, writer.pdfCopy); - g2.setRenderingHint(G2DPDFRenderingHints.KEY_PDF_BYTECONTENT, writer.cb); - g2.setRenderingHint(G2DPDFRenderingHints.KEY_PDF_FONTMAPPER, writer.fontMapper); - g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); - - // Page size in mm - double pw = page.pageDesc.getWidth(); - double ph = page.pageDesc.getHeight(); - // Drawable area size in mm - double w = page.getWidth(); - double h = page.getHeight(); - - // Get margins in mm - if (fitDiagramContentsToPageMargins) { - Rectangle2D controlArea = new Rectangle2D.Double(0, 0, w, h); - IDiagram diagram = canvasContext.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM); - final Rectangle2D diagramRect = DiagramUtils.getContentRect(diagram); - if (diagramRect != null) { - canvasContext.getSingleItem(TransformUtil.class).fitArea(controlArea, diagramRect, MarginUtils.NO_MARGINS); - } - } - - /// Margins - // Margin differences - Margins diagramMargins = diagramPageDesc.getMargins(); - Margins wizardMargins = page.pageDesc.getMargins(); - - g2.translate( wizardMargins.left.diagramAbsolute, wizardMargins.top.diagramAbsolute); - - double diagramPageWidth = diagramPageDesc.getOrientedWidth(); - double diagramPageHeight = diagramPageDesc.getOrientedHeight(); - - double wizardPageWidth = page.pageDesc.getOrientedWidth(); - double wizardPageHeight = page.pageDesc.getOrientedHeight(); - - double diagramContentWidth = diagramPageDesc.getOrientedWidth() - diagramMargins.left.diagramAbsolute - diagramMargins.right.diagramAbsolute; - double diagramContentHeight = diagramPageDesc.getOrientedHeight() - diagramMargins.top.diagramAbsolute - diagramMargins.bottom.diagramAbsolute; - - double wizardContentWidth = page.pageDesc.getOrientedWidth() - wizardMargins.left.diagramAbsolute - wizardMargins.right.diagramAbsolute; - double wizardContentHeight = page.pageDesc.getOrientedHeight() - wizardMargins.top.diagramAbsolute - wizardMargins.bottom.diagramAbsolute; - - if ( diagramContentWidth!=wizardContentWidth || diagramContentHeight!=wizardContentHeight ) { - double r1 = wizardContentWidth / diagramContentWidth; - double r2 = wizardContentHeight / diagramContentHeight; - double r = Math.min(r1, r2); - if ( r1 < r2 ) { - g2.translate(0, wizardContentHeight/2); - } else { - g2.translate( wizardContentWidth/2, 0); - } - g2.scale(r, r); - if ( r1 < r2 ) { - g2.translate(0, -diagramContentHeight/ 2); - } else { - g2.translate(-diagramContentWidth/ 2, 0); - } - } - g2.translate( -diagramMargins.left.diagramAbsolute, -diagramMargins.top.diagramAbsolute); - g2.setRenderingHint(G2DRenderingHints.KEY_CONTROL_BOUNDS, new Rectangle2D.Double(0, 0, w, h)); - - if (canvasContext.isLocked()) - throw new IllegalStateException("cannot render PDF, canvas context is locked: " + canvasContext); - - canvasContext.getSceneGraph().render(g2); - -// // Write diagram name -// if ( diagramName != null ) { -// g2.setColor(Color.black); -// java.awt.Font arial = new java.awt.Font("Arial", java.awt.Font.ITALIC, 3); -// g2.setFont(arial); -// FontMetrics metrics = g2.getFontMetrics(); -// int width = metrics.stringWidth(diagramName); -//// System.out.println(diagramName + ", w: " + w + ", width: " + width); -//// System.out.println(diagramName + ", wizardPageHeight: " + wizardPageHeight + ", wizardMargins: " + wizardMargins); -//// System.out.println(PageDesc.toPoints(1)); -// float x = (float) ((w - width) / 2); -// float y = (float) (wizardPageHeight - wizardMargins.bottom.diagramAbsolute - PageDesc.toPoints(1)); -// g2.drawString(diagramName, x, y); -//// System.out.println(diagramName + ", X: " + x + ", Y: " + y); -// } - - } finally { - g2.dispose(); - } - } - - - @Override - public void savePref(Variant options, Preferences contentScopeNode, Preferences workbenchScopeNode) throws ExportException { - int tag = getContentFitArea(options); - if ( tag>=0 ) contentScopeNode.putInt(S_CONTENT_FIT, tag); - - tag = getPageFitArea(options); - if ( tag>=0 ) contentScopeNode.putInt(S_PAGE_SIZE, tag); - } - - @Override - public void loadPref(Variant options, Preferences contentScopeNode, Preferences workbenchScopeNode) throws ExportException { - try { - RecordAccessor ra = Accessors.getAccessor(options); - - int tag = contentScopeNode.getInt(S_CONTENT_FIT, -1); - if ( tag>=0 ) ExporterUtils.setUnionValue(ra, P_CONTENT_FIT, tag); - - tag = contentScopeNode.getInt(S_PAGE_SIZE, -1); - if ( tag>=0 ) ExporterUtils.setUnionValue(ra, P_PAGE_SIZE, tag); - - } catch (AccessorConstructionException e) { - } - } - - @Override - public List validate(String contentUri, ExportContext context, Variant options) { - return Collections.emptyList(); - } - - public static int getContentFitArea(Variant options) { - try { - RecordAccessor ra = Accessors.getAccessor(options); - UnionAccessor ua = ra.getComponent(P_CONTENT_FIT); - return ua.getTag(); - } catch (AccessorConstructionException e) { - return -1; - } catch (AccessorException e) { - return -1; - } - } - - public static int getPageFitArea(Variant options) { - try { - RecordAccessor ra = Accessors.getAccessor(options); - UnionAccessor ua = ra.getComponent(P_PAGE_SIZE); - return ua.getTag(); - } catch (AccessorConstructionException e) { - return -1; - } catch (AccessorException e) { - return -1; - } - } - -} +package org.simantics.diagram.export; + +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.geom.Rectangle2D; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.osgi.service.prefs.Preferences; +import org.simantics.databoard.Accessors; +import org.simantics.databoard.accessor.RecordAccessor; +import org.simantics.databoard.accessor.UnionAccessor; +import org.simantics.databoard.accessor.error.AccessorConstructionException; +import org.simantics.databoard.accessor.error.AccessorException; +import org.simantics.databoard.accessor.reference.ChildReference; +import org.simantics.databoard.accessor.reference.LabelReference; +import org.simantics.databoard.binding.mutable.Variant; +import org.simantics.databoard.type.RecordType; +import org.simantics.databoard.type.UnionType; +import org.simantics.db.Resource; +import org.simantics.db.common.ResourceArray; +import org.simantics.db.common.primitiverequest.SingleObject; +import org.simantics.db.common.request.Queries; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.request.PossibleModel; +import org.simantics.db.layer0.util.SessionGarbageCollection; +import org.simantics.diagram.elements.DiagramNodeUtil; +import org.simantics.diagram.query.DiagramRequests; +import org.simantics.diagram.stubs.DiagramResource; +import org.simantics.export.core.ExportContext; +import org.simantics.export.core.error.ExportException; +import org.simantics.export.core.intf.ExportClass; +import org.simantics.export.core.manager.Content; +import org.simantics.export.core.pdf.ExportPdfWriter; +import org.simantics.export.core.pdf.ExportPdfWriter.Page; +import org.simantics.export.core.util.ExportQueries; +import org.simantics.export.core.util.ExporterUtils; +import org.simantics.g2d.canvas.Hints; +import org.simantics.g2d.canvas.ICanvasContext; +import org.simantics.g2d.canvas.impl.CanvasContext; +import org.simantics.g2d.diagram.DiagramHints; +import org.simantics.g2d.diagram.DiagramUtils; +import org.simantics.g2d.diagram.IDiagram; +import org.simantics.g2d.participant.TransformUtil; +import org.simantics.g2d.scenegraph.ICanvasSceneGraphProvider; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ModelingResources; +import org.simantics.modeling.template2d.ontology.Template2dResource; +import org.simantics.scenegraph.g2d.G2DPDFRenderingHints; +import org.simantics.scenegraph.g2d.G2DRenderingHints; +import org.simantics.scenegraph.utils.QualityHints; +import org.simantics.simulation.ontology.SimulationResource; +import org.simantics.structural.stubs.StructuralResource2; +import org.simantics.structural2.StructuralVariables; +import org.simantics.utils.datastructures.MapList; +import org.simantics.utils.page.MarginUtils; +import org.simantics.utils.page.MarginUtils.Margins; +import org.simantics.utils.page.PageDesc; +import org.simantics.utils.threads.ThreadUtils; +import org.simantics.utils.threads.WorkerThread; + +import com.kitfox.svg.SVGCache; + +public class ExportDiagramPdf implements ExportClass { + + public static LabelReference P_DIAGRAM_OPTIONS = new LabelReference("Diagram Options"); + public static String S_CONTENT_FIT = "Content Fit"; + public static ChildReference P_CONTENT_FIT = ChildReference.parsePath("Diagram Options/"+S_CONTENT_FIT); + public static String S_PAGE_SIZE = "Page Size"; + public static ChildReference P_PAGE_SIZE = ChildReference.parsePath("Diagram Options/"+S_PAGE_SIZE); + + // Diagram export options + RecordType deo, options; + UnionType contentUt, pageUt; + + public ExportDiagramPdf() { + options = new RecordType(); + deo = new RecordType(); + contentUt = UnionType.newEnum("Use the diagram specific borders", "Fit page by its contents"); + pageUt = UnionType.newEnum("Use the page size from this wizard", "Use diagram specific page sizes"); + deo.addComponent(S_CONTENT_FIT, contentUt); + deo.addComponent(S_PAGE_SIZE, pageUt); + options.addComponent(P_DIAGRAM_OPTIONS.label, deo); + } + + @Override + public RecordType options(ExportContext context, Collection content) throws ExportException { + return options; + } + + @Override + public void fillDefaultPrefs(ExportContext ctx, Variant options) throws ExportException { + try { + RecordAccessor ra = Accessors.getAccessor(options); + ExporterUtils.setUnionValue(ra, P_CONTENT_FIT, 0); + ExporterUtils.setUnionValue(ra, P_PAGE_SIZE, 1); + } catch (AccessorConstructionException e) { + } + } + + @Override + public void export(List contents, + Object handle, + ExportContext ctx, + Variant options, + IProgressMonitor monitor, + MapList attachmentMap + ) throws ExportException { + + final ExportPdfWriter writer = (ExportPdfWriter) handle; + + WorkerThread workerThread = new WorkerThread("Diagram PDF Painter"); + workerThread.start(); + + Page page = null; + try { + ModelingResources MOD = ModelingResources.getInstance( ctx.session ); + SimulationResource SIMU = SimulationResource.getInstance( ctx.session ); + StructuralResource2 STR = StructuralResource2.getInstance( ctx.session ); + DiagramResource DIA = DiagramResource.getInstance( ctx.session ); + final Template2dResource TMPL = Template2dResource.getInstance( ctx.session ); + Layer0 L0 = Layer0.getInstance( ctx.session ); + + for ( Content content : contents ) { + if (monitor.isCanceled()) + throw new OperationCanceledException(); + + // Diagram's composite resource + Resource resource = ctx.session.syncRequest( ExportQueries.toResource(content.url) ); + boolean isComposite = ctx.session.syncRequest( Queries.isInstanceOf(resource, STR.Composite) ); + if ( !isComposite ) { + resource = ctx.session.syncRequest( Queries.possibleObjectWithType(resource, L0.ConsistsOf, STR.Composite) ); + isComposite = ctx.session.syncRequest( Queries.isInstanceOf(resource, STR.Composite) ); + } + if ( !isComposite ) { + throw new ExportException(content.url+" doesnt contain a diagram."); + } + final Resource composite = resource; + final Resource diagram = ctx.session.syncRequest( new SingleObject( composite, MOD.CompositeToDiagram ) ); + final Resource drawingTemplate = ctx.session.syncRequest( Queries.possibleObject( diagram, TMPL.HasDrawingTemplate ) ); + final Resource activeProfile = ctx.session.syncRequest( Queries.possibleObject( diagram, DIA.HasActiveProfile ) ); + final Collection activeProfileEntries = activeProfile != null ? ctx.session.syncRequest( Queries.objects(activeProfile, SIMU.IsActive) ) : Collections.emptyList(); + final Resource model = ctx.session.syncRequest( new PossibleModel( composite ) ); + if ( model==null ) throw new ExportException("Cannot export diagram. Model was not found."); + final String diagramName = content.label; + + ResourceArray compositePath = StructuralVariables.getCompositeArray(ctx.session, composite); + ResourceArray variablePath = compositePath.removeFromBeginning(1); + final String modelRVI = StructuralVariables.getRVI(ctx.session, variablePath); + + // PageDesc, Read page desc from the graph + int tag = getPageFitArea(options); + PageDesc diagramPageDesc = ctx.session.syncRequest( DiagramRequests.getPageDesc(diagram, writer.defaultPageDesc)); + PageDesc wizardPageDesc = writer.defaultPageDesc; + PageDesc marginaaliViiva = diagramPageDesc; + + // Close previous page before starting a new one. + if (page != null) { + page.close(); + page = null; + } + + if ( tag == 0 ) { + // top,left margin translation is applied to G2D on createGraphics(..) + page = writer.createPage( wizardPageDesc ); + marginaaliViiva = diagramPageDesc; + } else { + marginaaliViiva = diagramPageDesc; + page = writer.createPage( diagramPageDesc ); + } + final PageDesc _marginaaliViiva = marginaaliViiva; + final PageDesc _diagramPageDesc = diagramPageDesc; + final Page _page = page; + final boolean fitDiagramContentsToPageMargins = getContentFitArea(options) == 1; + + final CanvasContext cctx = new CanvasContext( workerThread ); + final Exception[] errors = new Exception[1]; + final ICanvasSceneGraphProvider provider = DiagramNodeUtil.loadSceneGraphProvider(cctx, model, diagram, modelRVI); + + ThreadUtils.syncExec(workerThread, new Runnable() { + @Override + public void run() { + try { + cctx.getDefaultHintContext().setHint(Hints.KEY_PAGE_DESC, _marginaaliViiva); + + String bottomLabel = diagramName; + if ( drawingTemplate != null && activeProfileEntries.contains(TMPL.DrawingTemplate) ) bottomLabel = null; + + paint(cctx, writer, _page, fitDiagramContentsToPageMargins, bottomLabel, _diagramPageDesc); +// } catch (DatabaseException e) { +// errors[0] = e; +// } catch (InterruptedException e) { +// errors[0] = e; + } finally { + provider.dispose(); + cctx.dispose(); + } + } + }); + if ( errors[0] != null ) { + throw new ExportException( errors[0] ); + } + + + // Add page specific attachments + if ( attachmentMap!=null ) { + List ats = attachmentMap.getValues(content); + if ( ats != null ) for ( Content at : ats ) page.addAttachment(at); + } + } + + // These still have to be done to keep memory consumption down + // and avoid OOMs. + SVGCache.getSVGUniverse().clearUnreferenced(); + SessionGarbageCollection.gc(null, writer.ctx.session, true, null); + System.gc(); + + } catch (DatabaseException e) { + throw new ExportException( e.getClass().getName()+": "+e.getMessage(), e ); + } catch (InterruptedException e) { + throw new ExportException( e.getClass().getName()+": "+e.getMessage(), e ); + } finally { + if ( workerThread!=null ) workerThread.stopDispatchingEvents(true); + if ( page!=null ) page.close(); + } + + } + + + public void paint(ICanvasContext canvasContext, ExportPdfWriter writer, Page page, boolean fitDiagramContentsToPageMargins, String diagramName, PageDesc diagramPageDesc) { + // Specify rendering template size in points. + Graphics2D g2 = page.createGraphics(false); + try { + QualityHints.HIGH_QUALITY_HINTS.setQuality(g2); + g2.setRenderingHint(G2DPDFRenderingHints.KEY_EXPORT_PDF_WRITER, writer); + g2.setRenderingHint(G2DPDFRenderingHints.KEY_PDF_WRITER, writer.pdfCopy); + g2.setRenderingHint(G2DPDFRenderingHints.KEY_PDF_BYTECONTENT, writer.cb); + g2.setRenderingHint(G2DPDFRenderingHints.KEY_PDF_FONTMAPPER, writer.fontMapper); + g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + + // Page size in mm + double pw = page.pageDesc.getWidth(); + double ph = page.pageDesc.getHeight(); + // Drawable area size in mm + double w = page.getWidth(); + double h = page.getHeight(); + + // Get margins in mm + if (fitDiagramContentsToPageMargins) { + Rectangle2D controlArea = new Rectangle2D.Double(0, 0, w, h); + IDiagram diagram = canvasContext.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM); + final Rectangle2D diagramRect = DiagramUtils.getContentRect(diagram); + if (diagramRect != null) { + canvasContext.getSingleItem(TransformUtil.class).fitArea(controlArea, diagramRect, MarginUtils.NO_MARGINS); + } + } + + /// Margins + // Margin differences + Margins diagramMargins = diagramPageDesc.getMargins(); + Margins wizardMargins = page.pageDesc.getMargins(); + + g2.translate( wizardMargins.left.diagramAbsolute, wizardMargins.top.diagramAbsolute); + + double diagramPageWidth = diagramPageDesc.getOrientedWidth(); + double diagramPageHeight = diagramPageDesc.getOrientedHeight(); + + double wizardPageWidth = page.pageDesc.getOrientedWidth(); + double wizardPageHeight = page.pageDesc.getOrientedHeight(); + + double diagramContentWidth = diagramPageDesc.getOrientedWidth() - diagramMargins.left.diagramAbsolute - diagramMargins.right.diagramAbsolute; + double diagramContentHeight = diagramPageDesc.getOrientedHeight() - diagramMargins.top.diagramAbsolute - diagramMargins.bottom.diagramAbsolute; + + double wizardContentWidth = page.pageDesc.getOrientedWidth() - wizardMargins.left.diagramAbsolute - wizardMargins.right.diagramAbsolute; + double wizardContentHeight = page.pageDesc.getOrientedHeight() - wizardMargins.top.diagramAbsolute - wizardMargins.bottom.diagramAbsolute; + + if ( diagramContentWidth!=wizardContentWidth || diagramContentHeight!=wizardContentHeight ) { + double r1 = wizardContentWidth / diagramContentWidth; + double r2 = wizardContentHeight / diagramContentHeight; + double r = Math.min(r1, r2); + if ( r1 < r2 ) { + g2.translate(0, wizardContentHeight/2); + } else { + g2.translate( wizardContentWidth/2, 0); + } + g2.scale(r, r); + if ( r1 < r2 ) { + g2.translate(0, -diagramContentHeight/ 2); + } else { + g2.translate(-diagramContentWidth/ 2, 0); + } + } + g2.translate( -diagramMargins.left.diagramAbsolute, -diagramMargins.top.diagramAbsolute); + g2.setRenderingHint(G2DRenderingHints.KEY_CONTROL_BOUNDS, new Rectangle2D.Double(0, 0, w, h)); + + if (canvasContext.isLocked()) + throw new IllegalStateException("cannot render PDF, canvas context is locked: " + canvasContext); + + canvasContext.getSceneGraph().render(g2); + +// // Write diagram name +// if ( diagramName != null ) { +// g2.setColor(Color.black); +// java.awt.Font arial = new java.awt.Font("Arial", java.awt.Font.ITALIC, 3); +// g2.setFont(arial); +// FontMetrics metrics = g2.getFontMetrics(); +// int width = metrics.stringWidth(diagramName); +//// System.out.println(diagramName + ", w: " + w + ", width: " + width); +//// System.out.println(diagramName + ", wizardPageHeight: " + wizardPageHeight + ", wizardMargins: " + wizardMargins); +//// System.out.println(PageDesc.toPoints(1)); +// float x = (float) ((w - width) / 2); +// float y = (float) (wizardPageHeight - wizardMargins.bottom.diagramAbsolute - PageDesc.toPoints(1)); +// g2.drawString(diagramName, x, y); +//// System.out.println(diagramName + ", X: " + x + ", Y: " + y); +// } + + } finally { + g2.dispose(); + } + } + + + @Override + public void savePref(Variant options, Preferences contentScopeNode, Preferences workbenchScopeNode) throws ExportException { + int tag = getContentFitArea(options); + if ( tag>=0 ) contentScopeNode.putInt(S_CONTENT_FIT, tag); + + tag = getPageFitArea(options); + if ( tag>=0 ) contentScopeNode.putInt(S_PAGE_SIZE, tag); + } + + @Override + public void loadPref(Variant options, Preferences contentScopeNode, Preferences workbenchScopeNode) throws ExportException { + try { + RecordAccessor ra = Accessors.getAccessor(options); + + int tag = contentScopeNode.getInt(S_CONTENT_FIT, -1); + if ( tag>=0 ) ExporterUtils.setUnionValue(ra, P_CONTENT_FIT, tag); + + tag = contentScopeNode.getInt(S_PAGE_SIZE, -1); + if ( tag>=0 ) ExporterUtils.setUnionValue(ra, P_PAGE_SIZE, tag); + + } catch (AccessorConstructionException e) { + } + } + + @Override + public List validate(String contentUri, ExportContext context, Variant options) { + return Collections.emptyList(); + } + + public static int getContentFitArea(Variant options) { + try { + RecordAccessor ra = Accessors.getAccessor(options); + UnionAccessor ua = ra.getComponent(P_CONTENT_FIT); + return ua.getTag(); + } catch (AccessorConstructionException e) { + return -1; + } catch (AccessorException e) { + return -1; + } + } + + public static int getPageFitArea(Variant options) { + try { + RecordAccessor ra = Accessors.getAccessor(options); + UnionAccessor ua = ra.getComponent(P_PAGE_SIZE); + return ua.getTag(); + } catch (AccessorConstructionException e) { + return -1; + } catch (AccessorException e) { + return -1; + } + } + +}