language selector, bug fixed
[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.io.File;
10 import java.util.ArrayList;
11 import java.util.Collections;
12 import java.util.List;
13 import java.util.Locale;
14
15 import javax.swing.AbstractListModel;
16 import javax.swing.ComboBoxModel;
17 import javax.swing.JButton;
18 import javax.swing.JCheckBox;
19 import javax.swing.JComboBox;
20 import javax.swing.JDialog;
21 import javax.swing.JFileChooser;
22 import javax.swing.JLabel;
23 import javax.swing.JOptionPane;
24 import javax.swing.JPanel;
25 import javax.swing.JProgressBar;
26 import javax.swing.JTabbedPane;
27 import javax.swing.JTextField;
28 import javax.swing.Timer;
29 import javax.swing.event.DocumentEvent;
30 import javax.swing.event.DocumentListener;
31
32 import net.miginfocom.swing.MigLayout;
33 import net.sf.openrocket.communication.UpdateInfo;
34 import net.sf.openrocket.communication.UpdateInfoRetriever;
35 import net.sf.openrocket.gui.components.DescriptionArea;
36 import net.sf.openrocket.gui.components.StyledLabel;
37 import net.sf.openrocket.gui.components.StyledLabel.Style;
38 import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
39 import net.sf.openrocket.l10n.Translator;
40 import net.sf.openrocket.logging.LogHelper;
41 import net.sf.openrocket.startup.Application;
42 import net.sf.openrocket.unit.Unit;
43 import net.sf.openrocket.unit.UnitGroup;
44 import net.sf.openrocket.util.GUIUtil;
45 import net.sf.openrocket.util.Named;
46 import net.sf.openrocket.util.Prefs;
47 import net.sf.openrocket.util.SimpleFileFilter;
48 import net.sf.openrocket.util.Utils;
49
50
51 public class PreferencesDialog extends JDialog {
52         private static final LogHelper log = Application.getLogger();
53         
54         private final List<DefaultUnitSelector> unitSelectors = new ArrayList<DefaultUnitSelector>();
55         
56         private File defaultDirectory = null;
57         private static final Translator trans = Application.getTranslator();
58         
59         private PreferencesDialog(Window parent) {
60                 //// Preferences
61                 super(parent, trans.get("pref.dlg.title.Preferences"), Dialog.ModalityType.APPLICATION_MODAL);
62                 
63                 JPanel panel = new JPanel(new MigLayout("fill, gap unrel", "[grow]", "[grow][]"));
64                 
65                 JTabbedPane tabbedPane = new JTabbedPane();
66                 panel.add(tabbedPane, "grow, wrap");
67                 
68                 //// Units and Default units
69                 tabbedPane.addTab(trans.get("pref.dlg.tab.Units"), null, unitsPane(),
70                                 trans.get("pref.dlg.tab.Defaultunits"));
71                 //// Materials and Custom materials
72                 tabbedPane.addTab(trans.get("pref.dlg.tab.Materials"), null, new MaterialEditPanel(),
73                                 trans.get("pref.dlg.tab.Custommaterials"));
74                 //// Options and Miscellaneous options
75                 tabbedPane.addTab(trans.get("pref.dlg.tab.Options"), null, optionsPane(),
76                                 trans.get("pref.dlg.tab.Miscellaneousoptions"));
77                 
78                 //// Close button
79                 JButton close = new JButton(trans.get("dlg.but.close"));
80                 close.addActionListener(new ActionListener() {
81                         @Override
82                         public void actionPerformed(ActionEvent arg0) {
83                                 PreferencesDialog.this.setVisible(false);
84                                 PreferencesDialog.this.dispose();
85                         }
86                 });
87                 panel.add(close, "span, right, tag close");
88                 
89                 this.setContentPane(panel);
90                 pack();
91                 this.setLocationRelativeTo(null);
92                 
93                 this.addWindowListener(new WindowAdapter() {
94                         @Override
95                         public void windowClosed(WindowEvent e) {
96                                 Prefs.storeDefaultUnits();
97                         }
98                 });
99                 
100                 GUIUtil.setDisposableDialogOptions(this, close);
101         }
102         
103         
104         private JPanel optionsPane() {
105                 JPanel panel = new JPanel(new MigLayout("fillx, ins 30lp n n n"));
106                 
107
108                 //// Language selector
109                 Locale userLocale = Prefs.getUserLocale();
110                 List<Named<Locale>> locales = new ArrayList<Named<Locale>>();
111                 for (Locale l : Prefs.getSupportedLocales()) {
112                         locales.add(new Named<Locale>(l, l.getDisplayLanguage()));
113                 }
114                 Collections.sort(locales);
115                 locales.add(0, new Named<Locale>(null, trans.get("languages.default")));
116                 
117                 final JComboBox languageCombo = new JComboBox(locales.toArray());
118                 for (int i = 0; i < locales.size(); i++) {
119                         if (Utils.equals(userLocale, locales.get(i).get())) {
120                                 languageCombo.setSelectedIndex(i);
121                         }
122                 }
123                 languageCombo.addActionListener(new ActionListener() {
124                         @Override
125                         @SuppressWarnings("unchecked")
126                         public void actionPerformed(ActionEvent e) {
127                                 Named<Locale> selection = (Named<Locale>) languageCombo.getSelectedItem();
128                                 Prefs.setUserLocale(selection.get());
129                         }
130                 });
131                 panel.add(new JLabel(trans.get("lbl.language")), "gapright para");
132                 panel.add(languageCombo, "wrap rel, growx, sg combos");
133                 
134                 panel.add(new StyledLabel(trans.get("PreferencesDialog.lbl.languageEffect"), -3, Style.ITALIC), "span, wrap para*2");
135                 
136
137                 //// Position to insert new body components:
138                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Positiontoinsert")), "gapright para");
139                 panel.add(new JComboBox(new PrefChoiseSelector(Prefs.BODY_COMPONENT_INSERT_POSITION_KEY,
140                                 //// Always ask
141                                 //// Insert in middle
142                                 //// Add to end
143                                 trans.get("pref.dlg.PrefChoiseSelector1"),
144                                 trans.get("pref.dlg.PrefChoiseSelector2"),
145                                 trans.get("pref.dlg.PrefChoiseSelector3"))), "wrap para, growx, sg combos");
146                 
147                 //// Confirm deletion of simulations:
148                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Confirmdeletion")));
149                 panel.add(new JComboBox(new PrefBooleanSelector(Prefs.CONFIRM_DELETE_SIMULATION,
150                                 //// Delete
151                                 //// Confirm
152                                 trans.get("pref.dlg.PrefBooleanSelector1"),
153                                 trans.get("pref.dlg.PrefBooleanSelector2"), true)), "wrap 40lp, growx, sg combos");
154                 
155                 //// User-defined thrust curves:
156                 panel.add(new JLabel(trans.get("pref.dlg.lbl.User-definedthrust")), "spanx, wrap");
157                 final JTextField field = new JTextField();
158                 List<File> files = Prefs.getUserThrustCurveFiles();
159                 String str = "";
160                 for (File file : files) {
161                         if (str.length() > 0) {
162                                 str += ";";
163                         }
164                         str += file.getAbsolutePath();
165                 }
166                 field.setText(str);
167                 field.getDocument().addDocumentListener(new DocumentListener() {
168                         @Override
169                         public void removeUpdate(DocumentEvent e) {
170                                 changed();
171                         }
172                         
173                         @Override
174                         public void insertUpdate(DocumentEvent e) {
175                                 changed();
176                         }
177                         
178                         @Override
179                         public void changedUpdate(DocumentEvent e) {
180                                 changed();
181                         }
182                         
183                         private void changed() {
184                                 String text = field.getText();
185                                 List<File> list = new ArrayList<File>();
186                                 for (String s : text.split(";")) {
187                                         s = s.trim();
188                                         if (s.length() > 0) {
189                                                 list.add(new File(s));
190                                         }
191                                 }
192                                 Prefs.setUserThrustCurveFiles(list);
193                         }
194                 });
195                 panel.add(field, "w 100px, gapright unrel, spanx, growx, split");
196                 
197                 //// Add button
198                 JButton button = new JButton(trans.get("pref.dlg.but.add"));
199                 button.addActionListener(new ActionListener() {
200                         @Override
201                         public void actionPerformed(ActionEvent e) {
202                                 JFileChooser chooser = new JFileChooser();
203                                 SimpleFileFilter filter =
204                                                 new SimpleFileFilter(
205                                                                 //// All thrust curve files (*.eng; *.rse; *.zip; directories)
206                                                                 trans.get("pref.dlg.Allthrustcurvefiles"),
207                                                                 true, "eng", "rse", "zip");
208                                 chooser.addChoosableFileFilter(filter);
209                                 //// RASP motor files (*.eng)
210                                 chooser.addChoosableFileFilter(new SimpleFileFilter(trans.get("pref.dlg.RASPfiles"),
211                                                 true, "eng"));
212                                 //// RockSim engine files (*.rse)
213                                 chooser.addChoosableFileFilter(new SimpleFileFilter(trans.get("pref.dlg.RockSimfiles"),
214                                                 true, "rse"));
215                                 //// ZIP archives (*.zip)
216                                 chooser.addChoosableFileFilter(new SimpleFileFilter(trans.get("pref.dlg.ZIParchives"),
217                                                 true, "zip"));
218                                 chooser.setFileFilter(filter);
219                                 chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
220                                 if (defaultDirectory != null) {
221                                         chooser.setCurrentDirectory(defaultDirectory);
222                                 }
223                                 
224                                 //// Add
225                                 int returnVal = chooser.showDialog(PreferencesDialog.this, trans.get("pref.dlg.Add"));
226                                 if (returnVal == JFileChooser.APPROVE_OPTION) {
227                                         log.user("Adding user thrust curve: " + chooser.getSelectedFile());
228                                         defaultDirectory = chooser.getCurrentDirectory();
229                                         String text = field.getText().trim();
230                                         if (text.length() > 0) {
231                                                 text += ";";
232                                         }
233                                         text += chooser.getSelectedFile().getAbsolutePath();
234                                         field.setText(text);
235                                 }
236                         }
237                 });
238                 panel.add(button, "gapright unrel");
239                 
240                 //// Reset button
241                 button = new JButton(trans.get("pref.dlg.but.reset"));
242                 
243                 button.addActionListener(new ActionListener() {
244                         @Override
245                         public void actionPerformed(ActionEvent e) {
246                                 // First one sets to the default, but does not un-set the pref
247                                 field.setText(Prefs.getDefaultUserThrustCurveFile().getAbsolutePath());
248                                 Prefs.setUserThrustCurveFiles(null);
249                         }
250                 });
251                 panel.add(button, "wrap");
252                 
253                 //// Add directories, RASP motor files (*.eng), RockSim engine files (*.rse) or ZIP archives separated by a semicolon (;) to load external thrust curves.  Changes will take effect the next time you start OpenRocket.
254                 DescriptionArea desc = new DescriptionArea(trans.get("pref.dlg.DescriptionArea.Adddirectories"), 3, -3, false);
255                 desc.setBackground(getBackground());
256                 panel.add(desc, "spanx, growx, wrap 40lp");
257                 
258
259
260                 //// Check for software updates at startup
261                 final JCheckBox softwareUpdateBox =
262                                 new JCheckBox(trans.get("pref.dlg.checkbox.Checkupdates"));
263                 softwareUpdateBox.setSelected(Prefs.getCheckUpdates());
264                 softwareUpdateBox.addActionListener(new ActionListener() {
265                         @Override
266                         public void actionPerformed(ActionEvent e) {
267                                 Prefs.setCheckUpdates(softwareUpdateBox.isSelected());
268                         }
269                 });
270                 panel.add(softwareUpdateBox);
271                 
272                 //// Check now button
273                 button = new JButton(trans.get("pref.dlg.but.checknow"));
274                 //// Check for software updates now
275                 button.setToolTipText(trans.get("pref.dlg.ttip.Checkupdatesnow"));
276                 button.addActionListener(new ActionListener() {
277                         @Override
278                         public void actionPerformed(ActionEvent e) {
279                                 checkForUpdates();
280                         }
281                 });
282                 panel.add(button, "right, wrap");
283                 
284
285                 return panel;
286         }
287         
288         private JPanel unitsPane() {
289                 JPanel panel = new JPanel(new MigLayout("", "[][]40lp[][]"));
290                 JComboBox combo;
291                 
292                 //// Select your preferred units:
293                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Selectprefunits")), "span, wrap paragraph");
294                 
295
296                 //// Rocket dimensions:
297                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Rocketdimensions")));
298                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_LENGTH));
299                 panel.add(combo, "sizegroup boxes");
300                 
301                 //// Line density:
302                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Linedensity")));
303                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_LINE));
304                 panel.add(combo, "sizegroup boxes, wrap");
305                 
306
307                 //// Motor dimensions:
308                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Motordimensions")));
309                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_MOTOR_DIMENSIONS));
310                 panel.add(combo, "sizegroup boxes");
311                 
312                 //// Surface density:
313                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Surfacedensity")));
314                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_SURFACE));
315                 panel.add(combo, "sizegroup boxes, wrap");
316                 
317
318                 //// Distance:
319                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Distance")));
320                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DISTANCE));
321                 panel.add(combo, "sizegroup boxes");
322                 
323                 //// Bulk density::
324                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Bulkdensity")));
325                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_BULK));
326                 panel.add(combo, "sizegroup boxes, wrap");
327                 
328
329                 //// Velocity:
330                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Velocity")));
331                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_VELOCITY));
332                 panel.add(combo, "sizegroup boxes");
333                 
334                 //// Surface roughness:
335                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Surfaceroughness")));
336                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ROUGHNESS));
337                 panel.add(combo, "sizegroup boxes, wrap");
338                 
339
340                 //// Acceleration:
341                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Acceleration")));
342                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ACCELERATION));
343                 panel.add(combo, "sizegroup boxes");
344                 
345                 //// Area:
346                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Area")));
347                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_AREA));
348                 panel.add(combo, "sizegroup boxes, wrap");
349                 
350
351                 //// Mass:
352                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Mass")));
353                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_MASS));
354                 panel.add(combo, "sizegroup boxes");
355                 
356                 //// Angle:
357                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Angle")));
358                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ANGLE));
359                 panel.add(combo, "sizegroup boxes, wrap");
360                 
361
362                 //// Force:
363                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Force")));
364                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_FORCE));
365                 panel.add(combo, "sizegroup boxes");
366                 
367                 //// Roll rate:
368                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Rollrate")));
369                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ROLL));
370                 panel.add(combo, "sizegroup boxes, wrap");
371                 
372
373                 //// Total impulse:
374                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Totalimpulse")));
375                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_IMPULSE));
376                 panel.add(combo, "sizegroup boxes");
377                 
378                 //// Temperature:
379                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Temperature")));
380                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_TEMPERATURE));
381                 panel.add(combo, "sizegroup boxes, wrap");
382                 
383
384                 //// Moment of inertia:
385                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Momentofinertia")));
386                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_INERTIA));
387                 panel.add(combo, "sizegroup boxes");
388                 
389                 //// Pressure:
390                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Pressure")));
391                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_PRESSURE));
392                 panel.add(combo, "sizegroup boxes, wrap");
393                 
394
395                 //// Stability:
396                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Stability")));
397                 combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_STABILITY));
398                 panel.add(combo, "sizegroup boxes, wrap para");
399                 
400
401
402                 //// Default metric button
403                 JButton button = new JButton(trans.get("pref.dlg.but.defaultmetric"));
404                 button.addActionListener(new ActionListener() {
405                         @Override
406                         public void actionPerformed(ActionEvent e) {
407                                 UnitGroup.setDefaultMetricUnits();
408                                 for (DefaultUnitSelector s : unitSelectors)
409                                         s.fireChange();
410                         }
411                 });
412                 panel.add(button, "spanx, split 2, grow");
413                 
414                 //// Default imperial button
415                 button = new JButton(trans.get("pref.dlg.but.defaultimperial"));
416                 button.addActionListener(new ActionListener() {
417                         @Override
418                         public void actionPerformed(ActionEvent e) {
419                                 UnitGroup.setDefaultImperialUnits();
420                                 for (DefaultUnitSelector s : unitSelectors)
421                                         s.fireChange();
422                         }
423                 });
424                 panel.add(button, "grow, wrap para");
425                 
426                 //// The effects will take place the next time you open a window.
427                 panel.add(new StyledLabel(
428                                 trans.get("pref.dlg.lbl.effect1"), -2, Style.ITALIC),
429                                 "spanx, wrap");
430                 
431
432                 return panel;
433         }
434         
435         
436
437
438
439         private class DefaultUnitSelector extends AbstractListModel implements ComboBoxModel {
440                 
441                 private final UnitGroup group;
442                 
443                 public DefaultUnitSelector(UnitGroup group) {
444                         this.group = group;
445                         unitSelectors.add(this);
446                 }
447                 
448                 @Override
449                 public Object getSelectedItem() {
450                         return group.getDefaultUnit();
451                 }
452                 
453                 @Override
454                 public void setSelectedItem(Object item) {
455                         if (item == null) {
456                                 // Clear selection - huh?
457                                 return;
458                         }
459                         if (!(item instanceof Unit)) {
460                                 throw new IllegalArgumentException("Illegal argument " + item);
461                         }
462                         group.setDefaultUnit(group.getUnitIndex((Unit) item));
463                 }
464                 
465                 @Override
466                 public Object getElementAt(int index) {
467                         return group.getUnit(index);
468                 }
469                 
470                 @Override
471                 public int getSize() {
472                         return group.getUnitCount();
473                 }
474                 
475                 
476                 public void fireChange() {
477                         this.fireContentsChanged(this, 0, this.getSize());
478                 }
479         }
480         
481         
482
483         private class PrefChoiseSelector extends AbstractListModel implements ComboBoxModel {
484                 private final String preference;
485                 private final String[] descriptions;
486                 
487                 public PrefChoiseSelector(String preference, String... descriptions) {
488                         this.preference = preference;
489                         this.descriptions = descriptions;
490                 }
491                 
492                 @Override
493                 public Object getSelectedItem() {
494                         return descriptions[Prefs.getChoise(preference, descriptions.length, 0)];
495                 }
496                 
497                 @Override
498                 public void setSelectedItem(Object item) {
499                         if (item == null) {
500                                 // Clear selection - huh?
501                                 return;
502                         }
503                         if (!(item instanceof String)) {
504                                 throw new IllegalArgumentException("Illegal argument " + item);
505                         }
506                         int index;
507                         for (index = 0; index < descriptions.length; index++) {
508                                 if (((String) item).equalsIgnoreCase(descriptions[index]))
509                                         break;
510                         }
511                         if (index >= descriptions.length) {
512                                 throw new IllegalArgumentException("Illegal argument " + item);
513                         }
514                         
515                         Prefs.putChoise(preference, index);
516                 }
517                 
518                 @Override
519                 public Object getElementAt(int index) {
520                         return descriptions[index];
521                 }
522                 
523                 @Override
524                 public int getSize() {
525                         return descriptions.length;
526                 }
527         }
528         
529         
530         private class PrefBooleanSelector extends AbstractListModel implements ComboBoxModel {
531                 private final String preference;
532                 private final String trueDesc, falseDesc;
533                 private final boolean def;
534                 
535                 public PrefBooleanSelector(String preference, String falseDescription,
536                                 String trueDescription, boolean defaultState) {
537                         this.preference = preference;
538                         this.trueDesc = trueDescription;
539                         this.falseDesc = falseDescription;
540                         this.def = defaultState;
541                 }
542                 
543                 @Override
544                 public Object getSelectedItem() {
545                         if (Prefs.NODE.getBoolean(preference, def)) {
546                                 return trueDesc;
547                         } else {
548                                 return falseDesc;
549                         }
550                 }
551                 
552                 @Override
553                 public void setSelectedItem(Object item) {
554                         if (item == null) {
555                                 // Clear selection - huh?
556                                 return;
557                         }
558                         if (!(item instanceof String)) {
559                                 throw new IllegalArgumentException("Illegal argument " + item);
560                         }
561                         
562                         if (trueDesc.equals(item)) {
563                                 Prefs.NODE.putBoolean(preference, true);
564                         } else if (falseDesc.equals(item)) {
565                                 Prefs.NODE.putBoolean(preference, false);
566                         } else {
567                                 throw new IllegalArgumentException("Illegal argument " + item);
568                         }
569                 }
570                 
571                 @Override
572                 public Object getElementAt(int index) {
573                         switch (index) {
574                         case 0:
575                                 return def ? trueDesc : falseDesc;
576                                 
577                         case 1:
578                                 return def ? falseDesc : trueDesc;
579                                 
580                         default:
581                                 throw new IndexOutOfBoundsException("Boolean asked for index=" + index);
582                         }
583                 }
584                 
585                 @Override
586                 public int getSize() {
587                         return 2;
588                 }
589         }
590         
591         
592         private void checkForUpdates() {
593                 final UpdateInfoRetriever retriever = new UpdateInfoRetriever();
594                 retriever.start();
595                 
596
597                 // Progress dialog
598                 final JDialog dialog = new JDialog(this, ModalityType.APPLICATION_MODAL);
599                 JPanel panel = new JPanel(new MigLayout());
600                 
601                 //// Checking for updates...
602                 panel.add(new JLabel(trans.get("pref.dlg.lbl.Checkingupdates")), "wrap");
603                 
604                 JProgressBar bar = new JProgressBar();
605                 bar.setIndeterminate(true);
606                 panel.add(bar, "growx, wrap para");
607                 
608                 //// Cancel button
609                 JButton cancel = new JButton(trans.get("dlg.but.cancel"));
610                 cancel.addActionListener(new ActionListener() {
611                         @Override
612                         public void actionPerformed(ActionEvent e) {
613                                 dialog.dispose();
614                         }
615                 });
616                 panel.add(cancel, "right");
617                 dialog.add(panel);
618                 
619                 GUIUtil.setDisposableDialogOptions(dialog, cancel);
620                 
621
622                 // Timer to monitor progress
623                 final Timer timer = new Timer(100, null);
624                 final long startTime = System.currentTimeMillis();
625                 
626                 ActionListener listener = new ActionListener() {
627                         @Override
628                         public void actionPerformed(ActionEvent e) {
629                                 if (!retriever.isRunning() || startTime + 10000 < System.currentTimeMillis()) {
630                                         timer.stop();
631                                         dialog.dispose();
632                                 }
633                         }
634                 };
635                 timer.addActionListener(listener);
636                 timer.start();
637                 
638
639                 // Wait for action
640                 dialog.setVisible(true);
641                 
642
643                 // Check result
644                 UpdateInfo info = retriever.getUpdateInfo();
645                 if (info == null) {
646                         JOptionPane.showMessageDialog(this,
647                                         //// An error occurred while communicating with the server.
648                                         trans.get("pref.dlg.lbl.msg1"),
649                                         //// Unable to retrieve update information
650                                         trans.get("pref.dlg.lbl.msg2"), JOptionPane.WARNING_MESSAGE, null);
651                 } else if (info.getLatestVersion() == null ||
652                                 info.getLatestVersion().equals("") ||
653                                 Prefs.getVersion().equalsIgnoreCase(info.getLatestVersion())) {
654                         JOptionPane.showMessageDialog(this,
655                                         //// You are running the latest version of OpenRocket.
656                                         trans.get("pref.dlg.lbl.msg3"),
657                                         //// No updates available
658                                         trans.get("pref.dlg.lbl.msg4"), JOptionPane.INFORMATION_MESSAGE, null);
659                 } else {
660                         UpdateInfoDialog infoDialog = new UpdateInfoDialog(info);
661                         infoDialog.setVisible(true);
662                         if (infoDialog.isReminderSelected()) {
663                                 Prefs.putString(Prefs.LAST_UPDATE, "");
664                         } else {
665                                 Prefs.putString(Prefs.LAST_UPDATE, info.getLatestVersion());
666                         }
667                 }
668                 
669         }
670         
671         
672         ////////  Singleton implementation  ////////
673         
674         private static PreferencesDialog dialog = null;
675         
676         public static void showPreferences(Window parent) {
677                 if (dialog != null) {
678                         dialog.dispose();
679                 }
680                 dialog = new PreferencesDialog(parent);
681                 dialog.setVisible(true);
682         }
683         
684
685 }