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