1 /* 2 * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package java.awt; 26 27 import java.awt.dnd.DropTarget; 28 29 import java.awt.event.*; 30 31 import java.awt.peer.ContainerPeer; 32 import java.awt.peer.ComponentPeer; 33 import java.awt.peer.LightweightPeer; 34 35 import java.beans.PropertyChangeListener; 36 37 import java.io.IOException; 38 import java.io.ObjectInputStream; 39 import java.io.ObjectOutputStream; 40 import java.io.ObjectStreamField; 41 import java.io.PrintStream; 42 import java.io.PrintWriter; 43 44 import java.security.AccessController; 45 46 import java.util.Arrays; 47 import java.util.EventListener; 48 import java.util.HashSet; 49 import java.util.Set; 50 51 import javax.accessibility.*; 52 53 import sun.util.logging.PlatformLogger; 54 55 import sun.awt.AppContext; 56 import sun.awt.AWTAccessor; 57 import sun.awt.CausedFocusEvent; 58 import sun.awt.PeerEvent; 59 import sun.awt.SunToolkit; 60 61 import sun.awt.dnd.SunDropTargetEvent; 62 63 import sun.java2d.pipe.Region; 64 65 import sun.security.action.GetBooleanAction; 66 67 /** 68 * A generic Abstract Window Toolkit(AWT) container object is a component 69 * that can contain other AWT components. 70 * <p> 71 * Components added to a container are tracked in a list. The order 72 * of the list will define the components' front-to-back stacking order 73 * within the container. If no index is specified when adding a 74 * component to a container, it will be added to the end of the list 75 * (and hence to the bottom of the stacking order). 76 * <p> 77 * <b>Note</b>: For details on the focus subsystem, see 78 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html"> 79 * How to Use the Focus Subsystem</a>, 80 * a section in <em>The Java Tutorial</em>, and the 81 * <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a> 82 * for more information. 83 * 84 * @author Arthur van Hoff 85 * @author Sami Shaio 86 * @see #add(java.awt.Component, int) 87 * @see #getComponent(int) 88 * @see LayoutManager 89 * @since JDK1.0 90 */ 91 public class Container extends Component { 92 93 private static final PlatformLogger log = PlatformLogger.getLogger("java.awt.Container"); 94 private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.Container"); 95 96 private static final Component[] EMPTY_ARRAY = new Component[0]; 97 98 /** 99 * The components in this container. 100 * @see #add 101 * @see #getComponents 102 */ 103 private java.util.List<Component> component = new java.util.ArrayList<Component>(); 104 105 /** 106 * Layout manager for this container. 107 * @see #doLayout 108 * @see #setLayout 109 * @see #getLayout 110 */ 111 LayoutManager layoutMgr; 112 113 /** 114 * Event router for lightweight components. If this container 115 * is native, this dispatcher takes care of forwarding and 116 * retargeting the events to lightweight components contained 117 * (if any). 118 */ 119 private LightweightDispatcher dispatcher; 120 121 /** 122 * The focus traversal policy that will manage keyboard traversal of this 123 * Container's children, if this Container is a focus cycle root. If the 124 * value is null, this Container inherits its policy from its focus-cycle- 125 * root ancestor. If all such ancestors of this Container have null 126 * policies, then the current KeyboardFocusManager's default policy is 127 * used. If the value is non-null, this policy will be inherited by all 128 * focus-cycle-root children that have no keyboard-traversal policy of 129 * their own (as will, recursively, their focus-cycle-root children). 130 * <p> 131 * If this Container is not a focus cycle root, the value will be 132 * remembered, but will not be used or inherited by this or any other 133 * Containers until this Container is made a focus cycle root. 134 * 135 * @see #setFocusTraversalPolicy 136 * @see #getFocusTraversalPolicy 137 * @since 1.4 138 */ 139 private transient FocusTraversalPolicy focusTraversalPolicy; 140 141 /** 142 * Indicates whether this Component is the root of a focus traversal cycle. 143 * Once focus enters a traversal cycle, typically it cannot leave it via 144 * focus traversal unless one of the up- or down-cycle keys is pressed. 145 * Normal traversal is limited to this Container, and all of this 146 * Container's descendants that are not descendants of inferior focus cycle 147 * roots. 148 * 149 * @see #setFocusCycleRoot 150 * @see #isFocusCycleRoot 151 * @since 1.4 152 */ 153 private boolean focusCycleRoot = false; 154 155 156 /** 157 * Stores the value of focusTraversalPolicyProvider property. 158 * @since 1.5 159 * @see #setFocusTraversalPolicyProvider 160 */ 161 private boolean focusTraversalPolicyProvider; 162 163 // keeps track of the threads that are printing this component 164 private transient Set<Thread> printingThreads; 165 // True if there is at least one thread that's printing this component 166 private transient boolean printing = false; 167 168 transient ContainerListener containerListener; 169 170 /* HierarchyListener and HierarchyBoundsListener support */ 171 transient int listeningChildren; 172 transient int listeningBoundsChildren; 173 transient int descendantsCount; 174 175 /* Non-opaque window support -- see Window.setLayersOpaque */ 176 transient Color preserveBackgroundColor = null; 177 178 /** 179 * JDK 1.1 serialVersionUID 180 */ 181 private static final long serialVersionUID = 4613797578919906343L; 182 183 /** 184 * A constant which toggles one of the controllable behaviors 185 * of <code>getMouseEventTarget</code>. It is used to specify whether 186 * the method can return the Container on which it is originally called 187 * in case if none of its children are the current mouse event targets. 188 * 189 * @see #getMouseEventTarget(int, int, boolean, boolean, boolean) 190 */ 191 static final boolean INCLUDE_SELF = true; 192 193 /** 194 * A constant which toggles one of the controllable behaviors 195 * of <code>getMouseEventTarget</code>. It is used to specify whether 196 * the method should search only lightweight components. 197 * 198 * @see #getMouseEventTarget(int, int, boolean, boolean, boolean) 199 */ 200 static final boolean SEARCH_HEAVYWEIGHTS = true; 201 202 /* 203 * Number of HW or LW components in this container (including 204 * all descendant containers). 205 */ 206 private transient int numOfHWComponents = 0; 207 private transient int numOfLWComponents = 0; 208 209 private static final PlatformLogger mixingLog = PlatformLogger.getLogger("java.awt.mixing.Container"); 210 211 /** 212 * @serialField ncomponents int 213 * The number of components in this container. 214 * This value can be null. 215 * @serialField component Component[] 216 * The components in this container. 217 * @serialField layoutMgr LayoutManager 218 * Layout manager for this container. 219 * @serialField dispatcher LightweightDispatcher 220 * Event router for lightweight components. If this container 221 * is native, this dispatcher takes care of forwarding and 222 * retargeting the events to lightweight components contained 223 * (if any). 224 * @serialField maxSize Dimension 225 * Maximum size of this Container. 226 * @serialField focusCycleRoot boolean 227 * Indicates whether this Component is the root of a focus traversal cycle. 228 * Once focus enters a traversal cycle, typically it cannot leave it via 229 * focus traversal unless one of the up- or down-cycle keys is pressed. 230 * Normal traversal is limited to this Container, and all of this 231 * Container's descendants that are not descendants of inferior focus cycle 232 * roots. 233 * @serialField containerSerializedDataVersion int 234 * Container Serial Data Version. 235 * @serialField focusTraversalPolicyProvider boolean 236 * Stores the value of focusTraversalPolicyProvider property. 237 */ 238 private static final ObjectStreamField[] serialPersistentFields = { 239 new ObjectStreamField("ncomponents", Integer.TYPE), 240 new ObjectStreamField("component", Component[].class), 241 new ObjectStreamField("layoutMgr", LayoutManager.class), 242 new ObjectStreamField("dispatcher", LightweightDispatcher.class), 243 new ObjectStreamField("maxSize", Dimension.class), 244 new ObjectStreamField("focusCycleRoot", Boolean.TYPE), 245 new ObjectStreamField("containerSerializedDataVersion", Integer.TYPE), 246 new ObjectStreamField("focusTraversalPolicyProvider", Boolean.TYPE), 247 }; 248 249 static { 250 /* ensure that the necessary native libraries are loaded */ 251 Toolkit.loadLibraries(); 252 if (!GraphicsEnvironment.isHeadless()) { 253 initIDs(); 254 } 255 256 AWTAccessor.setContainerAccessor(new AWTAccessor.ContainerAccessor() { 257 @Override 258 public void validateUnconditionally(Container cont) { 259 cont.validateUnconditionally(); 260 } 261 }); 262 } 263 264 /** 265 * Initialize JNI field and method IDs for fields that may be 266 called from C. 267 */ 268 private static native void initIDs(); 269 270 /** 271 * Constructs a new Container. Containers can be extended directly, 272 * but are lightweight in this case and must be contained by a parent 273 * somewhere higher up in the component tree that is native. 274 * (such as Frame for example). 275 */ 276 public Container() { 277 } 278 @SuppressWarnings({"unchecked","rawtypes"}) 279 void initializeFocusTraversalKeys() { 280 focusTraversalKeys = new Set[4]; 281 } 282 283 /** 284 * Gets the number of components in this panel. 285 * <p> 286 * Note: This method should be called under AWT tree lock. 287 * 288 * @return the number of components in this panel. 289 * @see #getComponent 290 * @since JDK1.1 291 * @see Component#getTreeLock() 292 */ 293 public int getComponentCount() { 294 return countComponents(); 295 } 296 297 /** 298 * @deprecated As of JDK version 1.1, 299 * replaced by getComponentCount(). 300 */ 301 @Deprecated 302 public int countComponents() { 303 // This method is not synchronized under AWT tree lock. 304 // Instead, the calling code is responsible for the 305 // synchronization. See 6784816 for details. 306 return component.size(); 307 } 308 309 /** 310 * Gets the nth component in this container. 311 * <p> 312 * Note: This method should be called under AWT tree lock. 313 * 314 * @param n the index of the component to get. 315 * @return the n<sup>th</sup> component in this container. 316 * @exception ArrayIndexOutOfBoundsException 317 * if the n<sup>th</sup> value does not exist. 318 * @see Component#getTreeLock() 319 */ 320 public Component getComponent(int n) { 321 // This method is not synchronized under AWT tree lock. 322 // Instead, the calling code is responsible for the 323 // synchronization. See 6784816 for details. 324 try { 325 return component.get(n); 326 } catch (IndexOutOfBoundsException z) { 327 throw new ArrayIndexOutOfBoundsException("No such child: " + n); 328 } 329 } 330 331 /** 332 * Gets all the components in this container. 333 * <p> 334 * Note: This method should be called under AWT tree lock. 335 * 336 * @return an array of all the components in this container. 337 * @see Component#getTreeLock() 338 */ 339 public Component[] getComponents() { 340 // This method is not synchronized under AWT tree lock. 341 // Instead, the calling code is responsible for the 342 // synchronization. See 6784816 for details. 343 return getComponents_NoClientCode(); 344 } 345 346 // NOTE: This method may be called by privileged threads. 347 // This functionality is implemented in a package-private method 348 // to insure that it cannot be overridden by client subclasses. 349 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 350 final Component[] getComponents_NoClientCode() { 351 return component.toArray(EMPTY_ARRAY); 352 } 353 354 /* 355 * Wrapper for getComponents() method with a proper synchronization. 356 */ 357 Component[] getComponentsSync() { 358 synchronized (getTreeLock()) { 359 return getComponents(); 360 } 361 } 362 363 /** 364 * Determines the insets of this container, which indicate the size 365 * of the container's border. 366 * <p> 367 * A <code>Frame</code> object, for example, has a top inset that 368 * corresponds to the height of the frame's title bar. 369 * @return the insets of this container. 370 * @see Insets 371 * @see LayoutManager 372 * @since JDK1.1 373 */ 374 public Insets getInsets() { 375 return insets(); 376 } 377 378 /** 379 * @deprecated As of JDK version 1.1, 380 * replaced by <code>getInsets()</code>. 381 */ 382 @Deprecated 383 public Insets insets() { 384 ComponentPeer peer = this.peer; 385 if (peer instanceof ContainerPeer) { 386 ContainerPeer cpeer = (ContainerPeer)peer; 387 return (Insets)cpeer.getInsets().clone(); 388 } 389 return new Insets(0, 0, 0, 0); 390 } 391 392 /** 393 * Appends the specified component to the end of this container. 394 * This is a convenience method for {@link #addImpl}. 395 * <p> 396 * This method changes layout-related information, and therefore, 397 * invalidates the component hierarchy. If the container has already been 398 * displayed, the hierarchy must be validated thereafter in order to 399 * display the added component. 400 * 401 * @param comp the component to be added 402 * @exception NullPointerException if {@code comp} is {@code null} 403 * @see #addImpl 404 * @see #invalidate 405 * @see #validate 406 * @see javax.swing.JComponent#revalidate() 407 * @return the component argument 408 */ 409 public Component add(Component comp) { 410 addImpl(comp, null, -1); 411 return comp; 412 } 413 414 /** 415 * Adds the specified component to this container. 416 * This is a convenience method for {@link #addImpl}. 417 * <p> 418 * This method is obsolete as of 1.1. Please use the 419 * method <code>add(Component, Object)</code> instead. 420 * <p> 421 * This method changes layout-related information, and therefore, 422 * invalidates the component hierarchy. If the container has already been 423 * displayed, the hierarchy must be validated thereafter in order to 424 * display the added component. 425 * 426 * @exception NullPointerException if {@code comp} is {@code null} 427 * @see #add(Component, Object) 428 * @see #invalidate 429 */ 430 public Component add(String name, Component comp) { 431 addImpl(comp, name, -1); 432 return comp; 433 } 434 435 /** 436 * Adds the specified component to this container at the given 437 * position. 438 * This is a convenience method for {@link #addImpl}. 439 * <p> 440 * This method changes layout-related information, and therefore, 441 * invalidates the component hierarchy. If the container has already been 442 * displayed, the hierarchy must be validated thereafter in order to 443 * display the added component. 444 * 445 * 446 * @param comp the component to be added 447 * @param index the position at which to insert the component, 448 * or <code>-1</code> to append the component to the end 449 * @exception NullPointerException if {@code comp} is {@code null} 450 * @exception IllegalArgumentException if {@code index} is invalid (see 451 * {@link #addImpl} for details) 452 * @return the component <code>comp</code> 453 * @see #addImpl 454 * @see #remove 455 * @see #invalidate 456 * @see #validate 457 * @see javax.swing.JComponent#revalidate() 458 */ 459 public Component add(Component comp, int index) { 460 addImpl(comp, null, index); 461 return comp; 462 } 463 464 /** 465 * Checks that the component 466 * isn't supposed to be added into itself. 467 */ 468 private void checkAddToSelf(Component comp){ 469 if (comp instanceof Container) { 470 for (Container cn = this; cn != null; cn=cn.parent) { 471 if (cn == comp) { 472 throw new IllegalArgumentException("adding container's parent to itself"); 473 } 474 } 475 } 476 } 477 478 /** 479 * Checks that the component is not a Window instance. 480 */ 481 private void checkNotAWindow(Component comp){ 482 if (comp instanceof Window) { 483 throw new IllegalArgumentException("adding a window to a container"); 484 } 485 } 486 487 /** 488 * Checks that the component comp can be added to this container 489 * Checks : index in bounds of container's size, 490 * comp is not one of this container's parents, 491 * and comp is not a window. 492 * Comp and container must be on the same GraphicsDevice. 493 * if comp is container, all sub-components must be on 494 * same GraphicsDevice. 495 * 496 * @since 1.5 497 */ 498 private void checkAdding(Component comp, int index) { 499 checkTreeLock(); 500 501 GraphicsConfiguration thisGC = getGraphicsConfiguration(); 502 503 if (index > component.size() || index < 0) { 504 throw new IllegalArgumentException("illegal component position"); 505 } 506 if (comp.parent == this) { 507 if (index == component.size()) { 508 throw new IllegalArgumentException("illegal component position " + 509 index + " should be less then " + component.size()); 510 } 511 } 512 checkAddToSelf(comp); 513 checkNotAWindow(comp); 514 515 Window thisTopLevel = getContainingWindow(); 516 Window compTopLevel = comp.getContainingWindow(); 517 if (thisTopLevel != compTopLevel) { 518 throw new IllegalArgumentException("component and container should be in the same top-level window"); 519 } 520 if (thisGC != null) { 521 comp.checkGD(thisGC.getDevice().getIDstring()); 522 } 523 } 524 525 /** 526 * Removes component comp from this container without making unneccessary changes 527 * and generating unneccessary events. This function intended to perform optimized 528 * remove, for example, if newParent and current parent are the same it just changes 529 * index without calling removeNotify. 530 * Note: Should be called while holding treeLock 531 * Returns whether removeNotify was invoked 532 * @since: 1.5 533 */ 534 private boolean removeDelicately(Component comp, Container newParent, int newIndex) { 535 checkTreeLock(); 536 537 int index = getComponentZOrder(comp); 538 boolean needRemoveNotify = isRemoveNotifyNeeded(comp, this, newParent); 539 if (needRemoveNotify) { 540 comp.removeNotify(); 541 } 542 if (newParent != this) { 543 if (layoutMgr != null) { 544 layoutMgr.removeLayoutComponent(comp); 545 } 546 adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK, 547 -comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK)); 548 adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 549 -comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); 550 adjustDescendants(-(comp.countHierarchyMembers())); 551 552 comp.parent = null; 553 if (needRemoveNotify) { 554 comp.setGraphicsConfiguration(null); 555 } 556 component.remove(index); 557 558 invalidateIfValid(); 559 } else { 560 // We should remove component and then 561 // add it by the newIndex without newIndex decrement if even we shift components to the left 562 // after remove. Consult the rules below: 563 // 2->4: 012345 -> 013425, 2->5: 012345 -> 013452 564 // 4->2: 012345 -> 014235 565 component.remove(index); 566 component.add(newIndex, comp); 567 } 568 if (comp.parent == null) { // was actually removed 569 if (containerListener != null || 570 (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 || 571 Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) { 572 ContainerEvent e = new ContainerEvent(this, 573 ContainerEvent.COMPONENT_REMOVED, 574 comp); 575 dispatchEvent(e); 576 577 } 578 comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp, 579 this, HierarchyEvent.PARENT_CHANGED, 580 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK)); 581 if (peer != null && layoutMgr == null && isVisible()) { 582 updateCursorImmediately(); 583 } 584 } 585 return needRemoveNotify; 586 } 587 588 /** 589 * Checks whether this container can contain component which is focus owner. 590 * Verifies that container is enable and showing, and if it is focus cycle root 591 * its FTP allows component to be focus owner 592 * @since 1.5 593 */ 594 boolean canContainFocusOwner(Component focusOwnerCandidate) { 595 if (!(isEnabled() && isDisplayable() 596 && isVisible() && isFocusable())) 597 { 598 return false; 599 } 600 if (isFocusCycleRoot()) { 601 FocusTraversalPolicy policy = getFocusTraversalPolicy(); 602 if (policy instanceof DefaultFocusTraversalPolicy) { 603 if (!((DefaultFocusTraversalPolicy)policy).accept(focusOwnerCandidate)) { 604 return false; 605 } 606 } 607 } 608 synchronized(getTreeLock()) { 609 if (parent != null) { 610 return parent.canContainFocusOwner(focusOwnerCandidate); 611 } 612 } 613 return true; 614 } 615 616 /** 617 * Checks whether or not this container has heavyweight children. 618 * Note: Should be called while holding tree lock 619 * @return true if there is at least one heavyweight children in a container, false otherwise 620 * @since 1.5 621 */ 622 final boolean hasHeavyweightDescendants() { 623 checkTreeLock(); 624 return numOfHWComponents > 0; 625 } 626 627 /** 628 * Checks whether or not this container has lightweight children. 629 * Note: Should be called while holding tree lock 630 * @return true if there is at least one lightweight children in a container, false otherwise 631 * @since 1.7 632 */ 633 final boolean hasLightweightDescendants() { 634 checkTreeLock(); 635 return numOfLWComponents > 0; 636 } 637 638 /** 639 * Returns closest heavyweight component to this container. If this container is heavyweight 640 * returns this. 641 * @since 1.5 642 */ 643 Container getHeavyweightContainer() { 644 checkTreeLock(); 645 if (peer != null && !(peer instanceof LightweightPeer)) { 646 return this; 647 } else { 648 return getNativeContainer(); 649 } 650 } 651 652 /** 653 * Detects whether or not remove from current parent and adding to new parent requires call of 654 * removeNotify on the component. Since removeNotify destroys native window this might (not) 655 * be required. For example, if new container and old containers are the same we don't need to 656 * destroy native window. 657 * @since: 1.5 658 */ 659 private static boolean isRemoveNotifyNeeded(Component comp, Container oldContainer, Container newContainer) { 660 if (oldContainer == null) { // Component didn't have parent - no removeNotify 661 return false; 662 } 663 if (comp.peer == null) { // Component didn't have peer - no removeNotify 664 return false; 665 } 666 if (newContainer.peer == null) { 667 // Component has peer but new Container doesn't - call removeNotify 668 return true; 669 } 670 671 // If component is lightweight non-Container or lightweight Container with all but heavyweight 672 // children there is no need to call remove notify 673 if (comp.isLightweight()) { 674 boolean isContainer = comp instanceof Container; 675 676 if (!isContainer || (isContainer && !((Container)comp).hasHeavyweightDescendants())) { 677 return false; 678 } 679 } 680 681 // If this point is reached, then the comp is either a HW or a LW container with HW descendants. 682 683 // All three components have peers, check for peer change 684 Container newNativeContainer = oldContainer.getHeavyweightContainer(); 685 Container oldNativeContainer = newContainer.getHeavyweightContainer(); 686 if (newNativeContainer != oldNativeContainer) { 687 // Native containers change - check whether or not current platform supports 688 // changing of widget hierarchy on native level without recreation. 689 // The current implementation forbids reparenting of LW containers with HW descendants 690 // into another native container w/o destroying the peers. Actually such an operation 691 // is quite rare. If we ever need to save the peers, we'll have to slightly change the 692 // addDelicately() method in order to handle such LW containers recursively, reparenting 693 // each HW descendant independently. 694 return !comp.peer.isReparentSupported(); 695 } else { 696 return false; 697 } 698 } 699 700 /** 701 * Moves the specified component to the specified z-order index in 702 * the container. The z-order determines the order that components 703 * are painted; the component with the highest z-order paints first 704 * and the component with the lowest z-order paints last. 705 * Where components overlap, the component with the lower 706 * z-order paints over the component with the higher z-order. 707 * <p> 708 * If the component is a child of some other container, it is 709 * removed from that container before being added to this container. 710 * The important difference between this method and 711 * <code>java.awt.Container.add(Component, int)</code> is that this method 712 * doesn't call <code>removeNotify</code> on the component while 713 * removing it from its previous container unless necessary and when 714 * allowed by the underlying native windowing system. This way, if the 715 * component has the keyboard focus, it maintains the focus when 716 * moved to the new position. 717 * <p> 718 * This property is guaranteed to apply only to lightweight 719 * non-<code>Container</code> components. 720 * <p> 721 * This method changes layout-related information, and therefore, 722 * invalidates the component hierarchy. 723 * <p> 724 * <b>Note</b>: Not all platforms support changing the z-order of 725 * heavyweight components from one container into another without 726 * the call to <code>removeNotify</code>. There is no way to detect 727 * whether a platform supports this, so developers shouldn't make 728 * any assumptions. 729 * 730 * @param comp the component to be moved 731 * @param index the position in the container's list to 732 * insert the component, where <code>getComponentCount()</code> 733 * appends to the end 734 * @exception NullPointerException if <code>comp</code> is 735 * <code>null</code> 736 * @exception IllegalArgumentException if <code>comp</code> is one of the 737 * container's parents 738 * @exception IllegalArgumentException if <code>index</code> is not in 739 * the range <code>[0, getComponentCount()]</code> for moving 740 * between containers, or not in the range 741 * <code>[0, getComponentCount()-1]</code> for moving inside 742 * a container 743 * @exception IllegalArgumentException if adding a container to itself 744 * @exception IllegalArgumentException if adding a <code>Window</code> 745 * to a container 746 * @see #getComponentZOrder(java.awt.Component) 747 * @see #invalidate 748 * @since 1.5 749 */ 750 public void setComponentZOrder(Component comp, int index) { 751 synchronized (getTreeLock()) { 752 // Store parent because remove will clear it 753 Container curParent = comp.parent; 754 int oldZindex = getComponentZOrder(comp); 755 756 if (curParent == this && index == oldZindex) { 757 return; 758 } 759 checkAdding(comp, index); 760 761 boolean peerRecreated = (curParent != null) ? 762 curParent.removeDelicately(comp, this, index) : false; 763 764 addDelicately(comp, curParent, index); 765 766 // If the oldZindex == -1, the component gets inserted, 767 // rather than it changes its z-order. 768 if (!peerRecreated && oldZindex != -1) { 769 // The new 'index' cannot be == -1. 770 // It gets checked at the checkAdding() method. 771 // Therefore both oldZIndex and index denote 772 // some existing positions at this point and 773 // this is actually a Z-order changing. 774 comp.mixOnZOrderChanging(oldZindex, index); 775 } 776 } 777 } 778 779 /** 780 * Traverses the tree of components and reparents children heavyweight component 781 * to new heavyweight parent. 782 * @since 1.5 783 */ 784 private void reparentTraverse(ContainerPeer parentPeer, Container child) { 785 checkTreeLock(); 786 787 for (int i = 0; i < child.getComponentCount(); i++) { 788 Component comp = child.getComponent(i); 789 if (comp.isLightweight()) { 790 // If components is lightweight check if it is container 791 // If it is container it might contain heavyweight children we need to reparent 792 if (comp instanceof Container) { 793 reparentTraverse(parentPeer, (Container)comp); 794 } 795 } else { 796 // Q: Need to update NativeInLightFixer? 797 comp.getPeer().reparent(parentPeer); 798 } 799 } 800 } 801 802 /** 803 * Reparents child component peer to this container peer. 804 * Container must be heavyweight. 805 * @since 1.5 806 */ 807 private void reparentChild(Component comp) { 808 checkTreeLock(); 809 if (comp == null) { 810 return; 811 } 812 if (comp.isLightweight()) { 813 // If component is lightweight container we need to reparent all its explicit heavyweight children 814 if (comp instanceof Container) { 815 // Traverse component's tree till depth-first until encountering heavyweight component 816 reparentTraverse((ContainerPeer)getPeer(), (Container)comp); 817 } 818 } else { 819 comp.getPeer().reparent((ContainerPeer)getPeer()); 820 } 821 } 822 823 /** 824 * Adds component to this container. Tries to minimize side effects of this adding - 825 * doesn't call remove notify if it is not required. 826 * @since 1.5 827 */ 828 private void addDelicately(Component comp, Container curParent, int index) { 829 checkTreeLock(); 830 831 // Check if moving between containers 832 if (curParent != this) { 833 //index == -1 means add to the end. 834 if (index == -1) { 835 component.add(comp); 836 } else { 837 component.add(index, comp); 838 } 839 comp.parent = this; 840 comp.setGraphicsConfiguration(getGraphicsConfiguration()); 841 842 adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK, 843 comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK)); 844 adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 845 comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); 846 adjustDescendants(comp.countHierarchyMembers()); 847 } else { 848 if (index < component.size()) { 849 component.set(index, comp); 850 } 851 } 852 853 invalidateIfValid(); 854 if (peer != null) { 855 if (comp.peer == null) { // Remove notify was called or it didn't have peer - create new one 856 comp.addNotify(); 857 } else { // Both container and child have peers, it means child peer should be reparented. 858 // In both cases we need to reparent native widgets. 859 Container newNativeContainer = getHeavyweightContainer(); 860 Container oldNativeContainer = curParent.getHeavyweightContainer(); 861 if (oldNativeContainer != newNativeContainer) { 862 // Native container changed - need to reparent native widgets 863 newNativeContainer.reparentChild(comp); 864 } 865 comp.updateZOrder(); 866 867 if (!comp.isLightweight() && isLightweight()) { 868 // If component is heavyweight and one of the containers is lightweight 869 // the location of the component should be fixed. 870 comp.relocateComponent(); 871 } 872 } 873 } 874 if (curParent != this) { 875 /* Notify the layout manager of the added component. */ 876 if (layoutMgr != null) { 877 if (layoutMgr instanceof LayoutManager2) { 878 ((LayoutManager2)layoutMgr).addLayoutComponent(comp, null); 879 } else { 880 layoutMgr.addLayoutComponent(null, comp); 881 } 882 } 883 if (containerListener != null || 884 (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 || 885 Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) { 886 ContainerEvent e = new ContainerEvent(this, 887 ContainerEvent.COMPONENT_ADDED, 888 comp); 889 dispatchEvent(e); 890 } 891 comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp, 892 this, HierarchyEvent.PARENT_CHANGED, 893 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK)); 894 895 // If component is focus owner or parent container of focus owner check that after reparenting 896 // focus owner moved out if new container prohibit this kind of focus owner. 897 if (comp.isFocusOwner() && !comp.canBeFocusOwnerRecursively()) { 898 comp.transferFocus(); 899 } else if (comp instanceof Container) { 900 Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); 901 if (focusOwner != null && isParentOf(focusOwner) && !focusOwner.canBeFocusOwnerRecursively()) { 902 focusOwner.transferFocus(); 903 } 904 } 905 } else { 906 comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp, 907 this, HierarchyEvent.HIERARCHY_CHANGED, 908 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK)); 909 } 910 911 if (peer != null && layoutMgr == null && isVisible()) { 912 updateCursorImmediately(); 913 } 914 } 915 916 /** 917 * Returns the z-order index of the component inside the container. 918 * The higher a component is in the z-order hierarchy, the lower 919 * its index. The component with the lowest z-order index is 920 * painted last, above all other child components. 921 * 922 * @param comp the component being queried 923 * @return the z-order index of the component; otherwise 924 * returns -1 if the component is <code>null</code> 925 * or doesn't belong to the container 926 * @see #setComponentZOrder(java.awt.Component, int) 927 * @since 1.5 928 */ 929 public int getComponentZOrder(Component comp) { 930 if (comp == null) { 931 return -1; 932 } 933 synchronized(getTreeLock()) { 934 // Quick check - container should be immediate parent of the component 935 if (comp.parent != this) { 936 return -1; 937 } 938 return component.indexOf(comp); 939 } 940 } 941 942 /** 943 * Adds the specified component to the end of this container. 944 * Also notifies the layout manager to add the component to 945 * this container's layout using the specified constraints object. 946 * This is a convenience method for {@link #addImpl}. 947 * <p> 948 * This method changes layout-related information, and therefore, 949 * invalidates the component hierarchy. If the container has already been 950 * displayed, the hierarchy must be validated thereafter in order to 951 * display the added component. 952 * 953 * 954 * @param comp the component to be added 955 * @param constraints an object expressing 956 * layout contraints for this component 957 * @exception NullPointerException if {@code comp} is {@code null} 958 * @see #addImpl 959 * @see #invalidate 960 * @see #validate 961 * @see javax.swing.JComponent#revalidate() 962 * @see LayoutManager 963 * @since JDK1.1 964 */ 965 public void add(Component comp, Object constraints) { 966 addImpl(comp, constraints, -1); 967 } 968 969 /** 970 * Adds the specified component to this container with the specified 971 * constraints at the specified index. Also notifies the layout 972 * manager to add the component to the this container's layout using 973 * the specified constraints object. 974 * This is a convenience method for {@link #addImpl}. 975 * <p> 976 * This method changes layout-related information, and therefore, 977 * invalidates the component hierarchy. If the container has already been 978 * displayed, the hierarchy must be validated thereafter in order to 979 * display the added component. 980 * 981 * 982 * @param comp the component to be added 983 * @param constraints an object expressing layout contraints for this 984 * @param index the position in the container's list at which to insert 985 * the component; <code>-1</code> means insert at the end 986 * component 987 * @exception NullPointerException if {@code comp} is {@code null} 988 * @exception IllegalArgumentException if {@code index} is invalid (see 989 * {@link #addImpl} for details) 990 * @see #addImpl 991 * @see #invalidate 992 * @see #validate 993 * @see javax.swing.JComponent#revalidate() 994 * @see #remove 995 * @see LayoutManager 996 */ 997 public void add(Component comp, Object constraints, int index) { 998 addImpl(comp, constraints, index); 999 } 1000 1001 /** 1002 * Adds the specified component to this container at the specified 1003 * index. This method also notifies the layout manager to add 1004 * the component to this container's layout using the specified 1005 * constraints object via the <code>addLayoutComponent</code> 1006 * method. 1007 * <p> 1008 * The constraints are 1009 * defined by the particular layout manager being used. For 1010 * example, the <code>BorderLayout</code> class defines five 1011 * constraints: <code>BorderLayout.NORTH</code>, 1012 * <code>BorderLayout.SOUTH</code>, <code>BorderLayout.EAST</code>, 1013 * <code>BorderLayout.WEST</code>, and <code>BorderLayout.CENTER</code>. 1014 * <p> 1015 * The <code>GridBagLayout</code> class requires a 1016 * <code>GridBagConstraints</code> object. Failure to pass 1017 * the correct type of constraints object results in an 1018 * <code>IllegalArgumentException</code>. 1019 * <p> 1020 * If the current layout manager implements {@code LayoutManager2}, then 1021 * {@link LayoutManager2#addLayoutComponent(Component,Object)} is invoked on 1022 * it. If the current layout manager does not implement 1023 * {@code LayoutManager2}, and constraints is a {@code String}, then 1024 * {@link LayoutManager#addLayoutComponent(String,Component)} is invoked on it. 1025 * <p> 1026 * If the component is not an ancestor of this container and has a non-null 1027 * parent, it is removed from its current parent before it is added to this 1028 * container. 1029 * <p> 1030 * This is the method to override if a program needs to track 1031 * every add request to a container as all other add methods defer 1032 * to this one. An overriding method should 1033 * usually include a call to the superclass's version of the method: 1034 * <p> 1035 * <blockquote> 1036 * <code>super.addImpl(comp, constraints, index)</code> 1037 * </blockquote> 1038 * <p> 1039 * This method changes layout-related information, and therefore, 1040 * invalidates the component hierarchy. If the container has already been 1041 * displayed, the hierarchy must be validated thereafter in order to 1042 * display the added component. 1043 * 1044 * @param comp the component to be added 1045 * @param constraints an object expressing layout constraints 1046 * for this component 1047 * @param index the position in the container's list at which to 1048 * insert the component, where <code>-1</code> 1049 * means append to the end 1050 * @exception IllegalArgumentException if {@code index} is invalid; 1051 * if {@code comp} is a child of this container, the valid 1052 * range is {@code [-1, getComponentCount()-1]}; if component is 1053 * not a child of this container, the valid range is 1054 * {@code [-1, getComponentCount()]} 1055 * 1056 * @exception IllegalArgumentException if {@code comp} is an ancestor of 1057 * this container 1058 * @exception IllegalArgumentException if adding a window to a container 1059 * @exception NullPointerException if {@code comp} is {@code null} 1060 * @see #add(Component) 1061 * @see #add(Component, int) 1062 * @see #add(Component, java.lang.Object) 1063 * @see #invalidate 1064 * @see LayoutManager 1065 * @see LayoutManager2 1066 * @since JDK1.1 1067 */ 1068 protected void addImpl(Component comp, Object constraints, int index) { 1069 synchronized (getTreeLock()) { 1070 /* Check for correct arguments: index in bounds, 1071 * comp cannot be one of this container's parents, 1072 * and comp cannot be a window. 1073 * comp and container must be on the same GraphicsDevice. 1074 * if comp is container, all sub-components must be on 1075 * same GraphicsDevice. 1076 */ 1077 GraphicsConfiguration thisGC = this.getGraphicsConfiguration(); 1078 1079 if (index > component.size() || (index < 0 && index != -1)) { 1080 throw new IllegalArgumentException( 1081 "illegal component position"); 1082 } 1083 checkAddToSelf(comp); 1084 checkNotAWindow(comp); 1085 if (thisGC != null) { 1086 comp.checkGD(thisGC.getDevice().getIDstring()); 1087 } 1088 1089 /* Reparent the component and tidy up the tree's state. */ 1090 if (comp.parent != null) { 1091 comp.parent.remove(comp); 1092 if (index > component.size()) { 1093 throw new IllegalArgumentException("illegal component position"); 1094 } 1095 } 1096 1097 //index == -1 means add to the end. 1098 if (index == -1) { 1099 component.add(comp); 1100 } else { 1101 component.add(index, comp); 1102 } 1103 comp.parent = this; 1104 comp.setGraphicsConfiguration(thisGC); 1105 1106 adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK, 1107 comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK)); 1108 adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 1109 comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); 1110 adjustDescendants(comp.countHierarchyMembers()); 1111 1112 invalidateIfValid(); 1113 if (peer != null) { 1114 comp.addNotify(); 1115 } 1116 1117 /* Notify the layout manager of the added component. */ 1118 if (layoutMgr != null) { 1119 if (layoutMgr instanceof LayoutManager2) { 1120 ((LayoutManager2)layoutMgr).addLayoutComponent(comp, constraints); 1121 } else if (constraints instanceof String) { 1122 layoutMgr.addLayoutComponent((String)constraints, comp); 1123 } 1124 } 1125 if (containerListener != null || 1126 (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 || 1127 Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) { 1128 ContainerEvent e = new ContainerEvent(this, 1129 ContainerEvent.COMPONENT_ADDED, 1130 comp); 1131 dispatchEvent(e); 1132 } 1133 1134 comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp, 1135 this, HierarchyEvent.PARENT_CHANGED, 1136 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK)); 1137 if (peer != null && layoutMgr == null && isVisible()) { 1138 updateCursorImmediately(); 1139 } 1140 } 1141 } 1142 1143 @Override 1144 boolean updateGraphicsData(GraphicsConfiguration gc) { 1145 checkTreeLock(); 1146 1147 boolean ret = super.updateGraphicsData(gc); 1148 1149 for (Component comp : component) { 1150 if (comp != null) { 1151 ret |= comp.updateGraphicsData(gc); 1152 } 1153 } 1154 return ret; 1155 } 1156 1157 /** 1158 * Checks that all Components that this Container contains are on 1159 * the same GraphicsDevice as this Container. If not, throws an 1160 * IllegalArgumentException. 1161 */ 1162 void checkGD(String stringID) { 1163 for (Component comp : component) { 1164 if (comp != null) { 1165 comp.checkGD(stringID); 1166 } 1167 } 1168 } 1169 1170 /** 1171 * Removes the component, specified by <code>index</code>, 1172 * from this container. 1173 * This method also notifies the layout manager to remove the 1174 * component from this container's layout via the 1175 * <code>removeLayoutComponent</code> method. 1176 * <p> 1177 * This method changes layout-related information, and therefore, 1178 * invalidates the component hierarchy. If the container has already been 1179 * displayed, the hierarchy must be validated thereafter in order to 1180 * reflect the changes. 1181 * 1182 * 1183 * @param index the index of the component to be removed 1184 * @throws ArrayIndexOutOfBoundsException if {@code index} is not in 1185 * range {@code [0, getComponentCount()-1]} 1186 * @see #add 1187 * @see #invalidate 1188 * @see #validate 1189 * @see #getComponentCount 1190 * @since JDK1.1 1191 */ 1192 public void remove(int index) { 1193 synchronized (getTreeLock()) { 1194 if (index < 0 || index >= component.size()) { 1195 throw new ArrayIndexOutOfBoundsException(index); 1196 } 1197 Component comp = component.get(index); 1198 if (peer != null) { 1199 comp.removeNotify(); 1200 } 1201 if (layoutMgr != null) { 1202 layoutMgr.removeLayoutComponent(comp); 1203 } 1204 1205 adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK, 1206 -comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK)); 1207 adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 1208 -comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); 1209 adjustDescendants(-(comp.countHierarchyMembers())); 1210 1211 comp.parent = null; 1212 component.remove(index); 1213 comp.setGraphicsConfiguration(null); 1214 1215 invalidateIfValid(); 1216 if (containerListener != null || 1217 (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 || 1218 Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) { 1219 ContainerEvent e = new ContainerEvent(this, 1220 ContainerEvent.COMPONENT_REMOVED, 1221 comp); 1222 dispatchEvent(e); 1223 } 1224 1225 comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp, 1226 this, HierarchyEvent.PARENT_CHANGED, 1227 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK)); 1228 if (peer != null && layoutMgr == null && isVisible()) { 1229 updateCursorImmediately(); 1230 } 1231 } 1232 } 1233 1234 /** 1235 * Removes the specified component from this container. 1236 * This method also notifies the layout manager to remove the 1237 * component from this container's layout via the 1238 * <code>removeLayoutComponent</code> method. 1239 * <p> 1240 * This method changes layout-related information, and therefore, 1241 * invalidates the component hierarchy. If the container has already been 1242 * displayed, the hierarchy must be validated thereafter in order to 1243 * reflect the changes. 1244 * 1245 * @param comp the component to be removed 1246 * @throws NullPointerException if {@code comp} is {@code null} 1247 * @see #add 1248 * @see #invalidate 1249 * @see #validate 1250 * @see #remove(int) 1251 */ 1252 public void remove(Component comp) { 1253 synchronized (getTreeLock()) { 1254 if (comp.parent == this) { 1255 int index = component.indexOf(comp); 1256 if (index >= 0) { 1257 remove(index); 1258 } 1259 } 1260 } 1261 } 1262 1263 /** 1264 * Removes all the components from this container. 1265 * This method also notifies the layout manager to remove the 1266 * components from this container's layout via the 1267 * <code>removeLayoutComponent</code> method. 1268 * <p> 1269 * This method changes layout-related information, and therefore, 1270 * invalidates the component hierarchy. If the container has already been 1271 * displayed, the hierarchy must be validated thereafter in order to 1272 * reflect the changes. 1273 * 1274 * @see #add 1275 * @see #remove 1276 * @see #invalidate 1277 */ 1278 public void removeAll() { 1279 synchronized (getTreeLock()) { 1280 adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK, 1281 -listeningChildren); 1282 adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 1283 -listeningBoundsChildren); 1284 adjustDescendants(-descendantsCount); 1285 1286 while (!component.isEmpty()) { 1287 Component comp = component.remove(component.size()-1); 1288 1289 if (peer != null) { 1290 comp.removeNotify(); 1291 } 1292 if (layoutMgr != null) { 1293 layoutMgr.removeLayoutComponent(comp); 1294 } 1295 comp.parent = null; 1296 comp.setGraphicsConfiguration(null); 1297 if (containerListener != null || 1298 (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 || 1299 Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) { 1300 ContainerEvent e = new ContainerEvent(this, 1301 ContainerEvent.COMPONENT_REMOVED, 1302 comp); 1303 dispatchEvent(e); 1304 } 1305 1306 comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, 1307 comp, this, 1308 HierarchyEvent.PARENT_CHANGED, 1309 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK)); 1310 } 1311 if (peer != null && layoutMgr == null && isVisible()) { 1312 updateCursorImmediately(); 1313 } 1314 invalidateIfValid(); 1315 } 1316 } 1317 1318 // Should only be called while holding tree lock 1319 int numListening(long mask) { 1320 int superListening = super.numListening(mask); 1321 1322 if (mask == AWTEvent.HIERARCHY_EVENT_MASK) { 1323 if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { 1324 // Verify listeningChildren is correct 1325 int sum = 0; 1326 for (Component comp : component) { 1327 sum += comp.numListening(mask); 1328 } 1329 if (listeningChildren != sum) { 1330 eventLog.fine("Assertion (listeningChildren == sum) failed"); 1331 } 1332 } 1333 return listeningChildren + superListening; 1334 } else if (mask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) { 1335 if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { 1336 // Verify listeningBoundsChildren is correct 1337 int sum = 0; 1338 for (Component comp : component) { 1339 sum += comp.numListening(mask); 1340 } 1341 if (listeningBoundsChildren != sum) { 1342 eventLog.fine("Assertion (listeningBoundsChildren == sum) failed"); 1343 } 1344 } 1345 return listeningBoundsChildren + superListening; 1346 } else { 1347 // assert false; 1348 if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { 1349 eventLog.fine("This code must never be reached"); 1350 } 1351 return superListening; 1352 } 1353 } 1354 1355 // Should only be called while holding tree lock 1356 void adjustListeningChildren(long mask, int num) { 1357 if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { 1358 boolean toAssert = (mask == AWTEvent.HIERARCHY_EVENT_MASK || 1359 mask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK || 1360 mask == (AWTEvent.HIERARCHY_EVENT_MASK | 1361 AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); 1362 if (!toAssert) { 1363 eventLog.fine("Assertion failed"); 1364 } 1365 } 1366 1367 if (num == 0) 1368 return; 1369 1370 if ((mask & AWTEvent.HIERARCHY_EVENT_MASK) != 0) { 1371 listeningChildren += num; 1372 } 1373 if ((mask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0) { 1374 listeningBoundsChildren += num; 1375 } 1376 1377 adjustListeningChildrenOnParent(mask, num); 1378 } 1379 1380 // Should only be called while holding tree lock 1381 void adjustDescendants(int num) { 1382 if (num == 0) 1383 return; 1384 1385 descendantsCount += num; 1386 adjustDecendantsOnParent(num); 1387 } 1388 1389 // Should only be called while holding tree lock 1390 void adjustDecendantsOnParent(int num) { 1391 if (parent != null) { 1392 parent.adjustDescendants(num); 1393 } 1394 } 1395 1396 // Should only be called while holding tree lock 1397 int countHierarchyMembers() { 1398 if (log.isLoggable(PlatformLogger.Level.FINE)) { 1399 // Verify descendantsCount is correct 1400 int sum = 0; 1401 for (Component comp : component) { 1402 sum += comp.countHierarchyMembers(); 1403 } 1404 if (descendantsCount != sum) { 1405 log.fine("Assertion (descendantsCount == sum) failed"); 1406 } 1407 } 1408 return descendantsCount + 1; 1409 } 1410 1411 private int getListenersCount(int id, boolean enabledOnToolkit) { 1412 checkTreeLock(); 1413 if (enabledOnToolkit) { 1414 return descendantsCount; 1415 } 1416 switch (id) { 1417 case HierarchyEvent.HIERARCHY_CHANGED: 1418 return listeningChildren; 1419 case HierarchyEvent.ANCESTOR_MOVED: 1420 case HierarchyEvent.ANCESTOR_RESIZED: 1421 return listeningBoundsChildren; 1422 default: 1423 return 0; 1424 } 1425 } 1426 1427 final int createHierarchyEvents(int id, Component changed, 1428 Container changedParent, long changeFlags, boolean enabledOnToolkit) 1429 { 1430 checkTreeLock(); 1431 int listeners = getListenersCount(id, enabledOnToolkit); 1432 1433 for (int count = listeners, i = 0; count > 0; i++) { 1434 count -= component.get(i).createHierarchyEvents(id, changed, 1435 changedParent, changeFlags, enabledOnToolkit); 1436 } 1437 return listeners + 1438 super.createHierarchyEvents(id, changed, changedParent, 1439 changeFlags, enabledOnToolkit); 1440 } 1441 1442 final void createChildHierarchyEvents(int id, long changeFlags, 1443 boolean enabledOnToolkit) 1444 { 1445 checkTreeLock(); 1446 if (component.isEmpty()) { 1447 return; 1448 } 1449 int listeners = getListenersCount(id, enabledOnToolkit); 1450 1451 for (int count = listeners, i = 0; count > 0; i++) { 1452 count -= component.get(i).createHierarchyEvents(id, this, parent, 1453 changeFlags, enabledOnToolkit); 1454 } 1455 } 1456 1457 /** 1458 * Gets the layout manager for this container. 1459 * @see #doLayout 1460 * @see #setLayout 1461 */ 1462 public LayoutManager getLayout() { 1463 return layoutMgr; 1464 } 1465 1466 /** 1467 * Sets the layout manager for this container. 1468 * <p> 1469 * This method changes layout-related information, and therefore, 1470 * invalidates the component hierarchy. 1471 * 1472 * @param mgr the specified layout manager 1473 * @see #doLayout 1474 * @see #getLayout 1475 * @see #invalidate 1476 */ 1477 public void setLayout(LayoutManager mgr) { 1478 layoutMgr = mgr; 1479 invalidateIfValid(); 1480 } 1481 1482 /** 1483 * Causes this container to lay out its components. Most programs 1484 * should not call this method directly, but should invoke 1485 * the <code>validate</code> method instead. 1486 * @see LayoutManager#layoutContainer 1487 * @see #setLayout 1488 * @see #validate 1489 * @since JDK1.1 1490 */ 1491 public void doLayout() { 1492 layout(); 1493 } 1494 1495 /** 1496 * @deprecated As of JDK version 1.1, 1497 * replaced by <code>doLayout()</code>. 1498 */ 1499 @Deprecated 1500 public void layout() { 1501 LayoutManager layoutMgr = this.layoutMgr; 1502 if (layoutMgr != null) { 1503 layoutMgr.layoutContainer(this); 1504 } 1505 } 1506 1507 /** 1508 * Indicates if this container is a <i>validate root</i>. 1509 * <p> 1510 * Layout-related changes, such as bounds of the validate root descendants, 1511 * do not affect the layout of the validate root parent. This peculiarity 1512 * enables the {@code invalidate()} method to stop invalidating the 1513 * component hierarchy when the method encounters a validate root. However, 1514 * to preserve backward compatibility this new optimized behavior is 1515 * enabled only when the {@code java.awt.smartInvalidate} system property 1516 * value is set to {@code true}. 1517 * <p> 1518 * If a component hierarchy contains validate roots and the new optimized 1519 * {@code invalidate()} behavior is enabled, the {@code validate()} method 1520 * must be invoked on the validate root of a previously invalidated 1521 * component to restore the validity of the hierarchy later. Otherwise, 1522 * calling the {@code validate()} method on the top-level container (such 1523 * as a {@code Frame} object) should be used to restore the validity of the 1524 * component hierarchy. 1525 * <p> 1526 * The {@code Window} class and the {@code Applet} class are the validate 1527 * roots in AWT. Swing introduces more validate roots. 1528 * 1529 * @return whether this container is a validate root 1530 * @see #invalidate 1531 * @see java.awt.Component#invalidate 1532 * @see javax.swing.JComponent#isValidateRoot 1533 * @see javax.swing.JComponent#revalidate 1534 * @since 1.7 1535 */ 1536 public boolean isValidateRoot() { 1537 return false; 1538 } 1539 1540 private static final boolean isJavaAwtSmartInvalidate; 1541 static { 1542 // Don't lazy-read because every app uses invalidate() 1543 isJavaAwtSmartInvalidate = AccessController.doPrivileged( 1544 new GetBooleanAction("java.awt.smartInvalidate")); 1545 } 1546 1547 /** 1548 * Invalidates the parent of the container unless the container 1549 * is a validate root. 1550 */ 1551 @Override 1552 void invalidateParent() { 1553 if (!isJavaAwtSmartInvalidate || !isValidateRoot()) { 1554 super.invalidateParent(); 1555 } 1556 } 1557 1558 /** 1559 * Invalidates the container. 1560 * <p> 1561 * If the {@code LayoutManager} installed on this container is an instance 1562 * of the {@code LayoutManager2} interface, then 1563 * the {@link LayoutManager2#invalidateLayout(Container)} method is invoked 1564 * on it supplying this {@code Container} as the argument. 1565 * <p> 1566 * Afterwards this method marks this container invalid, and invalidates its 1567 * ancestors. See the {@link Component#invalidate} method for more details. 1568 * 1569 * @see #validate 1570 * @see #layout 1571 * @see LayoutManager2 1572 */ 1573 @Override 1574 public void invalidate() { 1575 LayoutManager layoutMgr = this.layoutMgr; 1576 if (layoutMgr instanceof LayoutManager2) { 1577 LayoutManager2 lm = (LayoutManager2) layoutMgr; 1578 lm.invalidateLayout(this); 1579 } 1580 super.invalidate(); 1581 } 1582 1583 /** 1584 * Validates this container and all of its subcomponents. 1585 * <p> 1586 * Validating a container means laying out its subcomponents. 1587 * Layout-related changes, such as setting the bounds of a component, or 1588 * adding a component to the container, invalidate the container 1589 * automatically. Note that the ancestors of the container may be 1590 * invalidated also (see {@link Component#invalidate} for details.) 1591 * Therefore, to restore the validity of the hierarchy, the {@code 1592 * validate()} method should be invoked on the top-most invalid 1593 * container of the hierarchy. 1594 * <p> 1595 * Validating the container may be a quite time-consuming operation. For 1596 * performance reasons a developer may postpone the validation of the 1597 * hierarchy till a set of layout-related operations completes, e.g. after 1598 * adding all the children to the container. 1599 * <p> 1600 * If this {@code Container} is not valid, this method invokes 1601 * the {@code validateTree} method and marks this {@code Container} 1602 * as valid. Otherwise, no action is performed. 1603 * 1604 * @see #add(java.awt.Component) 1605 * @see #invalidate 1606 * @see Container#isValidateRoot 1607 * @see javax.swing.JComponent#revalidate() 1608 * @see #validateTree 1609 */ 1610 public void validate() { 1611 boolean updateCur = false; 1612 synchronized (getTreeLock()) { 1613 if ((!isValid() || descendUnconditionallyWhenValidating) 1614 && peer != null) 1615 { 1616 ContainerPeer p = null; 1617 if (peer instanceof ContainerPeer) { 1618 p = (ContainerPeer) peer; 1619 } 1620 if (p != null) { 1621 p.beginValidate(); 1622 } 1623 validateTree(); 1624 if (p != null) { 1625 p.endValidate(); 1626 // Avoid updating cursor if this is an internal call. 1627 // See validateUnconditionally() for details. 1628 if (!descendUnconditionallyWhenValidating) { 1629 updateCur = isVisible(); 1630 } 1631 } 1632 } 1633 } 1634 if (updateCur) { 1635 updateCursorImmediately(); 1636 } 1637 } 1638 1639 /** 1640 * Indicates whether valid containers should also traverse their 1641 * children and call the validateTree() method on them. 1642 * 1643 * Synchronization: TreeLock. 1644 * 1645 * The field is allowed to be static as long as the TreeLock itself is 1646 * static. 1647 * 1648 * @see #validateUnconditionally() 1649 */ 1650 private static boolean descendUnconditionallyWhenValidating = false; 1651 1652 /** 1653 * Unconditionally validate the component hierarchy. 1654 */ 1655 final void validateUnconditionally() { 1656 boolean updateCur = false; 1657 synchronized (getTreeLock()) { 1658 descendUnconditionallyWhenValidating = true; 1659 1660 validate(); 1661 if (peer instanceof ContainerPeer) { 1662 updateCur = isVisible(); 1663 } 1664 1665 descendUnconditionallyWhenValidating = false; 1666 } 1667 if (updateCur) { 1668 updateCursorImmediately(); 1669 } 1670 } 1671 1672 /** 1673 * Recursively descends the container tree and recomputes the 1674 * layout for any subtrees marked as needing it (those marked as 1675 * invalid). Synchronization should be provided by the method 1676 * that calls this one: <code>validate</code>. 1677 * 1678 * @see #doLayout 1679 * @see #validate 1680 */ 1681 protected void validateTree() { 1682 checkTreeLock(); 1683 if (!isValid() || descendUnconditionallyWhenValidating) { 1684 if (peer instanceof ContainerPeer) { 1685 ((ContainerPeer)peer).beginLayout(); 1686 } 1687 if (!isValid()) { 1688 doLayout(); 1689 } 1690 for (int i = 0; i < component.size(); i++) { 1691 Component comp = component.get(i); 1692 if ( (comp instanceof Container) 1693 && !(comp instanceof Window) 1694 && (!comp.isValid() || 1695 descendUnconditionallyWhenValidating)) 1696 { 1697 ((Container)comp).validateTree(); 1698 } else { 1699 comp.validate(); 1700 } 1701 } 1702 if (peer instanceof ContainerPeer) { 1703 ((ContainerPeer)peer).endLayout(); 1704 } 1705 } 1706 super.validate(); 1707 } 1708 1709 /** 1710 * Recursively descends the container tree and invalidates all 1711 * contained components. 1712 */ 1713 void invalidateTree() { 1714 synchronized (getTreeLock()) { 1715 for (int i = 0; i < component.size(); i++) { 1716 Component comp = component.get(i); 1717 if (comp instanceof Container) { 1718 ((Container)comp).invalidateTree(); 1719 } 1720 else { 1721 comp.invalidateIfValid(); 1722 } 1723 } 1724 invalidateIfValid(); 1725 } 1726 } 1727 1728 /** 1729 * Sets the font of this container. 1730 * <p> 1731 * This method changes layout-related information, and therefore, 1732 * invalidates the component hierarchy. 1733 * 1734 * @param f The font to become this container's font. 1735 * @see Component#getFont 1736 * @see #invalidate 1737 * @since JDK1.0 1738 */ 1739 public void setFont(Font f) { 1740 boolean shouldinvalidate = false; 1741 1742 Font oldfont = getFont(); 1743 super.setFont(f); 1744 Font newfont = getFont(); 1745 if (newfont != oldfont && (oldfont == null || 1746 !oldfont.equals(newfont))) { 1747 invalidateTree(); 1748 } 1749 } 1750 1751 /** 1752 * Returns the preferred size of this container. If the preferred size has 1753 * not been set explicitly by {@link Component#setPreferredSize(Dimension)} 1754 * and this {@code Container} has a {@code non-null} {@link LayoutManager}, 1755 * then {@link LayoutManager#preferredLayoutSize(Container)} 1756 * is used to calculate the preferred size. 1757 * 1758 * <p>Note: some implementations may cache the value returned from the 1759 * {@code LayoutManager}. Implementations that cache need not invoke 1760 * {@code preferredLayoutSize} on the {@code LayoutManager} every time 1761 * this method is invoked, rather the {@code LayoutManager} will only 1762 * be queried after the {@code Container} becomes invalid. 1763 * 1764 * @return an instance of <code>Dimension</code> that represents 1765 * the preferred size of this container. 1766 * @see #getMinimumSize 1767 * @see #getMaximumSize 1768 * @see #getLayout 1769 * @see LayoutManager#preferredLayoutSize(Container) 1770 * @see Component#getPreferredSize 1771 */ 1772 public Dimension getPreferredSize() { 1773 return preferredSize(); 1774 } 1775 1776 /** 1777 * @deprecated As of JDK version 1.1, 1778 * replaced by <code>getPreferredSize()</code>. 1779 */ 1780 @Deprecated 1781 public Dimension preferredSize() { 1782 /* Avoid grabbing the lock if a reasonable cached size value 1783 * is available. 1784 */ 1785 Dimension dim = prefSize; 1786 if (dim == null || !(isPreferredSizeSet() || isValid())) { 1787 synchronized (getTreeLock()) { 1788 prefSize = (layoutMgr != null) ? 1789 layoutMgr.preferredLayoutSize(this) : 1790 super.preferredSize(); 1791 dim = prefSize; 1792 } 1793 } 1794 if (dim != null){ 1795 return new Dimension(dim); 1796 } 1797 else{ 1798 return dim; 1799 } 1800 } 1801 1802 /** 1803 * Returns the minimum size of this container. If the minimum size has 1804 * not been set explicitly by {@link Component#setMinimumSize(Dimension)} 1805 * and this {@code Container} has a {@code non-null} {@link LayoutManager}, 1806 * then {@link LayoutManager#minimumLayoutSize(Container)} 1807 * is used to calculate the minimum size. 1808 * 1809 * <p>Note: some implementations may cache the value returned from the 1810 * {@code LayoutManager}. Implementations that cache need not invoke 1811 * {@code minimumLayoutSize} on the {@code LayoutManager} every time 1812 * this method is invoked, rather the {@code LayoutManager} will only 1813 * be queried after the {@code Container} becomes invalid. 1814 * 1815 * @return an instance of <code>Dimension</code> that represents 1816 * the minimum size of this container. 1817 * @see #getPreferredSize 1818 * @see #getMaximumSize 1819 * @see #getLayout 1820 * @see LayoutManager#minimumLayoutSize(Container) 1821 * @see Component#getMinimumSize 1822 * @since JDK1.1 1823 */ 1824 public Dimension getMinimumSize() { 1825 return minimumSize(); 1826 } 1827 1828 /** 1829 * @deprecated As of JDK version 1.1, 1830 * replaced by <code>getMinimumSize()</code>. 1831 */ 1832 @Deprecated 1833 public Dimension minimumSize() { 1834 /* Avoid grabbing the lock if a reasonable cached size value 1835 * is available. 1836 */ 1837 Dimension dim = minSize; 1838 if (dim == null || !(isMinimumSizeSet() || isValid())) { 1839 synchronized (getTreeLock()) { 1840 minSize = (layoutMgr != null) ? 1841 layoutMgr.minimumLayoutSize(this) : 1842 super.minimumSize(); 1843 dim = minSize; 1844 } 1845 } 1846 if (dim != null){ 1847 return new Dimension(dim); 1848 } 1849 else{ 1850 return dim; 1851 } 1852 } 1853 1854 /** 1855 * Returns the maximum size of this container. If the maximum size has 1856 * not been set explicitly by {@link Component#setMaximumSize(Dimension)} 1857 * and the {@link LayoutManager} installed on this {@code Container} 1858 * is an instance of {@link LayoutManager2}, then 1859 * {@link LayoutManager2#maximumLayoutSize(Container)} 1860 * is used to calculate the maximum size. 1861 * 1862 * <p>Note: some implementations may cache the value returned from the 1863 * {@code LayoutManager2}. Implementations that cache need not invoke 1864 * {@code maximumLayoutSize} on the {@code LayoutManager2} every time 1865 * this method is invoked, rather the {@code LayoutManager2} will only 1866 * be queried after the {@code Container} becomes invalid. 1867 * 1868 * @return an instance of <code>Dimension</code> that represents 1869 * the maximum size of this container. 1870 * @see #getPreferredSize 1871 * @see #getMinimumSize 1872 * @see #getLayout 1873 * @see LayoutManager2#maximumLayoutSize(Container) 1874 * @see Component#getMaximumSize 1875 */ 1876 public Dimension getMaximumSize() { 1877 /* Avoid grabbing the lock if a reasonable cached size value 1878 * is available. 1879 */ 1880 Dimension dim = maxSize; 1881 if (dim == null || !(isMaximumSizeSet() || isValid())) { 1882 synchronized (getTreeLock()) { 1883 if (layoutMgr instanceof LayoutManager2) { 1884 LayoutManager2 lm = (LayoutManager2) layoutMgr; 1885 maxSize = lm.maximumLayoutSize(this); 1886 } else { 1887 maxSize = super.getMaximumSize(); 1888 } 1889 dim = maxSize; 1890 } 1891 } 1892 if (dim != null){ 1893 return new Dimension(dim); 1894 } 1895 else{ 1896 return dim; 1897 } 1898 } 1899 1900 /** 1901 * Returns the alignment along the x axis. This specifies how 1902 * the component would like to be aligned relative to other 1903 * components. The value should be a number between 0 and 1 1904 * where 0 represents alignment along the origin, 1 is aligned 1905 * the furthest away from the origin, 0.5 is centered, etc. 1906 */ 1907 public float getAlignmentX() { 1908 float xAlign; 1909 if (layoutMgr instanceof LayoutManager2) { 1910 synchronized (getTreeLock()) { 1911 LayoutManager2 lm = (LayoutManager2) layoutMgr; 1912 xAlign = lm.getLayoutAlignmentX(this); 1913 } 1914 } else { 1915 xAlign = super.getAlignmentX(); 1916 } 1917 return xAlign; 1918 } 1919 1920 /** 1921 * Returns the alignment along the y axis. This specifies how 1922 * the component would like to be aligned relative to other 1923 * components. The value should be a number between 0 and 1 1924 * where 0 represents alignment along the origin, 1 is aligned 1925 * the furthest away from the origin, 0.5 is centered, etc. 1926 */ 1927 public float getAlignmentY() { 1928 float yAlign; 1929 if (layoutMgr instanceof LayoutManager2) { 1930 synchronized (getTreeLock()) { 1931 LayoutManager2 lm = (LayoutManager2) layoutMgr; 1932 yAlign = lm.getLayoutAlignmentY(this); 1933 } 1934 } else { 1935 yAlign = super.getAlignmentY(); 1936 } 1937 return yAlign; 1938 } 1939 1940 /** 1941 * Paints the container. This forwards the paint to any lightweight 1942 * components that are children of this container. If this method is 1943 * reimplemented, super.paint(g) should be called so that lightweight 1944 * components are properly rendered. If a child component is entirely 1945 * clipped by the current clipping setting in g, paint() will not be 1946 * forwarded to that child. 1947 * 1948 * @param g the specified Graphics window 1949 * @see Component#update(Graphics) 1950 */ 1951 public void paint(Graphics g) { 1952 if (isShowing()) { 1953 synchronized (getObjectLock()) { 1954 if (printing) { 1955 if (printingThreads.contains(Thread.currentThread())) { 1956 return; 1957 } 1958 } 1959 } 1960 1961 // The container is showing on screen and 1962 // this paint() is not called from print(). 1963 // Paint self and forward the paint to lightweight subcomponents. 1964 1965 // super.paint(); -- Don't bother, since it's a NOP. 1966 1967 GraphicsCallback.PaintCallback.getInstance(). 1968 runComponents(getComponentsSync(), g, GraphicsCallback.LIGHTWEIGHTS); 1969 } 1970 } 1971 1972 /** 1973 * Updates the container. This forwards the update to any lightweight 1974 * components that are children of this container. If this method is 1975 * reimplemented, super.update(g) should be called so that lightweight 1976 * components are properly rendered. If a child component is entirely 1977 * clipped by the current clipping setting in g, update() will not be 1978 * forwarded to that child. 1979 * 1980 * @param g the specified Graphics window 1981 * @see Component#update(Graphics) 1982 */ 1983 public void update(Graphics g) { 1984 if (isShowing()) { 1985 if (! (peer instanceof LightweightPeer)) { 1986 g.clearRect(0, 0, width, height); 1987 } 1988 paint(g); 1989 } 1990 } 1991 1992 /** 1993 * Prints the container. This forwards the print to any lightweight 1994 * components that are children of this container. If this method is 1995 * reimplemented, super.print(g) should be called so that lightweight 1996 * components are properly rendered. If a child component is entirely 1997 * clipped by the current clipping setting in g, print() will not be 1998 * forwarded to that child. 1999 * 2000 * @param g the specified Graphics window 2001 * @see Component#update(Graphics) 2002 */ 2003 public void print(Graphics g) { 2004 if (isShowing()) { 2005 Thread t = Thread.currentThread(); 2006 try { 2007 synchronized (getObjectLock()) { 2008 if (printingThreads == null) { 2009 printingThreads = new HashSet<>(); 2010 } 2011 printingThreads.add(t); 2012 printing = true; 2013 } 2014 super.print(g); // By default, Component.print() calls paint() 2015 } finally { 2016 synchronized (getObjectLock()) { 2017 printingThreads.remove(t); 2018 printing = !printingThreads.isEmpty(); 2019 } 2020 } 2021 2022 GraphicsCallback.PrintCallback.getInstance(). 2023 runComponents(getComponentsSync(), g, GraphicsCallback.LIGHTWEIGHTS); 2024 } 2025 } 2026 2027 /** 2028 * Paints each of the components in this container. 2029 * @param g the graphics context. 2030 * @see Component#paint 2031 * @see Component#paintAll 2032 */ 2033 public void paintComponents(Graphics g) { 2034 if (isShowing()) { 2035 GraphicsCallback.PaintAllCallback.getInstance(). 2036 runComponents(getComponentsSync(), g, GraphicsCallback.TWO_PASSES); 2037 } 2038 } 2039 2040 /** 2041 * Simulates the peer callbacks into java.awt for printing of 2042 * lightweight Containers. 2043 * @param g the graphics context to use for printing. 2044 * @see Component#printAll 2045 * @see #printComponents 2046 */ 2047 void lightweightPaint(Graphics g) { 2048 super.lightweightPaint(g); 2049 paintHeavyweightComponents(g); 2050 } 2051 2052 /** 2053 * Prints all the heavyweight subcomponents. 2054 */ 2055 void paintHeavyweightComponents(Graphics g) { 2056 if (isShowing()) { 2057 GraphicsCallback.PaintHeavyweightComponentsCallback.getInstance(). 2058 runComponents(getComponentsSync(), g, 2059 GraphicsCallback.LIGHTWEIGHTS | GraphicsCallback.HEAVYWEIGHTS); 2060 } 2061 } 2062 2063 /** 2064 * Prints each of the components in this container. 2065 * @param g the graphics context. 2066 * @see Component#print 2067 * @see Component#printAll 2068 */ 2069 public void printComponents(Graphics g) { 2070 if (isShowing()) { 2071 GraphicsCallback.PrintAllCallback.getInstance(). 2072 runComponents(getComponentsSync(), g, GraphicsCallback.TWO_PASSES); 2073 } 2074 } 2075 2076 /** 2077 * Simulates the peer callbacks into java.awt for printing of 2078 * lightweight Containers. 2079 * @param g the graphics context to use for printing. 2080 * @see Component#printAll 2081 * @see #printComponents 2082 */ 2083 void lightweightPrint(Graphics g) { 2084 super.lightweightPrint(g); 2085 printHeavyweightComponents(g); 2086 } 2087 2088 /** 2089 * Prints all the heavyweight subcomponents. 2090 */ 2091 void printHeavyweightComponents(Graphics g) { 2092 if (isShowing()) { 2093 GraphicsCallback.PrintHeavyweightComponentsCallback.getInstance(). 2094 runComponents(getComponentsSync(), g, 2095 GraphicsCallback.LIGHTWEIGHTS | GraphicsCallback.HEAVYWEIGHTS); 2096 } 2097 } 2098 2099 /** 2100 * Adds the specified container listener to receive container events 2101 * from this container. 2102 * If l is null, no exception is thrown and no action is performed. 2103 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads" 2104 * >AWT Threading Issues</a> for details on AWT's threading model. 2105 * 2106 * @param l the container listener 2107 * 2108 * @see #removeContainerListener 2109 * @see #getContainerListeners 2110 */ 2111 public synchronized void addContainerListener(ContainerListener l) { 2112 if (l == null) { 2113 return; 2114 } 2115 containerListener = AWTEventMulticaster.add(containerListener, l); 2116 newEventsOnly = true; 2117 } 2118 2119 /** 2120 * Removes the specified container listener so it no longer receives 2121 * container events from this container. 2122 * If l is null, no exception is thrown and no action is performed. 2123 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads" 2124 * >AWT Threading Issues</a> for details on AWT's threading model. 2125 * 2126 * @param l the container listener 2127 * 2128 * @see #addContainerListener 2129 * @see #getContainerListeners 2130 */ 2131 public synchronized void removeContainerListener(ContainerListener l) { 2132 if (l == null) { 2133 return; 2134 } 2135 containerListener = AWTEventMulticaster.remove(containerListener, l); 2136 } 2137 2138 /** 2139 * Returns an array of all the container listeners 2140 * registered on this container. 2141 * 2142 * @return all of this container's <code>ContainerListener</code>s 2143 * or an empty array if no container 2144 * listeners are currently registered 2145 * 2146 * @see #addContainerListener 2147 * @see #removeContainerListener 2148 * @since 1.4 2149 */ 2150 public synchronized ContainerListener[] getContainerListeners() { 2151 return getListeners(ContainerListener.class); 2152 } 2153 2154 /** 2155 * Returns an array of all the objects currently registered 2156 * as <code><em>Foo</em>Listener</code>s 2157 * upon this <code>Container</code>. 2158 * <code><em>Foo</em>Listener</code>s are registered using the 2159 * <code>add<em>Foo</em>Listener</code> method. 2160 * 2161 * <p> 2162 * You can specify the <code>listenerType</code> argument 2163 * with a class literal, such as 2164 * <code><em>Foo</em>Listener.class</code>. 2165 * For example, you can query a 2166 * <code>Container</code> <code>c</code> 2167 * for its container listeners with the following code: 2168 * 2169 * <pre>ContainerListener[] cls = (ContainerListener[])(c.getListeners(ContainerListener.class));</pre> 2170 * 2171 * If no such listeners exist, this method returns an empty array. 2172 * 2173 * @param listenerType the type of listeners requested; this parameter 2174 * should specify an interface that descends from 2175 * <code>java.util.EventListener</code> 2176 * @return an array of all objects registered as 2177 * <code><em>Foo</em>Listener</code>s on this container, 2178 * or an empty array if no such listeners have been added 2179 * @exception ClassCastException if <code>listenerType</code> 2180 * doesn't specify a class or interface that implements 2181 * <code>java.util.EventListener</code> 2182 * @exception NullPointerException if {@code listenerType} is {@code null} 2183 * 2184 * @see #getContainerListeners 2185 * 2186 * @since 1.3 2187 */ 2188 public <T extends EventListener> T[] getListeners(Class<T> listenerType) { 2189 EventListener l = null; 2190 if (listenerType == ContainerListener.class) { 2191 l = containerListener; 2192 } else { 2193 return super.getListeners(listenerType); 2194 } 2195 return AWTEventMulticaster.getListeners(l, listenerType); 2196 } 2197 2198 // REMIND: remove when filtering is done at lower level 2199 boolean eventEnabled(AWTEvent e) { 2200 int id = e.getID(); 2201 2202 if (id == ContainerEvent.COMPONENT_ADDED || 2203 id == ContainerEvent.COMPONENT_REMOVED) { 2204 if ((eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 || 2205 containerListener != null) { 2206 return true; 2207 } 2208 return false; 2209 } 2210 return super.eventEnabled(e); 2211 } 2212 2213 /** 2214 * Processes events on this container. If the event is a 2215 * <code>ContainerEvent</code>, it invokes the 2216 * <code>processContainerEvent</code> method, else it invokes 2217 * its superclass's <code>processEvent</code>. 2218 * <p>Note that if the event parameter is <code>null</code> 2219 * the behavior is unspecified and may result in an 2220 * exception. 2221 * 2222 * @param e the event 2223 */ 2224 protected void processEvent(AWTEvent e) { 2225 if (e instanceof ContainerEvent) { 2226 processContainerEvent((ContainerEvent)e); 2227 return; 2228 } 2229 super.processEvent(e); 2230 } 2231 2232 /** 2233 * Processes container events occurring on this container by 2234 * dispatching them to any registered ContainerListener objects. 2235 * NOTE: This method will not be called unless container events 2236 * are enabled for this component; this happens when one of the 2237 * following occurs: 2238 * <ul> 2239 * <li>A ContainerListener object is registered via 2240 * <code>addContainerListener</code> 2241 * <li>Container events are enabled via <code>enableEvents</code> 2242 * </ul> 2243 * <p>Note that if the event parameter is <code>null</code> 2244 * the behavior is unspecified and may result in an 2245 * exception. 2246 * 2247 * @param e the container event 2248 * @see Component#enableEvents 2249 */ 2250 protected void processContainerEvent(ContainerEvent e) { 2251 ContainerListener listener = containerListener; 2252 if (listener != null) { 2253 switch(e.getID()) { 2254 case ContainerEvent.COMPONENT_ADDED: 2255 listener.componentAdded(e); 2256 break; 2257 case ContainerEvent.COMPONENT_REMOVED: 2258 listener.componentRemoved(e); 2259 break; 2260 } 2261 } 2262 } 2263 2264 /* 2265 * Dispatches an event to this component or one of its sub components. 2266 * Create ANCESTOR_RESIZED and ANCESTOR_MOVED events in response to 2267 * COMPONENT_RESIZED and COMPONENT_MOVED events. We have to do this 2268 * here instead of in processComponentEvent because ComponentEvents 2269 * may not be enabled for this Container. 2270 * @param e the event 2271 */ 2272 void dispatchEventImpl(AWTEvent e) { 2273 if ((dispatcher != null) && dispatcher.dispatchEvent(e)) { 2274 // event was sent to a lightweight component. The 2275 // native-produced event sent to the native container 2276 // must be properly disposed of by the peer, so it 2277 // gets forwarded. If the native host has been removed 2278 // as a result of the sending the lightweight event, 2279 // the peer reference will be null. 2280 e.consume(); 2281 if (peer != null) { 2282 peer.handleEvent(e); 2283 } 2284 return; 2285 } 2286 2287 super.dispatchEventImpl(e); 2288 2289 synchronized (getTreeLock()) { 2290 switch (e.getID()) { 2291 case ComponentEvent.COMPONENT_RESIZED: 2292 createChildHierarchyEvents(HierarchyEvent.ANCESTOR_RESIZED, 0, 2293 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); 2294 break; 2295 case ComponentEvent.COMPONENT_MOVED: 2296 createChildHierarchyEvents(HierarchyEvent.ANCESTOR_MOVED, 0, 2297 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); 2298 break; 2299 default: 2300 break; 2301 } 2302 } 2303 } 2304 2305 /* 2306 * Dispatches an event to this component, without trying to forward 2307 * it to any subcomponents 2308 * @param e the event 2309 */ 2310 void dispatchEventToSelf(AWTEvent e) { 2311 super.dispatchEventImpl(e); 2312 } 2313 2314 /** 2315 * Fetchs the top-most (deepest) lightweight component that is interested 2316 * in receiving mouse events. 2317 */ 2318 Component getMouseEventTarget(int x, int y, boolean includeSelf) { 2319 return getMouseEventTarget(x, y, includeSelf, 2320 MouseEventTargetFilter.FILTER, 2321 !SEARCH_HEAVYWEIGHTS); 2322 } 2323 2324 /** 2325 * Fetches the top-most (deepest) component to receive SunDropTargetEvents. 2326 */ 2327 Component getDropTargetEventTarget(int x, int y, boolean includeSelf) { 2328 return getMouseEventTarget(x, y, includeSelf, 2329 DropTargetEventTargetFilter.FILTER, 2330 SEARCH_HEAVYWEIGHTS); 2331 } 2332 2333 /** 2334 * A private version of getMouseEventTarget which has two additional 2335 * controllable behaviors. This method searches for the top-most 2336 * descendant of this container that contains the given coordinates 2337 * and is accepted by the given filter. The search will be constrained to 2338 * lightweight descendants if the last argument is <code>false</code>. 2339 * 2340 * @param filter EventTargetFilter instance to determine whether the 2341 * given component is a valid target for this event. 2342 * @param searchHeavyweights if <code>false</code>, the method 2343 * will bypass heavyweight components during the search. 2344 */ 2345 private Component getMouseEventTarget(int x, int y, boolean includeSelf, 2346 EventTargetFilter filter, 2347 boolean searchHeavyweights) { 2348 Component comp = null; 2349 if (searchHeavyweights) { 2350 comp = getMouseEventTargetImpl(x, y, includeSelf, filter, 2351 SEARCH_HEAVYWEIGHTS, 2352 searchHeavyweights); 2353 } 2354 2355 if (comp == null || comp == this) { 2356 comp = getMouseEventTargetImpl(x, y, includeSelf, filter, 2357 !SEARCH_HEAVYWEIGHTS, 2358 searchHeavyweights); 2359 } 2360 2361 return comp; 2362 } 2363 2364 /** 2365 * A private version of getMouseEventTarget which has three additional 2366 * controllable behaviors. This method searches for the top-most 2367 * descendant of this container that contains the given coordinates 2368 * and is accepted by the given filter. The search will be constrained to 2369 * descendants of only lightweight children or only heavyweight children 2370 * of this container depending on searchHeavyweightChildren. The search will 2371 * be constrained to only lightweight descendants of the searched children 2372 * of this container if searchHeavyweightDescendants is <code>false</code>. 2373 * 2374 * @param filter EventTargetFilter instance to determine whether the 2375 * selected component is a valid target for this event. 2376 * @param searchHeavyweightChildren if <code>true</code>, the method 2377 * will bypass immediate lightweight children during the search. 2378 * If <code>false</code>, the methods will bypass immediate 2379 * heavyweight children during the search. 2380 * @param searchHeavyweightDescendants if <code>false</code>, the method 2381 * will bypass heavyweight descendants which are not immediate 2382 * children during the search. If <code>true</code>, the method 2383 * will traverse both lightweight and heavyweight descendants during 2384 * the search. 2385 */ 2386 private Component getMouseEventTargetImpl(int x, int y, boolean includeSelf, 2387 EventTargetFilter filter, 2388 boolean searchHeavyweightChildren, 2389 boolean searchHeavyweightDescendants) { 2390 synchronized (getTreeLock()) { 2391 2392 for (int i = 0; i < component.size(); i++) { 2393 Component comp = component.get(i); 2394 if (comp != null && comp.visible && 2395 ((!searchHeavyweightChildren && 2396 comp.peer instanceof LightweightPeer) || 2397 (searchHeavyweightChildren && 2398 !(comp.peer instanceof LightweightPeer))) && 2399 comp.contains(x - comp.x, y - comp.y)) { 2400 2401 // found a component that intersects the point, see if there 2402 // is a deeper possibility. 2403 if (comp instanceof Container) { 2404 Container child = (Container) comp; 2405 Component deeper = child.getMouseEventTarget( 2406 x - child.x, 2407 y - child.y, 2408 includeSelf, 2409 filter, 2410 searchHeavyweightDescendants); 2411 if (deeper != null) { 2412 return deeper; 2413 } 2414 } else { 2415 if (filter.accept(comp)) { 2416 // there isn't a deeper target, but this component 2417 // is a target 2418 return comp; 2419 } 2420 } 2421 } 2422 } 2423 2424 boolean isPeerOK; 2425 boolean isMouseOverMe; 2426 2427 isPeerOK = (peer instanceof LightweightPeer) || includeSelf; 2428 isMouseOverMe = contains(x,y); 2429 2430 // didn't find a child target, return this component if it's 2431 // a possible target 2432 if (isMouseOverMe && isPeerOK && filter.accept(this)) { 2433 return this; 2434 } 2435 // no possible target 2436 return null; 2437 } 2438 } 2439 2440 static interface EventTargetFilter { 2441 boolean accept(final Component comp); 2442 } 2443 2444 static class MouseEventTargetFilter implements EventTargetFilter { 2445 static final EventTargetFilter FILTER = new MouseEventTargetFilter(); 2446 2447 private MouseEventTargetFilter() {} 2448 2449 public boolean accept(final Component comp) { 2450 return (comp.eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0 2451 || (comp.eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0 2452 || (comp.eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0 2453 || comp.mouseListener != null 2454 || comp.mouseMotionListener != null 2455 || comp.mouseWheelListener != null; 2456 } 2457 } 2458 2459 static class DropTargetEventTargetFilter implements EventTargetFilter { 2460 static final EventTargetFilter FILTER = new DropTargetEventTargetFilter(); 2461 2462 private DropTargetEventTargetFilter() {} 2463 2464 public boolean accept(final Component comp) { 2465 DropTarget dt = comp.getDropTarget(); 2466 return dt != null && dt.isActive(); 2467 } 2468 } 2469 2470 /** 2471 * This is called by lightweight components that want the containing 2472 * windowed parent to enable some kind of events on their behalf. 2473 * This is needed for events that are normally only dispatched to 2474 * windows to be accepted so that they can be forwarded downward to 2475 * the lightweight component that has enabled them. 2476 */ 2477 void proxyEnableEvents(long events) { 2478 if (peer instanceof LightweightPeer) { 2479 // this container is lightweight.... continue sending it 2480 // upward. 2481 if (parent != null) { 2482 parent.proxyEnableEvents(events); 2483 } 2484 } else { 2485 // This is a native container, so it needs to host 2486 // one of it's children. If this function is called before 2487 // a peer has been created we don't yet have a dispatcher 2488 // because it has not yet been determined if this instance 2489 // is lightweight. 2490 if (dispatcher != null) { 2491 dispatcher.enableEvents(events); 2492 } 2493 } 2494 } 2495 2496 /** 2497 * @deprecated As of JDK version 1.1, 2498 * replaced by <code>dispatchEvent(AWTEvent e)</code> 2499 */ 2500 @Deprecated 2501 public void deliverEvent(Event e) { 2502 Component comp = getComponentAt(e.x, e.y); 2503 if ((comp != null) && (comp != this)) { 2504 e.translate(-comp.x, -comp.y); 2505 comp.deliverEvent(e); 2506 } else { 2507 postEvent(e); 2508 } 2509 } 2510 2511 /** 2512 * Locates the component that contains the x,y position. The 2513 * top-most child component is returned in the case where there 2514 * is overlap in the components. This is determined by finding 2515 * the component closest to the index 0 that claims to contain 2516 * the given point via Component.contains(), except that Components 2517 * which have native peers take precedence over those which do not 2518 * (i.e., lightweight Components). 2519 * 2520 * @param x the <i>x</i> coordinate 2521 * @param y the <i>y</i> coordinate 2522 * @return null if the component does not contain the position. 2523 * If there is no child component at the requested point and the 2524 * point is within the bounds of the container the container itself 2525 * is returned; otherwise the top-most child is returned. 2526 * @see Component#contains 2527 * @since JDK1.1 2528 */ 2529 public Component getComponentAt(int x, int y) { 2530 return locate(x, y); 2531 } 2532 2533 /** 2534 * @deprecated As of JDK version 1.1, 2535 * replaced by <code>getComponentAt(int, int)</code>. 2536 */ 2537 @Deprecated 2538 public Component locate(int x, int y) { 2539 if (!contains(x, y)) { 2540 return null; 2541 } 2542 synchronized (getTreeLock()) { 2543 // Two passes: see comment in sun.awt.SunGraphicsCallback 2544 for (int i = 0; i < component.size(); i++) { 2545 Component comp = component.get(i); 2546 if (comp != null && 2547 !(comp.peer instanceof LightweightPeer)) { 2548 if (comp.contains(x - comp.x, y - comp.y)) { 2549 return comp; 2550 } 2551 } 2552 } 2553 for (int i = 0; i < component.size(); i++) { 2554 Component comp = component.get(i); 2555 if (comp != null && 2556 comp.peer instanceof LightweightPeer) { 2557 if (comp.contains(x - comp.x, y - comp.y)) { 2558 return comp; 2559 } 2560 } 2561 } 2562 } 2563 return this; 2564 } 2565 2566 /** 2567 * Gets the component that contains the specified point. 2568 * @param p the point. 2569 * @return returns the component that contains the point, 2570 * or <code>null</code> if the component does 2571 * not contain the point. 2572 * @see Component#contains 2573 * @since JDK1.1 2574 */ 2575 public Component getComponentAt(Point p) { 2576 return getComponentAt(p.x, p.y); 2577 } 2578 2579 /** 2580 * Returns the position of the mouse pointer in this <code>Container</code>'s 2581 * coordinate space if the <code>Container</code> is under the mouse pointer, 2582 * otherwise returns <code>null</code>. 2583 * This method is similar to {@link Component#getMousePosition()} with the exception 2584 * that it can take the <code>Container</code>'s children into account. 2585 * If <code>allowChildren</code> is <code>false</code>, this method will return 2586 * a non-null value only if the mouse pointer is above the <code>Container</code> 2587 * directly, not above the part obscured by children. 2588 * If <code>allowChildren</code> is <code>true</code>, this method returns 2589 * a non-null value if the mouse pointer is above <code>Container</code> or any 2590 * of its descendants. 2591 * 2592 * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true 2593 * @param allowChildren true if children should be taken into account 2594 * @see Component#getMousePosition 2595 * @return mouse coordinates relative to this <code>Component</code>, or null 2596 * @since 1.5 2597 */ 2598 public Point getMousePosition(boolean allowChildren) throws HeadlessException { 2599 if (GraphicsEnvironment.isHeadless()) { 2600 throw new HeadlessException(); 2601 } 2602 PointerInfo pi = java.security.AccessController.doPrivileged( 2603 new java.security.PrivilegedAction<PointerInfo>() { 2604 public PointerInfo run() { 2605 return MouseInfo.getPointerInfo(); 2606 } 2607 } 2608 ); 2609 synchronized (getTreeLock()) { 2610 Component inTheSameWindow = findUnderMouseInWindow(pi); 2611 if (isSameOrAncestorOf(inTheSameWindow, allowChildren)) { 2612 return pointRelativeToComponent(pi.getLocation()); 2613 } 2614 return null; 2615 } 2616 } 2617 2618 boolean isSameOrAncestorOf(Component comp, boolean allowChildren) { 2619 return this == comp || (allowChildren && isParentOf(comp)); 2620 } 2621 2622 /** 2623 * Locates the visible child component that contains the specified 2624 * position. The top-most child component is returned in the case 2625 * where there is overlap in the components. If the containing child 2626 * component is a Container, this method will continue searching for 2627 * the deepest nested child component. Components which are not 2628 * visible are ignored during the search.<p> 2629 * 2630 * The findComponentAt method is different from getComponentAt in 2631 * that getComponentAt only searches the Container's immediate 2632 * children; if the containing component is a Container, 2633 * findComponentAt will search that child to find a nested component. 2634 * 2635 * @param x the <i>x</i> coordinate 2636 * @param y the <i>y</i> coordinate 2637 * @return null if the component does not contain the position. 2638 * If there is no child component at the requested point and the 2639 * point is within the bounds of the container the container itself 2640 * is returned. 2641 * @see Component#contains 2642 * @see #getComponentAt 2643 * @since 1.2 2644 */ 2645 public Component findComponentAt(int x, int y) { 2646 return findComponentAt(x, y, true); 2647 } 2648 2649 /** 2650 * Private version of findComponentAt which has a controllable 2651 * behavior. Setting 'ignoreEnabled' to 'false' bypasses disabled 2652 * Components during the search. This behavior is used by the 2653 * lightweight cursor support in sun.awt.GlobalCursorManager. 2654 * The cursor code calls this function directly via native code. 2655 * 2656 * The addition of this feature is temporary, pending the 2657 * adoption of new, public API which exports this feature. 2658 */ 2659 final Component findComponentAt(int x, int y, boolean ignoreEnabled) { 2660 synchronized (getTreeLock()) { 2661 if (isRecursivelyVisible()){ 2662 return findComponentAtImpl(x, y, ignoreEnabled); 2663 } 2664 } 2665 return null; 2666 } 2667 2668 final Component findComponentAtImpl(int x, int y, boolean ignoreEnabled){ 2669 checkTreeLock(); 2670 2671 if (!(contains(x, y) && visible && (ignoreEnabled || enabled))) { 2672 return null; 2673 } 2674 2675 // Two passes: see comment in sun.awt.SunGraphicsCallback 2676 for (int i = 0; i < component.size(); i++) { 2677 Component comp = component.get(i); 2678 if (comp != null && 2679 !(comp.peer instanceof LightweightPeer)) { 2680 if (comp instanceof Container) { 2681 comp = ((Container)comp).findComponentAtImpl(x - comp.x, 2682 y - comp.y, 2683 ignoreEnabled); 2684 } else { 2685 comp = comp.getComponentAt(x - comp.x, y - comp.y); 2686 } 2687 if (comp != null && comp.visible && 2688 (ignoreEnabled || comp.enabled)) 2689 { 2690 return comp; 2691 } 2692 } 2693 } 2694 for (int i = 0; i < component.size(); i++) { 2695 Component comp = component.get(i); 2696 if (comp != null && 2697 comp.peer instanceof LightweightPeer) { 2698 if (comp instanceof Container) { 2699 comp = ((Container)comp).findComponentAtImpl(x - comp.x, 2700 y - comp.y, 2701 ignoreEnabled); 2702 } else { 2703 comp = comp.getComponentAt(x - comp.x, y - comp.y); 2704 } 2705 if (comp != null && comp.visible && 2706 (ignoreEnabled || comp.enabled)) 2707 { 2708 return comp; 2709 } 2710 } 2711 } 2712 2713 return this; 2714 } 2715 2716 /** 2717 * Locates the visible child component that contains the specified 2718 * point. The top-most child component is returned in the case 2719 * where there is overlap in the components. If the containing child 2720 * component is a Container, this method will continue searching for 2721 * the deepest nested child component. Components which are not 2722 * visible are ignored during the search.<p> 2723 * 2724 * The findComponentAt method is different from getComponentAt in 2725 * that getComponentAt only searches the Container's immediate 2726 * children; if the containing component is a Container, 2727 * findComponentAt will search that child to find a nested component. 2728 * 2729 * @param p the point. 2730 * @return null if the component does not contain the position. 2731 * If there is no child component at the requested point and the 2732 * point is within the bounds of the container the container itself 2733 * is returned. 2734 * @throws NullPointerException if {@code p} is {@code null} 2735 * @see Component#contains 2736 * @see #getComponentAt 2737 * @since 1.2 2738 */ 2739 public Component findComponentAt(Point p) { 2740 return findComponentAt(p.x, p.y); 2741 } 2742 2743 /** 2744 * Makes this Container displayable by connecting it to 2745 * a native screen resource. Making a container displayable will 2746 * cause all of its children to be made displayable. 2747 * This method is called internally by the toolkit and should 2748 * not be called directly by programs. 2749 * @see Component#isDisplayable 2750 * @see #removeNotify 2751 */ 2752 public void addNotify() { 2753 synchronized (getTreeLock()) { 2754 // addNotify() on the children may cause proxy event enabling 2755 // on this instance, so we first call super.addNotify() and 2756 // possibly create an lightweight event dispatcher before calling 2757 // addNotify() on the children which may be lightweight. 2758 super.addNotify(); 2759 if (! (peer instanceof LightweightPeer)) { 2760 dispatcher = new LightweightDispatcher(this); 2761 } 2762 2763 // We shouldn't use iterator because of the Swing menu 2764 // implementation specifics: 2765 // the menu is being assigned as a child to JLayeredPane 2766 // instead of particular component so always affect 2767 // collection of component if menu is becoming shown or hidden. 2768 for (int i = 0; i < component.size(); i++) { 2769 component.get(i).addNotify(); 2770 } 2771 } 2772 } 2773 2774 /** 2775 * Makes this Container undisplayable by removing its connection 2776 * to its native screen resource. Making a container undisplayable 2777 * will cause all of its children to be made undisplayable. 2778 * This method is called by the toolkit internally and should 2779 * not be called directly by programs. 2780 * @see Component#isDisplayable 2781 * @see #addNotify 2782 */ 2783 public void removeNotify() { 2784 synchronized (getTreeLock()) { 2785 // We shouldn't use iterator because of the Swing menu 2786 // implementation specifics: 2787 // the menu is being assigned as a child to JLayeredPane 2788 // instead of particular component so always affect 2789 // collection of component if menu is becoming shown or hidden. 2790 for (int i = component.size()-1 ; i >= 0 ; i--) { 2791 Component comp = component.get(i); 2792 if (comp != null) { 2793 // Fix for 6607170. 2794 // We want to suppress focus change on disposal 2795 // of the focused component. But because of focus 2796 // is asynchronous, we should suppress focus change 2797 // on every component in case it receives native focus 2798 // in the process of disposal. 2799 comp.setAutoFocusTransferOnDisposal(false); 2800 comp.removeNotify(); 2801 comp.setAutoFocusTransferOnDisposal(true); 2802 } 2803 } 2804 // If some of the children had focus before disposal then it still has. 2805 // Auto-transfer focus to the next (or previous) component if auto-transfer 2806 // is enabled. 2807 if (containsFocus() && KeyboardFocusManager.isAutoFocusTransferEnabledFor(this)) { 2808 if (!transferFocus(false)) { 2809 transferFocusBackward(true); 2810 } 2811 } 2812 if ( dispatcher != null ) { 2813 dispatcher.dispose(); 2814 dispatcher = null; 2815 } 2816 super.removeNotify(); 2817 } 2818 } 2819 2820 /** 2821 * Checks if the component is contained in the component hierarchy of 2822 * this container. 2823 * @param c the component 2824 * @return <code>true</code> if it is an ancestor; 2825 * <code>false</code> otherwise. 2826 * @since JDK1.1 2827 */ 2828 public boolean isAncestorOf(Component c) { 2829 Container p; 2830 if (c == null || ((p = c.getParent()) == null)) { 2831 return false; 2832 } 2833 while (p != null) { 2834 if (p == this) { 2835 return true; 2836 } 2837 p = p.getParent(); 2838 } 2839 return false; 2840 } 2841 2842 /* 2843 * The following code was added to support modal JInternalFrames 2844 * Unfortunately this code has to be added here so that we can get access to 2845 * some private AWT classes like SequencedEvent. 2846 * 2847 * The native container of the LW component has this field set 2848 * to tell it that it should block Mouse events for all LW 2849 * children except for the modal component. 2850 * 2851 * In the case of nested Modal components, we store the previous 2852 * modal component in the new modal components value of modalComp; 2853 */ 2854 2855 transient Component modalComp; 2856 transient AppContext modalAppContext; 2857 2858 private void startLWModal() { 2859 // Store the app context on which this component is being shown. 2860 // Event dispatch thread of this app context will be sleeping until 2861 // we wake it by any event from hideAndDisposeHandler(). 2862 modalAppContext = AppContext.getAppContext(); 2863 2864 // keep the KeyEvents from being dispatched 2865 // until the focus has been transfered 2866 long time = Toolkit.getEventQueue().getMostRecentKeyEventTime(); 2867 Component predictedFocusOwner = (Component.isInstanceOf(this, "javax.swing.JInternalFrame")) ? ((javax.swing.JInternalFrame)(this)).getMostRecentFocusOwner() : null; 2868 if (predictedFocusOwner != null) { 2869 KeyboardFocusManager.getCurrentKeyboardFocusManager(). 2870 enqueueKeyEvents(time, predictedFocusOwner); 2871 } 2872 // We have two mechanisms for blocking: 1. If we're on the 2873 // EventDispatchThread, start a new event pump. 2. If we're 2874 // on any other thread, call wait() on the treelock. 2875 final Container nativeContainer; 2876 synchronized (getTreeLock()) { 2877 nativeContainer = getHeavyweightContainer(); 2878 if (nativeContainer.modalComp != null) { 2879 this.modalComp = nativeContainer.modalComp; 2880 nativeContainer.modalComp = this; 2881 return; 2882 } 2883 else { 2884 nativeContainer.modalComp = this; 2885 } 2886 } 2887 2888 Runnable pumpEventsForHierarchy = new Runnable() { 2889 public void run() { 2890 EventDispatchThread dispatchThread = 2891 (EventDispatchThread)Thread.currentThread(); 2892 dispatchThread.pumpEventsForHierarchy( 2893 new Conditional() { 2894 public boolean evaluate() { 2895 return ((windowClosingException == null) && (nativeContainer.modalComp != null)) ; 2896 } 2897 }, Container.this); 2898 } 2899 }; 2900 2901 if (EventQueue.isDispatchThread()) { 2902 SequencedEvent currentSequencedEvent = 2903 KeyboardFocusManager.getCurrentKeyboardFocusManager(). 2904 getCurrentSequencedEvent(); 2905 if (currentSequencedEvent != null) { 2906 currentSequencedEvent.dispose(); 2907 } 2908 2909 pumpEventsForHierarchy.run(); 2910 } else { 2911 synchronized (getTreeLock()) { 2912 Toolkit.getEventQueue(). 2913 postEvent(new PeerEvent(this, 2914 pumpEventsForHierarchy, 2915 PeerEvent.PRIORITY_EVENT)); 2916 while ((windowClosingException == null) && 2917 (nativeContainer.modalComp != null)) 2918 { 2919 try { 2920 getTreeLock().wait(); 2921 } catch (InterruptedException e) { 2922 break; 2923 } 2924 } 2925 } 2926 } 2927 if (windowClosingException != null) { 2928 windowClosingException.fillInStackTrace(); 2929 throw windowClosingException; 2930 } 2931 if (predictedFocusOwner != null) { 2932 KeyboardFocusManager.getCurrentKeyboardFocusManager(). 2933 dequeueKeyEvents(time, predictedFocusOwner); 2934 } 2935 } 2936 2937 private void stopLWModal() { 2938 synchronized (getTreeLock()) { 2939 if (modalAppContext != null) { 2940 Container nativeContainer = getHeavyweightContainer(); 2941 if(nativeContainer != null) { 2942 if (this.modalComp != null) { 2943 nativeContainer.modalComp = this.modalComp; 2944 this.modalComp = null; 2945 return; 2946 } 2947 else { 2948 nativeContainer.modalComp = null; 2949 } 2950 } 2951 // Wake up event dispatch thread on which the dialog was 2952 // initially shown 2953 SunToolkit.postEvent(modalAppContext, 2954 new PeerEvent(this, 2955 new WakingRunnable(), 2956 PeerEvent.PRIORITY_EVENT)); 2957 } 2958 EventQueue.invokeLater(new WakingRunnable()); 2959 getTreeLock().notifyAll(); 2960 } 2961 } 2962 2963 final static class WakingRunnable implements Runnable { 2964 public void run() { 2965 } 2966 } 2967 2968 /* End of JOptionPane support code */ 2969 2970 /** 2971 * Returns a string representing the state of this <code>Container</code>. 2972 * This method is intended to be used only for debugging purposes, and the 2973 * content and format of the returned string may vary between 2974 * implementations. The returned string may be empty but may not be 2975 * <code>null</code>. 2976 * 2977 * @return the parameter string of this container 2978 */ 2979 protected String paramString() { 2980 String str = super.paramString(); 2981 LayoutManager layoutMgr = this.layoutMgr; 2982 if (layoutMgr != null) { 2983 str += ",layout=" + layoutMgr.getClass().getName(); 2984 } 2985 return str; 2986 } 2987 2988 /** 2989 * Prints a listing of this container to the specified output 2990 * stream. The listing starts at the specified indentation. 2991 * <p> 2992 * The immediate children of the container are printed with 2993 * an indentation of <code>indent+1</code>. The children 2994 * of those children are printed at <code>indent+2</code> 2995 * and so on. 2996 * 2997 * @param out a print stream 2998 * @param indent the number of spaces to indent 2999 * @throws NullPointerException if {@code out} is {@code null} 3000 * @see Component#list(java.io.PrintStream, int) 3001 * @since JDK1.0 3002 */ 3003 public void list(PrintStream out, int indent) { 3004 super.list(out, indent); 3005 synchronized(getTreeLock()) { 3006 for (int i = 0; i < component.size(); i++) { 3007 Component comp = component.get(i); 3008 if (comp != null) { 3009 comp.list(out, indent+1); 3010 } 3011 } 3012 } 3013 } 3014 3015 /** 3016 * Prints out a list, starting at the specified indentation, 3017 * to the specified print writer. 3018 * <p> 3019 * The immediate children of the container are printed with 3020 * an indentation of <code>indent+1</code>. The children 3021 * of those children are printed at <code>indent+2</code> 3022 * and so on. 3023 * 3024 * @param out a print writer 3025 * @param indent the number of spaces to indent 3026 * @throws NullPointerException if {@code out} is {@code null} 3027 * @see Component#list(java.io.PrintWriter, int) 3028 * @since JDK1.1 3029 */ 3030 public void list(PrintWriter out, int indent) { 3031 super.list(out, indent); 3032 synchronized(getTreeLock()) { 3033 for (int i = 0; i < component.size(); i++) { 3034 Component comp = component.get(i); 3035 if (comp != null) { 3036 comp.list(out, indent+1); 3037 } 3038 } 3039 } 3040 } 3041 3042 /** 3043 * Sets the focus traversal keys for a given traversal operation for this 3044 * Container. 3045 * <p> 3046 * The default values for a Container's focus traversal keys are 3047 * implementation-dependent. Sun recommends that all implementations for a 3048 * particular native platform use the same default values. The 3049 * recommendations for Windows and Unix are listed below. These 3050 * recommendations are used in the Sun AWT implementations. 3051 * 3052 * <table border=1 summary="Recommended default values for a Container's focus traversal keys"> 3053 * <tr> 3054 * <th>Identifier</th> 3055 * <th>Meaning</th> 3056 * <th>Default</th> 3057 * </tr> 3058 * <tr> 3059 * <td>KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS</td> 3060 * <td>Normal forward keyboard traversal</td> 3061 * <td>TAB on KEY_PRESSED, CTRL-TAB on KEY_PRESSED</td> 3062 * </tr> 3063 * <tr> 3064 * <td>KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS</td> 3065 * <td>Normal reverse keyboard traversal</td> 3066 * <td>SHIFT-TAB on KEY_PRESSED, CTRL-SHIFT-TAB on KEY_PRESSED</td> 3067 * </tr> 3068 * <tr> 3069 * <td>KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS</td> 3070 * <td>Go up one focus traversal cycle</td> 3071 * <td>none</td> 3072 * </tr> 3073 * <tr> 3074 * <td>KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS<td> 3075 * <td>Go down one focus traversal cycle</td> 3076 * <td>none</td> 3077 * </tr> 3078 * </table> 3079 * 3080 * To disable a traversal key, use an empty Set; Collections.EMPTY_SET is 3081 * recommended. 3082 * <p> 3083 * Using the AWTKeyStroke API, client code can specify on which of two 3084 * specific KeyEvents, KEY_PRESSED or KEY_RELEASED, the focus traversal 3085 * operation will occur. Regardless of which KeyEvent is specified, 3086 * however, all KeyEvents related to the focus traversal key, including the 3087 * associated KEY_TYPED event, will be consumed, and will not be dispatched 3088 * to any Container. It is a runtime error to specify a KEY_TYPED event as 3089 * mapping to a focus traversal operation, or to map the same event to 3090 * multiple default focus traversal operations. 3091 * <p> 3092 * If a value of null is specified for the Set, this Container inherits the 3093 * Set from its parent. If all ancestors of this Container have null 3094 * specified for the Set, then the current KeyboardFocusManager's default 3095 * Set is used. 3096 * <p> 3097 * This method may throw a {@code ClassCastException} if any {@code Object} 3098 * in {@code keystrokes} is not an {@code AWTKeyStroke}. 3099 * 3100 * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 3101 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 3102 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or 3103 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS 3104 * @param keystrokes the Set of AWTKeyStroke for the specified operation 3105 * @see #getFocusTraversalKeys 3106 * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS 3107 * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS 3108 * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS 3109 * @see KeyboardFocusManager#DOWN_CYCLE_TRAVERSAL_KEYS 3110 * @throws IllegalArgumentException if id is not one of 3111 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 3112 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 3113 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or 3114 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, or if keystrokes 3115 * contains null, or if any keystroke represents a KEY_TYPED event, 3116 * or if any keystroke already maps to another focus traversal 3117 * operation for this Container 3118 * @since 1.4 3119 * @beaninfo 3120 * bound: true 3121 */ 3122 public void setFocusTraversalKeys(int id, 3123 Set<? extends AWTKeyStroke> keystrokes) 3124 { 3125 if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) { 3126 throw new IllegalArgumentException("invalid focus traversal key identifier"); 3127 } 3128 3129 // Don't call super.setFocusTraversalKey. The Component parameter check 3130 // does not allow DOWN_CYCLE_TRAVERSAL_KEYS, but we do. 3131 setFocusTraversalKeys_NoIDCheck(id, keystrokes); 3132 } 3133 3134 /** 3135 * Returns the Set of focus traversal keys for a given traversal operation 3136 * for this Container. (See 3137 * <code>setFocusTraversalKeys</code> for a full description of each key.) 3138 * <p> 3139 * If a Set of traversal keys has not been explicitly defined for this 3140 * Container, then this Container's parent's Set is returned. If no Set 3141 * has been explicitly defined for any of this Container's ancestors, then 3142 * the current KeyboardFocusManager's default Set is returned. 3143 * 3144 * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 3145 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 3146 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or 3147 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS 3148 * @return the Set of AWTKeyStrokes for the specified operation. The Set 3149 * will be unmodifiable, and may be empty. null will never be 3150 * returned. 3151 * @see #setFocusTraversalKeys 3152 * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS 3153 * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS 3154 * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS 3155 * @see KeyboardFocusManager#DOWN_CYCLE_TRAVERSAL_KEYS 3156 * @throws IllegalArgumentException if id is not one of 3157 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 3158 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 3159 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or 3160 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS 3161 * @since 1.4 3162 */ 3163 public Set<AWTKeyStroke> getFocusTraversalKeys(int id) { 3164 if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) { 3165 throw new IllegalArgumentException("invalid focus traversal key identifier"); 3166 } 3167 3168 // Don't call super.getFocusTraversalKey. The Component parameter check 3169 // does not allow DOWN_CYCLE_TRAVERSAL_KEY, but we do. 3170 return getFocusTraversalKeys_NoIDCheck(id); 3171 } 3172 3173 /** 3174 * Returns whether the Set of focus traversal keys for the given focus 3175 * traversal operation has been explicitly defined for this Container. If 3176 * this method returns <code>false</code>, this Container is inheriting the 3177 * Set from an ancestor, or from the current KeyboardFocusManager. 3178 * 3179 * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 3180 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 3181 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or 3182 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS 3183 * @return <code>true</code> if the the Set of focus traversal keys for the 3184 * given focus traversal operation has been explicitly defined for 3185 * this Component; <code>false</code> otherwise. 3186 * @throws IllegalArgumentException if id is not one of 3187 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 3188 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 3189 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or 3190 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS 3191 * @since 1.4 3192 */ 3193 public boolean areFocusTraversalKeysSet(int id) { 3194 if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) { 3195 throw new IllegalArgumentException("invalid focus traversal key identifier"); 3196 } 3197 3198 return (focusTraversalKeys != null && focusTraversalKeys[id] != null); 3199 } 3200 3201 /** 3202 * Returns whether the specified Container is the focus cycle root of this 3203 * Container's focus traversal cycle. Each focus traversal cycle has only 3204 * a single focus cycle root and each Container which is not a focus cycle 3205 * root belongs to only a single focus traversal cycle. Containers which 3206 * are focus cycle roots belong to two cycles: one rooted at the Container 3207 * itself, and one rooted at the Container's nearest focus-cycle-root 3208 * ancestor. This method will return <code>true</code> for both such 3209 * Containers in this case. 3210 * 3211 * @param container the Container to be tested 3212 * @return <code>true</code> if the specified Container is a focus-cycle- 3213 * root of this Container; <code>false</code> otherwise 3214 * @see #isFocusCycleRoot() 3215 * @since 1.4 3216 */ 3217 public boolean isFocusCycleRoot(Container container) { 3218 if (isFocusCycleRoot() && container == this) { 3219 return true; 3220 } else { 3221 return super.isFocusCycleRoot(container); 3222 } 3223 } 3224 3225 private Container findTraversalRoot() { 3226 // I potentially have two roots, myself and my root parent 3227 // If I am the current root, then use me 3228 // If none of my parents are roots, then use me 3229 // If my root parent is the current root, then use my root parent 3230 // If neither I nor my root parent is the current root, then 3231 // use my root parent (a guess) 3232 3233 Container currentFocusCycleRoot = KeyboardFocusManager. 3234 getCurrentKeyboardFocusManager().getCurrentFocusCycleRoot(); 3235 Container root; 3236 3237 if (currentFocusCycleRoot == this) { 3238 root = this; 3239 } else { 3240 root = getFocusCycleRootAncestor(); 3241 if (root == null) { 3242 root = this; 3243 } 3244 } 3245 3246 if (root != currentFocusCycleRoot) { 3247 KeyboardFocusManager.getCurrentKeyboardFocusManager(). 3248 setGlobalCurrentFocusCycleRootPriv(root); 3249 } 3250 return root; 3251 } 3252 3253 final boolean containsFocus() { 3254 final Component focusOwner = KeyboardFocusManager. 3255 getCurrentKeyboardFocusManager().getFocusOwner(); 3256 return isParentOf(focusOwner); 3257 } 3258 3259 /** 3260 * Check if this component is the child of this container or its children. 3261 * Note: this function acquires treeLock 3262 * Note: this function traverses children tree only in one Window. 3263 * @param comp a component in test, must not be null 3264 */ 3265 private boolean isParentOf(Component comp) { 3266 synchronized(getTreeLock()) { 3267 while (comp != null && comp != this && !(comp instanceof Window)) { 3268 comp = comp.getParent(); 3269 } 3270 return (comp == this); 3271 } 3272 } 3273 3274 void clearMostRecentFocusOwnerOnHide() { 3275 boolean reset = false; 3276 Window window = null; 3277 3278 synchronized (getTreeLock()) { 3279 window = getContainingWindow(); 3280 if (window != null) { 3281 Component comp = KeyboardFocusManager.getMostRecentFocusOwner(window); 3282 reset = ((comp == this) || isParentOf(comp)); 3283 // This synchronized should always be the second in a pair 3284 // (tree lock, KeyboardFocusManager.class) 3285 synchronized(KeyboardFocusManager.class) { 3286 Component storedComp = window.getTemporaryLostComponent(); 3287 if (isParentOf(storedComp) || storedComp == this) { 3288 window.setTemporaryLostComponent(null); 3289 } 3290 } 3291 } 3292 } 3293 3294 if (reset) { 3295 KeyboardFocusManager.setMostRecentFocusOwner(window, null); 3296 } 3297 } 3298 3299 void clearCurrentFocusCycleRootOnHide() { 3300 KeyboardFocusManager kfm = 3301 KeyboardFocusManager.getCurrentKeyboardFocusManager(); 3302 Container cont = kfm.getCurrentFocusCycleRoot(); 3303 3304 if (cont == this || isParentOf(cont)) { 3305 kfm.setGlobalCurrentFocusCycleRootPriv(null); 3306 } 3307 } 3308 3309 @Override 3310 void clearLightweightDispatcherOnRemove(Component removedComponent) { 3311 if (dispatcher != null) { 3312 dispatcher.removeReferences(removedComponent); 3313 } else { 3314 //It is a Lightweight Container, should clear parent`s Dispatcher 3315 super.clearLightweightDispatcherOnRemove(removedComponent); 3316 } 3317 } 3318 3319 final Container getTraversalRoot() { 3320 if (isFocusCycleRoot()) { 3321 return findTraversalRoot(); 3322 } 3323 3324 return super.getTraversalRoot(); 3325 } 3326 3327 /** 3328 * Sets the focus traversal policy that will manage keyboard traversal of 3329 * this Container's children, if this Container is a focus cycle root. If 3330 * the argument is null, this Container inherits its policy from its focus- 3331 * cycle-root ancestor. If the argument is non-null, this policy will be 3332 * inherited by all focus-cycle-root children that have no keyboard- 3333 * traversal policy of their own (as will, recursively, their focus-cycle- 3334 * root children). 3335 * <p> 3336 * If this Container is not a focus cycle root, the policy will be 3337 * remembered, but will not be used or inherited by this or any other 3338 * Containers until this Container is made a focus cycle root. 3339 * 3340 * @param policy the new focus traversal policy for this Container 3341 * @see #getFocusTraversalPolicy 3342 * @see #setFocusCycleRoot 3343 * @see #isFocusCycleRoot 3344 * @since 1.4 3345 * @beaninfo 3346 * bound: true 3347 */ 3348 public void setFocusTraversalPolicy(FocusTraversalPolicy policy) { 3349 FocusTraversalPolicy oldPolicy; 3350 synchronized (this) { 3351 oldPolicy = this.focusTraversalPolicy; 3352 this.focusTraversalPolicy = policy; 3353 } 3354 firePropertyChange("focusTraversalPolicy", oldPolicy, policy); 3355 } 3356 3357 /** 3358 * Returns the focus traversal policy that will manage keyboard traversal 3359 * of this Container's children, or null if this Container is not a focus 3360 * cycle root. If no traversal policy has been explicitly set for this 3361 * Container, then this Container's focus-cycle-root ancestor's policy is 3362 * returned. 3363 * 3364 * @return this Container's focus traversal policy, or null if this 3365 * Container is not a focus cycle root. 3366 * @see #setFocusTraversalPolicy 3367 * @see #setFocusCycleRoot 3368 * @see #isFocusCycleRoot 3369 * @since 1.4 3370 */ 3371 public FocusTraversalPolicy getFocusTraversalPolicy() { 3372 if (!isFocusTraversalPolicyProvider() && !isFocusCycleRoot()) { 3373 return null; 3374 } 3375 3376 FocusTraversalPolicy policy = this.focusTraversalPolicy; 3377 if (policy != null) { 3378 return policy; 3379 } 3380 3381 Container rootAncestor = getFocusCycleRootAncestor(); 3382 if (rootAncestor != null) { 3383 return rootAncestor.getFocusTraversalPolicy(); 3384 } else { 3385 return KeyboardFocusManager.getCurrentKeyboardFocusManager(). 3386 getDefaultFocusTraversalPolicy(); 3387 } 3388 } 3389 3390 /** 3391 * Returns whether the focus traversal policy has been explicitly set for 3392 * this Container. If this method returns <code>false</code>, this 3393 * Container will inherit its focus traversal policy from an ancestor. 3394 * 3395 * @return <code>true</code> if the focus traversal policy has been 3396 * explicitly set for this Container; <code>false</code> otherwise. 3397 * @since 1.4 3398 */ 3399 public boolean isFocusTraversalPolicySet() { 3400 return (focusTraversalPolicy != null); 3401 } 3402 3403 /** 3404 * Sets whether this Container is the root of a focus traversal cycle. Once 3405 * focus enters a traversal cycle, typically it cannot leave it via focus 3406 * traversal unless one of the up- or down-cycle keys is pressed. Normal 3407 * traversal is limited to this Container, and all of this Container's 3408 * descendants that are not descendants of inferior focus cycle roots. Note 3409 * that a FocusTraversalPolicy may bend these restrictions, however. For 3410 * example, ContainerOrderFocusTraversalPolicy supports implicit down-cycle 3411 * traversal. 3412 * <p> 3413 * The alternative way to specify the traversal order of this Container's 3414 * children is to make this Container a 3415 * <a href="doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus traversal policy provider</a>. 3416 * 3417 * @param focusCycleRoot indicates whether this Container is the root of a 3418 * focus traversal cycle 3419 * @see #isFocusCycleRoot() 3420 * @see #setFocusTraversalPolicy 3421 * @see #getFocusTraversalPolicy 3422 * @see ContainerOrderFocusTraversalPolicy 3423 * @see #setFocusTraversalPolicyProvider 3424 * @since 1.4 3425 * @beaninfo 3426 * bound: true 3427 */ 3428 public void setFocusCycleRoot(boolean focusCycleRoot) { 3429 boolean oldFocusCycleRoot; 3430 synchronized (this) { 3431 oldFocusCycleRoot = this.focusCycleRoot; 3432 this.focusCycleRoot = focusCycleRoot; 3433 } 3434 firePropertyChange("focusCycleRoot", oldFocusCycleRoot, 3435 focusCycleRoot); 3436 } 3437 3438 /** 3439 * Returns whether this Container is the root of a focus traversal cycle. 3440 * Once focus enters a traversal cycle, typically it cannot leave it via 3441 * focus traversal unless one of the up- or down-cycle keys is pressed. 3442 * Normal traversal is limited to this Container, and all of this 3443 * Container's descendants that are not descendants of inferior focus 3444 * cycle roots. Note that a FocusTraversalPolicy may bend these 3445 * restrictions, however. For example, ContainerOrderFocusTraversalPolicy 3446 * supports implicit down-cycle traversal. 3447 * 3448 * @return whether this Container is the root of a focus traversal cycle 3449 * @see #setFocusCycleRoot 3450 * @see #setFocusTraversalPolicy 3451 * @see #getFocusTraversalPolicy 3452 * @see ContainerOrderFocusTraversalPolicy 3453 * @since 1.4 3454 */ 3455 public boolean isFocusCycleRoot() { 3456 return focusCycleRoot; 3457 } 3458 3459 /** 3460 * Sets whether this container will be used to provide focus 3461 * traversal policy. Container with this property as 3462 * <code>true</code> will be used to acquire focus traversal policy 3463 * instead of closest focus cycle root ancestor. 3464 * @param provider indicates whether this container will be used to 3465 * provide focus traversal policy 3466 * @see #setFocusTraversalPolicy 3467 * @see #getFocusTraversalPolicy 3468 * @see #isFocusTraversalPolicyProvider 3469 * @since 1.5 3470 * @beaninfo 3471 * bound: true 3472 */ 3473 public final void setFocusTraversalPolicyProvider(boolean provider) { 3474 boolean oldProvider; 3475 synchronized(this) { 3476 oldProvider = focusTraversalPolicyProvider; 3477 focusTraversalPolicyProvider = provider; 3478 } 3479 firePropertyChange("focusTraversalPolicyProvider", oldProvider, provider); 3480 } 3481 3482 /** 3483 * Returns whether this container provides focus traversal 3484 * policy. If this property is set to <code>true</code> then when 3485 * keyboard focus manager searches container hierarchy for focus 3486 * traversal policy and encounters this container before any other 3487 * container with this property as true or focus cycle roots then 3488 * its focus traversal policy will be used instead of focus cycle 3489 * root's policy. 3490 * @see #setFocusTraversalPolicy 3491 * @see #getFocusTraversalPolicy 3492 * @see #setFocusCycleRoot 3493 * @see #setFocusTraversalPolicyProvider 3494 * @return <code>true</code> if this container provides focus traversal 3495 * policy, <code>false</code> otherwise 3496 * @since 1.5 3497 * @beaninfo 3498 * bound: true 3499 */ 3500 public final boolean isFocusTraversalPolicyProvider() { 3501 return focusTraversalPolicyProvider; 3502 } 3503 3504 /** 3505 * Transfers the focus down one focus traversal cycle. If this Container is 3506 * a focus cycle root, then the focus owner is set to this Container's 3507 * default Component to focus, and the current focus cycle root is set to 3508 * this Container. If this Container is not a focus cycle root, then no 3509 * focus traversal operation occurs. 3510 * 3511 * @see Component#requestFocus() 3512 * @see #isFocusCycleRoot 3513 * @see #setFocusCycleRoot 3514 * @since 1.4 3515 */ 3516 public void transferFocusDownCycle() { 3517 if (isFocusCycleRoot()) { 3518 KeyboardFocusManager.getCurrentKeyboardFocusManager(). 3519 setGlobalCurrentFocusCycleRootPriv(this); 3520 Component toFocus = getFocusTraversalPolicy(). 3521 getDefaultComponent(this); 3522 if (toFocus != null) { 3523 toFocus.requestFocus(CausedFocusEvent.Cause.TRAVERSAL_DOWN); 3524 } 3525 } 3526 } 3527 3528 void preProcessKeyEvent(KeyEvent e) { 3529 Container parent = this.parent; 3530 if (parent != null) { 3531 parent.preProcessKeyEvent(e); 3532 } 3533 } 3534 3535 void postProcessKeyEvent(KeyEvent e) { 3536 Container parent = this.parent; 3537 if (parent != null) { 3538 parent.postProcessKeyEvent(e); 3539 } 3540 } 3541 3542 boolean postsOldMouseEvents() { 3543 return true; 3544 } 3545 3546 /** 3547 * Sets the <code>ComponentOrientation</code> property of this container 3548 * and all components contained within it. 3549 * <p> 3550 * This method changes layout-related information, and therefore, 3551 * invalidates the component hierarchy. 3552 * 3553 * @param o the new component orientation of this container and 3554 * the components contained within it. 3555 * @exception NullPointerException if <code>orientation</code> is null. 3556 * @see Component#setComponentOrientation 3557 * @see Component#getComponentOrientation 3558 * @see #invalidate 3559 * @since 1.4 3560 */ 3561 public void applyComponentOrientation(ComponentOrientation o) { 3562 super.applyComponentOrientation(o); 3563 synchronized (getTreeLock()) { 3564 for (int i = 0; i < component.size(); i++) { 3565 Component comp = component.get(i); 3566 comp.applyComponentOrientation(o); 3567 } 3568 } 3569 } 3570 3571 /** 3572 * Adds a PropertyChangeListener to the listener list. The listener is 3573 * registered for all bound properties of this class, including the 3574 * following: 3575 * <ul> 3576 * <li>this Container's font ("font")</li> 3577 * <li>this Container's background color ("background")</li> 3578 * <li>this Container's foreground color ("foreground")</li> 3579 * <li>this Container's focusability ("focusable")</li> 3580 * <li>this Container's focus traversal keys enabled state 3581 * ("focusTraversalKeysEnabled")</li> 3582 * <li>this Container's Set of FORWARD_TRAVERSAL_KEYS 3583 * ("forwardFocusTraversalKeys")</li> 3584 * <li>this Container's Set of BACKWARD_TRAVERSAL_KEYS 3585 * ("backwardFocusTraversalKeys")</li> 3586 * <li>this Container's Set of UP_CYCLE_TRAVERSAL_KEYS 3587 * ("upCycleFocusTraversalKeys")</li> 3588 * <li>this Container's Set of DOWN_CYCLE_TRAVERSAL_KEYS 3589 * ("downCycleFocusTraversalKeys")</li> 3590 * <li>this Container's focus traversal policy ("focusTraversalPolicy") 3591 * </li> 3592 * <li>this Container's focus-cycle-root state ("focusCycleRoot")</li> 3593 * </ul> 3594 * Note that if this Container is inheriting a bound property, then no 3595 * event will be fired in response to a change in the inherited property. 3596 * <p> 3597 * If listener is null, no exception is thrown and no action is performed. 3598 * 3599 * @param listener the PropertyChangeListener to be added 3600 * 3601 * @see Component#removePropertyChangeListener 3602 * @see #addPropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener) 3603 */ 3604 public void addPropertyChangeListener(PropertyChangeListener listener) { 3605 super.addPropertyChangeListener(listener); 3606 } 3607 3608 /** 3609 * Adds a PropertyChangeListener to the listener list for a specific 3610 * property. The specified property may be user-defined, or one of the 3611 * following defaults: 3612 * <ul> 3613 * <li>this Container's font ("font")</li> 3614 * <li>this Container's background color ("background")</li> 3615 * <li>this Container's foreground color ("foreground")</li> 3616 * <li>this Container's focusability ("focusable")</li> 3617 * <li>this Container's focus traversal keys enabled state 3618 * ("focusTraversalKeysEnabled")</li> 3619 * <li>this Container's Set of FORWARD_TRAVERSAL_KEYS 3620 * ("forwardFocusTraversalKeys")</li> 3621 * <li>this Container's Set of BACKWARD_TRAVERSAL_KEYS 3622 * ("backwardFocusTraversalKeys")</li> 3623 * <li>this Container's Set of UP_CYCLE_TRAVERSAL_KEYS 3624 * ("upCycleFocusTraversalKeys")</li> 3625 * <li>this Container's Set of DOWN_CYCLE_TRAVERSAL_KEYS 3626 * ("downCycleFocusTraversalKeys")</li> 3627 * <li>this Container's focus traversal policy ("focusTraversalPolicy") 3628 * </li> 3629 * <li>this Container's focus-cycle-root state ("focusCycleRoot")</li> 3630 * <li>this Container's focus-traversal-policy-provider state("focusTraversalPolicyProvider")</li> 3631 * <li>this Container's focus-traversal-policy-provider state("focusTraversalPolicyProvider")</li> 3632 * </ul> 3633 * Note that if this Container is inheriting a bound property, then no 3634 * event will be fired in response to a change in the inherited property. 3635 * <p> 3636 * If listener is null, no exception is thrown and no action is performed. 3637 * 3638 * @param propertyName one of the property names listed above 3639 * @param listener the PropertyChangeListener to be added 3640 * 3641 * @see #addPropertyChangeListener(java.beans.PropertyChangeListener) 3642 * @see Component#removePropertyChangeListener 3643 */ 3644 public void addPropertyChangeListener(String propertyName, 3645 PropertyChangeListener listener) { 3646 super.addPropertyChangeListener(propertyName, listener); 3647 } 3648 3649 // Serialization support. A Container is responsible for restoring the 3650 // parent fields of its component children. 3651 3652 /** 3653 * Container Serial Data Version. 3654 */ 3655 private int containerSerializedDataVersion = 1; 3656 3657 /** 3658 * Serializes this <code>Container</code> to the specified 3659 * <code>ObjectOutputStream</code>. 3660 * <ul> 3661 * <li>Writes default serializable fields to the stream.</li> 3662 * <li>Writes a list of serializable ContainerListener(s) as optional 3663 * data. The non-serializable ContainerListner(s) are detected and 3664 * no attempt is made to serialize them.</li> 3665 * <li>Write this Container's FocusTraversalPolicy if and only if it 3666 * is Serializable; otherwise, <code>null</code> is written.</li> 3667 * </ul> 3668 * 3669 * @param s the <code>ObjectOutputStream</code> to write 3670 * @serialData <code>null</code> terminated sequence of 0 or more pairs; 3671 * the pair consists of a <code>String</code> and <code>Object</code>; 3672 * the <code>String</code> indicates the type of object and 3673 * is one of the following: 3674 * <code>containerListenerK</code> indicating an 3675 * <code>ContainerListener</code> object; 3676 * the <code>Container</code>'s <code>FocusTraversalPolicy</code>, 3677 * or <code>null</code> 3678 * 3679 * @see AWTEventMulticaster#save(java.io.ObjectOutputStream, java.lang.String, java.util.EventListener) 3680 * @see Container#containerListenerK 3681 * @see #readObject(ObjectInputStream) 3682 */ 3683 private void writeObject(ObjectOutputStream s) throws IOException { 3684 ObjectOutputStream.PutField f = s.putFields(); 3685 f.put("ncomponents", component.size()); 3686 f.put("component", getComponentsSync()); 3687 f.put("layoutMgr", layoutMgr); 3688 f.put("dispatcher", dispatcher); 3689 f.put("maxSize", maxSize); 3690 f.put("focusCycleRoot", focusCycleRoot); 3691 f.put("containerSerializedDataVersion", containerSerializedDataVersion); 3692 f.put("focusTraversalPolicyProvider", focusTraversalPolicyProvider); 3693 s.writeFields(); 3694 3695 AWTEventMulticaster.save(s, containerListenerK, containerListener); 3696 s.writeObject(null); 3697 3698 if (focusTraversalPolicy instanceof java.io.Serializable) { 3699 s.writeObject(focusTraversalPolicy); 3700 } else { 3701 s.writeObject(null); 3702 } 3703 } 3704 3705 /** 3706 * Deserializes this <code>Container</code> from the specified 3707 * <code>ObjectInputStream</code>. 3708 * <ul> 3709 * <li>Reads default serializable fields from the stream.</li> 3710 * <li>Reads a list of serializable ContainerListener(s) as optional 3711 * data. If the list is null, no Listeners are installed.</li> 3712 * <li>Reads this Container's FocusTraversalPolicy, which may be null, 3713 * as optional data.</li> 3714 * </ul> 3715 * 3716 * @param s the <code>ObjectInputStream</code> to read 3717 * @serial 3718 * @see #addContainerListener 3719 * @see #writeObject(ObjectOutputStream) 3720 */ 3721 private void readObject(ObjectInputStream s) 3722 throws ClassNotFoundException, IOException 3723 { 3724 ObjectInputStream.GetField f = s.readFields(); 3725 Component [] tmpComponent = (Component[])f.get("component", EMPTY_ARRAY); 3726 int ncomponents = (Integer) f.get("ncomponents", 0); 3727 component = new java.util.ArrayList<Component>(ncomponents); 3728 for (int i = 0; i < ncomponents; ++i) { 3729 component.add(tmpComponent[i]); 3730 } 3731 layoutMgr = (LayoutManager)f.get("layoutMgr", null); 3732 dispatcher = (LightweightDispatcher)f.get("dispatcher", null); 3733 // Old stream. Doesn't contain maxSize among Component's fields. 3734 if (maxSize == null) { 3735 maxSize = (Dimension)f.get("maxSize", null); 3736 } 3737 focusCycleRoot = f.get("focusCycleRoot", false); 3738 containerSerializedDataVersion = f.get("containerSerializedDataVersion", 1); 3739 focusTraversalPolicyProvider = f.get("focusTraversalPolicyProvider", false); 3740 java.util.List<Component> component = this.component; 3741 for(Component comp : component) { 3742 comp.parent = this; 3743 adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK, 3744 comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK)); 3745 adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 3746 comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); 3747 adjustDescendants(comp.countHierarchyMembers()); 3748 } 3749 3750 Object keyOrNull; 3751 while(null != (keyOrNull = s.readObject())) { 3752 String key = ((String)keyOrNull).intern(); 3753 3754 if (containerListenerK == key) { 3755 addContainerListener((ContainerListener)(s.readObject())); 3756 } else { 3757 // skip value for unrecognized key 3758 s.readObject(); 3759 } 3760 } 3761 3762 try { 3763 Object policy = s.readObject(); 3764 if (policy instanceof FocusTraversalPolicy) { 3765 focusTraversalPolicy = (FocusTraversalPolicy)policy; 3766 } 3767 } catch (java.io.OptionalDataException e) { 3768 // JDK 1.1/1.2/1.3 instances will not have this optional data. 3769 // e.eof will be true to indicate that there is no more data 3770 // available for this object. If e.eof is not true, throw the 3771 // exception as it might have been caused by reasons unrelated to 3772 // focusTraversalPolicy. 3773 3774 if (!e.eof) { 3775 throw e; 3776 } 3777 } 3778 } 3779 3780 /* 3781 * --- Accessibility Support --- 3782 */ 3783 3784 /** 3785 * Inner class of Container used to provide default support for 3786 * accessibility. This class is not meant to be used directly by 3787 * application developers, but is instead meant only to be 3788 * subclassed by container developers. 3789 * <p> 3790 * The class used to obtain the accessible role for this object, 3791 * as well as implementing many of the methods in the 3792 * AccessibleContainer interface. 3793 * @since 1.3 3794 */ 3795 protected class AccessibleAWTContainer extends AccessibleAWTComponent { 3796 3797 /** 3798 * JDK1.3 serialVersionUID 3799 */ 3800 private static final long serialVersionUID = 5081320404842566097L; 3801 3802 /** 3803 * Returns the number of accessible children in the object. If all 3804 * of the children of this object implement <code>Accessible</code>, 3805 * then this method should return the number of children of this object. 3806 * 3807 * @return the number of accessible children in the object 3808 */ 3809 public int getAccessibleChildrenCount() { 3810 return Container.this.getAccessibleChildrenCount(); 3811 } 3812 3813 /** 3814 * Returns the nth <code>Accessible</code> child of the object. 3815 * 3816 * @param i zero-based index of child 3817 * @return the nth <code>Accessible</code> child of the object 3818 */ 3819 public Accessible getAccessibleChild(int i) { 3820 return Container.this.getAccessibleChild(i); 3821 } 3822 3823 /** 3824 * Returns the <code>Accessible</code> child, if one exists, 3825 * contained at the local coordinate <code>Point</code>. 3826 * 3827 * @param p the point defining the top-left corner of the 3828 * <code>Accessible</code>, given in the coordinate space 3829 * of the object's parent 3830 * @return the <code>Accessible</code>, if it exists, 3831 * at the specified location; else <code>null</code> 3832 */ 3833 public Accessible getAccessibleAt(Point p) { 3834 return Container.this.getAccessibleAt(p); 3835 } 3836 3837 /** 3838 * Number of PropertyChangeListener objects registered. It's used 3839 * to add/remove ContainerListener to track target Container's state. 3840 */ 3841 private volatile transient int propertyListenersCount = 0; 3842 3843 protected ContainerListener accessibleContainerHandler = null; 3844 3845 /** 3846 * Fire <code>PropertyChange</code> listener, if one is registered, 3847 * when children are added or removed. 3848 * @since 1.3 3849 */ 3850 protected class AccessibleContainerHandler 3851 implements ContainerListener { 3852 public void componentAdded(ContainerEvent e) { 3853 Component c = e.getChild(); 3854 if (c != null && c instanceof Accessible) { 3855 AccessibleAWTContainer.this.firePropertyChange( 3856 AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, 3857 null, ((Accessible) c).getAccessibleContext()); 3858 } 3859 } 3860 public void componentRemoved(ContainerEvent e) { 3861 Component c = e.getChild(); 3862 if (c != null && c instanceof Accessible) { 3863 AccessibleAWTContainer.this.firePropertyChange( 3864 AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, 3865 ((Accessible) c).getAccessibleContext(), null); 3866 } 3867 } 3868 } 3869 3870 /** 3871 * Adds a PropertyChangeListener to the listener list. 3872 * 3873 * @param listener the PropertyChangeListener to be added 3874 */ 3875 public void addPropertyChangeListener(PropertyChangeListener listener) { 3876 if (accessibleContainerHandler == null) { 3877 accessibleContainerHandler = new AccessibleContainerHandler(); 3878 } 3879 if (propertyListenersCount++ == 0) { 3880 Container.this.addContainerListener(accessibleContainerHandler); 3881 } 3882 super.addPropertyChangeListener(listener); 3883 } 3884 3885 /** 3886 * Remove a PropertyChangeListener from the listener list. 3887 * This removes a PropertyChangeListener that was registered 3888 * for all properties. 3889 * 3890 * @param listener the PropertyChangeListener to be removed 3891 */ 3892 public void removePropertyChangeListener(PropertyChangeListener listener) { 3893 if (--propertyListenersCount == 0) { 3894 Container.this.removeContainerListener(accessibleContainerHandler); 3895 } 3896 super.removePropertyChangeListener(listener); 3897 } 3898 3899 } // inner class AccessibleAWTContainer 3900 3901 /** 3902 * Returns the <code>Accessible</code> child contained at the local 3903 * coordinate <code>Point</code>, if one exists. Otherwise 3904 * returns <code>null</code>. 3905 * 3906 * @param p the point defining the top-left corner of the 3907 * <code>Accessible</code>, given in the coordinate space 3908 * of the object's parent 3909 * @return the <code>Accessible</code> at the specified location, 3910 * if it exists; otherwise <code>null</code> 3911 */ 3912 Accessible getAccessibleAt(Point p) { 3913 synchronized (getTreeLock()) { 3914 if (this instanceof Accessible) { 3915 Accessible a = (Accessible)this; 3916 AccessibleContext ac = a.getAccessibleContext(); 3917 if (ac != null) { 3918 AccessibleComponent acmp; 3919 Point location; 3920 int nchildren = ac.getAccessibleChildrenCount(); 3921 for (int i=0; i < nchildren; i++) { 3922 a = ac.getAccessibleChild(i); 3923 if ((a != null)) { 3924 ac = a.getAccessibleContext(); 3925 if (ac != null) { 3926 acmp = ac.getAccessibleComponent(); 3927 if ((acmp != null) && (acmp.isShowing())) { 3928 location = acmp.getLocation(); 3929 Point np = new Point(p.x-location.x, 3930 p.y-location.y); 3931 if (acmp.contains(np)){ 3932 return a; 3933 } 3934 } 3935 } 3936 } 3937 } 3938 } 3939 return (Accessible)this; 3940 } else { 3941 Component ret = this; 3942 if (!this.contains(p.x,p.y)) { 3943 ret = null; 3944 } else { 3945 int ncomponents = this.getComponentCount(); 3946 for (int i=0; i < ncomponents; i++) { 3947 Component comp = this.getComponent(i); 3948 if ((comp != null) && comp.isShowing()) { 3949 Point location = comp.getLocation(); 3950 if (comp.contains(p.x-location.x,p.y-location.y)) { 3951 ret = comp; 3952 } 3953 } 3954 } 3955 } 3956 if (ret instanceof Accessible) { 3957 return (Accessible) ret; 3958 } 3959 } 3960 return null; 3961 } 3962 } 3963 3964 /** 3965 * Returns the number of accessible children in the object. If all 3966 * of the children of this object implement <code>Accessible</code>, 3967 * then this method should return the number of children of this object. 3968 * 3969 * @return the number of accessible children in the object 3970 */ 3971 int getAccessibleChildrenCount() { 3972 synchronized (getTreeLock()) { 3973 int count = 0; 3974 Component[] children = this.getComponents(); 3975 for (int i = 0; i < children.length; i++) { 3976 if (children[i] instanceof Accessible) { 3977 count++; 3978 } 3979 } 3980 return count; 3981 } 3982 } 3983 3984 /** 3985 * Returns the nth <code>Accessible</code> child of the object. 3986 * 3987 * @param i zero-based index of child 3988 * @return the nth <code>Accessible</code> child of the object 3989 */ 3990 Accessible getAccessibleChild(int i) { 3991 synchronized (getTreeLock()) { 3992 Component[] children = this.getComponents(); 3993 int count = 0; 3994 for (int j = 0; j < children.length; j++) { 3995 if (children[j] instanceof Accessible) { 3996 if (count == i) { 3997 return (Accessible) children[j]; 3998 } else { 3999 count++; 4000 } 4001 } 4002 } 4003 return null; 4004 } 4005 } 4006 4007 // ************************** MIXING CODE ******************************* 4008 4009 final void increaseComponentCount(Component c) { 4010 synchronized (getTreeLock()) { 4011 if (!c.isDisplayable()) { 4012 throw new IllegalStateException( 4013 "Peer does not exist while invoking the increaseComponentCount() method" 4014 ); 4015 } 4016 4017 int addHW = 0; 4018 int addLW = 0; 4019 4020 if (c instanceof Container) { 4021 addLW = ((Container)c).numOfLWComponents; 4022 addHW = ((Container)c).numOfHWComponents; 4023 } 4024 if (c.isLightweight()) { 4025 addLW++; 4026 } else { 4027 addHW++; 4028 } 4029 4030 for (Container cont = this; cont != null; cont = cont.getContainer()) { 4031 cont.numOfLWComponents += addLW; 4032 cont.numOfHWComponents += addHW; 4033 } 4034 } 4035 } 4036 4037 final void decreaseComponentCount(Component c) { 4038 synchronized (getTreeLock()) { 4039 if (!c.isDisplayable()) { 4040 throw new IllegalStateException( 4041 "Peer does not exist while invoking the decreaseComponentCount() method" 4042 ); 4043 } 4044 4045 int subHW = 0; 4046 int subLW = 0; 4047 4048 if (c instanceof Container) { 4049 subLW = ((Container)c).numOfLWComponents; 4050 subHW = ((Container)c).numOfHWComponents; 4051 } 4052 if (c.isLightweight()) { 4053 subLW++; 4054 } else { 4055 subHW++; 4056 } 4057 4058 for (Container cont = this; cont != null; cont = cont.getContainer()) { 4059 cont.numOfLWComponents -= subLW; 4060 cont.numOfHWComponents -= subHW; 4061 } 4062 } 4063 } 4064 4065 private int getTopmostComponentIndex() { 4066 checkTreeLock(); 4067 if (getComponentCount() > 0) { 4068 return 0; 4069 } 4070 return -1; 4071 } 4072 4073 private int getBottommostComponentIndex() { 4074 checkTreeLock(); 4075 if (getComponentCount() > 0) { 4076 return getComponentCount() - 1; 4077 } 4078 return -1; 4079 } 4080 4081 /* 4082 * This method is overriden to handle opaque children in non-opaque 4083 * containers. 4084 */ 4085 @Override 4086 final Region getOpaqueShape() { 4087 checkTreeLock(); 4088 if (isLightweight() && isNonOpaqueForMixing() 4089 && hasLightweightDescendants()) 4090 { 4091 Region s = Region.EMPTY_REGION; 4092 for (int index = 0; index < getComponentCount(); index++) { 4093 Component c = getComponent(index); 4094 if (c.isLightweight() && c.isShowing()) { 4095 s = s.getUnion(c.getOpaqueShape()); 4096 } 4097 } 4098 return s.getIntersection(getNormalShape()); 4099 } 4100 return super.getOpaqueShape(); 4101 } 4102 4103 final void recursiveSubtractAndApplyShape(Region shape) { 4104 recursiveSubtractAndApplyShape(shape, getTopmostComponentIndex(), getBottommostComponentIndex()); 4105 } 4106 4107 final void recursiveSubtractAndApplyShape(Region shape, int fromZorder) { 4108 recursiveSubtractAndApplyShape(shape, fromZorder, getBottommostComponentIndex()); 4109 } 4110 4111 final void recursiveSubtractAndApplyShape(Region shape, int fromZorder, int toZorder) { 4112 checkTreeLock(); 4113 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4114 mixingLog.fine("this = " + this + 4115 "; shape=" + shape + "; fromZ=" + fromZorder + "; toZ=" + toZorder); 4116 } 4117 if (fromZorder == -1) { 4118 return; 4119 } 4120 if (shape.isEmpty()) { 4121 return; 4122 } 4123 // An invalid container with not-null layout should be ignored 4124 // by the mixing code, the container will be validated later 4125 // and the mixing code will be executed later. 4126 if (getLayout() != null && !isValid()) { 4127 return; 4128 } 4129 for (int index = fromZorder; index <= toZorder; index++) { 4130 Component comp = getComponent(index); 4131 if (!comp.isLightweight()) { 4132 comp.subtractAndApplyShape(shape); 4133 } else if (comp instanceof Container && 4134 ((Container)comp).hasHeavyweightDescendants() && comp.isShowing()) { 4135 ((Container)comp).recursiveSubtractAndApplyShape(shape); 4136 } 4137 } 4138 } 4139 4140 final void recursiveApplyCurrentShape() { 4141 recursiveApplyCurrentShape(getTopmostComponentIndex(), getBottommostComponentIndex()); 4142 } 4143 4144 final void recursiveApplyCurrentShape(int fromZorder) { 4145 recursiveApplyCurrentShape(fromZorder, getBottommostComponentIndex()); 4146 } 4147 4148 final void recursiveApplyCurrentShape(int fromZorder, int toZorder) { 4149 checkTreeLock(); 4150 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4151 mixingLog.fine("this = " + this + 4152 "; fromZ=" + fromZorder + "; toZ=" + toZorder); 4153 } 4154 if (fromZorder == -1) { 4155 return; 4156 } 4157 // An invalid container with not-null layout should be ignored 4158 // by the mixing code, the container will be validated later 4159 // and the mixing code will be executed later. 4160 if (getLayout() != null && !isValid()) { 4161 return; 4162 } 4163 for (int index = fromZorder; index <= toZorder; index++) { 4164 Component comp = getComponent(index); 4165 if (!comp.isLightweight()) { 4166 comp.applyCurrentShape(); 4167 } 4168 if (comp instanceof Container && 4169 ((Container)comp).hasHeavyweightDescendants()) { 4170 ((Container)comp).recursiveApplyCurrentShape(); 4171 } 4172 } 4173 } 4174 4175 private void recursiveShowHeavyweightChildren() { 4176 if (!hasHeavyweightDescendants() || !isVisible()) { 4177 return; 4178 } 4179 for (int index = 0; index < getComponentCount(); index++) { 4180 Component comp = getComponent(index); 4181 if (comp.isLightweight()) { 4182 if (comp instanceof Container) { 4183 ((Container)comp).recursiveShowHeavyweightChildren(); 4184 } 4185 } else { 4186 if (comp.isVisible()) { 4187 ComponentPeer peer = comp.getPeer(); 4188 if (peer != null) { 4189 peer.setVisible(true); 4190 } 4191 } 4192 } 4193 } 4194 } 4195 4196 private void recursiveHideHeavyweightChildren() { 4197 if (!hasHeavyweightDescendants()) { 4198 return; 4199 } 4200 for (int index = 0; index < getComponentCount(); index++) { 4201 Component comp = getComponent(index); 4202 if (comp.isLightweight()) { 4203 if (comp instanceof Container) { 4204 ((Container)comp).recursiveHideHeavyweightChildren(); 4205 } 4206 } else { 4207 if (comp.isVisible()) { 4208 ComponentPeer peer = comp.getPeer(); 4209 if (peer != null) { 4210 peer.setVisible(false); 4211 } 4212 } 4213 } 4214 } 4215 } 4216 4217 private void recursiveRelocateHeavyweightChildren(Point origin) { 4218 for (int index = 0; index < getComponentCount(); index++) { 4219 Component comp = getComponent(index); 4220 if (comp.isLightweight()) { 4221 if (comp instanceof Container && 4222 ((Container)comp).hasHeavyweightDescendants()) 4223 { 4224 final Point newOrigin = new Point(origin); 4225 newOrigin.translate(comp.getX(), comp.getY()); 4226 ((Container)comp).recursiveRelocateHeavyweightChildren(newOrigin); 4227 } 4228 } else { 4229 ComponentPeer peer = comp.getPeer(); 4230 if (peer != null) { 4231 peer.setBounds(origin.x + comp.getX(), origin.y + comp.getY(), 4232 comp.getWidth(), comp.getHeight(), 4233 ComponentPeer.SET_LOCATION); 4234 } 4235 } 4236 } 4237 } 4238 4239 /** 4240 * Checks if the container and its direct lightweight containers are 4241 * visible. 4242 * 4243 * Consider the heavyweight container hides or shows the HW descendants 4244 * automatically. Therefore we care of LW containers' visibility only. 4245 * 4246 * This method MUST be invoked under the TreeLock. 4247 */ 4248 final boolean isRecursivelyVisibleUpToHeavyweightContainer() { 4249 if (!isLightweight()) { 4250 return true; 4251 } 4252 4253 for (Container cont = this; 4254 cont != null && cont.isLightweight(); 4255 cont = cont.getContainer()) 4256 { 4257 if (!cont.isVisible()) { 4258 return false; 4259 } 4260 } 4261 return true; 4262 } 4263 4264 @Override 4265 void mixOnShowing() { 4266 synchronized (getTreeLock()) { 4267 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4268 mixingLog.fine("this = " + this); 4269 } 4270 4271 boolean isLightweight = isLightweight(); 4272 4273 if (isLightweight && isRecursivelyVisibleUpToHeavyweightContainer()) { 4274 recursiveShowHeavyweightChildren(); 4275 } 4276 4277 if (!isMixingNeeded()) { 4278 return; 4279 } 4280 4281 if (!isLightweight || (isLightweight && hasHeavyweightDescendants())) { 4282 recursiveApplyCurrentShape(); 4283 } 4284 4285 super.mixOnShowing(); 4286 } 4287 } 4288 4289 @Override 4290 void mixOnHiding(boolean isLightweight) { 4291 synchronized (getTreeLock()) { 4292 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4293 mixingLog.fine("this = " + this + 4294 "; isLightweight=" + isLightweight); 4295 } 4296 if (isLightweight) { 4297 recursiveHideHeavyweightChildren(); 4298 } 4299 super.mixOnHiding(isLightweight); 4300 } 4301 } 4302 4303 @Override 4304 void mixOnReshaping() { 4305 synchronized (getTreeLock()) { 4306 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4307 mixingLog.fine("this = " + this); 4308 } 4309 4310 boolean isMixingNeeded = isMixingNeeded(); 4311 4312 if (isLightweight() && hasHeavyweightDescendants()) { 4313 final Point origin = new Point(getX(), getY()); 4314 for (Container cont = getContainer(); 4315 cont != null && cont.isLightweight(); 4316 cont = cont.getContainer()) 4317 { 4318 origin.translate(cont.getX(), cont.getY()); 4319 } 4320 4321 recursiveRelocateHeavyweightChildren(origin); 4322 4323 if (!isMixingNeeded) { 4324 return; 4325 } 4326 4327 recursiveApplyCurrentShape(); 4328 } 4329 4330 if (!isMixingNeeded) { 4331 return; 4332 } 4333 4334 super.mixOnReshaping(); 4335 } 4336 } 4337 4338 @Override 4339 void mixOnZOrderChanging(int oldZorder, int newZorder) { 4340 synchronized (getTreeLock()) { 4341 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4342 mixingLog.fine("this = " + this + 4343 "; oldZ=" + oldZorder + "; newZ=" + newZorder); 4344 } 4345 4346 if (!isMixingNeeded()) { 4347 return; 4348 } 4349 4350 boolean becameHigher = newZorder < oldZorder; 4351 4352 if (becameHigher && isLightweight() && hasHeavyweightDescendants()) { 4353 recursiveApplyCurrentShape(); 4354 } 4355 super.mixOnZOrderChanging(oldZorder, newZorder); 4356 } 4357 } 4358 4359 @Override 4360 void mixOnValidating() { 4361 synchronized (getTreeLock()) { 4362 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4363 mixingLog.fine("this = " + this); 4364 } 4365 4366 if (!isMixingNeeded()) { 4367 return; 4368 } 4369 4370 if (hasHeavyweightDescendants()) { 4371 recursiveApplyCurrentShape(); 4372 } 4373 4374 if (isLightweight() && isNonOpaqueForMixing()) { 4375 subtractAndApplyShapeBelowMe(); 4376 } 4377 4378 super.mixOnValidating(); 4379 } 4380 } 4381 4382 // ****************** END OF MIXING CODE ******************************** 4383 } 4384 4385 4386 /** 4387 * Class to manage the dispatching of MouseEvents to the lightweight descendants 4388 * and SunDropTargetEvents to both lightweight and heavyweight descendants 4389 * contained by a native container. 4390 * 4391 * NOTE: the class name is not appropriate anymore, but we cannot change it 4392 * because we must keep serialization compatibility. 4393 * 4394 * @author Timothy Prinzing 4395 */ 4396 class LightweightDispatcher implements java.io.Serializable, AWTEventListener { 4397 4398 /* 4399 * JDK 1.1 serialVersionUID 4400 */ 4401 private static final long serialVersionUID = 5184291520170872969L; 4402 /* 4403 * Our own mouse event for when we're dragged over from another hw 4404 * container 4405 */ 4406 private static final int LWD_MOUSE_DRAGGED_OVER = 1500; 4407 4408 private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.LightweightDispatcher"); 4409 4410 LightweightDispatcher(Container nativeContainer) { 4411 this.nativeContainer = nativeContainer; 4412 mouseEventTarget = null; 4413 eventMask = 0; 4414 } 4415 4416 /* 4417 * Clean up any resources allocated when dispatcher was created; 4418 * should be called from Container.removeNotify 4419 */ 4420 void dispose() { 4421 //System.out.println("Disposing lw dispatcher"); 4422 stopListeningForOtherDrags(); 4423 mouseEventTarget = null; 4424 targetLastEntered = null; 4425 } 4426 4427 /** 4428 * Enables events to subcomponents. 4429 */ 4430 void enableEvents(long events) { 4431 eventMask |= events; 4432 } 4433 4434 /** 4435 * Dispatches an event to a sub-component if necessary, and 4436 * returns whether or not the event was forwarded to a 4437 * sub-component. 4438 * 4439 * @param e the event 4440 */ 4441 boolean dispatchEvent(AWTEvent e) { 4442 boolean ret = false; 4443 4444 /* 4445 * Fix for BugTraq Id 4389284. 4446 * Dispatch SunDropTargetEvents regardless of eventMask value. 4447 * Do not update cursor on dispatching SunDropTargetEvents. 4448 */ 4449 if (e instanceof SunDropTargetEvent) { 4450 4451 SunDropTargetEvent sdde = (SunDropTargetEvent) e; 4452 ret = processDropTargetEvent(sdde); 4453 4454 } else { 4455 if (e instanceof MouseEvent && (eventMask & MOUSE_MASK) != 0) { 4456 MouseEvent me = (MouseEvent) e; 4457 ret = processMouseEvent(me); 4458 } 4459 4460 if (e.getID() == MouseEvent.MOUSE_MOVED) { 4461 nativeContainer.updateCursorImmediately(); 4462 } 4463 } 4464 4465 return ret; 4466 } 4467 4468 /* This method effectively returns whether or not a mouse button was down 4469 * just BEFORE the event happened. A better method name might be 4470 * wasAMouseButtonDownBeforeThisEvent(). 4471 */ 4472 private boolean isMouseGrab(MouseEvent e) { 4473 int modifiers = e.getModifiersEx(); 4474 4475 if(e.getID() == MouseEvent.MOUSE_PRESSED 4476 || e.getID() == MouseEvent.MOUSE_RELEASED) 4477 { 4478 switch (e.getButton()) { 4479 case MouseEvent.BUTTON1: 4480 modifiers ^= InputEvent.BUTTON1_DOWN_MASK; 4481 break; 4482 case MouseEvent.BUTTON2: 4483 modifiers ^= InputEvent.BUTTON2_DOWN_MASK; 4484 break; 4485 case MouseEvent.BUTTON3: 4486 modifiers ^= InputEvent.BUTTON3_DOWN_MASK; 4487 break; 4488 } 4489 } 4490 /* modifiers now as just before event */ 4491 return ((modifiers & (InputEvent.BUTTON1_DOWN_MASK 4492 | InputEvent.BUTTON2_DOWN_MASK 4493 | InputEvent.BUTTON3_DOWN_MASK)) != 0); 4494 } 4495 4496 /** 4497 * This method attempts to distribute a mouse event to a lightweight 4498 * component. It tries to avoid doing any unnecessary probes down 4499 * into the component tree to minimize the overhead of determining 4500 * where to route the event, since mouse movement events tend to 4501 * come in large and frequent amounts. 4502 */ 4503 private boolean processMouseEvent(MouseEvent e) { 4504 int id = e.getID(); 4505 Component mouseOver = // sensitive to mouse events 4506 nativeContainer.getMouseEventTarget(e.getX(), e.getY(), 4507 Container.INCLUDE_SELF); 4508 4509 trackMouseEnterExit(mouseOver, e); 4510 4511 // 4508327 : MOUSE_CLICKED should only go to the recipient of 4512 // the accompanying MOUSE_PRESSED, so don't reset mouseEventTarget on a 4513 // MOUSE_CLICKED. 4514 if (!isMouseGrab(e) && id != MouseEvent.MOUSE_CLICKED) { 4515 mouseEventTarget = (mouseOver != nativeContainer) ? mouseOver: null; 4516 isCleaned = false; 4517 } 4518 4519 if (mouseEventTarget != null) { 4520 switch (id) { 4521 case MouseEvent.MOUSE_ENTERED: 4522 case MouseEvent.MOUSE_EXITED: 4523 break; 4524 case MouseEvent.MOUSE_PRESSED: 4525 retargetMouseEvent(mouseEventTarget, id, e); 4526 break; 4527 case MouseEvent.MOUSE_RELEASED: 4528 retargetMouseEvent(mouseEventTarget, id, e); 4529 break; 4530 case MouseEvent.MOUSE_CLICKED: 4531 // 4508327: MOUSE_CLICKED should never be dispatched to a Component 4532 // other than that which received the MOUSE_PRESSED event. If the 4533 // mouse is now over a different Component, don't dispatch the event. 4534 // The previous fix for a similar problem was associated with bug 4535 // 4155217. 4536 if (mouseOver == mouseEventTarget) { 4537 retargetMouseEvent(mouseOver, id, e); 4538 } 4539 break; 4540 case MouseEvent.MOUSE_MOVED: 4541 retargetMouseEvent(mouseEventTarget, id, e); 4542 break; 4543 case MouseEvent.MOUSE_DRAGGED: 4544 if (isMouseGrab(e)) { 4545 retargetMouseEvent(mouseEventTarget, id, e); 4546 } 4547 break; 4548 case MouseEvent.MOUSE_WHEEL: 4549 // This may send it somewhere that doesn't have MouseWheelEvents 4550 // enabled. In this case, Component.dispatchEventImpl() will 4551 // retarget the event to a parent that DOES have the events enabled. 4552 if (eventLog.isLoggable(PlatformLogger.Level.FINEST) && (mouseOver != null)) { 4553 eventLog.finest("retargeting mouse wheel to " + 4554 mouseOver.getName() + ", " + 4555 mouseOver.getClass()); 4556 } 4557 retargetMouseEvent(mouseOver, id, e); 4558 break; 4559 } 4560 //Consuming of wheel events is implemented in "retargetMouseEvent". 4561 if (id != MouseEvent.MOUSE_WHEEL) { 4562 e.consume(); 4563 } 4564 } else if (isCleaned && id != MouseEvent.MOUSE_WHEEL) { 4565 //After mouseEventTarget was removed and cleaned should consume all events 4566 //until new mouseEventTarget is found 4567 e.consume(); 4568 } 4569 return e.isConsumed(); 4570 } 4571 4572 private boolean processDropTargetEvent(SunDropTargetEvent e) { 4573 int id = e.getID(); 4574 int x = e.getX(); 4575 int y = e.getY(); 4576 4577 /* 4578 * Fix for BugTraq ID 4395290. 4579 * It is possible that SunDropTargetEvent's Point is outside of the 4580 * native container bounds. In this case we truncate coordinates. 4581 */ 4582 if (!nativeContainer.contains(x, y)) { 4583 final Dimension d = nativeContainer.getSize(); 4584 if (d.width <= x) { 4585 x = d.width - 1; 4586 } else if (x < 0) { 4587 x = 0; 4588 } 4589 if (d.height <= y) { 4590 y = d.height - 1; 4591 } else if (y < 0) { 4592 y = 0; 4593 } 4594 } 4595 Component mouseOver = // not necessarily sensitive to mouse events 4596 nativeContainer.getDropTargetEventTarget(x, y, 4597 Container.INCLUDE_SELF); 4598 trackMouseEnterExit(mouseOver, e); 4599 4600 if (mouseOver != nativeContainer && mouseOver != null) { 4601 switch (id) { 4602 case SunDropTargetEvent.MOUSE_ENTERED: 4603 case SunDropTargetEvent.MOUSE_EXITED: 4604 break; 4605 default: 4606 retargetMouseEvent(mouseOver, id, e); 4607 e.consume(); 4608 break; 4609 } 4610 } 4611 return e.isConsumed(); 4612 } 4613 4614 /* 4615 * Generates enter/exit events as mouse moves over lw components 4616 * @param targetOver Target mouse is over (including native container) 4617 * @param e Mouse event in native container 4618 */ 4619 private void trackMouseEnterExit(Component targetOver, MouseEvent e) { 4620 Component targetEnter = null; 4621 int id = e.getID(); 4622 4623 if (e instanceof SunDropTargetEvent && 4624 id == MouseEvent.MOUSE_ENTERED && 4625 isMouseInNativeContainer == true) { 4626 // This can happen if a lightweight component which initiated the 4627 // drag has an associated drop target. MOUSE_ENTERED comes when the 4628 // mouse is in the native container already. To propagate this event 4629 // properly we should null out targetLastEntered. 4630 targetLastEntered = null; 4631 } else if ( id != MouseEvent.MOUSE_EXITED && 4632 id != MouseEvent.MOUSE_DRAGGED && 4633 id != LWD_MOUSE_DRAGGED_OVER && 4634 isMouseInNativeContainer == false ) { 4635 // any event but an exit or drag means we're in the native container 4636 isMouseInNativeContainer = true; 4637 startListeningForOtherDrags(); 4638 } else if ( id == MouseEvent.MOUSE_EXITED ) { 4639 isMouseInNativeContainer = false; 4640 stopListeningForOtherDrags(); 4641 } 4642 4643 if (isMouseInNativeContainer) { 4644 targetEnter = targetOver; 4645 } 4646 4647 if (targetLastEntered == targetEnter) { 4648 return; 4649 } 4650 4651 if (targetLastEntered != null) { 4652 retargetMouseEvent(targetLastEntered, MouseEvent.MOUSE_EXITED, e); 4653 } 4654 if (id == MouseEvent.MOUSE_EXITED) { 4655 // consume native exit event if we generate one 4656 e.consume(); 4657 } 4658 4659 if (targetEnter != null) { 4660 retargetMouseEvent(targetEnter, MouseEvent.MOUSE_ENTERED, e); 4661 } 4662 if (id == MouseEvent.MOUSE_ENTERED) { 4663 // consume native enter event if we generate one 4664 e.consume(); 4665 } 4666 4667 targetLastEntered = targetEnter; 4668 } 4669 4670 /* 4671 * Listens to global mouse drag events so even drags originating 4672 * from other heavyweight containers will generate enter/exit 4673 * events in this container 4674 */ 4675 private void startListeningForOtherDrags() { 4676 //System.out.println("Adding AWTEventListener"); 4677 java.security.AccessController.doPrivileged( 4678 new java.security.PrivilegedAction<Object>() { 4679 public Object run() { 4680 nativeContainer.getToolkit().addAWTEventListener( 4681 LightweightDispatcher.this, 4682 AWTEvent.MOUSE_EVENT_MASK | 4683 AWTEvent.MOUSE_MOTION_EVENT_MASK); 4684 return null; 4685 } 4686 } 4687 ); 4688 } 4689 4690 private void stopListeningForOtherDrags() { 4691 //System.out.println("Removing AWTEventListener"); 4692 java.security.AccessController.doPrivileged( 4693 new java.security.PrivilegedAction<Object>() { 4694 public Object run() { 4695 nativeContainer.getToolkit().removeAWTEventListener(LightweightDispatcher.this); 4696 return null; 4697 } 4698 } 4699 ); 4700 } 4701 4702 /* 4703 * (Implementation of AWTEventListener) 4704 * Listen for drag events posted in other hw components so we can 4705 * track enter/exit regardless of where a drag originated 4706 */ 4707 public void eventDispatched(AWTEvent e) { 4708 boolean isForeignDrag = (e instanceof MouseEvent) && 4709 !(e instanceof SunDropTargetEvent) && 4710 (e.id == MouseEvent.MOUSE_DRAGGED) && 4711 (e.getSource() != nativeContainer); 4712 4713 if (!isForeignDrag) { 4714 // only interested in drags from other hw components 4715 return; 4716 } 4717 4718 MouseEvent srcEvent = (MouseEvent)e; 4719 MouseEvent me; 4720 4721 synchronized (nativeContainer.getTreeLock()) { 4722 Component srcComponent = srcEvent.getComponent(); 4723 4724 // component may have disappeared since drag event posted 4725 // (i.e. Swing hierarchical menus) 4726 if ( !srcComponent.isShowing() ) { 4727 return; 4728 } 4729 4730 // see 5083555 4731 // check if srcComponent is in any modal blocked window 4732 Component c = nativeContainer; 4733 while ((c != null) && !(c instanceof Window)) { 4734 c = c.getParent_NoClientCode(); 4735 } 4736 if ((c == null) || ((Window)c).isModalBlocked()) { 4737 return; 4738 } 4739 4740 // 4741 // create an internal 'dragged-over' event indicating 4742 // we are being dragged over from another hw component 4743 // 4744 me = new MouseEvent(nativeContainer, 4745 LWD_MOUSE_DRAGGED_OVER, 4746 srcEvent.getWhen(), 4747 srcEvent.getModifiersEx() | srcEvent.getModifiers(), 4748 srcEvent.getX(), 4749 srcEvent.getY(), 4750 srcEvent.getXOnScreen(), 4751 srcEvent.getYOnScreen(), 4752 srcEvent.getClickCount(), 4753 srcEvent.isPopupTrigger(), 4754 srcEvent.getButton()); 4755 ((AWTEvent)srcEvent).copyPrivateDataInto(me); 4756 // translate coordinates to this native container 4757 final Point ptSrcOrigin = srcComponent.getLocationOnScreen(); 4758 4759 if (AppContext.getAppContext() != nativeContainer.appContext) { 4760 final MouseEvent mouseEvent = me; 4761 Runnable r = new Runnable() { 4762 public void run() { 4763 if (!nativeContainer.isShowing() ) { 4764 return; 4765 } 4766 4767 Point ptDstOrigin = nativeContainer.getLocationOnScreen(); 4768 mouseEvent.translatePoint(ptSrcOrigin.x - ptDstOrigin.x, 4769 ptSrcOrigin.y - ptDstOrigin.y ); 4770 Component targetOver = 4771 nativeContainer.getMouseEventTarget(mouseEvent.getX(), 4772 mouseEvent.getY(), 4773 Container.INCLUDE_SELF); 4774 trackMouseEnterExit(targetOver, mouseEvent); 4775 } 4776 }; 4777 SunToolkit.executeOnEventHandlerThread(nativeContainer, r); 4778 return; 4779 } else { 4780 if (!nativeContainer.isShowing() ) { 4781 return; 4782 } 4783 4784 Point ptDstOrigin = nativeContainer.getLocationOnScreen(); 4785 me.translatePoint( ptSrcOrigin.x - ptDstOrigin.x, ptSrcOrigin.y - ptDstOrigin.y ); 4786 } 4787 } 4788 //System.out.println("Track event: " + me); 4789 // feed the 'dragged-over' event directly to the enter/exit 4790 // code (not a real event so don't pass it to dispatchEvent) 4791 Component targetOver = 4792 nativeContainer.getMouseEventTarget(me.getX(), me.getY(), 4793 Container.INCLUDE_SELF); 4794 trackMouseEnterExit(targetOver, me); 4795 } 4796 4797 /** 4798 * Sends a mouse event to the current mouse event recipient using 4799 * the given event (sent to the windowed host) as a srcEvent. If 4800 * the mouse event target is still in the component tree, the 4801 * coordinates of the event are translated to those of the target. 4802 * If the target has been removed, we don't bother to send the 4803 * message. 4804 */ 4805 void retargetMouseEvent(Component target, int id, MouseEvent e) { 4806 if (target == null) { 4807 return; // mouse is over another hw component or target is disabled 4808 } 4809 4810 int x = e.getX(), y = e.getY(); 4811 Component component; 4812 4813 for(component = target; 4814 component != null && component != nativeContainer; 4815 component = component.getParent()) { 4816 x -= component.x; 4817 y -= component.y; 4818 } 4819 MouseEvent retargeted; 4820 if (component != null) { 4821 if (e instanceof SunDropTargetEvent) { 4822 retargeted = new SunDropTargetEvent(target, 4823 id, 4824 x, 4825 y, 4826 ((SunDropTargetEvent)e).getDispatcher()); 4827 } else if (id == MouseEvent.MOUSE_WHEEL) { 4828 retargeted = new MouseWheelEvent(target, 4829 id, 4830 e.getWhen(), 4831 e.getModifiersEx() | e.getModifiers(), 4832 x, 4833 y, 4834 e.getXOnScreen(), 4835 e.getYOnScreen(), 4836 e.getClickCount(), 4837 e.isPopupTrigger(), 4838 ((MouseWheelEvent)e).getScrollType(), 4839 ((MouseWheelEvent)e).getScrollAmount(), 4840 ((MouseWheelEvent)e).getWheelRotation(), 4841 ((MouseWheelEvent)e).getPreciseWheelRotation()); 4842 } 4843 else { 4844 retargeted = new MouseEvent(target, 4845 id, 4846 e.getWhen(), 4847 e.getModifiersEx() | e.getModifiers(), 4848 x, 4849 y, 4850 e.getXOnScreen(), 4851 e.getYOnScreen(), 4852 e.getClickCount(), 4853 e.isPopupTrigger(), 4854 e.getButton()); 4855 } 4856 4857 ((AWTEvent)e).copyPrivateDataInto(retargeted); 4858 4859 if (target == nativeContainer) { 4860 // avoid recursively calling LightweightDispatcher... 4861 ((Container)target).dispatchEventToSelf(retargeted); 4862 } else { 4863 assert AppContext.getAppContext() == target.appContext; 4864 4865 if (nativeContainer.modalComp != null) { 4866 if (((Container)nativeContainer.modalComp).isAncestorOf(target)) { 4867 target.dispatchEvent(retargeted); 4868 } else { 4869 e.consume(); 4870 } 4871 } else { 4872 target.dispatchEvent(retargeted); 4873 } 4874 } 4875 if (id == MouseEvent.MOUSE_WHEEL && retargeted.isConsumed()) { 4876 //An exception for wheel bubbling to the native system. 4877 //In "processMouseEvent" total event consuming for wheel events is skipped. 4878 //Protection from bubbling of Java-accepted wheel events. 4879 e.consume(); 4880 } 4881 } 4882 } 4883 4884 // --- member variables ------------------------------- 4885 4886 /** 4887 * The windowed container that might be hosting events for 4888 * subcomponents. 4889 */ 4890 private Container nativeContainer; 4891 4892 /** 4893 * This variable is not used, but kept for serialization compatibility 4894 */ 4895 private Component focus; 4896 4897 /** 4898 * The current subcomponent being hosted by this windowed 4899 * component that has events being forwarded to it. If this 4900 * is null, there are currently no events being forwarded to 4901 * a subcomponent. 4902 */ 4903 private transient Component mouseEventTarget; 4904 4905 /** 4906 * The last component entered 4907 */ 4908 private transient Component targetLastEntered; 4909 4910 /** 4911 * Indicates whether {@code mouseEventTarget} was removed and nulled 4912 */ 4913 private transient boolean isCleaned; 4914 4915 /** 4916 * Is the mouse over the native container 4917 */ 4918 private transient boolean isMouseInNativeContainer = false; 4919 4920 /** 4921 * This variable is not used, but kept for serialization compatibility 4922 */ 4923 private Cursor nativeCursor; 4924 4925 /** 4926 * The event mask for contained lightweight components. Lightweight 4927 * components need a windowed container to host window-related 4928 * events. This separate mask indicates events that have been 4929 * requested by contained lightweight components without effecting 4930 * the mask of the windowed component itself. 4931 */ 4932 private long eventMask; 4933 4934 /** 4935 * The kind of events routed to lightweight components from windowed 4936 * hosts. 4937 */ 4938 private static final long PROXY_EVENT_MASK = 4939 AWTEvent.FOCUS_EVENT_MASK | 4940 AWTEvent.KEY_EVENT_MASK | 4941 AWTEvent.MOUSE_EVENT_MASK | 4942 AWTEvent.MOUSE_MOTION_EVENT_MASK | 4943 AWTEvent.MOUSE_WHEEL_EVENT_MASK; 4944 4945 private static final long MOUSE_MASK = 4946 AWTEvent.MOUSE_EVENT_MASK | 4947 AWTEvent.MOUSE_MOTION_EVENT_MASK | 4948 AWTEvent.MOUSE_WHEEL_EVENT_MASK; 4949 4950 void removeReferences(Component removedComponent) { 4951 if (mouseEventTarget == removedComponent) { 4952 isCleaned = true; 4953 mouseEventTarget = null; 4954 } 4955 if (targetLastEntered == removedComponent) { 4956 targetLastEntered = null; 4957 } 4958 } 4959 }