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