729586d3455e70e69423fbbc5200ab2942051360
[debian/openrocket] / core / 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.Color;
7 import java.awt.Desktop;
8 import java.awt.Window;
9 import java.awt.event.ActionEvent;
10 import java.awt.event.ActionListener;
11 import java.io.File;
12 import java.io.FileOutputStream;
13 import java.io.IOException;
14 import java.util.Enumeration;
15 import java.util.Iterator;
16
17 import javax.swing.JButton;
18 import javax.swing.JCheckBox;
19 import javax.swing.JDialog;
20 import javax.swing.JFileChooser;
21 import javax.swing.JLabel;
22 import javax.swing.JOptionPane;
23 import javax.swing.JPanel;
24 import javax.swing.JScrollPane;
25 import javax.swing.event.TreeSelectionEvent;
26 import javax.swing.event.TreeSelectionListener;
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.print.PrintController;
33 import net.sf.openrocket.gui.print.PrintSettings;
34 import net.sf.openrocket.gui.print.PrintableContext;
35 import net.sf.openrocket.gui.print.TemplateProperties;
36 import net.sf.openrocket.gui.print.components.CheckTreeManager;
37 import net.sf.openrocket.gui.print.components.RocketPrintTree;
38 import net.sf.openrocket.gui.util.FileHelper;
39 import net.sf.openrocket.gui.util.GUIUtil;
40 import net.sf.openrocket.gui.util.SwingPreferences;
41 import net.sf.openrocket.l10n.Translator;
42 import net.sf.openrocket.logging.LogHelper;
43 import net.sf.openrocket.rocketcomponent.Rocket;
44 import net.sf.openrocket.startup.Application;
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         private final static SwingPreferences prefs = (SwingPreferences) Application.getPreferences();
67         
68         /**
69          * Constructor.
70          *
71          * @param orDocument the OR rocket container
72          */
73         public PrintDialog(Window parent, OpenRocketDocument orDocument) {
74                 super(parent, trans.get("title"), ModalityType.APPLICATION_MODAL);
75                 
76
77                 JPanel panel = new JPanel(new MigLayout("fill, gap rel unrel"));
78                 this.add(panel);
79                 
80
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();
85                 } else {
86                         desktop = null;
87                 }
88                 
89                 document = orDocument;
90                 Rocket rocket = orDocument.getRocket();
91                 
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);
96                 
97                 final int stages = rocket.getStageCount();
98                 
99
100                 JLabel label = new JLabel(trans.get("lbl.selectElements"));
101                 panel.add(label, "wrap unrel");
102                 
103                 // Create the tree
104                 if (stages > 1) {
105                         stagedTree = RocketPrintTree.create(rocket.getName(), rocket.getChildren());
106                         ctm = new CheckTreeManager(stagedTree);
107                         stagedTree.setShowsRootHandles(false);
108                         ctm.addTreeSelectionListener(this);
109                 } else {
110                         stagedTree = noStagedTree;
111                 }
112                 currentTree = stagedTree;
113                 
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");
117                 
118
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() {
124                         @Override
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;
131                                         }
132                                         else {
133                                                 scrollPane.setViewportView(noStagedTree);
134                                                 noStagedTree.setExpandsSelectedPaths(true);
135                                                 currentTree = noStagedTree;
136                                         }
137                                 }
138                         }
139                 });
140                 panel.add(sortByStage, "aligny top, split");
141                 
142
143                 panel.add(new JPanel(), "growx");
144                 
145
146                 JButton settingsButton = new JButton(trans.get("printdlg.but.settings"));
147                 settingsButton.addActionListener(new ActionListener() {
148                         @Override
149                         public void actionPerformed(ActionEvent e) {
150                                 PrintSettings settings = getPrintSettings();
151                                 log.debug("settings=" + settings);
152                                 PrintSettingsDialog settingsDialog = new PrintSettingsDialog(PrintDialog.this, settings);
153                                 settingsDialog.setVisible(true);
154                                 setPrintSettings(settings);
155                         }
156                 });
157                 panel.add(settingsButton, "wrap para");
158                 
159
160                 previewButton = new JButton(trans.get("but.previewAndPrint"));
161                 previewButton.addActionListener(new ActionListener() {
162                         @Override
163                         public void actionPerformed(ActionEvent e) {
164                                 onPreview();
165                                 PrintDialog.this.setVisible(false);
166                         }
167                 });
168                 panel.add(previewButton, "split, right, gap para");
169                 
170
171                 saveAsPDF = new JButton(trans.get("printdlg.but.saveaspdf"));
172                 saveAsPDF.addActionListener(new ActionListener() {
173                         @Override
174                         public void actionPerformed(ActionEvent e) {
175                                 if (onSavePDF()) {
176                                         PrintDialog.this.setVisible(false);
177                                 }
178                         }
179                 });
180                 panel.add(saveAsPDF, "right, gap para");
181                 
182
183                 cancel = new JButton(trans.get("button.cancel"));
184                 cancel.addActionListener(new ActionListener() {
185                         @Override
186                         public void actionPerformed(ActionEvent e) {
187                                 PrintDialog.this.setVisible(false);
188                         }
189                 });
190                 panel.add(cancel, "right, gap para");
191                 
192
193                 expandAll(currentTree, true);
194                 if (currentTree != noStagedTree) {
195                         expandAll(noStagedTree, true);
196                 }
197                 
198
199                 GUIUtil.setDisposableDialogOptions(this, previewButton);
200                 
201         }
202         
203         
204         @Override
205         public void valueChanged(final TreeSelectionEvent e) {
206                 final TreePath path = e.getNewLeadSelectionPath();
207                 if (path != null) {
208                         previewButton.setEnabled(true);
209                         saveAsPDF.setEnabled(true);
210                 } else {
211                         previewButton.setEnabled(false);
212                         saveAsPDF.setEnabled(false);
213                 }
214         }
215         
216         /**
217          * If expand is true, expands all nodes in the tree. Otherwise, collapses all nodes in the theTree.
218          *
219          * @param theTree   the tree to expand/contract
220          * @param expand expand if true, contract if not
221          */
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);
226         }
227         
228         /**
229          * Recursively walk a tree, and if expand is true, expands all nodes in the tree. Otherwise, collapses all nodes in
230          * the theTree.
231          *
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
235          */
236         private void expandAll(RocketPrintTree theTree, TreePath parent, boolean expand) {
237                 theTree.addSelectionPath(parent);
238                 // Traverse children
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);
245                         }
246                 }
247                 // Expansion or collapse must be done bottom-up
248                 if (expand) {
249                         theTree.expandPath(parent);
250                 } else {
251                         theTree.collapsePath(parent);
252                 }
253         }
254         
255         
256
257         /**
258          * Generate a report using a temporary file.  The file will be deleted upon JVM exit.
259          *
260          * @param paper the name of the paper size
261          *
262          * @return a file, populated with the "printed" output (the rocket info)
263          *
264          * @throws IOException thrown if the file could not be generated
265          */
266         private File generateReport(PrintSettings settings) throws IOException {
267                 final File f = File.createTempFile("openrocket-", ".pdf");
268                 f.deleteOnExit();
269                 return generateReport(f, settings);
270         }
271         
272         /**
273          * Generate a report to a specified file.
274          *
275          * @param f     the file to which rocket data will be written
276          * @param paper the name of the paper size
277          *
278          * @return a file, populated with the "printed" output (the rocket info)
279          *
280          * @throws IOException thrown if the file could not be generated
281          */
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);
285                 return f;
286         }
287         
288         
289         /**
290          * Handler for when the Preview button is clicked.
291          */
292         private void onPreview() {
293                 if (desktop != null) {
294                         try {
295                                 PrintSettings settings = getPrintSettings();
296                                 // TODO: HIGH: Remove UIManager, and pass settings to the actual printing methods
297                                 TemplateProperties.setColors(settings);
298                                 File f = generateReport(settings);
299                                 desktop.open(f);
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);
307                         }
308                 } else {
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);
314                 }
315         }
316         
317         /**
318          * Handler for when the "Save as PDF" button is clicked.
319          *
320          * @return      true if the PDF was saved
321          */
322         private boolean onSavePDF() {
323                 
324                 JFileChooser chooser = new JFileChooser();
325                 chooser.setFileFilter(FileHelper.PDF_FILTER);
326                 
327                 // Select initial directory
328                 File dir = document.getFile();
329                 if (dir != null) {
330                         dir = dir.getParentFile();
331                 }
332                 if (dir == null) {
333                         dir = prefs.getDefaultDirectory();
334                 }
335                 chooser.setCurrentDirectory(dir);
336                 
337                 int returnVal = chooser.showSaveDialog(this);
338                 File file = chooser.getSelectedFile();
339                 if (returnVal == JFileChooser.APPROVE_OPTION && file != null) {
340                         
341                         file = FileHelper.ensureExtension(file, "pdf");
342                         if (!FileHelper.confirmWrite(file, this)) {
343                                 return false;
344                         }
345                         
346                         try {
347                                 
348                                 PrintSettings settings = getPrintSettings();
349                                 // TODO: HIGH: Remove UIManager, and pass settings to the actual printing methods
350                                 TemplateProperties.setColors(settings);
351                                 generateReport(file, settings);
352                                 
353                         } catch (IOException e) {
354                                 FileHelper.errorWriting(e, this);
355                                 return false;
356                         }
357                         return true;
358                 } else {
359                         return false;
360                 }
361         }
362         
363         public PrintSettings getPrintSettings() {
364                 PrintSettings settings = new PrintSettings();
365                 Color c;
366                 
367                 c = prefs.getColor("print.template.fillColor", (java.awt.Color) null);
368                 if (c != null) {
369                         settings.setTemplateFillColor(c);
370                 }
371                 
372                 c = prefs.getColor("print.template.borderColor", (java.awt.Color) null);
373                 if (c != null) {
374                         settings.setTemplateBorderColor(c);
375                 }
376                 
377                 settings.setPaperSize(prefs.getEnum("print.paper.size", settings.getPaperSize()));
378                 settings.setPaperOrientation(prefs.getEnum("print.paper.orientation", settings.getPaperOrientation()));
379                 
380                 return settings;
381         }
382         
383         public void setPrintSettings(PrintSettings settings) {
384                 prefs.putColor("print.template.fillColor", settings.getTemplateFillColor() );
385                 prefs.putColor("print.template.borderColor", settings.getTemplateBorderColor() );
386                 prefs.putEnum("print.paper.size", settings.getPaperSize());
387                 prefs.putEnum("print.paper.orientation", settings.getPaperOrientation());
388         }
389
390 }