]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Fonts are now embedded in diagram, wiki, etc PDF exports. 60/360/1
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Fri, 10 Mar 2017 16:27:03 +0000 (18:27 +0200)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Fri, 10 Mar 2017 16:27:03 +0000 (18:27 +0200)
A lot of general cleanup/refactoring for the old "Diagrams to PDF"
export wizard backend implementation. Consolidated some page numbering
code into org.simantics.export.core.pdf.PageNumbering.

Also consolidated iText FontMapper initialization into
org.simantics.export.core.pdf.FontMapping. It turned out that the key to
getting iText to embed fonts for text rendered into PDFs was that the
FontMapper used needs to have all system fonts registered into it.

Also fixed PDF export page number positioning in the more generic PDF
export wizard.

refs #7084

Change-Id: Ife4f96889659834a780566152f63e9e1ccd4979f

12 files changed:
bundles/org.simantics.document/src/org/simantics/document/DocumentUtils.java
bundles/org.simantics.document/src/org/simantics/document/Exportable.java
bundles/org.simantics.export.core/src/org/simantics/export/core/pdf/ExportPdfFormat.java
bundles/org.simantics.export.core/src/org/simantics/export/core/pdf/ExportPdfWriter.java
bundles/org.simantics.export.core/src/org/simantics/export/core/pdf/FontMapping.java [new file with mode: 0644]
bundles/org.simantics.export.core/src/org/simantics/export/core/pdf/PageNumbering.java [new file with mode: 0644]
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/DiagramPrinter.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFDiagramExportWizard.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFExportPlan.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFPainter.java
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/utils/NodeUtil.java
bundles/org.simantics.wiki.ui/src/org/simantics/wiki/ui/editor/IExportable.java

index e539df2c3aa27cdc0cb276363809d52e125e48ba..16a81f6f33636a772874d20b679637d3cfff7c67 100644 (file)
@@ -28,7 +28,6 @@ import org.simantics.db.common.request.PossibleIndexRoot;
 import org.simantics.db.common.request.ResourceRead;
 import org.simantics.db.common.request.UniqueRead;
 import org.simantics.db.common.request.WriteResultRequest;
-import org.simantics.db.common.utils.Logger;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.variable.Variable;
 import org.simantics.db.layer0.variable.Variables;
@@ -194,22 +193,15 @@ public class DocumentUtils {
                }
        }       
 
