--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.modeling.ui.pdf;\r
+\r
+import java.io.FileNotFoundException;\r
+import java.io.FileOutputStream;\r
+import java.security.Security;\r
+import java.util.Collection;\r
+import java.util.concurrent.atomic.AtomicBoolean;\r
+\r
+import org.eclipse.core.runtime.IProduct;\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.OperationCanceledException;\r
+import org.eclipse.core.runtime.Platform;\r
+import org.eclipse.core.runtime.SubMonitor;\r
+import org.simantics.db.RequestProcessor;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.util.SessionGarbageCollection;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.document.DocumentSettings;\r
+import org.simantics.document.DocumentUtils;\r
+import org.simantics.modeling.requests.CollectionRequest;\r
+import org.simantics.modeling.requests.CollectionResult;\r
+import org.simantics.modeling.requests.Node;\r
+import org.simantics.modeling.ui.preferences.DiagramPreferenceUtil;\r
+import org.simantics.ui.jobs.SessionGarbageCollectorJob;\r
+import org.simantics.utils.page.PageDesc;\r
+import org.simantics.utils.page.PageOrientation;\r
+import org.simantics.utils.threads.WorkerThread;\r
+\r
+import com.kitfox.svg.SVGCache;\r
+import com.lowagie.text.Document;\r
+import com.lowagie.text.DocumentException;\r
+import com.lowagie.text.FontFactory;\r
+import com.lowagie.text.PageSize;\r
+import com.lowagie.text.Rectangle;\r
+import com.lowagie.text.pdf.DefaultFontMapper;\r
+import com.lowagie.text.pdf.PdfBoolean;\r
+import com.lowagie.text.pdf.PdfContentByte;\r
+import com.lowagie.text.pdf.PdfName;\r
+import com.lowagie.text.pdf.PdfTemplate;\r
+import com.lowagie.text.pdf.PdfWriter;\r
+\r
+public class DiagramPrinter {\r
+\r
+ public static CollectionResult browse(IProgressMonitor monitor, RequestProcessor processor, Resource[] input) throws DatabaseException {\r
+ final CollectionResult result = processor.syncRequest(new CollectionRequest(monitor, DiagramPreferenceUtil.getDefaultPreferences().getCompletePageDesc(), input));\r
+ return result;\r
+ }\r
+\r
+ private static final AtomicBoolean fontFactoryInitialized = new AtomicBoolean();\r
+\r
+ /**\r
+ * @param monitor the progress monitor to use for reporting progress to the\r
+ * user. It is the caller's responsibility to call done() on the\r
+ * given monitor. Accepts <code>null</code>, indicating that no\r
+ * progress should be reported and that the operation cannot be\r
+ * cancelled.\r
+ * \r
+ * @param exportPath\r
+ * @param flattenedNodes\r
+ * @param sessionContext\r
+ * @throws DocumentException\r
+ * @throws FileNotFoundException\r
+ */\r
+ public static void printToPdf(\r
+ IProgressMonitor monitor, \r
+ PDFExportPlan exportPlan, \r
+ String exportPath, \r
+ Collection<Node> flattenedNodes,\r
+ ISessionContext sessionContext) \r
+ throws PdfException {\r
+ Collection<Node> flattened = flattenedNodes;\r
+\r
+ SubMonitor progress = SubMonitor.convert(monitor, "Export to PDF", flattened.size() * 2);\r
+\r
+ WorkerThread workerThread = new WorkerThread("Diagram PDF Painter");\r
+ workerThread.start();\r
+\r
+ PdfWriter writer = null;\r
+ Document document = null;\r
+\r
+ try {\r
+ progress.subTask("Loading system fonts");\r
+ DefaultFontMapper mapper = new DefaultFontMapper();\r
+ if (fontFactoryInitialized.compareAndSet(false, true)) {\r
+ // Only register directories once.\r
+ FontFactory.registerDirectories();\r
+ }\r
+\r
+ SessionGarbageCollectorJob.getInstance().setEnabled(false);\r
+\r
+\r
+ boolean first = true; \r
+ int i = 0;\r
+ for (Node d : flattened) {\r
+ ++i;\r
+ \r
+ //System.out.println("PAGE DESC: " + d.getPageDesc());\r
+ //System.out.println("PAGE SIZE: " + pageSize);\r
+\r
+ Rectangle pageSize = toPageSize(d.getPageDesc());\r
+ if (writer == null) {\r
+ document = new Document(pageSize);\r
+ writer = PdfWriter.getInstance(document, new FileOutputStream(exportPath));\r
+ writer.setPdfVersion(PdfWriter.PDF_VERSION_1_7);\r
+ if ( exportPlan.attachTG ) {\r
+ writer.addViewerPreference(PdfName.USEATTACHMENTS, PdfBoolean.PDFTRUE);\r
+ }\r
+ \r
+ String creator = getCreator();\r
+ document.addCreator(creator);\r
+\r
+ /*\r
+ File keystoreFile = new File("c:\\0009278.p12");\r
+ String password = "ka7GfzI9Oq";\r
+\r
+ try {\r
+ KeyStore ks = KeyStore.getInstance("pkcs12");\r
+ ks.load(new FileInputStream(keystoreFile), password.toCharArray());\r
+ List<String> aliases = Collections.list(ks.aliases());\r
+ String alias = aliases.get(0);\r
+ PrivateKey key = (PrivateKey)ks.getKey(alias, password.toCharArray());\r
+ Certificate[] chain = ks.getCertificateChain(alias);\r
+ int permission = PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY;\r
+ \r
+ PdfEncryption crypto = new PdfEncryption();\r
+ //for (Certificate c : chain) crypto.addRecipient(c, permission);\r
+ //crypto.addRecipient(chain[2], permission);\r
+ crypto.setCryptoMode(PdfWriter.ENCRYPTION_AES_128, 0);\r
+ crypto.setupByEncryptionKey(key.getEncoded(), key.getEncoded().length*8);\r
+ crypto.getEncryptionDictionary();\r
+ \r
+ \r
+ } catch (Exception e) {\r
+ e.printStackTrace();\r
+ }*/\r
+ \r
+ /*\r
+ writer.setEncryption(\r
+ new Certificate[] {}, \r
+ new int[] {PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING}, \r
+ PdfWriter.STANDARD_ENCRYPTION_128);\r
+ */\r
+ //writer.setEncryption(PdfWriter.STANDARD_ENCRYPTION_128, "", "password", PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY);\r
+ \r
+ \r
+// PdfName companyName = new PdfName("SMTC"); \r
+// PdfDeveloperExtension ext = new PdfDeveloperExtension(companyName, PdfWriter.PDF_VERSION_1_7, 3);\r
+// writer.addDeveloperExtension( ext );\r
+ \r
+ document.open();\r
+ }\r
+\r
+ if (!first) {\r
+ document.setPageSize(pageSize);\r
+ document.newPage();\r
+ }\r
+\r
+ /*\r
+ /// ATTACHMENTS - TG ///\r
+ byte[] attachment = null;\r
+ if ( exportPlan.attachTG && !d.getDefiningResources().isEmpty() ) \r
+ try {\r
+ PdfDictionary fileParameter = new PdfDictionary();\r
+\r
+ {\r
+ final Resource composite = d.getDefiningResources().iterator().next(); \r
+ final Session session = exportPlan.sessionContext.getSession();\r
+ \r
+ SimanticsClipboard clipboard = session.syncRequest(new Read<SimanticsClipboard>() {\r
+ @Override\r
+ public SimanticsClipboard perform(ReadGraph graph) throws DatabaseException {\r
+ CopyHandler ch = graph.adapt(composite, CopyHandler.class);\r
+ SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl();\r
+ ch.copyToClipboard(graph, clipboard);\r
+ return clipboard;\r
+ }\r
+ });\r
+ for (Set<Representation> object : clipboard.getContents()) {\r
+ TransferableGraph1 tg = ClipboardUtils.accept(object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);\r
+ String filename = d.getName()+".diagram";\r
+ try {\r
+ byte[] data = DataContainers.writeFile( \r
+ new DataContainer("aprosDiagram", 1, new Variant(TransferableGraph1.BINDING, tg))\r
+ );\r
+ PdfFileSpecification fs = PdfFileSpecification.fileEmbedded(\r
+ writer, \r
+ "/Diagram", filename, data, true, "application/simantics/diagram", \r
+ fileParameter);\r
+ writer.addFileAttachment(d.getName()+".diagram", fs);\r
+ } catch ( NullPointerException npe ) {\r
+ throw new PdfException("Experiment must be activated to export attachments"+npe.getMessage(), npe);\r
+ }\r
+ }\r
+ }\r
+\r
+ } catch (DatabaseException e) {\r
+ e.printStackTrace();\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ }\r
+ */\r
+ //////////////////////////\r
+ \r
+ String diagramName = formDiagramName(d, true);\r
+ String subTask = "Page (" + i + "/" + flattened.size() + "): " + diagramName;\r
+\r
+ Resource diagram = d.getDiagramResource();\r
+ if (diagram == null) {\r
+ // No diagram, skip page.\r
+ subTask += " skipped, no diagram.";\r
+ System.out.println(subTask);\r
+ continue;\r
+ }\r
+\r
+ System.out.println(subTask);\r
+ progress.subTask(subTask);\r
+\r
+ try {\r
+ PDFPainter.render(workerThread, sessionContext, exportPlan, d, writer, mapper,\r
+ pageSize, d.getPageDesc(), exportPlan.fitContentToPageMargins, 10000);\r
+ } catch (InterruptedException e) {\r
+ e.printStackTrace();\r
+ } catch (DatabaseException e) {\r
+ e.printStackTrace();\r
+ }\r
+\r
+ // Paint diagram path/name on the page\r
+ // TODO: remove this hard coded diagram name printing and\r
+ // replace it with a page templates that is loaded along with\r
+ // the rest of the diagram\r
+\r
+ int w = (int) pageSize.getWidth();\r
+ int h = (int) pageSize.getHeight();\r
+\r
+ // Write Page Number\r
+ PdfContentByte cb = writer.getDirectContent();\r
+\r
+// PdfTemplate tp = cb.createTemplate(w, h);\r
+// Graphics2D g2d = tp.createGraphics(w, h, mapper);\r
+// g2d.setColor(Color.black);\r
+// java.awt.Font thisFont = new java.awt.Font("Arial", java.awt.Font.ITALIC, 10);\r
+// g2d.setFont(thisFont);\r
+// FontMetrics metrics = g2d.getFontMetrics();\r
+// int width = metrics.stringWidth(diagramName);\r
+// g2d.drawString(diagramName, (w - width) / 2, document.getPageSize().getHeight() - PageDesc.toPoints(5));\r
+// g2d.dispose();\r
+// cb.addTemplate(tp, 0, 0);\r
+\r
+ /// ATTACHMENTS - Write WIKI ///\r
+ if ( exportPlan.attachWiki && !d.getDefiningResources().isEmpty() ) {\r
+ final Session session = exportPlan.sessionContext.getSession();\r
+ Resource composite = d.getDefiningResources().iterator().next();\r
+ DocumentUtils du = new DocumentUtils();\r
+ StringBuilder wiki = new StringBuilder();\r
+ StringBuilder css = new StringBuilder();\r
+ du.getDocumentWikiTextRecursive(session, composite, wiki, css);\r
+ DocumentSettings settings = du.getDocumentSettings(session, composite);\r
+ PdfTemplate tp_ = cb.createTemplate(w, h);\r
+ if ( wiki.length()>0 ) {\r
+ String wikiText = wiki.toString();\r
+ String cssText = css.toString();\r
+ du.print(session, composite, wikiText, cssText, settings, tp_.getPdfWriter(), document);\r
+ }\r
+ cb.addTemplate(tp_, 0, 0);\r
+ }\r
+ //////////////////////////\r
+\r
+ progress.worked(1);\r
+ first = false;\r
+\r
+ if (progress.isCanceled())\r
+ throw new OperationCanceledException();\r
+\r
+ System.out.println("GC");\r
+ SVGCache.getSVGUniverse().clearUnreferenced();\r
+ SessionGarbageCollection.gc(null, sessionContext.getSession(), true, null);\r
+ System.gc();\r
+ System.out.println("GC finished");\r
+ progress.worked(1);\r
+ }\r
+ } catch (DatabaseException e) {\r
+ throw new PdfException(e);\r
+ } catch (FileNotFoundException e) {\r
+ throw new PdfException(e);\r
+ } catch (DocumentException e) {\r
+ throw new PdfException(e);\r
+ } finally {\r
+ workerThread.stopDispatchingEvents(true);\r
+ System.out.println("closing document");\r
+ try {\r
+ if ( document!=null ) document.close();\r
+ if ( writer!=null ) writer.close();\r
+ } catch(RuntimeException e) {\r
+ e.printStackTrace();\r
+ }\r
+ System.out.println("document closed");\r
+ SessionGarbageCollectorJob.getInstance().setEnabled(true).scheduleAfterQuietTime();\r
+ }\r
+ }\r
+\r
+ public static Rectangle toPageSize(PageDesc pageDesc) {\r
+ String arg = PageDesc.toPoints(pageDesc.getWidth()) + " " + PageDesc.toPoints(pageDesc.getHeight());\r
+ Rectangle r = PageSize.getRectangle(arg);\r
+\r
+ if (PageOrientation.Landscape == pageDesc.getOrientation())\r
+ r = r.rotate();\r
+\r
+ // Disable inherent borders from the PDF writer.\r
+ r.setBorder(0);\r
+\r
+ return r;\r
+ }\r
+\r
+ public static String formDiagramName(Node node, boolean parents) {\r
+ Node d = node;\r
+ String ret = d.getName();\r
+ if (parents) {\r
+ while (d.getParent() != null) {\r
+ d = d.getParent();\r
+ ret = d.getName() + " / " + ret;\r
+ }\r
+ }\r
+// String[] pg = node.getPartOfGroups();\r
+// if (pg.length > 0)\r
+// ret += " [" + EString.implode(pg, " / ") + " / " + node.getName() + "]";\r
+ return ret;\r
+ }\r
+\r
+ public static String getCreator() {\r
+ String creator = null;\r
+ IProduct product = Platform.getProduct();\r
+ if (product != null) {\r
+ creator = product.getDescription();\r
+ if (creator == null) {\r
+ creator = product.getName();\r
+ }\r
+ }\r
+ if (creator == null) {\r
+ creator = "Simantics";\r
+ }\r
+ return creator;\r
+ }\r
+\r
+ static {\r
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());\r
+ }\r
+\r
+}
\ No newline at end of file