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