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 };