1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap;
21
22 import gnu.getopt.Getopt;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.InputStreamReader;
27 import java.text.MessageFormat;
28 import java.util.Locale;
29 import java.util.MissingResourceException;
30 import java.util.ResourceBundle;
31
32 import org.apache.log4j.Level;
33 import org.xnap.cmdl.CommandLine;
34 import org.xnap.gui.ErrorHandler;
35 import org.xnap.gui.SplashWindow;
36 import org.xnap.gui.XNapFrame;
37 import org.xnap.gui.theme.ThemeManager;
38 import org.xnap.loader.XNapClassLoader;
39 import org.xnap.loader.XNapLoader;
40 import org.xnap.util.Debug;
41 import org.xnap.util.FileHelper;
42 import org.xnap.util.Preferences;
43 import org.xnap.util.SystemHelper;
44 import org.xnap.util.UncaughtExceptionListener;
45 import org.xnap.util.UncaughtExceptionManager;
46 import org.xnap.util.Updater;
47 import org.xnap.util.VersionParser;
48 import org.xnap.util.XNapThreadGroup;
49
50 /***
51 * Starts the main application.
52 */
53 public class XNap {
54
55
56
57 public static final String FILE_REVISION = "$Revision: 1.20 $";
58
59 /***
60 * The minimal JDK version required to run the commandline version
61 */
62 public static final String REQUIRED_CMDL_JDK = "1.2.0";
63
64 /***
65 * The minimal JDK version required to run the gui version
66 */
67 public static final String REQUIRED_GUI_JDK = "1.3.0";
68
69 /***
70 * This list contains all languages the XNap interface has been
71 * translated into. Add new languages here (see TRANSLATION file).
72 */
73 public static final Locale[] LANGUAGES = {
74 Locale.CHINESE, Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN,
75 Locale.ITALIAN, Locale.JAPANESE, new Locale("nl", "", ""),
76 new Locale("es", "", ""), new Locale("ru", "", ""),
77 };
78
79 /***
80 * This list contains all public keys automatically accepted by xnap.
81 */
82 public static final String[] TRUSTED_KEYS = {
83
84 "MIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4"
85 +"C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7u"
86 +"p1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUA"
87 +"l2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMC"
88 +"z0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpn"
89 +"WRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYU"
90 +"AAoGBAO2rM0tzQs52zUd0yXq7JbPd9lclsE00b9H5s4dDRtkGzzqViywV8qxCbkjJc4Kq"
91 +"O249NBY5Je0nlLnMRxqTepHgeXF2WEDQmIsz5r7ZoVfUhZ90XTIHnE4IwdktX02Pbj/H6"
92 +"a1aOugUBaNnkBIClv239djzy1FekT+N0gGsN5w4"
93 };
94
95 public static final long START_TIME = System.currentTimeMillis();
96
97
98
99 public static boolean clearPackageInfos = false;
100
101 /*** Reference to the current localization bundle. */
102 private static ResourceBundle resources;
103
104 /*** The global thread group */
105 private static XNapThreadGroup tg;
106 private static UncaughtExceptionListener exceptionHandler;
107
108 /*** The version that was last launched. */
109 public static String lastLaunchVersion;
110
111 /***
112 * True if xnap is run from cvs. Enables a few development quirks.
113 */
114 private static boolean isRunFromCvs = false;
115
116 private static boolean firstTime = true;
117
118
119
120 /***
121 * Cleanly exits the applicaton.
122 */
123 public static void exit()
124 {
125 if (XNapFrame.getInstance() != null) {
126 XNapFrame.getInstance().stop();
127 }
128
129 if (CommandLine.getInstance() != null) {
130 CommandLine.getInstance().stop();
131 }
132
133 Updater.stop();
134 System.exit(0);
135 }
136
137 /***
138 * Brings up the Command Line (Cmdl) or Graphic User Interface (GUI).
139 *
140 * @param args parameters
141 */
142 public static void main(final String[] argv)
143 {
144 tg = new XNapThreadGroup("XNapThreadGroup");
145 System.setProperty("sun.awt.exception.handler",
146 "xnap.util.XNapAWTExceptionHandler");
147 Thread mainRunner = new Thread(tg, "XNapMain") {
148 public void run() {
149 setContextClassLoader(XNapClassLoader.getInstance());
150 runMain(argv);
151 }
152 };
153
154 mainRunner.start();
155 }
156
157 private static void runMain(String[] argv)
158 {
159 Level level = Level.OFF;
160 boolean debug = false;
161 boolean startCmdl = false;
162 boolean showHelp = false;
163 boolean jdkCheck = true;
164
165 Getopt g = new Getopt("xnap", argv, "cd::hnpvx");
166
167 int c;
168 while ((c = g.getopt()) != -1) {
169
170 switch (c) {
171 case 'c':
172 startCmdl = true;
173 break;
174 case 'd':
175 debug = true;
176 String arg = g.getOptarg();
177 level = (arg != null) ? Level.toLevel(arg) : Level.ALL;
178 break;
179 case 'h':
180 showHelp = true;
181 break;
182 case 'n':
183 jdkCheck = false;
184 break;
185 case 'p':
186 clearPackageInfos = true;
187 break;
188 case 'v':
189 System.out.println(XNapLoader.VERSION);
190 System.exit(0);
191 break;
192 case 'x':
193 isRunFromCvs = true;
194 break;
195 case '?':
196 System.exit(1);
197 break;
198 }
199 }
200
201 File debugPrefs = new File(FileHelper.getHomeDir() + "debug.prefs");
202 Debug.init(debugPrefs, level);
203
204 if (!debug) {
205 File f = new File(FileHelper.getHomeDir() + "error.log");
206 Debug.setErrorFile(f);
207 }
208
209
210 SystemHelper.init();
211 Preferences prefs = Preferences.getInstance();
212 prefs.read();
213
214 lastLaunchVersion = prefs.getLastLaunchVersion();
215 if (!XNapLoader.VERSION.equals(lastLaunchVersion)) {
216
217 clearPackageInfos = true;
218 }
219 prefs.setLastLaunchVersion(XNapLoader.VERSION);
220
221 initLocale(prefs.getLanguage());
222
223 if (debug) {
224 try {
225 InputStreamReader in = new InputStreamReader(System.in);
226 System.err.println("Default encoding: " + in.getEncoding());
227 in.close();
228 }
229 catch (IOException e) {
230 }
231 }
232
233 if (showHelp) {
234 showHelp();
235 System.exit(0);
236 }
237 else {
238 if (jdkCheck) {
239 checkJDK(REQUIRED_CMDL_JDK);
240 }
241
242 if (!startCmdl) {
243 exceptionHandler = new ErrorHandler();
244 UncaughtExceptionManager.getInstance().addExceptionListener
245 (exceptionHandler);
246
247 if (prefs.getShowSplash()) {
248 SplashWindow.showSplashWindow(0);
249 SplashWindow.setText(XNap.tr("Starting up"));
250 }
251 }
252
253 Updater.start();
254
255 if (startCmdl) {
256 CommandLine cmdl = new CommandLine();
257 cmdl.start();
258 }
259 else {
260 startGUI();
261 }
262 }
263 }
264
265 /***
266 * Sets default locale and loads resources.
267 */
268 public static void initLocale(String language)
269 {
270 for (int i = 0; i < LANGUAGES.length; i++) {
271 if (language.equals(LANGUAGES[i].getLanguage())) {
272 Locale.setDefault(LANGUAGES[i]);
273 break;
274 }
275 }
276
277 try {
278 resources = ResourceBundle.getBundle("org.xnap.resources.XNap",
279 Locale.getDefault());
280 }
281 catch (MissingResourceException e) {
282 System.err.println("org/xnap/resources/XNap.properties not found");
283 System.exit(1);
284 }
285 }
286
287 public static final XNapThreadGroup getThreadGroup()
288 {
289 return tg;
290 }
291
292 public static boolean isRunFromCvs()
293 {
294 return isRunFromCvs;
295 }
296
297 /***
298 * Prints a warning message if <code>reqVer</code> is smaller than the
299 * current jdk version.
300 */
301 public static final void checkJDK(String reqVer)
302 {
303 String jdkVer = System.getProperty("java.version");
304
305 if (VersionParser.compare(jdkVer, reqVer) < 0) {
306 System.out.println(XNap.tr("Your java version") + "\t: " + jdkVer);
307 System.out.println(XNap.tr("Required version") + "\t: " + reqVer);
308 System.out.println(XNap.tr("If XNap runs fine, you can safely ignore this message.\n")
309 + XNap.tr("Otherwise you probably need to update your jdk from\nhttp://java.sun.com/products/jdk/1.3/jre/index.html."));
310 System.out.println(tr("See http://xnap.sourceforge.net for more information.\n")
311 + "(" + XNap.tr("use -n to suppress this message") + ")\n");
312 }
313 }
314
315 /***
316 * Print a help message to stdout.
317 */
318 public static final void showHelp()
319 {
320 System.out.println(XNap.tr("Usage: xnap [options]"));
321 System.out.println(" -c\t " + XNap.tr("start in commandline mode"));
322 System.out.println(" -d[level]\t " + XNap.tr("show debug messages"));
323 System.out.println(" -h\t " + XNap.tr("show this help"));
324 System.out.println(" -n\t" + XNap.tr("do not check jdk version"));
325 }
326
327 public static final void startGUI()
328 {
329 if (exceptionHandler == null) {
330 exceptionHandler = new ErrorHandler();
331 UncaughtExceptionManager.getInstance().addExceptionListener
332 (exceptionHandler);
333 }
334
335 if (firstTime) {
336 ThemeManager.initialize();
337 XNapFrame.updateLookAndFeel();
338 firstTime = false;
339 }
340
341 XNapFrame f = new XNapFrame();
342 f.setVisible(true);
343
344 f.guiVisible();
345
346 SplashWindow.closeSplashWindow();
347 }
348
349 public static final void stopGUI()
350 {
351 XNapFrame.getInstance().stop();
352
353 UncaughtExceptionManager.getInstance().removeExceptionListener
354 (exceptionHandler);
355 exceptionHandler = null;
356 }
357
358 /***
359 * Returns <code>text</code> translated into the currently selected
360 * language. Every user-visible string in the program must be wrapped
361 * into this function.
362 */
363 public static final String tr(String text)
364 {
365 try {
366 return resources.getString(text);
367 }
368 catch (MissingResourceException e) {
369
370
371 return text;
372 }
373 catch (NullPointerException e) {
374
375 return text;
376 }
377 }
378
379 /***
380 * Returns <code>text</code> translated into the currently selected
381 * language.
382 *
383 * <p>The first occurence of {0} is replaced by <code>o1.toString()</code>.
384 */
385 public static final String tr(String text, Object o1)
386 {
387 return MessageFormat.format(XNap.tr(text), new Object[] { o1 });
388 }
389
390 /***
391 * Returns <code>text</code> translated into the currently selected
392 * language.
393 *
394 * <p>The first occurence of {0} is replaced by <code>o1.toString()</code>.
395 * The first occurence of {1} is replaced by <code>o2.toString()</code>.
396 */
397 public static final String tr(String text, Object o1, Object o2)
398 {
399 return MessageFormat.format(XNap.tr(text), new Object[] { o1, o2 });
400 }
401
402 /***
403 * Returns <code>text</code> translated into the currently selected
404 * language.
405 *
406 * <p>The first occurence of {0} is replaced by <code>o1.toString()</code>.
407 * The first occurence of {1} is replaced by <code>o2.toString()</code>.
408 * The first occurence of {2} is replaced by <code>o3.toString()</code>.
409 */
410 public static final String tr(String text, Object o1, Object o2,
411 Object o3)
412 {
413 return MessageFormat.format(XNap.tr(text),
414 new Object[] { o1, o2, o3 });
415 }
416
417 /***
418 * Returns <code>text</code> translated into the currently selected
419 * language.
420 *
421 * <p>The first occurence of {0} is replaced by <code>o1.toString()</code>.
422 * The first occurence of {1} is replaced by <code>o2.toString()</code>.
423 * The first occurence of {2} is replaced by <code>o3.toString()</code>.
424 * The first occurence of {3} is replaced by <code>o4.toString()</code>.
425 */
426 public static final String tr(String text, Object o1, Object o2,
427 Object o3, Object o4)
428 {
429 return MessageFormat.format(XNap.tr(text),
430 new Object[] { o1, o2, o3, o4 });
431 }
432
433 /***
434 * Returns <code>text</code> translated into the currently selected
435 * language. Prepends and appends <code>padding</code> whitespaces.
436 */
437 public static final String tr(String text, int padding)
438 {
439 String s = tr(text);
440 if (padding <= 0) {
441 return s;
442 }
443 StringBuffer sb = new StringBuffer(s.length() + padding * 2);
444 append(sb, " ", padding);
445 sb.append(s);
446 append(sb, " ", padding);
447 return sb.toString();
448 }
449
450 /***
451 * Returns <code>text</code> translated into the currently selected
452 * language. Prepends <code>lpadding</code> whitespaces. Appends
453 * <code>rpadding</code> whitespaces.
454 */
455 public static final String tr(String text, int lpadding, int rpadding)
456 {
457 String s = tr(text);
458 StringBuffer sb = new StringBuffer(s.length() + lpadding + rpadding);
459 append(sb, " ", lpadding);
460 sb.append(s);
461 append(sb, " ", rpadding);
462 return sb.toString();
463 }
464
465 private static final void append(StringBuffer sb, String s, int count)
466 {
467 for (int i = 0; i < count; i++) {
468 sb.append(s);
469 }
470 }
471 }