c820c071e59e7358628c0a2f635b0d3d557eae8d
[debian/openrocket] / src / net / sf / openrocket / gui / dialogs / PrintDialog.java
1 /*
2  * PrintPanel.java
3  */
4 package net.sf.openrocket.gui.dialogs;
5
6 import java.awt.Desktop;
7 import java.awt.Window;
8 import java.awt.event.ActionEvent;
9 import java.awt.event.ActionListener;
10 import java.io.File;
11 import java.io.FileOutputStream;
12 import java.io.IOException;
13 import java.util.Enumeration;
14 import java.util.Iterator;
15
16 import javax.swing.JButton;
17 import javax.swing.JCheckBox;
18 import javax.swing.JDialog;
19 import javax.swing.JFileChooser;
20 import javax.swing.JLabel;
21 import javax.swing.JOptionPane;
22 import javax.swing.JPanel;
23 import javax.swing.JScrollPane;
24 import javax.swing.event.TreeSelectionEvent;
25 import javax.swing.event.TreeSelectionListener;
26 import javax.swing.filechooser.FileFilter;
27 import javax.swing.tree.TreeNode;
28 import javax.swing.tree.TreePath;
29
30 import net.miginfocom.swing.MigLayout;
31 import net.sf.openrocket.document.OpenRocketDocument;
32 import net.sf.openrocket.gui.main.ExceptionHandler;
33 import net.sf.openrocket.gui.print.PrintController;
34 import net.sf.openrocket.gui.print.PrintSettings;
35 import net.sf.openrocket.gui.print.PrintableContext;
36 import net.sf.openrocket.gui.print.TemplateProperties;
37 import net.sf.openrocket.gui.print.components.CheckTreeManager;
38 import net.sf.openrocket.gui.print.components.RocketPrintTree;
39 import net.sf.openrocket.l10n.Translator;
40 import net.sf.openrocket.logging.LogHelper;
41 import net.sf.openrocket.rocketcomponent.Rocket;
42 import net.sf.openrocket.startup.Application;
43 import net.sf.openrocket.util.GUIUtil;
44 import net.sf.openrocket.util.Prefs;
45
46 /**
47  * This class isolates the Swing components used to create a panel that is added to a standard Java print dialog.
48  */
49 public class PrintDialog extends JDialog implements TreeSelectionListener {
50         
51         private static final LogHelper log = Application.getLogger();
52         private static final Translator trans = Application.getTranslator();
53         
54         private final Desktop desktop;
55         
56         private final RocketPrintTree stagedTree;
57         private final RocketPrintTree noStagedTree;
58         private OpenRocketDocument document;
59         private RocketPrintTree currentTree;
60         
61         private JButton previewButton;
62         private JButton saveAsPDF;
63         private JButton cancel;
64         
65         /**
66          * Constructor.
67          *
68          * @param orDocument the OR rocket container
69          */
70         public PrintDialog(Window parent, OpenRocketDocument orDocument) {
71                 super(parent, trans.get("title"), ModalityType.APPLICATION_MODAL);
72                 
73
74                 JPanel panel = new JPanel(new MigLayout("fill, gap rel unrel"));
75                 this.add(panel);
76                 
77
78                 // before any Desktop APIs are used, first check whether the API is
79                 // supported by this particular VM on this particular host
80                 if (Desktop.isDesktopSupported()) {
81                         desktop = Desktop.getDesktop();
82                 } else {
83                         desktop = null;
84                 }
85                 
86                 document = orDocument;
87                 Rocket rocket = orDocument.getRocket();
88                 
89                 noStagedTree = RocketPrintTree.create(rocket.getName());
90                 noStagedTree.setShowsRootHandles(false);
91                 CheckTreeManager ctm = new net.sf.openrocket.gui.print.components.CheckTreeManager(noStagedTree);
92                 ctm.addTreeSelectionListener(this);
93                 
94                 final int stages = rocket.getStageCount();
95                 
96
97                 JLabel label = new JLabel(trans.get("lbl.selectElements"));
98                 panel.add(label, "wrap unrel");
99                 
100                 // Create the tree
101                 if (stages > 1) {
102                         stagedTree = RocketPrintTree.create(rocket.getName(), rocket.getChildren());
103                         ctm = new CheckTreeManager(stagedTree);
104                         stagedTree.setShowsRootHandles(false);
105                         ctm.addTreeSelectionListener(this);
106                 } else {
107                         stagedTree = noStagedTree;
108                 }
109                 currentTree = stagedTree;
110                 
111                 // Add the tree to the UI
112                 final JScrollPane scrollPane = new JScrollPane(stagedTree);
113                 panel.add(scrollPane, "width 400lp, height 200lp, grow, wrap para");
114                 
115
116                 // Checkboxes and buttons
117                 final JCheckBox sortByStage = new JCheckBox(trans.get("checkbox.showByStage"));
118                 sortByStage.setEnabled(stages > 1);
119                 sortByStage.setSelected(stages > 1);
120                 sortByStage.addActionListener(new ActionListener() {
121                         @Override
122                         public void actionPerformed(ActionEvent e) {
123                                 if (sortByStage.isEnabled()) {
124                                         if (((JCheckBox) e.getSource()).isSelected()) {
125                                                 scrollPane.setViewportView(stagedTree);
126                                                 stagedTree.setExpandsSelectedPaths(true);
127                                                 currentTree = stagedTree;
128                                         }
129                                         else {
130                                                 scrollPane.setViewportView(noStagedTree);
131                                                 noStagedTree.setExpandsSelectedPaths(true);
132                                                 currentTree = noStagedTree;
133                                         }
134                                 }
135                         }
136                 });
137                 panel.add(sortByStage, "aligny top, split");
138                 
139
140                 panel.add(new JPanel(), "growx");
141                 
142
143                 JButton settingsButton = new JButton(trans.get("printdlg.but.settings"));
144                 settingsButton.addActionListener(new ActionListener() {
145                         @Override
146                         public void actionPerformed(ActionEvent e) {
147                                 PrintSettings settings = Prefs.getPrintSettings();
148                                 log.debug("settings=" + settings);
149                                 PrintSettingsDialog settingsDialog = new PrintSettingsDialog(PrintDialog.this, settings);
150                                 settingsDialog.setVisible(true);
151                                 Prefs.setPrintSettings(settings);
152                         }
153                 });
154                 panel.add(settingsButton, "wrap para");
155                 
156
157                 previewButton = new JButton(trans.get("but.previewAndPrint"));
158                 previewButton.addActionListener(new ActionListener() {
159                         @Override
160                         public void actionPerformed(ActionEvent e) {
161                                 onPreview();
162                                 PrintDialog.this.setVisible(false);
163                         }
164                 });
165                 panel.add(previewButton, "split, right, gap para");
166                 
167
168                 saveAsPDF = new JButton(trans.get("printdlg.but.saveaspdf"));
169                 saveAsPDF.addActionListener(new ActionListener() {
170                         @Override
171                         public void actionPerformed(ActionEvent e) {
172                                 if (onSavePDF()) {
173                                         PrintDialog.this.setVisible(false);
174                                 }
175                         }
176                 });
177                 panel.add(saveAsPDF, "right, gap para");
178                 
179
180                 cancel = new JButton(trans.get("button.cancel"));
181                 cancel.addActionListener(new ActionListener() {
182                         @Override
183                         public void actionPerformed(ActionEvent e) {
184                                 PrintDialog.this.setVisible(false);
185                         }
186                 });
187                 panel.add(cancel, "right, gap para");
188                 
189
190                 expandAll(currentTree, true);
191                 if (currentTree != noStagedTree) {
192                         expandAll(noStagedTree, true);
193                 }
194                 
195
196                 GUIUtil.setDisposableDialogOptions(this, previewButton);
197                 
198         }
199         
200         
201         @Override
202         public void valueChanged(final TreeSelectionEvent e) {
203                 final TreePath path = e.getNewLeadSelectionPath();
204                 if (path != null) {
205                         previewButton.setEnabled(true);
206                         saveAsPDF.setEnabled(true);
207                 } else {
208                         previewButton.setEnabled(false);
209                         saveAsPDF.setEnabled(false);
210                 }
211         }
212         
213         /**
214          * If expand is true, expands all nodes in the tree. Otherwise, collapses all nodes in the theTree.
215          *
216          * @param theTree   the tree to expand/contract
217          * @param expand expand if true, contract if not
218          */
219         public void expandAll(RocketPrintTree theTree, boolean expand) {
220                 TreeNode root = (TreeNode) theTree.getModel().getRoot();
221                 // Traverse theTree from root
222                 expandAll(theTree, new TreePath(root), expand);
223         }
224         
225         /**
226          * Recursively walk a tree, and if expand is true, expands all nodes in the tree. Otherwise, collapses all nodes in
227          * the theTree.
228          *
229          * @param theTree   the tree to expand/contract
230          * @param parent the node to iterate/recurse over
231          * @param expand expand if true, contract if not
232          */
233         private void expandAll(RocketPrintTree theTree, TreePath parent, boolean expand) {
234                 theTree.addSelectionPath(parent);
235                 // Traverse children
236                 TreeNode node = (TreeNode) parent.getLastPathComponent();
237                 if (node.getChildCount() >= 0) {
238                         for (Enumeration<?> e = node.children(); e.hasMoreElements();) {
239                                 TreeNode n = (TreeNode) e.nextElement();
240                                 TreePath path = parent.pathByAddingChild(n);
241                                 expandAll(theTree, path, expand);
242                         }
243                 }
244                 // Expansion or collapse must be done bottom-up
245                 if (expand) {
246                         theTree.expandPath(parent);
247                 } else {
248                         theTree.collapsePath(parent);
249                 }
250         }
251         
252         
253
254         /**
255          * Generate a report using a temporary file.  The file will be deleted upon JVM exit.
256          *
257          * @param paper the name of the paper size
258          *
259          * @return a file, populated with the "printed" output (the rocket info)
260          *
261          * @throws IOException thrown if the file could not be generated
262          */
263         private File generateReport(PrintSettings settings) throws IOException {
264                 final File f = File.createTempFile("openrocket-", ".pdf");
265                 f.deleteOnExit();
266                 return generateReport(f, settings);
267         }
268         
269         /**
270          * Generate a report to a specified file.
271          *
272          * @param f     the file to which rocket data will be written
273          * @param paper the name of the paper size
274          *
275          * @return a file, populated with the "printed" output (the rocket info)
276          *
277          * @throws IOException thrown if the file could not be generated
278          */
279         private File generateReport(File f, PrintSettings settings) throws IOException {
280                 Iterator<PrintableContext> toBePrinted = currentTree.getToBePrinted();
281                 new PrintController().print(document, toBePrinted, new FileOutputStream(f), settings);
282                 return f;
283         }
284         
285         
286         /**
287          * Handler for when the Preview button is clicked.
288          */
289         private void onPreview() {
290                 if (desktop != null) {
291                         try {
292                                 PrintSettings settings = Prefs.getPrintSettings();
293                                 // TODO: HIGH: Remove UIManager, and pass settings to the actual printing methods
294                                 TemplateProperties.setColors(settings);
295                                 File f = generateReport(settings);
296                                 desktop.open(f);
297                         } catch (IOException e) {
298                                 log.error("Could not open preview.", e);
299                                 JOptionPane.showMessageDialog(this, new String[] {
300                                                 trans.get("error.preview.desc1"),
301                                                 trans.get("error.preview.desc2") },
302                                                 trans.get("error.preview.title"),
303                                                 JOptionPane.ERROR_MESSAGE);
304                         }
305                 } else {
306                         JOptionPane.showMessageDialog(this, new String[] {
307                                         trans.get("error.preview.desc1"),
308                                         trans.get("error.preview.desc2") },
309                                         trans.get("error.preview.title"),
310                                         JOptionPane.INFORMATION_MESSAGE);
311                 }
312         }
313         
314         /**
315          * Handler for when the "Save as PDF" button is clicked.
316          *
317          * @return      true if the PDF was saved
318          */
319         private boolean onSavePDF() {
320                 
321                 JFileChooser chooser = new JFileChooser();
322                 // Note: source for ExampleFileFilter can be found in FileChooserDemo,
323                 // under the demo/jfc directory in the Java 2 SDK, Standard Edition.
324                 FileFilter filter = new FileFilter() {
325                         
326                         //Accept all directories and all pdf files.
327                         @Override
328                         public boolean accept(File f) {
329                                 if (f.isDirectory())
330                                         return true;
331                                 return f.getName().toLowerCase().endsWith(".pdf");
332                         }
333                         
334                         //The description of this filter
335                         @Override
336                         public String getDescription() {
337                                 return trans.get("filetypes.pdf");
338                         }
339                 };
340                 chooser.setFileFilter(filter);
341                 int returnVal = chooser.showSaveDialog(this);
342                 if (returnVal == JFileChooser.APPROVE_OPTION) {
343                         
344                         try {
345                                 String fname = chooser.getSelectedFile().getCanonicalPath();
346                                 if (!getExtension(fname).equals("pdf")) {
347                                         fname = fname + ".pdf";
348                                 }
349                                 File f = new File(fname);
350                                 PrintSettings settings = Prefs.getPrintSettings();
351                                 // TODO: HIGH: Remove UIManager, and pass settings to the actual printing methods
352                                 TemplateProperties.setColors(settings);
353                                 generateReport(f, settings);
354                         } catch (IOException e) {
355                                 ExceptionHandler.handleErrorCondition(e);
356                         }
357                         return true;
358                 } else {
359                         return false;
360                 }
361         }
362         
363         /**
364          * Get the extension of a file.
365          */
366         private static String getExtension(String s) {
367                 String ext = null;
368                 int i = s.lastIndexOf('.');
369                 
370                 if (i > 0 && i < s.length() - 1) {
371                         ext = s.substring(i + 1).toLowerCase();
372                 }
373                 return ext != null ? ext : "";
374         }
375 }