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