4 package net.sf.openrocket.gui.dialogs;
6 import java.awt.Desktop;
7 import java.awt.Window;
8 import java.awt.event.ActionEvent;
9 import java.awt.event.ActionListener;
11 import java.io.FileOutputStream;
12 import java.io.IOException;
13 import java.util.Enumeration;
14 import java.util.Iterator;
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;
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;
47 * This class isolates the Swing components used to create a panel that is added to a standard Java print dialog.
49 public class PrintDialog extends JDialog implements TreeSelectionListener {
51 // FIXME: Printouts use SI units even when imperial are selected
52 // FIXME: Array out of bounds exception when printing
54 private static final LogHelper log = Application.getLogger();
55 private static final Translator trans = Application.getTranslator();
57 private final Desktop desktop;
59 private final RocketPrintTree stagedTree;
60 private final RocketPrintTree noStagedTree;
61 private OpenRocketDocument document;
62 private RocketPrintTree currentTree;
64 private JButton previewButton;
65 private JButton saveAsPDF;
66 private JButton cancel;
71 * @param orDocument the OR rocket container
73 public PrintDialog(Window parent, OpenRocketDocument orDocument) {
74 super(parent, trans.get("title"), ModalityType.APPLICATION_MODAL);
77 JPanel panel = new JPanel(new MigLayout("fill, gap rel unrel"));
81 // before any Desktop APIs are used, first check whether the API is
82 // supported by this particular VM on this particular host
83 if (Desktop.isDesktopSupported()) {
84 desktop = Desktop.getDesktop();
89 document = orDocument;
90 Rocket rocket = orDocument.getRocket();
92 noStagedTree = RocketPrintTree.create(rocket.getName());
93 noStagedTree.setShowsRootHandles(false);
94 CheckTreeManager ctm = new net.sf.openrocket.gui.print.components.CheckTreeManager(noStagedTree);
95 ctm.addTreeSelectionListener(this);
97 final int stages = rocket.getStageCount();
100 JLabel label = new JLabel(trans.get("lbl.selectElements"));
101 panel.add(label, "wrap unrel");
105 stagedTree = RocketPrintTree.create(rocket.getName(), rocket.getChildren());
106 ctm = new CheckTreeManager(stagedTree);
107 stagedTree.setShowsRootHandles(false);
108 ctm.addTreeSelectionListener(this);
110 stagedTree = noStagedTree;
112 currentTree = stagedTree;
114 // Add the tree to the UI
115 final JScrollPane scrollPane = new JScrollPane(stagedTree);
116 panel.add(scrollPane, "width 400lp, height 200lp, grow, wrap para");
119 // Checkboxes and buttons
120 final JCheckBox sortByStage = new JCheckBox(trans.get("checkbox.showByStage"));
121 sortByStage.setEnabled(stages > 1);
122 sortByStage.setSelected(stages > 1);
123 sortByStage.addActionListener(new ActionListener() {
125 public void actionPerformed(ActionEvent e) {
126 if (sortByStage.isEnabled()) {
127 if (((JCheckBox) e.getSource()).isSelected()) {
128 scrollPane.setViewportView(stagedTree);
129 stagedTree.setExpandsSelectedPaths(true);
130 currentTree = stagedTree;
133 scrollPane.setViewportView(noStagedTree);
134 noStagedTree.setExpandsSelectedPaths(true);
135 currentTree = noStagedTree;
140 panel.add(sortByStage, "aligny top, split");
143 panel.add(new JPanel(), "growx");
146 JButton settingsButton = new JButton(trans.get("printdlg.but.settings"));
147 settingsButton.addActionListener(new ActionListener() {
149 public void actionPerformed(ActionEvent e) {
150 PrintSettings settings = Prefs.getPrintSettings();
151 log.debug("settings=" + settings);
152 PrintSettingsDialog settingsDialog = new PrintSettingsDialog(PrintDialog.this, settings);
153 settingsDialog.setVisible(true);
154 Prefs.setPrintSettings(settings);
157 panel.add(settingsButton, "wrap para");
160 previewButton = new JButton(trans.get("but.previewAndPrint"));
161 previewButton.addActionListener(new ActionListener() {
163 public void actionPerformed(ActionEvent e) {
165 PrintDialog.this.setVisible(false);
168 panel.add(previewButton, "split, right, gap para");
171 saveAsPDF = new JButton(trans.get("printdlg.but.saveaspdf"));
172 saveAsPDF.addActionListener(new ActionListener() {
174 public void actionPerformed(ActionEvent e) {
176 PrintDialog.this.setVisible(false);
180 panel.add(saveAsPDF, "right, gap para");
183 cancel = new JButton(trans.get("button.cancel"));
184 cancel.addActionListener(new ActionListener() {
186 public void actionPerformed(ActionEvent e) {
187 PrintDialog.this.setVisible(false);
190 panel.add(cancel, "right, gap para");
193 expandAll(currentTree, true);
194 if (currentTree != noStagedTree) {
195 expandAll(noStagedTree, true);
199 GUIUtil.setDisposableDialogOptions(this, previewButton);
205 public void valueChanged(final TreeSelectionEvent e) {
206 final TreePath path = e.getNewLeadSelectionPath();
208 previewButton.setEnabled(true);
209 saveAsPDF.setEnabled(true);
211 previewButton.setEnabled(false);
212 saveAsPDF.setEnabled(false);
217 * If expand is true, expands all nodes in the tree. Otherwise, collapses all nodes in the theTree.
219 * @param theTree the tree to expand/contract
220 * @param expand expand if true, contract if not
222 public void expandAll(RocketPrintTree theTree, boolean expand) {
223 TreeNode root = (TreeNode) theTree.getModel().getRoot();
224 // Traverse theTree from root
225 expandAll(theTree, new TreePath(root), expand);
229 * Recursively walk a tree, and if expand is true, expands all nodes in the tree. Otherwise, collapses all nodes in
232 * @param theTree the tree to expand/contract
233 * @param parent the node to iterate/recurse over
234 * @param expand expand if true, contract if not
236 private void expandAll(RocketPrintTree theTree, TreePath parent, boolean expand) {
237 theTree.addSelectionPath(parent);
239 TreeNode node = (TreeNode) parent.getLastPathComponent();
240 if (node.getChildCount() >= 0) {
241 for (Enumeration<?> e = node.children(); e.hasMoreElements();) {
242 TreeNode n = (TreeNode) e.nextElement();
243 TreePath path = parent.pathByAddingChild(n);
244 expandAll(theTree, path, expand);
247 // Expansion or collapse must be done bottom-up
249 theTree.expandPath(parent);
251 theTree.collapsePath(parent);
258 * Generate a report using a temporary file. The file will be deleted upon JVM exit.
260 * @param paper the name of the paper size
262 * @return a file, populated with the "printed" output (the rocket info)
264 * @throws IOException thrown if the file could not be generated
266 private File generateReport(PrintSettings settings) throws IOException {
267 final File f = File.createTempFile("openrocket-", ".pdf");
269 return generateReport(f, settings);
273 * Generate a report to a specified file.
275 * @param f the file to which rocket data will be written
276 * @param paper the name of the paper size
278 * @return a file, populated with the "printed" output (the rocket info)
280 * @throws IOException thrown if the file could not be generated
282 private File generateReport(File f, PrintSettings settings) throws IOException {
283 Iterator<PrintableContext> toBePrinted = currentTree.getToBePrinted();
284 new PrintController().print(document, toBePrinted, new FileOutputStream(f), settings);
290 * Handler for when the Preview button is clicked.
292 private void onPreview() {
293 if (desktop != null) {
295 PrintSettings settings = Prefs.getPrintSettings();
296 // TODO: HIGH: Remove UIManager, and pass settings to the actual printing methods
297 TemplateProperties.setColors(settings);
298 File f = generateReport(settings);
300 } catch (IOException e) {
301 log.error("Could not open preview.", e);
302 JOptionPane.showMessageDialog(this, new String[] {
303 trans.get("error.preview.desc1"),
304 trans.get("error.preview.desc2") },
305 trans.get("error.preview.title"),
306 JOptionPane.ERROR_MESSAGE);
309 JOptionPane.showMessageDialog(this, new String[] {
310 trans.get("error.preview.desc1"),
311 trans.get("error.preview.desc2") },
312 trans.get("error.preview.title"),
313 JOptionPane.INFORMATION_MESSAGE);
318 * Handler for when the "Save as PDF" button is clicked.
320 * @return true if the PDF was saved
322 private boolean onSavePDF() {
324 JFileChooser chooser = new JFileChooser();
325 // Note: source for ExampleFileFilter can be found in FileChooserDemo,
326 // under the demo/jfc directory in the Java 2 SDK, Standard Edition.
327 FileFilter filter = new FileFilter() {
329 //Accept all directories and all pdf files.
331 public boolean accept(File f) {
334 return f.getName().toLowerCase().endsWith(".pdf");
337 //The description of this filter
339 public String getDescription() {
340 return trans.get("filetypes.pdf");
343 chooser.setFileFilter(filter);
344 int returnVal = chooser.showSaveDialog(this);
345 if (returnVal == JFileChooser.APPROVE_OPTION) {
348 String fname = chooser.getSelectedFile().getCanonicalPath();
349 if (!getExtension(fname).equals("pdf")) {
350 fname = fname + ".pdf";
352 File f = new File(fname);
353 PrintSettings settings = Prefs.getPrintSettings();
354 // TODO: HIGH: Remove UIManager, and pass settings to the actual printing methods
355 TemplateProperties.setColors(settings);
356 generateReport(f, settings);
357 } catch (IOException e) {
358 ExceptionHandler.handleErrorCondition(e);
367 * Get the extension of a file.
369 private static String getExtension(String s) {
371 int i = s.lastIndexOf('.');
373 if (i > 0 && i < s.length() - 1) {
374 ext = s.substring(i + 1).toLowerCase();
376 return ext != null ? ext : "";