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 * @(#) Shadow.java 1.89 - last change made 07/25/97 34 */ 35 36 package sunsoft.jws.visual.rt.base; 37 38 import java.util.Enumeration; 39 import java.util.StringTokenizer; 40 41 /** 42 * This class implements the basic interfaces 43 * that Visual Java requires 44 * for its visual components. Objects that wish to be added to 45 * the Visual Java palette must be sub-classed from Shadow. 46 * <p> 47 * The attributes this class adds to an AttributeManager 48 * class are listed below. In the type column, type names beginning 49 * with "sunsoft.jws.visual.rt" have been abbreviated to begin 50 * with "rt". 51 * 52 * <pre> 53 * name type default value 54 * -------------------------------------------------------------------- 55 * none 56 * < /pre> 57 * 58 * Check the super class for additional attributes. 59 * 60 * @version 1.89, 07/25/97 61 */ 62 public class Shadow extends AttributeManager { 63 /** 64 * Flags 65 */ 66 67 /** 68 * When this flag is set, a provision must be made in order 69 * to set 70 * the attribute in the body's constructor. It is up to the 71 * caller to call 72 * recreate on the shadow and validate on the shadow's 73 * parent after 74 * a constructor attribute has been set. 75 */ 76 public static final int CONSTRUCTOR = 0x40; 77 78 /** 79 * This flag signifies that the attribute has nothing to 80 * do with a shadow 'body' and therefore 81 * <a href="sunsoft.jws.visual.rt.base.Shadow.html 82 * #getOnBody(java.lang.String)">getOnBody</a> and 83 * <a href="sunsoft.jws.visual.rt.base.Shadow.html 84 * #setOnBody(java.lang.String, java.lang.Object)">setOnBody</a> 85 * will not be called for this attribute. 86 */ 87 public static final int NONBODY = 0x80; 88 89 /** 90 * Constructor 91 */ Shadow()92 public Shadow() { 93 super(); 94 } 95 96 /** 97 * The AWT component for this shadow. 98 */ 99 protected Object body; 100 101 /** 102 * Returns the AWT component for this shadow. 103 * The return value is of 104 * type Object, therefore the caller must do a cast to the 105 * appropriate AWT component type. 106 */ getBody()107 public Object getBody() { 108 return (body); 109 } 110 111 /** 112 * Returns a type name suitable for use in naming instances of 113 * shadow sub-classes (i.e. names that make sense to a user.) 114 * This 115 * can be overridden in sub-classes to give more useful 116 * names when 117 * this (default) algorithm comes up with something ugly. 118 */ getUserTypeName()119 protected String getUserTypeName() { 120 // get the final word after the last '.' 121 String last = /* NOI18N */"unknown"; 122 StringTokenizer st = new StringTokenizer( 123 getClass().getName(), /* NOI18N */".", false); 124 while (st.hasMoreTokens()) { 125 last = st.nextToken(); 126 } 127 128 // remove "Shadow" from the end of the string 129 int index = last.lastIndexOf(/* NOI18N */"Shadow"); 130 if (index != -1) { 131 last = last.substring(0, index); 132 } 133 134 // always return a lower case word 135 if (last.length() > 0) 136 return (last.toLowerCase()); 137 else 138 return (/* NOI18N */"shadow"); 139 } 140 141 /** 142 * Gets attributes from this shadow's body. 143 * Should be overridden in each sub-class which has its own 144 * attributes. There should be an entry for every 145 * attribute that 146 * doesn't have the NONBODY flag, even if it's just to return 147 * the value from the attribute list when a certain attribute 148 * can't 149 * be looked up from the body. 150 */ getOnBody(String key)151 protected Object getOnBody(String key) { 152 throw new Error(Global.fmtMsg( 153 "sunsoft.jws.visual.rt.base.Shadow.NoSuchKey", key)); 154 } 155 156 /** 157 * Gets an attribute either from the body (if available) 158 * or from the 159 * shadow's attribute list. 160 */ get(String key)161 public Object get(String key) { 162 key = attributes.resolveAlias(key); 163 if (attributes.contains(key)) { 164 Attribute a = attributes.get(key); 165 if (body != null && !a.flagged(NONBODY)) 166 return (getOnBody(key)); 167 else 168 return (a.getValue()); 169 } else { 170 throw new Error(Global.fmtMsg( 171 "sunsoft.jws.visual.rt.base.Shadow.UnknownAttribute", 172 key, getClass().getName())); 173 } 174 } 175 176 /** 177 * Sets attributes on this shadow's body. 178 * Should be overridden in each sub-class which has its own 179 * attributes. There should be an entry for every attribute that 180 * doesn't have the NONBODY flag, even if it's just to set the 181 * value in the attribute list when a certain attribute 182 * can't be set on the body. 183 */ setOnBody(String key, Object value)184 protected void setOnBody(String key, Object value) { 185 throw new Error(Global.fmtMsg( 186 "sunsoft.jws.visual.rt.base.Shadow.NoSuchKey2", key)); 187 } 188 189 /** 190 * Sets an attribute either in the body (if available) or in the 191 * shadow's attribute list. Destroys the body when 192 * a CONSTRUCTOR attribute is set. 193 * It is up to the caller to call 194 * recreate on the shadow and validate on the shadow's 195 * parent after a constructor attribute has been set. 196 */ set(String key, Object value)197 public void set(String key, Object value) { 198 key = attributes.resolveAlias(key); 199 Attribute a = attributes.get(key); 200 if (a == null) 201 throw new Error(Global.fmtMsg( 202 "sunsoft.jws.visual.rt.base.Shadow.InvalidAttributeSet", 203 key)); 204 if (a.flagged(READONLY)) 205 throw new Error(Global.fmtMsg( 206 "sunsoft.jws.visual.rt.base.Shadow.ReadOnlyAttributeSet", 207 key)); 208 209 if (a.flagged(CONSTRUCTOR)) { 210 if (isCreated) { 211 isCreated = false; 212 refetchAttributeList(); 213 unregisterBody(); 214 destroyBody(); 215 if (body != null) 216 throw new Error(Global.getMsg( 217 "sunsoft.jws.visual.rt.base.Shadow.BodyNotDestroyed")); 218 } 219 } 220 221 // Save the previous value 222 Object prev = a.getValue(); 223 a.setValue(value); 224 225 if (body != null && !a.flagged(NONBODY)) { 226 // If setOnBody throws a VJException, then restore 227 // the old value. I couldn't just move the setValue 228 // to be after 229 // setOnBody, because many shadows depend on the value 230 // being set first. 231 try { 232 setOnBody(key, value); 233 } 234 catch (VJException ex) { 235 a.setValue(prev); 236 throw ex; 237 } 238 } 239 240 // update the the global register for unsaved changes 241 if (inDesignerRoot()) 242 DesignerAccess.setChangesMade(true); 243 244 if (parent != null && a.flagged(CONTAINER)) 245 ((AMContainer)parent).updateContainerAttribute(this, 246 key, value); 247 } 248 249 /** 250 * Creates this shadow. 251 * It is safe to call create multiple times on a shadow object. 252 */ create()253 public void create() { 254 if (!isCreated) { 255 isCreated = true; 256 257 if (getGroup() == null || !getGroup().hasBase()) { 258 throw new Error(Global.getMsg( 259 "sunsoft.jws.visual.rt.base.Group.ShadowCreationWarning")); 260 } 261 262 if (body == null) 263 createBody(); 264 if (body == null) 265 throw new Error(Global.getMsg( 266 "sunsoft.jws.visual.rt.base.Group.BodyNotCreated")); 267 268 registerBody(); 269 270 super.create(); 271 if (parent != null && body != null) 272 parent.addChildBody(this); 273 274 postCreate(); 275 } else { 276 super.create(); 277 if (parent != null && body != null) 278 parent.addChildBody(this); 279 } 280 } 281 282 /** 283 * Called just after this shadow has been created. 284 */ postCreate()285 protected void postCreate() {}; 286 287 /** 288 * Creates the AWT component for this shadow. 289 * Sub-classes must override this method. 290 */ createBody()291 public void createBody() {}; 292 293 /** 294 * Registers newly created shadows. 295 * Sub-classes should not override 296 * this method. 297 */ registerBody()298 protected void registerBody() { 299 // Add this shadow's body to the global shadow table. 300 DesignerAccess.getShadowTable().put(body, this); 301 302 // Set attributes on the new body 303 for (Enumeration e = attributes.attributesWithoutFlags( 304 NONBODY|READONLY); 305 /* JSTYLED */ 306 e.hasMoreElements(); ) { 307 Attribute a = (Attribute) e.nextElement(); 308 if (a.isModified() || !a.flagged(DEFAULT)) { 309 setOnBody(a.getName(), a.getValue()); 310 } 311 } 312 313 // System.out.println("Shadow created: " + toString()); 314 } 315 316 /** 317 * Creates this shadow again after a constructor 318 * attribute has been set. 319 */ recreate()320 public void recreate() { 321 if (!isCreated) { 322 isCreated = true; 323 324 createBody(); 325 326 // Reparent the children 327 if (this instanceof AMContainer) 328 ((AMContainer)this).reparentChildren(); 329 330 registerBody(); 331 332 postCreate(); 333 } 334 335 if (parent != null && body != null) 336 parent.addChildBody(this); 337 } 338 339 /** 340 * Destroys this shadow and all its children. 341 */ destroy()342 public void destroy() { 343 if (isCreated) { 344 isCreated = false; 345 346 preDestroy(); 347 348 super.destroy(); 349 350 unregisterBody(); 351 352 destroyBody(); 353 if (body != null) 354 throw new Error(Global.getMsg( 355 "sunsoft.jws.visual.rt.base.Shadow.BodyNotDestroyed")); 356 } else { 357 super.destroy(); 358 } 359 } 360 361 /** 362 * Called during destroy, but before the children are 363 * destroyed. By the time destroyBody is called, all 364 * the children have already been destroyed. 365 */ preDestroy()366 protected void preDestroy() { 367 } 368 369 /** 370 * Destroys the body for this shadow. 371 * Sub-classes are not required to override this method. 372 */ destroyBody()373 protected void destroyBody() { 374 body = null; 375 } 376 377 /** 378 * Unregisters destroyed shadows. Sub-classes should not 379 * override this method. 380 */ unregisterBody()381 protected void unregisterBody() { 382 // remove this shadow's body from its container and from the 383 // global shadow table 384 if (body != null) { 385 if (parent != null && body != null) 386 parent.removeChildBody(this); 387 DesignerAccess.getShadowTable().remove(body); 388 } 389 } 390 toString()391 public String toString() { 392 return (super.toString() + /* NOI18N */"[" 393 + /* NOI18N */"," + /* NOI18N */"body=" + 394 ((body == null) ? /* NOI18N */"null" : body.toString()) 395 + /* NOI18N */"]"); 396 } 397 } 398