DGP - 1st printing
[debian/openrocket] / src / net / sf / openrocket / gui / dialogs / PrintDialog.java
1 /*
2  * PrintDialog.java
3  */
4 package net.sf.openrocket.gui.dialogs;
5
6 import net.sf.openrocket.document.OpenRocketDocument;
7 import net.sf.openrocket.gui.print.PDFPrintStreamDoc;
8 import net.sf.openrocket.gui.print.PrintUtilities;
9 import sun.print.ServiceDialog;
10
11 import javax.print.DocFlavor;
12 import javax.print.DocPrintJob;
13 import javax.print.PrintException;
14 import javax.print.PrintService;
15 import javax.print.PrintServiceLookup;
16 import javax.print.attribute.Attribute;
17 import javax.print.attribute.AttributeSet;
18 import javax.print.attribute.HashPrintRequestAttributeSet;
19 import javax.print.attribute.PrintRequestAttributeSet;
20 import javax.print.attribute.standard.Destination;
21 import javax.print.attribute.standard.Fidelity;
22 import javax.swing.JDialog;
23 import javax.swing.JMenu;
24 import javax.swing.JTabbedPane;
25 import java.awt.Component;
26 import java.awt.Container;
27 import java.awt.Dialog;
28 import java.awt.GraphicsConfiguration;
29 import java.awt.GraphicsDevice;
30 import java.awt.GraphicsEnvironment;
31 import java.awt.HeadlessException;
32 import java.awt.Rectangle;
33 import java.io.ByteArrayOutputStream;
34
35 /**
36  * This class is not a dialog by inheritance, but is by delegation.  It front-ends a java print dialog by
37  * augmenting it with application specific (rocket) settings.
38  */
39 public class PrintDialog {
40
41     /**
42      * The service UI dialog.
43      */
44     private ServiceDialog dialog;
45
46     /**
47      * A javax doc flavor specific for printing PDF documents.
48      */
49     private static final DocFlavor.INPUT_STREAM PDF = DocFlavor.INPUT_STREAM.PDF;
50
51     /**
52      * Construct a print dialog using an Open Rocket document - which contains the rocket data to ultimately be
53      * printed.
54      *
55      * @param orDocument the rocket container
56      */
57     public PrintDialog (OpenRocketDocument orDocument) {
58         PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
59         PrintService svc = PrintServiceLookup.lookupDefaultPrintService();
60         PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet();
61         attrs.add(PrintUtilities.getDefaultMedia().getMediaSizeName());
62
63         final PrintPanel panel = new PrintPanel(orDocument, this);
64         PrintService ps = printDialog(null, 100, 100, services, svc, PDF, attrs, panel);
65         if (ps != null) {
66             DocPrintJob dpj = ps.createPrintJob();
67             try {
68                 System.err.println(attrs.size());
69                 ByteArrayOutputStream baos = panel.generateReport();
70                 dpj.print(new PDFPrintStreamDoc(baos, null), attrs);
71             }
72             catch (PrintException e) {
73                 e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
74             }
75         }
76     }
77
78     /**
79      * Get the set of attributes from the service ui print dialog.
80      *
81      * @return a set of print attributes
82      */
83     PrintRequestAttributeSet getAttributes () {
84         return dialog.getAttributes();
85     }
86
87     /**
88      * Get the service ui dialog.  This is the actual dialog that gets displayed - we co-opt it for adding a rocket
89      * specific tab.
90      *
91      * @return the Java service ui print dialog
92      */
93     JDialog getDialog () {
94         return dialog;
95     }
96
97     /**
98      * Mimics the ServiceUI.printDialog method, but with enhancements for our own print settings tab.
99      *
100      * @param gc             used to select screen. null means primary or default screen.
101      * @param x              location of dialog including border in screen coordinates
102      * @param y              location of dialog including border in screen coordinates
103      * @param services       to be browsable, must be non-null.
104      * @param defaultService - initial PrintService to display.
105      * @param flavor         - the flavor to be printed, or null.
106      * @param attributes     on input is the initial application supplied preferences. This cannot be null but may be
107      *                       empty. On output the attributes reflect changes made by the user.
108      * @param addnl          a panel to be added, as a tab, to the internal tabbed pane of the resulting print dialog
109      *
110      * @return print service selected by the user, or null if the user cancelled the dialog.
111      *
112      * @throws HeadlessException        if GraphicsEnvironment.isHeadless() returns true.
113      * @throws IllegalArgumentException if services is null or empty, or attributes is null, or the initial PrintService
114      *                                  is not in the list of browsable services.
115      */
116     private PrintService printDialog (GraphicsConfiguration gc,
117                                       int x, int y,
118                                       PrintService[] services,
119                                       PrintService defaultService,
120                                       DocFlavor flavor,
121                                       PrintRequestAttributeSet attributes,
122                                       PrintPanel addnl)
123             throws HeadlessException {
124         int defaultIndex = -1;
125
126         if (GraphicsEnvironment.isHeadless()) {
127             throw new HeadlessException();
128         }
129         else if ((services == null) || (services.length == 0)) {
130             throw new IllegalArgumentException("services must be non-null " +
131                                                "and non-empty");
132         }
133         else if (attributes == null) {
134             throw new IllegalArgumentException("attributes must be non-null");
135         }
136
137         if (defaultService != null) {
138             for (int i = 0; i < services.length; i++) {
139                 if (services[i].equals(defaultService)) {
140                     defaultIndex = i;
141                     break;
142                 }
143             }
144
145             if (defaultIndex < 0) {
146                 throw new IllegalArgumentException("services must contain " +
147                                                    "defaultService");
148             }
149         }
150         else {
151             defaultIndex = 0;
152         }
153
154         Rectangle gcBounds = (gc == null) ? GraphicsEnvironment.
155                 getLocalGraphicsEnvironment().getDefaultScreenDevice().
156                 getDefaultConfiguration().getBounds() : gc.getBounds();
157
158         dialog = new ServiceDialog(gc,
159                                    x + gcBounds.x,
160                                    y + gcBounds.y,
161                                    services, defaultIndex,
162                                    flavor, attributes,
163                                    (Dialog) null);
164         Rectangle dlgBounds = dialog.getBounds();
165
166         // get union of all GC bounds
167         GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
168         GraphicsDevice[] gs = ge.getScreenDevices();
169         for (GraphicsDevice g : gs) {
170             gcBounds = gcBounds.union(g.getDefaultConfiguration().getBounds());
171         }
172
173         // if portion of dialog is not within the gc boundary
174         if (!gcBounds.contains(dlgBounds)) {
175             // put in the center relative to parent frame/dialog
176             dialog.setLocationRelativeTo(null);
177         }
178         if (addnl != null && addnl.getTitle() != null) {
179             JTabbedPane tp = (JTabbedPane) getDescendantOfClass(JTabbedPane.class, dialog);
180             tp.add(addnl, addnl.getTitle(), 0);
181             tp.setSelectedIndex(0);
182         }
183
184         dialog.setVisible(true);
185
186         if (dialog.getStatus() == ServiceDialog.APPROVE) {
187             PrintRequestAttributeSet newas = dialog.getAttributes();
188             Class dstCategory = Destination.class;
189             Class fdCategory = Fidelity.class;
190
191             if (attributes.containsKey(dstCategory) &&
192                 !newas.containsKey(dstCategory)) {
193                 attributes.remove(dstCategory);
194             }
195
196             attributes.addAll(newas);
197
198             Fidelity fd = (Fidelity) attributes.get(fdCategory);
199             if (fd != null) {
200                 if (fd == Fidelity.FIDELITY_TRUE) {
201                     removeUnsupportedAttributes(dialog.getPrintService(),
202                                                 flavor, attributes);
203                 }
204             }
205             return dialog.getPrintService();
206         }
207         else {
208             return null;
209         }
210     }
211
212     private Component getDescendantOfClass (Class c, Container cont) {
213         if (c == null || cont == null) {
214             return null;
215         }
216         Component[] children = (cont instanceof JMenu)
217                                ? ((JMenu) cont).getMenuComponents()
218                                : cont.getComponents();
219         for (int i = 0, n = children.length; i < n; i++) {
220             Component comp = children[i];
221             if (c.isInstance(comp)) {
222                 return comp;
223             }
224             comp = getDescendantOfClass(c, (Container) comp);
225             if (comp != null) {
226                 return comp;
227             }
228         }
229         return null;
230     }
231
232     /**
233      * Removes any attributes from the given AttributeSet that are unsupported by the given PrintService/DocFlavor
234      * combination.
235      * 
236      * @param ps      the print service for which unsupported attributes will be determined
237      * @param flavor  the document flavor; PDF in our case
238      * @param aset    the set of attributes requested
239      */
240     private static void removeUnsupportedAttributes (PrintService ps,
241                                                      DocFlavor flavor,
242                                                      AttributeSet aset) {
243         AttributeSet asUnsupported = ps.getUnsupportedAttributes(flavor,
244                                                                  aset);
245
246         if (asUnsupported != null) {
247             Attribute[] usAttrs = asUnsupported.toArray();
248
249             for (Attribute usAttr : usAttrs) {
250                 Class<? extends Attribute> category = usAttr.getCategory();
251
252                 if (ps.isAttributeCategorySupported(category)) {
253                     Attribute attr =
254                             (Attribute) ps.getDefaultAttributeValue(category);
255
256                     if (attr != null) {
257                         aset.add(attr);
258                     }
259                     else {
260                         aset.remove(category);
261                     }
262                 }
263                 else {
264                     aset.remove(category);
265                 }
266             }
267         }
268     }
269
270 }