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