added svn:ignores
[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.logging.LogHelper;
40 import net.sf.openrocket.rocketcomponent.Rocket;
41 import net.sf.openrocket.startup.Application;
42 import net.sf.openrocket.util.GUIUtil;
43 import net.sf.openrocket.util.Prefs;
44
45 /**
46  * This class isolates the Swing components used to create a panel that is added to a standard Java print dialog.
47  */
48 public class PrintDialog extends JDialog implements TreeSelectionListener {
49         
50         private static final LogHelper log = Application.getLogger();
51         
52         private static final String SETTINGS_BUTTON_TEXT = "Settings";
53         private static final String PREVIEW_BUTTON_TEXT = "Preview & Print";
54         private static final String SAVE_AS_PDF_BUTTON_TEXT = "Save as PDF";
55         private static final String SHOW_BY_STAGE = "Show By Stage";
56         
57         private final RocketPrintTree stagedTree;
58         private final RocketPrintTree noStagedTree;
59         private OpenRocketDocument document;
60         private RocketPrintTree currentTree;
61         private Desktop desktop = null;
62         
63         private JButton previewButton;
64         private JButton saveAsPDF;
65         private JButton cancel;
66         
67         /**
68          * Constructor.
69          *
70          * @param orDocument the OR rocket container
71          */
72         public PrintDialog(Window parent, OpenRocketDocument orDocument) {
73                 super(parent, "Print or export", ModalityType.APPLICATION_MODAL);
74                 
75
76                 JPanel panel = new JPanel(new MigLayout("fill, gap rel unrel"));
77                 this.add(panel);
78                 
79
80                 // before any Desktop APIs are used, first check whether the API is
81                 // supported by this particular VM on this particular host
82                 if (Desktop.isDesktopSupported()) {
83                         desktop = Desktop.getDesktop();
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("Select elements to include:");
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(SHOW_BY_STAGE);
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(SETTINGS_BUTTON_TEXT);
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(PREVIEW_BUTTON_TEXT);
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(SAVE_AS_PDF_BUTTON_TEXT);
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("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 create temporary file for previewing.", e);
299                                 JOptionPane.showMessageDialog(this, "Could not create a temporary file for previewing.",
300                                                                                                 "Error creating file", JOptionPane.ERROR_MESSAGE);
301                         }
302                 } else {
303                         JOptionPane.showMessageDialog(this,
304                                                                                         "Your environment does not support automatically opening the default PDF viewer.",
305                                                                                         "Error creating file", JOptionPane.INFORMATION_MESSAGE);
306                 }
307         }
308         
309         /**
310          * Handler for when the "Save as PDF" button is clicked.
311          *
312          * @return      true if the PDF was saved
313          */
314         private boolean onSavePDF() {
315                 
316                 JFileChooser chooser = new JFileChooser();
317                 // Note: source for ExampleFileFilter can be found in FileChooserDemo,
318                 // under the demo/jfc directory in the Java 2 SDK, Standard Edition.
319                 FileFilter filter = new FileFilter() {
320                         
321                         //Accept all directories and all pdf files.
322                         @Override
323                         public boolean accept(File f) {
324                                 if (f.isDirectory())
325                                         return true;
326                                 return f.getName().toLowerCase().endsWith(".pdf");
327                         }
328                         
329                         //The description of this filter
330                         @Override
331                         public String getDescription() {
332                                 return "PDF files";
333                         }
334                 };
335                 chooser.setFileFilter(filter);
336                 int returnVal = chooser.showSaveDialog(this);
337                 if (returnVal == JFileChooser.APPROVE_OPTION) {
338                         
339                         try {
340                                 String fname = chooser.getSelectedFile().getCanonicalPath();
341                                 if (!getExtension(fname).equals("pdf")) {
342                                         fname = fname + ".pdf";
343                                 }
344                                 File f = new File(fname);
345                                 PrintSettings settings = Prefs.getPrintSettings();
346                                 // TODO: HIGH: Remove UIManager, and pass settings to the actual printing methods
347                                 TemplateProperties.setColors(settings);
348                                 generateReport(f, settings);
349                         } catch (IOException e) {
350                                 ExceptionHandler.handleErrorCondition(e);
351                         }
352                         return true;
353                 } else {
354                         return false;
355                 }
356         }
357         
358         /**
359          * Get the extension of a file.
360          */
361         private static String getExtension(String s) {
362                 String ext = null;
363                 int i = s.lastIndexOf('.');
364                 
365                 if (i > 0 && i < s.length() - 1) {
366                         ext = s.substring(i + 1).toLowerCase();
367                 }
368                 return ext != null ? ext : "";
369         }
370 }