updates for 0.9.4
[debian/openrocket] / src / net / sf / openrocket / gui / dialogs / preferences / PreferencesDialog.java
1 package net.sf.openrocket.gui.dialogs.preferences;
2
3 import java.awt.Dialog;
4 import java.awt.Window;
5 import java.awt.event.ActionEvent;
6 import java.awt.event.ActionListener;
7 import java.awt.event.WindowAdapter;
8 import java.awt.event.WindowEvent;
9 import java.util.ArrayList;
10 import java.util.List;
11
12 import javax.swing.AbstractListModel;
13 import javax.swing.ComboBoxModel;
14 import javax.swing.JButton;
15 import javax.swing.JCheckBox;
16 import javax.swing.JComboBox;
17 import javax.swing.JDialog;
18 import javax.swing.JLabel;
19 import javax.swing.JOptionPane;
20 import javax.swing.JPanel;
21 import javax.swing.JProgressBar;
22 import javax.swing.JTabbedPane;
23 import javax.swing.Timer;
24
25 import net.miginfocom.swing.MigLayout;
26 import net.sf.openrocket.communication.UpdateInfo;
27 import net.sf.openrocket.communication.UpdateInfoRetriever;
28 import net.sf.openrocket.gui.components.StyledLabel;
29 import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
30 import net.sf.openrocket.unit.Unit;
31 import net.sf.openrocket.unit.UnitGroup;
32 import net.sf.openrocket.util.GUIUtil;
33 import net.sf.openrocket.util.Prefs;
34
35 public class PreferencesDialog extends JDialog {
36         
37         private final List<DefaultUnitSelector> unitSelectors = new ArrayList<DefaultUnitSelector>();
38
39         private PreferencesDialog() {
40                 super((Window)null, "Preferences", Dialog.ModalityType.APPLICATION_MODAL);
41                 
42                 JPanel panel = new JPanel(new MigLayout("fill, gap unrel","[grow]","[grow][]"));
43                                 
44                 JTabbedPane tabbedPane = new JTabbedPane();
45                 panel.add(tabbedPane,"grow, wrap");
46                 
47
48                 tabbedPane.addTab("Units", null, unitsPane(), "Default units");
49                 tabbedPane.addTab("Materials", null, new MaterialEditPanel(), "Custom materials");
50                 tabbedPane.addTab("Options", null, optionsPane(), "Miscellaneous options");
51                 
52                 
53                 JButton close = new JButton("Close");
54                 close.addActionListener(new ActionListener() {
55                         @Override
56                         public void actionPerformed(ActionEvent arg0) {
57                                 PreferencesDialog.this.setVisible(false);
58                                 PreferencesDialog.this.dispose();
59                         }
60                 });
61                 panel.add(close,"span, right, tag close");
62                 
63                 this.setContentPane(panel);
64                 pack();
65                 this.setLocationRelativeTo(null);
66                 
67                 this.addWindowListener(new WindowAdapter() {
68                         @Override
69                         public void windowClosed(WindowEvent e) {
70                                 Prefs.storeDefaultUnits();
71                         }
72                 });
73
74                 GUIUtil.setDisposableDialogOptions(this, close);
75         }
76         
77         
78         private JPanel optionsPane() {
79                 JPanel panel = new JPanel(new MigLayout("fillx, ins 30lp n n n"));
80                 
81                 
82                 panel.add(new JLabel("Position to insert new body components:"), "gapright para");
83                 panel.add(new JComboBox(new PrefChoiseSelector(Prefs.BODY_COMPONENT_INSERT_POSITION_KEY,
84                                 "Always ask", "Insert in middle", "Add to end")), "wrap para, growx, sg combos");
85                 
86                 panel.add(new JLabel("Confirm deletion of simulations:"));
87                 panel.add(new JComboBox(new PrefBooleanSelector(Prefs.CONFIRM_DELETE_SIMULATION,
88                                 "Delete", "Confirm", true)), "wrap 40lp, growx, sg combos");
89                 
90                 
91                 final JCheckBox softwareUpdateBox = new JCheckBox("Check for software updates");
92                 softwareUpdateBox.setSelected(Prefs.getCheckUpdates());
93                 softwareUpdateBox.addActionListener(new ActionListener() {
94                         @Override
95                         public void actionPerformed(ActionEvent e) {
96                                 Prefs.setCheckUpdates(softwareUpdateBox.isSelected());
97                         }
98                 });
99                 panel.add(softwareUpdateBox);
100                 
101                 JButton button = new JButton("Check now");
102                 button.setToolTipText("Check for software updates now");
103                 button.addActionListener(new ActionListener() {
104                         @Override
105                         public void actionPerformed(ActionEvent e) {
106                                 checkForUpdates();
107                         }
108                 });
109                 panel.add(button, "right, wrap");
110                 
111                 
112                 return panel;
113         }
114         
115         
116         
117         private JPanel unitsPane() {
118                 JPanel panel = new JPanel(new MigLayout("", "[][]40lp[][]"));
119                 JComboBox combo;
120                 
121                 panel.add(new JLabel("Select your preferred units:"), "span, wrap paragraph");
122                 
123                 
124                 panel.add(new JLabel("Rocket dimensions:"));
125                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_LENGTH));
126                 panel.add(combo, "sizegroup boxes");
127                 
128                 panel.add(new JLabel("Line density:"));
129                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_LINE));
130                 panel.add(combo, "sizegroup boxes, wrap");
131                 
132                 
133                 
134                 panel.add(new JLabel("Motor dimensions:"));
135                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_MOTOR_DIMENSIONS));
136                 panel.add(combo, "sizegroup boxes");
137                 
138                 panel.add(new JLabel("Surface density:"));
139                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_SURFACE));
140                 panel.add(combo, "sizegroup boxes, wrap");
141                 
142
143                 
144                 panel.add(new JLabel("Distance:"));
145                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DISTANCE));
146                 panel.add(combo, "sizegroup boxes");
147                 
148                 panel.add(new JLabel("Bulk density::"));
149                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_BULK));
150                 panel.add(combo, "sizegroup boxes, wrap");
151                 
152
153                 
154                 panel.add(new JLabel("Velocity:"));
155                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_VELOCITY));
156                 panel.add(combo, "sizegroup boxes");
157
158                 panel.add(new JLabel("Surface roughness:"));
159                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ROUGHNESS));
160                 panel.add(combo, "sizegroup boxes, wrap");
161                 
162                 
163                 
164                 panel.add(new JLabel("Acceleration:"));
165                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ACCELERATION));
166                 panel.add(combo, "sizegroup boxes");
167
168                 panel.add(new JLabel("Area:"));
169                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_AREA));
170                 panel.add(combo, "sizegroup boxes, wrap");
171                 
172                 
173
174                 panel.add(new JLabel("Mass:"));
175                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_MASS));
176                 panel.add(combo, "sizegroup boxes");
177                 
178                 panel.add(new JLabel("Angle:"));
179                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ANGLE));
180                 panel.add(combo, "sizegroup boxes, wrap");
181                 
182
183                 
184                 panel.add(new JLabel("Force:"));
185                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_FORCE));
186                 panel.add(combo, "sizegroup boxes");
187                 
188                 panel.add(new JLabel("Roll rate:"));
189                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ROLL));
190                 panel.add(combo, "sizegroup boxes, wrap");
191                 
192
193                 
194                 panel.add(new JLabel("Total impulse:"));
195                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_IMPULSE));
196                 panel.add(combo, "sizegroup boxes");
197                 
198                 panel.add(new JLabel("Temperature:"));
199                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_TEMPERATURE));
200                 panel.add(combo, "sizegroup boxes, wrap");
201                 
202
203                 
204                 panel.add(new JLabel("Stability:"));
205                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_STABILITY));
206                 panel.add(combo, "sizegroup boxes");
207
208                 panel.add(new JLabel("Pressure:"));
209                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_PRESSURE));
210                 panel.add(combo, "sizegroup boxes, wrap para");
211                 
212                 
213                 
214                 JButton button = new JButton("Default metric");
215                 button.addActionListener(new ActionListener() {
216                         @Override
217                         public void actionPerformed(ActionEvent e) {
218                                 UnitGroup.setDefaultMetricUnits();
219                                 for (DefaultUnitSelector s: unitSelectors)
220                                         s.fireChange();
221                         }
222                 });
223                 panel.add(button, "spanx, split 2, grow");
224                 
225                 button = new JButton("Default imperial");
226                 button.addActionListener(new ActionListener() {
227                         @Override
228                         public void actionPerformed(ActionEvent e) {
229                                 UnitGroup.setDefaultImperialUnits();
230                                 for (DefaultUnitSelector s: unitSelectors)
231                                         s.fireChange();
232                         }
233                 });
234                 panel.add(button, "grow, wrap para");
235                 
236                 
237                 panel.add(new StyledLabel("The effects will take place the next time you open a window.",-2),
238                                 "spanx, wrap");
239                 
240
241                 return panel;
242         }
243         
244         
245         
246         
247         
248         private class DefaultUnitSelector extends AbstractListModel implements ComboBoxModel {
249                 
250                 private final UnitGroup group;
251                 public DefaultUnitSelector(UnitGroup group) {
252                         this.group = group;
253                         unitSelectors.add(this);
254                 }
255                 
256                 @Override
257                 public Object getSelectedItem() {
258                         return group.getDefaultUnit();
259                 }
260                 @Override
261                 public void setSelectedItem(Object item) {
262                         if (!(item instanceof Unit)) {
263                                 throw new IllegalArgumentException("Illegal argument "+item);
264                         }
265                         group.setDefaultUnit(group.getUnitIndex((Unit)item));
266                 }
267                 @Override
268                 public Object getElementAt(int index) {
269                         return group.getUnit(index);
270                 }
271                 @Override
272                 public int getSize() {
273                         return group.getUnitCount();
274                 }
275                 
276                 
277                 public void fireChange() {
278                         this.fireContentsChanged(this, 0, this.getSize());
279                 }
280         }
281         
282
283         
284         private class PrefChoiseSelector extends AbstractListModel implements ComboBoxModel {
285                 private final String preference;
286                 private final String[] descriptions;
287                 
288                 public PrefChoiseSelector(String preference, String ... descriptions) {
289                         this.preference = preference;
290                         this.descriptions = descriptions;
291                 }
292                 
293                 @Override
294                 public Object getSelectedItem() {
295                         return descriptions[Prefs.getChoise(preference, descriptions.length, 0)];
296                 }
297                 
298                 @Override
299                 public void setSelectedItem(Object item) {
300                         if (!(item instanceof String)) {
301                                 throw new IllegalArgumentException("Illegal argument "+item);
302                         }
303                         int index;
304                         for (index = 0; index < descriptions.length; index++) {
305                                 if (((String)item).equalsIgnoreCase(descriptions[index]))
306                                         break;
307                         }
308                         if (index >= descriptions.length) {
309                                 throw new IllegalArgumentException("Illegal argument "+item);
310                         }
311                         
312                         Prefs.putChoise(preference, index);
313                 }
314                 
315                 @Override
316                 public Object getElementAt(int index) {
317                         return descriptions[index];
318                 }
319                 @Override
320                 public int getSize() {
321                         return descriptions.length;
322                 }
323         }
324         
325
326         private class PrefBooleanSelector extends AbstractListModel implements ComboBoxModel {
327                 private final String preference;
328                 private final String trueDesc, falseDesc;
329                 private final boolean def;
330                 
331                 public PrefBooleanSelector(String preference, String falseDescription, 
332                                 String trueDescription, boolean defaultState) {
333                         this.preference = preference;
334                         this.trueDesc = trueDescription;
335                         this.falseDesc = falseDescription;
336                         this.def = defaultState;
337                 }
338                 
339                 @Override
340                 public Object getSelectedItem() {
341                         if (Prefs.NODE.getBoolean(preference, def)) {
342                                 return trueDesc;
343                         } else {
344                                 return falseDesc;
345                         }
346                 }
347                 
348                 @Override
349                 public void setSelectedItem(Object item) {
350                         if (!(item instanceof String)) {
351                                 throw new IllegalArgumentException("Illegal argument "+item);
352                         }
353                         
354                         if (trueDesc.equals(item)) {
355                                 Prefs.NODE.putBoolean(preference, true);
356                         } else if (falseDesc.equals(item)) {
357                                 Prefs.NODE.putBoolean(preference, false);
358                         } else {
359                                 throw new IllegalArgumentException("Illegal argument "+item);
360                         }
361                 }
362                 
363                 @Override
364                 public Object getElementAt(int index) {
365                         switch (index) {
366                         case 0:
367                                 return def ? trueDesc : falseDesc;
368
369                         case 1:
370                                 return def ? falseDesc: trueDesc;
371                                 
372                         default:
373                                 throw new IndexOutOfBoundsException("Boolean asked for index="+index);
374                         }
375                 }
376                 @Override
377                 public int getSize() {
378                         return 2;
379                 }
380         }
381         
382         
383         private void checkForUpdates() {
384                 final UpdateInfoRetriever retriever = new UpdateInfoRetriever();
385                 retriever.start();
386                 
387                 
388                 // Progress dialog
389                 final JDialog dialog = new JDialog(this, ModalityType.APPLICATION_MODAL);
390                 JPanel panel = new JPanel(new MigLayout());
391                 
392                 panel.add(new JLabel("Checking for updates..."), "wrap");
393                 
394                 JProgressBar bar = new JProgressBar();
395                 bar.setIndeterminate(true);
396                 panel.add(bar, "growx, wrap para");
397                 
398                 JButton cancel = new JButton("Cancel");
399                 cancel.addActionListener(new ActionListener() {
400                         @Override
401                         public void actionPerformed(ActionEvent e) {
402                                 dialog.dispose();
403                         }
404                 });
405                 panel.add(cancel, "right");
406                 dialog.add(panel);
407                 
408                 GUIUtil.setDisposableDialogOptions(dialog, cancel);
409                 
410                 
411                 // Timer to monitor progress
412                 final Timer timer = new Timer(100, null);
413                 final long startTime = System.currentTimeMillis();
414
415                 ActionListener listener = new ActionListener() {
416                         @Override
417                         public void actionPerformed(ActionEvent e) {
418                                 if (!retriever.isRunning() || startTime+10000 < System.currentTimeMillis()) {
419                                         timer.stop();
420                                         dialog.dispose();
421                                 }
422                         }
423                 };
424                 timer.addActionListener(listener);
425                 timer.start();
426                 
427                 
428                 // Wait for action
429                 dialog.setVisible(true);
430                 
431                 
432                 // Check result
433                 UpdateInfo info = retriever.getUpdateInfo();
434                 if (info == null) {
435                         JOptionPane.showMessageDialog(this, 
436                                         "An error occurred while communicating with the server.", 
437                                         "Unable to retrieve update information", JOptionPane.WARNING_MESSAGE, null);
438                 } else if (info.getLatestVersion() == null || 
439                                 info.getLatestVersion().equals("") ||
440                                 Prefs.getVersion().equalsIgnoreCase(info.getLatestVersion())) {
441                         JOptionPane.showMessageDialog(this, 
442                                         "You are running the latest version of OpenRocket.", 
443                                         "No updates available", JOptionPane.INFORMATION_MESSAGE, null);
444                 } else {
445                         new UpdateInfoDialog(info).setVisible(true);
446                 }
447                 
448         }
449         
450         
451         ////////  Singleton implementation  ////////
452         
453         private static PreferencesDialog dialog = null;
454         
455         public static void showPreferences() {
456                 if (dialog != null) {
457                         dialog.dispose();
458                 }
459                 dialog = new PreferencesDialog();
460                 dialog.setVisible(true);
461         }
462         
463         
464 }