1   /****************************************************************************
2    **
3    ** This file is part of the yFiles extension package yExport-1.0.
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 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 yext.export.io.PDFOutputHandler;
19  
20  import y.base.EdgeCursor;
21  import y.base.NodeCursor;
22  import y.option.ConstraintManager;
23  import y.option.OptionGroup;
24  import y.option.OptionHandler;
25  import y.option.OptionItem;
26  import y.geom.YPoint;
27  import y.view.BackgroundRenderer;
28  import y.view.EdgeRealizer;
29  import y.view.Graph2D;
30  import y.view.Graph2DView;
31  import y.view.NodeRealizer;
32  
33  import java.awt.Dimension;
34  import java.awt.Insets;
35  import java.awt.Point;
36  import java.awt.Rectangle;
37  import java.awt.event.ActionEvent;
38  import java.awt.print.PageFormat;
39  import java.net.URL;
40  import javax.swing.AbstractAction;
41  import javax.swing.Action;
42  import javax.swing.JButton;
43  import javax.swing.JToolBar;
44  import javax.print.attribute.standard.MediaSize;
45  import javax.print.attribute.standard.MediaSizeName;
46  
47  
48  /**
49   * Demonstrates how to export a graph to PDF format.
50   * Additionally, the demo allows to specify a preferred page format for
51   * the PDF export.
52   * It uses a custom background renderer to provide an indication on whether the
53   * graph to be exported will fit on the specified page.
54   */
55  public class PDFExportDemo extends AbstractExportDemo
56  {
57    private static final String ACTIVATE_TILING = "Activate Tiling";
58  
59    private static final String LANDSCAPE = "Landscape";
60    private static final String PORTRAIT  = "Portrait";
61    private static final String PAGE  = "Page";
62  
63    private static final String MARGIN_TOP    = "Margin Top";
64    private static final String MARGIN_LEFT   = "Margin Left";
65    private static final String MARGIN_BOTTOM = "Margin Bottom";
66    private static final String MARGIN_RIGHT  = "Margin Right";
67  
68  
69    PageFormat pageFormat;
70    PDFOutputHandler outputHandler;
71  
72    public PDFExportDemo() {
73      if (outputHandler == null) {
74        outputHandler = new PDFOutputHandler();
75      }
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      outputHandler.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     if (outputHandler == null) {
106       outputHandler = new PDFOutputHandler();
107     }
108     jtb.add(new JButton(new PDFExportAction("PDF Export", outputHandler)));
109     jtb.add(new JButton(new PageFormatAction()));
110     jtb.add(new JButton(new CenterGraphOnPageAction()));
111 
112     return jtb;
113   }
114 
115   protected Action createLoadResourceAction( final URL resource ) {
116     return new LoadResourceAction(resource) {
117       private final Action a = new CenterGraphOnPageAction();
118       public void actionPerformed( final ActionEvent e ) {
119         super.actionPerformed(e);
120         a.actionPerformed(e);
121         view.fitContent();
122         view.updateView();
123       }
124     };
125   }
126 
127 
128   /**
129    * Action that provides a means to configure page formats for PDF generation.
130    */
131   class PageFormatAction extends AbstractAction {
132     OptionHandler op;
133     MediaSizeName[] mediaNames = {
134         MediaSizeName.ISO_A0,
135         MediaSizeName.ISO_A1,
136         MediaSizeName.ISO_A2,
137         MediaSizeName.ISO_A3,
138         MediaSizeName.ISO_A4,
139         MediaSizeName.ISO_A5,
140         MediaSizeName.ISO_A6
141       };
142 
143     public PageFormatAction() {
144       final String name = "Page Format";
145       putValue(Action.NAME, name);
146       putValue(Action.SMALL_ICON, createIcon("resource/PageFormat16.gif"));
147       putValue(Action.SHORT_DESCRIPTION, name);
148 
149       op = new OptionHandler(name);
150       final OptionGroup group = new OptionGroup();
151       group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, name + " Options");
152       group.addItem(op.addEnum("Paper Size", mediaNames, 4));
153       group.addItem(op.addEnum("Orientation", new String[]{PORTRAIT, LANDSCAPE},0));
154       OptionItem item;
155       item = op.addDouble(MARGIN_TOP, 0, 0, 4);
156       item.setTipText("Top margin in inch.");
157       group.addItem(item);
158       item = op.addDouble(MARGIN_LEFT, 0, 0, 4);
159       item.setTipText("Left margin in inch.");
160       group.addItem(item);
161       item = op.addDouble(MARGIN_BOTTOM, 0, 0, 4);
162       item.setTipText("Bottom margin in inch.");
163       group.addItem(item);
164       item = op.addDouble(MARGIN_RIGHT, 0, 0, 4);
165       item.setTipText("Right margin in inch.");
166       group.addItem(item);
167     }
168 
169     public void actionPerformed(ActionEvent e) {
170       if(op.showEditor()) {
171         MediaSizeName mediaName = (MediaSizeName) op.get("Paper Size");
172         MediaSize mediaSize = MediaSize.getMediaSizeForName(mediaName);
173         PageFormat pageFormat = new PageFormat();
174         PageFormatHelper.assignMediaSize(pageFormat, mediaSize);
175         final double dpi = 72;
176         PageFormatHelper.setMargin(
177                 pageFormat,
178                 new Insets((int)Math.ceil(dpi*op.getDouble(MARGIN_TOP)),
179                            (int)Math.ceil(dpi*op.getDouble(MARGIN_LEFT)),
180                            (int)Math.ceil(dpi*op.getDouble(MARGIN_BOTTOM)),
181                            (int)Math.ceil(dpi*op.getDouble(MARGIN_RIGHT)))
182         );
183         if (LANDSCAPE.equals(op.get("Orientation"))) {
184           pageFormat.setOrientation(PageFormat.LANDSCAPE);
185         }
186         else {
187           pageFormat.setOrientation(PageFormat.PORTRAIT);
188         }
189         updatePageFormat(pageFormat);
190         view.updateView();
191       }
192     }
193 
194     private void updatePageFormat( final PageFormat pageFormat ) {
195       PDFExportDemo.this.pageFormat = pageFormat;
196       PDFExportDemo.this.outputHandler.setPageFormat(pageFormat);
197       final BackgroundRenderer renderer = view.getBackgroundRenderer();
198       if (renderer instanceof PageBackgroundRenderer) {
199         ((PageBackgroundRenderer)renderer).setPageFormat(pageFormat);
200       }
201     }
202   }
203 
204   /**
205    * Action that centers the current graph on thebackground page indicator.
206    */
207   class CenterGraphOnPageAction extends AbstractAction {
208     public CenterGraphOnPageAction() {
209       final String name = "Center Graph on Page";
210       putValue(Action.NAME, name);
211       putValue(Action.SMALL_ICON, createIcon("resource/CenterOnPage16.gif"));
212       putValue(Action.SHORT_DESCRIPTION, name);
213     }
214 
215     public void actionPerformed( final ActionEvent e ) {
216       final Graph2D graph = view.getGraph2D();
217       final Rectangle bbx = graph.getBoundingBox();
218 
219       final double dx = pageFormat.getWidth()  * 0.5 - bbx.getCenterX();
220       final double dy = pageFormat.getHeight() * 0.5 - bbx.getCenterY();
221 
222       for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
223         final NodeRealizer nr = graph.getRealizer(nc.node());
224         nr.setCenter(nr.getCenterX() + dx, nr.getCenterY() + dy);
225       }
226 
227       for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
228         final EdgeRealizer er = graph.getRealizer(ec.edge());
229         for (int i = er.pointCount(); i --> 0;) {
230           final YPoint p = er.getPoint(i);
231           er.setPoint(i, p.getX() + dx, p.getY() + dy);
232         }
233       }
234 
235       view.setCenter(bbx.getCenterX() + dx, bbx.getCenterY() + dy);
236       view.updateView();
237     }
238   }
239 
240   /**
241    * Action that exports the given graph to PDF.
242    */
243   class PDFExportAction extends ExportAction
244   {
245     PDFExportAction( String name, PDFOutputHandler outputHandler ) {
246       super(name, outputHandler);
247 
248       final String[] sizes = new String[]{
249               "Use Original Size", USE_CUSTOM_WIDTH, USE_CUSTOM_HEIGHT
250       };
251       final String[] clipRegions = {
252               GRAPH, PAGE, VIEW
253       };
254 
255       // set up an OptionHandler to allow for user customizations
256       options = new OptionHandler(name);
257       final OptionGroup group = new OptionGroup();
258       group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, name + " Options");
259       group.addItem(options.addEnum(SIZE, sizes, 0));
260       group.addItem(options.addInt(CUSTOM_WIDTH,  500));
261       group.addItem(options.addInt(CUSTOM_HEIGHT, 500));
262       group.addItem(options.addInt(EMPTY_BORDER_WIDTH, 10));
263       group.addItem(options.addEnum(CLIP_REGION, clipRegions, 0));
264       final OptionItem item = options.addBool(ACTIVATE_TILING, false);
265       item.setTipText("Splits large graphs over multiple pages.");
266       group.addItem(item);
267 
268       final ConstraintManager cm = new ConstraintManager(options);
269       cm.setEnabledOnValueEquals(SIZE, USE_CUSTOM_WIDTH, CUSTOM_WIDTH);
270       cm.setEnabledOnValueEquals(SIZE, USE_CUSTOM_HEIGHT, CUSTOM_HEIGHT);
271       cm.setEnabledOnValueEquals(CLIP_REGION, GRAPH, EMPTY_BORDER_WIDTH);
272       cm.setEnabledOnValueEquals(CLIP_REGION, PAGE, ACTIVATE_TILING, true);
273     }
274 
275     void configureViewPort( final Graph2DView viewPort ) {
276       Graph2D graph = view.getGraph2D();
277 
278       double width  = options.getInt(CUSTOM_WIDTH);
279       double height = options.getInt(CUSTOM_HEIGHT);
280       Point viewPoint = viewPort.getViewPoint();
281       double zoom = 1.0;
282 
283       if (GRAPH.equals(options.get(CLIP_REGION))) {
284         Rectangle box = graph.getBoundingBox();
285         int border = options.getInt(EMPTY_BORDER_WIDTH);
286         box.width  += 2*border;
287         box.height += 2*border;
288         box.x -= border;
289         box.y -= border;
290 
291         if (USE_CUSTOM_HEIGHT.equals(options.get(SIZE))) {
292           width = height*box.getWidth()/box.getHeight();
293         } else if (USE_CUSTOM_WIDTH.equals(options.get(SIZE))) {
294           height = width*box.getHeight()/box.getWidth();
295         } else {
296           width =  box.getWidth();
297           height = box.getHeight();
298         }
299         zoom = width/box.getWidth();
300         viewPoint = new Point(box.x, box.y);
301       } else if (VIEW.equals(options.get(CLIP_REGION))) {
302         if (USE_CUSTOM_HEIGHT.equals(options.get(SIZE))) {
303           width = height*view.getWidth()/view.getHeight();
304         } else if (USE_CUSTOM_WIDTH.equals(options.get(SIZE))) {
305           height = width*view.getHeight()/view.getWidth();
306         } else {
307           width =  view.getWidth();
308           height = view.getHeight();
309         }
310         viewPoint = view.getViewPoint();
311         zoom = view.getZoom()*width/view.getWidth();
312       } else if (PAGE.equals(options.get(CLIP_REGION))) {
313         final Insets margin = PageFormatHelper.getMargin(pageFormat);
314         viewPoint = new Point(margin.left, margin.top);
315         width = pageFormat.getWidth() - margin.left - margin.right;
316         height = pageFormat.getHeight() - margin.top - margin.bottom;
317       }
318 
319       viewPort.setZoom(zoom);
320       viewPort.setSize((int)Math.ceil(width), (int)Math.ceil(height));
321       viewPort.setViewPoint(viewPoint.x, viewPoint.y);
322     }
323 
324     public void actionPerformed( final ActionEvent e ) {
325       // show our OptionHandler to allow the user to set up the export view
326       // according to his or her wishes
327       if (!options.showEditor()) {
328         return;
329       }
330       ((PDFOutputHandler)outputHandler).setMultiPageTilingEnabled(
331               options.getBool(ACTIVATE_TILING) &&
332               !PAGE.equals(options.get(CLIP_REGION)));
333 
334       Graph2D graph = view.getGraph2D();
335       Graph2DView viewPort = outputHandler.createDefaultGraph2DView(graph);
336 
337       // configure the export view according to the options specified by the
338       // user
339       configureViewPort(viewPort);
340       graph.setCurrentView(viewPort);
341 
342       // ask for the destination file and finally write the graph to the chosen
343       // destination
344       export(outputHandler);
345 
346       graph.removeView(viewPort);
347     }
348   }
349 
350   /**
351    * Launches this demo.
352    */
353   public static void main(String[] args) {
354     initLnF();
355     (new PDFExportDemo()).start();
356   }
357 }