]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/DiagramPrinter.java
Sync git svn branch with SVN repository r33173.
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / pdf / DiagramPrinter.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.modeling.ui.pdf;\r
13 \r
14 import java.io.FileNotFoundException;\r
15 import java.io.FileOutputStream;\r
16 import java.security.Security;\r
17 import java.util.Collection;\r
18 import java.util.concurrent.atomic.AtomicBoolean;\r
19 \r
20 import org.eclipse.core.runtime.IProduct;\r
21 import org.eclipse.core.runtime.IProgressMonitor;\r
22 import org.eclipse.core.runtime.OperationCanceledException;\r
23 import org.eclipse.core.runtime.Platform;\r
24 import org.eclipse.core.runtime.SubMonitor;\r
25 import org.simantics.db.RequestProcessor;\r
26 import org.simantics.db.Resource;\r
27 import org.simantics.db.Session;\r
28 import org.simantics.db.exception.DatabaseException;\r
29 import org.simantics.db.layer0.util.SessionGarbageCollection;\r
30 import org.simantics.db.management.ISessionContext;\r
31 import org.simantics.document.DocumentSettings;\r
32 import org.simantics.document.DocumentUtils;\r
33 import org.simantics.export.core.pdf.ServiceBasedPdfExportPageEvent;\r
34 import org.simantics.modeling.requests.CollectionRequest;\r
35 import org.simantics.modeling.requests.CollectionResult;\r
36 import org.simantics.modeling.requests.Node;\r
37 import org.simantics.modeling.ui.preferences.DiagramPreferenceUtil;\r
38 import org.simantics.ui.jobs.SessionGarbageCollectorJob;\r
39 import org.simantics.utils.page.PageDesc;\r
40 import org.simantics.utils.page.PageOrientation;\r
41 import org.simantics.utils.threads.WorkerThread;\r
42 \r
43 import com.kitfox.svg.SVGCache;\r
44 import com.lowagie.text.Document;\r
45 import com.lowagie.text.DocumentException;\r
46 import com.lowagie.text.FontFactory;\r
47 import com.lowagie.text.PageSize;\r
48 import com.lowagie.text.Rectangle;\r
49 import com.lowagie.text.pdf.DefaultFontMapper;\r
50 import com.lowagie.text.pdf.PdfBoolean;\r
51 import com.lowagie.text.pdf.PdfContentByte;\r
52 import com.lowagie.text.pdf.PdfName;\r
53 import com.lowagie.text.pdf.PdfTemplate;\r
54 import com.lowagie.text.pdf.PdfWriter;\r
55 \r
56 public class DiagramPrinter {\r
57 \r
58     public static CollectionResult browse(IProgressMonitor monitor, RequestProcessor processor, Resource[] input) throws DatabaseException {\r
59         final CollectionResult result = processor.syncRequest(new CollectionRequest(monitor, DiagramPreferenceUtil.getDefaultPreferences().getCompletePageDesc(), input));\r
60         return result;\r
61     }\r
62 \r
63     private static final AtomicBoolean fontFactoryInitialized = new AtomicBoolean();\r
64 \r
65     /**\r
66      * @param monitor the progress monitor to use for reporting progress to the\r
67      *        user. It is the caller's responsibility to call done() on the\r
68      *        given monitor. Accepts <code>null</code>, indicating that no\r
69      *        progress should be reported and that the operation cannot be\r
70      *        cancelled.\r
71      * \r
72      * @param exportPath\r
73      * @param flattenedNodes\r
74      * @param sessionContext\r
75      * @throws DocumentException\r
76      * @throws FileNotFoundException\r
77      */\r
78     public static void printToPdf(\r
79                 IProgressMonitor monitor, \r
80                 PDFExportPlan exportPlan, \r
81                 String exportPath, \r
82                 Collection<Node> flattenedNodes,\r
83             ISessionContext sessionContext) \r
84     throws PdfException {\r
85         Collection<Node> flattened = flattenedNodes;\r
86 \r
87         SubMonitor progress = SubMonitor.convert(monitor, "Export to PDF", flattened.size() * 2);\r
88 \r
89         WorkerThread workerThread = new WorkerThread("Diagram PDF Painter");\r
90         workerThread.start();\r
91 \r
92         PdfWriter writer = null;\r
93         Document document = null;\r
94 \r
95         try {\r
96             progress.subTask("Loading system fonts");\r
97             DefaultFontMapper mapper = new DefaultFontMapper();\r
98             if (fontFactoryInitialized.compareAndSet(false, true)) {\r
99                 // Only register directories once.\r
100                 FontFactory.registerDirectories();\r
101             }\r
102 \r
103             SessionGarbageCollectorJob.getInstance().setEnabled(false);\r
104 \r
105 \r
106             boolean first = true;           \r
107             int i = 0;\r
108             for (Node d : flattened) {\r
109                 ++i;\r
110                 \r
111                 //System.out.println("PAGE DESC: " + d.getPageDesc());\r
112                 //System.out.println("PAGE SIZE: " + pageSize);\r
113 \r
114                 Rectangle pageSize = toPageSize(d.getPageDesc());\r
115                 if (writer == null) {\r
116                     document = new Document(pageSize);\r
117                     writer = PdfWriter.getInstance(document, new FileOutputStream(exportPath));\r
118                     writer.setPdfVersion(PdfWriter.PDF_VERSION_1_7);\r
119                     writer.setPageEvent(new ServiceBasedPdfExportPageEvent());\r
120                     if ( exportPlan.attachTG ) {\r
121                         writer.addViewerPreference(PdfName.USEATTACHMENTS, PdfBoolean.PDFTRUE);\r
122                     }\r
123    \r
124                     String creator = getCreator();\r
125                     document.addCreator(creator);\r
126 \r
127                     /*\r
128                         File keystoreFile = new File("c:\\0009278.p12");\r
129                         String password = "ka7GfzI9Oq";\r
130 \r
131                         try {\r
132                                 KeyStore ks = KeyStore.getInstance("pkcs12");\r
133                                 ks.load(new FileInputStream(keystoreFile), password.toCharArray());\r
134                                 List<String> aliases = Collections.list(ks.aliases());\r
135                                 String alias = aliases.get(0);\r
136                                 PrivateKey key = (PrivateKey)ks.getKey(alias, password.toCharArray());\r
137                                 Certificate[] chain = ks.getCertificateChain(alias);\r
138                                 int permission = PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY;\r
139                                 \r
140                                 PdfEncryption crypto = new PdfEncryption();\r
141                                 //for (Certificate c : chain) crypto.addRecipient(c, permission);\r
142                                 //crypto.addRecipient(chain[2], permission);\r
143                         crypto.setCryptoMode(PdfWriter.ENCRYPTION_AES_128, 0);\r
144                                 crypto.setupByEncryptionKey(key.getEncoded(), key.getEncoded().length*8);\r
145                         crypto.getEncryptionDictionary();\r
146                         \r
147                                 \r
148                         } catch (Exception e) {\r
149                                 e.printStackTrace();\r
150                         }*/\r
151                     \r
152                     /*\r
153                     writer.setEncryption(\r
154                                 new Certificate[] {}, \r
155                                 new int[] {PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING}, \r
156                                 PdfWriter.STANDARD_ENCRYPTION_128);\r
157                                 */\r
158                     //writer.setEncryption(PdfWriter.STANDARD_ENCRYPTION_128, "", "password", PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY);\r
159                         \r
160                     \r
161 //                      PdfName companyName = new PdfName("SMTC");          \r
162 //                  PdfDeveloperExtension ext = new PdfDeveloperExtension(companyName, PdfWriter.PDF_VERSION_1_7, 3);\r
163 //                  writer.addDeveloperExtension( ext );\r
164                     \r
165                     document.open();\r
166                 }\r
167 \r
168                 if (!first) {\r
169                 document.setPageSize(pageSize);\r
170                 document.newPage();\r
171                 }\r
172 \r
173                 /*\r
174                 /// ATTACHMENTS - TG ///\r
175                 byte[] attachment = null;\r
176                 if ( exportPlan.attachTG && !d.getDefiningResources().isEmpty() ) \r
177                 try {\r
178                     PdfDictionary fileParameter = new PdfDictionary();\r
179 \r
180                         {\r
181                                 final Resource composite = d.getDefiningResources().iterator().next();                                          \r
182                                 final Session session = exportPlan.sessionContext.getSession();\r
183                                 \r
184                             SimanticsClipboard clipboard = session.syncRequest(new Read<SimanticsClipboard>() {\r
185                                 @Override\r
186                                 public SimanticsClipboard perform(ReadGraph graph) throws DatabaseException {\r
187                                     CopyHandler ch = graph.adapt(composite, CopyHandler.class);\r
188                                     SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl();\r
189                                     ch.copyToClipboard(graph, clipboard);\r
190                                     return clipboard;\r
191                                 }\r
192                             });\r
193                             for (Set<Representation> object : clipboard.getContents()) {\r
194                                 TransferableGraph1 tg = ClipboardUtils.accept(object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);\r
195                                 String filename = d.getName()+".diagram";\r
196                                 try {\r
197                                         byte[] data = DataContainers.writeFile(                                 \r
198                                                 new DataContainer("aprosDiagram", 1, new Variant(TransferableGraph1.BINDING, tg))\r
199                                         );\r
200                                             PdfFileSpecification fs = PdfFileSpecification.fileEmbedded(\r
201                                                         writer, \r
202                                                         "/Diagram", filename, data, true, "application/simantics/diagram", \r
203                                                         fileParameter);\r
204                                             writer.addFileAttachment(d.getName()+".diagram", fs);\r
205                                 } catch ( NullPointerException npe ) {\r
206                                         throw new PdfException("Experiment must be activated to export attachments"+npe.getMessage(), npe);\r
207                                 }\r
208                             }\r
209                         }\r
210 \r
211                 } catch (DatabaseException e) {\r
212                     e.printStackTrace();\r
213                 } catch (IOException e) {\r
214                     e.printStackTrace();\r
215                 }\r
216                 */\r
217                 //////////////////////////\r
218                 \r
219                 String diagramName = formDiagramName(d, true);\r
220                 String subTask = "Page (" + i + "/" + flattened.size() + "): " + diagramName;\r
221 \r
222                 Resource diagram = d.getDiagramResource();\r
223                 if (diagram == null) {\r
224                     // No diagram, skip page.\r
225                     subTask += " skipped, no diagram.";\r
226                     System.out.println(subTask);\r
227                     continue;\r
228                 }\r
229 \r
230                 System.out.println(subTask);\r
231                 progress.subTask(subTask);\r
232 \r
233                 try {\r
234                     PDFPainter.render(workerThread, sessionContext, exportPlan, d, writer, mapper,\r
235                             pageSize, d.getPageDesc(), exportPlan.fitContentToPageMargins, 10000);\r
236                 } catch (InterruptedException e) {\r
237                     e.printStackTrace();\r
238                 } catch (DatabaseException e) {\r
239                     e.printStackTrace();\r
240                 }\r
241 \r
242                 // Paint diagram path/name on the page\r
243                 // TODO: remove this hard coded diagram name printing and\r
244                 // replace it with a page templates that is loaded along with\r
245                 // the rest of the diagram\r
246 \r
247                 int w = (int) pageSize.getWidth();\r
248                 int h = (int) pageSize.getHeight();\r
249 \r
250                 // Write Page Number\r
251                 PdfContentByte cb = writer.getDirectContent();\r
252 \r
253 //                PdfTemplate tp = cb.createTemplate(w, h);\r
254 //                Graphics2D g2d = tp.createGraphics(w, h, mapper);\r
255 //                g2d.setColor(Color.black);\r
256 //                java.awt.Font thisFont = new java.awt.Font("Arial", java.awt.Font.ITALIC, 10);\r
257 //                g2d.setFont(thisFont);\r
258 //                FontMetrics metrics = g2d.getFontMetrics();\r
259 //                int width = metrics.stringWidth(diagramName);\r
260 //                g2d.drawString(diagramName, (w - width) / 2, document.getPageSize().getHeight() - PageDesc.toPoints(5));\r
261 //                g2d.dispose();\r
262 //                cb.addTemplate(tp, 0, 0);\r
263 \r
264                 /// ATTACHMENTS - Write WIKI ///\r
265                 if ( exportPlan.attachWiki && !d.getDefiningResources().isEmpty() ) {\r
266                     final Session session = exportPlan.sessionContext.getSession();\r
267                     Resource composite = d.getDefiningResources().iterator().next();\r
268                     DocumentUtils du = new DocumentUtils();\r
269                     StringBuilder wiki = new StringBuilder();\r
270                     StringBuilder css = new StringBuilder();\r
271                     du.getDocumentWikiTextRecursive(session, composite, wiki, css);\r
272                         DocumentSettings settings = du.getDocumentSettings(session, composite);\r
273                     PdfTemplate tp_ = cb.createTemplate(w, h);\r
274                     if ( wiki.length()>0 ) {\r
275                         String wikiText = wiki.toString();\r
276                         String cssText = css.toString();\r
277                         du.print(session, composite, wikiText, cssText, settings, tp_.getPdfWriter(), document);\r
278                     }\r
279                     cb.addTemplate(tp_, 0, 0);\r
280                 }\r
281                 //////////////////////////\r
282 \r
283                 progress.worked(1);\r
284                 first = false;\r
285 \r
286                 if (progress.isCanceled())\r
287                     throw new OperationCanceledException();\r
288 \r
289                 System.out.println("GC");\r
290                 SVGCache.getSVGUniverse().clearUnreferenced();\r
291                 SessionGarbageCollection.gc(null, sessionContext.getSession(), true, null);\r
292                 System.gc();\r
293                 System.out.println("GC finished");\r
294                 progress.worked(1);\r
295             }\r
296                 } catch (DatabaseException e) {\r
297                         throw new PdfException(e);\r
298                 } catch (FileNotFoundException e) {\r
299                         throw new PdfException(e);\r
300                 } catch (DocumentException e) {\r
301                         throw new PdfException(e);\r
302                 } finally {\r
303             workerThread.stopDispatchingEvents(true);\r
304             System.out.println("closing document");\r
305             try {\r
306                 if ( document!=null ) document.close();\r
307                 if ( writer!=null ) writer.close();\r
308             } catch(RuntimeException e) {\r
309                 e.printStackTrace();\r
310             }\r
311             System.out.println("document closed");\r
312             SessionGarbageCollectorJob.getInstance().setEnabled(true).scheduleAfterQuietTime();\r
313         }\r
314     }\r
315 \r
316     public static Rectangle toPageSize(PageDesc pageDesc) {\r
317         String arg = PageDesc.toPoints(pageDesc.getWidth()) + " " + PageDesc.toPoints(pageDesc.getHeight());\r
318         Rectangle r = PageSize.getRectangle(arg);\r
319 \r
320         if (PageOrientation.Landscape == pageDesc.getOrientation())\r
321             r = r.rotate();\r
322 \r
323         // Disable inherent borders from the PDF writer.\r
324         r.setBorder(0);\r
325 \r
326         return r;\r
327     }\r
328 \r
329     public static String formDiagramName(Node node, boolean parents) {\r
330         Node d = node;\r
331         String ret = d.getName();\r
332         if (parents) {\r
333             while (d.getParent() != null) {\r
334                 d = d.getParent();\r
335                 ret = d.getName() + " / " + ret;\r
336             }\r
337         }\r
338 //        String[] pg = node.getPartOfGroups();\r
339 //        if (pg.length > 0)\r
340 //            ret += " [" + EString.implode(pg, " / ") + " / " + node.getName() + "]";\r
341         return ret;\r
342     }\r
343 \r
344         public static String getCreator() {\r
345                 String creator = null;\r
346                 IProduct product = Platform.getProduct();\r
347                 if (product != null) {\r
348                         creator = product.getDescription();\r
349                         if (creator == null) {\r
350                                 creator = product.getName();\r
351                         }\r
352                 }\r
353                 if (creator == null) {\r
354                         creator = "Simantics";\r
355                 }\r
356                 return creator;\r
357         }\r
358 \r
359     static {\r
360                 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());\r
361     }\r
362 \r
363 }