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