1   /****************************************************************************
2    **
3    ** This file is part of the yFiles extension package yExport-1.3.
4    ** 
5    ** yWorks proprietary/confidential. Use is subject to license terms.
6    **
7    ** Redistribution of this file or of an unauthorized byte-code version
8    ** of this file is strictly forbidden.
9    **
10   ** Copyright (c) 2007-2012 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  
15  package demo.yext.export;
16  
17  
18  import y.view.YRenderingHints;
19  import yext.export.io.PDFOutputHandler;
20  
21  import y.base.EdgeCursor;
22  import y.base.NodeCursor;
23  import y.option.ConstraintManager;
24  import y.option.OptionGroup;
25  import y.option.OptionHandler;
26  import y.option.OptionItem;
27  import y.geom.YPoint;
28  import y.view.BackgroundRenderer;
29  import y.view.EdgeRealizer;
30  import y.view.Graph2D;
31  import y.view.Graph2DView;
32  import y.view.NodeRealizer;
33  
34  import java.awt.Dimension;
35  import java.awt.Insets;
36  import java.awt.Point;
37  import java.awt.Rectangle;
38  import java.awt.event.ActionEvent;
39  import java.awt.print.PageFormat;
40  import java.net.URL;
41  import javax.swing.AbstractAction;
42  import javax.swing.Action;
43  import javax.swing.JButton;
44  import javax.swing.JToolBar;
45  import javax.print.attribute.standard.MediaSize;
46  import javax.print.attribute.standard.MediaSizeName;
47  
48  
49  /**
50   * Demonstrates how to export a graph to PDF format.
51   * Additionally, the demo allows to specify a preferred page format for
52   * the PDF export.
53   * It uses a custom background renderer to provide an indication on whether the
54   * graph to be exported will fit on the specified page.
55   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/export_usage.html#export_usage">Using the yExport Extension Package</a> in the yFiles for Java Developer's Guide
56   */
57  public class PDFExportDemo extends AbstractExportDemo {
58    private static final String ACTIVATE_TILING = "Activate Tiling";
59    private static final String RENDER_TEXT_AS_SHAPES = "Render Text as Shapes";
60    private static final String EMBED_FONTS = "Embed Fonts";
61  
62    private static final String LANDSCAPE = "Landscape";
63    private static final String PORTRAIT  = "Portrait";
64    private static final String PAGE  = "Page";
65  
66    private static final String MARGIN_TOP    = "Margin Top";
67    private static final String MARGIN_LEFT   = "Margin Left";
68    private static final String MARGIN_BOTTOM = "Margin Bottom";
69    private static final String MARGIN_RIGHT  = "Margin Right";
70  
71  
72    PageFormat pageFormat;
73    PDFOutputHandler outputHandler;
74  
75    public PDFExportDemo() {
76      pageFormat = new PageFormat();
77      PageFormatHelper.assignMediaSize(
78              pageFormat,
79              MediaSize.getMediaSizeForName(MediaSizeName.ISO_A4)
80      );
81      PageFormatHelper.setMargin(pageFormat, new Insets(0, 0, 0, 0));
82      PageBackgroundRenderer pbr = new PageBackgroundRenderer(view);
83      pbr.setPageFormat(pageFormat);
84      getOutputHandler().setPageFormat(pageFormat);
85  
86      final double w = pageFormat.getWidth();
87      final double h = pageFormat.getHeight();
88      Dimension ps;
89      ps = view.getPreferredSize();
90      ps = new Dimension(ps.width, (int)Math.ceil(ps.width * h/w));
91  
92      view.setBackgroundRenderer(pbr);
93      view.setPreferredSize(ps);
94      view.zoomToArea(-10, -10, w + 20, h + 20);
95      view.updateView();
96    }
97  
98    /**
99     * Creates a toolbar for this demo.
100    */
101   protected JToolBar createToolBar() {
102     JToolBar jtb = super.createToolBar();
103     jtb.addSeparator();
104 
105     jtb.add(new JButton(new PDFExportAction("PDF Export", getOutputHandler())));
106     jtb.add(new JButton(new PageFormatAction()));
107     jtb.add(new JButton(new CenterGraphOnPageAction()));
108 
109     return jtb;
110   }
111 
112   protected void loadGraph(final URL resource, final boolean updateView) {
113     super.loadGraph(resource, false);
114     final Action a = new CenterGraphOnPageAction();
115     a.actionPerformed(null);
116     view.fitContent();
117     view.updateView();
118   }
119 
120   private PDFOutputHandler getOutputHandler() {
121     if (outputHandler == null) {
122       outputHandler = new PDFOutputHandler();
123       outputHandler.setPageOutlinesEnabled(false);
124     }
125     return outputHandler;
126   }
127 
128 
129   /**
130    * Action that provides a means to configure page formats for PDF generation.
131    */
132   class PageFormatAction extends AbstractAction {
133     OptionHandler op;
134     MediaSizeName[] mediaNames = {
135         MediaSizeName.ISO_A0,
136         MediaSizeName.ISO_A1,
137         MediaSizeName.ISO_A2,
138         MediaSizeName.ISO_A3,
139         MediaSizeName.ISO_A4,
140         MediaSizeName.ISO_A5,
141         MediaSizeName.ISO_A6
142       };
143 
144     public PageFormatAction() {
145       final String name = "Page Format";
146       putValue(Action.NAME, name);
147       putValue(Action.SMALL_ICON, createIcon("resource/PageFormat16.gif"));
148       putValue(Action.SHORT_DESCRIPTION, name);
149 
150       op = new OptionHandler(name);
151       final OptionGroup group = new OptionGroup();
152       group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, name + " Options");
153       group.addItem(op.addEnum("Paper Size", mediaNames, 4));
154       group.addItem(op.addEnum("Orientation", new String[]{PORTRAIT, LANDSCAPE},0));
155       OptionItem item;
156       item = op.addDouble(MARGIN_TOP, 0, 0, 4);
157       item.setTipText("Top margin in inch.");
158       group.addItem(item);
159       item = op.addDouble(MARGIN_LEFT, 0, 0, 4);
160       item.setTipText("Left margin in inch.");
161       group.addItem(item);
162       item = op.addDouble(MARGIN_BOTTOM, 0, 0, 4);
163       item.setTipText("Bottom margin in inch.");
164       group.addItem(item);
165       item = op.addDouble(MARGIN_RIGHT, 0, 0, 4);
166       item.setTipText("Right margin in inch.");
167       group.addItem(item);
168     }
169 
170     public void actionPerformed(ActionEvent e) {
171       if(op.showEditor(view.getFrame())) {
172         MediaSizeName mediaName = (MediaSizeName) op.get("Paper Size");
173         MediaSize mediaSize = MediaSize.getMediaSizeForName(mediaName);
174         PageFormat pageFormat = new PageFormat();
175         PageFormatHelper.assignMediaSize(pageFormat, mediaSize);
176         final double dpi = 72;
177         PageFormatHelper.setMargin(
178                 pageFormat,
179                 new Insets((int)Math.ceil(dpi*op.getDouble(MARGIN_TOP)),
180                            (int)Math.ceil(dpi*op.getDouble(MARGIN_LEFT)),
181                            (int)Math.ceil(dpi*op.getDouble(MARGIN_BOTTOM)),
182                            (int)Math.ceil(dpi*op.getDouble(MARGIN_RIGHT)))
183         );
184         if (LANDSCAPE.equals(op.get("Orientation"))) {
185           pageFormat.setOrientation(PageFormat.LANDSCAPE);
186         }
187         else {
188           pageFormat.setOrientation(PageFormat.PORTRAIT);
189         }
190         updatePageFormat(pageFormat);
191         view.updateView();
192       }
193     }
194 
195     private void updatePageFormat( final PageFormat pageFormat ) {
196       PDFExportDemo.this.pageFormat = pageFormat;
197       PDFExportDemo.this.getOutputHandler().setPageFormat(pageFormat);
198       final BackgroundRenderer renderer = view.getBackgroundRenderer();
199       if (renderer instanceof PageBackgroundRenderer) {
200         ((PageBackgroundRenderer)renderer).setPageFormat(pageFormat);
201       }
202     }
203   }
204 
205   /**
206    * Action that centers the current graph on the background page indicator.
207    */
208   class CenterGraphOnPageAction extends AbstractAction {
209     CenterGraphOnPageAction() {
210       final String name = "Center Graph on Page";
211       putValue(Action.NAME, name);
212       putValue(Action.SMALL_ICON, createIcon("resource/CenterOnPage16.gif"));
213       putValue(Action.SHORT_DESCRIPTION, name);
214     }
215 
216     public void actionPerformed( final ActionEvent e ) {
217       final Graph2D graph = view.getGraph2D();
218       final Rectangle bbx = graph.getBoundingBox();
219 
220       final double dx = pageFormat.getWidth()  * 0.5 - bbx.getCenterX();
221       final double dy = pageFormat.getHeight() * 0.5 - bbx.getCenterY();
222 
223       for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
224         final NodeRealizer nr = graph.getRealizer(nc.node());
225         nr.setCenter(nr.getCenterX() + dx, nr.getCenterY() + dy);
226       }
227 
228       for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
229         final EdgeRealizer er = graph.getRealizer(ec.edge());
230         for (int i = er.pointCount(); i --> 0;) {
231           final YPoint p = er.getPoint(i);
232           er.setPoint(i, p.getX() + dx, p.getY() + dy);
233         }
234       }
235 
236       view.setCenter(bbx.getCenterX() + dx, bbx.getCenterY() + dy);
237       view.updateView();
238     }
239   }
240 
241   /**
242    * Action that exports the given graph to PDF.
243    */
244   class PDFExportAction extends ExportAction
245   {
246     PDFExportAction( String name, PDFOutputHandler outputHandler ) {
247       super(name, outputHandler);
248 
249       final String[] sizes = {
250               "Use Original Size", USE_CUSTOM_WIDTH, USE_CUSTOM_HEIGHT
251       };
252       final String[] clipRegions = {
253               GRAPH, PAGE, VIEW
254       };
255 
256       // set up an OptionHandler to allow for user customizations
257       options = new OptionHandler(name);
258       final OptionGroup group = new OptionGroup();
259       group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, name + " Options");
260       group.addItem(options.addEnum(SIZE, sizes, 0));
261       group.addItem(options.addInt(CUSTOM_WIDTH,  500));
262       group.addItem(options.addInt(CUSTOM_HEIGHT, 500));
263       group.addItem(options.addInt(EMPTY_BORDER_WIDTH, 10));
264       group.addItem(options.addEnum(CLIP_REGION, clipRegions, 0));
265       group.addItem(options.addBool(SELECTION_PAINTING, false));
266       final OptionItem item = options.addBool(ACTIVATE_TILING, false);
267       item.setTipText("Splits large graphs over multiple pages.");
268       group.addItem(item);
269       group.addItem(options.addBool(RENDER_TEXT_AS_SHAPES, false));
270       group.addItem(options.addBool(EMBED_FONTS, false));
271 
272       final ConstraintManager cm = new ConstraintManager(options);
273       cm.setEnabledOnValueEquals(SIZE, USE_CUSTOM_WIDTH, CUSTOM_WIDTH);
274       cm.setEnabledOnValueEquals(SIZE, USE_CUSTOM_HEIGHT, CUSTOM_HEIGHT);
275       cm.setEnabledOnValueEquals(CLIP_REGION, GRAPH, EMPTY_BORDER_WIDTH);
276       cm.setEnabledOnValueEquals(CLIP_REGION, PAGE, ACTIVATE_TILING, true);
277       cm.setEnabledOnValueEquals(RENDER_TEXT_AS_SHAPES, Boolean.FALSE, EMBED_FONTS);
278     }
279 
280     void configureViewPort( final Graph2DView viewPort ) {
281       Graph2D graph = view.getGraph2D();
282 
283       double width  = options.getInt(CUSTOM_WIDTH);
284       double height = options.getInt(CUSTOM_HEIGHT);
285       Point viewPoint = viewPort.getViewPoint();
286       double zoom = 1.0;
287 
288       if (GRAPH.equals(options.get(CLIP_REGION))) {
289         Rectangle box = graph.getBoundingBox();
290         int border = options.getInt(EMPTY_BORDER_WIDTH);
291         box.width  += 2*border;
292         box.height += 2*border;
293         box.x -= border;
294         box.y -= border;
295 
296         if (USE_CUSTOM_HEIGHT.equals(options.get(SIZE))) {
297           width = height*box.getWidth()/box.getHeight();
298         } else if (USE_CUSTOM_WIDTH.equals(options.get(SIZE))) {
299           height = width*box.getHeight()/box.getWidth();
300         } else {
301           width =  box.getWidth();
302           height = box.getHeight();
303         }
304         zoom = width/box.getWidth();
305         viewPoint = new Point(box.x, box.y);
306       } else if (VIEW.equals(options.get(CLIP_REGION))) {
307         if (USE_CUSTOM_HEIGHT.equals(options.get(SIZE))) {
308           width = height*view.getWidth()/view.getHeight();
309         } else if (USE_CUSTOM_WIDTH.equals(options.get(SIZE))) {
310           height = width*view.getHeight()/view.getWidth();
311         } else {
312           width =  view.getWidth();
313           height = view.getHeight();
314         }
315         viewPoint = view.getViewPoint();
316         zoom = view.getZoom()*width/view.getWidth();
317       } else if (PAGE.equals(options.get(CLIP_REGION))) {
318         final Insets margin = PageFormatHelper.getMargin(pageFormat);
319         viewPoint = new Point(margin.left, margin.top);
320         width = pageFormat.getWidth() - margin.left - margin.right;
321         height = pageFormat.getHeight() - margin.top - margin.bottom;
322       }
323 
324       viewPort.setZoom(zoom);
325       viewPort.setSize((int)Math.ceil(width), (int)Math.ceil(height));
326       viewPort.setViewPoint(viewPoint.x, viewPoint.y);
327     }
328 
329     public void actionPerformed( final ActionEvent e ) {
330       // show our OptionHandler to allow the user to set up the export view
331       // according to his or her wishes
332       if (!options.showEditor(view.getFrame())) {
333         return;
334       }
335 
336       if (options.getBool(SELECTION_PAINTING)) {
337         outputHandler.removeRenderingHint(YRenderingHints.KEY_SELECTION_PAINTING);
338       } else {
339         outputHandler.addRenderingHint(
340                 YRenderingHints.KEY_SELECTION_PAINTING,
341                 YRenderingHints.VALUE_SELECTION_PAINTING_OFF);
342       }
343 
344       ((PDFOutputHandler)outputHandler).setMultiPageTilingEnabled(
345               options.getBool(ACTIVATE_TILING) &&
346               !PAGE.equals(options.get(CLIP_REGION)));
347       final byte policy;
348       if (options.getBool(RENDER_TEXT_AS_SHAPES)) {
349         policy = PDFOutputHandler.VECTORIZED_TEXT;
350       } else if (options.getBool(EMBED_FONTS)) {
351         policy = PDFOutputHandler.PLAIN_TEXT_WITH_EMBEDDED_FONTS;
352       } else {
353         policy = PDFOutputHandler.PLAIN_TEXT;
354       }
355       ((PDFOutputHandler)outputHandler).setTextRenderingPolicy(policy);
356 
357       Graph2D graph = view.getGraph2D();
358       Graph2DView viewPort = outputHandler.createDefaultGraph2DView(graph);
359 
360       // configure the export view according to the options specified by the
361       // user
362       configureViewPort(viewPort);
363       graph.setCurrentView(viewPort);
364 
365       // ask for the destination file and finally write the graph to the chosen
366       // destination
367       export(outputHandler);
368 
369       graph.removeView(viewPort);
370     }
371   }
372 
373   /**
374    * Launches this demo.
375    */
376   public static void main(String[] args) {
377     initLnF();
378     (new PDFExportDemo()).start();
379   }
380 }