Include OSX UI elements.
[debian/openrocket] / core / 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
8 import javax.swing.SwingUtilities;
9 import javax.swing.Timer;
10 import javax.swing.ToolTipManager;
11
12 import net.sf.openrocket.arch.SystemInfo;
13 import net.sf.openrocket.arch.SystemInfo.Platform;
14 import net.sf.openrocket.communication.UpdateInfo;
15 import net.sf.openrocket.communication.UpdateInfoRetriever;
16 import net.sf.openrocket.database.ComponentPresetDatabase;
17 import net.sf.openrocket.database.Databases;
18 import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
19 import net.sf.openrocket.gui.main.BasicFrame;
20 import net.sf.openrocket.gui.main.Splash;
21 import net.sf.openrocket.gui.main.SwingExceptionHandler;
22 import net.sf.openrocket.gui.util.GUIUtil;
23 import net.sf.openrocket.gui.util.SwingPreferences;
24 import net.sf.openrocket.logging.LogHelper;
25 import net.sf.openrocket.util.BuildProperties;
26
27 /**
28  * The second class in the OpenRocket startup sequence.  This class can assume the
29  * Application class to be properly set up, and can use any classes safely.
30  * 
31  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
32  */
33 public class Startup2 {
34         private static final LogHelper log = Application.getLogger();
35         
36
37         private static final String THRUSTCURVE_DIRECTORY = "datafiles/thrustcurves/";
38         
39         /**
40          * Run when starting up OpenRocket after Application has been set up.
41          * 
42          * @param args  command line arguments
43          */
44         static void runMain(final String[] args) throws Exception {
45                 
46                 log.info("Starting up OpenRocket version " + BuildProperties.getVersion());
47                 
48                 // Check that we're not running headless
49                 log.info("Checking for graphics head");
50                 checkHead();
51                 
52                 // Check that we're running a good version of a JRE
53                 log.info("Checking JRE compatibility");
54                 VersionHelper.checkVersion();
55                 VersionHelper.checkOpenJDK();
56                 
57                 // If running on a MAC set up OSX UI Elements.
58                 if ( SystemInfo.getPlatform() == Platform.MAC_OS ){
59                         OSXStartup.setupOSX();
60                 }
61                 
62                 // Run the actual startup method in the EDT since it can use progress dialogs etc.
63                 log.info("Moving startup to EDT");
64                 SwingUtilities.invokeAndWait(new Runnable() {
65                         @Override
66                         public void run() {
67                                 runInEDT(args);
68                         }
69                 });
70                 
71                 log.info("Startup complete");
72         }
73         
74         
75         /**
76          * Run in the EDT when starting up OpenRocket.
77          * 
78          * @param args  command line arguments
79          */
80         private static void runInEDT(String[] args) {
81                 
82                 // Initialize the splash screen with version info
83                 log.info("Initializing the splash screen");
84                 Splash.init();
85                 
86                 // Must be done after localization is initialized
87                 ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase();
88                 ConcurrentComponentPresetDatabaseLoader presetLoader = new ConcurrentComponentPresetDatabaseLoader( componentPresetDao );
89                 presetLoader.load();
90                 
91                 Application.setComponentPresetDao( componentPresetDao );
92                 
93                 // Setup the uncaught exception handler
94                 log.info("Registering exception handler");
95                 SwingExceptionHandler exceptionHandler = new SwingExceptionHandler();
96                 Application.setExceptionHandler(exceptionHandler);
97                 exceptionHandler.registerExceptionHandler();
98                 
99                 // Start update info fetching
100                 final UpdateInfoRetriever updateInfo;
101                 if ( Application.getPreferences().getCheckUpdates()) {
102                         log.info("Starting update check");
103                         updateInfo = new UpdateInfoRetriever();
104                         updateInfo.start();
105                 } else {
106                         log.info("Update check disabled");
107                         updateInfo = null;
108                 }
109                 
110                 // Set the best available look-and-feel
111                 log.info("Setting best LAF");
112                 GUIUtil.setBestLAF();
113                 
114                 // Set tooltip delay time.  Tooltips are used in MotorChooserDialog extensively.
115                 ToolTipManager.sharedInstance().setDismissDelay(30000);
116                 
117                 // Load defaults
118                 ((SwingPreferences) Application.getPreferences()).loadDefaultUnits();
119                 
120                 // Load motors etc.
121                 log.info("Loading databases");
122                 
123                 loadMotor();
124                 
125                 Databases.fakeMethod();
126                 
127                 try {
128                         presetLoader.await();
129                 } catch ( InterruptedException iex) {
130                         
131                 }
132
133                 // Starting action (load files or open new document)
134                 log.info("Opening main application window");
135                 if (!handleCommandLine(args)) {
136                         BasicFrame.newAction();
137                 }
138                 
139                 // Check whether update info has been fetched or whether it needs more time
140                 log.info("Checking update status");
141                 checkUpdateStatus(updateInfo);
142                 
143         }
144         
145         /**
146          * this method is useful for the python bindings.
147          */
148         public static void loadMotor() {
149                 ConcurrentLoadingThrustCurveMotorSetDatabase motorLoader = new ConcurrentLoadingThrustCurveMotorSetDatabase(THRUSTCURVE_DIRECTORY);
150                 motorLoader.startLoading();
151                 Application.setMotorSetDatabase(motorLoader);
152         }
153         
154         /**
155          * Check that the JRE is not running headless.
156          */
157         private static void checkHead() {
158                 
159                 if (GraphicsEnvironment.isHeadless()) {
160                         log.error("Application is headless.");
161                         System.err.println();
162                         System.err.println("OpenRocket cannot currently be run without the graphical " +
163                                         "user interface.");
164                         System.err.println();
165                         System.exit(1);
166                 }
167                 
168         }
169         
170         
171         private static void checkUpdateStatus(final UpdateInfoRetriever updateInfo) {
172                 if (updateInfo == null)
173                         return;
174                 
175                 int delay = 1000;
176                 if (!updateInfo.isRunning())
177                         delay = 100;
178                 
179                 final Timer timer = new Timer(delay, null);
180                 
181                 ActionListener listener = new ActionListener() {
182                         private int count = 5;
183                         
184                         @Override
185                         public void actionPerformed(ActionEvent e) {
186                                 if (!updateInfo.isRunning()) {
187                                         timer.stop();
188                                         
189                                         String current = BuildProperties.getVersion();
190                                         String last = Application.getPreferences().getString(Preferences.LAST_UPDATE, "");
191                                         
192                                         UpdateInfo info = updateInfo.getUpdateInfo();
193                                         if (info != null && info.getLatestVersion() != null &&
194                                                         !current.equals(info.getLatestVersion()) &&
195                                                         !last.equals(info.getLatestVersion())) {
196                                                 
197                                                 UpdateInfoDialog infoDialog = new UpdateInfoDialog(info);
198                                                 infoDialog.setVisible(true);
199                                                 if (infoDialog.isReminderSelected()) {
200                                                         Application.getPreferences().putString(Preferences.LAST_UPDATE, "");
201                                                 } else {
202                                                         Application.getPreferences().putString(Preferences.LAST_UPDATE, info.getLatestVersion());
203                                                 }
204                                         }
205                                 }
206                                 count--;
207                                 if (count <= 0)
208                                         timer.stop();
209                         }
210                 };
211                 timer.addActionListener(listener);
212                 timer.start();
213         }
214         
215         /**
216          * Handles arguments passed from the command line.  This may be used either
217          * when starting the first instance of OpenRocket or later when OpenRocket is
218          * executed again while running.
219          * 
220          * @param args  the command-line arguments.
221          * @return              whether a new frame was opened or similar user desired action was
222          *                              performed as a result.
223          */
224         private static boolean handleCommandLine(String[] args) {
225                 
226                 // Check command-line for files
227                 boolean opened = false;
228                 for (String file : args) {
229                         if (BasicFrame.open(new File(file), null)) {
230                                 opened = true;
231                         }
232                 }
233                 return opened;
234         }
235         
236 }