1 package net.sf.openrocket.startup;
3 import java.awt.GraphicsEnvironment;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
8 import java.util.concurrent.Callable;
9 import java.util.concurrent.CountDownLatch;
10 import java.util.concurrent.ExecutorService;
11 import java.util.concurrent.Executors;
12 import java.util.concurrent.ThreadFactory;
13 import java.util.concurrent.atomic.AtomicInteger;
15 import javax.swing.SwingUtilities;
16 import javax.swing.Timer;
17 import javax.swing.ToolTipManager;
19 import net.sf.openrocket.communication.UpdateInfo;
20 import net.sf.openrocket.communication.UpdateInfoRetriever;
21 import net.sf.openrocket.database.ComponentPresetDatabase;
22 import net.sf.openrocket.database.Databases;
23 import net.sf.openrocket.database.ThrustCurveMotorSet;
24 import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
25 import net.sf.openrocket.file.iterator.DirectoryIterator;
26 import net.sf.openrocket.file.iterator.FileIterator;
27 import net.sf.openrocket.file.motor.MotorLoaderHelper;
28 import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
29 import net.sf.openrocket.gui.main.BasicFrame;
30 import net.sf.openrocket.gui.main.Splash;
31 import net.sf.openrocket.gui.main.SwingExceptionHandler;
32 import net.sf.openrocket.gui.util.GUIUtil;
33 import net.sf.openrocket.gui.util.SimpleFileFilter;
34 import net.sf.openrocket.gui.util.SwingPreferences;
35 import net.sf.openrocket.logging.LogHelper;
36 import net.sf.openrocket.motor.Motor;
37 import net.sf.openrocket.motor.ThrustCurveMotor;
38 import net.sf.openrocket.util.BuildProperties;
41 * The second class in the OpenRocket startup sequence. This class can assume the
42 * Application class to be properly set up, and can use any classes safely.
44 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
46 public class Startup2 {
47 private static final LogHelper log = Application.getLogger();
50 private static final String THRUSTCURVE_DIRECTORY = "datafiles/thrustcurves/";
53 * Run when starting up OpenRocket after Application has been set up.
55 * @param args command line arguments
57 static void runMain(final String[] args) throws Exception {
59 log.info("Starting up OpenRocket version " + BuildProperties.getVersion());
61 // Check that we're not running headless
62 log.info("Checking for graphics head");
65 // Check that we're running a good version of a JRE
66 log.info("Checking JRE compatibility");
67 VersionHelper.checkVersion();
68 VersionHelper.checkOpenJDK();
70 // Run the actual startup method in the EDT since it can use progress dialogs etc.
71 log.info("Moving startup to EDT");
72 SwingUtilities.invokeAndWait(new Runnable() {
79 log.info("Startup complete");
84 * Run in the EDT when starting up OpenRocket.
86 * @param args command line arguments
88 private static void runInEDT(String[] args) {
90 // Initialize the splash screen with version info
91 log.info("Initializing the splash screen");
94 // Latch which counts the number of background loading processes we need to complete.
95 CountDownLatch loading = new CountDownLatch(1);
96 ExecutorService exec = Executors.newFixedThreadPool(1, new ThreadFactory() {
99 public Thread newThread(Runnable r) {
100 Thread t = new Thread(r);
101 t.setPriority(Thread.MIN_PRIORITY);
107 // Must be done after localization is initialized
108 ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase();
109 exec.submit( new ComponentPresetLoader( loading, componentPresetDao));
111 Application.setComponentPresetDao( componentPresetDao );
113 // Setup the uncaught exception handler
114 log.info("Registering exception handler");
115 SwingExceptionHandler exceptionHandler = new SwingExceptionHandler();
116 Application.setExceptionHandler(exceptionHandler);
117 exceptionHandler.registerExceptionHandler();
119 // Start update info fetching
120 final UpdateInfoRetriever updateInfo;
121 if ( Application.getPreferences().getCheckUpdates()) {
122 log.info("Starting update check");
123 updateInfo = new UpdateInfoRetriever();
126 log.info("Update check disabled");
130 // Set the best available look-and-feel
131 log.info("Setting best LAF");
132 GUIUtil.setBestLAF();
134 // Set tooltip delay time. Tooltips are used in MotorChooserDialog extensively.
135 ToolTipManager.sharedInstance().setDismissDelay(30000);
138 ((SwingPreferences) Application.getPreferences()).loadDefaultUnits();
141 log.info("Loading databases");
143 ConcurrentLoadingThrustCurveMotorSetDatabase motorLoader = new ConcurrentLoadingThrustCurveMotorSetDatabase(THRUSTCURVE_DIRECTORY);
144 motorLoader.startLoading();
145 Application.setMotorSetDatabase(motorLoader);
147 Databases.fakeMethod();
151 } catch ( InterruptedException iex) {
155 // Starting action (load files or open new document)
156 log.info("Opening main application window");
157 if (!handleCommandLine(args)) {
158 BasicFrame.newAction();
161 // Check whether update info has been fetched or whether it needs more time
162 log.info("Checking update status");
163 checkUpdateStatus(updateInfo);
169 * Check that the JRE is not running headless.
171 private static void checkHead() {
173 if (GraphicsEnvironment.isHeadless()) {
174 log.error("Application is headless.");
175 System.err.println();
176 System.err.println("OpenRocket cannot currently be run without the graphical " +
178 System.err.println();
185 private static void checkUpdateStatus(final UpdateInfoRetriever updateInfo) {
186 if (updateInfo == null)
190 if (!updateInfo.isRunning())
193 final Timer timer = new Timer(delay, null);
195 ActionListener listener = new ActionListener() {
196 private int count = 5;
199 public void actionPerformed(ActionEvent e) {
200 if (!updateInfo.isRunning()) {
203 String current = BuildProperties.getVersion();
204 String last = Application.getPreferences().getString(Preferences.LAST_UPDATE, "");
206 UpdateInfo info = updateInfo.getUpdateInfo();
207 if (info != null && info.getLatestVersion() != null &&
208 !current.equals(info.getLatestVersion()) &&
209 !last.equals(info.getLatestVersion())) {
211 UpdateInfoDialog infoDialog = new UpdateInfoDialog(info);
212 infoDialog.setVisible(true);
213 if (infoDialog.isReminderSelected()) {
214 Application.getPreferences().putString(Preferences.LAST_UPDATE, "");
216 Application.getPreferences().putString(Preferences.LAST_UPDATE, info.getLatestVersion());
225 timer.addActionListener(listener);
229 private static class ComponentPresetLoader implements Callable {
231 CountDownLatch latch;
232 ComponentPresetDatabase componentPresetDao;
234 private ComponentPresetLoader( CountDownLatch latch, ComponentPresetDatabase componentPresetDao ) {
235 this.componentPresetDao = componentPresetDao;
240 public Object call() throws Exception {
241 long start = System.currentTimeMillis();
242 componentPresetDao.load("datafiles/presets", "(?i).*orc");
244 long end = System.currentTimeMillis();
245 log.debug("Time to load presets: " + (end-start) + "ms");
252 * Handles arguments passed from the command line. This may be used either
253 * when starting the first instance of OpenRocket or later when OpenRocket is
254 * executed again while running.
256 * @param args the command-line arguments.
257 * @return whether a new frame was opened or similar user desired action was
258 * performed as a result.
260 private static boolean handleCommandLine(String[] args) {
262 // Check command-line for files
263 boolean opened = false;
264 for (String file : args) {
265 if (BasicFrame.open(new File(file), null)) {