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