001 /*
002 * Copyright (c) Holger Pfaff - http://pfaff.ws
003 *
004 * This software maybe used for any purpose provided the
005 * above copyright notice is retained. It is supplied as is.
006 * No warranty expressed or implied - Use at your own risk.
007 */
008
009 import java.applet.*;
010 import java.awt.*;
011 import java.awt.event.*;
012 import java.net.*;
013 import java.util.*;
014
015 /**
016 * (#)Main.java
017 * @author Holger Pfaff
018 * @version 3.2 19-Mar-2004<br><br>
019 *
020 * Common class used as base for GUI programs. Clients should implement <code>Base</code>.
021 * Main offers: <br>
022 * - run as applet or standalone program<br>
023 * - transparent handling of program parameter/options<br>
024 * - language/locale handling
025 * - resource/property files handling
026 * - variable depot
027 * - floating applet
028 *
029 * Property files are searched in a up to four level hierachy.
030 *
031 * (0) variables (see put())
032 * (1) <module>.properties
033 * (2) <basename>.properties
034 * (3) Main.properties
035 *
036 * For each hierachy up to three files are loaded:
037 * <name>.properties
038 * <name>_en.properties
039 * <name>_<lang>.properties
040 *
041 * Possible cmdline switches/applet args <br>
042 *
043 * -bg <color> specify background color @see Awt.getColor()<br>
044 * -fg <color> specify foreground color @see Awt.getColor()<br>
045 * -bgimage <imgfile> specify background image<br>
046 * -font <font> specify font to use e.g. sans-14<br>
047 * -lang <lang> specify language to use e.g. de<br>
048 * -debug <debuglevel> specifi debuglevel @see Debug.setArgs()<br>
049 *
050 *
051 */
052
053 public class Main extends Applet implements WindowListener,ParserListener {
054
055 /**
056 * global language - initialized from system default
057 */
058 protected String lang = Locale.getDefault().getLanguage();
059
060 /**
061 * our instance of the client program
062 */
063 protected Base base = null;
064
065 /**
066 * usually the name of the client class
067 */
068 protected String basename = null;
069
070 /**
071 * vectorized cmdline/applet args
072 */
073 protected Vector baseargs = null;
074
075 /**
076 * used for standalone progs or for floating applets
077 */
078 protected Frame baseframe = new Frame();
079
080 /**
081 * the current mode (applet or normal prog)
082 */
083 protected boolean isApplet = false;
084
085 /**
086 * the current mode (applet or normal prog)
087 */
088 protected boolean inFrame = false;
089
090 /**
091 * cache for already opened resources
092 */
093 protected Hashtable rescache = new Hashtable();
094
095 /**
096 * a four level resource hierachy
097 */
098 protected Hashtable[] restable = new Hashtable[4];
099
100 /**
101 * Put an object in the var bucket. null keys are ignored -
102 * null valued cause the key to be deleted from bucket
103 *
104 * @param key object to use as key.
105 * @param val object to use as value.
106 */
107 public void put(String key, Object val) {
108 Debug.debug(this, "key="+key+" val="+val);
109 if(key == null) return;
110 if(val == null) {
111 restable[0].remove(key);
112 } else {
113 restable[0].put(key, val);
114 }
115 }
116
117 /**
118 * set the module name to use as second level in the
119 * resource lookup hierachy
120 *
121 * @param mod module name to use
122 */
123 public void setModule(String mod) {
124 restable[1] = mod == null ? restable[2] : getHash(mod);
125 }
126
127 /**
128 * get an Object from our resource hierachy. Return null for error
129 *
130 * @param key the key to use
131 */
132 public Object get(String key) {
133 return get(key, 0);
134 }
135
136 /**
137 * get an Object from our resource hierachy. Return null for error
138 *
139 * @param key the key to use
140 * @param s start at hierachy level s
141 */
142 public Object get(String key, int s) {
143 Object r = null;
144 while(r == null && s < restable.length) {
145 r = restable[s++].get(key);
146 }
147 Debug.debug(this,"key="+key+" r="+r);
148 return r instanceof String ? Parser.replace((String) r, this) : r;
149 }
150
151 /**
152 * get a String from our resource hierachy. Return null for error
153 *
154 * @param key the key to use
155 */
156 public String getString(String key) {
157 Object result = get(key);
158 return result == null ? null : result.toString();
159 }
160
161 /**
162 * implement ParserListener
163 *
164 * @param error the error String
165 */
166 public void parseError(String error) {
167 Awt.error(error, baseframe);
168 }
169
170 /**
171 * get a hashtable from a resource file
172 *
173 * @param name the basename of the property file
174 */
175 public Hashtable getHash(String name) {
176 if(rescache.containsKey(name) == false) {
177 rescache.put(name, Util.getResourceHash(name, lang));
178 }
179 return (Hashtable) rescache.get(name);
180 }
181
182 /**
183 * set the default font
184 *
185 * @param font the default font
186 */
187 public void setFont(Font font) {
188 if(font == null) {
189 return;
190 }
191 super.setFont(font);
192 baseframe.setFont(font);
193 }
194
195 /**
196 * set the default foreground color
197 *
198 * @param color the default foreground color
199 */
200 public void setForeground(Color color) {
201 if(color == null) {
202 return;
203 }
204 super.setForeground(color);
205 baseframe.setForeground(color);
206 }
207
208 /**
209 * set the default background color
210 *
211 * @param color the default background color
212 */
213 public void setBackground(Color color) {
214 if(color == null) {
215 return;
216 }
217 super.setBackground(color);
218 baseframe.setBackground(color);
219 }
220
221 /**
222 * get the current language
223 */
224 public String getLang() {
225 return lang;
226 }
227
228 /**
229 * are we an applet?
230 */
231 public boolean isApplet() {
232 return isApplet;
233 }
234
235 /**
236 * are we an applet? Issue msg on failure
237 */
238 protected boolean isAppletCheck() {
239 if(isApplet == false) {
240 Awt.error("Only supported in applet mode", baseframe);
241 }
242 return isApplet;
243 }
244
245 /**
246 * get our origin hostname (only in applet mode)
247 */
248 public String getHost() {
249 try {
250 return getDocumentBase().getHost();
251 } catch (Exception x) {
252 return null;
253 }
254 }
255
256 /**
257 * make our applet floating (only in applet mode)
258 */
259 public void transform() {
260 if(isAppletCheck()) {
261 inFrame = !inFrame;
262 removeAll();
263 baseframe.removeAll();
264 baseframe.setVisible(inFrame);
265 if(inFrame) {
266 baseframe.add(BorderLayout.CENTER, base);
267 } else {
268 add(BorderLayout.CENTER, base);
269 }
270 baseframe.pack();
271 base.refreshAll();
272 }
273 }
274
275 /**
276 * duplicate our applet by opening a new browser window (only in applet mode)
277 */
278 public void duplicate() {
279 if(isAppletCheck()) {
280 showDocument(getDocumentBase().toString(), "_blank");
281 }
282 }
283
284 /**
285 * show an url in a browser window (only in applet mode)
286 *
287 * @param url the url
288 * @param name the location to use; null = "_self"
289 */
290 public void showDocument(String url, String name) {
291 if(isAppletCheck()) {
292 try {
293 getAppletContext().showDocument(new URL(url), name == null ? "_self" : name);
294 } catch(Exception x) {
295 Debug.debug(this, x);
296 }
297 }
298 }
299
300 /**
301 * the common part of the init routine
302 */
303 protected void init_() throws Exception {
304
305 Debug.setArgs(getArg("-debug", ""));
306 lang = getArg("-lang", lang);
307
308 restable[0] = getHash("VAR");
309 restable[1] = new Hashtable();
310 restable[2] = getHash(basename);
311 restable[3] = getHash(getClass().getName());
312
313 if(getString("Font") != null) {
314 setFont(Font.decode(getString("Font")));
315 }
316 setFont(Awt.getFont(getArg("-font", getFont())));
317
318 setBackground(SystemColor.text);
319 setForeground(SystemColor.textText);
320 setBackground(Awt.getColor(get("Background")));
321 setForeground(Awt.getColor(get("Foreground")));
322 setBackground(Awt.getColor(getArg("-bg", getBackground())));
323 setForeground(Awt.getColor(getArg("-fg", getForeground())));
324
325 // our widgets need some contrast to look good
326 if(getBackground().getRGB() == Color.white.getRGB()) {
327 setBackground(Color.lightGray);
328 }
329
330 put("HOST", getHost());
331 put("LANG", lang);
332 put("BASENAME", basename);
333 put("TIMEZONE", TimeZone.getDefault().getID());
334 put("TOTALMEM", "" + Runtime.getRuntime().totalMemory() / 1024);
335 put("BACKGROUND", Awt.Color2Esc(getBackground()));
336 put("FOREGROUND", Awt.Color2Esc(getForeground()));
337
338 String props[] = {"java.vendor", "java.version", "os.name", "os.arch", "os.version"};
339
340 for(int i = 0; i < props.length; ++i) {
341 put(props[i], System.getProperty(props[i]));
342 }
343
344 Class argt[] = {Main.class};
345 Object args[] = {this};
346
347 base = (Base) Class.forName(basename).getConstructor(argt).newInstance(args);
348
349 setLayout(new BorderLayout());
350 add(BorderLayout.CENTER, base);
351
352 baseframe.setTitle(basename);
353 baseframe.addWindowListener(this);
354
355 base.setBG(getArg("-bgimage", null));
356 base.refreshAll();
357 }
358
359 /**
360 * the applet part of the init routine
361 */
362 public void init() {
363 try {
364 isApplet = true;
365 baseargs = new StringSplitter(getParameter("args"), " ").toVector();
366 basename = getParameter("app");
367 if(basename == null) {
368 throw new Exception("Parameter 'app' missing");
369 }
370 init_();
371 } catch(Exception x) {
372 Awt.error(x, null);
373 showStatus(x.toString());
374 }
375 }
376
377 /**
378 * applet has been stopped -> tell base
379 */
380 public void stop() {
381 if(inFrame) transform();
382 if(base != null) base.stop();
383 }
384
385 /**
386 * applet has been started -> tell base
387 */
388 public void start() {
389 if(base != null) base.start();
390 }
391
392 /**
393 * satisfy curious browser
394 */
395 public String getAppletInfo() {
396 return "j-awt(" + basename + ") (c) 1999-2004 H. Pfaff";
397 }
398
399 /**
400 * satisfy curious browser
401 */
402 public String[][] getParameterInfo() {
403 String pinfo[][] = {
404 {"app", "String", "name of app"},
405 {"args", "String", "args for app"}};
406 return pinfo;
407 }
408
409 /**
410 * main() for standalone programms
411 *
412 * @param args commandline args
413 */
414 public static void main(String[] args) {
415 if(args.length > 0) {
416 try {
417 Main main = new Main();
418 main.basename = args[0];
419 main.baseargs = Util.array2Vector(args, 1);
420 main.init_();
421 main.start();
422 main.baseframe.add(BorderLayout.CENTER, main);
423 main.baseframe.setVisible(true);
424 main.baseframe.pack();
425 } catch (Exception x) {
426 Awt.error(x, null);
427 System.exit(1);
428 }
429 } else {
430 Awt.error("Usage: Main <app> [args]", null);
431 System.exit(1);
432 }
433 }
434
435 /**
436 * fetch arguments from args vector
437 *
438 * @param name name of argument
439 * @param def value to return on failure
440 */
441 public Object getArg(String name, Object def) {
442 int i = baseargs.indexOf(name) + 1;
443 return i == 0 || i == baseargs.size() ? def : baseargs.elementAt(i);
444 }
445
446 /**
447 * fetch String arguments from args vector
448 *
449 * @param name name of argument
450 * @param def value to return on failure
451 */
452 public String getArg(String name, String def) {
453 return (String) getArg(name , (Object) def);
454 }
455
456 /**
457 * fetch int arguments from args vector
458 *
459 * @param name name of argument
460 * @param def value to return on failure
461 */
462 public int getArg(String name, int def) {
463 try {
464 return Integer.parseInt(getArg(name, "" + def));
465 } catch(Exception x) {
466 return def;
467 }
468 }
469
470 /**
471 * fetch boolean arguments from args vector
472 *
473 * @param name name of argument
474 */
475 public boolean getArg(String name) {
476 return baseargs.contains(name);
477 }
478
479 /**
480 * implement java.awt.WindowListener to capture closing events
481 * and close window on request
482 *
483 * @param e WindowEvent
484 */
485 public void windowClosing(WindowEvent e) {
486 if(isApplet == false) {
487 System.exit(0);
488 }
489 if(inFrame) {
490 transform();
491 }
492 }
493
494 /**
495 * implement java.awt.WindowListener to capture iconify events
496 * to retransform window on request
497 *
498 * @param e WindowEvent
499 */
500 public void windowIconified(WindowEvent e) {
501 if(inFrame) {
502 transform();
503 }
504 }
505
506 /**
507 * implement java.awt.WindowListener - not used
508 *
509 * @param e WindowEvent
510 */
511 public void windowDeiconified(WindowEvent e) {
512 }
513
514 /**
515 * implement java.awt.WindowListener - not used
516 *
517 * @param e WindowEvent
518 */
519 public void windowOpened(WindowEvent e) {
520 }
521
522 /**
523 * implement java.awt.WindowListener - not used
524 *
525 * @param e WindowEvent
526 */
527 public void windowActivated(WindowEvent e) {
528 }
529
530 /**
531 * implement java.awt.WindowListener - not used
532 *
533 * @param e WindowEvent
534 */
535 public void windowDeactivated(WindowEvent e) {
536 }
537
538 /**
539 * implement java.awt.WindowListener - not used
540 *
541 * @param e WindowEvent
542 */
543 public void windowClosed(WindowEvent e) {
544 }
545 };