create changelog entry
[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(true) {
88
89                         @Override
90                         protected void load() {
91                                 ConcurrentComponentPresetDatabaseLoader presetLoader = new ConcurrentComponentPresetDatabaseLoader( this );
92                                 presetLoader.load();
93                                 try {
94                                         presetLoader.await();
95                                 } catch ( InterruptedException iex) {
96                                         
97                                 }
98                         }
99                         
100                 };
101                 Application.setComponentPresetDao( componentPresetDao );
102
103                 componentPresetDao.startLoading();
104                 
105                 // Setup the uncaught exception handler
106                 log.info("Registering exception handler");
107                 SwingExceptionHandler exceptionHandler = new SwingExceptionHandler();
108                 Application.setExceptionHandler(exceptionHandler);
109                 exceptionHandler.registerExceptionHandler();
110                 
111                 // Start update info fetching
112                 final UpdateInfoRetriever updateInfo;
113                 if ( Application.getPreferences().getCheckUpdates()) {
114                         log.info("Starting update check");
115                         updateInfo = new UpdateInfoRetriever();
116                         updateInfo.start();
117                 } else {
118                         log.info("Update check disabled");
119                         updateInfo = null;
120                 }
121                 
122                 // Set the best available look-and-feel
123                 log.info("Setting best LAF");
124                 GUIUtil.setBestLAF();
125                 
126                 // Set tooltip delay time.  Tooltips are used in MotorChooserDialog extensively.
127                 ToolTipManager.sharedInstance().setDismissDelay(30000);
128                 
129                 // Load defaults
130                 ((SwingPreferences) Application.getPreferences()).loadDefaultUnits();
131                 
132                 // Load motors etc.
133                 log.info("Loading databases");
134                 
135                 loadMotor();
136                 
137                 Databases.fakeMethod();
138                 
139
140                 // Starting action (load files or open new document)
141                 log.info("Opening main application window");
142                 if (!handleCommandLine(args)) {
143                         BasicFrame.newAction();
144                 }
145                 
146                 // Check whether update info has been fetched or whether it needs more time
147                 log.info("Checking update status");
148                 checkUpdateStatus(updateInfo);
149                 
150         }
151         
152         /**
153          * this method is useful for the python bindings.
154          */
155         public static void loadMotor() {
156                 ConcurrentLoadingThrustCurveMotorSetDatabase motorLoader = new ConcurrentLoadingThrustCurveMotorSetDatabase(THRUSTCURVE_DIRECTORY);
157                 motorLoader.startLoading();
158                 Application.setMotorSetDatabase(motorLoader);
159         }
160         
161         /**
162          * Check that the JRE is not running headless.
163          */
164         private static void checkHead() {
165                 
166                 if (GraphicsEnvironment.isHeadless()) {
167                         log.error("Application is headless.");
168                         System.err.println();
169                         System.err.println("OpenRocket cannot currently be run without the graphical " +
170                                         "user interface.");
171                         System.err.println();
172                         System.exit(1);
173                 }
174                 
175         }
176         
177         
178         private static void checkUpdateStatus(final UpdateInfoRetriever updateInfo) {
179                 if (updateInfo == null)
180                         return;
181                 
182                 int delay = 1000;
183                 if (!updateInfo.isRunning())
184                         delay = 100;
185                 
186                 final Timer timer = new Timer(delay, null);
187                 
188                 ActionListener listener = new ActionListener() {
189                         private int count = 5;
190                         
191                         @Override
192                         public void actionPerformed(ActionEvent e) {
193                                 if (!updateInfo.isRunning()) {
194                                         timer.stop();
195                                         
196                                         String current = BuildProperties.getVersion();
197                                         String last = Application.getPreferences().getString(Preferences.LAST_UPDATE, "");
198                                         
199                                         UpdateInfo info = updateInfo.getUpdateInfo();
200                                         if (info != null && info.getLatestVersion() != null &&
201                                                         !current.equals(info.getLatestVersion()) &&
202                                                         !last.equals(info.getLatestVersion())) {
203                                                 
204                                                 UpdateInfoDialog infoDialog = new UpdateInfoDialog(info);
205                                                 infoDialog.setVisible(true);
206                                                 if (infoDialog.isReminderSelected()) {
207                                                         Application.getPreferences().putString(Preferences.LAST_UPDATE, "");
208                                                 } else {
209                                                         Application.getPreferences().putString(Preferences.LAST_UPDATE, info.getLatestVersion());
210                                                 }
211                                         }
212                                 }
213                                 count--;
214                                 if (count <= 0)
215                                         timer.stop();
216                         }
217                 };
218                 timer.addActionListener(listener);
219                 timer.start();
220         }
221         
222         /**
223          * Handles arguments passed from the command line.  This may be used either
224          * when starting the first instance of OpenRocket or later when OpenRocket is
225          * executed again while running.
226          * 
227          * @param args  the command-line arguments.
228          * @return              whether a new frame was opened or similar user desired action was
229          *                              performed as a result.
230          */
231         private static boolean handleCommandLine(String[] args) {
232                 
233                 // Check command-line for files
234                 boolean opened = false;
235                 for (String file : args) {
236                         if (BasicFrame.open(new File(file), null)) {
237                                 opened = true;
238                         }
239                 }
240                 return opened;
241         }
242         
243 }