create changelog entry
[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     private double rotation = 0d;
66         
67         private final static SwingPreferences prefs = (SwingPreferences) Application.getPreferences();
68         
69         /**
70          * Constructor.
71          *
72      * @param parent     the parent awt component
73          * @param orDocument the OR rocket container
74      * @param theRotation the angle of rocket figure rotation
75          */
76         public PrintDialog(Window parent, OpenRocketDocument orDocument, double theRotation) {
77                 super(parent, trans.get("title"), ModalityType.APPLICATION_MODAL);
78                 
79
80                 JPanel panel = new JPanel(new MigLayout("fill, gap rel unrel"));
81                 this.add(panel);
82                 rotation = theRotation;
83
84                 // before any Desktop APIs are used, first check whether the API is
85                 // supported by this particular VM on this particular host
86                 if (Desktop.isDesktopSupported()) {
87                         desktop = Desktop.getDesktop();
88                 } else {
89                         desktop = null;
90                 }
91                 
92                 document = orDocument;
93                 Rocket rocket = orDocument.getRocket();
94                 
95                 noStagedTree = RocketPrintTree.create(rocket.getName());
96                 noStagedTree.setShowsRootHandles(false);
97                 CheckTreeManager ctm = new net.sf.openrocket.gui.print.components.CheckTreeManager(noStagedTree);
98                 ctm.addTreeSelectionListener(this);
99                 
100                 final int stages = rocket.getStageCount();
101                 
102
103                 JLabel label = new JLabel(trans.get("lbl.selectElements"));
104                 panel.add(label, "wrap unrel");
105                 
106                 // Create the tree
107                 if (stages > 1) {
108                         stagedTree = RocketPrintTree.create(rocket.getName(), rocket.getChildren());
109                         ctm = new CheckTreeManager(stagedTree);
110                         stagedTree.setShowsRootHandles(false);
111                         ctm.addTreeSelectionListener(this);
112                 } else {
113                         stagedTree = noStagedTree;
114                 }
115                 currentTree = stagedTree;
116                 
117                 // Add the tree to the UI
118                 final JScrollPane scrollPane = new JScrollPane(stagedTree);
119                 panel.add(scrollPane, "width 400lp, height 200lp, grow, wrap para");
120                 
121
122                 // Checkboxes and buttons
123                 final JCheckBox sortByStage = new JCheckBox(trans.get("checkbox.showByStage"));
124                 sortByStage.setEnabled(stages > 1);
125                 sortByStage.setSelected(stages > 1);
126                 sortByStage.addActionListener(new ActionListener() {
127                         @Override
128                         public void actionPerformed(ActionEvent e) {
129                                 if (sortByStage.isEnabled()) {
130                                         if (((JCheckBox) e.getSource()).isSelected()) {
131                                                 scrollPane.setViewportView(stagedTree);
132                                                 stagedTree.setExpandsSelectedPaths(true);
133                                                 currentTree = stagedTree;
134                                         }
135                                         else {
136                                                 scrollPane.setViewportView(noStagedTree);
137                                                 noStagedTree.setExpandsSelectedPaths(true);
138                                                 currentTree = noStagedTree;
139                                         }
140                                 }
141                         }
142                 });
143                 panel.add(sortByStage, "aligny top, split");
144                 
145
146                 panel.add(new JPanel(), "growx");
147                 
148
149                 JButton settingsButton = new JButton(trans.get("printdlg.but.settings"));
150                 settingsButton.addActionListener(new ActionListener() {
151                         @Override
152                         public void actionPerformed(ActionEvent e) {
153                                 PrintSettings settings = getPrintSettings();
154                                 log.debug("settings=" + settings);
155                                 PrintSettingsDialog settingsDialog = new PrintSettingsDialog(PrintDialog.this, settings);
156                                 settingsDialog.setVisible(true);
157                                 setPrintSettings(settings);
158                         }
159                 });
160                 panel.add(settingsButton, "wrap para");
161                 
162
163                 previewButton = new JButton(trans.get("but.previewAndPrint"));
164                 previewButton.addActionListener(new ActionListener() {
165                         @Override
166                         public void actionPerformed(ActionEvent e) {
167                                 onPreview();
168                                 PrintDialog.this.setVisible(false);
169                         }
170                 });
171                 panel.add(previewButton, "split, right, gap para");
172                 
173
174                 saveAsPDF = new JButton(trans.get("printdlg.but.saveaspdf"));
175                 saveAsPDF.addActionListener(new ActionListener() {
176                         @Override
177                         public void actionPerformed(ActionEvent e) {
178                                 if (onSavePDF()) {
179                                         PrintDialog.this.setVisible(false);
180                                 }
181                         }
182                 });
183                 panel.add(saveAsPDF, "right, gap para");
184                 
185
186                 cancel = new JButton(trans.get("button.cancel"));
187                 cancel.addActionListener(new ActionListener() {
188                         @Override
189                         public void actionPerformed(ActionEvent e) {
190                                 PrintDialog.this.setVisible(false);
191                         }
192                 });
193                 panel.add(cancel, "right, gap para");
194                 
195
196                 expandAll(currentTree, true);
197                 if (currentTree != noStagedTree) {
198                         expandAll(noStagedTree, true);
199                 }
200                 
201
202                 GUIUtil.setDisposableDialogOptions(this, previewButton);
203                 
204         }
205         
206         
207         @Override
208         public void valueChanged(final TreeSelectionEvent e) {
209                 final TreePath path = e.getNewLeadSelectionPath();
210                 if (path != null) {
211                         previewButton.setEnabled(true);
212                         saveAsPDF.setEnabled(true);
213                 } else {
214                         previewButton.setEnabled(false);
215                         saveAsPDF.setEnabled(false);
216                 }
217         }
218         
219         /**
220          * If expand is true, expands all nodes in the tree. Otherwise, collapses all nodes in the theTree.
221          *
222          * @param theTree   the tree to expand/contract
223          * @param expand expand if true, contract if not
224          */
225         public void expandAll(RocketPrintTree theTree, boolean expand) {
226                 TreeNode root = (TreeNode) theTree.getModel().getRoot();
227                 // Traverse theTree from root
228                 expandAll(theTree, new TreePath(root), expand);
229         }
230         
231         /**
232          * Recursively walk a tree, and if expand is true, expands all nodes in the tree. Otherwise, collapses all nodes in
233          * the theTree.
234          *
235          * @param theTree   the tree to expand/contract
236          * @param parent the node to iterate/recurse over
237          * @param expand expand if true, contract if not
238          */
239         private void expandAll(RocketPrintTree theTree, TreePath parent, boolean expand) {
240                 theTree.addSelectionPath(parent);
241                 // Traverse children
242                 TreeNode node = (TreeNode) parent.getLastPathComponent();
243                 if (node.getChildCount() >= 0) {
244                         for (Enumeration<?> e = node.children(); e.hasMoreElements();) {
245                                 TreeNode n = (TreeNode) e.nextElement();
246                                 TreePath path = parent.pathByAddingChild(n);
247                                 expandAll(theTree, path, expand);
248                         }
249                 }
250                 // Expansion or collapse must be done bottom-up
251                 if (expand) {
252                         theTree.expandPath(parent);
253                 } else {
254                         theTree.collapsePath(parent);
255                 }
256         }
257         
258         
259
260         /**
261          * Generate a report using a temporary file.  The file will be deleted upon JVM exit.
262          *
263      * @param settings  the container of different print settings
264          *
265          * @return a file, populated with the "printed" output (the rocket info)
266          *
267          * @throws IOException thrown if the file could not be generated
268          */
269         private File generateReport(PrintSettings settings) throws IOException {
270                 final File f = File.createTempFile("openrocket-", ".pdf");
271                 f.deleteOnExit();
272                 return generateReport(f, settings);
273         }
274         
275         /**
276          * Generate a report to a specified file.
277          *
278          * @param f     the file to which rocket data will be written
279          * @param settings  the container of different print settings
280          *
281          * @return a file, populated with the "printed" output (the rocket info)
282          *
283          * @throws IOException thrown if the file could not be generated
284          */
285         private File generateReport(File f, PrintSettings settings) throws IOException {
286                 Iterator<PrintableContext> toBePrinted = currentTree.getToBePrinted();
287                 new PrintController().print(document, toBePrinted, new FileOutputStream(f), settings, rotation);
288                 return f;
289         }
290         
291         
292         /**
293          * Handler for when the Preview button is clicked.
294          */
295         private void onPreview() {
296                 if (desktop != null) {
297                         try {
298                                 PrintSettings settings = getPrintSettings();
299                                 // TODO: HIGH: Remove UIManager, and pass settings to the actual printing methods
300                                 TemplateProperties.setColors(settings);
301                                 File f = generateReport(settings);
302                                 desktop.open(f);
303                         } catch (IOException e) {
304                                 log.error("Could not open preview.", e);
305                                 JOptionPane.showMessageDialog(this, new String[] {
306                                                 trans.get("error.preview.desc1"),
307                                                 trans.get("error.preview.desc2") },
308                                                 trans.get("error.preview.title"),
309                                                 JOptionPane.ERROR_MESSAGE);
310                         }
311                 } else {
312                         JOptionPane.showMessageDialog(this, new String[] {
313                                         trans.get("error.preview.desc1"),
314                                         trans.get("error.preview.desc2") },
315                                         trans.get("error.preview.title"),
316                                         JOptionPane.INFORMATION_MESSAGE);
317                 }
318         }
319         
320         /**
321          * Handler for when the "Save as PDF" button is clicked.
322          *
323          * @return      true if the PDF was saved
324          */
325         private boolean onSavePDF() {
326                 
327                 JFileChooser chooser = new JFileChooser();
328                 chooser.setFileFilter(FileHelper.PDF_FILTER);
329                 
330                 // Select initial directory
331                 File dir = document.getFile();
332                 if (dir != null) {
333                         dir = dir.getParentFile();
334                 }
335                 if (dir == null) {
336                         dir = prefs.getDefaultDirectory();
337                 }
338                 chooser.setCurrentDirectory(dir);
339                 
340                 int returnVal = chooser.showSaveDialog(this);
341                 File file = chooser.getSelectedFile();
342                 if (returnVal == JFileChooser.APPROVE_OPTION && file != null) {
343                         
344                         file = FileHelper.ensureExtension(file, "pdf");
345                         if (!FileHelper.confirmWrite(file, this)) {
346                                 return false;
347                         }
348                         
349                         try {
350                                 
351                                 PrintSettings settings = getPrintSettings();
352                                 // TODO: HIGH: Remove UIManager, and pass settings to the actual printing methods
353                                 TemplateProperties.setColors(settings);
354                                 generateReport(file, settings);
355                                 
356                         } catch (IOException e) {
357                                 FileHelper.errorWriting(e, this);
358                                 return false;
359                         }
360                         return true;
361                 } else {
362                         return false;
363                 }
364         }
365         
366         public PrintSettings getPrintSettings() {
367                 PrintSettings settings = new PrintSettings();
368                 Color c;
369                 
370                 c = prefs.getColor("print.template.fillColor", (java.awt.Color) null);
371                 if (c != null) {
372                         settings.setTemplateFillColor(c);
373                 }
374                 
375                 c = prefs.getColor("print.template.borderColor", (java.awt.Color) null);
376                 if (c != null) {
377                         settings.setTemplateBorderColor(c);
378                 }
379                 
380                 settings.setPaperSize(prefs.getEnum("print.paper.size", settings.getPaperSize()));
381                 settings.setPaperOrientation(prefs.getEnum("print.paper.orientation", settings.getPaperOrientation()));
382                 
383                 return settings;
384         }
385         
386         public void setPrintSettings(PrintSettings settings) {
387                 prefs.putColor("print.template.fillColor", settings.getTemplateFillColor() );
388                 prefs.putColor("print.template.borderColor", settings.getTemplateBorderColor() );
389                 prefs.putEnum("print.paper.size", settings.getPaperSize());
390                 prefs.putEnum("print.paper.orientation", settings.getPaperOrientation());
391         }
392
393 }