Updates for 0.9.5
[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 at startup");
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 == null) {
263                                 // Clear selection - huh?
264                                 return;
265                         }
266                         if (!(item instanceof Unit)) {
267                                 throw new IllegalArgumentException("Illegal argument "+item);
268                         }
269                         group.setDefaultUnit(group.getUnitIndex((Unit)item));
270                 }
271                 @Override
272                 public Object getElementAt(int index) {
273                         return group.getUnit(index);
274                 }
275                 @Override
276                 public int getSize() {
277                         return group.getUnitCount();
278                 }
279                 
280                 
281                 public void fireChange() {
282                         this.fireContentsChanged(this, 0, this.getSize());
283                 }
284         }
285         
286
287         
288         private class PrefChoiseSelector extends AbstractListModel implements ComboBoxModel {
289                 private final String preference;
290                 private final String[] descriptions;
291                 
292                 public PrefChoiseSelector(String preference, String ... descriptions) {
293                         this.preference = preference;
294                         this.descriptions = descriptions;
295                 }
296                 
297                 @Override
298                 public Object getSelectedItem() {
299                         return descriptions[Prefs.getChoise(preference, descriptions.length, 0)];
300                 }
301                 
302                 @Override
303                 public void setSelectedItem(Object item) {
304                         if (item == null) {
305                                 // Clear selection - huh?
306                                 return;
307                         }
308                         if (!(item instanceof String)) {
309                                 throw new IllegalArgumentException("Illegal argument "+item);
310                         }
311                         int index;
312                         for (index = 0; index < descriptions.length; index++) {
313                                 if (((String)item).equalsIgnoreCase(descriptions[index]))
314                                         break;
315                         }
316                         if (index >= descriptions.length) {
317                                 throw new IllegalArgumentException("Illegal argument "+item);
318                         }
319                         
320                         Prefs.putChoise(preference, index);
321                 }
322                 
323                 @Override
324                 public Object getElementAt(int index) {
325                         return descriptions[index];
326                 }
327                 @Override
328                 public int getSize() {
329                         return descriptions.length;
330                 }
331         }
332         
333
334         private class PrefBooleanSelector extends AbstractListModel implements ComboBoxModel {
335                 private final String preference;
336                 private final String trueDesc, falseDesc;
337                 private final boolean def;
338                 
339                 public PrefBooleanSelector(String preference, String falseDescription, 
340                                 String trueDescription, boolean defaultState) {
341                         this.preference = preference;
342                         this.trueDesc = trueDescription;
343                         this.falseDesc = falseDescription;
344                         this.def = defaultState;
345                 }
346                 
347                 @Override
348                 public Object getSelectedItem() {
349                         if (Prefs.NODE.getBoolean(preference, def)) {
350                                 return trueDesc;
351                         } else {
352                                 return falseDesc;
353                         }
354                 }
355                 
356                 @Override
357                 public void setSelectedItem(Object item) {
358                         if (item == null) {
359                                 // Clear selection - huh?
360                                 return;
361                         }
362                         if (!(item instanceof String)) {
363                                 throw new IllegalArgumentException("Illegal argument "+item);
364                         }
365                         
366                         if (trueDesc.equals(item)) {
367                                 Prefs.NODE.putBoolean(preference, true);
368                         } else if (falseDesc.equals(item)) {
369                                 Prefs.NODE.putBoolean(preference, false);
370                         } else {
371                                 throw new IllegalArgumentException("Illegal argument "+item);
372                         }
373                 }
374                 
375                 @Override
376                 public Object getElementAt(int index) {
377                         switch (index) {
378                         case 0:
379                                 return def ? trueDesc : falseDesc;
380
381                         case 1:
382                                 return def ? falseDesc: trueDesc;
383                                 
384                         default:
385                                 throw new IndexOutOfBoundsException("Boolean asked for index="+index);
386                         }
387                 }
388                 @Override
389                 public int getSize() {
390                         return 2;
391                 }
392         }
393         
394         
395         private void checkForUpdates() {
396                 final UpdateInfoRetriever retriever = new UpdateInfoRetriever();
397                 retriever.start();
398                 
399                 
400                 // Progress dialog
401                 final JDialog dialog = new JDialog(this, ModalityType.APPLICATION_MODAL);
402                 JPanel panel = new JPanel(new MigLayout());
403                 
404                 panel.add(new JLabel("Checking for updates..."), "wrap");
405                 
406                 JProgressBar bar = new JProgressBar();
407                 bar.setIndeterminate(true);
408                 panel.add(bar, "growx, wrap para");
409                 
410                 JButton cancel = new JButton("Cancel");
411                 cancel.addActionListener(new ActionListener() {
412                         @Override
413                         public void actionPerformed(ActionEvent e) {
414                                 dialog.dispose();
415                         }
416                 });
417                 panel.add(cancel, "right");
418                 dialog.add(panel);
419                 
420                 GUIUtil.setDisposableDialogOptions(dialog, cancel);
421                 
422                 
423                 // Timer to monitor progress
424                 final Timer timer = new Timer(100, null);
425                 final long startTime = System.currentTimeMillis();
426
427                 ActionListener listener = new ActionListener() {
428                         @Override
429                         public void actionPerformed(ActionEvent e) {
430                                 if (!retriever.isRunning() || startTime+10000 < System.currentTimeMillis()) {
431                                         timer.stop();
432                                         dialog.dispose();
433                                 }
434                         }
435                 };
436                 timer.addActionListener(listener);
437                 timer.start();
438                 
439                 
440                 // Wait for action
441                 dialog.setVisible(true);
442                 
443                 
444                 // Check result
445                 UpdateInfo info = retriever.getUpdateInfo();
446                 if (info == null) {
447                         JOptionPane.showMessageDialog(this, 
448                                         "An error occurred while communicating with the server.", 
449                                         "Unable to retrieve update information", JOptionPane.WARNING_MESSAGE, null);
450                 } else if (info.getLatestVersion() == null || 
451                                 info.getLatestVersion().equals("") ||
452                                 Prefs.getVersion().equalsIgnoreCase(info.getLatestVersion())) {
453                         JOptionPane.showMessageDialog(this, 
454                                         "You are running the latest version of OpenRocket.", 
455                                         "No updates available", JOptionPane.INFORMATION_MESSAGE, null);
456                 } else {
457                         UpdateInfoDialog infoDialog = new UpdateInfoDialog(info);
458                         infoDialog.setVisible(true);
459                         if (infoDialog.isReminderSelected()) {
460                                 Prefs.putString(Prefs.LAST_UPDATE, "");
461                         } else {
462                                 Prefs.putString(Prefs.LAST_UPDATE, info.getLatestVersion());
463                         }
464                 }
465                 
466         }
467         
468         
469         ////////  Singleton implementation  ////////
470         
471         private static PreferencesDialog dialog = null;
472         
473         public static void showPreferences() {
474                 if (dialog != null) {
475                         dialog.dispose();
476                 }
477                 dialog = new PreferencesDialog();
478                 dialog.setVisible(true);
479         }
480         
481         
482 }