/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * ident "%Z%%M% %I% %E% SMI" * * Copyright (c) 2000 by Sun Microsystems, Inc. * All rights reserved. */ /* * Copyright (C) 1996 Active Software, Inc. * All rights reserved. * * @(#) Group.java 1.143 - last change made 07/25/97 */ package sunsoft.jws.visual.rt.base; import sunsoft.jws.visual.rt.awt.RootFrame; import sunsoft.jws.visual.rt.shadow.*; import sunsoft.jws.visual.rt.shadow.java.awt.*; import sunsoft.jws.visual.rt.type.Converter; import sunsoft.jws.visual.rt.type.AMConverter; import sunsoft.jws.visual.rt.type.AMRef; import sunsoft.jws.visual.rt.base.Global; import java.awt.*; import java.util.*; import java.net.URL; import java.applet.Applet; /** * The base class for every kind of group. *
* The attributes available for this * class are listed below. In the type column, type names beginning * with "sunsoft.jws.visual.rt" have been abbreviated to begin * with "rt". * *
* name type default value * --------------------------------------------------------------- * visible java.lang.Boolean true * < /pre> * * Check the super class for additional attributes. * * @version 1.143, 07/25/97 */ public abstract class Group extends AttributeManager { // Print the warning message only once. private boolean warned = false; /** * This flag is used to detect when showGroup is called * recursively during create. * We don't want to execute the showGroup code twice * because modal dialogs block during "show". * This means that if * show is called twice, the modal dialog will pop up * again after it is hidden. */ private boolean doingShow = false; /** * This flag indicates whether or not the group is * currently shown. */ private boolean isShowing = false; /** * This flag is set for forwarded attributes in a group. */ public static final int FORWARD = 0x100; /** * This flag is set for forwarded attributes that will * be removed during initialization if the group's * container does not define the attribute. */ public static final int FORWARD_REMOVE = 0x200; /** * This constant can be passed to the setCursor call. * It indicates * that the cursor should be restored to its previous value. */ public static final int RESTORE_CURSOR = 50000; public static final int BACKSPACE_KEY = 8; public static final int TAB_KEY = 9; public static final int RETURN_KEY = 10; public static final int ESCAPE_KEY = 27; public static final int DELETE_KEY = 127; // The root of the shadow tree. private Root root; /** * Set to true when this group is initialized. */ private boolean isInitialized; /** * Set to true when this group has been started, but * has not yet been stopped. */ private boolean isStarted = false; /** * Parent group for this group. */ private Group parentGroup = null; private Vector children = new Vector(); // Operations private Vector operations = null; /** * Time Bomb */ private void checkDate() { // August 1, 1996 : 838882801 // August 15, 1996 : 840092401 // October 15, 1996 : 845362801 Date date = new Date(840092401000L); if (System.currentTimeMillis() >= 840092401000L) { throw new Error(Global.getMsg( "sunsoft.jws.visual.rt.base.Group.ExpiredVersion")); } else if (!warned) { warned = true; System.out.println(Global.fmtMsg( "sunsoft.jws.visual.rt.base.Group.ExpiredVersionDate", date.toString())); } } // NOTE: Any changes made to this comment should also // be made in the lib/visual/gen/group.java file. /** * All the attributes used by this group must be defined in the * constructor. setOnGroup is called at initialization for all * the attributes. If the attribute has not been set prior to * initialization, setOnGroup is called with the default value. */ public Group() { // The "visible" attribute MUST have the DEFAULT // flag set! We don't want "visible" // being set during initialization. attributes.add(/* NOI18N */"visible", /* NOI18N */"java.lang.Boolean", Boolean.TRUE, DEFAULT); } /** * Initialize the group. The shadow tree for the group * is created during initialization. */ public void initialize() { boolean wasInitialized = isInitialized; if (!isInitialized) { if (!hasEnvironment()) { throw new Error(Global.getMsg( "sunsoft.jws.visual.rt.base.Group.GroupInitializationWarning")); } isInitialized = true; /** * AMREF: We could have started a recording of all * new AMRef's * here, but it's a performance hit that doesn't buy us * anything, the user shouldn't be making AMRef's * that point to * an object by a certain name, changing the name * of that object, and expecting it to work. * The stopRecording call * further down goes with this call. */ // AMRef.startRecording(); root = initRoot(); if (root == null && !(this instanceof NVGroup)) throw new Error(Global.fmtMsg( "sunsoft.jws.visual.rt.base.Group.RootIsNull", this.getClass().getName())); /** AMREF: resolves all AMRef's loaded */ // AMRef.stopRecording(root); removeForwardedAttributes(); initGroup(); if (operations != null) { Enumeration e = operations.elements(); while (e.hasMoreElements()) { Operations ops = (Operations)e.nextElement(); ops.setRoot(root); } } } // Initialize the visible sub-groups Enumeration e = getChildList(); while (e.hasMoreElements()) { Group child = (Group)e.nextElement(); if (wouldBeVisible(child)) child.initialize(); } if (!wasInitialized) { // Set attributes on the newly initialized group e = attributes.elements(); while (e.hasMoreElements()) { Attribute a = (Attribute) e.nextElement(); String name = a.getName(); if (a.isModified() || !a.flagged(DEFAULT | READONLY)) { set(name, a.getValue()); } } if (isLayoutMode()) { WindowShadow s = getWindow(); if (s != null) s.setLayout(true); } } } /** * Returns true if the group is currently initialized. */ public boolean isInitialized() { return isInitialized; } // NOTE: Any changes made to this comment should // also be made in the // lib/visual/gen/group.java file. /** * initRoot must be overridden in group subclasses to * initialize the shadow tree. The return value must be the * root of the newly initialized shadow tree. */ protected abstract Root initRoot(); // NOTE: Any changes made to this comment should // also be made in the // lib/visual/gen/group.java file. /** * Called during initialization. It is called just after * initRoot is called, but before the sub-groups * are initialized and * before the attributes are sent to the setOnGroup method. * * initGroup is only called once in the lifetime of the Group. * This is because groups cannot be uninitialized. * Anything that * needs to be cleaned up should be created in * createGroup instead * of initGroup, and then can be cleaned up in destroyGroup. * createGroup and destroyGroup may be called multiple * times during * the lifetime of a group. */ protected void initGroup() {}; /** * Returns a type name for this group to be used by visual java. * May be overridden in sub-classes to give more useful names. */ protected String getUserTypeName() { return (Converter.shortClassName(getClass().getName()).toLowerCase()); } /** * Returns the main container for this group. This can * be either a WindowShadow or a PanelShadow. */ public ContainerShadow getContainer() { if (root == null) return null; AttributeManager mgr = root.getMainChild(); if (mgr == null) return null; else if (mgr instanceof ContainerShadow) return (ContainerShadow)mgr; else if (mgr instanceof Group) return ((Group)mgr).getContainer(); else throw new Error(Global.fmtMsg( "sunsoft.jws.visual.rt.base.Group.UnexpectedMainChildType", mgr)); } /** * Returns the main panel for this group. Returns * null if the main container is not a panel. */ public PanelShadow getPanel() { ContainerShadow c = getContainer(); if (c instanceof PanelShadow) return (PanelShadow)c; else return null; } /** * Returns the main window for this group. Returns * null if the main container is not a window. */ public WindowShadow getWindow() { ContainerShadow c = getContainer(); if (c instanceof WindowShadow) return (WindowShadow)c; else return null; } /** * Calls show or hide, depending on the value of cond. */ public void show(boolean cond) { if (cond) show(); else hide(); } /** * Shows the group by setting the visible attribute to true. */ public void show() { set(/* NOI18N */"visible", Boolean.TRUE); } /** * Hides the group by setting the visible attribute to false. */ public void hide() { set(/* NOI18N */"visible", Boolean.FALSE); } /** * Returns true if the group is currently visible. * * If the application has not yet been fully initialized * and created, * then isVisible may return true for a group that is not yet * visible on the screen. This means that by the time the * initialization is complete, the group will be visible * on the screen. */ public boolean isVisible() { Group base = getBase(); if (base == null) return false; else return base.wouldBeVisible(this); } /** * Returns true if the child group passed as a parameter * will be visible * when this group is made visible. If the group parameter * is not a * child of this group, then the return value will be false. */ public boolean wouldBeVisible(Group group) { while (group != null && group != this) { Boolean v = (Boolean)group.get(/* NOI18N */"visible"); if (!v.booleanValue()) return false; AttributeManager mgr = (AttributeManager)group.getParent(); while (!(mgr instanceof Root)) { v = (Boolean)mgr.get(/* NOI18N */"visible"); if (!v.booleanValue()) return false; mgr = (AttributeManager)mgr.getParent(); } if (mgr == null) return false; group = ((Root)mgr).getGroup(); } if (group == null) return false; return true; } /** * Returns true if the group is currently showing. */ public boolean isShowing() { return isShowing; } /** * The only reason that this method exists if because * the FrameEditor * bypasses the visible attribute, and calls internalShowGroup * directly. This means that the group becomes visible * even though * the visible attribute is set to false. In this situation, we * still want the isVisible call for child groups to * return true, * hence the need for the isContainerVisible method. */ private boolean isContainerVisible() { if (inDesignerRoot()) { ComponentShadow s = getContainer(); if (s == null) return false; Component comp = (Component)s.getBody(); if (comp == null) return false; return comp.isVisible(); } else { return false; } } // NOTE: Any changes made to this comment should also // be made in the // lib/visual/gen/group.java file. /** * May be overridden by group subclasses that want * to know when the group becomes visible. * It is called just before * the group becomes visible. * The group will already be initialized * and created at this point. */ protected void showGroup() { } /** * Shows the group. Calling internalShowGroup does * not affect the * value of the visible attribute. */ void internalShowGroup() { Group base = null; // Initialize ourselves if we haven't been initialized yet if (!isInitialized) { base = getBase(); if (base != null) base.setCursor(Frame.WAIT_CURSOR); initialize(); } // Create ourselves if we haven't been created yet if (!isCreated) { doingShow = true; create(); doingShow = false; } if (!isShowing) { isShowing = true; if (root != null) showGroup(); // showGroup might call hide (trust me, it can happen) if (!isShowing) return; } // // Invoke "show" on all the child groups that // are not directly // descended from the root. This solves two problems: // // 1) Panel groups are not immediate children of the root, // therefore showRoot does not show the panel groups. // // 2) Some of the groups may not yet be created due // to delayed // instantiation. Calling internalShowGroup // on these groups // will cause them to be initialized and created, as well as // shown. For example, say that this group was created while // its visible attribute was set to false. This means that // none of its child groups would be created because // isVisible // would return false for them. // Now say that visibile is set // to true for this group, causing internalShowGroup to be // called. At this point, the child groups need to be // initialized, created and shown, because now // isVisible will // return true for them. // // Note that this needs to be done before the call // to showRoot. // This is because panel groups must be created // before the frames // that contain them are shown in showRoot,or else the frame // will come up the wrong size. // Enumeration e = children.elements(); while (e.hasMoreElements()) { Group child = (Group)e.nextElement(); if (wouldBeVisible(child) && child.getParent() != root) child.internalShowGroup(); } // Invoke "show" on all the children of the root if (root != null) root.showRoot(); // Start the group if it isn't already started if (hasStarted() && !isStarted) start(); // Revert the cursor if (base != null) base.setCursor(RESTORE_CURSOR); } // NOTE: Any changes made to this comment should // also be made in the // lib/visual/gen/group.java file. /** * May be overridden by group subclasses that want * to know when the group becomes non-visible. * It is called just * before the group becomes non-visible. */ protected void hideGroup() { } /** * Hides the group. Calling hideGroup does not affect the * value of the visible attribute. * You should normally use "hide" * instead of "hideGroup" so that the visible attribute is * properly * updated. */ void internalHideGroup() { if (!isInitialized) return; if (isShowing) { isShowing = false; if (root != null) hideGroup(); } // Invoke "hide" on all the child groups Enumeration e = children.elements(); while (e.hasMoreElements()) { Group group = (Group)e.nextElement(); if (group.getParent() != root) group.internalHideGroup(); } // Invoke "hide" on all the children of the root if (root != null) root.hideRoot(); } // // Create and Destroy - Life span of the shadow bodies // /** * Create the group. Creating the group causes * all the AWT components * to be created. Also, the createGroup method is called during * group creation. */ public void create() { // Initialize ourselves if we haven't been initialized yet if (!isInitialized) initialize(); if (!hasBase()) { throw new Error(Global.getMsg( "sunsoft.jws.visual.rt.base.Group.GroupCreationWarning")); } boolean wasCreated = isCreated; boolean tmpShow = doingShow; boolean shouldShow = false; if (!wasCreated && !doingShow() && isVisible()) { // Set the doingShow flag to true so that the windows // under the // root will not show while they are being created. // We want to // have them wait to be shown until internalShowGroup // is called. doingShow = true; shouldShow = true; } super.create(); if (root == null && !(this instanceof NVGroup)) throw new Error(Global.getMsg( "sunsoft.jws.visual.rt.base.Group.RootIsNull2")); if (root != null) root.create(); if (!wasCreated) { createGroup(); // Show the group if it is visible if (shouldShow) internalShowGroup(); } doingShow = tmpShow; } // NOTE: Any changes made to this comment should // also be made in the // lib/visual/gen/group.java file. /** * Called during group creation. Groups can be * created and destroyed multiple times during their lifetime. * Anything that is created in createGroup should be cleaned up * in destroyGroup. createGroup is called just after the group * has been created. Anything that needs to be done before the * group is created should be done in initGroup. */ protected void createGroup() {} /** * Destroy the group. This will destroy all AWT components, but * does not destroy the shadow tree or the group tree. The group * can be created again after a destroy by calling the "create" * method. */ public void destroy() { if (!isInitialized) return; stop(); if (isCreated) destroyGroup(); super.destroy(); if (root != null) root.destroy(); } // NOTE: Any changes made to this comment should also // be made in the // lib/visual/gen/group.java file. /** * Called during the destroy operation. Groups can * be created and destroyed multiple times during their * lifetime. * Anything that has been created in createGroup should be * cleaned up * in destroyGroup. destroyGroup is called just before the * group * is destroyed. */ protected void destroyGroup() {} // // start/stop // /** * This method should not be overridden by group subclasses. * The "startGroup" method should be overridden instead. */ public void start() { if (!isInitialized) return; if (!isCreated) create(); if (!isStarted) { isStarted = true; startGroup(); } Enumeration e = children.elements(); while (e.hasMoreElements()) { Group child = (Group)e.nextElement(); if (wouldBeVisible(child)) child.start(); } } // NOTE: Any changes made to this comment should also // be made in the // lib/visual/gen/group.java file. /** * May be overridden by group subclasses that want * to be informed when the application is starting. * This method is * only called after the entire application has been * initialized and created. * * For applets, startGroup is called whenever start * is called on the applet. */ protected void startGroup() {} /** * Returns true if the group is currently started. */ public boolean isStarted() { return isStarted; } /** * This method should not be overridden by group subclasses. * The "stopGroup" method should be overridden instead. */ public void stop() { if (!isInitialized) return; if (isStarted) { isStarted = false; stopGroup(); } Enumeration e = children.elements(); while (e.hasMoreElements()) ((Group)e.nextElement()).stop(); } // NOTE: Any changes made to this comment should also // be made in the // lib/visual/gen/group.java file. /** * May be overridden by group subclasses that want * to be informed when the application is stopping. This method * will be called before a destroy is done. * * For applets, stopGroup is called whenever stop is called * on the applet. */ protected void stopGroup() {} /** * Returns true if the base group has been started. */ protected boolean hasStarted() { if (isBase()) { return isStarted; } else if (parentGroup != null) { return parentGroup.hasStarted(); } else { return false; } } // // Group tree - An group can be either a node or a leaf. // void add(Group child) { if (!children.contains(child)) { child.setParentGroup(this); children.addElement(child); } } void remove(Group child) { if (children.contains(child)) { child.setParentGroup(null); children.removeElement(child); } } void addRootChildren(Root root) { addChildren((AMContainer)root); } private void addChildren(AMContainer cntr) { Enumeration e = cntr.getChildList(); while (e.hasMoreElements()) { AttributeManager child = (AttributeManager)e.nextElement(); if (child instanceof Group) add((Group)child); if (child instanceof AMContainer) addChildren((AMContainer)child); } } void removeRootChildren(Root root) { Enumeration e = children.elements(); while (e.hasMoreElements()) { Group child = (Group)e.nextElement(); if (child.getRoot() == root) remove(child); } } /** * Looks up a named child group of this group. Not recursive. */ public Group getChild(String name) { for (Enumeration e = children.elements(); e.hasMoreElements(); ) { Group child = (Group)e.nextElement(); if (name.equals(child.get(/* NOI18N */"name"))) return (child); } return (null); } /** * Returns an enumerated list of this group's children. The list * is cloned because the caller might use it for removing child * groups from this group. */ public Enumeration getChildList() { return ((Vector)children.clone()).elements(); } private void setParentGroup(Group parent) { parentGroup = parent; } /** * Returns this group's parent. */ public Group getParentGroup() { return parentGroup; } /** * Returns this group (overrides the behavior of getGroup * as defined in AttributeManager). */ public Group getGroup() { return this; } /** * Returns a hierarchy name based on the group tree. */ public String getFullName() { String name = getName(); if (name == null) return null; if (parentGroup != null) { String parentName = parentGroup.getFullName(); if (parentName != null) name = parentName + /* NOI18N */"." + name; } return name; } /** * Find a component from its full path name. */ public AttributeManager resolveFullName(String name) { AttributeManager mgr = null; Group group = this; Group newGroup; while (group != null && !group.isBase()) group = group.parentGroup; if (group == null) return null; StringTokenizer st = new StringTokenizer(name, /* NOI18N */"."); if (group.getName() != null) { if (!st.hasMoreTokens()) return null; name = st.nextToken(); if (!name.equals(group.getName())) return null; } while (st.hasMoreTokens()) { name = st.nextToken(); newGroup = group.resolveGroup(name); if (newGroup == null) { if (group.root == null) return null; mgr = group.root.resolve(name); break; } else { group = newGroup; } } if (st.hasMoreTokens()) return null; return mgr; } /** * Recursively looks for a named sub-group of this group. */ public Group resolveGroup(String name) { Group group; String groupName; Enumeration e = children.elements(); while (e.hasMoreElements()) { group = (Group)e.nextElement(); groupName = group.getName(); if (groupName != null && groupName.equals(name)) { return group; } } return null; } // // AWT parenting // void setParentBody() { if (root != null) root.addChildBody(getContainer()); } void unsetParentBody() { if (root != null) root.removeChildBody(getContainer()); } /** * Add an operations class. */ public synchronized void addOperations(Operations ops) { if (operations == null) operations = new Vector(); if (!operations.contains(ops)) { ops.setGroup(this); if (root != null) ops.setRoot(root); operations.addElement(ops); } } /** * Remove an operations class. */ public synchronized void removeOperations(Operations ops) { if (operations != null) operations.removeElement(ops); } // // Events // /** * Posts a message to this group's parent. This method should * be used when sending a message from within this group. */ public void postMessageToParent(Message msg) { if (parentGroup != null) parentGroup.postMessage(msg); } /** * Posts a message to this group. This method should * be used when sending a message to this group. */ public void postMessage(Message msg) { // Distribute the message to the operations classes if (operations != null) { Enumeration e = operations.elements(); while (e.hasMoreElements()) { Operations ops = (Operations)e.nextElement(); if (ops.handleMessage(msg)) return; } } // Handle the message if (handleMessage(msg)) return; // Don't pass AWT events up to the parent. If you want // an AWT event // to go to the parent group, call // "parent.postEvent()" directly. if (!msg.isAWT && parentGroup != null) parentGroup.postMessage(msg); } // NOTE: Any changes made to this comment should also be // made in the // lib/visual/gen/group.java file. /** * May be overridden by subclasses that want to act * on messages that are sent to the group. * Typically, messages are * either AWT events that have been translated to * messages, or they * are messages that have been sent by other groups. * super.handleMessage should be called for any messages * that aren't handled. If super.handleMessage is not * called, then handleEvent * will not be called. ** AWT events are not propagated regardless of the return * value from * handleEvent. If you want an AWT event to go to the parent * group, you need to call postMessageToParent() * with the event message. *
*/ public boolean handleMessage(Message msg) { if (msg.isAWT) { Event evt = (Event)msg.arg; handleEvent(msg, evt); // Post AcceleratorKey messages for certain keys if (evt.id == Event.KEY_PRESS && evt.key != 0 && (evt.key < 32 || evt.key >= 127)) { postMessage(new Message(this, /* NOI18N */"AcceleratorKey", evt)); } return true; } return false; } // NOTE: Any changes made to this comment should also be // made in the // lib/visual/gen/group.java file. /** * May be overridden by subclasses that want to get * notified when AWT events that are sent by the gui components. * The return value should be true for handled events, and * super.handleEvent should be called for unhandled events. * If super.handleEvent is not called, then the specific event * handling methods will not be called. *
* The message's target is set to the shadow that sent * the event. * The event's target is set to the AWT component that * sent the event. *
* The following more specific methods may also be overridden: *
* public boolean mouseDown(Message msg, * Event evt, int x, int y); * public boolean mouseDrag(Message msg, Event evt, * int x, int y); * public boolean mouseUp(Message msg, Event evt, int x, int y); * public boolean mouseMove(Message msg, Event evt, * int x, int y); * public boolean mouseEnter(Message msg, Event evt, * int x, int y); * public boolean mouseExit(Message msg, Event evt, * int x, int y); * public boolean keyDown(Message msg, Event evt, int key); * public boolean keyUp(Message msg, Event evt, int key); * public boolean action(Message msg, Event evt, Object what); * public boolean gotFocus(Message msg, Event evt, Object what); * public boolean lostFocus(Message msg, * Event evt, Object what); **/ public boolean handleEvent(Message msg, Event evt) { if (super.handleEvent(msg, evt)) return true; // Intercept some of the WINDOW events. // Sub-groups that want to do // something different with these WINDOW events // should return true // after handling the event. switch (evt.id) { case Event.WINDOW_DESTROY: windowDestroy(msg); return true; case Event.WINDOW_ICONIFY: if (evt.target instanceof Window) { if (isBaseWindow((Window)evt.target)) { hide(); return true; } } return false; case Event.WINDOW_DEICONIFY: if (evt.target instanceof Window) { if (isBaseWindow((Window)evt.target)) { show(); return true; } } return false; } return false; } /** * Exit the application with no error code. */ public void exit() { exit(0); } /** * Exit the application. Calls exit on the parent * if there is a parent. * Only calls System.exit() if there is no applet. */ public void exit(int errCode) { if (isBase()) { destroy(); if (applet == null) System.exit(errCode); } else if (parentGroup != null) { parentGroup.exit(errCode); } else { destroy(); } } /** * Called when a WINDOW_DESTROY event is received by this group. * The default behavior for WINDOW_DESTROY events is to * set the visible * attribute to false for the target of the event. * If the target of * the event is the main window, then set this group's * visible attribute * to false. If this group is the base group, then exit the * application. */ protected void windowDestroy(Message msg) { if (msg.target == getContainer()) { if (inDesignerRoot()) internalHideGroup(); else if (isBase()) exit(); else hide(); } else { if (msg.target instanceof AttributeManager) ((AttributeManager)msg.target).set(/* NOI18N */"visible", Boolean.FALSE); else if (msg.target instanceof Component) ((Component)msg.target).hide(); } } /** * Attribute forwarding */ private Vector forwardVector = new Vector(); /** * Adds the attribute manager to the list of forwards. When * an attribute is set and is flagged FORWARD, the value for the * attribute will be forwarded to every matching attribute * manager * in the list of forwards. */ protected void addAttributeForward(AttributeManager mgr) { if (forwardVector.contains(mgr)) return; // Add this guy to the list of attribute forwards forwardVector.addElement(mgr); // Override values in mgr with values from forwards Enumeration e = attributes.attributesWithFlags(FORWARD); while (e.hasMoreElements()) { Attribute attr = (Attribute)e.nextElement(); String name = attr.getName(); String type = attr.getType(); if (mgr.hasAttribute(name, type)) { Object value = mgr.get(name); if (!attr.flagged(READONLY)) { if (!attr.isModified()) putInTable(name, value); else if (!mgr.getAttribute(name).flagged(READONLY)) mgr.set(name, attr.getValue()); } attr.setDefaultValue(value); } } } /** * Adds a set of attributes to this group that * are suitable for forwarding to a frame, dialog or panel. */ protected void addForwardedAttributes() { if (genericAttrList == null) { genericAttrList = new AttributeList(); mergeForward(genericAttrList, new VJPanelShadow()); mergeForward(genericAttrList, new FrameShadow()); mergeForward(genericAttrList, new DialogShadow()); } Enumeration e = genericAttrList.elements(); while (e.hasMoreElements()) { Attribute attr = (Attribute)e.nextElement(); if (!hasAttribute(attr.getName())) attributes.add((Attribute)attr.clone()); } if (!hasAttribute(/* NOI18N */"text")) attributes.alias(/* NOI18N */"text", /* NOI18N */"title"); } private void mergeForward(AttributeList list, Shadow shadow) { AttributeList shadowList = (AttributeList)shadow.getAttributeList().clone(); Enumeration e = shadowList.elements(); while (e.hasMoreElements()) { Attribute attr = (Attribute)e.nextElement(); if (!list.contains(attr.getName())) { // System.out.println(/* NOI18N */"add " + // attr.getName() + /* NOI18N */" " + attr.getType()); attr.addFlags(FORWARD | FORWARD_REMOVE); list.add(attr); } } } private void removeForwardedAttributes() { ContainerShadow cntr = getContainer(); if (cntr == null) return; Enumeration e = attributes.attributesWithFlags(FORWARD_REMOVE); while (e.hasMoreElements()) { Attribute attr = (Attribute)e.nextElement(); if (!cntr.hasAttribute(attr.getName())) { attributes.remove(attr.getName()); } } } /** * Return true if we are forwarding the attribute "attrName" * to "mgr", * otherwise return false. */ boolean hasAttributeForward(AttributeManager mgr, String attrName) { return (forwardVector.contains(mgr) && attributes.get(attrName).flagged(FORWARD)); } /** * These are helper routines for the group. * If you are fowarding * attributes to a component, dialog or frame, you should call * one of these methods in the constructor. */ private static AttributeList genericAttrList = null; /** * Compatibility method - do not use! */ protected void addComponentAttributes() { addForwardedAttributes(); } /** * Compatibility method - do not use! */ protected void addPanelAttributes() { addForwardedAttributes(); } /** * Compatibility method - do not use! */ protected void addFrameAttributes() { addForwardedAttributes(); } /** * Compatibility method - do not use! */ protected void addDialogAttributes() { addForwardedAttributes(); } // // Attributes - get and set // /** * Get the value of a named attribute. */ public Object get(String key) { Attribute attr = attributes.get(key); if (key.equals(/* NOI18N */"name")) { return super.get(key); } else if (key.equals(/* NOI18N */"visible")) { return super.get(key); } else if (!isInitialized) { return super.get(key); } else if (attr != null && attr.flagged(FORWARD)) { Enumeration e = forwardVector.elements(); AttributeManager mgr; while (e.hasMoreElements()) { mgr = (AttributeManager)e.nextElement(); if (mgr.hasAttribute(key, attr.getType())) { return mgr.get(key); } } return null; } else { return getOnGroup(key); } } // NOTE: Any changes made to this comment should also // be made in the // lib/visual/gen/group.java file. /** * May be overridden by sub-groups that * store attribute values themselves, and do not depend on the * group superclass to store them. * This method should be overridden * instead of "get". Any attributes handled in setOnGroup where * super.setOnGroup is not called must also be handled * in getOnGroup. ** The default implementation of getOnGroup retrieves the value * from the attribute table. *
* The reason that "getOnGroup" should be overridden instead * of "get" is that "getOnGroup" is guaranteed not to be called * until the group class is initialized. * This means that initRoot * will always be called before any calls to getOnGroup * are made. *
* Also, this method is only for attributes that are defined * in the * sub-groups. It is not called for forwarded attributes. *
*/ protected Object getOnGroup(String key) { return super.get(key); } /** * Set the value of a named attribute. */ public void set(String key, Object value) { Attribute attr = attributes.get(key); if (key.equals(/* NOI18N */"name")) { super.set(key, value); } else if (key.equals(/* NOI18N */"visible")) { super.set(key, value); if (((Boolean)value).booleanValue()) { if (isVisible()) internalShowGroup(); } else internalHideGroup(); } else if (!isInitialized) { super.set(key, value); } else if (attr != null && attr.flagged(FORWARD)) { super.set(key, value); Enumeration e = forwardVector.elements(); AttributeManager mgr; boolean set = false; while (e.hasMoreElements()) { mgr = (AttributeManager)e.nextElement(); if (mgr.hasAttribute(key, attr.getType())) { mgr.set(key, value); set = true; } } if (set) { // update the the global register for unsaved changes if (inDesignerRoot()) DesignerAccess.setChangesMade(true); } } else { setOnGroup(key, value); } } // NOTE: Any changes made to this comment should also // be made in the // lib/visual/gen/group.java file. /** * May be overridden by sub-groups that * want notification when attributes are changed. This method * should be overridden instead of "set". * Any attributes handled * in setOnGroup where super.setOnGroup is not called * must also be * handled in getOnGroup. *
* The default implementation of setOnGroup puts the value * in the attribute table. *
* The reason that "setOnGroup" should be overridden instead * of "set" is that "setOnGroup" is guaranteed not to be called * until the group class is initialized. * This means that initRoot * will always be called before any calls to setOnGroup * are made. *
* During initialization, "setOnGroup" will be called for all * the group's attributes even if they have not be changed from * the default value. But for attributes that have the DEFAULT * flag set, "setOnGroup" will only be called if the value * of the attribute has changed from the default. *
* Also, this method is only called when attributes defined * in the * sub-groups are updated. It is not called for forwarded * attributes. *
*/ protected void setOnGroup(String key, Object value) { super.set(key, value); } /** * Base group information. */ private Applet applet = null; private String cmdLineArgs[]; private Frame topLevel = null; private Registry registry = null; private boolean hasEnvironment = false; private boolean hasEnvironment() { if (hasEnvironment) return true; else if (parentGroup != null) return parentGroup.hasEnvironment(); else return false; } /** * Returns true if this group is the base group. */ public boolean isBase() { return hasEnvironment; } /** * Returns true if the given window this group's base window. */ protected boolean isBaseWindow(Window win) { WindowShadow shadow = (WindowShadow)DesignerAccess.getShadowTable().get(win); return (isBase() && (getWindow() == shadow)); } /** * Returns true if this group is either the base group * or is a descendant * of the base group. */ public boolean hasBase() { if (hasEnvironment) return true; else if (parentGroup != null) return parentGroup.hasBase(); else return false; } /** * Returns the base group. */ public Group getBase() { if (hasEnvironment) return this; else if (parentGroup != null) return parentGroup.getBase(); else return null; } /** * Returns true if we are doing a create operation in the * middle of a show operation. Create likes to call show if the * visible attribute is set to true, but create shouldn't call * show if show caused create to be called if the first place. */ boolean doingShow() { if (doingShow) return true; else if (parentGroup != null) return parentGroup.doingShow(); else return false; } /** * Sets the environment information for the group. * This method should * be invoked only on the top-most group in the application. * Invoking * setEnvironmentInfo and setTopLevel on a group makes * it the base group. */ public void setEnvironmentInfo(Applet applet, String args[]) { // checkDate(); this.applet = applet; this.cmdLineArgs = args; hasEnvironment = true; } /** * Sets the top level frame for the group. This method should * be invoked only on the top most group in the application. * Invoking setEnvironmentInfo and setTopLevel on a group * makes it * the base group. */ public void setTopLevel(Frame topLevel) { this.topLevel = topLevel; } /** * Sets the cursor for all of the group's frames to the given * cursor value. Calls setCursor on all the child groups. */ public void setCursor(int cursor) { if (root != null) root.setCursor(cursor); Enumeration e = children.elements(); while (e.hasMoreElements()) { Group child = (Group)e.nextElement(); child.setCursor(cursor); } } /** * Accessor method for the applet. Null is returned * when you're not * running as an applet. */ public Applet getApplet() { if (applet != null) return applet; else if (parentGroup != null) return parentGroup.getApplet(); else return null; } /** * Accessor method for the command line arguments. * Null is returned * when you're not running from the command line. */ public String[] getCmdLineArgs() { if (cmdLineArgs != null) return cmdLineArgs; else if (parentGroup != null) return parentGroup.getCmdLineArgs(); else return null; } /** * Returns the first frame found while traversing up the * group tree. If no frame is found, then the top level * frame is returned. */ public Frame getFrame() { WindowShadow win = getWindow(); if (win != null && win.getBody() != null) { if (win instanceof DialogShadow) return (Frame)((Window) win.getBody()).getParent(); else return (Frame)win.getBody(); } else if (parentGroup != null) return parentGroup.getFrame(); else return getTopLevel(); } /** * Accessor method for the top level frame. This will not * return null providing that the base group has been * initialized properly. */ public Frame getTopLevel() { if (topLevel != null) return topLevel; else if (parentGroup != null) return parentGroup.getTopLevel(); else return null; } /** * Accessor method for the registry. The registry is * created when * the application starts. */ public Registry getRegistry() { if (isBase()) { initRegistry(); return registry; } else if (parentGroup != null) return parentGroup.getRegistry(); else return null; } private synchronized void initRegistry() { if (registry == null) registry = new Registry(); } public void layoutMode() { super.layoutMode(); WindowShadow s = getWindow(); if (s != null) s.setLayout(true); } public void previewMode() { super.previewMode(); WindowShadow s = getWindow(); if (s != null) s.setPreview(true); } protected void preValidate() { PanelShadow panel = getPanel(); if (panel != null) panel.preValidate(); } }