- /*
- * @(#)Container.java 1.239 03/02/26
- *
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
- package java.awt;
- import java.io.PrintStream;
- import java.io.PrintWriter;
- import java.awt.peer.ContainerPeer;
- import java.awt.peer.ComponentPeer;
- import java.awt.peer.LightweightPeer;
- import java.awt.event.ComponentEvent;
- import java.awt.event.ContainerEvent;
- import java.awt.event.FocusEvent;
- import java.awt.event.HierarchyEvent;
- import java.awt.event.InputEvent;
- import java.awt.event.KeyEvent;
- import java.awt.event.MouseEvent;
- import java.awt.event.MouseWheelEvent;
- import java.awt.event.ContainerListener;
- import java.util.EventListener;
- import java.io.ObjectOutputStream;
- import java.io.ObjectInputStream;
- import java.io.IOException;
- import java.awt.event.AWTEventListener;
- import java.awt.event.WindowAdapter;
- import java.awt.event.WindowListener;
- import java.awt.event.WindowEvent;
- import java.awt.dnd.DropTarget;
- import java.util.HashSet;
- import java.util.LinkedList;
- import java.util.Set;
- import java.util.Iterator;
- import javax.accessibility.*;
- import java.beans.PropertyChangeListener;
- import javax.swing.JRootPane;
- import sun.awt.AppContext;
- import sun.awt.DebugHelper;
- import sun.awt.SunToolkit;
- import sun.awt.dnd.SunDropTargetEvent;
- /**
- * A generic Abstract Window Toolkit(AWT) container object is a component
- * that can contain other AWT components.
- * <p>
- * Components added to a container are tracked in a list. The order
- * of the list will define the components' front-to-back stacking order
- * within the container. If no index is specified when adding a
- * component to a container, it will be added to the end of the list
- * (and hence to the bottom of the stacking order).
- * @version 1.239, 02/26/03
- * @author Arthur van Hoff
- * @author Sami Shaio
- * @see #add(java.awt.Component, int)
- * @see #getComponent(int)
- * @see LayoutManager
- * @since JDK1.0
- */
- public class Container extends Component {
- /**
- * The number of components in this container.
- * This value can be null.
- * @serial
- * @see #getComponent
- * @see #getComponents
- * @see #getComponentCount
- */
- int ncomponents;
- /**
- * The components in this container.
- * @serial
- * @see #add
- * @see #getComponents
- */
- Component component[] = new Component[0];
- /**
- * Layout manager for this container.
- * @serial
- * @see #doLayout
- * @see #setLayout
- * @see #getLayout
- */
- LayoutManager layoutMgr;
- /**
- * Event router for lightweight components. If this container
- * is native, this dispatcher takes care of forwarding and
- * retargeting the events to lightweight components contained
- * (if any).
- * @serial
- */
- private LightweightDispatcher dispatcher;
- /*
- * Internal, cached size information.
- * @serial
- * @see #getMaximumSize
- * @see #getPreferredSize
- */
- private Dimension maxSize;
- /**
- * The focus traversal policy that will manage keyboard traversal of this
- * Container's children, if this Container is a focus cycle root. If the
- * value is null, this Container inherits its policy from its focus-cycle-
- * root ancestor. If all such ancestors of this Container have null
- * policies, then the current KeyboardFocusManager's default policy is
- * used. If the value is non-null, this policy will be inherited by all
- * focus-cycle-root children that have no keyboard-traversal policy of
- * their own (as will, recursively, their focus-cycle-root children).
- * <p>
- * If this Container is not a focus cycle root, the value will be
- * remembered, but will not be used or inherited by this or any other
- * Containers until this Container is made a focus cycle root.
- *
- * @serial
- * @see #setFocusTraversalPolicy
- * @see #getFocusTraversalPolicy
- * @since 1.4
- */
- private transient FocusTraversalPolicy focusTraversalPolicy;
- /**
- * Indicates whether this Component is the root of a focus traversal cycle.
- * Once focus enters a traversal cycle, typically it cannot leave it via
- * focus traversal unless one of the up- or down-cycle keys is pressed.
- * Normal traversal is limited to this Container, and all of this
- * Container's descendants that are not descendants of inferior focus cycle
- * roots.
- *
- * @serial
- * @see #setFocusCycleRoot
- * @see #isFocusCycleRoot
- * @since 1.4
- */
- private boolean focusCycleRoot = false;
- // keeps track of the threads that are printing this component
- private transient Set printingThreads;
- // True if there is at least one thread that's printing this component
- private transient boolean printing = false;
- transient ContainerListener containerListener;
- /* HierarchyListener and HierarchyBoundsListener support */
- transient int listeningChildren;
- transient int listeningBoundsChildren;
- transient int descendantsCount;
- /**
- * JDK 1.1 serialVersionUID
- */
- private static final long serialVersionUID = 4613797578919906343L;
- private static final DebugHelper dbg = DebugHelper.create(Container.class);
- /**
- * A constant which toggles one of the controllable behaviors
- * of <code>getMouseEventTarget</code>. It is used to specify whether
- * the method can return the Container on which it is originally called
- * in case if none of its children are the current mouse event targets.
- *
- * @see #getMouseEventTarget(int, int, boolean, boolean, boolean)
- */
- static final boolean INCLUDE_SELF = true;
- /**
- * A constant which toggles one of the controllable behaviors
- * of <code>getMouseEventTarget</code>. It is used to specify whether
- * the method should search only lightweight components.
- *
- * @see #getMouseEventTarget(int, int, boolean, boolean, boolean)
- */
- static final boolean SEARCH_HEAVYWEIGHTS = true;
- static {
- /* ensure that the necessary native libraries are loaded */
- Toolkit.loadLibraries();
- if (!GraphicsEnvironment.isHeadless()) {
- initIDs();
- }
- }
- /**
- * Initialize JNI field and method IDs for fields that may be
- called from C.
- */
- private static native void initIDs();
- /**
- * Constructs a new Container. Containers can be extended directly,
- * but are lightweight in this case and must be contained by a parent
- * somewhere higher up in the component tree that is native.
- * (such as Frame for example).
- */
- public Container() {
- }
- void initializeFocusTraversalKeys() {
- focusTraversalKeys = new Set[4];
- }
- /**
- * Gets the number of components in this panel.
- * @return the number of components in this panel.
- * @see #getComponent
- * @since JDK1.1
- */
- public int getComponentCount() {
- return countComponents();
- }
- /**
- * @deprecated As of JDK version 1.1,
- * replaced by getComponentCount().
- */
- public int countComponents() {
- return ncomponents;
- }
- /**
- * Gets the nth component in this container.
- * @param n the index of the component to get.
- * @return the n<sup>th</sup> component in this container.
- * @exception ArrayIndexOutOfBoundsException
- * if the n<sup>th</sup> value does not exist.
- */
- public Component getComponent(int n) {
- synchronized (getTreeLock()) {
- if ((n < 0) || (n >= ncomponents)) {
- throw new ArrayIndexOutOfBoundsException("No such child: " + n);
- }
- return component[n];
- }
- }
- /**
- * Gets all the components in this container.
- * @return an array of all the components in this container.
- */
- public Component[] getComponents() {
- return getComponents_NoClientCode();
- }
- // NOTE: This method may be called by privileged threads.
- // This functionality is implemented in a package-private method
- // to insure that it cannot be overridden by client subclasses.
- // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
- final Component[] getComponents_NoClientCode() {
- synchronized (getTreeLock()) {
- Component list[] = new Component[ncomponents];
- System.arraycopy(component, 0, list, 0, ncomponents);
- return list;
- }
- } // getComponents_NoClientCode()
- /**
- * Determines the insets of this container, which indicate the size
- * of the container's border.
- * <p>
- * A <code>Frame</code> object, for example, has a top inset that
- * corresponds to the height of the frame's title bar.
- * @return the insets of this container.
- * @see Insets
- * @see LayoutManager
- * @since JDK1.1
- */
- public Insets getInsets() {
- return insets();
- }
- /**
- * @deprecated As of JDK version 1.1,
- * replaced by <code>getInsets()</code>.
- */
- public Insets insets() {
- if (this.peer != null && this.peer instanceof ContainerPeer) {
- ContainerPeer peer = (ContainerPeer)this.peer;
- return (Insets)peer.insets().clone();
- }
- return new Insets(0, 0, 0, 0);
- }
- /**
- * Appends the specified component to the end of this container.
- * This is a convenience method for {@link #addImpl}.
- * <p>
- * Note: If a component has been added to a container that
- * has been displayed, <code>validate</code> must be
- * called on that container to display the new component.
- * If multiple components are being added, you can improve
- * efficiency by calling <code>validate</code> only once,
- * after all the components have been added.
- *
- * @param comp the component to be added
- * @see #addImpl
- * @see #validate
- * @see javax.swing.JComponent#revalidate()
- * @return the component argument
- */
- public Component add(Component comp) {
- addImpl(comp, null, -1);
- return comp;
- }
- /**
- * Adds the specified component to this container.
- * This is a convenience method for {@link #addImpl}.
- * <p>
- * This method is obsolete as of 1.1. Please use the
- * method <code>add(Component, Object)</code> instead.
- * @see #add(Component, Object)
- */
- public Component add(String name, Component comp) {
- addImpl(comp, name, -1);
- return comp;
- }
- /**
- * Adds the specified component to this container at the given
- * position.
- * This is a convenience method for {@link #addImpl}.
- * <p>
- * Note: If a component has been added to a container that
- * has been displayed, <code>validate</code> must be
- * called on that container to display the new component.
- * If multiple components are being added, you can improve
- * efficiency by calling <code>validate</code> only once,
- * after all the components have been added.
- *
- * @param comp the component to be added
- * @param index the position at which to insert the component,
- * or <code>-1</code> to append the component to the end
- * @return the component <code>comp</code>
- * @see #addImpl
- * @see #remove
- * @see #validate
- * @see javax.swing.JComponent#revalidate()
- */
- public Component add(Component comp, int index) {
- addImpl(comp, null, index);
- return comp;
- }
- void setZOrder(Component comp, int index) {
- synchronized (getTreeLock()) {
- /* Check for correct arguments: index in bounds,
- * comp cannot be one of this container's parents,
- * and comp cannot be a window.
- * comp and container must be on the same GraphicsDevice.
- * if comp is container, all sub-components must be on
- * same GraphicsDevice.
- */
- GraphicsConfiguration thisGC = this.getGraphicsConfiguration();
- if (index > ncomponents || (index < 0 && index != -1)) {
- throw new IllegalArgumentException(
- "illegal component position");
- }
- if (comp instanceof Container) {
- for (Container cn = this; cn != null; cn=cn.parent) {
- if (cn == comp) {
- throw new IllegalArgumentException(
- "adding container's parent to itself");
- }
- }
- if (comp instanceof Window) {
- throw new IllegalArgumentException(
- "adding a window to a container");
- }
- }
- if (!(comp.peer instanceof LightweightPeer)) {
- throw new IllegalArgumentException("should be lightweight component");
- }
- Container nativeContainer =
- (this.peer instanceof LightweightPeer) ? getNativeContainer() : this;
- if (nativeContainer != comp.getNativeContainer()) {
- throw new IllegalArgumentException("component should be in the same heavyweight container");
- }
- if (thisGC != null) {
- comp.checkGD(thisGC.getDevice().getIDstring());
- }
- /* Reparent the component and tidy up the tree's state. */
- if (comp.parent != null) {
- Container oldParent = comp.parent;
- /* Search backwards, expect that more recent additions
- * are more likely to be removed.
- */
- Component component[] = oldParent.component;
- int ncomponents = oldParent.ncomponents;
- for (int i = ncomponents; --i >= 0; ) {
- if (component[i] == comp) {
- if (oldParent.layoutMgr != null) {
- oldParent.layoutMgr.removeLayoutComponent(comp);
- }
- oldParent.adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
- -comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
- oldParent.adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
- -comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
- oldParent.adjustDescendants(-(comp.countHierarchyMembers()));
- comp.parent = null;
- System.arraycopy(oldParent.component, i + 1,
- oldParent.component, i,
- oldParent.ncomponents - i - 1);
- component[--oldParent.ncomponents] = null;
- if (oldParent.valid) {
- oldParent.invalidate();
- }
- if (oldParent.containerListener != null ||
- (oldParent.eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
- Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
- ContainerEvent e = new ContainerEvent(oldParent,
- ContainerEvent.COMPONENT_REMOVED,
- comp);
- oldParent.dispatchEvent(e);
- }
- comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
- oldParent, HierarchyEvent.PARENT_CHANGED,
- Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
- if (oldParent.peer != null && oldParent.layoutMgr == null && oldParent.isVisible()) {
- oldParent.updateCursorImmediately();
- }
- }
- }
- if (index > ncomponents) {
- throw new IllegalArgumentException("illegal component position");
- }
- }
- /* Add component to list; allocate new array if necessary. */
- if (ncomponents == component.length) {
- Component newcomponents[] = new Component[ncomponents * 2 + 1];
- System.arraycopy(component, 0, newcomponents, 0, ncomponents);
- component = newcomponents;
- }
- if (index == -1 || index == ncomponents) {
- component[ncomponents++] = comp;
- } else {
- System.arraycopy(component, index, component,
- index + 1, ncomponents - index);
- component[index] = comp;
- ncomponents++;
- }
- comp.parent = this;
- adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
- comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
- adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
- comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
- adjustDescendants(comp.countHierarchyMembers());
- if (valid) {
- invalidate();
- }
- if (peer != null) {
- comp.addNotify();
- }
- /* Notify the layout manager of the added component. */
- if (layoutMgr != null) {
- if (layoutMgr instanceof LayoutManager2) {
- ((LayoutManager2)layoutMgr).addLayoutComponent(comp, null);
- }
- }
- if (containerListener != null ||
- (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
- Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
- ContainerEvent e = new ContainerEvent(this,
- ContainerEvent.COMPONENT_ADDED,
- comp);
- dispatchEvent(e);
- }
- comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
- this, HierarchyEvent.PARENT_CHANGED,
- Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
- if (peer != null && layoutMgr == null && isVisible()) {
- updateCursorImmediately();
- }
- }
- }
- /**
- * Adds the specified component to the end of this container.
- * Also notifies the layout manager to add the component to
- * this container's layout using the specified constraints object.
- * This is a convenience method for {@link #addImpl}.
- * <p>
- * Note: If a component has been added to a container that
- * has been displayed, <code>validate</code> must be
- * called on that container to display the new component.
- * If multiple components are being added, you can improve
- * efficiency by calling <code>validate</code> only once,
- * after all the components have been added.
- *
- * @param comp the component to be added
- * @param constraints an object expressing
- * layout contraints for this component
- * @see #addImpl
- * @see #validate
- * @see javax.swing.JComponent#revalidate()
- * @see LayoutManager
- * @since JDK1.1
- */
- public void add(Component comp, Object constraints) {
- addImpl(comp, constraints, -1);
- }
- /**
- * Adds the specified component to this container with the specified
- * constraints at the specified index. Also notifies the layout
- * manager to add the component to the this container's layout using
- * the specified constraints object.
- * This is a convenience method for {@link #addImpl}.
- * <p>
- * Note: If a component has been added to a container that
- * has been displayed, <code>validate</code> must be
- * called on that container to display the new component.
- * If multiple components are being added, you can improve
- * efficiency by calling <code>validate</code> only once,
- * after all the components have been added.
- *
- * @param comp the component to be added
- * @param constraints an object expressing layout contraints for this
- * @param index the position in the container's list at which to insert
- * the component; <code>-1</code> means insert at the end
- * component
- * @see #addImpl
- * @see #validate
- * @see javax.swing.JComponent#revalidate()
- * @see #remove
- * @see LayoutManager
- */
- public void add(Component comp, Object constraints, int index) {
- addImpl(comp, constraints, index);
- }
- /**
- * Adds the specified component to this container at the specified
- * index. This method also notifies the layout manager to add
- * the component to this container's layout using the specified
- * constraints object via the <code>addLayoutComponent</code>
- * method. The constraints are
- * defined by the particular layout manager being used. For
- * example, the <code>BorderLayout</code> class defines five
- * constraints: <code>BorderLayout.NORTH</code>,
- * <code>BorderLayout.SOUTH</code>, <code>BorderLayout.EAST</code>,
- * <code>BorderLayout.WEST</code>, and <code>BorderLayout.CENTER</code>.
- *
- * <p>Note that if the component already exists
- * in this container or a child of this container,
- * it is removed from that container before
- * being added to this container.
- * <p>
- * This is the method to override if a program needs to track
- * every add request to a container as all other add methods defer
- * to this one. An overriding method should
- * usually include a call to the superclass's version of the method:
- * <p>
- * <blockquote>
- * <code>super.addImpl(comp, constraints, index)</code>
- * </blockquote>
- * <p>
- * @param comp the component to be added
- * @param constraints an object expressing layout constraints
- * for this component
- * @param index the position in the container's list at which to
- * insert the component, where <code>-1</code>
- * means append to the end
- * @exception IllegalArgumentException if <code>index</code> is invalid
- * @exception IllegalArgumentException if adding the container's parent
- * to itself
- * @exception IllegalArgumentException if adding a window to a container
- * @see #add(Component)
- * @see #add(Component, int)
- * @see #add(Component, java.lang.Object)
- * @see LayoutManager
- * @see LayoutManager2
- * @since JDK1.1
- */
- protected void addImpl(Component comp, Object constraints, int index) {
- synchronized (getTreeLock()) {
- /* Check for correct arguments: index in bounds,
- * comp cannot be one of this container's parents,
- * and comp cannot be a window.
- * comp and container must be on the same GraphicsDevice.
- * if comp is container, all sub-components must be on
- * same GraphicsDevice.
- */
- GraphicsConfiguration thisGC = this.getGraphicsConfiguration();
- if (index > ncomponents || (index < 0 && index != -1)) {
- throw new IllegalArgumentException(
- "illegal component position");
- }
- if (comp instanceof Container) {
- for (Container cn = this; cn != null; cn=cn.parent) {
- if (cn == comp) {
- throw new IllegalArgumentException(
- "adding container's parent to itself");
- }
- }
- if (comp instanceof Window) {
- throw new IllegalArgumentException(
- "adding a window to a container");
- }
- }
- if (thisGC != null) {
- comp.checkGD(thisGC.getDevice().getIDstring());
- }
- /* Reparent the component and tidy up the tree's state. */
- if (comp.parent != null) {
- comp.parent.remove(comp);
- if (index > ncomponents) {
- throw new IllegalArgumentException("illegal component position");
- }
- }
- /* Add component to list; allocate new array if necessary. */
- if (ncomponents == component.length) {
- Component newcomponents[] = new Component[ncomponents * 2 + 1];
- System.arraycopy(component, 0, newcomponents, 0, ncomponents);
- component = newcomponents;
- }
- if (index == -1 || index == ncomponents) {
- component[ncomponents++] = comp;
- } else {
- System.arraycopy(component, index, component,
- index + 1, ncomponents - index);
- component[index] = comp;
- ncomponents++;
- }
- comp.parent = this;
- adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
- comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
- adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
- comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
- adjustDescendants(comp.countHierarchyMembers());
- if (valid) {
- invalidate();
- }
- if (peer != null) {
- comp.addNotify();
- }
- /* Notify the layout manager of the added component. */
- if (layoutMgr != null) {
- if (layoutMgr instanceof LayoutManager2) {
- ((LayoutManager2)layoutMgr).addLayoutComponent(comp, constraints);
- } else if (constraints instanceof String) {
- layoutMgr.addLayoutComponent((String)constraints, comp);
- }
- }
- if (containerListener != null ||
- (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
- Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
- ContainerEvent e = new ContainerEvent(this,
- ContainerEvent.COMPONENT_ADDED,
- comp);
- dispatchEvent(e);
- }
- comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
- this, HierarchyEvent.PARENT_CHANGED,
- Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
- if (peer != null && layoutMgr == null && isVisible()) {
- updateCursorImmediately();
- }
- }
- }
- /**
- * Checks that all Components that this Container contains are on
- * the same GraphicsDevice as this Container. If not, throws an
- * IllegalArgumentException.
- */
- void checkGD(String stringID) {
- Component tempComp;
- for (int i = 0; i < component.length; i++) {
- tempComp= component[i];
- if (tempComp != null) {
- tempComp.checkGD(stringID);
- }
- }
- }
- /**
- * Removes the component, specified by <code>index</code>,
- * from this container.
- * @param index the index of the component to be removed.
- * @see #add
- * @since JDK1.1
- */
- public void remove(int index) {
- synchronized (getTreeLock()) {
- if (index < 0 || index >= ncomponents) {
- throw new ArrayIndexOutOfBoundsException(index);
- }
- Component comp = component[index];
- if (peer != null) {
- comp.removeNotify();
- }
- if (layoutMgr != null) {
- layoutMgr.removeLayoutComponent(comp);
- }
- adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
- -comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
- adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
- -comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
- adjustDescendants(-(comp.countHierarchyMembers()));
- comp.parent = null;
- System.arraycopy(component, index + 1,
- component, index,
- ncomponents - index - 1);
- component[--ncomponents] = null;
- if (valid) {
- invalidate();
- }
- if (containerListener != null ||
- (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
- Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
- ContainerEvent e = new ContainerEvent(this,
- ContainerEvent.COMPONENT_REMOVED,
- comp);
- dispatchEvent(e);
- }
- comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
- this, HierarchyEvent.PARENT_CHANGED,
- Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
- if (peer != null && layoutMgr == null && isVisible()) {
- updateCursorImmediately();
- }
- }
- }
- /**
- * Removes the specified component from this container.
- * @param comp the component to be removed
- * @see #add
- */
- public void remove(Component comp) {
- synchronized (getTreeLock()) {
- if (comp.parent == this) {
- /* Search backwards, expect that more recent additions
- * are more likely to be removed.
- */
- Component component[] = this.component;
- for (int i = ncomponents; --i >= 0; ) {
- if (component[i] == comp) {
- remove(i);
- }
- }
- }
- }
- }
- /**
- * Removes all the components from this container.
- * @see #add
- * @see #remove
- */
- public void removeAll() {
- synchronized (getTreeLock()) {
- adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
- -listeningChildren);
- adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
- -listeningBoundsChildren);
- adjustDescendants(-descendantsCount);
- while (ncomponents > 0) {
- Component comp = component[--ncomponents];
- component[ncomponents] = null;
- if (peer != null) {
- comp.removeNotify();
- }
- if (layoutMgr != null) {
- layoutMgr.removeLayoutComponent(comp);
- }
- comp.parent = null;
- if (containerListener != null ||
- (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
- Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
- ContainerEvent e = new ContainerEvent(this,
- ContainerEvent.COMPONENT_REMOVED,
- comp);
- dispatchEvent(e);
- }
- comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED,
- comp, this,
- HierarchyEvent.PARENT_CHANGED,
- Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
- }
- if (peer != null && layoutMgr == null && isVisible()) {
- updateCursorImmediately();
- }
- if (valid) {
- invalidate();
- }
- }
- }
- // Should only be called while holding tree lock
- int numListening(long mask) {
- int superListening = super.numListening(mask);
- if (mask == AWTEvent.HIERARCHY_EVENT_MASK) {
- if (dbg.on) {
- // Verify listeningChildren is correct
- int sum = 0;
- for (int i = 0; i < ncomponents; i++) {
- sum += component[i].numListening(mask);
- }
- dbg.assertion(listeningChildren == sum);
- }
- return listeningChildren + superListening;
- } else if (mask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) {
- if (dbg.on) {
- // Verify listeningBoundsChildren is correct
- int sum = 0;
- for (int i = 0; i < ncomponents; i++) {
- sum += component[i].numListening(mask);
- }
- dbg.assertion(listeningBoundsChildren == sum);
- }
- return listeningBoundsChildren + superListening;
- } else {
- if (dbg.on) {
- dbg.assertion(false);
- }
- return superListening;
- }
- }
- // Should only be called while holding tree lock
- void adjustListeningChildren(long mask, int num) {
- if (dbg.on) {
- dbg.assertion(mask == AWTEvent.HIERARCHY_EVENT_MASK ||
- mask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK ||
- mask == (AWTEvent.HIERARCHY_EVENT_MASK |
- AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
- }
- if (num == 0)
- return;
- if ((mask & AWTEvent.HIERARCHY_EVENT_MASK) != 0) {
- listeningChildren += num;
- }
- if ((mask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0) {
- listeningBoundsChildren += num;
- }
- adjustListeningChildrenOnParent(mask, num);
- }
- // Should only be called while holding tree lock
- void adjustDescendants(int num) {
- if (num == 0)
- return;
- descendantsCount += num;
- adjustDecendantsOnParent(num);
- }
- // Should only be called while holding tree lock
- void adjustDecendantsOnParent(int num) {
- if (parent != null) {
- parent.adjustDescendants(num);
- }
- }
- // Should only be called while holding tree lock
- int countHierarchyMembers() {
- if (dbg.on) {
- // Verify descendantsCount is correct
- int sum = 0;
- for (int i = 0; i < ncomponents; i++) {
- sum += component[i].countHierarchyMembers();
- }
- dbg.assertion(descendantsCount == sum);
- }
- return descendantsCount;
- }
- // Should only be called while holding tree lock
- int createHierarchyEvents(int id, Component changed,
- Container changedParent, long changeFlags,
- boolean enabledOnToolkit) {
- int listeners = 0;
- switch (id) {
- case HierarchyEvent.HIERARCHY_CHANGED:
- listeners = listeningChildren;
- break;
- case HierarchyEvent.ANCESTOR_MOVED:
- case HierarchyEvent.ANCESTOR_RESIZED:
- if (dbg.on) {
- dbg.assertion(changeFlags == 0);
- }
- listeners = listeningBoundsChildren;
- break;
- default:
- if (dbg.on) {
- dbg.assertion(false);
- }
- break;
- }
- if (enabledOnToolkit) {
- listeners = descendantsCount;
- }
- for (int count = listeners, i = 0; count > 0; i++) {
- count -= component[i].createHierarchyEvents(id, changed,
- changedParent,
- changeFlags,
- enabledOnToolkit);
- }
- return listeners +
- super.createHierarchyEvents(id, changed, changedParent,
- changeFlags, enabledOnToolkit);
- }
- void createChildHierarchyEvents(int id, long changeFlags,
- boolean enabledOnToolkit) {
- synchronized (getTreeLock()) {
- int listeners = 0;
- switch (id) {
- case HierarchyEvent.HIERARCHY_CHANGED:
- listeners = listeningChildren;
- break;
- case HierarchyEvent.ANCESTOR_MOVED:
- case HierarchyEvent.ANCESTOR_RESIZED:
- if (dbg.on) {
- dbg.assertion(changeFlags == 0);
- }
- listeners = listeningBoundsChildren;
- break;
- default:
- if (dbg.on) {
- dbg.assertion(false);
- }
- break;
- }
- if (enabledOnToolkit) {
- listeners = descendantsCount;
- }
- for (int count = listeners, i = 0; count > 0; i++) {
- count -= component[i].createHierarchyEvents(id, this, parent,
- changeFlags,
- enabledOnToolkit);
- }
- }
- }
- /**
- * Gets the layout manager for this container.
- * @see #doLayout
- * @see #setLayout
- */
- public LayoutManager getLayout() {
- return layoutMgr;
- }
- /**
- * Sets the layout manager for this container.
- * @param mgr the specified layout manager
- * @see #doLayout
- * @see #getLayout
- */
- public void setLayout(LayoutManager mgr) {
- layoutMgr = mgr;
- if (valid) {
- invalidate();
- }
- }
- /**
- * Causes this container to lay out its components. Most programs
- * should not call this method directly, but should invoke
- * the <code>validate</code> method instead.
- * @see LayoutManager#layoutContainer
- * @see #setLayout
- * @see #validate
- * @since JDK1.1
- */
- public void doLayout() {
- layout();
- }
- /**
- * @deprecated As of JDK version 1.1,
- * replaced by <code>doLayout()</code>.
- */
- public void layout() {
- LayoutManager layoutMgr = this.layoutMgr;
- if (layoutMgr != null) {
- layoutMgr.layoutContainer(this);
- }
- }
- /**
- * Invalidates the container. The container and all parents
- * above it are marked as needing to be laid out. This method can
- * be called often, so it needs to execute quickly.
- * @see #validate
- * @see #layout
- * @see LayoutManager
- */
- public void invalidate() {
- LayoutManager layoutMgr = this.layoutMgr;
- if (layoutMgr instanceof LayoutManager2) {
- LayoutManager2 lm = (LayoutManager2) layoutMgr;
- lm.invalidateLayout(this);
- }
- super.invalidate();
- }
- /**
- * Validates this container and all of its subcomponents.
- * <p>
- * The <code>validate</code> method is used to cause a container
- * to lay out its subcomponents again. It should be invoked when
- * this container's subcomponents are modified (added to or
- * removed from the container, or layout-related information
- * changed) after the container has been displayed.
- *
- * @see #add(java.awt.Component)
- * @see Component#invalidate
- * @see javax.swing.JComponent#revalidate()
- */
- public void validate() {
- /* Avoid grabbing lock unless really necessary. */
- if (!valid) {
- boolean updateCur = false;
- synchronized (getTreeLock()) {
- if (!valid && peer != null) {
- ContainerPeer p = null;
- if (peer instanceof ContainerPeer) {
- p = (ContainerPeer) peer;
- }
- if (p != null) {
- p.beginValidate();
- }
- validateTree();
- valid = true;
- if (p != null) {
- p.endValidate();
- updateCur = isVisible();
- }
- }
- }
- if (updateCur) {
- updateCursorImmediately();
- }
- }
- }
- /**
- * Recursively descends the container tree and recomputes the
- * layout for any subtrees marked as needing it (those marked as
- * invalid). Synchronization should be provided by the method
- * that calls this one: <code>validate</code>.
- */
- protected void validateTree() {
- if (!valid) {
- if (peer instanceof ContainerPeer) {
- ((ContainerPeer)peer).beginLayout();
- }
- doLayout();
- Component component[] = this.component;
- for (int i = 0 ; i < ncomponents ; ++i) {
- Component comp = component[i];
- if ( (comp instanceof Container)
- && !(comp instanceof Window)
- && !comp.valid) {
- ((Container)comp).validateTree();
- } else {
- comp.validate();
- }
- }
- if (peer instanceof ContainerPeer) {
- ((ContainerPeer)peer).endLayout();
- }
- }
- valid = true;
- }
- /**
- * Recursively descends the container tree and invalidates all
- * contained components.
- */
- void invalidateTree() {
- synchronized (getTreeLock()) {
- for (int i = 0; i < ncomponents; ++i) {
- Component comp = component[i];
- if (comp instanceof Container) {
- ((Container)comp).invalidateTree();
- }
- else {
- if (comp.valid) {
- comp.invalidate();
- }
- }
- }
- if (valid) {
- invalidate();
- }
- }
- }
- /**
- * Sets the font of this container.
- * @param f The font to become this container's font.
- * @see Component#getFont
- * @since JDK1.0
- */
- public void setFont(Font f) {
- boolean shouldinvalidate = false;
- Font oldfont = getFont();
- super.setFont(f);
- Font newfont = getFont();
- if (newfont != oldfont && (oldfont == null ||
- !oldfont.equals(newfont))) {
- invalidateTree();
- }
- }
- /**
- * Returns the preferred size of this container.
- * @return an instance of <code>Dimension</code> that represents
- * the preferred size of this container.
- * @see #getMinimumSize
- * @see #getLayout
- * @see LayoutManager#preferredLayoutSize(Container)
- * @see Component#getPreferredSize
- */
- public Dimension getPreferredSize() {
- return preferredSize();
- }
- /**
- * @deprecated As of JDK version 1.1,
- * replaced by <code>getPreferredSize()</code>.
- */
- public Dimension preferredSize() {
- /* Avoid grabbing the lock if a reasonable cached size value
- * is available.
- */
- Dimension dim = prefSize;
- if (dim != null && isValid()) {
- return dim;
- }
- synchronized (getTreeLock()) {
- prefSize = (layoutMgr != null) ?
- layoutMgr.preferredLayoutSize(this) :
- super.preferredSize();
- return prefSize;
- }
- }
- /**
- * Returns the minimum size of this container.
- * @return an instance of <code>Dimension</code> that represents
- * the minimum size of this container.
- * @see #getPreferredSize
- * @see #getLayout
- * @see LayoutManager#minimumLayoutSize(Container)
- * @see Component#getMinimumSize
- * @since JDK1.1
- */
- public Dimension getMinimumSize() {
- return minimumSize();
- }
- /**
- * @deprecated As of JDK version 1.1,
- * replaced by <code>getMinimumSize()</code>.
- */
- public Dimension minimumSize() {
- /* Avoid grabbing the lock if a reasonable cached size value
- * is available.
- */
- Dimension dim = minSize;
- if (dim != null && isValid()) {
- return dim;
- }
- synchronized (getTreeLock()) {
- minSize = (layoutMgr != null) ?
- layoutMgr.minimumLayoutSize(this) :
- super.minimumSize();
- return minSize;
- }
- }
- /**
- * Returns the maximum size of this container.
- * @see #getPreferredSize
- */
- public Dimension getMaximumSize() {
- /* Avoid grabbing the lock if a reasonable cached size value
- * is available.
- */
- Dimension dim = maxSize;
- if (dim != null && isValid()) {
- return dim;
- }
- if (layoutMgr instanceof LayoutManager2) {
- synchronized (getTreeLock()) {
- LayoutManager2 lm = (LayoutManager2) layoutMgr;
- maxSize = lm.maximumLayoutSize(this);
- }
- } else {
- maxSize = super.getMaximumSize();
- }
- return maxSize;
- }
- /**
- * Returns the alignment along the x axis. This specifies how
- * the component would like to be aligned relative to other
- * components. The value should be a number between 0 and 1
- * where 0 represents alignment along the origin, 1 is aligned
- * the furthest away from the origin, 0.5 is centered, etc.
- */
- public float getAlignmentX() {
- float xAlign;
- if (layoutMgr instanceof LayoutManager2) {
- synchronized (getTreeLock()) {
- LayoutManager2 lm = (LayoutManager2) layoutMgr;
- xAlign = lm.getLayoutAlignmentX(this);
- }
- } else {
- xAlign = super.getAlignmentX();
- }
- return xAlign;
- }
- /**
- * Returns the alignment along the y axis. This specifies how
- * the component would like to be aligned relative to other
- * components. The value should be a number between 0 and 1
- * where 0 represents alignment along the origin, 1 is aligned
- * the furthest away from the origin, 0.5 is centered, etc.
- */
- public float getAlignmentY() {
- float yAlign;
- if (layoutMgr instanceof LayoutManager2) {
- synchronized (getTreeLock()) {
- LayoutManager2 lm = (LayoutManager2) layoutMgr;
- yAlign = lm.getLayoutAlignmentY(this);
- }
- } else {
- yAlign = super.getAlignmentY();
- }
- return yAlign;
- }
- /**
- * Paints the container. This forwards the paint to any lightweight
- * components that are children of this container. If this method is
- * reimplemented, super.paint(g) should be called so that lightweight
- * components are properly rendered. If a child component is entirely
- * clipped by the current clipping setting in g, paint() will not be
- * forwarded to that child.
- *
- * @param g the specified Graphics window
- * @see Component#update(Graphics)
- */
- public void paint(Graphics g) {
- if (isShowing()) {
- if (printing) {
- synchronized (this) {
- if (printing) {
- if (printingThreads.contains(Thread.currentThread())) {
- return;
- }
- }
- }
- }
- // The container is showing on screen and
- // this paint() is not called from print().
- // Paint self and forward the paint to lightweight subcomponents.
- // super.paint(); -- Don't bother, since it's a NOP.
- GraphicsCallback.PaintCallback.getInstance().
- runComponents(component, g, GraphicsCallback.LIGHTWEIGHTS);
- }
- }
- /**
- * Updates the container. This forwards the update to any lightweight
- * components that are children of this container. If this method is
- * reimplemented, super.update(g) should be called so that lightweight
- * components are properly rendered. If a child component is entirely
- * clipped by the current clipping setting in g, update() will not be
- * forwarded to that child.
- *
- * @param g the specified Graphics window
- * @see Component#update(Graphics)
- */
- public void update(Graphics g) {
- if (isShowing()) {
- if (! (peer instanceof LightweightPeer)) {
- g.clearRect(0, 0, width, height);
- }
- paint(g);
- }
- }
- /**
- * Prints the container. This forwards the print to any lightweight
- * components that are children of this container. If this method is
- * reimplemented, super.print(g) should be called so that lightweight
- * components are properly rendered. If a child component is entirely
- * clipped by the current clipping setting in g, print() will not be
- * forwarded to that child.
- *
- * @param g the specified Graphics window
- * @see Component#update(Graphics)
- */
- public void print(Graphics g) {
- if (isShowing()) {
- Thread t = Thread.currentThread();
- try {
- synchronized (this) {
- if (printingThreads == null) {
- printingThreads = new HashSet();
- }
- printingThreads.add(t);
- printing = true;
- }
- super.print(g); // By default, Component.print() calls paint()
- } finally {
- synchronized (this) {
- printingThreads.remove(t);
- printing = !printingThreads.isEmpty();
- }
- }
- GraphicsCallback.PrintCallback.getInstance().
- runComponents(component, g, GraphicsCallback.LIGHTWEIGHTS);
- }
- }
- /**
- * Paints each of the components in this container.
- * @param g the graphics context.
- * @see Component#paint
- * @see Component#paintAll
- */
- public void paintComponents(Graphics g) {
- if (isShowing()) {
- GraphicsCallback.PaintAllCallback.getInstance().
- runComponents(component, g, GraphicsCallback.TWO_PASSES);
- }
- }
- /**
- * Simulates the peer callbacks into java.awt for printing of
- * lightweight Containers.
- * @param g the graphics context to use for printing.
- * @see Component#printAll
- * @see #printComponents
- */
- void lightweightPaint(Graphics g) {
- super.lightweightPaint(g);
- paintHeavyweightComponents(g);
- }
- /**
- * Prints all the heavyweight subcomponents.
- */
- void paintHeavyweightComponents(Graphics g) {
- if (isShowing()) {
- GraphicsCallback.PaintHeavyweightComponentsCallback.getInstance().
- runComponents(component, g, GraphicsCallback.LIGHTWEIGHTS |
- GraphicsCallback.HEAVYWEIGHTS);
- }
- }
- /**
- * Prints each of the components in this container.
- * @param g the graphics context.
- * @see Component#print
- * @see Component#printAll
- */
- public void printComponents(Graphics g) {
- if (isShowing()) {
- GraphicsCallback.PrintAllCallback.getInstance().
- runComponents(component, g, GraphicsCallback.TWO_PASSES);
- }
- }
- /**
- * Simulates the peer callbacks into java.awt for printing of
- * lightweight Containers.
- * @param g the graphics context to use for printing.
- * @see Component#printAll
- * @see #printComponents
- */
- void lightweightPrint(Graphics g) {
- super.lightweightPrint(g);
- printHeavyweightComponents(g);
- }
- /**
- * Prints all the heavyweight subcomponents.
- */
- void printHeavyweightComponents(Graphics g) {
- if (isShowing()) {
- GraphicsCallback.PrintHeavyweightComponentsCallback.getInstance().
- runComponents(component, g, GraphicsCallback.LIGHTWEIGHTS |
- GraphicsCallback.HEAVYWEIGHTS);
- }
- }
- /**
- * Adds the specified container listener to receive container events
- * from this container.
- * If l is null, no exception is thrown and no action is performed.
- *
- * @param l the container listener
- *
- * @see #removeContainerListener
- * @see #getContainerListeners
- */
- public synchronized void addContainerListener(ContainerListener l) {
- if (l == null) {
- return;
- }
- containerListener = AWTEventMulticaster.add(containerListener, l);
- newEventsOnly = true;
- }
- /**
- * Removes the specified container listener so it no longer receives
- * container events from this container.
- * If l is null, no exception is thrown and no action is performed.
- *
- * @param l the container listener
- *
- * @see #addContainerListener
- * @see #getContainerListeners
- */
- public synchronized void removeContainerListener(ContainerListener l) {
- if (l == null) {
- return;
- }
- containerListener = AWTEventMulticaster.remove(containerListener, l);
- }
- /**
- * Returns an array of all the container listeners
- * registered on this container.
- *
- * @return all of this container's <code>ContainerListener</code>s
- * or an empty array if no container
- * listeners are currently registered
- *
- * @see #addContainerListener
- * @see #removeContainerListener
- * @since 1.4
- */
- public synchronized ContainerListener[] getContainerListeners() {
- return (ContainerListener[]) (getListeners(ContainerListener.class));
- }
- /**
- * Returns an array of all the objects currently registered
- * as <code><em>Foo</em>Listener</code>s
- * upon this <code>Container</code>.
- * <code><em>Foo</em>Listener</code>s are registered using the
- * <code>add<em>Foo</em>Listener</code> method.
- *
- * <p>
- * You can specify the <code>listenerType</code> argument
- * with a class literal, such as
- * <code><em>Foo</em>Listener.class</code>.
- * For example, you can query a
- * <code>Container</code> <code>c</code>
- * for its container listeners with the following code:
- *
- * <pre>ContainerListener[] cls = (ContainerListener[])(c.getListeners(ContainerListener.class));</pre>
- *
- * If no such listeners exist, this method returns an empty array.
- *
- * @param listenerType the type of listeners requested; this parameter
- * should specify an interface that descends from
- * <code>java.util.EventListener</code>
- * @return an array of all objects registered as
- * <code><em>Foo</em>Listener</code>s on this container,
- * or an empty array if no such listeners have been added
- * @exception ClassCastException if <code>listenerType</code>
- * doesn't specify a class or interface that implements
- * <code>java.util.EventListener</code>
- *
- * @see #getContainerListeners
- *
- * @since 1.3
- */
- public EventListener[] getListeners(Class listenerType) {
- EventListener l = null;
- if (listenerType == ContainerListener.class) {
- l = containerListener;
- } else {
- return super.getListeners(listenerType);
- }
- return AWTEventMulticaster.getListeners(l, listenerType);
- }
- // REMIND: remove when filtering is done at lower level
- boolean eventEnabled(AWTEvent e) {
- int id = e.getID();
- if (id == ContainerEvent.COMPONENT_ADDED ||
- id == ContainerEvent.COMPONENT_REMOVED) {
- if ((eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
- containerListener !=