create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / gui / StorageOptionChooser.java
1 package net.sf.openrocket.gui;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5
6 import javax.swing.BorderFactory;
7 import javax.swing.ButtonGroup;
8 import javax.swing.JCheckBox;
9 import javax.swing.JFrame;
10 import javax.swing.JLabel;
11 import javax.swing.JOptionPane;
12 import javax.swing.JPanel;
13 import javax.swing.JRadioButton;
14 import javax.swing.JSpinner;
15 import javax.swing.SpinnerNumberModel;
16 import javax.swing.event.ChangeEvent;
17 import javax.swing.event.ChangeListener;
18
19 import net.miginfocom.swing.MigLayout;
20 import net.sf.openrocket.document.OpenRocketDocument;
21 import net.sf.openrocket.document.Simulation;
22 import net.sf.openrocket.document.StorageOptions;
23 import net.sf.openrocket.file.RocketSaver;
24 import net.sf.openrocket.file.openrocket.OpenRocketSaver;
25 import net.sf.openrocket.l10n.Translator;
26 import net.sf.openrocket.simulation.FlightData;
27 import net.sf.openrocket.simulation.FlightDataBranch;
28 import net.sf.openrocket.startup.Application;
29
30 public class StorageOptionChooser extends JPanel {
31         
32         public static final double DEFAULT_SAVE_TIME_SKIP = 0.20;
33
34         private final OpenRocketDocument document;
35         
36         private JRadioButton allButton;
37         private JRadioButton someButton;
38         private JRadioButton noneButton;
39         
40         private JSpinner timeSpinner;
41         
42         private JCheckBox compressButton;
43         
44         private JLabel estimateLabel;
45         
46         
47         private boolean artificialEvent = false;
48         private static final Translator trans = Application.getTranslator();
49         
50         public StorageOptionChooser(OpenRocketDocument doc, StorageOptions opts) {
51                 super(new MigLayout());
52                 
53                 this.document = doc;
54                 
55                 
56                 ChangeListener changeUpdater = new ChangeListener() {
57                         @Override
58                         public void stateChanged(ChangeEvent e) {
59                                 updateEstimate();
60                         }
61                 };
62                 ActionListener actionUpdater = new ActionListener() {
63                         @Override
64                         public void actionPerformed(ActionEvent e) {
65                                 updateEstimate();
66                         }
67                 };
68                 
69
70                 ButtonGroup buttonGroup = new ButtonGroup();
71                 String tip;
72                 
73                 //// Simulated data to store:
74                 this.add(new JLabel(trans.get("StorageOptChooser.lbl.Simdatatostore")), "spanx, wrap unrel");
75
76                 //// All simulated data
77                 allButton = new JRadioButton(trans.get("StorageOptChooser.rdbut.Allsimdata"));
78                 //// <html>Store all simulated data.<br>
79                 //// This can result in very large files!
80                 allButton.setToolTipText(trans.get("StorageOptChooser.lbl.longA1") +
81                                 trans.get("StorageOptChooser.lbl.longA2"));
82                 buttonGroup.add(allButton);
83                 allButton.addActionListener(actionUpdater);
84                 this.add(allButton, "spanx, wrap rel");
85                 
86                 //// Every
87                 someButton = new JRadioButton(trans.get("StorageOptChooser.rdbut.Every"));
88                 //// <html>Store plottable values approximately this far apart.<br>"
89                 //// Larger values result in smaller files.
90                 tip = trans.get("StorageOptChooser.lbl.longB1") +
91                 trans.get("StorageOptChooser.lbl.longB2");
92                 someButton.setToolTipText(tip);
93                 buttonGroup.add(someButton);
94                 someButton.addActionListener(actionUpdater);
95                 this.add(someButton, "");
96                 
97                 timeSpinner = new JSpinner(new SpinnerNumberModel(0.0, 0.0, 5.0, 0.1));
98                 timeSpinner.setToolTipText(tip);
99                 timeSpinner.addChangeListener(new ChangeListener() {
100                         @Override
101                         public void stateChanged(ChangeEvent e) {
102                                 if (artificialEvent)
103                                         return;
104                                 someButton.setSelected(true);
105                         }
106                 });
107                 this.add(timeSpinner, "wmin 55lp");
108                 timeSpinner.addChangeListener(changeUpdater);
109                 
110                 //// seconds
111                 JLabel label = new JLabel(trans.get("StorageOptChooser.lbl.seconds"));
112                 label.setToolTipText(tip);
113                 this.add(label, "wrap rel");
114                 
115                 //// Only primary figures
116                 noneButton = new JRadioButton(trans.get("StorageOptChooser.rdbut.Onlyprimfig"));
117                 //// <html>Store only the values shown in the summary table.<br>
118                 //// This results in the smallest files.
119                 noneButton.setToolTipText(trans.get("StorageOptChooser.lbl.longC1") +
120                                 trans.get("StorageOptChooser.lbl.longC2"));
121                 buttonGroup.add(noneButton);
122                 noneButton.addActionListener(actionUpdater);
123                 this.add(noneButton, "spanx, wrap 20lp");
124                 
125                 
126                 //// Compress file
127                 compressButton = new JCheckBox(trans.get("StorageOptChooser.checkbox.Compfile"));
128                 //// Using compression reduces the file size significantly.
129                 compressButton.setToolTipText(trans.get("StorageOptChooser.lbl.UsingComp"));
130                 compressButton.addActionListener(actionUpdater);
131                 this.add(compressButton, "spanx, wrap para");
132                 
133                 
134                 // Estimate is updated in loadOptions(opts)
135                 estimateLabel = new JLabel("");
136                 //// An estimate on how large the resulting file would
137                 //// be with the present options.
138                 estimateLabel.setToolTipText(trans.get("StorageOptChooser.lbl.longD1"));
139                 this.add(estimateLabel, "spanx");
140                 
141                 
142                 this.setBorder(BorderFactory.createCompoundBorder(
143                                 BorderFactory.createEmptyBorder(0, 10, 0, 0),
144                                 //// Save options
145                                 BorderFactory.createTitledBorder(trans.get("StorageOptChooser.ttip.Saveopt"))));
146                 
147                 loadOptions(opts);
148         }
149         
150         
151         public void loadOptions(StorageOptions opts) {
152                 double t;
153                 
154                 // Data storage radio button
155                 t = opts.getSimulationTimeSkip();
156                 if (t == StorageOptions.SIMULATION_DATA_ALL) {
157                         allButton.setSelected(true);
158                         t = DEFAULT_SAVE_TIME_SKIP;
159                 } else if (t == StorageOptions.SIMULATION_DATA_NONE) {
160                         noneButton.setSelected(true);
161                         t = DEFAULT_SAVE_TIME_SKIP;
162                 } else {
163                         someButton.setSelected(true);
164                 }
165                 
166                 // Time skip spinner
167                 artificialEvent = true;
168                 timeSpinner.setValue(t);
169                 artificialEvent = false;
170                 
171                 // Compression checkbox
172                 compressButton.setSelected(opts.isCompressionEnabled());
173                 
174                 updateEstimate();
175         }
176         
177         
178         public void storeOptions(StorageOptions opts) {
179                 double t;
180                 
181                 if (allButton.isSelected()) {
182                         t = StorageOptions.SIMULATION_DATA_ALL;
183                 } else if (noneButton.isSelected()) {
184                         t = StorageOptions.SIMULATION_DATA_NONE;
185                 } else {
186                         t = (Double)timeSpinner.getValue();
187                 }
188                 
189                 opts.setSimulationTimeSkip(t);
190                 
191                 opts.setCompressionEnabled(compressButton.isSelected());
192                 
193                 opts.setExplicitlySet(true);
194         }
195         
196         
197         
198         // TODO: MEDIUM: The estimation method always uses OpenRocketSaver!
199         private static final RocketSaver ROCKET_SAVER = new OpenRocketSaver();
200         
201         private void updateEstimate() {
202                 StorageOptions opts = new StorageOptions();
203                 
204                 storeOptions(opts);
205                 long size = ROCKET_SAVER.estimateFileSize(document, opts);
206                 size = Math.max((size+512)/1024, 1);
207
208                 String formatted;
209                 
210                 if (size >= 10000) {
211                         formatted = (size/1000) + " MB";
212                 } else if (size >= 1000){
213                         formatted = (size/1000) + "." + ((size/100)%10) + " MB";
214                 } else if (size >= 100) {
215                         formatted = ((size/10)*10) + " kB";
216                 } else {
217                         formatted = size + " kB";
218                 }
219
220                 //// Estimated file size:
221                 estimateLabel.setText(trans.get("StorageOptChooser.lbl.Estfilesize") + " " + formatted);
222         }
223         
224         
225         
226         /**
227          * Asks the user the storage options using a modal dialog window if the document
228          * contains simulated data and the user has not explicitly set how to store the data.
229          * 
230          * @param document      the document to check.
231          * @param parent        the parent frame for the dialog.
232          * @return                      <code>true</code> to continue, <code>false</code> if the user cancelled.
233          */
234         public static boolean verifyStorageOptions(OpenRocketDocument document, JFrame parent) {
235                 StorageOptions options = document.getDefaultStorageOptions();
236                 
237                 if (options.isExplicitlySet()) {
238                         // User has explicitly set the values, save as is
239                         return true;
240                 }
241                 
242                 
243                 boolean hasData = false;
244                 
245                 simulationLoop:
246                         for (Simulation s: document.getSimulations()) {
247                                 if (s.getStatus() == Simulation.Status.NOT_SIMULATED ||
248                                                 s.getStatus() == Simulation.Status.EXTERNAL)
249                                         continue;
250                                 
251                                 FlightData data = s.getSimulatedData();
252                                 if (data == null)
253                                         continue;
254                                 
255                                 for (int i=0; i < data.getBranchCount(); i++) {
256                                         FlightDataBranch branch = data.getBranch(i);
257                                         if (branch == null)
258                                                 continue;
259                                         if (branch.getLength() > 0) {
260                                                 hasData = true;
261                                                 break simulationLoop;
262                                         }
263                                 }
264                         }
265                 
266
267                 if (!hasData) {
268                         // No data to store, do not ask only about compression
269                         return true;
270                 }
271                 
272                 
273                 StorageOptionChooser chooser = new StorageOptionChooser(document, options);
274                 
275                 //// Save options
276                 if (JOptionPane.showConfirmDialog(parent, chooser, trans.get("StorageOptChooser.lbl.Saveopt"), 
277                                 JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) !=
278                                         JOptionPane.OK_OPTION) {
279                         // User cancelled
280                         return false;
281                 }
282                 
283                 chooser.storeOptions(options);
284                 return true;
285         }
286         
287 }