component config refactoring, localization fixes
[debian/openrocket] / src / net / sf / openrocket / startup / Startup2.java
1 package net.sf.openrocket.startup;
2
3 import java.awt.GraphicsEnvironment;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import java.io.File;
7 import java.util.List;
8 import java.util.concurrent.atomic.AtomicInteger;
9
10 import javax.swing.SwingUtilities;
11 import javax.swing.Timer;
12 import javax.swing.ToolTipManager;
13
14 import net.sf.openrocket.communication.UpdateInfo;
15 import net.sf.openrocket.communication.UpdateInfoRetriever;
16 import net.sf.openrocket.database.Databases;
17 import net.sf.openrocket.database.ThrustCurveMotorSet;
18 import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
19 import net.sf.openrocket.file.iterator.DirectoryIterator;
20 import net.sf.openrocket.file.iterator.FileIterator;
21 import net.sf.openrocket.file.motor.MotorLoaderHelper;
22 import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
23 import net.sf.openrocket.gui.main.BasicFrame;
24 import net.sf.openrocket.gui.main.ExceptionHandler;
25 import net.sf.openrocket.gui.main.Splash;
26 import net.sf.openrocket.logging.LogHelper;
27 import net.sf.openrocket.motor.Motor;
28 import net.sf.openrocket.motor.ThrustCurveMotor;
29 import net.sf.openrocket.util.GUIUtil;
30 import net.sf.openrocket.util.Prefs;
31 import net.sf.openrocket.util.SimpleFileFilter;
32
33 /**
34  * The second class in the OpenRocket startup sequence.  This class can assume the
35  * Application class to be properly set up, and can use any classes safely.
36  * 
37  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
38  */
39 public class Startup2 {
40         private static final LogHelper log = Application.getLogger();
41         
42
43         private static final String THRUSTCURVE_DIRECTORY = "datafiles/thrustcurves/";
44         
45         /** Block motor loading for this many milliseconds */
46         private static AtomicInteger blockLoading = new AtomicInteger(Integer.MAX_VALUE);
47         
48         
49
50         /**
51          * Run when starting up OpenRocket after Application has been set up.
52          * 
53          * @param args  command line arguments
54          */
55         static void runMain(final String[] args) throws Exception {
56                 
57                 log.info("Starting up OpenRocket version " + Prefs.getVersion());
58                 
59                 // Check that we're not running headless
60                 log.info("Checking for graphics head");
61                 checkHead();
62                 
63                 // Check that we're running a good version of a JRE
64                 log.info("Checking JRE compatibility");
65                 VersionHelper.checkVersion();
66                 VersionHelper.checkOpenJDK();
67                 
68                 // Run the actual startup method in the EDT since it can use progress dialogs etc.
69                 log.info("Moving startup to EDT");
70                 SwingUtilities.invokeAndWait(new Runnable() {
71                         @Override
72                         public void run() {
73                                 runInEDT(args);
74                         }
75                 });
76                 
77                 log.info("Startup complete");
78         }
79         
80         
81         /**
82          * Run in the EDT when starting up OpenRocket.
83          * 
84          * @param args  command line arguments
85          */
86         private static void runInEDT(String[] args) {
87                 
88                 // Initialize the splash screen with version info
89                 log.info("Initializing the splash screen");
90                 Splash.init();
91                 
92                 // Setup the uncaught exception handler
93                 log.info("Registering exception handler");
94                 ExceptionHandler.registerExceptionHandler();
95                 
96                 // Start update info fetching
97                 final UpdateInfoRetriever updateInfo;
98                 if (Prefs.getCheckUpdates()) {
99                         log.info("Starting update check");
100                         updateInfo = new UpdateInfoRetriever();
101                         updateInfo.start();
102                 } else {
103                         log.info("Update check disabled");
104                         updateInfo = null;
105                 }
106                 
107                 // Set the best available look-and-feel
108                 log.info("Setting best LAF");
109                 GUIUtil.setBestLAF();
110                 
111                 // Set tooltip delay time.  Tooltips are used in MotorChooserDialog extensively.
112                 ToolTipManager.sharedInstance().setDismissDelay(30000);
113                 
114                 // Load defaults
115                 Prefs.loadDefaultUnits();
116                 
117                 // Load motors etc.
118                 log.info("Loading databases");
119                 loadMotor();
120                 Databases.fakeMethod();
121                 
122                 // Starting action (load files or open new document)
123                 log.info("Opening main application window");
124                 if (!handleCommandLine(args)) {
125                         BasicFrame.newAction();
126                 }
127                 
128                 // Check whether update info has been fetched or whether it needs more time
129                 log.info("Checking update status");
130                 checkUpdateStatus(updateInfo);
131                 
132                 // Block motor loading for 1.5 seconds to allow window painting to be faster
133                 blockLoading.set(1500);
134         }
135         
136         
137         /**
138          * Check that the JRE is not running headless.
139          */
140         private static void checkHead() {
141                 
142                 if (GraphicsEnvironment.isHeadless()) {
143                         log.error("Application is headless.");
144                         System.err.println();
145                         System.err.println("OpenRocket cannot currently be run without the graphical " +
146                                         "user interface.");
147                         System.err.println();
148                         System.exit(1);
149                 }
150                 
151         }
152         
153         
154         private static void loadMotor() {
155                 
156                 log.info("Starting motor loading from " + THRUSTCURVE_DIRECTORY + " in background thread.");
157                 ThrustCurveMotorSetDatabase db = new ThrustCurveMotorSetDatabase(true) {
158                         
159                         @Override
160                         protected void loadMotors() {
161                                 
162                                 // Block loading until timeout occurs or database is taken into use
163                                 log.info("Blocking motor loading while starting up");
164                                 while (!inUse && blockLoading.addAndGet(-100) > 0) {
165                                         try {
166                                                 Thread.sleep(100);
167                                         } catch (InterruptedException e) {
168                                         }
169                                 }
170                                 log.info("Blocking ended, inUse=" + inUse + " blockLoading=" + blockLoading.get());
171                                 
172                                 // Start loading
173                                 log.info("Loading motors from " + THRUSTCURVE_DIRECTORY);
174                                 long t0 = System.currentTimeMillis();
175                                 int fileCount;
176                                 int thrustCurveCount;
177                                 
178                                 // Load the packaged thrust curves
179                                 List<Motor> list;
180                                 FileIterator iterator = DirectoryIterator.findDirectory(THRUSTCURVE_DIRECTORY,
181                                                                 new SimpleFileFilter("", false, "eng", "rse"));
182                                 if (iterator == null) {
183                                         throw new IllegalStateException("Thrust curve directory " + THRUSTCURVE_DIRECTORY +
184                                                         "not found, distribution built wrong");
185                                 }
186                                 list = MotorLoaderHelper.load(iterator);
187                                 for (Motor m : list) {
188                                         this.addMotor((ThrustCurveMotor) m);
189                                 }
190                                 fileCount = iterator.getFileCount();
191                                 
192                                 thrustCurveCount = list.size();
193                                 
194                                 // Load the user-defined thrust curves
195                                 for (File file : Prefs.getUserThrustCurveFiles()) {
196                                         log.info("Loading motors from " + file);
197                                         list = MotorLoaderHelper.load(file);
198                                         for (Motor m : list) {
199                                                 this.addMotor((ThrustCurveMotor) m);
200                                         }
201                                         fileCount++;
202                                         thrustCurveCount += list.size();
203                                 }
204                                 
205                                 long t1 = System.currentTimeMillis();
206                                 
207                                 // Count statistics
208                                 int distinctMotorCount = 0;
209                                 int distinctThrustCurveCount = 0;
210                                 distinctMotorCount = motorSets.size();
211                                 for (ThrustCurveMotorSet set : motorSets) {
212                                         distinctThrustCurveCount += set.getMotorCount();
213                                 }
214                                 log.info("Motor loading done, took " + (t1 - t0) + " ms to load "
215                                                 + fileCount + " files/directories containing "
216                                                 + thrustCurveCount + " thrust curves which contained "
217                                                 + distinctMotorCount + " distinct motors with "
218                                                 + distinctThrustCurveCount + " distinct thrust curves.");
219                         }
220                         
221                 };
222                 db.startLoading();
223                 Application.setMotorSetDatabase(db);
224         }
225         
226         private static void checkUpdateStatus(final UpdateInfoRetriever updateInfo) {
227                 if (updateInfo == null)
228                         return;
229                 
230                 int delay = 1000;
231                 if (!updateInfo.isRunning())
232                         delay = 100;
233                 
234                 final Timer timer = new Timer(delay, null);
235                 
236                 ActionListener listener = new ActionListener() {
237                         private int count = 5;
238                         
239                         @Override
240                         public void actionPerformed(ActionEvent e) {
241                                 if (!updateInfo.isRunning()) {
242                                         timer.stop();
243                                         
244                                         String current = Prefs.getVersion();
245                                         String last = Prefs.getString(Prefs.LAST_UPDATE, "");
246                                         
247                                         UpdateInfo info = updateInfo.getUpdateInfo();
248                                         if (info != null && info.getLatestVersion() != null &&
249                                                         !current.equals(info.getLatestVersion()) &&
250                                                         !last.equals(info.getLatestVersion())) {
251                                                 
252                                                 UpdateInfoDialog infoDialog = new UpdateInfoDialog(info);
253                                                 infoDialog.setVisible(true);
254                                                 if (infoDialog.isReminderSelected()) {
255                                                         Prefs.putString(Prefs.LAST_UPDATE, "");
256                                                 } else {
257                                                         Prefs.putString(Prefs.LAST_UPDATE, info.getLatestVersion());
258                                                 }
259                                         }
260                                 }
261                                 count--;
262                                 if (count <= 0)
263                                         timer.stop();
264                         }
265                 };
266                 timer.addActionListener(listener);
267                 timer.start();
268         }
269         
270         /**
271          * Handles arguments passed from the command line.  This may be used either
272          * when starting the first instance of OpenRocket or later when OpenRocket is
273          * executed again while running.
274          * 
275          * @param args  the command-line arguments.
276          * @return              whether a new frame was opened or similar user desired action was
277          *                              performed as a result.
278          */
279         private static boolean handleCommandLine(String[] args) {
280                 
281                 // Check command-line for files
282                 boolean opened = false;
283                 for (String file : args) {
284                         if (BasicFrame.open(new File(file), null)) {
285                                 opened = true;
286                         }
287                 }
288                 return opened;
289         }
290         
291 }