1 package net.sf.openrocket.gui.dialogs.preferences;
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;
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;
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;
35 public class PreferencesDialog extends JDialog {
37 private final List<DefaultUnitSelector> unitSelectors = new ArrayList<DefaultUnitSelector>();
39 private PreferencesDialog() {
40 super((Window)null, "Preferences", Dialog.ModalityType.APPLICATION_MODAL);
42 JPanel panel = new JPanel(new MigLayout("fill, gap unrel","[grow]","[grow][]"));
44 JTabbedPane tabbedPane = new JTabbedPane();
45 panel.add(tabbedPane,"grow, wrap");
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");
53 JButton close = new JButton("Close");
54 close.addActionListener(new ActionListener() {
56 public void actionPerformed(ActionEvent arg0) {
57 PreferencesDialog.this.setVisible(false);
58 PreferencesDialog.this.dispose();
61 panel.add(close,"span, right, tag close");
63 this.setContentPane(panel);
65 this.setLocationRelativeTo(null);
67 this.addWindowListener(new WindowAdapter() {
69 public void windowClosed(WindowEvent e) {
70 Prefs.storeDefaultUnits();
74 GUIUtil.setDisposableDialogOptions(this, close);
78 private JPanel optionsPane() {
79 JPanel panel = new JPanel(new MigLayout("fillx, ins 30lp n n n"));
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");
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");
91 final JCheckBox softwareUpdateBox = new JCheckBox("Check for software updates at startup");
92 softwareUpdateBox.setSelected(Prefs.getCheckUpdates());
93 softwareUpdateBox.addActionListener(new ActionListener() {
95 public void actionPerformed(ActionEvent e) {
96 Prefs.setCheckUpdates(softwareUpdateBox.isSelected());
99 panel.add(softwareUpdateBox);
101 JButton button = new JButton("Check now");
102 button.setToolTipText("Check for software updates now");
103 button.addActionListener(new ActionListener() {
105 public void actionPerformed(ActionEvent e) {
109 panel.add(button, "right, wrap");
117 private JPanel unitsPane() {
118 JPanel panel = new JPanel(new MigLayout("", "[][]40lp[][]"));
121 panel.add(new JLabel("Select your preferred units:"), "span, wrap paragraph");
124 panel.add(new JLabel("Rocket dimensions:"));
125 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_LENGTH));
126 panel.add(combo, "sizegroup boxes");
128 panel.add(new JLabel("Line density:"));
129 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_LINE));
130 panel.add(combo, "sizegroup boxes, wrap");
134 panel.add(new JLabel("Motor dimensions:"));
135 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_MOTOR_DIMENSIONS));
136 panel.add(combo, "sizegroup boxes");
138 panel.add(new JLabel("Surface density:"));
139 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_SURFACE));
140 panel.add(combo, "sizegroup boxes, wrap");
144 panel.add(new JLabel("Distance:"));
145 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DISTANCE));
146 panel.add(combo, "sizegroup boxes");
148 panel.add(new JLabel("Bulk density::"));
149 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_BULK));
150 panel.add(combo, "sizegroup boxes, wrap");
154 panel.add(new JLabel("Velocity:"));
155 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_VELOCITY));
156 panel.add(combo, "sizegroup boxes");
158 panel.add(new JLabel("Surface roughness:"));
159 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ROUGHNESS));
160 panel.add(combo, "sizegroup boxes, wrap");
164 panel.add(new JLabel("Acceleration:"));
165 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ACCELERATION));
166 panel.add(combo, "sizegroup boxes");
168 panel.add(new JLabel("Area:"));
169 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_AREA));
170 panel.add(combo, "sizegroup boxes, wrap");
174 panel.add(new JLabel("Mass:"));
175 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_MASS));
176 panel.add(combo, "sizegroup boxes");
178 panel.add(new JLabel("Angle:"));
179 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ANGLE));
180 panel.add(combo, "sizegroup boxes, wrap");
184 panel.add(new JLabel("Force:"));
185 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_FORCE));
186 panel.add(combo, "sizegroup boxes");
188 panel.add(new JLabel("Roll rate:"));
189 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ROLL));
190 panel.add(combo, "sizegroup boxes, wrap");
194 panel.add(new JLabel("Total impulse:"));
195 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_IMPULSE));
196 panel.add(combo, "sizegroup boxes");
198 panel.add(new JLabel("Temperature:"));
199 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_TEMPERATURE));
200 panel.add(combo, "sizegroup boxes, wrap");
204 panel.add(new JLabel("Stability:"));
205 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_STABILITY));
206 panel.add(combo, "sizegroup boxes");
208 panel.add(new JLabel("Pressure:"));
209 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_PRESSURE));
210 panel.add(combo, "sizegroup boxes, wrap para");
214 JButton button = new JButton("Default metric");
215 button.addActionListener(new ActionListener() {
217 public void actionPerformed(ActionEvent e) {
218 UnitGroup.setDefaultMetricUnits();
219 for (DefaultUnitSelector s: unitSelectors)
223 panel.add(button, "spanx, split 2, grow");
225 button = new JButton("Default imperial");
226 button.addActionListener(new ActionListener() {
228 public void actionPerformed(ActionEvent e) {
229 UnitGroup.setDefaultImperialUnits();
230 for (DefaultUnitSelector s: unitSelectors)
234 panel.add(button, "grow, wrap para");
237 panel.add(new StyledLabel("The effects will take place the next time you open a window.",-2),
248 private class DefaultUnitSelector extends AbstractListModel implements ComboBoxModel {
250 private final UnitGroup group;
251 public DefaultUnitSelector(UnitGroup group) {
253 unitSelectors.add(this);
257 public Object getSelectedItem() {
258 return group.getDefaultUnit();
261 public void setSelectedItem(Object item) {
263 // Clear selection - huh?
266 if (!(item instanceof Unit)) {
267 throw new IllegalArgumentException("Illegal argument "+item);
269 group.setDefaultUnit(group.getUnitIndex((Unit)item));
272 public Object getElementAt(int index) {
273 return group.getUnit(index);
276 public int getSize() {
277 return group.getUnitCount();
281 public void fireChange() {
282 this.fireContentsChanged(this, 0, this.getSize());
288 private class PrefChoiseSelector extends AbstractListModel implements ComboBoxModel {
289 private final String preference;
290 private final String[] descriptions;
292 public PrefChoiseSelector(String preference, String ... descriptions) {
293 this.preference = preference;
294 this.descriptions = descriptions;
298 public Object getSelectedItem() {
299 return descriptions[Prefs.getChoise(preference, descriptions.length, 0)];
303 public void setSelectedItem(Object item) {
305 // Clear selection - huh?
308 if (!(item instanceof String)) {
309 throw new IllegalArgumentException("Illegal argument "+item);
312 for (index = 0; index < descriptions.length; index++) {
313 if (((String)item).equalsIgnoreCase(descriptions[index]))
316 if (index >= descriptions.length) {
317 throw new IllegalArgumentException("Illegal argument "+item);
320 Prefs.putChoise(preference, index);
324 public Object getElementAt(int index) {
325 return descriptions[index];
328 public int getSize() {
329 return descriptions.length;
334 private class PrefBooleanSelector extends AbstractListModel implements ComboBoxModel {
335 private final String preference;
336 private final String trueDesc, falseDesc;
337 private final boolean def;
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;
348 public Object getSelectedItem() {
349 if (Prefs.NODE.getBoolean(preference, def)) {
357 public void setSelectedItem(Object item) {
359 // Clear selection - huh?
362 if (!(item instanceof String)) {
363 throw new IllegalArgumentException("Illegal argument "+item);
366 if (trueDesc.equals(item)) {
367 Prefs.NODE.putBoolean(preference, true);
368 } else if (falseDesc.equals(item)) {
369 Prefs.NODE.putBoolean(preference, false);
371 throw new IllegalArgumentException("Illegal argument "+item);
376 public Object getElementAt(int index) {
379 return def ? trueDesc : falseDesc;
382 return def ? falseDesc: trueDesc;
385 throw new IndexOutOfBoundsException("Boolean asked for index="+index);
389 public int getSize() {
395 private void checkForUpdates() {
396 final UpdateInfoRetriever retriever = new UpdateInfoRetriever();
401 final JDialog dialog = new JDialog(this, ModalityType.APPLICATION_MODAL);
402 JPanel panel = new JPanel(new MigLayout());
404 panel.add(new JLabel("Checking for updates..."), "wrap");
406 JProgressBar bar = new JProgressBar();
407 bar.setIndeterminate(true);
408 panel.add(bar, "growx, wrap para");
410 JButton cancel = new JButton("Cancel");
411 cancel.addActionListener(new ActionListener() {
413 public void actionPerformed(ActionEvent e) {
417 panel.add(cancel, "right");
420 GUIUtil.setDisposableDialogOptions(dialog, cancel);
423 // Timer to monitor progress
424 final Timer timer = new Timer(100, null);
425 final long startTime = System.currentTimeMillis();
427 ActionListener listener = new ActionListener() {
429 public void actionPerformed(ActionEvent e) {
430 if (!retriever.isRunning() || startTime+10000 < System.currentTimeMillis()) {
436 timer.addActionListener(listener);
441 dialog.setVisible(true);
445 UpdateInfo info = retriever.getUpdateInfo();
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);
457 UpdateInfoDialog infoDialog = new UpdateInfoDialog(info);
458 infoDialog.setVisible(true);
459 if (infoDialog.isReminderSelected()) {
460 Prefs.putString(Prefs.LAST_UPDATE, "");
462 Prefs.putString(Prefs.LAST_UPDATE, info.getLatestVersion());
469 //////// Singleton implementation ////////
471 private static PreferencesDialog dialog = null;
473 public static void showPreferences() {
474 if (dialog != null) {
477 dialog = new PreferencesDialog();
478 dialog.setVisible(true);