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");
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) {
262 if (!(item instanceof Unit)) {
263 throw new IllegalArgumentException("Illegal argument "+item);
265 group.setDefaultUnit(group.getUnitIndex((Unit)item));
268 public Object getElementAt(int index) {
269 return group.getUnit(index);
272 public int getSize() {
273 return group.getUnitCount();
277 public void fireChange() {
278 this.fireContentsChanged(this, 0, this.getSize());
284 private class PrefChoiseSelector extends AbstractListModel implements ComboBoxModel {
285 private final String preference;
286 private final String[] descriptions;
288 public PrefChoiseSelector(String preference, String ... descriptions) {
289 this.preference = preference;
290 this.descriptions = descriptions;
294 public Object getSelectedItem() {
295 return descriptions[Prefs.getChoise(preference, descriptions.length, 0)];
299 public void setSelectedItem(Object item) {
300 if (!(item instanceof String)) {
301 throw new IllegalArgumentException("Illegal argument "+item);
304 for (index = 0; index < descriptions.length; index++) {
305 if (((String)item).equalsIgnoreCase(descriptions[index]))
308 if (index >= descriptions.length) {
309 throw new IllegalArgumentException("Illegal argument "+item);
312 Prefs.putChoise(preference, index);
316 public Object getElementAt(int index) {
317 return descriptions[index];
320 public int getSize() {
321 return descriptions.length;
326 private class PrefBooleanSelector extends AbstractListModel implements ComboBoxModel {
327 private final String preference;
328 private final String trueDesc, falseDesc;
329 private final boolean def;
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;
340 public Object getSelectedItem() {
341 if (Prefs.NODE.getBoolean(preference, def)) {
349 public void setSelectedItem(Object item) {
350 if (!(item instanceof String)) {
351 throw new IllegalArgumentException("Illegal argument "+item);
354 if (trueDesc.equals(item)) {
355 Prefs.NODE.putBoolean(preference, true);
356 } else if (falseDesc.equals(item)) {
357 Prefs.NODE.putBoolean(preference, false);
359 throw new IllegalArgumentException("Illegal argument "+item);
364 public Object getElementAt(int index) {
367 return def ? trueDesc : falseDesc;
370 return def ? falseDesc: trueDesc;
373 throw new IndexOutOfBoundsException("Boolean asked for index="+index);
377 public int getSize() {
383 private void checkForUpdates() {
384 final UpdateInfoRetriever retriever = new UpdateInfoRetriever();
389 final JDialog dialog = new JDialog(this, ModalityType.APPLICATION_MODAL);
390 JPanel panel = new JPanel(new MigLayout());
392 panel.add(new JLabel("Checking for updates..."), "wrap");
394 JProgressBar bar = new JProgressBar();
395 bar.setIndeterminate(true);
396 panel.add(bar, "growx, wrap para");
398 JButton cancel = new JButton("Cancel");
399 cancel.addActionListener(new ActionListener() {
401 public void actionPerformed(ActionEvent e) {
405 panel.add(cancel, "right");
408 GUIUtil.setDisposableDialogOptions(dialog, cancel);
411 // Timer to monitor progress
412 final Timer timer = new Timer(100, null);
413 final long startTime = System.currentTimeMillis();
415 ActionListener listener = new ActionListener() {
417 public void actionPerformed(ActionEvent e) {
418 if (!retriever.isRunning() || startTime+10000 < System.currentTimeMillis()) {
424 timer.addActionListener(listener);
429 dialog.setVisible(true);
433 UpdateInfo info = retriever.getUpdateInfo();
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);
445 new UpdateInfoDialog(info).setVisible(true);
451 //////// Singleton implementation ////////
453 private static PreferencesDialog dialog = null;
455 public static void showPreferences() {
456 if (dialog != null) {
459 dialog = new PreferencesDialog();
460 dialog.setVisible(true);