-       public void print(RequestProcessor processor, Resource res, String wiki, String css, DocumentSettings settings, final PdfWriter writer, final Document document) throws DocumentException {
-               try {
-                       Exportable exp = processor.syncRequest(new UniqueRead<Exportable>() {
-
-                               @Override
-                               public Exportable perform(ReadGraph graph) throws DatabaseException {
-                                       return new Exportable(graph, res, wiki, css, settings, true);
-                               }
-                               
-                       });
-                       exp.export(document, writer);
-               } catch (DocumentException e) {
-                       Logger.defaultLogError(e);
-               } catch (DatabaseException e) {
-                       Logger.defaultLogError(e);
-               }
+       public int print(RequestProcessor processor, Resource res, String wiki, String css, DocumentSettings settings, final PdfWriter writer, final Document document)
+                       throws DocumentException, DatabaseException {
+               Exportable exp = processor.syncRequest(new UniqueRead<Exportable>() {
+                       @Override
+                       public Exportable perform(ReadGraph graph) throws DatabaseException {
+                               return new Exportable(graph, res, wiki, css, settings, true);
+                       }
+               });
+               return exp.export(document, writer);
        }
 
     public static String indexRootPath(ReadGraph graph, Variable selection) throws DatabaseException {
index a1053dd83001dafde9e6923f2a569b3b3d8f1585..a6dd790de51b78937f71ad627f1b27a2e1a01edd 100644 (file)
@@ -105,7 +105,7 @@ public class Exportable implements IExportable {
        }
 
        @Override
-       public void export(Document document, PdfWriter writer) throws DocumentException {
+       public int export(Document document, PdfWriter writer) throws DocumentException {
 
                File temp = Simantics.getTempfile("wikiPdfExport", "pdf");
                try {
@@ -113,6 +113,7 @@ public class Exportable implements IExportable {
                        temp.getParentFile().mkdirs();
                        PhantomJSDriver.print(html, settings, temp);
                        
+                       int result = 0;
                PdfContentByte cb = writer.getDirectContent();
                PdfReader reader = new PdfReader(new BufferedInputStream(new FileInputStream(temp)));
                for (int i = 1; i <= reader.getNumberOfPages(); i++) {
@@ -123,8 +124,10 @@ public class Exportable implements IExportable {
                        //add the page to the destination pdf
                        float pts = Utilities.millimetersToPoints(10);
                        cb.addTemplate(page, pts, pts);
+                       ++result;
                }
 
+               return result;
                } catch (IOException e) {
 
                        throw new DocumentException(e);
index 9711fbccf06e02ca60b01f837ed7e0f0b757a2d7..9e80cd16f1e828ac26955c7efb15ba61799b8ede 100644 (file)
@@ -46,7 +46,6 @@ import com.lowagie.text.Document;
 import com.lowagie.text.DocumentException;
 import com.lowagie.text.FontFactory;
 import com.lowagie.text.Rectangle;
-import com.lowagie.text.pdf.DefaultFontMapper;
 import com.lowagie.text.pdf.PdfBoolean;
 import com.lowagie.text.pdf.PdfCopy;
 import com.lowagie.text.pdf.PdfName;
@@ -160,7 +159,7 @@ public class ExportPdfFormat implements FormatClass {
                        writer.fos = new FileOutputStream(writer.outputFile);
                        writer.pdfCopy = new PdfCopy(writer.document, writer.fos); 
                        writer.pdfCopy.setPdfVersion(PdfWriter.PDF_VERSION_1_7);
-                       writer.fontMapper = new DefaultFontMapper();
+                       writer.fontMapper = FontMapping.defaultFontMapper();
                        writer.options = options;
                        writer.ctx = ctx;
 
index 204763b687175b215e1a31531d236e54629e1bb3..97488908ee1822c04ec9a9a183483626baa0486f 100644 (file)
@@ -317,10 +317,10 @@ public class ExportPdfWriter {
                                try {
                                int n = reader.getNumberOfPages();
 
-                               for (int i = 0; i < n; ) {
-                                   Rectangle pageSize = reader.getPageSizeWithRotation(n);
+                               for (int i = 1; i <= n; ++i) {
+                                   Rectangle pageSize = reader.getPageSizeWithRotation(i);
 
-                                   PdfImportedPage imp = pdfCopy.getImportedPage(reader, ++i);
+                                   PdfImportedPage imp = pdfCopy.getImportedPage(reader, i);
                                    PdfCopy.PageStamp ps = pdfCopy.createPageStamp(imp);
 
                                    PdfContentByte over = ps.getOverContent();
diff --git a/bundles/org.simantics.export.core/src/org/simantics/export/core/pdf/FontMapping.java b/bundles/org.simantics.export.core/src/org/simantics/export/core/pdf/FontMapping.java
new file mode 100644 (file)
index 0000000..9c68b16
--- /dev/null
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2017 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:
+ *     Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.export.core.pdf;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.lowagie.text.FontFactory;
+import com.lowagie.text.pdf.DefaultFontMapper;
+import com.lowagie.text.pdf.FontMapper;
+
+/**
+ * A utility class for constructing properly initialize iText {@link FontMapper}
+ * instances.
+ * 
+ * @author Tuukka Lehtonen
+ * @since 1.28.0
+ */
+public class FontMapping {
+
+       private static final AtomicBoolean fontFactoryInitialized = new AtomicBoolean();
+
+       public static FontMapper defaultFontMapper() {
+               // NOTE: recreation is intentional because users might add fonts between exports.
+               // At some point, perhaps we could listen to file system changes in these locations
+               // and only then recreate the mapper.
+               return createDefaultFontMapper(); 
+       }
+
+       public static FontMapper createDefaultFontMapper() {
+               initializeFontFactory();
+               DefaultFontMapper mapper = new DefaultFontMapper();
+               insertDirectories(mapper);
+               return mapper;
+       }
+
+       private static void insertDirectories(DefaultFontMapper mapper) {
+               switch (OSType.calculate()) {
+               case APPLE:
+                       mapper.insertDirectory("/Library/Fonts");
+                       mapper.insertDirectory("/System/Library/Fonts");
+
+               case LINUX:
+               case SUN:
+                       mapper.insertDirectory("/usr/share/X11/fonts");
+                       mapper.insertDirectory("/usr/X/lib/X11/fonts");
+                       mapper.insertDirectory("/usr/openwin/lib/X11/fonts");
+                       mapper.insertDirectory("/usr/share/fonts");
+                       mapper.insertDirectory("/usr/X11R6/lib/X11/fonts");
+                       break;
+
+               case WINDOWS:
+                       String windir = System.getenv("WINDIR");
+                       if (windir != null && !windir.isEmpty()) {
+                               mapper.insertDirectory(windir + "\\Fonts");
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       private static void initializeFontFactory() {
+               if (!fontFactoryInitialized.compareAndSet(false, true))
+                       return;
+
+               switch (OSType.calculate()) {
+               case APPLE:
+                       FontFactory.registerDirectory("/Library/Fonts");
+                       FontFactory.registerDirectory("/System/Library/Fonts");
+
+               case LINUX:
+               case SUN:
+                       FontFactory.registerDirectory("/usr/share/X11/fonts", true);
+                       FontFactory.registerDirectory("/usr/X/lib/X11/fonts", true);
+                       FontFactory.registerDirectory("/usr/openwin/lib/X11/fonts", true);
+                       FontFactory.registerDirectory("/usr/share/fonts", true);
+                       FontFactory.registerDirectory("/usr/X11R6/lib/X11/fonts", true);
+                       break;
+
+               case WINDOWS:
+                       String windir = System.getenv("WINDIR");
+                       if (windir != null && !windir.isEmpty()) {
+                               FontFactory.registerDirectory(windir + "\\Fonts");
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       static enum OSType {
+               APPLE, LINUX, SUN, WINDOWS, UNKNOWN;
+
+               public static OSType calculate() {
+                       String osName = System.getProperty("os.name");
+                       assert osName != null;
+                       osName = osName.toLowerCase();
+                       if (osName.startsWith("mac os x"))
+                               return APPLE;
+                       if (osName.startsWith("windows"))
+                               return WINDOWS;
+                       if (osName.startsWith("linux"))
+                               return LINUX;
+                       if (osName.startsWith("sun"))
+                               return SUN;
+                       return UNKNOWN;
+               }
+       }
+
+}
diff --git a/bundles/org.simantics.export.core/src/org/simantics/export/core/pdf/PageNumbering.java b/bundles/org.simantics.export.core/src/org/simantics/export/core/pdf/PageNumbering.java
new file mode 100644 (file)
index 0000000..edf4e72
--- /dev/null
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2017 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:
+ *     Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.export.core.pdf;
+
+import java.awt.geom.Point2D;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
+
+import com.lowagie.text.Document;
+import com.lowagie.text.DocumentException;
+import com.lowagie.text.Element;
+import com.lowagie.text.Font;
+import com.lowagie.text.Phrase;
+import com.lowagie.text.Rectangle;
+import com.lowagie.text.pdf.BadPdfFormatException;
+import com.lowagie.text.pdf.ColumnText;
+import com.lowagie.text.pdf.PdfContentByte;
+import com.lowagie.text.pdf.PdfCopy;
+import com.lowagie.text.pdf.PdfImportedPage;
+import com.lowagie.text.pdf.PdfReader;
+import com.lowagie.text.pdf.PdfWriter;
+
+/**
+ * PDF page numbering related post-processing utilities using iText.
+ * 
+ * @author Tuukka Lehtonen
+ * @since 1.28.0
+ */
+public class PageNumbering {
+
+       public static enum NumberingFormat {
+               PAGE_SLASH_TOTAL_PAGES
+       }
+
+       public static enum Position {
+               BOTTOM_LEFT,
+               BOTTOM_RIGHT,
+               TOP_LEFT,
+               TOP_RIGHT,
+       }
+
+       private static int pageNumberAlignment(Position positioning) {
+               switch (positioning) {
+               case BOTTOM_LEFT:
+               case TOP_LEFT:  return Element.ALIGN_LEFT;
+
+               case BOTTOM_RIGHT:
+               case TOP_RIGHT:
+               default: return Element.ALIGN_RIGHT;
+               }
+       }
+
+       private static Point2D.Float pageNumberPosition(Position positioning, Rectangle pageSize, Font font) {
+               switch (positioning) {
+               case TOP_LEFT:
+                       return new Point2D.Float(12, pageSize.getHeight() - 12 - font.getCalculatedSize()*0.8f);
+               case TOP_RIGHT:
+                       return new Point2D.Float(pageSize.getWidth() - 12, pageSize.getHeight() - 12 - font.getCalculatedSize()*0.8f);
+               case BOTTOM_LEFT:
+                       return new Point2D.Float(12, 12);
+               case BOTTOM_RIGHT: 
+               default:
+                       return new Point2D.Float(pageSize.getWidth() - 12, 12);
+               }
+       }
+
+       public static String formatPageNumber(NumberingFormat format, int pageNumber, int totalPages) {
+               switch (format) {
+               case PAGE_SLASH_TOTAL_PAGES: return String.format("%d / %d", pageNumber, totalPages);
+               default:
+                       throw new UnsupportedOperationException("Unsupported numbering format: " + format);
+               }
+       }
+
+       public static void addPageNumber(
+                       PdfCopy pdfCopy,
+                       PdfReader sourceReader,
+                       int sourcePageNumber,
+                       int currentPageNumber,
+                       int totalPages,
+                       Font font,
+                       Position positioning,
+                       NumberingFormat format)
+                                       throws IOException, BadPdfFormatException
+       {
+               Rectangle pageSize = sourceReader.getPageSizeWithRotation(sourcePageNumber);
+               PdfImportedPage imp = pdfCopy.getImportedPage(sourceReader, sourcePageNumber);
+               PdfCopy.PageStamp ps = pdfCopy.createPageStamp(imp);
+               PdfContentByte over = ps.getOverContent();
+               String text = formatPageNumber(format, currentPageNumber, totalPages);
+               Point2D.Float pos = pageNumberPosition(positioning, pageSize, font);
+               int alignment = pageNumberAlignment(positioning);
+               ColumnText.showTextAligned(over, alignment, new Phrase(text, font), pos.x, pos.y, 0);
+               ps.alterContents();
+               pdfCopy.addPage(imp);
+       }
+
+       public static void addPageNumbers(
+                       IProgressMonitor monitor,
+                       Path inputFile,
+                       Path outputFile,
+                       Position positioning,
+                       NumberingFormat format,
+                       Font pageNumberFont)
+                                       throws IOException, DocumentException
+       {
+               PdfReader reader = null;
+               try {
+                       reader = new PdfReader(inputFile.toString());
+                       int totalPages = reader.getNumberOfPages();
+                       int currentPage = 1;
+
+                       SubMonitor mon = SubMonitor.convert(monitor, totalPages);
+
+                       try (OutputStream fos = Files.newOutputStream(outputFile)) {
+                               Document document = new Document();
+                               PdfCopy pdfCopy = new PdfCopy(document, fos); 
+                               pdfCopy.setPdfVersion(PdfWriter.PDF_VERSION_1_7);
+                               document.open();
+                               try {
+                                       for (int i = 1; i <= totalPages; ++i) {
+                                               mon.subTask(i + "/" + totalPages);
+                                               PageNumbering.addPageNumber(pdfCopy, reader, i,
+                                                               currentPage++, totalPages,
+                                                               pageNumberFont,
+                                                               positioning,
+                                                               format);
+                                       }
+                               } finally {
+                                       if (document != null && document.isOpen())
+                                               document.close();
+                                       if (pdfCopy != null)
+                                               pdfCopy.close();
+                               }
+                       }
+               } finally {
+                       if (reader != null)
+                               reader.close();
+               }
+
+       }
+
+       public static void addPageNumbers(
+                       IProgressMonitor monitor,
+                       Path inputFile,
+                       Path outputFile,
+                       Position positioning,
+                       NumberingFormat format)
+                                       throws IOException, DocumentException
+       {
+               addPageNumbers(monitor, inputFile, outputFile, positioning, format, new Font(Font.HELVETICA, 8));
+       }
+
+}
\ No newline at end of file
index e3101dce2e31ea8d2e200d9f96f56c692e6e463f..7f0559348d5b67d227512b37c433b5b407936041 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * Copyright (c) 2007, 2017 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
@@ -8,14 +8,17 @@
  *
  * Contributors:
  *     VTT Technical Research Centre of Finland - initial API and implementation
+ *     Semantum Oy - (#7084) refactoring, page numbering support
  *******************************************************************************/
 package org.simantics.modeling.ui.pdf;
 
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.security.Security;
 import java.util.Collection;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.core.runtime.IProduct;
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -27,9 +30,10 @@ import org.simantics.db.Resource;
 import org.simantics.db.Session;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.util.SessionGarbageCollection;
-import org.simantics.db.management.ISessionContext;
 import org.simantics.document.DocumentSettings;
 import org.simantics.document.DocumentUtils;
+import org.simantics.export.core.pdf.FontMapping;
+import org.simantics.export.core.pdf.PageNumbering;
 import org.simantics.export.core.pdf.ServiceBasedPdfExportPageEvent;
 import org.simantics.modeling.requests.CollectionRequest;
 import org.simantics.modeling.requests.CollectionResult;
@@ -39,29 +43,34 @@ import org.simantics.ui.jobs.SessionGarbageCollectorJob;
 import org.simantics.utils.page.PageDesc;
 import org.simantics.utils.page.PageOrientation;
 import org.simantics.utils.threads.WorkerThread;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.kitfox.svg.SVGCache;
 import com.lowagie.text.Document;
 import com.lowagie.text.DocumentException;
-import com.lowagie.text.FontFactory;
+import com.lowagie.text.ExceptionConverter;
 import com.lowagie.text.PageSize;
 import com.lowagie.text.Rectangle;
-import com.lowagie.text.pdf.DefaultFontMapper;
+import com.lowagie.text.pdf.FontMapper;
 import com.lowagie.text.pdf.PdfBoolean;
 import com.lowagie.text.pdf.PdfContentByte;
 import com.lowagie.text.pdf.PdfName;
 import com.lowagie.text.pdf.PdfTemplate;
 import com.lowagie.text.pdf.PdfWriter;
 
+/**
+ * @author Tuukka Lehtonen
+ */
 public class DiagramPrinter {
 
+    private static final Logger LOGGER = LoggerFactory.getLogger(DiagramPrinter.class);
+
     public static CollectionResult browse(IProgressMonitor monitor, RequestProcessor processor, Resource[] input) throws DatabaseException {
         final CollectionResult result = processor.syncRequest(new CollectionRequest(monitor, DiagramPreferenceUtil.getDefaultPreferences().getCompletePageDesc(), input));
         return result;
     }
 
-    private static final AtomicBoolean fontFactoryInitialized = new AtomicBoolean();
-
     /**
      * @param monitor the progress monitor to use for reporting progress to the
      *        user. It is the caller's responsibility to call done() on the
@@ -76,38 +85,88 @@ public class DiagramPrinter {
      * @throws FileNotFoundException
      */
     public static void printToPdf(
-               IProgressMonitor monitor, 
-               PDFExportPlan exportPlan, 
-               String exportPath, 
-               Collection<Node> flattenedNodes,
-            ISessionContext sessionContext) 
-    throws PdfException {
-        Collection<Node> flattened = flattenedNodes;
+            IProgressMonitor monitor, 
+            PDFExportPlan exportPlan, 
+            String exportPath, 
+            Collection<Node> flattenedNodes) 
+                throws PdfException
+    {
+        if (!exportPlan.addPageNumbers) {
+            printToPdfWithoutPageNumbers(monitor, exportPlan, exportPath, flattenedNodes);
+        } else {
+            SubMonitor mon = SubMonitor.convert(monitor, "Export to PDF", flattenedNodes.size() * 3);
+
+            Path tempOutput = Paths.get(exportPath + ".tmp");
+            Path finalOutput = Paths.get(exportPath);
+
+            int exportedPages = printToPdfWithoutPageNumbers(
+                    mon.newChild(flattenedNodes.size() * 2, SubMonitor.SUPPRESS_NONE),
+                    exportPlan,
+                    tempOutput.toString(),
+                    flattenedNodes);
+
+            if (mon.isCanceled()) {
+                tempOutput.toFile().delete();
+                throw new OperationCanceledException();
+            }
 
-        SubMonitor progress = SubMonitor.convert(monitor, "Export to PDF", flattened.size() * 2);
+            try {
+                mon.setWorkRemaining(exportedPages);
+                mon.setTaskName("Numbering output pages");
+                mon.subTask("");
+                PageNumbering.addPageNumbers(
+                        mon.newChild(flattenedNodes.size()),
+                        tempOutput, finalOutput,
+                        exportPlan.pageNumberPosition,
+                        exportPlan.pageNumberFormat);
+            } catch (IOException | DocumentException | ExceptionConverter e) {
+                throw new PdfException(e);
+            } finally {
+                tempOutput.toFile().delete();
+            }
+        }
+    }
+
+    /**
+     * @param monitor the progress monitor to use for reporting progress to the
+     *        user. It is the caller's responsibility to call done() on the
+     *        given monitor. Accepts <code>null</code>, indicating that no
+     *        progress should be reported and that the operation cannot be
+     *        cancelled.
+     * 
+     * @param exportPath
+     * @param flattenedNodes
+     * @return number of pages printed
+     * @throws PdfException
+     * @since 1.28.0
+     */
+    public static int printToPdfWithoutPageNumbers(
+            IProgressMonitor monitor, 
+            PDFExportPlan exportPlan, 
+            String exportPath, 
+            Collection<Node> flattenedNodes) 
+                    throws PdfException
+    {
+        SubMonitor progress = SubMonitor.convert(monitor, "Export to PDF", flattenedNodes.size() * 2);
 
         WorkerThread workerThread = new WorkerThread("Diagram PDF Painter");
         workerThread.start();
 
         PdfWriter writer = null;
         Document document = null;
+        int exportedPages = 0;
 
         try {
             progress.subTask("Loading system fonts");
-            DefaultFontMapper mapper = new DefaultFontMapper();
-            if (fontFactoryInitialized.compareAndSet(false, true)) {
-                // Only register directories once.
-                FontFactory.registerDirectories();
-            }
+            FontMapper mapper = FontMapping.defaultFontMapper();
 
             SessionGarbageCollectorJob.getInstance().setEnabled(false);
 
-
-            boolean first = true;           
+            boolean first = true;
             int i = 0;
-            for (Node d : flattened) {
+            for (Node d : flattenedNodes) {
                 ++i;
-                
+
                 //System.out.println("PAGE DESC: " + d.getPageDesc());
                 //System.out.println("PAGE SIZE: " + pageSize);
 
@@ -115,98 +174,96 @@ public class DiagramPrinter {
                 if (writer == null) {
                     document = new Document(pageSize);
                     writer = PdfWriter.getInstance(document, new FileOutputStream(exportPath));
-                   writer.setPdfVersion(PdfWriter.PDF_VERSION_1_7);
-                   writer.setPageEvent(new ServiceBasedPdfExportPageEvent());
-                   if ( exportPlan.attachTG ) {
-                       writer.addViewerPreference(PdfName.USEATTACHMENTS, PdfBoolean.PDFTRUE);
-                   }
+                    writer.setPdfVersion(PdfWriter.PDF_VERSION_1_7);
+                    writer.setPageEvent(new ServiceBasedPdfExportPageEvent());
+                    if ( exportPlan.attachTG ) {
+                        writer.addViewerPreference(PdfName.USEATTACHMENTS, PdfBoolean.PDFTRUE);
+                    }
    
-                   String creator = getCreator();
-                   document.addCreator(creator);
-
-                   /*
-                       File keystoreFile = new File("c:\\0009278.p12");
-                       String password = "ka7GfzI9Oq";
-
-                       try {
-                               KeyStore ks = KeyStore.getInstance("pkcs12");
-                               ks.load(new FileInputStream(keystoreFile), password.toCharArray());
-                               List<String> aliases = Collections.list(ks.aliases());
-                               String alias = aliases.get(0);
-                               PrivateKey key = (PrivateKey)ks.getKey(alias, password.toCharArray());
-                               Certificate[] chain = ks.getCertificateChain(alias);
-                               int permission = PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY;
-                               
-                               PdfEncryption crypto = new PdfEncryption();
-                               //for (Certificate c : chain) crypto.addRecipient(c, permission);
-                               //crypto.addRecipient(chain[2], permission);
-                       crypto.setCryptoMode(PdfWriter.ENCRYPTION_AES_128, 0);
-                               crypto.setupByEncryptionKey(key.getEncoded(), key.getEncoded().length*8);
-                       crypto.getEncryptionDictionary();
-                       
-                               
-                       } catch (Exception e) {
-                               e.printStackTrace();
-                       }*/
-                   
-                   /*
-                   writer.setEncryption(
-                               new Certificate[] {}, 
-                               new int[] {PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING}, 
-                               PdfWriter.STANDARD_ENCRYPTION_128);
-                               */
-                   //writer.setEncryption(PdfWriter.STANDARD_ENCRYPTION_128, "", "password", PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY);
-                       
-                   
-//                     PdfName companyName = new PdfName("SMTC");          
-//                 PdfDeveloperExtension ext = new PdfDeveloperExtension(companyName, PdfWriter.PDF_VERSION_1_7, 3);
-//                 writer.addDeveloperExtension( ext );
-                   
+                    String creator = getCreator();
+                    document.addCreator(creator);
+
+                    /*
+                    File keystoreFile = new File("c:\\0009278.p12");
+                    String password = "ka7GfzI9Oq";
+
+                    try {
+                        KeyStore ks = KeyStore.getInstance("pkcs12");
+                        ks.load(new FileInputStream(keystoreFile), password.toCharArray());
+                        List<String> aliases = Collections.list(ks.aliases());
+                        String alias = aliases.get(0);
+                        PrivateKey key = (PrivateKey)ks.getKey(alias, password.toCharArray());
+                        Certificate[] chain = ks.getCertificateChain(alias);
+                        int permission = PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY;
+
+                        PdfEncryption crypto = new PdfEncryption();
+                        //for (Certificate c : chain) crypto.addRecipient(c, permission);
+                        //crypto.addRecipient(chain[2], permission);
+                        crypto.setCryptoMode(PdfWriter.ENCRYPTION_AES_128, 0);
+                        crypto.setupByEncryptionKey(key.getEncoded(), key.getEncoded().length*8);
+                        crypto.getEncryptionDictionary();
+
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }*/
+
+                    /*
+                    writer.setEncryption(
+                            new Certificate[] {}, 
+                            new int[] {PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING}, 
+                            PdfWriter.STANDARD_ENCRYPTION_128);
+                            */
+                    //writer.setEncryption(PdfWriter.STANDARD_ENCRYPTION_128, "", "password", PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY);
+
+//                    PdfName companyName = new PdfName("SMTC");
+//                    PdfDeveloperExtension ext = new PdfDeveloperExtension(companyName, PdfWriter.PDF_VERSION_1_7, 3);
+//                    writer.addDeveloperExtension( ext );
+
                     document.open();
                 }
 
                 if (!first) {
-                document.setPageSize(pageSize);
-                document.newPage();
+                    document.setPageSize(pageSize);
+                    document.newPage();
                 }
 
                 /*
                 /// ATTACHMENTS - TG ///
                 byte[] attachment = null;
-                       if ( exportPlan.attachTG && !d.getDefiningResources().isEmpty() ) 
+                if ( exportPlan.attachTG && !d.getDefiningResources().isEmpty() ) 
                 try {
                     PdfDictionary fileParameter = new PdfDictionary();
 
-                       {
-                               final Resource composite = d.getDefiningResources().iterator().next();                                          
-                               final Session session = exportPlan.sessionContext.getSession();
-                               
-                           SimanticsClipboard clipboard = session.syncRequest(new Read<SimanticsClipboard>() {
-                               @Override
-                               public SimanticsClipboard perform(ReadGraph graph) throws DatabaseException {
-                                   CopyHandler ch = graph.adapt(composite, CopyHandler.class);
-                                   SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl();
-                                   ch.copyToClipboard(graph, clipboard);
-                                   return clipboard;
-                               }
-                           });
-                           for (Set<Representation> object : clipboard.getContents()) {
-                               TransferableGraph1 tg = ClipboardUtils.accept(object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);
-                               String filename = d.getName()+".diagram";
-                               try {
-                                       byte[] data = DataContainers.writeFile(                                 
-                                               new DataContainer("aprosDiagram", 1, new Variant(TransferableGraph1.BINDING, tg))
-                                       );
-                                           PdfFileSpecification fs = PdfFileSpecification.fileEmbedded(
-                                                       writer, 
-                                                       "/Diagram", filename, data, true, "application/simantics/diagram", 
-                                                       fileParameter);
-                                           writer.addFileAttachment(d.getName()+".diagram", fs);
-                               } catch ( NullPointerException npe ) {
-                                       throw new PdfException("Experiment must be activated to export attachments"+npe.getMessage(), npe);
-                               }
-                           }
-                       }
+                    {
+                        final Resource composite = d.getDefiningResources().iterator().next();
+                        final Session session = exportPlan.sessionContext.getSession();
+
+                        SimanticsClipboard clipboard = session.syncRequest(new Read<SimanticsClipboard>() {
+                            @Override
+                            public SimanticsClipboard perform(ReadGraph graph) throws DatabaseException {
+                                CopyHandler ch = graph.adapt(composite, CopyHandler.class);
+                                SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl();
+                                ch.copyToClipboard(graph, clipboard);
+                                return clipboard;
+                            }
+                        });
+                        for (Set<Representation> object : clipboard.getContents()) {
+                            TransferableGraph1 tg = ClipboardUtils.accept(object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);
+                            String filename = d.getName()+".diagram";
+                            try {
+                                byte[] data = DataContainers.writeFile(
+                                    new DataContainer("aprosDiagram", 1, new Variant(TransferableGraph1.BINDING, tg))
+                                );
+                                PdfFileSpecification fs = PdfFileSpecification.fileEmbedded(
+                                        writer, 
+                                        "/Diagram", filename, data, true, "application/simantics/diagram", 
+                                        fileParameter);
+                                writer.addFileAttachment(d.getName()+".diagram", fs);
+                            } catch ( NullPointerException npe ) {
+                                throw new PdfException("Experiment must be activated to export attachments"+npe.getMessage(), npe);
+                            }
+                        }
+                    }
 
                 } catch (DatabaseException e) {
                     e.printStackTrace();
@@ -215,66 +272,50 @@ public class DiagramPrinter {
                 }
                 */
                 //////////////////////////
-                
+
                 String diagramName = formDiagramName(d, true);
-                String subTask = "Page (" + i + "/" + flattened.size() + "): " + diagramName;
+                String subTask = "Page (" + i + "/" + flattenedNodes.size() + "): " + diagramName;
 
                 Resource diagram = d.getDiagramResource();
                 if (diagram == null) {
                     // No diagram, skip page.
                     subTask += " skipped, no diagram.";
-                    System.out.println(subTask);
+                    LOGGER.info(subTask);
                     continue;
                 }
 
-                System.out.println(subTask);
+                LOGGER.info(subTask);
                 progress.subTask(subTask);
 
                 try {
-                    PDFPainter.render(workerThread, sessionContext, exportPlan, d, writer, mapper,
+                    PDFPainter.render(workerThread, exportPlan, d, writer, mapper,
                             pageSize, d.getPageDesc(), exportPlan.fitContentToPageMargins, 10000);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                } catch (DatabaseException e) {
-                    e.printStackTrace();
+                    ++exportedPages;
+                } catch (DatabaseException | InterruptedException e) {
+                    LOGGER.error("PDF rendering failed.", e);
                 }
 
-                // Paint diagram path/name on the page
-                // TODO: remove this hard coded diagram name printing and
-                // replace it with a page templates that is loaded along with
-                // the rest of the diagram
-
-                int w = (int) pageSize.getWidth();
-                int h = (int) pageSize.getHeight();
-
-                // Write Page Number
-                PdfContentByte cb = writer.getDirectContent();
-
-//                PdfTemplate tp = cb.createTemplate(w, h);
-//                Graphics2D g2d = tp.createGraphics(w, h, mapper);
-//                g2d.setColor(Color.black);
-//                java.awt.Font thisFont = new java.awt.Font("Arial", java.awt.Font.ITALIC, 10);
-//                g2d.setFont(thisFont);
-//                FontMetrics metrics = g2d.getFontMetrics();
-//                int width = metrics.stringWidth(diagramName);
-//                g2d.drawString(diagramName, (w - width) / 2, document.getPageSize().getHeight() - PageDesc.toPoints(5));
-//                g2d.dispose();
-//                cb.addTemplate(tp, 0, 0);
-
                 /// ATTACHMENTS - Write WIKI ///
                 if ( exportPlan.attachWiki && !d.getDefiningResources().isEmpty() ) {
-                    final Session session = exportPlan.sessionContext.getSession();
+                    int w = (int) pageSize.getWidth();
+                    int h = (int) pageSize.getHeight();
+                    PdfContentByte cb = writer.getDirectContent();
+                    Session session = exportPlan.sessionContext.getSession();
                     Resource composite = d.getDefiningResources().iterator().next();
                     DocumentUtils du = new DocumentUtils();
                     StringBuilder wiki = new StringBuilder();
                     StringBuilder css = new StringBuilder();
                     du.getDocumentWikiTextRecursive(session, composite, wiki, css);
-                       DocumentSettings settings = du.getDocumentSettings(session, composite);
+                    DocumentSettings settings = du.getDocumentSettings(session, composite);
                     PdfTemplate tp_ = cb.createTemplate(w, h);
                     if ( wiki.length()>0 ) {
                         String wikiText = wiki.toString();
                         String cssText = css.toString();
-                        du.print(session, composite, wikiText, cssText, settings, tp_.getPdfWriter(), document);
+                        try {
+                            exportedPages += du.print(session, composite, wikiText, cssText, settings, tp_.getPdfWriter(), document);
+                        } catch (DatabaseException | DocumentException e) {
+                            LOGGER.error("Wiki documentation to PDF rendering failed.", e);
+                        }
                     }
                     cb.addTemplate(tp_, 0, 0);
                 }
@@ -286,29 +327,27 @@ public class DiagramPrinter {
                 if (progress.isCanceled())
                     throw new OperationCanceledException();
 
-                System.out.println("GC");
+                LOGGER.trace("GC");
                 SVGCache.getSVGUniverse().clearUnreferenced();
-                SessionGarbageCollection.gc(null, sessionContext.getSession(), true, null);
+                SessionGarbageCollection.gc(null, exportPlan.sessionContext.getSession(), true, null);
                 System.gc();
-                System.out.println("GC finished");
+                LOGGER.trace("GC finished");
                 progress.worked(1);
             }
-               } catch (DatabaseException e) {
-                       throw new PdfException(e);
-               } catch (FileNotFoundException e) {
-                       throw new PdfException(e);
-               } catch (DocumentException e) {
-                       throw new PdfException(e);
-               } finally {
+
+            return exportedPages;
+        } catch (DatabaseException | FileNotFoundException | DocumentException | ExceptionConverter e) {
+            throw new PdfException(e);
+        } finally {
             workerThread.stopDispatchingEvents(true);
-            System.out.println("closing document");
+            LOGGER.trace("closing document");
             try {
-               if ( document!=null ) document.close();
-                if ( writer!=null ) writer.close();
-            } catch(RuntimeException e) {
-               e.printStackTrace();
+                if ( document != null ) document.close();
+                if ( writer != null ) writer.close();
+                LOGGER.trace("document closed");
+            } catch (RuntimeException e) {
+                LOGGER.error("Error closing PDF document writer", e);
             }
-            System.out.println("document closed");
             SessionGarbageCollectorJob.getInstance().setEnabled(true).scheduleAfterQuietTime();
         }
     }
@@ -341,23 +380,23 @@ public class DiagramPrinter {
         return ret;
     }
 
-       public static String getCreator() {
-               String creator = null;
-               IProduct product = Platform.getProduct();
-               if (product != null) {
-                       creator = product.getDescription();
-                       if (creator == null) {
-                               creator = product.getName();
-                       }
-               }
-               if (creator == null) {
-                       creator = "Simantics";
-               }
-               return creator;
-       }
+    public static String getCreator() {
+        String creator = null;
+        IProduct product = Platform.getProduct();
+        if (product != null) {
+            creator = product.getDescription();
+            if (creator == null) {
+                creator = product.getName();
+            }
+        }
+        if (creator == null) {
+            creator = "Simantics";
+        }
+        return creator;
+    }
 
     static {
-               Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
     }
 
 }
\ No newline at end of file
index ba389f77d3cd149d96e8c4d3db788b06983edb8e..f0c9cddb32514610ec850b0bb9b30919e5657516 100644 (file)
@@ -260,9 +260,7 @@ public class PDFDiagramExportWizard extends Wizard implements IExportWizard {
                 @Override
                 public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                     try {
-                       // Print pdf
-                        DiagramPrinter.printToPdf(monitor, exportPlan, exportPlan.exportLocation.toString(), exportPlan.selectedNodes, exportPlan.sessionContext);
-                        
+                        DiagramPrinter.printToPdf(monitor, exportPlan, exportPlan.exportLocation.toString(), exportPlan.selectedNodes);
                     } catch (PdfException e) {
                         throw new InvocationTargetException(e);
                     } finally {
index 88312f67fe27ba54c1ce539e727af99f31811093..a41715f3bc81e64d4eabb0c44323c523541b7c6c 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * Copyright (c) 2007, 2017 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
@@ -8,6 +8,7 @@
  *
  * Contributors:
  *     VTT Technical Research Centre of Finland - initial API and implementation
+ *     Semantum Oy - (#7084) page numbering
  *******************************************************************************/
 package org.simantics.modeling.ui.pdf;
 
@@ -20,6 +21,7 @@ import java.util.Set;
 
 import org.simantics.db.common.NamedResource;
 import org.simantics.db.management.ISessionContext;
+import org.simantics.export.core.pdf.PageNumbering;
 import org.simantics.modeling.requests.CollectionResult;
 import org.simantics.modeling.requests.Node;
 import org.simantics.project.IProject;
@@ -63,8 +65,26 @@ public class PDFExportPlan {
      * <code>true</code> to attach Wiki page.
      */
     public boolean attachWiki = false;
-    
-    
+
+    /**
+     * Whether or not to add page numbers to the exported PDF. Default value is
+     * {@value #addPageNumbers}.
+     * 
+     * @since 1.28.0
+     */
+    public boolean addPageNumbers = true;
+
+    /**
+     * This is ignored if {@link #addPageNumbers} is <code>false</code>.
+     */
+    public PageNumbering.Position pageNumberPosition = PageNumbering.Position.BOTTOM_RIGHT;
+
+    /**
+     * This is ignored if {@link #addPageNumbers} is <code>false</code>.
+     */
+    public PageNumbering.NumberingFormat pageNumberFormat = PageNumbering.NumberingFormat.PAGE_SLASH_TOTAL_PAGES;
+
+
     public PDFExportPlan(ISessionContext sessionContext, Collection<String> recentLocations) {
         this.sessionContext = sessionContext;
         this.recentLocations = recentLocations;
index 85cf4bc08a801fe109b2ce5bf8bc1514b3d159e5..1adcf25c23d33a2b2f7ede11eaf9210697097fb6 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * Copyright (c) 2007, 2017 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
@@ -8,14 +8,15 @@
  *
  * Contributors:
  *     VTT Technical Research Centre of Finland - initial API and implementation
+ *     Semantum Oy - (#7084) refactoring
  *******************************************************************************/
 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.Session;
 import org.simantics.db.common.request.PossibleIndexRoot;
 import org.simantics.db.common.request.UniqueRead;
 import org.simantics.db.common.utils.NameUtils;
@@ -23,7 +24,7 @@ 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.db.request.Read;
 import org.simantics.diagram.elements.DiagramNodeUtil;
 import org.simantics.diagram.stubs.DiagramResource;
 import org.simantics.g2d.canvas.Hints;
@@ -31,7 +32,6 @@ 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;
@@ -48,9 +48,8 @@ import com.lowagie.text.pdf.PdfWriter;
  */
 public class PDFPainter {
 
-    public static boolean render(
+    public static void render(
             final IThreadWorkQueue thread,
-            final ISessionContext sessionContext,
             PDFExportPlan exportModel,
             final Node node,
             final PdfWriter writer,
@@ -59,105 +58,101 @@ public class PDFPainter {
             final PageDesc pageDesc,
             final boolean fitDiagramContentsToPageMargins,
             long timeout)
-    throws InterruptedException, DatabaseException
+                    throws InterruptedException, DatabaseException
     {
-        final DataContainer<Boolean> result = new DataContainer<Boolean>(false);
-        final DataContainer<DatabaseException> exception = new DataContainer<DatabaseException>();
+        DatabaseException[] exception = { null };
+        ICanvasSceneGraphProvider[] sgProvider = { null };
 
-        final CanvasContext ctx = new CanvasContext(thread);
-        final AtomicReference<ICanvasSceneGraphProvider> sgProvider = new AtomicReference<ICanvasSceneGraphProvider>();
+        CanvasContext ctx = new CanvasContext(thread);
 
         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<Resource, String> modelAndRVI = sessionContext.getSession().syncRequest(new UniqueRead<Pair<Resource, String>>() {
-                            @Override
-                            public Pair<Resource, String> perform(ReadGraph graph) throws DatabaseException {
-                                return new Pair<Resource, String>( resolveModel(graph, node), resolveRVI(graph, node) );
-                            }
-                        });
-                        
-                        final Boolean isSymbol = sessionContext.getSession().syncRequest(new UniqueRead<Boolean>() {
-                            @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();
-                    }
+            ThreadUtils.getBlockingWorkExecutor().execute(() -> {
+                try {
+                    Session s = exportModel.sessionContext.getSession();
+
+                    Pair<Resource, String> modelAndRVI = s.syncRequest( modelAndRVI(node) );
+                    Boolean isSymbol = s.syncRequest( isSymbol(node) ); 
+
+                    ICanvasSceneGraphProvider provider = DiagramNodeUtil.loadSceneGraphProvider(
+                            ctx,
+                            modelAndRVI.first,
+                            node.getDiagramResource(),
+                            modelAndRVI.second,
+                            5000);
+                    sgProvider[0] = provider;
+                    ctx.getDefaultHintContext().setHint(Hints.KEY_PAGE_DESC, pageDesc);
+
+//                    System.err.println(NodeUtil.printTreeNodes(ctx.getCanvasNode(), new StringBuilder()).toString());
+
+                    ThreadUtils.asyncExec(thread, () -> {
+                        try {
+                            PDFBuilder chassis = new PDFBuilder(writer, mapper, pageSize, pageDesc, fitDiagramContentsToPageMargins || isSymbol);
+                            chassis.paint(ctx, true);
+                        } catch (Throwable e) {
+                            exception[0] = new DatabaseException(e);
+                        } finally {
+                            done.release();
+                        }
+                    });
+                } catch (DatabaseException e) {
+                    done.release();
+                    exception[0] = e;
+                } catch (Throwable e) {
+                    done.release();
+                    exception[0] = new DatabaseException(e);
+                } finally {
+                    done.release();
                 }
             });
 
             done.acquire(2);
-            if (exception.get() != null)
-                throw exception.get();
-            return result.get();
+            if (exception[0] != null)
+                throw exception[0];
         } finally {
-            if (sgProvider.get() != null)
-                sgProvider.get().dispose();
+            if (sgProvider[0] != null)
+                sgProvider[0].dispose();
             ctx.dispose();
         }
     }
 
+    private static Read<Pair<Resource, String>> modelAndRVI(Node node) {
+        return new UniqueRead<Pair<Resource, String>>() {
+            @Override
+            public Pair<Resource, String> perform(ReadGraph graph) throws DatabaseException {
+                return Pair.make( resolveModel(graph, node), resolveRVI(graph, node) );
+            }
+        };
+    }
+
+    private static Read<Boolean> isSymbol(Node node) {
+        return new UniqueRead<Boolean>() {
+            @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);
+            }
+        };
+    }
+
     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;
+        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);
+        return rvi != null ? rvi.toString() : null;
     }
 
-}
+}
\ No newline at end of file
index 80b9a8a52c288207c5eb56f1c9ffc5989d0ddd5e..c3bb2144108256319a21368469d2385216db658e 100644 (file)
@@ -336,11 +336,12 @@ public final class NodeUtil {
         return result;
     }
 
-    public static final void printTreeNodes(INode node, StringBuilder builder) {
+    public static final StringBuilder printTreeNodes(INode node, StringBuilder builder) {
         printTreeNodes(node, 0, builder);
+        return builder;
     }
 
-    public static final void printTreeNodes(INode node, int indent, StringBuilder builder) {
+    public static final StringBuilder printTreeNodes(INode node, int indent, StringBuilder builder) {
         for (int i = 0; i < indent; i++)
             builder.append(" ");
         builder.append(node.toString() + "\n");
@@ -351,6 +352,7 @@ public final class NodeUtil {
                 printTreeNodes(n, indent+2, builder);
             }
         }
+        return builder;
     }
 
     public static final <T extends INode> Set<T> collectNodes(INode node, Class<T> clazz) {
index eba35a5715748ace20ead2fd7ed4e8ce0ca67083..492fd1928ef89ab1632f3fe0a792b5c17f4af89f 100644 (file)
@@ -16,5 +16,11 @@ import com.lowagie.text.DocumentException;
 import com.lowagie.text.pdf.PdfWriter;
 
 public interface IExportable {
-       public void export(Document doc, PdfWriter writer) throws DocumentException;
+       /**
+        * @param doc
+        * @param writer
+        * @return the amount of PDF pages exported
+        * @throws DocumentException
+        */
+       public int export(Document doc, PdfWriter writer) throws DocumentException;
 }