0001: /*
0002: * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025: package java.awt;
0026:
0027: import java.io.PrintStream;
0028: import java.io.PrintWriter;
0029: import java.awt.peer.ContainerPeer;
0030: import java.awt.peer.ComponentPeer;
0031: import java.awt.peer.LightweightPeer;
0032: import sun.awt.PeerEvent;
0033: import java.awt.event.ComponentEvent;
0034: import java.awt.event.ContainerEvent;
0035: import java.awt.event.FocusEvent;
0036: import java.awt.event.HierarchyEvent;
0037: import java.awt.event.InputEvent;
0038: import java.awt.event.KeyEvent;
0039: import java.awt.event.MouseEvent;
0040: import java.awt.event.MouseWheelEvent;
0041: import java.awt.event.ContainerListener;
0042: import java.util.EventListener;
0043: import java.io.ObjectStreamField;
0044: import java.io.ObjectOutputStream;
0045: import java.io.ObjectInputStream;
0046: import java.io.IOException;
0047: import java.awt.event.AWTEventListener;
0048: import java.awt.event.WindowAdapter;
0049: import java.awt.event.WindowListener;
0050: import java.awt.event.WindowEvent;
0051: import java.awt.dnd.DropTarget;
0052: import java.util.HashSet;
0053: import java.util.LinkedList;
0054: import java.util.Set;
0055: import java.util.Iterator;
0056: import java.util.Arrays;
0057: import javax.accessibility.*;
0058: import java.beans.PropertyChangeListener;
0059:
0060: import sun.awt.AppContext;
0061: import sun.awt.DebugHelper;
0062: import sun.awt.SunToolkit;
0063: import sun.awt.dnd.SunDropTargetEvent;
0064: import sun.awt.CausedFocusEvent;
0065:
0066: /**
0067: * A generic Abstract Window Toolkit(AWT) container object is a component
0068: * that can contain other AWT components.
0069: * <p>
0070: * Components added to a container are tracked in a list. The order
0071: * of the list will define the components' front-to-back stacking order
0072: * within the container. If no index is specified when adding a
0073: * component to a container, it will be added to the end of the list
0074: * (and hence to the bottom of the stacking order).
0075: * <p>
0076: * <b>Note</b>: For details on the focus subsystem, see
0077: * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
0078: * How to Use the Focus Subsystem</a>,
0079: * a section in <em>The Java Tutorial</em>, and the
0080: * <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
0081: * for more information.
0082: *
0083: * @version 1.295, 05/05/07
0084: * @author Arthur van Hoff
0085: * @author Sami Shaio
0086: * @see #add(java.awt.Component, int)
0087: * @see #getComponent(int)
0088: * @see LayoutManager
0089: * @since JDK1.0
0090: */
0091: public class Container extends Component {
0092:
0093: /**
0094: * The number of components in this container.
0095: * This value can be null.
0096: * @see #getComponent
0097: * @see #getComponents
0098: * @see #getComponentCount
0099: */
0100: int ncomponents;
0101:
0102: /**
0103: * The components in this container.
0104: * @see #add
0105: * @see #getComponents
0106: */
0107: Component component[] = new Component[0];
0108:
0109: /**
0110: * Layout manager for this container.
0111: * @see #doLayout
0112: * @see #setLayout
0113: * @see #getLayout
0114: */
0115: LayoutManager layoutMgr;
0116:
0117: /**
0118: * Event router for lightweight components. If this container
0119: * is native, this dispatcher takes care of forwarding and
0120: * retargeting the events to lightweight components contained
0121: * (if any).
0122: */
0123: private LightweightDispatcher dispatcher;
0124:
0125: /**
0126: * The focus traversal policy that will manage keyboard traversal of this
0127: * Container's children, if this Container is a focus cycle root. If the
0128: * value is null, this Container inherits its policy from its focus-cycle-
0129: * root ancestor. If all such ancestors of this Container have null
0130: * policies, then the current KeyboardFocusManager's default policy is
0131: * used. If the value is non-null, this policy will be inherited by all
0132: * focus-cycle-root children that have no keyboard-traversal policy of
0133: * their own (as will, recursively, their focus-cycle-root children).
0134: * <p>
0135: * If this Container is not a focus cycle root, the value will be
0136: * remembered, but will not be used or inherited by this or any other
0137: * Containers until this Container is made a focus cycle root.
0138: *
0139: * @see #setFocusTraversalPolicy
0140: * @see #getFocusTraversalPolicy
0141: * @since 1.4
0142: */
0143: private transient FocusTraversalPolicy focusTraversalPolicy;
0144:
0145: /**
0146: * Indicates whether this Component is the root of a focus traversal cycle.
0147: * Once focus enters a traversal cycle, typically it cannot leave it via
0148: * focus traversal unless one of the up- or down-cycle keys is pressed.
0149: * Normal traversal is limited to this Container, and all of this
0150: * Container's descendants that are not descendants of inferior focus cycle
0151: * roots.
0152: *
0153: * @see #setFocusCycleRoot
0154: * @see #isFocusCycleRoot
0155: * @since 1.4
0156: */
0157: private boolean focusCycleRoot = false;
0158:
0159: /**
0160: * Stores the value of focusTraversalPolicyProvider property.
0161: * @since 1.5
0162: * @see #setFocusTraversalPolicyProvider
0163: */
0164: private boolean focusTraversalPolicyProvider;
0165:
0166: // keeps track of the threads that are printing this component
0167: private transient Set printingThreads;
0168: // True if there is at least one thread that's printing this component
0169: private transient boolean printing = false;
0170:
0171: transient ContainerListener containerListener;
0172:
0173: /* HierarchyListener and HierarchyBoundsListener support */
0174: transient int listeningChildren;
0175: transient int listeningBoundsChildren;
0176: transient int descendantsCount;
0177:
0178: /**
0179: * JDK 1.1 serialVersionUID
0180: */
0181: private static final long serialVersionUID = 4613797578919906343L;
0182:
0183: private static final DebugHelper dbg = DebugHelper
0184: .create(Container.class);
0185:
0186: /**
0187: * A constant which toggles one of the controllable behaviors
0188: * of <code>getMouseEventTarget</code>. It is used to specify whether
0189: * the method can return the Container on which it is originally called
0190: * in case if none of its children are the current mouse event targets.
0191: *
0192: * @see #getMouseEventTarget(int, int, boolean, boolean, boolean)
0193: */
0194: static final boolean INCLUDE_SELF = true;
0195:
0196: /**
0197: * A constant which toggles one of the controllable behaviors
0198: * of <code>getMouseEventTarget</code>. It is used to specify whether
0199: * the method should search only lightweight components.
0200: *
0201: * @see #getMouseEventTarget(int, int, boolean, boolean, boolean)
0202: */
0203: static final boolean SEARCH_HEAVYWEIGHTS = true;
0204:
0205: /**
0206: * @serialField ncomponents int
0207: * The number of components in this container.
0208: * This value can be null.
0209: * @serialField component Component[]
0210: * The components in this container.
0211: * @serialField layoutMgr LayoutManager
0212: * Layout manager for this container.
0213: * @serialField dispatcher LightweightDispatcher
0214: * Event router for lightweight components. If this container
0215: * is native, this dispatcher takes care of forwarding and
0216: * retargeting the events to lightweight components contained
0217: * (if any).
0218: * @serialField maxSize Dimension
0219: * Maximum size of this Container.
0220: * @serialField focusCycleRoot boolean
0221: * Indicates whether this Component is the root of a focus traversal cycle.
0222: * Once focus enters a traversal cycle, typically it cannot leave it via
0223: * focus traversal unless one of the up- or down-cycle keys is pressed.
0224: * Normal traversal is limited to this Container, and all of this
0225: * Container's descendants that are not descendants of inferior focus cycle
0226: * roots.
0227: * @serialField containerSerializedDataVersion int
0228: * Container Serial Data Version.
0229: * @serialField focusTraversalPolicyProvider boolean
0230: * Stores the value of focusTraversalPolicyProvider property.
0231: */
0232: private static final ObjectStreamField[] serialPersistentFields = {
0233: new ObjectStreamField("ncomponents", Integer.TYPE),
0234: new ObjectStreamField("component", Component[].class),
0235: new ObjectStreamField("layoutMgr", LayoutManager.class),
0236: new ObjectStreamField("dispatcher",
0237: LightweightDispatcher.class),
0238: new ObjectStreamField("maxSize", Dimension.class),
0239: new ObjectStreamField("focusCycleRoot", Boolean.TYPE),
0240: new ObjectStreamField("containerSerializedDataVersion",
0241: Integer.TYPE),
0242: new ObjectStreamField("focusTraversalPolicyProvider",
0243: Boolean.TYPE), };
0244:
0245: static {
0246: /* ensure that the necessary native libraries are loaded */
0247: Toolkit.loadLibraries();
0248: if (!GraphicsEnvironment.isHeadless()) {
0249: initIDs();
0250: }
0251: }
0252:
0253: /**
0254: * Initialize JNI field and method IDs for fields that may be
0255: called from C.
0256: */
0257: private static native void initIDs();
0258:
0259: /**
0260: * Constructs a new Container. Containers can be extended directly,
0261: * but are lightweight in this case and must be contained by a parent
0262: * somewhere higher up in the component tree that is native.
0263: * (such as Frame for example).
0264: */
0265: public Container() {
0266: }
0267:
0268: void initializeFocusTraversalKeys() {
0269: focusTraversalKeys = new Set[4];
0270: }
0271:
0272: /**
0273: * Gets the number of components in this panel.
0274: * @return the number of components in this panel.
0275: * @see #getComponent
0276: * @since JDK1.1
0277: */
0278: public int getComponentCount() {
0279: return countComponents();
0280: }
0281:
0282: /**
0283: * @deprecated As of JDK version 1.1,
0284: * replaced by getComponentCount().
0285: */
0286: @Deprecated
0287: public int countComponents() {
0288: return ncomponents;
0289: }
0290:
0291: /**
0292: * Gets the nth component in this container.
0293: * @param n the index of the component to get.
0294: * @return the n<sup>th</sup> component in this container.
0295: * @exception ArrayIndexOutOfBoundsException
0296: * if the n<sup>th</sup> value does not exist.
0297: */
0298: public Component getComponent(int n) {
0299: synchronized (getTreeLock()) {
0300: if ((n < 0) || (n >= ncomponents)) {
0301: throw new ArrayIndexOutOfBoundsException(
0302: "No such child: " + n);
0303: }
0304: return component[n];
0305: }
0306: }
0307:
0308: /**
0309: * Gets all the components in this container.
0310: * @return an array of all the components in this container.
0311: */
0312: public Component[] getComponents() {
0313: return getComponents_NoClientCode();
0314: }
0315:
0316: // NOTE: This method may be called by privileged threads.
0317: // This functionality is implemented in a package-private method
0318: // to insure that it cannot be overridden by client subclasses.
0319: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
0320: final Component[] getComponents_NoClientCode() {
0321: synchronized (getTreeLock()) {
0322: return Arrays.copyOf(component, ncomponents);
0323: }
0324: } // getComponents_NoClientCode()
0325:
0326: /**
0327: * Determines the insets of this container, which indicate the size
0328: * of the container's border.
0329: * <p>
0330: * A <code>Frame</code> object, for example, has a top inset that
0331: * corresponds to the height of the frame's title bar.
0332: * @return the insets of this container.
0333: * @see Insets
0334: * @see LayoutManager
0335: * @since JDK1.1
0336: */
0337: public Insets getInsets() {
0338: return insets();
0339: }
0340:
0341: /**
0342: * @deprecated As of JDK version 1.1,
0343: * replaced by <code>getInsets()</code>.
0344: */
0345: @Deprecated
0346: public Insets insets() {
0347: ComponentPeer peer = this .peer;
0348: if (peer instanceof ContainerPeer) {
0349: ContainerPeer cpeer = (ContainerPeer) peer;
0350: return (Insets) cpeer.insets().clone();
0351: }
0352: return new Insets(0, 0, 0, 0);
0353: }
0354:
0355: /**
0356: * Appends the specified component to the end of this container.
0357: * This is a convenience method for {@link #addImpl}.
0358: * <p>
0359: * Note: If a component has been added to a container that
0360: * has been displayed, <code>validate</code> must be
0361: * called on that container to display the new component.
0362: * If multiple components are being added, you can improve
0363: * efficiency by calling <code>validate</code> only once,
0364: * after all the components have been added.
0365: *
0366: * @param comp the component to be added
0367: * @exception NullPointerException if {@code comp} is {@code null}
0368: * @see #addImpl
0369: * @see #validate
0370: * @see javax.swing.JComponent#revalidate()
0371: * @return the component argument
0372: */
0373: public Component add(Component comp) {
0374: addImpl(comp, null, -1);
0375: return comp;
0376: }
0377:
0378: /**
0379: * Adds the specified component to this container.
0380: * This is a convenience method for {@link #addImpl}.
0381: * <p>
0382: * This method is obsolete as of 1.1. Please use the
0383: * method <code>add(Component, Object)</code> instead.
0384: * @exception NullPointerException if {@code comp} is {@code null}
0385: * @see #add(Component, Object)
0386: */
0387: public Component add(String name, Component comp) {
0388: addImpl(comp, name, -1);
0389: return comp;
0390: }
0391:
0392: /**
0393: * Adds the specified component to this container at the given
0394: * position.
0395: * This is a convenience method for {@link #addImpl}.
0396: * <p>
0397: * Note: If a component has been added to a container that
0398: * has been displayed, <code>validate</code> must be
0399: * called on that container to display the new component.
0400: * If multiple components are being added, you can improve
0401: * efficiency by calling <code>validate</code> only once,
0402: * after all the components have been added.
0403: *
0404: * @param comp the component to be added
0405: * @param index the position at which to insert the component,
0406: * or <code>-1</code> to append the component to the end
0407: * @exception NullPointerException if {@code comp} is {@code null}
0408: * @exception IllegalArgumentException if {@code index} is invalid (see
0409: * {@link #addImpl} for details)
0410: * @return the component <code>comp</code>
0411: * @see #addImpl
0412: * @see #remove
0413: * @see #validate
0414: * @see javax.swing.JComponent#revalidate()
0415: */
0416: public Component add(Component comp, int index) {
0417: addImpl(comp, null, index);
0418: return comp;
0419: }
0420:
0421: void checkTreeLock() {
0422: if (!Thread.holdsLock(getTreeLock())) {
0423: throw new IllegalStateException(
0424: "This function should be called while holding treeLock");
0425: }
0426: }
0427:
0428: /**
0429: * Checks that the component comp can be added to this container
0430: * Checks : index in bounds of container's size,
0431: * comp is not one of this container's parents,
0432: * and comp is not a window.
0433: * Comp and container must be on the same GraphicsDevice.
0434: * if comp is container, all sub-components must be on
0435: * same GraphicsDevice.
0436: *
0437: * @since 1.5
0438: */
0439: private void checkAdding(Component comp, int index) {
0440: checkTreeLock();
0441:
0442: GraphicsConfiguration this GC = getGraphicsConfiguration();
0443:
0444: if (index > ncomponents || index < 0) {
0445: throw new IllegalArgumentException(
0446: "illegal component position");
0447: }
0448: if (comp.parent == this ) {
0449: if (index == ncomponents) {
0450: throw new IllegalArgumentException(
0451: "illegal component position " + index
0452: + " should be less then " + ncomponents);
0453: }
0454: }
0455: if (comp instanceof Container) {
0456: for (Container cn = this ; cn != null; cn = cn.parent) {
0457: if (cn == comp) {
0458: throw new IllegalArgumentException(
0459: "adding container's parent to itself");
0460: }
0461: }
0462:
0463: if (comp instanceof Window) {
0464: throw new IllegalArgumentException(
0465: "adding a window to a container");
0466: }
0467: }
0468: Window this TopLevel = getContainingWindow();
0469: Window compTopLevel = comp.getContainingWindow();
0470: if (this TopLevel != compTopLevel) {
0471: throw new IllegalArgumentException(
0472: "component and container should be in the same top-level window");
0473: }
0474: if (this GC != null) {
0475: comp.checkGD(this GC.getDevice().getIDstring());
0476: }
0477: }
0478:
0479: /**
0480: * Removes component comp from this container without making unneccessary changes
0481: * and generating unneccessary events. This function intended to perform optimized
0482: * remove, for example, if newParent and current parent are the same it just changes
0483: * index without calling removeNotify.
0484: * Note: Should be called while holding treeLock
0485: * @since: 1.5
0486: */
0487: private void removeDelicately(Component comp, Container newParent,
0488: int newIndex) {
0489: checkTreeLock();
0490:
0491: int index = getComponentZOrder(comp);
0492: if (isRemoveNotifyNeeded(comp, this , newParent)) {
0493: comp.removeNotify();
0494: }
0495: if (newParent != this ) {
0496: if (layoutMgr != null) {
0497: layoutMgr.removeLayoutComponent(comp);
0498: }
0499: adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
0500: -comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
0501: adjustListeningChildren(
0502: AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
0503: -comp
0504: .numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
0505: adjustDescendants(-(comp.countHierarchyMembers()));
0506:
0507: comp.parent = null;
0508: System.arraycopy(component, index + 1, component, index,
0509: ncomponents - index - 1);
0510: component[--ncomponents] = null;
0511:
0512: if (valid) {
0513: invalidate();
0514: }
0515: } else {
0516: if (newIndex > index) { // 2->4: 012345 -> 013425, 2->5: 012345 -> 013452
0517: if (newIndex - index > 0) {
0518: System.arraycopy(component, index + 1, component,
0519: index, newIndex - index);
0520: }
0521: } else { // 4->2: 012345 -> 014235
0522: if (index - newIndex > 0) {
0523: System.arraycopy(component, newIndex, component,
0524: newIndex + 1, index - newIndex);
0525: }
0526: }
0527: component[newIndex] = comp;
0528: }
0529: if (comp.parent == null) { // was actually removed
0530: if (containerListener != null
0531: || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0
0532: || Toolkit
0533: .enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
0534: ContainerEvent e = new ContainerEvent(this ,
0535: ContainerEvent.COMPONENT_REMOVED, comp);
0536: dispatchEvent(e);
0537:
0538: }
0539: comp
0540: .createHierarchyEvents(
0541: HierarchyEvent.HIERARCHY_CHANGED,
0542: comp,
0543: this ,
0544: HierarchyEvent.PARENT_CHANGED,
0545: Toolkit
0546: .enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
0547: if (peer != null && layoutMgr == null && isVisible()) {
0548: updateCursorImmediately();
0549: }
0550: }
0551: }
0552:
0553: /**
0554: * Checks whether this container can contain component which is focus owner.
0555: * Verifies that container is enable and showing, and if it is focus cycle root
0556: * its FTP allows component to be focus owner
0557: * @since 1.5
0558: */
0559: boolean canContainFocusOwner(Component focusOwnerCandidate) {
0560: if (!(isEnabled() && isDisplayable() && isVisible() && isFocusable())) {
0561: return false;
0562: }
0563: if (isFocusCycleRoot()) {
0564: FocusTraversalPolicy policy = getFocusTraversalPolicy();
0565: if (policy instanceof DefaultFocusTraversalPolicy) {
0566: if (!((DefaultFocusTraversalPolicy) policy)
0567: .accept(focusOwnerCandidate)) {
0568: return false;
0569: }
0570: }
0571: }
0572: synchronized (getTreeLock()) {
0573: if (parent != null) {
0574: return parent.canContainFocusOwner(focusOwnerCandidate);
0575: }
0576: }
0577: return true;
0578: }
0579:
0580: /**
0581: * Checks whether or not this container has heavyweight children.
0582: * Note: Should be called while holding tree lock
0583: * @return true if there is at least one heavyweight children in a container, false otherwise
0584: * @since 1.5
0585: */
0586: private boolean hasHeavyweightChildren() {
0587: checkTreeLock();
0588: boolean res = true; // true while it is lightweight
0589: for (int i = 0; i < getComponentCount() && res; i++) {
0590: Component child = getComponent(i);
0591: res &= child.isLightweight();
0592: if (res && child instanceof Container) {
0593: res &= !((Container) child).hasHeavyweightChildren();
0594: }
0595: }
0596: return !res;
0597: }
0598:
0599: /**
0600: * Returns closest heavyweight component to this container. If this container is heavyweight
0601: * returns this.
0602: * @since 1.5
0603: */
0604: Container getHeavyweightContainer() {
0605: checkTreeLock();
0606: if (peer != null && !(peer instanceof LightweightPeer)) {
0607: return this ;
0608: } else {
0609: return getNativeContainer();
0610: }
0611: }
0612:
0613: /**
0614: * Detects whether or not remove from current parent and adding to new parent requires call of
0615: * removeNotify on the component. Since removeNotify destroys native window this might (not)
0616: * be required. For example, if new container and old containers are the same we don't need to
0617: * destroy native window.
0618: * @since: 1.5
0619: */
0620: private static boolean isRemoveNotifyNeeded(Component comp,
0621: Container oldContainer, Container newContainer) {
0622: if (oldContainer == null) { // Component didn't have parent - no removeNotify
0623: return false;
0624: }
0625: if (comp.peer == null) { // Component didn't have peer - no removeNotify
0626: return false;
0627: }
0628: if (newContainer.peer == null) {
0629: // Component has peer but new Container doesn't - call removeNotify
0630: return true;
0631: }
0632:
0633: // If component is lightweight non-Container or lightweight Container with all but heavyweight
0634: // children there is no need to call remove notify
0635: if (comp.isLightweight()) {
0636: if (comp instanceof Container) {
0637: // If it has heavyweight children then removeNotify is required
0638: return ((Container) comp).hasHeavyweightChildren();
0639: } else {
0640: // Just a lightweight
0641: return false;
0642: }
0643: }
0644:
0645: // All three components have peers, check for peer change
0646: Container newNativeContainer = oldContainer
0647: .getHeavyweightContainer();
0648: Container oldNativeContainer = newContainer
0649: .getHeavyweightContainer();
0650: if (newNativeContainer != oldNativeContainer) {
0651: // Native containers change - check whether or not current platform supports
0652: // changing of widget hierarchy on native level without recreation.
0653: return !comp.peer.isReparentSupported();
0654: } else {
0655: // if container didn't change we still might need to recreate component's window as
0656: // changes to zorder should be reflected in native window stacking order and it might
0657: // not be supported by the platform. This is important only for heavyweight child
0658: return !comp.isLightweight()
0659: && !((ContainerPeer) (newNativeContainer.peer))
0660: .isRestackSupported();
0661: }
0662: }
0663:
0664: /**
0665: * Moves the specified component to the specified z-order index in
0666: * the container. The z-order determines the order that components
0667: * are painted; the component with the highest z-order paints first
0668: * and the component with the lowest z-order paints last.
0669: * Where components overlap, the component with the lower
0670: * z-order paints over the component with the higher z-order.
0671: * <p>
0672: * If the component is a child of some other container, it is
0673: * removed from that container before being added to this container.
0674: * The important difference between this method and
0675: * <code>java.awt.Container.add(Component, int)</code> is that this method
0676: * doesn't call <code>removeNotify</code> on the component while
0677: * removing it from its previous container unless necessary and when
0678: * allowed by the underlying native windowing system. This way, if the
0679: * component has the keyboard focus, it maintains the focus when
0680: * moved to the new position.
0681: * <p>
0682: * This property is guaranteed to apply only to lightweight
0683: * non-<code>Container</code> components.
0684: * <p>
0685: * <b>Note</b>: Not all platforms support changing the z-order of
0686: * heavyweight components from one container into another without
0687: * the call to <code>removeNotify</code>. There is no way to detect
0688: * whether a platform supports this, so developers shouldn't make
0689: * any assumptions.
0690: *
0691: * @param comp the component to be moved
0692: * @param index the position in the container's list to
0693: * insert the component, where <code>getComponentCount()</code>
0694: * appends to the end
0695: * @exception NullPointerException if <code>comp</code> is
0696: * <code>null</code>
0697: * @exception IllegalArgumentException if <code>comp</code> is one of the
0698: * container's parents
0699: * @exception IllegalArgumentException if <code>index</code> is not in
0700: * the range <code>[0, getComponentCount()]</code> for moving
0701: * between containers, or not in the range
0702: * <code>[0, getComponentCount()-1]</code> for moving inside
0703: * a container
0704: * @exception IllegalArgumentException if adding a container to itself
0705: * @exception IllegalArgumentException if adding a <code>Window</code>
0706: * to a container
0707: * @see #getComponentZOrder(java.awt.Component)
0708: * @since 1.5
0709: */
0710: public void setComponentZOrder(Component comp, int index) {
0711: synchronized (getTreeLock()) {
0712: // Store parent because remove will clear it
0713: Container curParent = comp.parent;
0714: if (curParent == this && index == getComponentZOrder(comp)) {
0715: return;
0716: }
0717: checkAdding(comp, index);
0718: if (curParent != null) {
0719: curParent.removeDelicately(comp, this , index);
0720: }
0721:
0722: addDelicately(comp, curParent, index);
0723: }
0724: }
0725:
0726: /**
0727: * Traverses the tree of components and reparents children heavyweight component
0728: * to new heavyweight parent.
0729: * @since 1.5
0730: */
0731: private void reparentTraverse(ContainerPeer parentPeer,
0732: Container child) {
0733: checkTreeLock();
0734:
0735: for (int i = 0; i < child.getComponentCount(); i++) {
0736: Component comp = child.getComponent(i);
0737: if (comp.isLightweight()) {
0738: // If components is lightweight check if it is container
0739: // If it is container it might contain heavyweight children we need to reparent
0740: if (comp instanceof Container) {
0741: reparentTraverse(parentPeer, (Container) comp);
0742: }
0743: } else {
0744: // Q: Need to update NativeInLightFixer?
0745: comp.getPeer().reparent(parentPeer);
0746: }
0747: }
0748: }
0749:
0750: /**
0751: * Reparents child component peer to this container peer.
0752: * Container must be heavyweight.
0753: * @since 1.5
0754: */
0755: private void reparentChild(Component comp) {
0756: checkTreeLock();
0757: if (comp == null) {
0758: return;
0759: }
0760: if (comp.isLightweight()) {
0761: // If component is lightweight container we need to reparent all its explicit heavyweight children
0762: if (comp instanceof Container) {
0763: // Traverse component's tree till depth-first until encountering heavyweight component
0764: reparentTraverse((ContainerPeer) getPeer(),
0765: (Container) comp);
0766: }
0767: } else {
0768: comp.getPeer().reparent((ContainerPeer) getPeer());
0769: }
0770: }
0771:
0772: /**
0773: * Adds component to this container. Tries to minimize side effects of this adding -
0774: * doesn't call remove notify if it is not required.
0775: * @since 1.5
0776: */
0777: private void addDelicately(Component comp, Container curParent,
0778: int index) {
0779: checkTreeLock();
0780:
0781: // Check if moving between containers
0782: if (curParent != this ) {
0783: /* Add component to list; allocate new array if necessary. */
0784: if (ncomponents == component.length) {
0785: component = Arrays.copyOf(component,
0786: ncomponents * 2 + 1);
0787: }
0788: if (index == -1 || index == ncomponents) {
0789: component[ncomponents++] = comp;
0790: } else {
0791: System.arraycopy(component, index, component,
0792: index + 1, ncomponents - index);
0793: component[index] = comp;
0794: ncomponents++;
0795: }
0796: comp.parent = this ;
0797:
0798: adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK, comp
0799: .numListening(AWTEvent.HIERARCHY_EVENT_MASK));
0800: adjustListeningChildren(
0801: AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
0802: comp
0803: .numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
0804: adjustDescendants(comp.countHierarchyMembers());
0805: } else {
0806: if (index < ncomponents) {
0807: component[index] = comp;
0808: }
0809: }
0810:
0811: if (valid) {
0812: invalidate();
0813: }
0814: if (peer != null) {
0815: if (comp.peer == null) { // Remove notify was called or it didn't have peer - create new one
0816: comp.addNotify();
0817: // New created peer creates component on top of the stacking order
0818: Container newNativeContainer = getHeavyweightContainer();
0819: if (((ContainerPeer) newNativeContainer.getPeer())
0820: .isRestackSupported()) {
0821: ((ContainerPeer) newNativeContainer.getPeer())
0822: .restack();
0823: }
0824: } else { // Both container and child have peers, it means child peer should be reparented.
0825: // In both cases we need to reparent native widgets.
0826: Container newNativeContainer = getHeavyweightContainer();
0827: Container oldNativeContainer = curParent
0828: .getHeavyweightContainer();
0829: if (oldNativeContainer != newNativeContainer) {
0830: // Native container changed - need to reparent native widgets
0831: newNativeContainer.reparentChild(comp);
0832: }
0833: // If component still has a peer and it is either container or heavyweight
0834: // and restack is supported we have to restack native windows since order might have changed
0835: if ((!comp.isLightweight() || (comp instanceof Container))
0836: && ((ContainerPeer) newNativeContainer
0837: .getPeer()).isRestackSupported()) {
0838: ((ContainerPeer) newNativeContainer.getPeer())
0839: .restack();
0840: }
0841: if (!comp.isLightweight() && isLightweight()) {
0842: // If component is heavyweight and one of the containers is lightweight
0843: // some NativeInLightFixer activity should be performed
0844: if (!curParent.isLightweight()) {
0845: // Moving from heavyweight container to lightweight container - should create NativeInLightFixer
0846: // since addNotify does this
0847: comp.nativeInLightFixer = new NativeInLightFixer();
0848: } else {
0849: // Component already has NativeInLightFixer - just reinstall it
0850: // because hierarchy changed and he needs to rebuild list of parents to listen.
0851: comp.nativeInLightFixer.install(this );
0852: }
0853: }
0854: }
0855: }
0856: if (curParent != this ) {
0857: /* Notify the layout manager of the added component. */
0858: if (layoutMgr != null) {
0859: if (layoutMgr instanceof LayoutManager2) {
0860: ((LayoutManager2) layoutMgr).addLayoutComponent(
0861: comp, null);
0862: } else {
0863: layoutMgr.addLayoutComponent(null, comp);
0864: }
0865: }
0866: if (containerListener != null
0867: || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0
0868: || Toolkit
0869: .enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
0870: ContainerEvent e = new ContainerEvent(this ,
0871: ContainerEvent.COMPONENT_ADDED, comp);
0872: dispatchEvent(e);
0873: }
0874: comp
0875: .createHierarchyEvents(
0876: HierarchyEvent.HIERARCHY_CHANGED,
0877: comp,
0878: this ,
0879: HierarchyEvent.PARENT_CHANGED,
0880: Toolkit
0881: .enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
0882:
0883: // If component is focus owner or parent container of focus owner check that after reparenting
0884: // focus owner moved out if new container prohibit this kind of focus owner.
0885: if (comp.isFocusOwner() && !comp.canBeFocusOwner()) {
0886: comp.transferFocus();
0887: } else if (comp instanceof Container) {
0888: Component focusOwner = KeyboardFocusManager
0889: .getCurrentKeyboardFocusManager()
0890: .getFocusOwner();
0891: if (focusOwner != null && isParentOf(focusOwner)
0892: && !focusOwner.canBeFocusOwner()) {
0893: focusOwner.transferFocus();
0894: }
0895: }
0896: } else {
0897: comp
0898: .createHierarchyEvents(
0899: HierarchyEvent.HIERARCHY_CHANGED,
0900: comp,
0901: this ,
0902: HierarchyEvent.HIERARCHY_CHANGED,
0903: Toolkit
0904: .enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
0905: }
0906:
0907: if (peer != null && layoutMgr == null && isVisible()) {
0908: updateCursorImmediately();
0909: }
0910: }
0911:
0912: /**
0913: * Returns the z-order index of the component inside the container.
0914: * The higher a component is in the z-order hierarchy, the lower
0915: * its index. The component with the lowest z-order index is
0916: * painted last, above all other child components.
0917: *
0918: * @param comp the component being queried
0919: * @return the z-order index of the component; otherwise
0920: * returns -1 if the component is <code>null</code>
0921: * or doesn't belong to the container
0922: * @see #setComponentZOrder(java.awt.Component, int)
0923: * @since 1.5
0924: */
0925: public int getComponentZOrder(Component comp) {
0926: if (comp == null) {
0927: return -1;
0928: }
0929: synchronized (getTreeLock()) {
0930: // Quick check - container should be immediate parent of the component
0931: if (comp.parent != this ) {
0932: return -1;
0933: }
0934: for (int i = 0; i < ncomponents; i++) {
0935: if (component[i] == comp) {
0936: return i;
0937: }
0938: }
0939: }
0940: // To please javac
0941: return -1;
0942: }
0943:
0944: /**
0945: * Adds the specified component to the end of this container.
0946: * Also notifies the layout manager to add the component to
0947: * this container's layout using the specified constraints object.
0948: * This is a convenience method for {@link #addImpl}.
0949: * <p>
0950: * Note: If a component has been added to a container that
0951: * has been displayed, <code>validate</code> must be
0952: * called on that container to display the new component.
0953: * If multiple components are being added, you can improve
0954: * efficiency by calling <code>validate</code> only once,
0955: * after all the components have been added.
0956: *
0957: * @param comp the component to be added
0958: * @param constraints an object expressing
0959: * layout contraints for this component
0960: * @exception NullPointerException if {@code comp} is {@code null}
0961: * @see #addImpl
0962: * @see #validate
0963: * @see javax.swing.JComponent#revalidate()
0964: * @see LayoutManager
0965: * @since JDK1.1
0966: */
0967: public void add(Component comp, Object constraints) {
0968: addImpl(comp, constraints, -1);
0969: }
0970:
0971: /**
0972: * Adds the specified component to this container with the specified
0973: * constraints at the specified index. Also notifies the layout
0974: * manager to add the component to the this container's layout using
0975: * the specified constraints object.
0976: * This is a convenience method for {@link #addImpl}.
0977: * <p>
0978: * Note: If a component has been added to a container that
0979: * has been displayed, <code>validate</code> must be
0980: * called on that container to display the new component.
0981: * If multiple components are being added, you can improve
0982: * efficiency by calling <code>validate</code> only once,
0983: * after all the components have been added.
0984: *
0985: * @param comp the component to be added
0986: * @param constraints an object expressing layout contraints for this
0987: * @param index the position in the container's list at which to insert
0988: * the component; <code>-1</code> means insert at the end
0989: * component
0990: * @exception NullPointerException if {@code comp} is {@code null}
0991: * @exception IllegalArgumentException if {@code index} is invalid (see
0992: * {@link #addImpl} for details)
0993: * @see #addImpl
0994: * @see #validate
0995: * @see javax.swing.JComponent#revalidate()
0996: * @see #remove
0997: * @see LayoutManager
0998: */
0999: public void add(Component comp, Object constraints, int index) {
1000: addImpl(comp, constraints, index);
1001: }
1002:
1003: /**
1004: * Adds the specified component to this container at the specified
1005: * index. This method also notifies the layout manager to add
1006: * the component to this container's layout using the specified
1007: * constraints object via the <code>addLayoutComponent</code>
1008: * method.
1009: * <p>
1010: * The constraints are
1011: * defined by the particular layout manager being used. For
1012: * example, the <code>BorderLayout</code> class defines five
1013: * constraints: <code>BorderLayout.NORTH</code>,
1014: * <code>BorderLayout.SOUTH</code>, <code>BorderLayout.EAST</code>,
1015: * <code>BorderLayout.WEST</code>, and <code>BorderLayout.CENTER</code>.
1016: * <p>
1017: * The <code>GridBagLayout</code> class requires a
1018: * <code>GridBagConstraints</code> object. Failure to pass
1019: * the correct type of constraints object results in an
1020: * <code>IllegalArgumentException</code>.
1021: * <p>
1022: * If the current layout manager implements {@code LayoutManager2}, then
1023: * {@link LayoutManager2#addLayoutComponent(Component,Object)} is invoked on
1024: * it. If the current layout manager does not implement
1025: * {@code LayoutManager2}, and constraints is a {@code String}, then
1026: * {@link LayoutManager#addLayoutComponent(String,Component)} is invoked on it.
1027: * <p>
1028: * If the component is not an ancestor of this container and has a non-null
1029: * parent, it is removed from its current parent before it is added to this
1030: * container.
1031: * <p>
1032: * This is the method to override if a program needs to track
1033: * every add request to a container as all other add methods defer
1034: * to this one. An overriding method should
1035: * usually include a call to the superclass's version of the method:
1036: * <p>
1037: * <blockquote>
1038: * <code>super.addImpl(comp, constraints, index)</code>
1039: * </blockquote>
1040: * <p>
1041: * @param comp the component to be added
1042: * @param constraints an object expressing layout constraints
1043: * for this component
1044: * @param index the position in the container's list at which to
1045: * insert the component, where <code>-1</code>
1046: * means append to the end
1047: * @exception IllegalArgumentException if {@code index} is invalid;
1048: * if {@code comp} is a child of this container, the valid
1049: * range is {@code [-1, getComponentCount()-1]}; if component is
1050: * not a child of this container, the valid range is
1051: * {@code [-1, getComponentCount()]}
1052: *
1053: * @exception IllegalArgumentException if {@code comp} is an ancestor of
1054: * this container
1055: * @exception IllegalArgumentException if adding a window to a container
1056: * @exception NullPointerException if {@code comp} is {@code null}
1057: * @see #add(Component)
1058: * @see #add(Component, int)
1059: * @see #add(Component, java.lang.Object)
1060: * @see LayoutManager
1061: * @see LayoutManager2
1062: * @since JDK1.1
1063: */
1064: protected void addImpl(Component comp, Object constraints, int index) {
1065: synchronized (getTreeLock()) {
1066: /* Check for correct arguments: index in bounds,
1067: * comp cannot be one of this container's parents,
1068: * and comp cannot be a window.
1069: * comp and container must be on the same GraphicsDevice.
1070: * if comp is container, all sub-components must be on
1071: * same GraphicsDevice.
1072: */
1073: GraphicsConfiguration this GC = this
1074: .getGraphicsConfiguration();
1075:
1076: if (index > ncomponents || (index < 0 && index != -1)) {
1077: throw new IllegalArgumentException(
1078: "illegal component position");
1079: }
1080: if (comp instanceof Container) {
1081: for (Container cn = this ; cn != null; cn = cn.parent) {
1082: if (cn == comp) {
1083: throw new IllegalArgumentException(
1084: "adding container's parent to itself");
1085: }
1086: }
1087: if (comp instanceof Window) {
1088: throw new IllegalArgumentException(
1089: "adding a window to a container");
1090: }
1091: }
1092: if (this GC != null) {
1093: comp.checkGD(this GC.getDevice().getIDstring());
1094: }
1095:
1096: /* Reparent the component and tidy up the tree's state. */
1097: if (comp.parent != null) {
1098: comp.parent.remove(comp);
1099: if (index > ncomponents) {
1100: throw new IllegalArgumentException(
1101: "illegal component position");
1102: }
1103: }
1104:
1105: /* Add component to list; allocate new array if necessary. */
1106: if (ncomponents == component.length) {
1107: component = Arrays.copyOf(component,
1108: ncomponents * 2 + 1);
1109: }
1110: if (index == -1 || index == ncomponents) {
1111: component[ncomponents++] = comp;
1112: } else {
1113: System.arraycopy(component, index, component,
1114: index + 1, ncomponents - index);
1115: component[index] = comp;
1116: ncomponents++;
1117: }
1118: comp.parent = this ;
1119:
1120: adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK, comp
1121: .numListening(AWTEvent.HIERARCHY_EVENT_MASK));
1122: adjustListeningChildren(
1123: AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
1124: comp
1125: .numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
1126: adjustDescendants(comp.countHierarchyMembers());
1127:
1128: if (valid) {
1129: invalidate();
1130: }
1131: if (peer != null) {
1132: comp.addNotify();
1133: }
1134:
1135: /* Notify the layout manager of the added component. */
1136: if (layoutMgr != null) {
1137: if (layoutMgr instanceof LayoutManager2) {
1138: ((LayoutManager2) layoutMgr).addLayoutComponent(
1139: comp, constraints);
1140: } else if (constraints instanceof String) {
1141: layoutMgr.addLayoutComponent((String) constraints,
1142: comp);
1143: }
1144: }
1145: if (containerListener != null
1146: || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0
1147: || Toolkit
1148: .enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
1149: ContainerEvent e = new ContainerEvent(this ,
1150: ContainerEvent.COMPONENT_ADDED, comp);
1151: dispatchEvent(e);
1152: }
1153:
1154: comp
1155: .createHierarchyEvents(
1156: HierarchyEvent.HIERARCHY_CHANGED,
1157: comp,
1158: this ,
1159: HierarchyEvent.PARENT_CHANGED,
1160: Toolkit
1161: .enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
1162: if (peer != null && layoutMgr == null && isVisible()) {
1163: updateCursorImmediately();
1164: }
1165: }
1166: }
1167:
1168: /**
1169: * Checks that all Components that this Container contains are on
1170: * the same GraphicsDevice as this Container. If not, throws an
1171: * IllegalArgumentException.
1172: */
1173: void checkGD(String stringID) {
1174: Component tempComp;
1175: for (int i = 0; i < component.length; i++) {
1176: tempComp = component[i];
1177: if (tempComp != null) {
1178: tempComp.checkGD(stringID);
1179: }
1180: }
1181: }
1182:
1183: /**
1184: * Removes the component, specified by <code>index</code>,
1185: * from this container.
1186: * This method also notifies the layout manager to remove the
1187: * component from this container's layout via the
1188: * <code>removeLayoutComponent</code> method.
1189: *
1190: * <p>
1191: * Note: If a component has been removed from a container that
1192: * had been displayed, {@link #validate} must be
1193: * called on that container to reflect changes.
1194: * If multiple components are being removed, you can improve
1195: * efficiency by calling {@link #validate} only once,
1196: * after all the components have been removed.
1197: *
1198: * @param index the index of the component to be removed
1199: * @throws ArrayIndexOutOfBoundsException if {@code index} is not in
1200: * range {@code [0, getComponentCount()-1]}
1201: * @see #add
1202: * @see #validate
1203: * @see #getComponentCount
1204: * @since JDK1.1
1205: */
1206: public void remove(int index) {
1207: synchronized (getTreeLock()) {
1208: if (index < 0 || index >= ncomponents) {
1209: throw new ArrayIndexOutOfBoundsException(index);
1210: }
1211: Component comp = component[index];
1212: if (peer != null) {
1213: comp.removeNotify();
1214: }
1215: if (layoutMgr != null) {
1216: layoutMgr.removeLayoutComponent(comp);
1217: }
1218:
1219: adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
1220: -comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
1221: adjustListeningChildren(
1222: AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
1223: -comp
1224: .numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
1225: adjustDescendants(-(comp.countHierarchyMembers()));
1226:
1227: comp.parent = null;
1228: System.arraycopy(component, index + 1, component, index,
1229: ncomponents - index - 1);
1230: component[--ncomponents] = null;
1231:
1232: if (valid) {
1233: invalidate();
1234: }
1235: if (containerListener != null
1236: || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0
1237: || Toolkit
1238: .enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
1239: ContainerEvent e = new ContainerEvent(this ,
1240: ContainerEvent.COMPONENT_REMOVED, comp);
1241: dispatchEvent(e);
1242: }
1243:
1244: comp
1245: .createHierarchyEvents(
1246: HierarchyEvent.HIERARCHY_CHANGED,
1247: comp,
1248: this ,
1249: HierarchyEvent.PARENT_CHANGED,
1250: Toolkit
1251: .enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
1252: if (peer != null && layoutMgr == null && isVisible()) {
1253: updateCursorImmediately();
1254: }
1255: }
1256: }
1257:
1258: /**
1259: * Removes the specified component from this container.
1260: * This method also notifies the layout manager to remove the
1261: * component from this container's layout via the
1262: * <code>removeLayoutComponent</code> method.
1263: *
1264: * <p>
1265: * Note: If a component has been removed from a container that
1266: * had been displayed, {@link #validate} must be
1267: * called on that container to reflect changes.
1268: * If multiple components are being removed, you can improve
1269: * efficiency by calling {@link #validate} only once,
1270: * after all the components have been removed.
1271: *
1272: * @param comp the component to be removed
1273: * @see #add
1274: * @see #validate
1275: * @see #remove(int)
1276: */
1277: public void remove(Component comp) {
1278: synchronized (getTreeLock()) {
1279: if (comp.parent == this ) {
1280: /* Search backwards, expect that more recent additions
1281: * are more likely to be removed.
1282: */
1283: Component component[] = this .component;
1284: for (int i = ncomponents; --i >= 0;) {
1285: if (component[i] == comp) {
1286: remove(i);
1287: }
1288: }
1289: }
1290: }
1291: }
1292:
1293: /**
1294: * Removes all the components from this container.
1295: * This method also notifies the layout manager to remove the
1296: * components from this container's layout via the
1297: * <code>removeLayoutComponent</code> method.
1298: * @see #add
1299: * @see #remove
1300: */
1301: public void removeAll() {
1302: synchronized (getTreeLock()) {
1303: adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
1304: -listeningChildren);
1305: adjustListeningChildren(
1306: AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
1307: -listeningBoundsChildren);
1308: adjustDescendants(-descendantsCount);
1309:
1310: while (ncomponents > 0) {
1311: Component comp = component[--ncomponents];
1312: component[ncomponents] = null;
1313:
1314: if (peer != null) {
1315: comp.removeNotify();
1316: }
1317: if (layoutMgr != null) {
1318: layoutMgr.removeLayoutComponent(comp);
1319: }
1320: comp.parent = null;
1321: if (containerListener != null
1322: || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0
1323: || Toolkit
1324: .enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
1325: ContainerEvent e = new ContainerEvent(this ,
1326: ContainerEvent.COMPONENT_REMOVED, comp);
1327: dispatchEvent(e);
1328: }
1329:
1330: comp
1331: .createHierarchyEvents(
1332: HierarchyEvent.HIERARCHY_CHANGED,
1333: comp,
1334: this ,
1335: HierarchyEvent.PARENT_CHANGED,
1336: Toolkit
1337: .enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
1338: }
1339: if (peer != null && layoutMgr == null && isVisible()) {
1340: updateCursorImmediately();
1341: }
1342: if (valid) {
1343: invalidate();
1344: }
1345: }
1346: }
1347:
1348: // Should only be called while holding tree lock
1349: int numListening(long mask) {
1350: int super Listening = super .numListening(mask);
1351:
1352: if (mask == AWTEvent.HIERARCHY_EVENT_MASK) {
1353: if (dbg.on) {
1354: // Verify listeningChildren is correct
1355: int sum = 0;
1356: for (int i = 0; i < ncomponents; i++) {
1357: sum += component[i].numListening(mask);
1358: }
1359: dbg.assertion(listeningChildren == sum);
1360: }
1361: return listeningChildren + super Listening;
1362: } else if (mask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) {
1363: if (dbg.on) {
1364: // Verify listeningBoundsChildren is correct
1365: int sum = 0;
1366: for (int i = 0; i < ncomponents; i++) {
1367: sum += component[i].numListening(mask);
1368: }
1369: dbg.assertion(listeningBoundsChildren == sum);
1370: }
1371: return listeningBoundsChildren + super Listening;
1372: } else {
1373: if (dbg.on) {
1374: dbg.assertion(false);
1375: }
1376: return super Listening;
1377: }
1378: }
1379:
1380: // Should only be called while holding tree lock
1381: void adjustListeningChildren(long mask, int num) {
1382: if (dbg.on) {
1383: dbg
1384: .assertion(mask == AWTEvent.HIERARCHY_EVENT_MASK
1385: || mask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK
1386: || mask == (AWTEvent.HIERARCHY_EVENT_MASK | AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
1387: }
1388:
1389: if (num == 0)
1390: return;
1391:
1392: if ((mask & AWTEvent.HIERARCHY_EVENT_MASK) != 0) {
1393: listeningChildren += num;
1394: }
1395: if ((mask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0) {
1396: listeningBoundsChildren += num;
1397: }
1398:
1399: adjustListeningChildrenOnParent(mask, num);
1400: }
1401:
1402: // Should only be called while holding tree lock
1403: void adjustDescendants(int num) {
1404: if (num == 0)
1405: return;
1406:
1407: descendantsCount += num;
1408: adjustDecendantsOnParent(num);
1409: }
1410:
1411: // Should only be called while holding tree lock
1412: void adjustDecendantsOnParent(int num) {
1413: if (parent != null) {
1414: parent.adjustDescendants(num);
1415: }
1416: }
1417:
1418: // Should only be called while holding tree lock
1419: int countHierarchyMembers() {
1420: if (dbg.on) {
1421: // Verify descendantsCount is correct
1422: int sum = 0;
1423: for (int i = 0; i < ncomponents; i++) {
1424: sum += component[i].countHierarchyMembers();
1425: }
1426: dbg.assertion(descendantsCount == sum);
1427: }
1428: return descendantsCount + 1;
1429: }
1430:
1431: private int getListenersCount(int id, boolean enabledOnToolkit) {
1432: assert Thread.holdsLock(getTreeLock());
1433: if (enabledOnToolkit) {
1434: return descendantsCount;
1435: }
1436: switch (id) {
1437: case HierarchyEvent.HIERARCHY_CHANGED:
1438: return listeningChildren;
1439: case HierarchyEvent.ANCESTOR_MOVED:
1440: case HierarchyEvent.ANCESTOR_RESIZED:
1441: return listeningBoundsChildren;
1442: default:
1443: return 0;
1444: }
1445: }
1446:
1447: final int createHierarchyEvents(int id, Component changed,
1448: Container changedParent, long changeFlags,
1449: boolean enabledOnToolkit) {
1450: assert Thread.holdsLock(getTreeLock());
1451: int listeners = getListenersCount(id, enabledOnToolkit);
1452:
1453: for (int count = listeners, i = 0; count > 0; i++) {
1454: count -= component[i].createHierarchyEvents(id, changed,
1455: changedParent, changeFlags, enabledOnToolkit);
1456: }
1457: return listeners
1458: + super .createHierarchyEvents(id, changed,
1459: changedParent, changeFlags, enabledOnToolkit);
1460: }
1461:
1462: final void createChildHierarchyEvents(int id, long changeFlags,
1463: boolean enabledOnToolkit) {
1464: assert Thread.holdsLock(getTreeLock());
1465: if (ncomponents == 0) {
1466: return;
1467: }
1468: int listeners = getListenersCount(id, enabledOnToolkit);
1469:
1470: for (int count = listeners, i = 0; count > 0; i++) {
1471: count -= component[i].createHierarchyEvents(id, this ,
1472: parent, changeFlags, enabledOnToolkit);
1473: }
1474: }
1475:
1476: /**
1477: * Gets the layout manager for this container.
1478: * @see #doLayout
1479: * @see #setLayout
1480: */
1481: public LayoutManager getLayout() {
1482: return layoutMgr;
1483: }
1484:
1485: /**
1486: * Sets the layout manager for this container.
1487: * @param mgr the specified layout manager
1488: * @see #doLayout
1489: * @see #getLayout
1490: */
1491: public void setLayout(LayoutManager mgr) {
1492: layoutMgr = mgr;
1493: if (valid) {
1494: invalidate();
1495: }
1496: }
1497:
1498: /**
1499: * Causes this container to lay out its components. Most programs
1500: * should not call this method directly, but should invoke
1501: * the <code>validate</code> method instead.
1502: * @see LayoutManager#layoutContainer
1503: * @see #setLayout
1504: * @see #validate
1505: * @since JDK1.1
1506: */
1507: public void doLayout() {
1508: layout();
1509: }
1510:
1511: /**
1512: * @deprecated As of JDK version 1.1,
1513: * replaced by <code>doLayout()</code>.
1514: */
1515: @Deprecated
1516: public void layout() {
1517: LayoutManager layoutMgr = this .layoutMgr;
1518: if (layoutMgr != null) {
1519: layoutMgr.layoutContainer(this );
1520: }
1521: }
1522:
1523: /**
1524: * Invalidates the container. The container and all parents
1525: * above it are marked as needing to be laid out. This method can
1526: * be called often, so it needs to execute quickly.
1527: *
1528: * <p> If the {@code LayoutManager} installed on this container is
1529: * an instance of {@code LayoutManager2}, then
1530: * {@link LayoutManager2#invalidateLayout(Container)} is invoked on
1531: * it supplying this {@code Container} as the argument.
1532: *
1533: * @see #validate
1534: * @see #layout
1535: * @see LayoutManager
1536: * @see LayoutManager2#invalidateLayout(Container)
1537: */
1538: public void invalidate() {
1539: LayoutManager layoutMgr = this .layoutMgr;
1540: if (layoutMgr instanceof LayoutManager2) {
1541: LayoutManager2 lm = (LayoutManager2) layoutMgr;
1542: lm.invalidateLayout(this );
1543: }
1544: super .invalidate();
1545: }
1546:
1547: /**
1548: * Validates this container and all of its subcomponents.
1549: * <p>
1550: * The <code>validate</code> method is used to cause a container
1551: * to lay out its subcomponents again. It should be invoked when
1552: * this container's subcomponents are modified (added to or
1553: * removed from the container, or layout-related information
1554: * changed) after the container has been displayed.
1555: *
1556: * <p>If this {@code Container} is not valid, this method invokes
1557: * the {@code validateTree} method and marks this {@code Container}
1558: * as valid. Otherwise, no action is performed.
1559: *
1560: * @see #add(java.awt.Component)
1561: * @see Component#invalidate
1562: * @see javax.swing.JComponent#revalidate()
1563: * @see #validateTree
1564: */
1565: public void validate() {
1566: /* Avoid grabbing lock unless really necessary. */
1567: if (!valid) {
1568: boolean updateCur = false;
1569: synchronized (getTreeLock()) {
1570: if (!valid && peer != null) {
1571: ContainerPeer p = null;
1572: if (peer instanceof ContainerPeer) {
1573: p = (ContainerPeer) peer;
1574: }
1575: if (p != null) {
1576: p.beginValidate();
1577: }
1578: validateTree();
1579: valid = true;
1580: if (p != null) {
1581: p.endValidate();
1582: updateCur = isVisible();
1583: }
1584: }
1585: }
1586: if (updateCur) {
1587: updateCursorImmediately();
1588: }
1589: }
1590: }
1591:
1592: /**
1593: * Recursively descends the container tree and recomputes the
1594: * layout for any subtrees marked as needing it (those marked as
1595: * invalid). Synchronization should be provided by the method
1596: * that calls this one: <code>validate</code>.
1597: *
1598: * @see #doLayout
1599: * @see #validate
1600: */
1601: protected void validateTree() {
1602: if (!valid) {
1603: if (peer instanceof ContainerPeer) {
1604: ((ContainerPeer) peer).beginLayout();
1605: }
1606: doLayout();
1607: Component component[] = this .component;
1608: for (int i = 0; i < ncomponents; ++i) {
1609: Component comp = component[i];
1610: if ((comp instanceof Container)
1611: && !(comp instanceof Window) && !comp.valid) {
1612: ((Container) comp).validateTree();
1613: } else {
1614: comp.validate();
1615: }
1616: }
1617: if (peer instanceof ContainerPeer) {
1618: ((ContainerPeer) peer).endLayout();
1619: }
1620: }
1621: valid = true;
1622: }
1623:
1624: /**
1625: * Recursively descends the container tree and invalidates all
1626: * contained components.
1627: */
1628: void invalidateTree() {
1629: synchronized (getTreeLock()) {
1630: for (int i = 0; i < ncomponents; ++i) {
1631: Component comp = component[i];
1632: if (comp instanceof Container) {
1633: ((Container) comp).invalidateTree();
1634: } else {
1635: if (comp.valid) {
1636: comp.invalidate();
1637: }
1638: }
1639: }
1640: if (valid) {
1641: invalidate();
1642: }
1643: }
1644: }
1645:
1646: /**
1647: * Sets the font of this container.
1648: * @param f The font to become this container's font.
1649: * @see Component#getFont
1650: * @since JDK1.0
1651: */
1652: public void setFont(Font f) {
1653: boolean shouldinvalidate = false;
1654:
1655: Font oldfont = getFont();
1656: super .setFont(f);
1657: Font newfont = getFont();
1658: if (newfont != oldfont
1659: && (oldfont == null || !oldfont.equals(newfont))) {
1660: invalidateTree();
1661: }
1662: }
1663:
1664: /**
1665: * Returns the preferred size of this container. If the preferred size has
1666: * not been set explicitly by {@link Component#setPreferredSize(Dimension)}
1667: * and this {@code Container} has a {@code non-null} {@link LayoutManager},
1668: * then {@link LayoutManager#preferredLayoutSize(Container)}
1669: * is used to calculate the preferred size.
1670: *
1671: * <p>Note: some implementations may cache the value returned from the
1672: * {@code LayoutManager}. Implementations that cache need not invoke
1673: * {@code preferredLayoutSize} on the {@code LayoutManager} every time
1674: * this method is invoked, rather the {@code LayoutManager} will only
1675: * be queried after the {@code Container} becomes invalid.
1676: *
1677: * @return an instance of <code>Dimension</code> that represents
1678: * the preferred size of this container.
1679: * @see #getMinimumSize
1680: * @see #getMaximumSize
1681: * @see #getLayout
1682: * @see LayoutManager#preferredLayoutSize(Container)
1683: * @see Component#getPreferredSize
1684: */
1685: public Dimension getPreferredSize() {
1686: return preferredSize();
1687: }
1688:
1689: /**
1690: * @deprecated As of JDK version 1.1,
1691: * replaced by <code>getPreferredSize()</code>.
1692: */
1693: @Deprecated
1694: public Dimension preferredSize() {
1695: /* Avoid grabbing the lock if a reasonable cached size value
1696: * is available.
1697: */
1698: Dimension dim = prefSize;
1699: if (dim == null || !(isPreferredSizeSet() || isValid())) {
1700: synchronized (getTreeLock()) {
1701: prefSize = (layoutMgr != null) ? layoutMgr
1702: .preferredLayoutSize(this ) : super
1703: .preferredSize();
1704: dim = prefSize;
1705: }
1706: }
1707: if (dim != null) {
1708: return new Dimension(dim);
1709: } else {
1710: return dim;
1711: }
1712: }
1713:
1714: /**
1715: * Returns the minimum size of this container. If the minimum size has
1716: * not been set explicitly by {@link Component#setMinimumSize(Dimension)}
1717: * and this {@code Container} has a {@code non-null} {@link LayoutManager},
1718: * then {@link LayoutManager#minimumLayoutSize(Container)}
1719: * is used to calculate the minimum size.
1720: *
1721: * <p>Note: some implementations may cache the value returned from the
1722: * {@code LayoutManager}. Implementations that cache need not invoke
1723: * {@code minimumLayoutSize} on the {@code LayoutManager} every time
1724: * this method is invoked, rather the {@code LayoutManager} will only
1725: * be queried after the {@code Container} becomes invalid.
1726: *
1727: * @return an instance of <code>Dimension</code> that represents
1728: * the minimum size of this container.
1729: * @see #getPreferredSize
1730: * @see #getMaximumSize
1731: * @see #getLayout
1732: * @see LayoutManager#minimumLayoutSize(Container)
1733: * @see Component#getMinimumSize
1734: * @since JDK1.1
1735: */
1736: public Dimension getMinimumSize() {
1737: return minimumSize();
1738: }
1739:
1740: /**
1741: * @deprecated As of JDK version 1.1,
1742: * replaced by <code>getMinimumSize()</code>.
1743: */
1744: @Deprecated
1745: public Dimension minimumSize() {
1746: /* Avoid grabbing the lock if a reasonable cached size value
1747: * is available.
1748: */
1749: Dimension dim = minSize;
1750: if (dim == null || !(isMinimumSizeSet() || isValid())) {
1751: synchronized (getTreeLock()) {
1752: minSize = (layoutMgr != null) ? layoutMgr
1753: .minimumLayoutSize(this ) : super .minimumSize();
1754: dim = minSize;
1755: }
1756: }
1757: if (dim != null) {
1758: return new Dimension(dim);
1759: } else {
1760: return dim;
1761: }
1762: }
1763:
1764: /**
1765: * Returns the maximum size of this container. If the maximum size has
1766: * not been set explicitly by {@link Component#setMaximumSize(Dimension)}
1767: * and the {@link LayoutManager} installed on this {@code Container}
1768: * is an instance of {@link LayoutManager2}, then
1769: * {@link LayoutManager2#maximumLayoutSize(Container)}
1770: * is used to calculate the maximum size.
1771: *
1772: * <p>Note: some implementations may cache the value returned from the
1773: * {@code LayoutManager2}. Implementations that cache need not invoke
1774: * {@code maximumLayoutSize} on the {@code LayoutManager2} every time
1775: * this method is invoked, rather the {@code LayoutManager2} will only
1776: * be queried after the {@code Container} becomes invalid.
1777: *
1778: * @return an instance of <code>Dimension</code> that represents
1779: * the maximum size of this container.
1780: * @see #getPreferredSize
1781: * @see #getMinimumSize
1782: * @see #getLayout
1783: * @see LayoutManager2#maximumLayoutSize(Container)
1784: * @see Component#getMaximumSize
1785: */
1786: public Dimension getMaximumSize() {
1787: /* Avoid grabbing the lock if a reasonable cached size value
1788: * is available.
1789: */
1790: Dimension dim = maxSize;
1791: if (dim == null || !(isMaximumSizeSet() || isValid())) {
1792: synchronized (getTreeLock()) {
1793: if (layoutMgr instanceof LayoutManager2) {
1794: LayoutManager2 lm = (LayoutManager2) layoutMgr;
1795: maxSize = lm.maximumLayoutSize(this );
1796: } else {
1797: maxSize = super .getMaximumSize();
1798: }
1799: dim = maxSize;
1800: }
1801: }
1802: if (dim != null) {
1803: return new Dimension(dim);
1804: } else {
1805: return dim;
1806: }
1807: }
1808:
1809: /**
1810: * Returns the alignment along the x axis. This specifies how
1811: * the component would like to be aligned relative to other
1812: * components. The value should be a number between 0 and 1
1813: * where 0 represents alignment along the origin, 1 is aligned
1814: * the furthest away from the origin, 0.5 is centered, etc.
1815: */
1816: public float getAlignmentX() {
1817: float xAlign;
1818: if (layoutMgr instanceof LayoutManager2) {
1819: synchronized (getTreeLock()) {
1820: LayoutManager2 lm = (LayoutManager2) layoutMgr;
1821: xAlign = lm.getLayoutAlignmentX(this );
1822: }
1823: } else {
1824: xAlign = super .getAlignmentX();
1825: }
1826: return xAlign;
1827: }
1828:
1829: /**
1830: * Returns the alignment along the y axis. This specifies how
1831: * the component would like to be aligned relative to other
1832: * components. The value should be a number between 0 and 1
1833: * where 0 represents alignment along the origin, 1 is aligned
1834: * the furthest away from the origin, 0.5 is centered, etc.
1835: */
1836: public float getAlignmentY() {
1837: float yAlign;
1838: if (layoutMgr instanceof LayoutManager2) {
1839: synchronized (getTreeLock()) {
1840: LayoutManager2 lm = (LayoutManager2) layoutMgr;
1841: yAlign = lm.getLayoutAlignmentY(this );
1842: }
1843: } else {
1844: yAlign = super .getAlignmentY();
1845: }
1846: return yAlign;
1847: }
1848:
1849: /**
1850: * Paints the container. This forwards the paint to any lightweight
1851: * components that are children of this container. If this method is
1852: * reimplemented, super.paint(g) should be called so that lightweight
1853: * components are properly rendered. If a child component is entirely
1854: * clipped by the current clipping setting in g, paint() will not be
1855: * forwarded to that child.
1856: *
1857: * @param g the specified Graphics window
1858: * @see Component#update(Graphics)
1859: */
1860: public void paint(Graphics g) {
1861: if (isShowing()) {
1862: synchronized (this ) {
1863: if (printing) {
1864: if (printingThreads
1865: .contains(Thread.currentThread())) {
1866: return;
1867: }
1868: }
1869: }
1870:
1871: // The container is showing on screen and
1872: // this paint() is not called from print().
1873: // Paint self and forward the paint to lightweight subcomponents.
1874:
1875: // super.paint(); -- Don't bother, since it's a NOP.
1876:
1877: GraphicsCallback.PaintCallback.getInstance().runComponents(
1878: component, g, GraphicsCallback.LIGHTWEIGHTS);
1879: }
1880: }
1881:
1882: /**
1883: * Updates the container. This forwards the update to any lightweight
1884: * components that are children of this container. If this method is
1885: * reimplemented, super.update(g) should be called so that lightweight
1886: * components are properly rendered. If a child component is entirely
1887: * clipped by the current clipping setting in g, update() will not be
1888: * forwarded to that child.
1889: *
1890: * @param g the specified Graphics window
1891: * @see Component#update(Graphics)
1892: */
1893: public void update(Graphics g) {
1894: if (isShowing()) {
1895: if (!(peer instanceof LightweightPeer)) {
1896: g.clearRect(0, 0, width, height);
1897: }
1898: paint(g);
1899: }
1900: }
1901:
1902: /**
1903: * Prints the container. This forwards the print to any lightweight
1904: * components that are children of this container. If this method is
1905: * reimplemented, super.print(g) should be called so that lightweight
1906: * components are properly rendered. If a child component is entirely
1907: * clipped by the current clipping setting in g, print() will not be
1908: * forwarded to that child.
1909: *
1910: * @param g the specified Graphics window
1911: * @see Component#update(Graphics)
1912: */
1913: public void print(Graphics g) {
1914: if (isShowing()) {
1915: Thread t = Thread.currentThread();
1916: try {
1917: synchronized (this ) {
1918: if (printingThreads == null) {
1919: printingThreads = new HashSet();
1920: }
1921: printingThreads.add(t);
1922: printing = true;
1923: }
1924: super .print(g); // By default, Component.print() calls paint()
1925: } finally {
1926: synchronized (this ) {
1927: printingThreads.remove(t);
1928: printing = !printingThreads.isEmpty();
1929: }
1930: }
1931:
1932: GraphicsCallback.PrintCallback.getInstance().runComponents(
1933: component, g, GraphicsCallback.LIGHTWEIGHTS);
1934: }
1935: }
1936:
1937: /**
1938: * Paints each of the components in this container.
1939: * @param g the graphics context.
1940: * @see Component#paint
1941: * @see Component#paintAll
1942: */
1943: public void paintComponents(Graphics g) {
1944: if (isShowing()) {
1945: GraphicsCallback.PaintAllCallback.getInstance()
1946: .runComponents(component, g,
1947: GraphicsCallback.TWO_PASSES);
1948: }
1949: }
1950:
1951: /**
1952: * Simulates the peer callbacks into java.awt for printing of
1953: * lightweight Containers.
1954: * @param g the graphics context to use for printing.
1955: * @see Component#printAll
1956: * @see #printComponents
1957: */
1958: void lightweightPaint(Graphics g) {
1959: super .lightweightPaint(g);
1960: paintHeavyweightComponents(g);
1961: }
1962:
1963: /**
1964: * Prints all the heavyweight subcomponents.
1965: */
1966: void paintHeavyweightComponents(Graphics g) {
1967: if (isShowing()) {
1968: GraphicsCallback.PaintHeavyweightComponentsCallback
1969: .getInstance().runComponents(
1970: component,
1971: g,
1972: GraphicsCallback.LIGHTWEIGHTS
1973: | GraphicsCallback.HEAVYWEIGHTS);
1974: }
1975: }
1976:
1977: /**
1978: * Prints each of the components in this container.
1979: * @param g the graphics context.
1980: * @see Component#print
1981: * @see Component#printAll
1982: */
1983: public void printComponents(Graphics g) {
1984: if (isShowing()) {
1985: GraphicsCallback.PrintAllCallback.getInstance()
1986: .runComponents(component, g,
1987: GraphicsCallback.TWO_PASSES);
1988: }
1989: }
1990:
1991: /**
1992: * Simulates the peer callbacks into java.awt for printing of
1993: * lightweight Containers.
1994: * @param g the graphics context to use for printing.
1995: * @see Component#printAll
1996: * @see #printComponents
1997: */
1998: void lightweightPrint(Graphics g) {
1999: super .lightweightPrint(g);
2000: printHeavyweightComponents(g);
2001: }
2002:
2003: /**
2004: * Prints all the heavyweight subcomponents.
2005: */
2006: void printHeavyweightComponents(Graphics g) {
2007: if (isShowing()) {
2008: GraphicsCallback.PrintHeavyweightComponentsCallback
2009: .getInstance().runComponents(
2010: component,
2011: g,
2012: GraphicsCallback.LIGHTWEIGHTS
2013: | GraphicsCallback.HEAVYWEIGHTS);
2014: }
2015: }
2016:
2017: /**
2018: * Adds the specified container listener to receive container events
2019: * from this container.
2020: * If l is null, no exception is thrown and no action is performed.
2021: * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
2022: * >AWT Threading Issues</a> for details on AWT's threading model.
2023: *
2024: * @param l the container listener
2025: *
2026: * @see #removeContainerListener
2027: * @see #getContainerListeners
2028: */
2029: public synchronized void addContainerListener(ContainerListener l) {
2030: if (l == null) {
2031: return;
2032: }
2033: containerListener = AWTEventMulticaster.add(containerListener,
2034: l);
2035: newEventsOnly = true;
2036: }
2037:
2038: /**
2039: * Removes the specified container listener so it no longer receives
2040: * container events from this container.
2041: * If l is null, no exception is thrown and no action is performed.
2042: * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
2043: * >AWT Threading Issues</a> for details on AWT's threading model.
2044: *
2045: * @param l the container listener
2046: *
2047: * @see #addContainerListener
2048: * @see #getContainerListeners
2049: */
2050: public synchronized void removeContainerListener(ContainerListener l) {
2051: if (l == null) {
2052: return;
2053: }
2054: containerListener = AWTEventMulticaster.remove(
2055: containerListener, l);
2056: }
2057:
2058: /**
2059: * Returns an array of all the container listeners
2060: * registered on this container.
2061: *
2062: * @return all of this container's <code>ContainerListener</code>s
2063: * or an empty array if no container
2064: * listeners are currently registered
2065: *
2066: * @see #addContainerListener
2067: * @see #removeContainerListener
2068: * @since 1.4
2069: */
2070: public synchronized ContainerListener[] getContainerListeners() {
2071: return (ContainerListener[]) (getListeners(ContainerListener.class));
2072: }
2073:
2074: /**
2075: * Returns an array of all the objects currently registered
2076: * as <code><em>Foo</em>Listener</code>s
2077: * upon this <code>Container</code>.
2078: * <code><em>Foo</em>Listener</code>s are registered using the
2079: * <code>add<em>Foo</em>Listener</code> method.
2080: *
2081: * <p>
2082: * You can specify the <code>listenerType</code> argument
2083: * with a class literal, such as
2084: * <code><em>Foo</em>Listener.class</code>.
2085: * For example, you can query a
2086: * <code>Container</code> <code>c</code>
2087: * for its container listeners with the following code:
2088: *
2089: * <pre>ContainerListener[] cls = (ContainerListener[])(c.getListeners(ContainerListener.class));</pre>
2090: *
2091: * If no such listeners exist, this method returns an empty array.
2092: *
2093: * @param listenerType the type of listeners requested; this parameter
2094: * should specify an interface that descends from
2095: * <code>java.util.EventListener</code>
2096: * @return an array of all objects registered as
2097: * <code><em>Foo</em>Listener</code>s on this container,
2098: * or an empty array if no such listeners have been added
2099: * @exception ClassCastException if <code>listenerType</code>
2100: * doesn't specify a class or interface that implements
2101: * <code>java.util.EventListener</code>
2102: *
2103: * @see #getContainerListeners
2104: *
2105: * @since 1.3
2106: */
2107: public <T extends EventListener> T[] getListeners(
2108: Class<T> listenerType) {
2109: EventListener l = null;
2110: if (listenerType == ContainerListener.class) {
2111: l = containerListener;
2112: } else {
2113: return super .getListeners(listenerType);
2114: }
2115: return AWTEventMulticaster.getListeners(l, listenerType);
2116: }
2117:
2118: // REMIND: remove when filtering is done at lower level
2119: boolean eventEnabled(AWTEvent e) {
2120: int id = e.getID();
2121:
2122: if (id == ContainerEvent.COMPONENT_ADDED
2123: || id == ContainerEvent.COMPONENT_REMOVED) {
2124: if ((eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0
2125: || containerListener != null) {
2126: return true;
2127: }
2128: return false;
2129: }
2130: return super .eventEnabled(e);
2131: }
2132:
2133: /**
2134: * Processes events on this container. If the event is a
2135: * <code>ContainerEvent</code>, it invokes the
2136: * <code>processContainerEvent</code> method, else it invokes
2137: * its superclass's <code>processEvent</code>.
2138: * <p>Note that if the event parameter is <code>null</code>
2139: * the behavior is unspecified and may result in an
2140: * exception.
2141: *
2142: * @param e the event
2143: */
2144: protected void processEvent(AWTEvent e) {
2145: if (e instanceof ContainerEvent) {
2146: processContainerEvent((ContainerEvent) e);
2147: return;
2148: }
2149: super .processEvent(e);
2150: }
2151:
2152: /**
2153: * Processes container events occurring on this container by
2154: * dispatching them to any registered ContainerListener objects.
2155: * NOTE: This method will not be called unless container events
2156: * are enabled for this component; this happens when one of the
2157: * following occurs:
2158: * <ul>
2159: * <li>A ContainerListener object is registered via
2160: * <code>addContainerListener</code>
2161: * <li>Container events are enabled via <code>enableEvents</code>
2162: * </ul>
2163: * <p>Note that if the event parameter is <code>null</code>
2164: * the behavior is unspecified and may result in an
2165: * exception.
2166: *
2167: * @param e the container event
2168: * @see Component#enableEvents
2169: */
2170: protected void processContainerEvent(ContainerEvent e) {
2171: ContainerListener listener = containerListener;
2172: if (listener != null) {
2173: switch (e.getID()) {
2174: case ContainerEvent.COMPONENT_ADDED:
2175: listener.componentAdded(e);
2176: break;
2177: case ContainerEvent.COMPONENT_REMOVED:
2178: listener.componentRemoved(e);
2179: break;
2180: }
2181: }
2182: }
2183:
2184: /*
2185: * Dispatches an event to this component or one of its sub components.
2186: * Create ANCESTOR_RESIZED and ANCESTOR_MOVED events in response to
2187: * COMPONENT_RESIZED and COMPONENT_MOVED events. We have to do this
2188: * here instead of in processComponentEvent because ComponentEvents
2189: * may not be enabled for this Container.
2190: * @param e the event
2191: */
2192: void dispatchEventImpl(AWTEvent e) {
2193: if ((dispatcher != null) && dispatcher.dispatchEvent(e)) {
2194: // event was sent to a lightweight component. The
2195: // native-produced event sent to the native container
2196: // must be properly disposed of by the peer, so it
2197: // gets forwarded. If the native host has been removed
2198: // as a result of the sending the lightweight event,
2199: // the peer reference will be null.
2200: e.consume();
2201: if (peer != null) {
2202: peer.handleEvent(e);
2203: }
2204: return;
2205: }
2206:
2207: super .dispatchEventImpl(e);
2208:
2209: synchronized (getTreeLock()) {
2210: switch (e.getID()) {
2211: case ComponentEvent.COMPONENT_RESIZED:
2212: createChildHierarchyEvents(
2213: HierarchyEvent.ANCESTOR_RESIZED,
2214: 0,
2215: Toolkit
2216: .enabledOnToolkit(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
2217: break;
2218: case ComponentEvent.COMPONENT_MOVED:
2219: createChildHierarchyEvents(
2220: HierarchyEvent.ANCESTOR_MOVED,
2221: 0,
2222: Toolkit
2223: .enabledOnToolkit(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
2224: break;
2225: default:
2226: break;
2227: }
2228: }
2229: }
2230:
2231: /*
2232: * Dispatches an event to this component, without trying to forward
2233: * it to any subcomponents
2234: * @param e the event
2235: */
2236: void dispatchEventToSelf(AWTEvent e) {
2237: super .dispatchEventImpl(e);
2238: }
2239:
2240: /**
2241: * Fetchs the top-most (deepest) lightweight component that is interested
2242: * in receiving mouse events.
2243: */
2244: Component getMouseEventTarget(int x, int y, boolean includeSelf) {
2245: return getMouseEventTarget(x, y, includeSelf,
2246: MouseEventTargetFilter.FILTER, !SEARCH_HEAVYWEIGHTS);
2247: }
2248:
2249: /**
2250: * Fetches the top-most (deepest) component to receive SunDropTargetEvents.
2251: */
2252: Component getDropTargetEventTarget(int x, int y, boolean includeSelf) {
2253: return getMouseEventTarget(x, y, includeSelf,
2254: DropTargetEventTargetFilter.FILTER, SEARCH_HEAVYWEIGHTS);
2255: }
2256:
2257: /**
2258: * A private version of getMouseEventTarget which has two additional
2259: * controllable behaviors. This method searches for the top-most
2260: * descendant of this container that contains the given coordinates
2261: * and is accepted by the given filter. The search will be constrained to
2262: * lightweight descendants if the last argument is <code>false</code>.
2263: *
2264: * @param filter EventTargetFilter instance to determine whether the
2265: * given component is a valid target for this event.
2266: * @param searchHeavyweights if <code>false</code>, the method
2267: * will bypass heavyweight components during the search.
2268: */
2269: private Component getMouseEventTarget(int x, int y,
2270: boolean includeSelf, EventTargetFilter filter,
2271: boolean searchHeavyweights) {
2272: Component comp = null;
2273: if (searchHeavyweights) {
2274: comp = getMouseEventTargetImpl(x, y, includeSelf, filter,
2275: SEARCH_HEAVYWEIGHTS, searchHeavyweights);
2276: }
2277:
2278: if (comp == null || comp == this ) {
2279: comp = getMouseEventTargetImpl(x, y, includeSelf, filter,
2280: !SEARCH_HEAVYWEIGHTS, searchHeavyweights);
2281: }
2282:
2283: return comp;
2284: }
2285:
2286: /**
2287: * A private version of getMouseEventTarget which has three additional
2288: * controllable behaviors. This method searches for the top-most
2289: * descendant of this container that contains the given coordinates
2290: * and is accepted by the given filter. The search will be constrained to
2291: * descendants of only lightweight children or only heavyweight children
2292: * of this container depending on searchHeavyweightChildren. The search will
2293: * be constrained to only lightweight descendants of the searched children
2294: * of this container if searchHeavyweightDescendants is <code>false</code>.
2295: *
2296: * @param filter EventTargetFilter instance to determine whether the
2297: * selected component is a valid target for this event.
2298: * @param searchHeavyweightChildren if <code>true</code>, the method
2299: * will bypass immediate lightweight children during the search.
2300: * If <code>false</code>, the methods will bypass immediate
2301: * heavyweight children during the search.
2302: * @param searchHeavyweightDescendants if <code>false</code>, the method
2303: * will bypass heavyweight descendants which are not immediate
2304: * children during the search. If <code>true</code>, the method
2305: * will traverse both lightweight and heavyweight descendants during
2306: * the search.
2307: */
2308: private Component getMouseEventTargetImpl(int x, int y,
2309: boolean includeSelf, EventTargetFilter filter,
2310: boolean searchHeavyweightChildren,
2311: boolean searchHeavyweightDescendants) {
2312: int ncomponents = this .ncomponents;
2313: Component component[] = this .component;
2314:
2315: for (int i = 0; i < ncomponents; i++) {
2316: Component comp = component[i];
2317: if (comp != null
2318: && comp.visible
2319: && ((!searchHeavyweightChildren && comp.peer instanceof LightweightPeer) || (searchHeavyweightChildren && !(comp.peer instanceof LightweightPeer)))
2320: && comp.contains(x - comp.x, y - comp.y)) {
2321:
2322: // found a component that intersects the point, see if there is
2323: // a deeper possibility.
2324: if (comp instanceof Container) {
2325: Container child = (Container) comp;
2326: Component deeper = child.getMouseEventTarget(x
2327: - child.x, y - child.y, includeSelf,
2328: filter, searchHeavyweightDescendants);
2329: if (deeper != null) {
2330: return deeper;
2331: }
2332: } else {
2333: if (filter.accept(comp)) {
2334: // there isn't a deeper target, but this component is a
2335: // target
2336: return comp;
2337: }
2338: }
2339: }
2340: }
2341:
2342: boolean isPeerOK;
2343: boolean isMouseOverMe;
2344:
2345: isPeerOK = (peer instanceof LightweightPeer) || includeSelf;
2346: isMouseOverMe = contains(x, y);
2347:
2348: // didn't find a child target, return this component if it's a possible
2349: // target
2350: if (isMouseOverMe && isPeerOK && filter.accept(this )) {
2351: return this ;
2352: }
2353: // no possible target
2354: return null;
2355: }
2356:
2357: static interface EventTargetFilter {
2358: boolean accept(final Component comp);
2359: }
2360:
2361: static class MouseEventTargetFilter implements EventTargetFilter {
2362: static final EventTargetFilter FILTER = new MouseEventTargetFilter();
2363:
2364: private MouseEventTargetFilter() {
2365: }
2366:
2367: public boolean accept(final Component comp) {
2368: return (comp.eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0
2369: || (comp.eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0
2370: || (comp.eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0
2371: || comp.mouseListener != null
2372: || comp.mouseMotionListener != null
2373: || comp.mouseWheelListener != null;
2374: }
2375: }
2376:
2377: static class DropTargetEventTargetFilter implements
2378: EventTargetFilter {
2379: static final EventTargetFilter FILTER = new DropTargetEventTargetFilter();
2380:
2381: private DropTargetEventTargetFilter() {
2382: }
2383:
2384: public boolean accept(final Component comp) {
2385: DropTarget dt = comp.getDropTarget();
2386: return dt != null && dt.isActive();
2387: }
2388: }
2389:
2390: /**
2391: * This is called by lightweight components that want the containing
2392: * windowed parent to enable some kind of events on their behalf.
2393: * This is needed for events that are normally only dispatched to
2394: * windows to be accepted so that they can be forwarded downward to
2395: * the lightweight component that has enabled them.
2396: */
2397: void proxyEnableEvents(long events) {
2398: if (peer instanceof LightweightPeer) {
2399: // this container is lightweight.... continue sending it
2400: // upward.
2401: if (parent != null) {
2402: parent.proxyEnableEvents(events);
2403: }
2404: } else {
2405: // This is a native container, so it needs to host
2406: // one of it's children. If this function is called before
2407: // a peer has been created we don't yet have a dispatcher
2408: // because it has not yet been determined if this instance
2409: // is lightweight.
2410: if (dispatcher != null) {
2411: dispatcher.enableEvents(events);
2412: }
2413: }
2414: }
2415:
2416: /**
2417: * @deprecated As of JDK version 1.1,
2418: * replaced by <code>dispatchEvent(AWTEvent e)</code>
2419: */
2420: @Deprecated
2421: public void deliverEvent(Event e) {
2422: Component comp = getComponentAt(e.x, e.y);
2423: if ((comp != null) && (comp != this )) {
2424: e.translate(-comp.x, -comp.y);
2425: comp.deliverEvent(e);
2426: } else {
2427: postEvent(e);
2428: }
2429: }
2430:
2431: /**
2432: * Locates the component that contains the x,y position. The
2433: * top-most child component is returned in the case where there
2434: * is overlap in the components. This is determined by finding
2435: * the component closest to the index 0 that claims to contain
2436: * the given point via Component.contains(), except that Components
2437: * which have native peers take precedence over those which do not
2438: * (i.e., lightweight Components).
2439: *
2440: * @param x the <i>x</i> coordinate
2441: * @param y the <i>y</i> coordinate
2442: * @return null if the component does not contain the position.
2443: * If there is no child component at the requested point and the
2444: * point is within the bounds of the container the container itself
2445: * is returned; otherwise the top-most child is returned.
2446: * @see Component#contains
2447: * @since JDK1.1
2448: */
2449: public Component getComponentAt(int x, int y) {
2450: return locate(x, y);
2451: }
2452:
2453: /**
2454: * @deprecated As of JDK version 1.1,
2455: * replaced by <code>getComponentAt(int, int)</code>.
2456: */
2457: @Deprecated
2458: public Component locate(int x, int y) {
2459: if (!contains(x, y)) {
2460: return null;
2461: }
2462: synchronized (getTreeLock()) {
2463: // Two passes: see comment in sun.awt.SunGraphicsCallback
2464: for (int i = 0; i < ncomponents; i++) {
2465: Component comp = component[i];
2466: if (comp != null
2467: && !(comp.peer instanceof LightweightPeer)) {
2468: if (comp.contains(x - comp.x, y - comp.y)) {
2469: return comp;
2470: }
2471: }
2472: }
2473: for (int i = 0; i < ncomponents; i++) {
2474: Component comp = component[i];
2475: if (comp != null
2476: && comp.peer instanceof LightweightPeer) {
2477: if (comp.contains(x - comp.x, y - comp.y)) {
2478: return comp;
2479: }
2480: }
2481: }
2482: }
2483: return this ;
2484: }
2485:
2486: /**
2487: * Gets the component that contains the specified point.
2488: * @param p the point.
2489: * @return returns the component that contains the point,
2490: * or <code>null</code> if the component does
2491: * not contain the point.
2492: * @see Component#contains
2493: * @since JDK1.1
2494: */
2495: public Component getComponentAt(Point p) {
2496: return getComponentAt(p.x, p.y);
2497: }
2498:
2499: /**
2500: * Returns the position of the mouse pointer in this <code>Container</code>'s
2501: * coordinate space if the <code>Container</code> is under the mouse pointer,
2502: * otherwise returns <code>null</code>.
2503: * This method is similar to {@link Component#getMousePosition()} with the exception
2504: * that it can take the <code>Container</code>'s children into account.
2505: * If <code>allowChildren</code> is <code>false</code>, this method will return
2506: * a non-null value only if the mouse pointer is above the <code>Container</code>
2507: * directly, not above the part obscured by children.
2508: * If <code>allowChildren</code> is <code>true</code>, this method returns
2509: * a non-null value if the mouse pointer is above <code>Container</code> or any
2510: * of its descendants.
2511: *
2512: * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true
2513: * @param allowChildren true if children should be taken into account
2514: * @see Component#getMousePosition
2515: * @return mouse coordinates relative to this <code>Component</code>, or null
2516: * @since 1.5
2517: */
2518: public Point getMousePosition(boolean allowChildren)
2519: throws HeadlessException {
2520: if (GraphicsEnvironment.isHeadless()) {
2521: throw new HeadlessException();
2522: }
2523: PointerInfo pi = (PointerInfo) java.security.AccessController
2524: .doPrivileged(new java.security.PrivilegedAction() {
2525: public Object run() {
2526: return MouseInfo.getPointerInfo();
2527: }
2528: });
2529: synchronized (getTreeLock()) {
2530: Component inTheSameWindow = findUnderMouseInWindow(pi);
2531: if (isSameOrAncestorOf(inTheSameWindow, allowChildren)) {
2532: return pointRelativeToComponent(pi.getLocation());
2533: }
2534: return null;
2535: }
2536: }
2537:
2538: boolean isSameOrAncestorOf(Component comp, boolean allowChildren) {
2539: return this == comp || (allowChildren && isParentOf(comp));
2540: }
2541:
2542: /**
2543: * Locates the visible child component that contains the specified
2544: * position. The top-most child component is returned in the case
2545: * where there is overlap in the components. If the containing child
2546: * component is a Container, this method will continue searching for
2547: * the deepest nested child component. Components which are not
2548: * visible are ignored during the search.<p>
2549: *
2550: * The findComponentAt method is different from getComponentAt in
2551: * that getComponentAt only searches the Container's immediate
2552: * children; if the containing component is a Container,
2553: * findComponentAt will search that child to find a nested component.
2554: *
2555: * @param x the <i>x</i> coordinate
2556: * @param y the <i>y</i> coordinate
2557: * @return null if the component does not contain the position.
2558: * If there is no child component at the requested point and the
2559: * point is within the bounds of the container the container itself
2560: * is returned.
2561: * @see Component#contains
2562: * @see #getComponentAt
2563: * @since 1.2
2564: */
2565: public Component findComponentAt(int x, int y) {
2566: synchronized (getTreeLock()) {
2567: return findComponentAt(x, y, true);
2568: }
2569: }
2570:
2571: /**
2572: * Private version of findComponentAt which has a controllable
2573: * behavior. Setting 'ignoreEnabled' to 'false' bypasses disabled
2574: * Components during the search. This behavior is used by the
2575: * lightweight cursor support in sun.awt.GlobalCursorManager.
2576: * The cursor code calls this function directly via native code.
2577: *
2578: * The addition of this feature is temporary, pending the
2579: * adoption of new, public API which exports this feature.
2580: */
2581: final Component findComponentAt(int x, int y, boolean ignoreEnabled) {
2582: if (isRecursivelyVisible()) {
2583: return findComponentAtImpl(x, y, ignoreEnabled);
2584: }
2585: return null;
2586: }
2587:
2588: final Component findComponentAtImpl(int x, int y,
2589: boolean ignoreEnabled) {
2590: if (!(contains(x, y) && visible && (ignoreEnabled || enabled))) {
2591: return null;
2592: }
2593: int ncomponents = this .ncomponents;
2594: Component component[] = this .component;
2595:
2596: // Two passes: see comment in sun.awt.SunGraphicsCallback
2597: for (int i = 0; i < ncomponents; i++) {
2598: Component comp = component[i];
2599: if (comp != null && !(comp.peer instanceof LightweightPeer)) {
2600: if (comp instanceof Container) {
2601: comp = ((Container) comp).findComponentAtImpl(x
2602: - comp.x, y - comp.y, ignoreEnabled);
2603: } else {
2604: comp = comp.locate(x - comp.x, y - comp.y);
2605: }
2606: if (comp != null && comp.visible
2607: && (ignoreEnabled || comp.enabled)) {
2608: return comp;
2609: }
2610: }
2611: }
2612: for (int i = 0; i < ncomponents; i++) {
2613: Component comp = component[i];
2614: if (comp != null && comp.peer instanceof LightweightPeer) {
2615: if (comp instanceof Container) {
2616: comp = ((Container) comp).findComponentAtImpl(x
2617: - comp.x, y - comp.y, ignoreEnabled);
2618: } else {
2619: comp = comp.locate(x - comp.x, y - comp.y);
2620: }
2621: if (comp != null && comp.visible
2622: && (ignoreEnabled || comp.enabled)) {
2623: return comp;
2624: }
2625: }
2626: }
2627: return this ;
2628: }
2629:
2630: /**
2631: * Locates the visible child component that contains the specified
2632: * point. The top-most child component is returned in the case
2633: * where there is overlap in the components. If the containing child
2634: * component is a Container, this method will continue searching for
2635: * the deepest nested child component. Components which are not
2636: * visible are ignored during the search.<p>
2637: *
2638: * The findComponentAt method is different from getComponentAt in
2639: * that getComponentAt only searches the Container's immediate
2640: * children; if the containing component is a Container,
2641: * findComponentAt will search that child to find a nested component.
2642: *
2643: * @param p the point.
2644: * @return null if the component does not contain the position.
2645: * If there is no child component at the requested point and the
2646: * point is within the bounds of the container the container itself
2647: * is returned.
2648: * @see Component#contains
2649: * @see #getComponentAt
2650: * @since 1.2
2651: */
2652: public Component findComponentAt(Point p) {
2653: return findComponentAt(p.x, p.y);
2654: }
2655:
2656: /**
2657: * Makes this Container displayable by connecting it to
2658: * a native screen resource. Making a container displayable will
2659: * cause all of its children to be made displayable.
2660: * This method is called internally by the toolkit and should
2661: * not be called directly by programs.
2662: * @see Component#isDisplayable
2663: * @see #removeNotify
2664: */
2665: public void addNotify() {
2666: synchronized (getTreeLock()) {
2667: // addNotify() on the children may cause proxy event enabling
2668: // on this instance, so we first call super.addNotify() and
2669: // possibly create an lightweight event dispatcher before calling
2670: // addNotify() on the children which may be lightweight.
2671: super .addNotify();
2672: if (!(peer instanceof LightweightPeer)) {
2673: dispatcher = new LightweightDispatcher(this );
2674: }
2675: int ncomponents = this .ncomponents;
2676: Component component[] = this .component;
2677: for (int i = 0; i < ncomponents; i++) {
2678: component[i].addNotify();
2679: }
2680: // Update stacking order if native platform allows
2681: ContainerPeer cpeer = (ContainerPeer) peer;
2682: if (cpeer.isRestackSupported()) {
2683: cpeer.restack();
2684: }
2685:
2686: }
2687: }
2688:
2689: /**
2690: * Makes this Container undisplayable by removing its connection
2691: * to its native screen resource. Making a container undisplayable
2692: * will cause all of its children to be made undisplayable.
2693: * This method is called by the toolkit internally and should
2694: * not be called directly by programs.
2695: * @see Component#isDisplayable
2696: * @see #addNotify
2697: */
2698: public void removeNotify() {
2699: synchronized (getTreeLock()) {
2700: int ncomponents = this .ncomponents;
2701: Component component[] = this .component;
2702: for (int i = ncomponents - 1; i >= 0; i--) {
2703: if (component[i] != null)
2704: component[i].removeNotify();
2705: }
2706: if (dispatcher != null) {
2707: dispatcher.dispose();
2708: dispatcher = null;
2709: }
2710: super .removeNotify();
2711: }
2712: }
2713:
2714: /**
2715: * Checks if the component is contained in the component hierarchy of
2716: * this container.
2717: * @param c the component
2718: * @return <code>true</code> if it is an ancestor;
2719: * <code>false</code> otherwise.
2720: * @since JDK1.1
2721: */
2722: public boolean isAncestorOf(Component c) {
2723: Container p;
2724: if (c == null || ((p = c.getParent()) == null)) {
2725: return false;
2726: }
2727: while (p != null) {
2728: if (p == this ) {
2729: return true;
2730: }
2731: p = p.getParent();
2732: }
2733: return false;
2734: }
2735:
2736: /*
2737: * The following code was added to support modal JInternalFrames
2738: * Unfortunately this code has to be added here so that we can get access to
2739: * some private AWT classes like SequencedEvent.
2740: *
2741: * The native container of the LW component has this field set
2742: * to tell it that it should block Mouse events for all LW
2743: * children except for the modal component.
2744: *
2745: * In the case of nested Modal components, we store the previous
2746: * modal component in the new modal components value of modalComp;
2747: */
2748:
2749: transient Component modalComp;
2750: transient AppContext modalAppContext;
2751:
2752: private void startLWModal() {
2753: // Store the app context on which this component is being shown.
2754: // Event dispatch thread of this app context will be sleeping until
2755: // we wake it by any event from hideAndDisposeHandler().
2756: modalAppContext = AppContext.getAppContext();
2757:
2758: // keep the KeyEvents from being dispatched
2759: // until the focus has been transfered
2760: long time = Toolkit.getEventQueue().getMostRecentEventTime();
2761: Component predictedFocusOwner = (Component.isInstanceOf(this ,
2762: "javax.swing.JInternalFrame")) ? ((javax.swing.JInternalFrame) (this ))
2763: .getMostRecentFocusOwner()
2764: : null;
2765: if (predictedFocusOwner != null) {
2766: KeyboardFocusManager.getCurrentKeyboardFocusManager()
2767: .enqueueKeyEvents(time, predictedFocusOwner);
2768: }
2769: // We have two mechanisms for blocking: 1. If we're on the
2770: // EventDispatchThread, start a new event pump. 2. If we're
2771: // on any other thread, call wait() on the treelock.
2772: final Container nativeContainer;
2773: synchronized (getTreeLock()) {
2774: nativeContainer = getHeavyweightContainer();
2775: if (nativeContainer.modalComp != null) {
2776: this .modalComp = nativeContainer.modalComp;
2777: nativeContainer.modalComp = this ;
2778: return;
2779: } else {
2780: nativeContainer.modalComp = this ;
2781: }
2782: }
2783:
2784: Runnable pumpEventsForHierarchy = new Runnable() {
2785: public void run() {
2786: EventDispatchThread dispatchThread = (EventDispatchThread) Thread
2787: .currentThread();
2788: dispatchThread.pumpEventsForHierarchy(
2789: new Conditional() {
2790: public boolean evaluate() {
2791: return ((windowClosingException == null) && (nativeContainer.modalComp != null));
2792: }
2793: }, Container.this );
2794: }
2795: };
2796:
2797: if (EventQueue.isDispatchThread()) {
2798: SequencedEvent currentSequencedEvent = KeyboardFocusManager
2799: .getCurrentKeyboardFocusManager()
2800: .getCurrentSequencedEvent();
2801: if (currentSequencedEvent != null) {
2802: currentSequencedEvent.dispose();
2803: }
2804:
2805: pumpEventsForHierarchy.run();
2806: } else {
2807: synchronized (getTreeLock()) {
2808: Toolkit.getEventQueue().postEvent(
2809: new PeerEvent(this , pumpEventsForHierarchy,
2810: PeerEvent.PRIORITY_EVENT));
2811: while ((windowClosingException == null)
2812: && (nativeContainer.modalComp != null)) {
2813: try {
2814: getTreeLock().wait();
2815: } catch (InterruptedException e) {
2816: break;
2817: }
2818: }
2819: }
2820: }
2821: if (windowClosingException != null) {
2822: windowClosingException.fillInStackTrace();
2823: throw windowClosingException;
2824: }
2825: if (predictedFocusOwner != null) {
2826: KeyboardFocusManager.getCurrentKeyboardFocusManager()
2827: .dequeueKeyEvents(time, predictedFocusOwner);
2828: }
2829: }
2830:
2831: private void stopLWModal() {
2832: synchronized (getTreeLock()) {
2833: if (modalAppContext != null) {
2834: Container nativeContainer = getHeavyweightContainer();
2835: if (nativeContainer != null) {
2836: if (this .modalComp != null) {
2837: nativeContainer.modalComp = this .modalComp;
2838: this .modalComp = null;
2839: return;
2840: } else {
2841: nativeContainer.modalComp = null;
2842: }
2843: }
2844: // Wake up event dispatch thread on which the dialog was
2845: // initially shown
2846: SunToolkit.postEvent(modalAppContext, new PeerEvent(
2847: this , new WakingRunnable(),
2848: PeerEvent.PRIORITY_EVENT));
2849: }
2850: EventQueue.invokeLater(new WakingRunnable());
2851: getTreeLock().notifyAll();
2852: }
2853: }
2854:
2855: final static class WakingRunnable implements Runnable {
2856: public void run() {
2857: }
2858: }
2859:
2860: /* End of JOptionPane support code */
2861:
2862: /**
2863: * Returns a string representing the state of this <code>Container</code>.
2864: * This method is intended to be used only for debugging purposes, and the
2865: * content and format of the returned string may vary between
2866: * implementations. The returned string may be empty but may not be
2867: * <code>null</code>.
2868: *
2869: * @return the parameter string of this container
2870: */
2871: protected String paramString() {
2872: String str = super .paramString();
2873: LayoutManager layoutMgr = this .layoutMgr;
2874: if (layoutMgr != null) {
2875: str += ",layout=" + layoutMgr.getClass().getName();
2876: }
2877: return str;
2878: }
2879:
2880: /**
2881: * Prints a listing of this container to the specified output
2882: * stream. The listing starts at the specified indentation.
2883: * <p>
2884: * The immediate children of the container are printed with
2885: * an indentation of <code>indent+1</code>. The children
2886: * of those children are printed at <code>indent+2</code>
2887: * and so on.
2888: *
2889: * @param out a print stream
2890: * @param indent the number of spaces to indent
2891: * @see Component#list(java.io.PrintStream, int)
2892: * @since JDK1.0
2893: */
2894: public void list(PrintStream out, int indent) {
2895: super .list(out, indent);
2896: int ncomponents = this .ncomponents;
2897: Component component[] = this .component;
2898: for (int i = 0; i < ncomponents; i++) {
2899: Component comp = component[i];
2900: if (comp != null) {
2901: comp.list(out, indent + 1);
2902: }
2903: }
2904: }
2905:
2906: /**
2907: * Prints out a list, starting at the specified indentation,
2908: * to the specified print writer.
2909: * <p>
2910: * The immediate children of the container are printed with
2911: * an indentation of <code>indent+1</code>. The children
2912: * of those children are printed at <code>indent+2</code>
2913: * and so on.
2914: *
2915: * @param out a print writer
2916: * @param indent the number of spaces to indent
2917: * @see Component#list(java.io.PrintWriter, int)
2918: * @since JDK1.1
2919: */
2920: public void list(PrintWriter out, int indent) {
2921: super .list(out, indent);
2922: int ncomponents = this .ncomponents;
2923: Component component[] = this .component;
2924: for (int i = 0; i < ncomponents; i++) {
2925: Component comp = component[i];
2926: if (comp != null) {
2927: comp.list(out, indent + 1);
2928: }
2929: }
2930: }
2931:
2932: /**
2933: * Sets the focus traversal keys for a given traversal operation for this
2934: * Container.
2935: * <p>
2936: * The default values for a Container's focus traversal keys are
2937: * implementation-dependent. Sun recommends that all implementations for a
2938: * particular native platform use the same default values. The
2939: * recommendations for Windows and Unix are listed below. These
2940: * recommendations are used in the Sun AWT implementations.
2941: *
2942: * <table border=1 summary="Recommended default values for a Container's focus traversal keys">
2943: * <tr>
2944: * <th>Identifier</th>
2945: * <th>Meaning</th>
2946: * <th>Default</th>
2947: * </tr>
2948: * <tr>
2949: * <td>KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS</td>
2950: * <td>Normal forward keyboard traversal</td>
2951: * <td>TAB on KEY_PRESSED, CTRL-TAB on KEY_PRESSED</td>
2952: * </tr>
2953: * <tr>
2954: * <td>KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS</td>
2955: * <td>Normal reverse keyboard traversal</td>
2956: * <td>SHIFT-TAB on KEY_PRESSED, CTRL-SHIFT-TAB on KEY_PRESSED</td>
2957: * </tr>
2958: * <tr>
2959: * <td>KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS</td>
2960: * <td>Go up one focus traversal cycle</td>
2961: * <td>none</td>
2962: * </tr>
2963: * <tr>
2964: * <td>KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS<td>
2965: * <td>Go down one focus traversal cycle</td>
2966: * <td>none</td>
2967: * </tr>
2968: * </table>
2969: *
2970: * To disable a traversal key, use an empty Set; Collections.EMPTY_SET is
2971: * recommended.
2972: * <p>
2973: * Using the AWTKeyStroke API, client code can specify on which of two
2974: * specific KeyEvents, KEY_PRESSED or KEY_RELEASED, the focus traversal
2975: * operation will occur. Regardless of which KeyEvent is specified,
2976: * however, all KeyEvents related to the focus traversal key, including the
2977: * associated KEY_TYPED event, will be consumed, and will not be dispatched
2978: * to any Container. It is a runtime error to specify a KEY_TYPED event as
2979: * mapping to a focus traversal operation, or to map the same event to
2980: * multiple default focus traversal operations.
2981: * <p>
2982: * If a value of null is specified for the Set, this Container inherits the
2983: * Set from its parent. If all ancestors of this Container have null
2984: * specified for the Set, then the current KeyboardFocusManager's default
2985: * Set is used.
2986: *
2987: * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
2988: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
2989: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
2990: * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
2991: * @param keystrokes the Set of AWTKeyStroke for the specified operation
2992: * @see #getFocusTraversalKeys
2993: * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS
2994: * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS
2995: * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
2996: * @see KeyboardFocusManager#DOWN_CYCLE_TRAVERSAL_KEYS
2997: * @throws IllegalArgumentException if id is not one of
2998: * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
2999: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3000: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3001: * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, or if keystrokes
3002: * contains null, or if any Object in keystrokes is not an
3003: * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event,
3004: * or if any keystroke already maps to another focus traversal
3005: * operation for this Container
3006: * @since 1.4
3007: * @beaninfo
3008: * bound: true
3009: */
3010: public void setFocusTraversalKeys(int id,
3011: Set<? extends AWTKeyStroke> keystrokes) {
3012: if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) {
3013: throw new IllegalArgumentException(
3014: "invalid focus traversal key identifier");
3015: }
3016:
3017: // Don't call super.setFocusTraversalKey. The Component parameter check
3018: // does not allow DOWN_CYCLE_TRAVERSAL_KEYS, but we do.
3019: setFocusTraversalKeys_NoIDCheck(id, keystrokes);
3020: }
3021:
3022: /**
3023: * Returns the Set of focus traversal keys for a given traversal operation
3024: * for this Container. (See
3025: * <code>setFocusTraversalKeys</code> for a full description of each key.)
3026: * <p>
3027: * If a Set of traversal keys has not been explicitly defined for this
3028: * Container, then this Container's parent's Set is returned. If no Set
3029: * has been explicitly defined for any of this Container's ancestors, then
3030: * the current KeyboardFocusManager's default Set is returned.
3031: *
3032: * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3033: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3034: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3035: * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
3036: * @return the Set of AWTKeyStrokes for the specified operation. The Set
3037: * will be unmodifiable, and may be empty. null will never be
3038: * returned.
3039: * @see #setFocusTraversalKeys
3040: * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS
3041: * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS
3042: * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
3043: * @see KeyboardFocusManager#DOWN_CYCLE_TRAVERSAL_KEYS
3044: * @throws IllegalArgumentException if id is not one of
3045: * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3046: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3047: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3048: * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
3049: * @since 1.4
3050: */
3051: public Set<AWTKeyStroke> getFocusTraversalKeys(int id) {
3052: if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) {
3053: throw new IllegalArgumentException(
3054: "invalid focus traversal key identifier");
3055: }
3056:
3057: // Don't call super.getFocusTraversalKey. The Component parameter check
3058: // does not allow DOWN_CYCLE_TRAVERSAL_KEY, but we do.
3059: return getFocusTraversalKeys_NoIDCheck(id);
3060: }
3061:
3062: /**
3063: * Returns whether the Set of focus traversal keys for the given focus
3064: * traversal operation has been explicitly defined for this Container. If
3065: * this method returns <code>false</code>, this Container is inheriting the
3066: * Set from an ancestor, or from the current KeyboardFocusManager.
3067: *
3068: * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3069: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3070: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3071: * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
3072: * @return <code>true</code> if the the Set of focus traversal keys for the
3073: * given focus traversal operation has been explicitly defined for
3074: * this Component; <code>false</code> otherwise.
3075: * @throws IllegalArgumentException if id is not one of
3076: * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3077: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3078: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3079: * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
3080: * @since 1.4
3081: */
3082: public boolean areFocusTraversalKeysSet(int id) {
3083: if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) {
3084: throw new IllegalArgumentException(
3085: "invalid focus traversal key identifier");
3086: }
3087:
3088: return (focusTraversalKeys != null && focusTraversalKeys[id] != null);
3089: }
3090:
3091: /**
3092: * Returns whether the specified Container is the focus cycle root of this
3093: * Container's focus traversal cycle. Each focus traversal cycle has only
3094: * a single focus cycle root and each Container which is not a focus cycle
3095: * root belongs to only a single focus traversal cycle. Containers which
3096: * are focus cycle roots belong to two cycles: one rooted at the Container
3097: * itself, and one rooted at the Container's nearest focus-cycle-root
3098: * ancestor. This method will return <code>true</code> for both such
3099: * Containers in this case.
3100: *
3101: * @param container the Container to be tested
3102: * @return <code>true</code> if the specified Container is a focus-cycle-
3103: * root of this Container; <code>false</code> otherwise
3104: * @see #isFocusCycleRoot()
3105: * @since 1.4
3106: */
3107: public boolean isFocusCycleRoot(Container container) {
3108: if (isFocusCycleRoot() && container == this ) {
3109: return true;
3110: } else {
3111: return super .isFocusCycleRoot(container);
3112: }
3113: }
3114:
3115: private Container findTraversalRoot() {
3116: // I potentially have two roots, myself and my root parent
3117: // If I am the current root, then use me
3118: // If none of my parents are roots, then use me
3119: // If my root parent is the current root, then use my root parent
3120: // If neither I nor my root parent is the current root, then
3121: // use my root parent (a guess)
3122:
3123: Container currentFocusCycleRoot = KeyboardFocusManager
3124: .getCurrentKeyboardFocusManager()
3125: .getCurrentFocusCycleRoot();
3126: Container root;
3127:
3128: if (currentFocusCycleRoot == this ) {
3129: root = this ;
3130: } else {
3131: root = getFocusCycleRootAncestor();
3132: if (root == null) {
3133: root = this ;
3134: }
3135: }
3136:
3137: if (root != currentFocusCycleRoot) {
3138: KeyboardFocusManager.getCurrentKeyboardFocusManager()
3139: .setGlobalCurrentFocusCycleRoot(root);
3140: }
3141: return root;
3142: }
3143:
3144: final boolean containsFocus() {
3145: final Component focusOwner = KeyboardFocusManager
3146: .getCurrentKeyboardFocusManager().getFocusOwner();
3147: return isParentOf(focusOwner);
3148: }
3149:
3150: /**
3151: * Check if this component is the child of this container or its children.
3152: * Note: this function acquires treeLock
3153: * Note: this function traverses children tree only in one Window.
3154: * @param comp a component in test, must not be null
3155: */
3156: private boolean isParentOf(Component comp) {
3157: synchronized (getTreeLock()) {
3158: while (comp != null && comp != this
3159: && !(comp instanceof Window)) {
3160: comp = comp.getParent();
3161: }
3162: return (comp == this );
3163: }
3164: }
3165:
3166: void clearMostRecentFocusOwnerOnHide() {
3167: boolean reset = false;
3168: Window window = null;
3169:
3170: synchronized (getTreeLock()) {
3171: window = getContainingWindow();
3172: if (window != null) {
3173: Component comp = KeyboardFocusManager
3174: .getMostRecentFocusOwner(window);
3175: reset = ((comp == this ) || isParentOf(comp));
3176: // This synchronized should always be the second in a pair
3177: // (tree lock, KeyboardFocusManager.class)
3178: synchronized (KeyboardFocusManager.class) {
3179: Component storedComp = window
3180: .getTemporaryLostComponent();
3181: if (isParentOf(storedComp) || storedComp == this ) {
3182: window.setTemporaryLostComponent(null);
3183: }
3184: }
3185: }
3186: }
3187:
3188: if (reset) {
3189: KeyboardFocusManager.setMostRecentFocusOwner(window, null);
3190: }
3191: }
3192:
3193: void clearCurrentFocusCycleRootOnHide() {
3194: KeyboardFocusManager kfm = KeyboardFocusManager
3195: .getCurrentKeyboardFocusManager();
3196: Container cont = kfm.getCurrentFocusCycleRoot();
3197:
3198: if (cont == this || isParentOf(cont)) {
3199: kfm.setGlobalCurrentFocusCycleRoot(null);
3200: }
3201: }
3202:
3203: final Container getTraversalRoot() {
3204: if (isFocusCycleRoot()) {
3205: return findTraversalRoot();
3206: }
3207:
3208: return super .getTraversalRoot();
3209: }
3210:
3211: /**
3212: * Sets the focus traversal policy that will manage keyboard traversal of
3213: * this Container's children, if this Container is a focus cycle root. If
3214: * the argument is null, this Container inherits its policy from its focus-
3215: * cycle-root ancestor. If the argument is non-null, this policy will be
3216: * inherited by all focus-cycle-root children that have no keyboard-
3217: * traversal policy of their own (as will, recursively, their focus-cycle-
3218: * root children).
3219: * <p>
3220: * If this Container is not a focus cycle root, the policy will be
3221: * remembered, but will not be used or inherited by this or any other
3222: * Containers until this Container is made a focus cycle root.
3223: *
3224: * @param policy the new focus traversal policy for this Container
3225: * @see #getFocusTraversalPolicy
3226: * @see #setFocusCycleRoot
3227: * @see #isFocusCycleRoot
3228: * @since 1.4
3229: * @beaninfo
3230: * bound: true
3231: */
3232: public void setFocusTraversalPolicy(FocusTraversalPolicy policy) {
3233: FocusTraversalPolicy oldPolicy;
3234: synchronized (this ) {
3235: oldPolicy = this .focusTraversalPolicy;
3236: this .focusTraversalPolicy = policy;
3237: }
3238: firePropertyChange("focusTraversalPolicy", oldPolicy, policy);
3239: }
3240:
3241: /**
3242: * Returns the focus traversal policy that will manage keyboard traversal
3243: * of this Container's children, or null if this Container is not a focus
3244: * cycle root. If no traversal policy has been explicitly set for this
3245: * Container, then this Container's focus-cycle-root ancestor's policy is
3246: * returned.
3247: *
3248: * @return this Container's focus traversal policy, or null if this
3249: * Container is not a focus cycle root.
3250: * @see #setFocusTraversalPolicy
3251: * @see #setFocusCycleRoot
3252: * @see #isFocusCycleRoot
3253: * @since 1.4
3254: */
3255: public FocusTraversalPolicy getFocusTraversalPolicy() {
3256: if (!isFocusTraversalPolicyProvider() && !isFocusCycleRoot()) {
3257: return null;
3258: }
3259:
3260: FocusTraversalPolicy policy = this .focusTraversalPolicy;
3261: if (policy != null) {
3262: return policy;
3263: }
3264:
3265: Container rootAncestor = getFocusCycleRootAncestor();
3266: if (rootAncestor != null) {
3267: return rootAncestor.getFocusTraversalPolicy();
3268: } else {
3269: return KeyboardFocusManager
3270: .getCurrentKeyboardFocusManager()
3271: .getDefaultFocusTraversalPolicy();
3272: }
3273: }
3274:
3275: /**
3276: * Returns whether the focus traversal policy has been explicitly set for
3277: * this Container. If this method returns <code>false</code>, this
3278: * Container will inherit its focus traversal policy from an ancestor.
3279: *
3280: * @return <code>true</code> if the focus traversal policy has been
3281: * explicitly set for this Container; <code>false</code> otherwise.
3282: * @since 1.4
3283: */
3284: public boolean isFocusTraversalPolicySet() {
3285: return (focusTraversalPolicy != null);
3286: }
3287:
3288: /**
3289: * Sets whether this Container is the root of a focus traversal cycle. Once
3290: * focus enters a traversal cycle, typically it cannot leave it via focus
3291: * traversal unless one of the up- or down-cycle keys is pressed. Normal
3292: * traversal is limited to this Container, and all of this Container's
3293: * descendants that are not descendants of inferior focus cycle roots. Note
3294: * that a FocusTraversalPolicy may bend these restrictions, however. For
3295: * example, ContainerOrderFocusTraversalPolicy supports implicit down-cycle
3296: * traversal.
3297: * <p>
3298: * The alternative way to specify the traversal order of this Container's
3299: * children is to make this Container a
3300: * <a href="doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus traversal policy provider</a>.
3301: *
3302: * @param focusCycleRoot indicates whether this Container is the root of a
3303: * focus traversal cycle
3304: * @see #isFocusCycleRoot()
3305: * @see #setFocusTraversalPolicy
3306: * @see #getFocusTraversalPolicy
3307: * @see ContainerOrderFocusTraversalPolicy
3308: * @see #setFocusTraversalPolicyProvider
3309: * @since 1.4
3310: * @beaninfo
3311: * bound: true
3312: */
3313: public void setFocusCycleRoot(boolean focusCycleRoot) {
3314: boolean oldFocusCycleRoot;
3315: synchronized (this ) {
3316: oldFocusCycleRoot = this .focusCycleRoot;
3317: this .focusCycleRoot = focusCycleRoot;
3318: }
3319: firePropertyChange("focusCycleRoot", oldFocusCycleRoot,
3320: focusCycleRoot);
3321: }
3322:
3323: /**
3324: * Returns whether this Container is the root of a focus traversal cycle.
3325: * Once focus enters a traversal cycle, typically it cannot leave it via
3326: * focus traversal unless one of the up- or down-cycle keys is pressed.
3327: * Normal traversal is limited to this Container, and all of this
3328: * Container's descendants that are not descendants of inferior focus
3329: * cycle roots. Note that a FocusTraversalPolicy may bend these
3330: * restrictions, however. For example, ContainerOrderFocusTraversalPolicy
3331: * supports implicit down-cycle traversal.
3332: *
3333: * @return whether this Container is the root of a focus traversal cycle
3334: * @see #setFocusCycleRoot
3335: * @see #setFocusTraversalPolicy
3336: * @see #getFocusTraversalPolicy
3337: * @see ContainerOrderFocusTraversalPolicy
3338: * @since 1.4
3339: */
3340: public boolean isFocusCycleRoot() {
3341: return focusCycleRoot;
3342: }
3343:
3344: /**
3345: * Sets whether this container will be used to provide focus
3346: * traversal policy. Container with this property as
3347: * <code>true</code> will be used to acquire focus traversal policy
3348: * instead of closest focus cycle root ancestor.
3349: * @param provider indicates whether this container will be used to
3350: * provide focus traversal policy
3351: * @see #setFocusTraversalPolicy
3352: * @see #getFocusTraversalPolicy
3353: * @see #isFocusTraversalPolicyProvider
3354: * @since 1.5
3355: * @beaninfo
3356: * bound: true
3357: */
3358: public final void setFocusTraversalPolicyProvider(boolean provider) {
3359: boolean oldProvider;
3360: synchronized (this ) {
3361: oldProvider = focusTraversalPolicyProvider;
3362: focusTraversalPolicyProvider = provider;
3363: }
3364: firePropertyChange("focusTraversalPolicyProvider", oldProvider,
3365: provider);
3366: }
3367:
3368: /**
3369: * Returns whether this container provides focus traversal
3370: * policy. If this property is set to <code>true</code> then when
3371: * keyboard focus manager searches container hierarchy for focus
3372: * traversal policy and encounters this container before any other
3373: * container with this property as true or focus cycle roots then
3374: * its focus traversal policy will be used instead of focus cycle
3375: * root's policy.
3376: * @see #setFocusTraversalPolicy
3377: * @see #getFocusTraversalPolicy
3378: * @see #setFocusCycleRoot
3379: * @see #setFocusTraversalPolicyProvider
3380: * @return <code>true</code> if this container provides focus traversal
3381: * policy, <code>false</code> otherwise
3382: * @since 1.5
3383: * @beaninfo
3384: * bound: true
3385: */
3386: public final boolean isFocusTraversalPolicyProvider() {
3387: return focusTraversalPolicyProvider;
3388: }
3389:
3390: /**
3391: * Transfers the focus down one focus traversal cycle. If this Container is
3392: * a focus cycle root, then the focus owner is set to this Container's
3393: * default Component to focus, and the current focus cycle root is set to
3394: * this Container. If this Container is not a focus cycle root, then no
3395: * focus traversal operation occurs.
3396: *
3397: * @see Component#requestFocus()
3398: * @see #isFocusCycleRoot
3399: * @see #setFocusCycleRoot
3400: * @since 1.4
3401: */
3402: public void transferFocusDownCycle() {
3403: if (isFocusCycleRoot()) {
3404: KeyboardFocusManager.getCurrentKeyboardFocusManager()
3405: .setGlobalCurrentFocusCycleRoot(this );
3406: Component toFocus = getFocusTraversalPolicy()
3407: .getDefaultComponent(this );
3408: if (toFocus != null) {
3409: toFocus
3410: .requestFocus(CausedFocusEvent.Cause.TRAVERSAL_DOWN);
3411: }
3412: }
3413: }
3414:
3415: void preProcessKeyEvent(KeyEvent e) {
3416: Container parent = this .parent;
3417: if (parent != null) {
3418: parent.preProcessKeyEvent(e);
3419: }
3420: }
3421:
3422: void postProcessKeyEvent(KeyEvent e) {
3423: Container parent = this .parent;
3424: if (parent != null) {
3425: parent.postProcessKeyEvent(e);
3426: }
3427: }
3428:
3429: boolean postsOldMouseEvents() {
3430: return true;
3431: }
3432:
3433: /**
3434: * Sets the <code>ComponentOrientation</code> property of this container
3435: * and all components contained within it.
3436: *
3437: * @param o the new component orientation of this container and
3438: * the components contained within it.
3439: * @exception NullPointerException if <code>orientation</code> is null.
3440: * @see Component#setComponentOrientation
3441: * @see Component#getComponentOrientation
3442: * @since 1.4
3443: */
3444: public void applyComponentOrientation(ComponentOrientation o) {
3445: super .applyComponentOrientation(o);
3446:
3447: for (int i = 0; i < ncomponents; ++i) {
3448: component[i].applyComponentOrientation(o);
3449: }
3450: }
3451:
3452: /**
3453: * Adds a PropertyChangeListener to the listener list. The listener is
3454: * registered for all bound properties of this class, including the
3455: * following:
3456: * <ul>
3457: * <li>this Container's font ("font")</li>
3458: * <li>this Container's background color ("background")</li>
3459: * <li>this Container's foreground color ("foreground")</li>
3460: * <li>this Container's focusability ("focusable")</li>
3461: * <li>this Container's focus traversal keys enabled state
3462: * ("focusTraversalKeysEnabled")</li>
3463: * <li>this Container's Set of FORWARD_TRAVERSAL_KEYS
3464: * ("forwardFocusTraversalKeys")</li>
3465: * <li>this Container's Set of BACKWARD_TRAVERSAL_KEYS
3466: * ("backwardFocusTraversalKeys")</li>
3467: * <li>this Container's Set of UP_CYCLE_TRAVERSAL_KEYS
3468: * ("upCycleFocusTraversalKeys")</li>
3469: * <li>this Container's Set of DOWN_CYCLE_TRAVERSAL_KEYS
3470: * ("downCycleFocusTraversalKeys")</li>
3471: * <li>this Container's focus traversal policy ("focusTraversalPolicy")
3472: * </li>
3473: * <li>this Container's focus-cycle-root state ("focusCycleRoot")</li>
3474: * </ul>
3475: * Note that if this Container is inheriting a bound property, then no
3476: * event will be fired in response to a change in the inherited property.
3477: * <p>
3478: * If listener is null, no exception is thrown and no action is performed.
3479: *
3480: * @param listener the PropertyChangeListener to be added
3481: *
3482: * @see Component#removePropertyChangeListener
3483: * @see #addPropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener)
3484: */
3485: public void addPropertyChangeListener(
3486: PropertyChangeListener listener) {
3487: super .addPropertyChangeListener(listener);
3488: }
3489:
3490: /**
3491: * Adds a PropertyChangeListener to the listener list for a specific
3492: * property. The specified property may be user-defined, or one of the
3493: * following defaults:
3494: * <ul>
3495: * <li>this Container's font ("font")</li>
3496: * <li>this Container's background color ("background")</li>
3497: * <li>this Container's foreground color ("foreground")</li>
3498: * <li>this Container's focusability ("focusable")</li>
3499: * <li>this Container's focus traversal keys enabled state
3500: * ("focusTraversalKeysEnabled")</li>
3501: * <li>this Container's Set of FORWARD_TRAVERSAL_KEYS
3502: * ("forwardFocusTraversalKeys")</li>
3503: * <li>this Container's Set of BACKWARD_TRAVERSAL_KEYS
3504: * ("backwardFocusTraversalKeys")</li>
3505: * <li>this Container's Set of UP_CYCLE_TRAVERSAL_KEYS
3506: * ("upCycleFocusTraversalKeys")</li>
3507: * <li>this Container's Set of DOWN_CYCLE_TRAVERSAL_KEYS
3508: * ("downCycleFocusTraversalKeys")</li>
3509: * <li>this Container's focus traversal policy ("focusTraversalPolicy")
3510: * </li>
3511: * <li>this Container's focus-cycle-root state ("focusCycleRoot")</li>
3512: * <li>this Container's focus-traversal-policy-provider state("focusTraversalPolicyProvider")</li>
3513: * <li>this Container's focus-traversal-policy-provider state("focusTraversalPolicyProvider")</li>
3514: * </ul>
3515: * Note that if this Container is inheriting a bound property, then no
3516: * event will be fired in response to a change in the inherited property.
3517: * <p>
3518: * If listener is null, no exception is thrown and no action is performed.
3519: *
3520: * @param propertyName one of the property names listed above
3521: * @param listener the PropertyChangeListener to be added
3522: *
3523: * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
3524: * @see Component#removePropertyChangeListener
3525: */
3526: public void addPropertyChangeListener(String propertyName,
3527: PropertyChangeListener listener) {
3528: super .addPropertyChangeListener(propertyName, listener);
3529: }
3530:
3531: // Serialization support. A Container is responsible for restoring the
3532: // parent fields of its component children.
3533:
3534: /**
3535: * Container Serial Data Version.
3536: */
3537: private int containerSerializedDataVersion = 1;
3538:
3539: /**
3540: * Serializes this <code>Container</code> to the specified
3541: * <code>ObjectOutputStream</code>.
3542: * <ul>
3543: * <li>Writes default serializable fields to the stream.</li>
3544: * <li>Writes a list of serializable ContainerListener(s) as optional
3545: * data. The non-serializable ContainerListner(s) are detected and
3546: * no attempt is made to serialize them.</li>
3547: * <li>Write this Container's FocusTraversalPolicy if and only if it
3548: * is Serializable; otherwise, <code>null</code> is written.</li>
3549: * </ul>
3550: *
3551: * @param s the <code>ObjectOutputStream</code> to write
3552: * @serialData <code>null</code> terminated sequence of 0 or more pairs;
3553: * the pair consists of a <code>String</code> and <code>Object</code>;
3554: * the <code>String</code> indicates the type of object and
3555: * is one of the following:
3556: * <code>containerListenerK</code> indicating an
3557: * <code>ContainerListener</code> object;
3558: * the <code>Container</code>'s <code>FocusTraversalPolicy</code>,
3559: * or <code>null</code>
3560: *
3561: * @see AWTEventMulticaster#save(java.io.ObjectOutputStream, java.lang.String, java.util.EventListener)
3562: * @see Container#containerListenerK
3563: * @see #readObject(ObjectInputStream)
3564: */
3565: private void writeObject(ObjectOutputStream s) throws IOException {
3566: ObjectOutputStream.PutField f = s.putFields();
3567: f.put("ncomponents", ncomponents);
3568: f.put("component", component);
3569: f.put("layoutMgr", layoutMgr);
3570: f.put("dispatcher", dispatcher);
3571: f.put("maxSize", maxSize);
3572: f.put("focusCycleRoot", focusCycleRoot);
3573: f.put("containerSerializedDataVersion",
3574: containerSerializedDataVersion);
3575: f.put("focusTraversalPolicyProvider",
3576: focusTraversalPolicyProvider);
3577: s.writeFields();
3578:
3579: AWTEventMulticaster.save(s, containerListenerK,
3580: containerListener);
3581: s.writeObject(null);
3582:
3583: if (focusTraversalPolicy instanceof java.io.Serializable) {
3584: s.writeObject(focusTraversalPolicy);
3585: } else {
3586: s.writeObject(null);
3587: }
3588: }
3589:
3590: /**
3591: * Deserializes this <code>Container</code> from the specified
3592: * <code>ObjectInputStream</code>.
3593: * <ul>
3594: * <li>Reads default serializable fields from the stream.</li>
3595: * <li>Reads a list of serializable ContainerListener(s) as optional
3596: * data. If the list is null, no Listeners are installed.</li>
3597: * <li>Reads this Container's FocusTraversalPolicy, which may be null,
3598: * as optional data.</li>
3599: * </ul>
3600: *
3601: * @param s the <code>ObjectInputStream</code> to read
3602: * @serial
3603: * @see #addContainerListener
3604: * @see #writeObject(ObjectOutputStream)
3605: */
3606: private void readObject(ObjectInputStream s)
3607: throws ClassNotFoundException, IOException {
3608: ObjectInputStream.GetField f = s.readFields();
3609: ncomponents = f.get("ncomponents", 0);
3610: component = (Component[]) f.get("component", new Component[0]);
3611: layoutMgr = (LayoutManager) f.get("layoutMgr", null);
3612: dispatcher = (LightweightDispatcher) f.get("dispatcher", null);
3613: // Old stream. Doesn't contain maxSize among Component's fields.
3614: if (maxSize == null) {
3615: maxSize = (Dimension) f.get("maxSize", null);
3616: }
3617: focusCycleRoot = f.get("focusCycleRoot", false);
3618: containerSerializedDataVersion = f.get(
3619: "containerSerializedDataVersion", 1);
3620: focusTraversalPolicyProvider = f.get(
3621: "focusTraversalPolicyProvider", false);
3622:
3623: Component component[] = this .component;
3624: for (int i = 0; i < ncomponents; i++) {
3625: component[i].parent = this ;
3626: adjustListeningChildren(
3627: AWTEvent.HIERARCHY_EVENT_MASK,
3628: component[i]
3629: .numListening(AWTEvent.HIERARCHY_EVENT_MASK));
3630: adjustListeningChildren(
3631: AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
3632: component[i]
3633: .numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
3634: adjustDescendants(component[i].countHierarchyMembers());
3635: }
3636:
3637: Object keyOrNull;
3638: while (null != (keyOrNull = s.readObject())) {
3639: String key = ((String) keyOrNull).intern();
3640:
3641: if (containerListenerK == key) {
3642: addContainerListener((ContainerListener) (s
3643: .readObject()));
3644: } else {
3645: // skip value for unrecognized key
3646: s.readObject();
3647: }
3648: }
3649:
3650: try {
3651: Object policy = s.readObject();
3652: if (policy instanceof FocusTraversalPolicy) {
3653: focusTraversalPolicy = (FocusTraversalPolicy) policy;
3654: }
3655: } catch (java.io.OptionalDataException e) {
3656: // JDK 1.1/1.2/1.3 instances will not have this optional data.
3657: // e.eof will be true to indicate that there is no more data
3658: // available for this object. If e.eof is not true, throw the
3659: // exception as it might have been caused by reasons unrelated to
3660: // focusTraversalPolicy.
3661:
3662: if (!e.eof) {
3663: throw e;
3664: }
3665: }
3666: }
3667:
3668: /*
3669: * --- Accessibility Support ---
3670: */
3671:
3672: /**
3673: * Inner class of Container used to provide default support for
3674: * accessibility. This class is not meant to be used directly by
3675: * application developers, but is instead meant only to be
3676: * subclassed by container developers.
3677: * <p>
3678: * The class used to obtain the accessible role for this object,
3679: * as well as implementing many of the methods in the
3680: * AccessibleContainer interface.
3681: * @since 1.3
3682: */
3683: protected class AccessibleAWTContainer extends
3684: AccessibleAWTComponent {
3685:
3686: /**
3687: * JDK1.3 serialVersionUID
3688: */
3689: private static final long serialVersionUID = 5081320404842566097L;
3690:
3691: /**
3692: * Returns the number of accessible children in the object. If all
3693: * of the children of this object implement <code>Accessible</code>,
3694: * then this method should return the number of children of this object.
3695: *
3696: * @return the number of accessible children in the object
3697: */
3698: public int getAccessibleChildrenCount() {
3699: return Container.this .getAccessibleChildrenCount();
3700: }
3701:
3702: /**
3703: * Returns the nth <code>Accessible</code> child of the object.
3704: *
3705: * @param i zero-based index of child
3706: * @return the nth <code>Accessible</code> child of the object
3707: */
3708: public Accessible getAccessibleChild(int i) {
3709: return Container.this .getAccessibleChild(i);
3710: }
3711:
3712: /**
3713: * Returns the <code>Accessible</code> child, if one exists,
3714: * contained at the local coordinate <code>Point</code>.
3715: *
3716: * @param p the point defining the top-left corner of the
3717: * <code>Accessible</code>, given in the coordinate space
3718: * of the object's parent
3719: * @return the <code>Accessible</code>, if it exists,
3720: * at the specified location; else <code>null</code>
3721: */
3722: public Accessible getAccessibleAt(Point p) {
3723: return Container.this .getAccessibleAt(p);
3724: }
3725:
3726: protected ContainerListener accessibleContainerHandler = null;
3727:
3728: /**
3729: * Fire <code>PropertyChange</code> listener, if one is registered,
3730: * when children are added or removed.
3731: * @since 1.3
3732: */
3733: protected class AccessibleContainerHandler implements
3734: ContainerListener {
3735: public void componentAdded(ContainerEvent e) {
3736: Component c = e.getChild();
3737: if (c != null && c instanceof Accessible) {
3738: AccessibleAWTContainer.this
3739: .firePropertyChange(
3740: AccessibleContext.ACCESSIBLE_CHILD_PROPERTY,
3741: null, ((Accessible) c)
3742: .getAccessibleContext());
3743: }
3744: }
3745:
3746: public void componentRemoved(ContainerEvent e) {
3747: Component c = e.getChild();
3748: if (c != null && c instanceof Accessible) {
3749: AccessibleAWTContainer.this
3750: .firePropertyChange(
3751: AccessibleContext.ACCESSIBLE_CHILD_PROPERTY,
3752: ((Accessible) c)
3753: .getAccessibleContext(),
3754: null);
3755: }
3756: }
3757: }
3758:
3759: /**
3760: * Adds a PropertyChangeListener to the listener list.
3761: *
3762: * @param listener the PropertyChangeListener to be added
3763: */
3764: public void addPropertyChangeListener(
3765: PropertyChangeListener listener) {
3766: if (accessibleContainerHandler == null) {
3767: accessibleContainerHandler = new AccessibleContainerHandler();
3768: Container.this
3769: .addContainerListener(accessibleContainerHandler);
3770: }
3771: super .addPropertyChangeListener(listener);
3772: }
3773:
3774: } // inner class AccessibleAWTContainer
3775:
3776: /**
3777: * Returns the <code>Accessible</code> child contained at the local
3778: * coordinate <code>Point</code>, if one exists. Otherwise
3779: * returns <code>null</code>.
3780: *
3781: * @param p the point defining the top-left corner of the
3782: * <code>Accessible</code>, given in the coordinate space
3783: * of the object's parent
3784: * @return the <code>Accessible</code> at the specified location,
3785: * if it exists; otherwise <code>null</code>
3786: */
3787: Accessible getAccessibleAt(Point p) {
3788: synchronized (getTreeLock()) {
3789: if (this instanceof Accessible) {
3790: Accessible a = (Accessible) this ;
3791: AccessibleContext ac = a.getAccessibleContext();
3792: if (ac != null) {
3793: AccessibleComponent acmp;
3794: Point location;
3795: int nchildren = ac.getAccessibleChildrenCount();
3796: for (int i = 0; i < nchildren; i++) {
3797: a = ac.getAccessibleChild(i);
3798: if ((a != null)) {
3799: ac = a.getAccessibleContext();
3800: if (ac != null) {
3801: acmp = ac.getAccessibleComponent();
3802: if ((acmp != null)
3803: && (acmp.isShowing())) {
3804: location = acmp.getLocation();
3805: Point np = new Point(p.x
3806: - location.x, p.y
3807: - location.y);
3808: if (acmp.contains(np)) {
3809: return a;
3810: }
3811: }
3812: }
3813: }
3814: }
3815: }
3816: return (Accessible) this ;
3817: } else {
3818: Component ret = this ;
3819: if (!this .contains(p.x, p.y)) {
3820: ret = null;
3821: } else {
3822: int ncomponents = this .getComponentCount();
3823: for (int i = 0; i < ncomponents; i++) {
3824: Component comp = this .getComponent(i);
3825: if ((comp != null) && comp.isShowing()) {
3826: Point location = comp.getLocation();
3827: if (comp.contains(p.x - location.x, p.y
3828: - location.y)) {
3829: ret = comp;
3830: }
3831: }
3832: }
3833: }
3834: if (ret instanceof Accessible) {
3835: return (Accessible) ret;
3836: }
3837: }
3838: return null;
3839: }
3840: }
3841:
3842: /**
3843: * Returns the number of accessible children in the object. If all
3844: * of the children of this object implement <code>Accessible</code>,
3845: * then this method should return the number of children of this object.
3846: *
3847: * @return the number of accessible children in the object
3848: */
3849: int getAccessibleChildrenCount() {
3850: synchronized (getTreeLock()) {
3851: int count = 0;
3852: Component[] children = this .getComponents();
3853: for (int i = 0; i < children.length; i++) {
3854: if (children[i] instanceof Accessible) {
3855: count++;
3856: }
3857: }
3858: return count;
3859: }
3860: }
3861:
3862: /**
3863: * Returns the nth <code>Accessible</code> child of the object.
3864: *
3865: * @param i zero-based index of child
3866: * @return the nth <code>Accessible</code> child of the object
3867: */
3868: Accessible getAccessibleChild(int i) {
3869: synchronized (getTreeLock()) {
3870: Component[] children = this .getComponents();
3871: int count = 0;
3872: for (int j = 0; j < children.length; j++) {
3873: if (children[j] instanceof Accessible) {
3874: if (count == i) {
3875: return (Accessible) children[j];
3876: } else {
3877: count++;
3878: }
3879: }
3880: }
3881: return null;
3882: }
3883: }
3884:
3885: }
3886:
3887: /**
3888: * Class to manage the dispatching of MouseEvents to the lightweight descendants
3889: * and SunDropTargetEvents to both lightweight and heavyweight descendants
3890: * contained by a native container.
3891: *
3892: * NOTE: the class name is not appropriate anymore, but we cannot change it
3893: * because we must keep serialization compatibility.
3894: *
3895: * @author Timothy Prinzing
3896: */
3897: class LightweightDispatcher implements java.io.Serializable,
3898: AWTEventListener {
3899:
3900: /*
3901: * JDK 1.1 serialVersionUID
3902: */
3903: private static final long serialVersionUID = 5184291520170872969L;
3904: /*
3905: * Our own mouse event for when we're dragged over from another hw
3906: * container
3907: */
3908: private static final int LWD_MOUSE_DRAGGED_OVER = 1500;
3909:
3910: private static final DebugHelper dbg = DebugHelper
3911: .create(LightweightDispatcher.class);
3912:
3913: LightweightDispatcher(Container nativeContainer) {
3914: this .nativeContainer = nativeContainer;
3915: mouseEventTarget = null;
3916: eventMask = 0;
3917: }
3918:
3919: /*
3920: * Clean up any resources allocated when dispatcher was created;
3921: * should be called from Container.removeNotify
3922: */
3923: void dispose() {
3924: //System.out.println("Disposing lw dispatcher");
3925: stopListeningForOtherDrags();
3926: mouseEventTarget = null;
3927: }
3928:
3929: /**
3930: * Enables events to subcomponents.
3931: */
3932: void enableEvents(long events) {
3933: eventMask |= events;
3934: }
3935:
3936: /**
3937: * Dispatches an event to a sub-component if necessary, and
3938: * returns whether or not the event was forwarded to a
3939: * sub-component.
3940: *
3941: * @param e the event
3942: */
3943: boolean dispatchEvent(AWTEvent e) {
3944: boolean ret = false;
3945:
3946: /*
3947: * Fix for BugTraq Id 4389284.
3948: * Dispatch SunDropTargetEvents regardless of eventMask value.
3949: * Do not update cursor on dispatching SunDropTargetEvents.
3950: */
3951: if (e instanceof SunDropTargetEvent) {
3952:
3953: SunDropTargetEvent sdde = (SunDropTargetEvent) e;
3954: ret = processDropTargetEvent(sdde);
3955:
3956: } else {
3957: if (e instanceof MouseEvent
3958: && (eventMask & MOUSE_MASK) != 0) {
3959: MouseEvent me = (MouseEvent) e;
3960: ret = processMouseEvent(me);
3961: }
3962:
3963: if (e.getID() == MouseEvent.MOUSE_MOVED) {
3964: nativeContainer.updateCursorImmediately();
3965: }
3966: }
3967:
3968: return ret;
3969: }
3970:
3971: /* This method effectively returns whether or not a mouse button was down
3972: * just BEFORE the event happened. A better method name might be
3973: * wasAMouseButtonDownBeforeThisEvent().
3974: */
3975: private boolean isMouseGrab(MouseEvent e) {
3976: int modifiers = e.getModifiersEx();
3977:
3978: if (e.getID() == MouseEvent.MOUSE_PRESSED
3979: || e.getID() == MouseEvent.MOUSE_RELEASED) {
3980: switch (e.getButton()) {
3981: case MouseEvent.BUTTON1:
3982: modifiers ^= InputEvent.BUTTON1_DOWN_MASK;
3983: break;
3984: case MouseEvent.BUTTON2:
3985: modifiers ^= InputEvent.BUTTON2_DOWN_MASK;
3986: break;
3987: case MouseEvent.BUTTON3:
3988: modifiers ^= InputEvent.BUTTON3_DOWN_MASK;
3989: break;
3990: }
3991: }
3992: /* modifiers now as just before event */
3993: return ((modifiers & (InputEvent.BUTTON1_DOWN_MASK
3994: | InputEvent.BUTTON2_DOWN_MASK | InputEvent.BUTTON3_DOWN_MASK)) != 0);
3995: }
3996:
3997: /**
3998: * This method attempts to distribute a mouse event to a lightweight
3999: * component. It tries to avoid doing any unnecessary probes down
4000: * into the component tree to minimize the overhead of determining
4001: * where to route the event, since mouse movement events tend to
4002: * come in large and frequent amounts.
4003: */
4004: private boolean processMouseEvent(MouseEvent e) {
4005: int id = e.getID();
4006: Component mouseOver = // sensitive to mouse events
4007: nativeContainer.getMouseEventTarget(e.getX(), e.getY(),
4008: Container.INCLUDE_SELF);
4009:
4010: trackMouseEnterExit(mouseOver, e);
4011:
4012: // 4508327 : MOUSE_CLICKED should only go to the recipient of
4013: // the accompanying MOUSE_PRESSED, so don't reset mouseEventTarget on a
4014: // MOUSE_CLICKED.
4015: if (!isMouseGrab(e) && id != MouseEvent.MOUSE_CLICKED) {
4016: mouseEventTarget = (mouseOver != nativeContainer) ? mouseOver
4017: : null;
4018: }
4019:
4020: if (mouseEventTarget != null) {
4021: switch (id) {
4022: case MouseEvent.MOUSE_ENTERED:
4023: case MouseEvent.MOUSE_EXITED:
4024: break;
4025: case MouseEvent.MOUSE_PRESSED:
4026: retargetMouseEvent(mouseEventTarget, id, e);
4027: break;
4028: case MouseEvent.MOUSE_RELEASED:
4029: retargetMouseEvent(mouseEventTarget, id, e);
4030: break;
4031: case MouseEvent.MOUSE_CLICKED:
4032: // 4508327: MOUSE_CLICKED should never be dispatched to a Component
4033: // other than that which received the MOUSE_PRESSED event. If the
4034: // mouse is now over a different Component, don't dispatch the event.
4035: // The previous fix for a similar problem was associated with bug
4036: // 4155217.
4037: if (mouseOver == mouseEventTarget) {
4038: retargetMouseEvent(mouseOver, id, e);
4039: }
4040: break;
4041: case MouseEvent.MOUSE_MOVED:
4042: retargetMouseEvent(mouseEventTarget, id, e);
4043: break;
4044: case MouseEvent.MOUSE_DRAGGED:
4045: if (isMouseGrab(e)) {
4046: retargetMouseEvent(mouseEventTarget, id, e);
4047: }
4048: break;
4049: case MouseEvent.MOUSE_WHEEL:
4050: // This may send it somewhere that doesn't have MouseWheelEvents
4051: // enabled. In this case, Component.dispatchEventImpl() will
4052: // retarget the event to a parent that DOES have the events enabled.
4053: if (dbg.on && mouseOver != null) {
4054: dbg.println("LD retargeting mouse wheel to "
4055: + mouseOver.getName() + ", "
4056: + mouseOver.getClass());
4057: }
4058: retargetMouseEvent(mouseOver, id, e);
4059: break;
4060: }
4061: e.consume();
4062: }
4063: return e.isConsumed();
4064: }
4065:
4066: private boolean processDropTargetEvent(SunDropTargetEvent e) {
4067: int id = e.getID();
4068: int x = e.getX();
4069: int y = e.getY();
4070:
4071: /*
4072: * Fix for BugTraq ID 4395290.
4073: * It is possible that SunDropTargetEvent's Point is outside of the
4074: * native container bounds. In this case we truncate coordinates.
4075: */
4076: if (!nativeContainer.contains(x, y)) {
4077: final Dimension d = nativeContainer.getSize();
4078: if (d.width <= x) {
4079: x = d.width - 1;
4080: } else if (x < 0) {
4081: x = 0;
4082: }
4083: if (d.height <= y) {
4084: y = d.height - 1;
4085: } else if (y < 0) {
4086: y = 0;
4087: }
4088: }
4089: Component mouseOver = // not necessarily sensitive to mouse events
4090: nativeContainer.getDropTargetEventTarget(x, y,
4091: Container.INCLUDE_SELF);
4092: trackMouseEnterExit(mouseOver, e);
4093:
4094: if (mouseOver != nativeContainer && mouseOver != null) {
4095: switch (id) {
4096: case SunDropTargetEvent.MOUSE_ENTERED:
4097: case SunDropTargetEvent.MOUSE_EXITED:
4098: break;
4099: default:
4100: retargetMouseEvent(mouseOver, id, e);
4101: e.consume();
4102: break;
4103: }
4104: }
4105: return e.isConsumed();
4106: }
4107:
4108: /*
4109: * Generates enter/exit events as mouse moves over lw components
4110: * @param targetOver Target mouse is over (including native container)
4111: * @param e Mouse event in native container
4112: */
4113: private void trackMouseEnterExit(Component targetOver, MouseEvent e) {
4114: Component targetEnter = null;
4115: int id = e.getID();
4116:
4117: if (e instanceof SunDropTargetEvent
4118: && id == MouseEvent.MOUSE_ENTERED
4119: && isMouseInNativeContainer == true) {
4120: // This can happen if a lightweight component which initiated the
4121: // drag has an associated drop target. MOUSE_ENTERED comes when the
4122: // mouse is in the native container already. To propagate this event
4123: // properly we should null out targetLastEntered.
4124: targetLastEntered = null;
4125: } else if (id != MouseEvent.MOUSE_EXITED
4126: && id != MouseEvent.MOUSE_DRAGGED
4127: && id != LWD_MOUSE_DRAGGED_OVER
4128: && isMouseInNativeContainer == false) {
4129: // any event but an exit or drag means we're in the native container
4130: isMouseInNativeContainer = true;
4131: startListeningForOtherDrags();
4132: } else if (id == MouseEvent.MOUSE_EXITED) {
4133: isMouseInNativeContainer = false;
4134: stopListeningForOtherDrags();
4135: }
4136:
4137: if (isMouseInNativeContainer) {
4138: targetEnter = targetOver;
4139: }
4140:
4141: if (targetLastEntered == targetEnter) {
4142: return;
4143: }
4144:
4145: if (targetLastEntered != null) {
4146: retargetMouseEvent(targetLastEntered,
4147: MouseEvent.MOUSE_EXITED, e);
4148: }
4149: if (id == MouseEvent.MOUSE_EXITED) {
4150: // consume native exit event if we generate one
4151: e.consume();
4152: }
4153:
4154: if (targetEnter != null) {
4155: retargetMouseEvent(targetEnter, MouseEvent.MOUSE_ENTERED, e);
4156: }
4157: if (id == MouseEvent.MOUSE_ENTERED) {
4158: // consume native enter event if we generate one
4159: e.consume();
4160: }
4161:
4162: targetLastEntered = targetEnter;
4163: }
4164:
4165: /*
4166: * Listens to global mouse drag events so even drags originating
4167: * from other heavyweight containers will generate enter/exit
4168: * events in this container
4169: */
4170: private void startListeningForOtherDrags() {
4171: //System.out.println("Adding AWTEventListener");
4172: java.security.AccessController
4173: .doPrivileged(new java.security.PrivilegedAction() {
4174: public Object run() {
4175: nativeContainer
4176: .getToolkit()
4177: .addAWTEventListener(
4178: LightweightDispatcher.this ,
4179: AWTEvent.MOUSE_EVENT_MASK
4180: | AWTEvent.MOUSE_MOTION_EVENT_MASK);
4181: return null;
4182: }
4183: });
4184: }
4185:
4186: private void stopListeningForOtherDrags() {
4187: //System.out.println("Removing AWTEventListener");
4188: java.security.AccessController
4189: .doPrivileged(new java.security.PrivilegedAction() {
4190: public Object run() {
4191: nativeContainer.getToolkit()
4192: .removeAWTEventListener(
4193: LightweightDispatcher.this );
4194: return null;
4195: }
4196: });
4197: }
4198:
4199: /*
4200: * (Implementation of AWTEventListener)
4201: * Listen for drag events posted in other hw components so we can
4202: * track enter/exit regardless of where a drag originated
4203: */
4204: public void eventDispatched(AWTEvent e) {
4205: boolean isForeignDrag = (e instanceof MouseEvent)
4206: && !(e instanceof SunDropTargetEvent)
4207: && (e.id == MouseEvent.MOUSE_DRAGGED)
4208: && (e.getSource() != nativeContainer);
4209:
4210: if (!isForeignDrag) {
4211: // only interested in drags from other hw components
4212: return;
4213: }
4214:
4215: MouseEvent srcEvent = (MouseEvent) e;
4216: MouseEvent me;
4217:
4218: synchronized (nativeContainer.getTreeLock()) {
4219: Component srcComponent = srcEvent.getComponent();
4220:
4221: // component may have disappeared since drag event posted
4222: // (i.e. Swing hierarchical menus)
4223: if (!srcComponent.isShowing()) {
4224: return;
4225: }
4226:
4227: // see 5083555
4228: // check if srcComponent is in any modal blocked window
4229: Component c = nativeContainer;
4230: while ((c != null) && !(c instanceof Window)) {
4231: c = c.getParent_NoClientCode();
4232: }
4233: if ((c == null) || ((Window) c).isModalBlocked()) {
4234: return;
4235: }
4236:
4237: //
4238: // create an internal 'dragged-over' event indicating
4239: // we are being dragged over from another hw component
4240: //
4241: me = new MouseEvent(
4242: nativeContainer,
4243: LWD_MOUSE_DRAGGED_OVER,
4244: srcEvent.getWhen(),
4245: srcEvent.getModifiersEx() | srcEvent.getModifiers(),
4246: srcEvent.getX(), srcEvent.getY(), srcEvent
4247: .getXOnScreen(), srcEvent.getYOnScreen(),
4248: srcEvent.getClickCount(),
4249: srcEvent.isPopupTrigger(), srcEvent.getButton());
4250: ((AWTEvent) srcEvent).copyPrivateDataInto(me);
4251: // translate coordinates to this native container
4252: final Point ptSrcOrigin = srcComponent
4253: .getLocationOnScreen();
4254:
4255: if (AppContext.getAppContext() != nativeContainer.appContext) {
4256: final MouseEvent mouseEvent = me;
4257: Runnable r = new Runnable() {
4258: public void run() {
4259: if (!nativeContainer.isShowing()) {
4260: return;
4261: }
4262:
4263: Point ptDstOrigin = nativeContainer
4264: .getLocationOnScreen();
4265: mouseEvent.translatePoint(ptSrcOrigin.x
4266: - ptDstOrigin.x, ptSrcOrigin.y
4267: - ptDstOrigin.y);
4268: Component targetOver = nativeContainer
4269: .getMouseEventTarget(mouseEvent.getX(),
4270: mouseEvent.getY(),
4271: Container.INCLUDE_SELF);
4272: trackMouseEnterExit(targetOver, mouseEvent);
4273: }
4274: };
4275: SunToolkit.executeOnEventHandlerThread(nativeContainer,
4276: r);
4277: return;
4278: } else {
4279: if (!nativeContainer.isShowing()) {
4280: return;
4281: }
4282:
4283: Point ptDstOrigin = nativeContainer
4284: .getLocationOnScreen();
4285: me.translatePoint(ptSrcOrigin.x - ptDstOrigin.x,
4286: ptSrcOrigin.y - ptDstOrigin.y);
4287: }
4288: }
4289: //System.out.println("Track event: " + me);
4290: // feed the 'dragged-over' event directly to the enter/exit
4291: // code (not a real event so don't pass it to dispatchEvent)
4292: Component targetOver = nativeContainer.getMouseEventTarget(me
4293: .getX(), me.getY(), Container.INCLUDE_SELF);
4294: trackMouseEnterExit(targetOver, me);
4295: }
4296:
4297: /**
4298: * Sends a mouse event to the current mouse event recipient using
4299: * the given event (sent to the windowed host) as a srcEvent. If
4300: * the mouse event target is still in the component tree, the
4301: * coordinates of the event are translated to those of the target.
4302: * If the target has been removed, we don't bother to send the
4303: * message.
4304: */
4305: void retargetMouseEvent(Component target, int id, MouseEvent e) {
4306: if (target == null) {
4307: return; // mouse is over another hw component or target is disabled
4308: }
4309:
4310: int x = e.getX(), y = e.getY();
4311: Component component;
4312:
4313: for (component = target; component != null
4314: && component != nativeContainer; component = component
4315: .getParent()) {
4316: x -= component.x;
4317: y -= component.y;
4318: }
4319: MouseEvent retargeted;
4320: if (component != null) {
4321: if (e instanceof SunDropTargetEvent) {
4322: retargeted = new SunDropTargetEvent(target, id, x, y,
4323: ((SunDropTargetEvent) e).getDispatcher());
4324: } else if (id == MouseEvent.MOUSE_WHEEL) {
4325: retargeted = new MouseWheelEvent(target, id, e
4326: .getWhen(), e.getModifiersEx()
4327: | e.getModifiers(), x, y, e.getXOnScreen(), e
4328: .getYOnScreen(), e.getClickCount(), e
4329: .isPopupTrigger(), ((MouseWheelEvent) e)
4330: .getScrollType(), ((MouseWheelEvent) e)
4331: .getScrollAmount(), ((MouseWheelEvent) e)
4332: .getWheelRotation());
4333: } else {
4334: retargeted = new MouseEvent(target, id, e.getWhen(), e
4335: .getModifiersEx()
4336: | e.getModifiers(), x, y, e.getXOnScreen(), e
4337: .getYOnScreen(), e.getClickCount(), e
4338: .isPopupTrigger(), e.getButton());
4339: }
4340:
4341: ((AWTEvent) e).copyPrivateDataInto(retargeted);
4342:
4343: if (target == nativeContainer) {
4344: // avoid recursively calling LightweightDispatcher...
4345: ((Container) target).dispatchEventToSelf(retargeted);
4346: } else {
4347: assert AppContext.getAppContext() == target.appContext;
4348:
4349: if (nativeContainer.modalComp != null) {
4350: if (((Container) nativeContainer.modalComp)
4351: .isAncestorOf(target)) {
4352: target.dispatchEvent(retargeted);
4353: } else {
4354: e.consume();
4355: }
4356: } else {
4357: target.dispatchEvent(retargeted);
4358: }
4359: }
4360: }
4361: }
4362:
4363: // --- member variables -------------------------------
4364:
4365: /**
4366: * The windowed container that might be hosting events for
4367: * subcomponents.
4368: */
4369: private Container nativeContainer;
4370:
4371: /**
4372: * This variable is not used, but kept for serialization compatibility
4373: */
4374: private Component focus;
4375:
4376: /**
4377: * The current subcomponent being hosted by this windowed
4378: * component that has events being forwarded to it. If this
4379: * is null, there are currently no events being forwarded to
4380: * a subcomponent.
4381: */
4382: private transient Component mouseEventTarget;
4383:
4384: /**
4385: * The last component entered
4386: */
4387: private transient Component targetLastEntered;
4388:
4389: /**
4390: * Is the mouse over the native container
4391: */
4392: private transient boolean isMouseInNativeContainer = false;
4393:
4394: /**
4395: * This variable is not used, but kept for serialization compatibility
4396: */
4397: private Cursor nativeCursor;
4398:
4399: /**
4400: * The event mask for contained lightweight components. Lightweight
4401: * components need a windowed container to host window-related
4402: * events. This separate mask indicates events that have been
4403: * requested by contained lightweight components without effecting
4404: * the mask of the windowed component itself.
4405: */
4406: private long eventMask;
4407:
4408: /**
4409: * The kind of events routed to lightweight components from windowed
4410: * hosts.
4411: */
4412: private static final long PROXY_EVENT_MASK = AWTEvent.FOCUS_EVENT_MASK
4413: | AWTEvent.KEY_EVENT_MASK
4414: | AWTEvent.MOUSE_EVENT_MASK
4415: | AWTEvent.MOUSE_MOTION_EVENT_MASK
4416: | AWTEvent.MOUSE_WHEEL_EVENT_MASK;
4417:
4418: private static final long MOUSE_MASK = AWTEvent.MOUSE_EVENT_MASK
4419: | AWTEvent.MOUSE_MOTION_EVENT_MASK
4420: | AWTEvent.MOUSE_WHEEL_EVENT_MASK;
4421: }
|