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