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 }
|