0
|
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 "@(#)Converter.java 1.2 05/06/08 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 */
|
|
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 */
|
|
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
|
|
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 */
|
|
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 */
|
|
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 */
|
|
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
|
|
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 */
|
|
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 */
|
|
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 */
|
|
300 protected void setConverterType(String type) {
|
|
301 converterType = type;
|
|
302 }
|
|
303
|
|
304 /**
|
|
305 * Returns the type of object converted by this converter.
|
|
306 */
|
|
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 */
|
|
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 */
|
|
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 */
|
|
353 public abstract Object convertFromString(String s);
|
|
354
|
|
355 /**
|
|
356 * Converts an instance of the type into a block of code.
|
|
357 */
|
|
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 */
|
|
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 */
|
|
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 */
|
|
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 */
|
|
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
|
|
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
|
|
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 */
|
|
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 */
|
|
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 */
|
|
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 */
|
|
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 */
|
|
516 protected static void incrIndent() {
|
|
517 indentLevel++;
|
|
518 }
|
|
519
|
|
520 /**
|
|
521 * Decrements the indent level.
|
|
522 */
|
|
523 protected static void decrIndent() {
|
|
524 indentLevel--;
|
|
525 }
|
|
526
|
|
527 /**
|
|
528 * Returns the current indent level.
|
|
529 */
|
|
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 */
|
|
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 }
|