1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * ident "%Z%%M% %I% %E% SMI" 24 * 25 * Copyright (c) 2000 by Sun Microsystems, Inc. 26 * All rights reserved. 27 */ 28 29 /* 30 * Copyright (C) 1996 Active Software, Inc. 31 * All rights reserved. 32 * 33 * @(#) Converter.java 1.65 - last change made 08/20/97 34 */ 35 36 package sunsoft.jws.visual.rt.type; 37 38 import sunsoft.jws.visual.rt.base.Global; 39 40 import sunsoft.jws.visual.rt.base.*; 41 42 import java.util.*; 43 44 /** 45 * Base class for all converters. Converts a type of 46 * object to a string 47 * and back again. 48 * 49 * @version 1.65, 08/20/97 50 */ 51 52 public abstract class Converter { 53 /** 54 * Table of names for each registered converter. 55 */ 56 private static Hashtable converterNameTable = new Hashtable(); 57 58 /** 59 * Table of instances for each converter that has 60 * been instantiated. 61 */ 62 private static Hashtable converterInstanceTable = new Hashtable(); 63 64 /** 65 * Adds a new type converter to the global table of converters. A 66 * converter must be listed for this table in order for the search 67 * for a converter for that particular type to be successful. 68 * 69 * @param typeName the name of the type (what is returned by a 70 * call to getClass().getType() for an instance of that type) 71 * @param converterClassName the full name of the converter class 72 */ addConverter(String typeName, String converterClassName)73 public static void addConverter(String typeName, 74 String converterClassName) { 75 converterNameTable.put(typeName, converterClassName); 76 } 77 78 /** 79 * Initialize the type converters for the types we know about. 80 */ 81 static { 82 addConverter(/* NOI18N */"[I", /* NOI18N */ 83 "sunsoft.jws.visual.rt.type.IntArrayConverter"); 84 addConverter(/* NOI18N */"[D", /* NOI18N */ 85 "sunsoft.jws.visual.rt.type.DoubleArrayConverter"); 86 addConverter(/* NOI18N */"java.lang.String", 87 /* NOI18N */"sunsoft.jws.visual.rt.type.StringConverter"); 88 addConverter(/* NOI18N */"[Ljava.lang.String;", 89 /* NOI18N */"sunsoft.jws.visual.rt.type.StringArrayConverter"); 90 addConverter(/* NOI18N */"java.lang.Boolean", 91 /* NOI18N */"sunsoft.jws.visual.rt.type.BooleanConverter"); 92 addConverter(/* NOI18N */"java.lang.Character", 93 /* NOI18N */"sunsoft.jws.visual.rt.type.CharacterConverter"); 94 addConverter(/* NOI18N */"java.lang.Integer", 95 /* NOI18N */"sunsoft.jws.visual.rt.type.IntegerConverter"); 96 addConverter(/* NOI18N */"java.awt.Color", 97 /* NOI18N */"sunsoft.jws.visual.rt.type.ColorConverter"); 98 addConverter(/* NOI18N */"java.awt.SystemColor", 99 /* NOI18N */"sunsoft.jws.visual.rt.type.ColorConverter"); 100 addConverter(/* NOI18N */"java.awt.Font", 101 /* NOI18N */"sunsoft.jws.visual.rt.type.FontConverter"); 102 addConverter(/* NOI18N */"java.awt.Point", 103 /* NOI18N */"sunsoft.jws.visual.rt.type.PointConverter"); 104 addConverter(/* NOI18N */"java.awt.Dimension", 105 /* NOI18N */"sunsoft.jws.visual.rt.type.DimensionConverter"); 106 addConverter(/* NOI18N */"java.awt.Insets", 107 /* NOI18N */"sunsoft.jws.visual.rt.type.InsetsConverter"); 108 addConverter(/* NOI18N */ 109 "sunsoft.jws.visual.rt.awt.GBConstraints", 110 /* NOI18N */"sunsoft.jws.visual.rt.type.GBConstraintsConverter"); 111 addConverter(/* NOI18N */ 112 "sunsoft.jws.visual.rt.base.AttributeManager", 113 /* NOI18N */"sunsoft.jws.visual.rt.type.AMConverter"); 114 addConverter(/* NOI18N */"sunsoft.jws.visual.rt.type.AMRef", 115 /* NOI18N */"sunsoft.jws.visual.rt.type.AMRefConverter"); 116 addConverter(/* NOI18N */ 117 "sunsoft.jws.visual.rt.base.Attribute", 118 /* NOI18N */"sunsoft.jws.visual.rt.type.AttributeConverter"); 119 addConverter(/* NOI18N */ 120 "sunsoft.jws.visual.rt.base.AttributeList", 121 /* NOI18N */"sunsoft.jws.visual.rt.type.AttributeListConverter"); 122 addConverter(/* NOI18N */"sunsoft.jws.visual.rt.type.ImageRef", 123 /* NOI18N */"sunsoft.jws.visual.rt.type.ImageRefConverter"); 124 addConverter(/* NOI18N */ 125 "sunsoft.jws.visual.rt.type.AlignmentEnum", 126 /* NOI18N */"sunsoft.jws.visual.rt.type.BaseEnumConverter"); 127 addConverter(/* NOI18N */ 128 "sunsoft.jws.visual.rt.type.AnchorEnum", 129 /* NOI18N */"sunsoft.jws.visual.rt.type.BaseEnumConverter"); 130 addConverter(/* NOI18N */ 131 "sunsoft.jws.visual.rt.type.OrientationEnum", 132 /* NOI18N */"sunsoft.jws.visual.rt.type.BaseEnumConverter"); 133 addConverter(/* NOI18N */ 134 "sunsoft.jws.visual.rt.type.ReliefEnum", 135 /* NOI18N */"sunsoft.jws.visual.rt.type.BaseEnumConverter"); 136 addConverter(/* NOI18N */"sunsoft.jws.visual.rt.type.ModeEnum", 137 /* NOI18N */"sunsoft.jws.visual.rt.type.BaseEnumConverter"); 138 addConverter(/* NOI18N */"unknown", /* NOI18N */ 139 "sunsoft.jws.visual.rt.type.UnknownTypeConverter"); 140 } 141 142 /** 143 * Returns an existing converter for the given type. Creates a new 144 * converter only if necessary (typically the first 145 * time one is asked for.) 146 */ getConverter(String typeName)147 public static Converter getConverter(String typeName) { 148 Converter converter; 149 150 converter = (Converter)converterInstanceTable.get(typeName); 151 if (converter != null) 152 return converter; 153 154 String converterType = (String) converterNameTable.get 155 (typeName); 156 if (converterType == null) { 157 /* JSTYLED */ 158 // Load the class for the type and try again. Some types have 159 // static initializers that register their converters. 160 loadType(typeName); 161 converterType = (String) converterNameTable.get(typeName); 162 } 163 164 if (converterType == null) { 165 converterType = (String) converterNameTable.get 166 (/* NOI18N */"unknown"); 167 if (converterType == null) 168 /* JSTYLED */ 169 throw new Error(Global.getMsg("sunsoft.jws.visual.rt.type.Converter.No__converter__defined.20")); 170 } 171 try { 172 Class c = Class.forName(converterType); 173 converter = (Converter) c.newInstance(); 174 converter.setConverterType(typeName); 175 converterInstanceTable.put(typeName, converter); 176 return converter; 177 } 178 catch (Exception e) { 179 throw new Error(e.getMessage()); 180 } 181 } 182 loadType(String typeName)183 private static void loadType(String typeName) { 184 // For arrays, use the array type 185 if (typeName.charAt(0) == /* NOI18N */ '[') { 186 int i; 187 int len = typeName.length(); 188 for (i = 0; i < len; i++) { 189 if (typeName.charAt(i) != /* NOI18N */ '[') 190 break; 191 } 192 i++; 193 if (i < len) 194 typeName = typeName.substring(i, len-1); 195 } 196 197 try { 198 Class.forName(typeName); 199 } 200 catch (ClassNotFoundException ex) { 201 /* JSTYLED */ 202 System.out.println(Global.getMsg("sunsoft.jws.visual.rt.type.Converter.Class__not__found__for__.21") + typeName + /* NOI18N */"\"."); 203 } 204 } 205 206 /** 207 * Returns true if there is a converter for the given type. 208 */ hasConverter(String typeName)209 public static boolean hasConverter(String typeName) { 210 return (converterNameTable.containsKey(typeName)); 211 } 212 213 /** 214 * The type editors (for more complex types.) 215 */ 216 private static Hashtable typeEditorNameTable = new Hashtable(); 217 218 /** 219 * Registers a type editor for a type. At run-time (in generated 220 * applications) there will typically be no editors, but they are 221 * needed for the attribute editor in the designer. The designer 222 * will set up all the standard ones. 223 * 224 * @see TypeEditor 225 */ addTypeEditor(String typeName, String editorClassName)226 public static void addTypeEditor(String typeName, 227 String editorClassName) { 228 typeEditorNameTable.put(typeName, editorClassName); 229 } 230 231 /** 232 * Returns true if there is an editor for the given type. 233 * 234 * @see TypeEditor 235 */ hasTypeEditor(String typeName)236 public static boolean hasTypeEditor(String typeName) { 237 return (typeEditorNameTable.containsKey(typeName)); 238 } 239 240 /* BEGIN JSTYLED */ 241 /** 242 * Returns a new instance of a type editor. 243 * The caller (typically the 244 * Designer) gets a new one of these every time, one for each 245 * attribute being edited, even if they are the same type. Caching 246 * instances of these type editors is up to the caller. 247 */ 248 /* END JSTYLED */ 249 newTypeEditor(String typeName)250 public static TypeEditor newTypeEditor(String typeName) { 251 String editorType = (String) typeEditorNameTable.get(typeName); 252 253 if (editorType != null) { 254 try { 255 // instances of type editors are NOT cached 256 Class c = Class.forName(editorType); 257 return ((TypeEditor) c.newInstance()); 258 } 259 catch (Exception ex) { 260 /* JSTYLED */ 261 throw new VJException(Global.newline() + /* NOI18N */" " + ex.toString()); 262 } 263 } 264 265 return null; 266 } 267 268 /** 269 * Returns whether a converter instance has an 270 * associated type editor. 271 * 272 * @see TypeEditor 273 */ hasTypeEditor()274 public boolean hasTypeEditor() { 275 return (hasTypeEditor(getConverterType())); 276 } 277 278 /** 279 * Returns a new instance of the type editor associated with this 280 * converter. 281 */ newTypeEditor()282 public TypeEditor newTypeEditor() { 283 return (newTypeEditor(getConverterType())); 284 } 285 /* JSTYLED */ 286 // ------ Interfaces for Sub-Classers ----------------------------------- 287 288 /** 289 * The name of the type being edited. 290 */ 291 protected String converterType; 292 293 /** 294 * An interface that can be overridden in sub-classes 295 * to whom the type 296 * converted is important. 297 * 298 * @see BaseEnumConverter 299 */ setConverterType(String type)300 protected void setConverterType(String type) { 301 converterType = type; 302 } 303 304 /** 305 * Returns the type of object converted by this converter. 306 */ getConverterType()307 public String getConverterType() { 308 return (converterType); 309 } 310 311 /* BEGIN JSTYLED */ 312 /** 313 * Returns the string representation for an instance of 314 * the type this 315 * converter converts. Must be declared in subclasses 316 * to convert an 317 * object of the type specific to that subclass of Converter. 318 * <p> 319 * One of the two "convertToString" methods must be overridden in 320 * the converter sub-class. The overridden "convertToString" 321 * method 322 * should NOT call "super.convertToString". It is preferrable to 323 * override the StringBuffer version (the other one) because this 324 * will result in better performance. 325 */ 326 /* END JSTYLED */ convertToString(Object obj)327 public String convertToString(Object obj) { 328 enterConvert(TOSTRING, false); 329 StringBuffer buf = new StringBuffer(); 330 convertToString(obj, buf); 331 exitConvert(TOSTRING, false); 332 333 return buf.toString(); 334 } 335 336 /** 337 * Places a string representation of an instance of the type this 338 * converter converts into a string buffer. 339 */ convertToString(Object obj, StringBuffer buf)340 public void convertToString(Object obj, StringBuffer buf) { 341 enterConvert(TOSTRING, true); 342 buf.append(convertToString(obj)); 343 exitConvert(TOSTRING, true); 344 } 345 346 /** 347 * Returns a new instance of the type this converter converts, as 348 * specified by the string given. Must be declared 349 * in subclasses of 350 * Converter to convert a string representation into an object of 351 * the type converted by the subclass. 352 */ convertFromString(String s)353 public abstract Object convertFromString(String s); 354 355 /** 356 * Converts an instance of the type into a block of code. 357 */ convertToCodeBlock(String amName, Attribute a, int indent, StringBuffer buf)358 public void convertToCodeBlock(String amName, 359 Attribute a, int indent, StringBuffer buf) { 360 361 Converter c = getConverter(a.getType()); 362 String attr_name; 363 364 indent(buf, indent); 365 buf.append(amName); 366 buf.append(/* NOI18N */".set(\""); 367 attr_name = a.getName(); 368 buf.append(attr_name); 369 buf.append(/* NOI18N */"\", "); 370 buf.append(c.convertToCode(a.getValue())); 371 buf.append(/* NOI18N */");"); 372 newline(buf); 373 } 374 375 /** 376 * Converts an instance of the type converted into a line of code. 377 * This method provides a default way for any type to get a 378 * convertToCode method into it. It generates code that will feed 379 * the string representation of the object into the 380 * appropriate type 381 * converter. The performance isn't as good as customized 382 * convertToCode functions in subclasses since more classes have to 383 * be loaded at runtime. 384 */ convertToCode(Object obj)385 public String convertToCode(Object obj) { 386 if (obj != null) 387 return (/* NOI18N */"convert(\"" + 388 obj.getClass().getName() + /* NOI18N */"\", \"" 389 + convertToString(obj) + /* NOI18N */"\")"); 390 else 391 return (/* NOI18N */"null"); 392 } 393 394 /** 395 * Returns the string that should be displayed in the attribute 396 * editor. Subclassers that want something displayed other than 397 * what is returned from convertToString should override this 398 * method to return that. 399 */ displayString(Object obj)400 public String displayString(Object obj) { 401 return (convertToString(obj)); 402 } 403 404 /** 405 * Returns true if this type should be displayed in an editor. 406 * 407 * For the attribute editor, a return value of false means that the 408 * the textfield will be hidden. 409 * 410 * @return true 411 */ viewableAsString()412 public boolean viewableAsString() { 413 return true; 414 } 415 416 /** 417 * Returns true if this type is simple enough to be 418 * edited as a string 419 * in an editor. 420 * 421 * Sub-classers that represent type too complex for 422 * this should override 423 * this function to return false. For the attribute editor, 424 * this means 425 * that the textfield will be read-only. 426 * 427 * @see #viewableAsString 428 * @return same as viewableAsString 429 */ editableAsString()430 public boolean editableAsString() { 431 return viewableAsString(); 432 } 433 434 /** 435 * These weird looking enter/exit methods ensure that the converter 436 * sub-class is overriding at least one of the "convertToString" 437 * methods, and at least one of the "convertToCode" methods. 438 * An error will be thrown at runtime if this in not the case. 439 * If this check wasn't done here , then the failure to 440 * override one 441 * of the methods would result in an infinite loop. 442 */ 443 private static final int TOSTRING = 0; 444 private static final int TOCODE = 1; 445 446 private boolean converting[] = {false, false}; 447 private boolean isBuffered[] = {false, false}; 448 private int convertRecurse[] = {0, 0}; 449 enterConvert(int c, boolean isBuffered)450 private void enterConvert(int c, boolean isBuffered) { 451 if (converting[c] && this.isBuffered[c] != isBuffered) 452 throw new Error(Global.getMsg( 453 "sunsoft.jws.visual.rt.type.Converter.Sub-classes__of__Conve.22")); 454 455 this.isBuffered[c] = isBuffered; 456 converting[c] = true; 457 convertRecurse[c]++; 458 } 459 exitConvert(int c, boolean isBuffered)460 private void exitConvert(int c, boolean isBuffered) { 461 if (!converting[c]) 462 /* BEGIN JSTYLED */ 463 throw new Error(Global.getMsg("sunsoft.jws.visual.rt.type.Converter.Convert__exit__without.25")); 464 465 if (this.isBuffered[c] != isBuffered) 466 throw new Error(Global.getMsg("sunsoft.jws.visual.rt.type.Converter.isBuffered__mismatch__.26")); 467 468 /* END JSTYLED */ 469 convertRecurse[c]--; 470 if (convertRecurse[c] == 0) 471 converting[c] = false; 472 } 473 /* BEGIN JSTYLED */ 474 // ------ Utility Functions ---------------------------------------------- 475 476 /** 477 * Returns a string that can be used as a newline. 478 * This string includes 479 * a carriage return if we are running on Windows. 480 */ 481 /* END JSTYLED */ newline()482 public static String newline() { 483 return Global.newline(); 484 } 485 486 /** 487 * Appends a newline to buf. This also appends a carriage return 488 * if we are running on Windows. 489 */ newline(StringBuffer buf)490 public static void newline(StringBuffer buf) { 491 Global.newline(buf); 492 } 493 494 private static final String indentString = /* NOI18N */" "; 495 private static int indentLevel = 0; 496 497 /** 498 * Appends spaces to "buf" based on the current indent level. 499 */ indent(StringBuffer buf)500 protected static void indent(StringBuffer buf) { 501 for (int i = 0; i < indentLevel; i++) 502 buf.append(indentString); 503 } 504 505 /** 506 * Appends spaces to "buf" based on the given indent level. 507 */ indent(StringBuffer buf, int indentLevel)508 protected static void indent(StringBuffer buf, int indentLevel) { 509 for (int i = 0; i < indentLevel; i++) 510 buf.append(/* NOI18N */ ' '); 511 } 512 513 /** 514 * Increments the indent level. 515 */ incrIndent()516 protected static void incrIndent() { 517 indentLevel++; 518 } 519 520 /** 521 * Decrements the indent level. 522 */ decrIndent()523 protected static void decrIndent() { 524 indentLevel--; 525 } 526 527 /** 528 * Returns the current indent level. 529 */ indentLevel()530 protected static int indentLevel() { 531 return indentLevel; 532 } 533 534 /** 535 * Returns the last token in a class name. i.e. the name that you 536 * can use for a class when you've imported the class already. 537 */ shortClassName(String className)538 public static String shortClassName(String className) { 539 int index = className.lastIndexOf(/* NOI18N */ '.'); 540 if (index == -1) 541 return (className); 542 else 543 return (className.substring(index + 1)); 544 } 545 546 } 547