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 JDK1.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 JDK1.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 JDK1.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 JDK1.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 JDK1.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 JDK1.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 JDK1.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 JDK1.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 JDK1.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 JDK1.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 JDK1.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 JDK1.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 = new Runnable() { 2903 public void run() { 2904 EventDispatchThread dispatchThread = 2905 (EventDispatchThread)Thread.currentThread(); 2906 dispatchThread.pumpEventsForHierarchy( 2907 new Conditional() { 2908 public boolean evaluate() { 2909 return ((windowClosingException == null) && (nativeContainer.modalComp != null)) ; 2910 } 2911 }, Container.this); 2912 } 2913 }; 2914 2915 if (EventQueue.isDispatchThread()) { 2916 SequencedEvent currentSequencedEvent = 2917 KeyboardFocusManager.getCurrentKeyboardFocusManager(). 2918 getCurrentSequencedEvent(); 2919 if (currentSequencedEvent != null) { 2920 currentSequencedEvent.dispose(); 2921 } 2922 2923 pumpEventsForHierarchy.run(); 2924 } else { 2925 synchronized (getTreeLock()) { 2926 Toolkit.getEventQueue(). 2927 postEvent(new PeerEvent(this, 2928 pumpEventsForHierarchy, 2929 PeerEvent.PRIORITY_EVENT)); 2930 while ((windowClosingException == null) && 2931 (nativeContainer.modalComp != null)) 2932 { 2933 try { 2934 getTreeLock().wait(); 2935 } catch (InterruptedException e) { 2936 break; 2937 } 2938 } 2939 } 2940 } 2941 if (windowClosingException != null) { 2942 windowClosingException.fillInStackTrace(); 2943 throw windowClosingException; 2944 } 2945 if (predictedFocusOwner != null) { 2946 KeyboardFocusManager.getCurrentKeyboardFocusManager(). 2947 dequeueKeyEvents(time, predictedFocusOwner); 2948 } 2949 } 2950 2951 private void stopLWModal() { 2952 synchronized (getTreeLock()) { 2953 if (modalAppContext != null) { 2954 Container nativeContainer = getHeavyweightContainer(); 2955 if(nativeContainer != null) { 2956 if (this.modalComp != null) { 2957 nativeContainer.modalComp = this.modalComp; 2958 this.modalComp = null; 2959 return; 2960 } 2961 else { 2962 nativeContainer.modalComp = null; 2963 } 2964 } 2965 // Wake up event dispatch thread on which the dialog was 2966 // initially shown 2967 SunToolkit.postEvent(modalAppContext, 2968 new PeerEvent(this, 2969 new WakingRunnable(), 2970 PeerEvent.PRIORITY_EVENT)); 2971 } 2972 EventQueue.invokeLater(new WakingRunnable()); 2973 getTreeLock().notifyAll(); 2974 } 2975 } 2976 2977 final static class WakingRunnable implements Runnable { 2978 public void run() { 2979 } 2980 } 2981 2982 /* End of JOptionPane support code */ 2983 2984 /** 2985 * Returns a string representing the state of this <code>Container</code>. 2986 * This method is intended to be used only for debugging purposes, and the 2987 * content and format of the returned string may vary between 2988 * implementations. The returned string may be empty but may not be 2989 * <code>null</code>. 2990 * 2991 * @return the parameter string of this container 2992 */ 2993 protected String paramString() { 2994 String str = super.paramString(); 2995 LayoutManager layoutMgr = this.layoutMgr; 2996 if (layoutMgr != null) { 2997 str += ",layout=" + layoutMgr.getClass().getName(); 2998 } 2999 return str; 3000 } 3001 3002 /** 3003 * Prints a listing of this container to the specified output 3004 * stream. The listing starts at the specified indentation. 3005 * <p> 3006 * The immediate children of the container are printed with 3007 * an indentation of <code>indent+1</code>. The children 3008 * of those children are printed at <code>indent+2</code> 3009 * and so on. 3010 * 3011 * @param out a print stream 3012 * @param indent the number of spaces to indent 3013 * @throws NullPointerException if {@code out} is {@code null} 3014 * @see Component#list(java.io.PrintStream, int) 3015 * @since JDK1.0 3016 */ 3017 public void list(PrintStream out, int indent) { 3018 super.list(out, indent); 3019 synchronized(getTreeLock()) { 3020 for (int i = 0; i < component.size(); i++) { 3021 Component comp = component.get(i); 3022 if (comp != null) { 3023 comp.list(out, indent+1); 3024 } 3025 } 3026 } 3027 } 3028 3029 /** 3030 * Prints out a list, starting at the specified indentation, 3031 * to the specified print writer. 3032 * <p> 3033 * The immediate children of the container are printed with 3034 * an indentation of <code>indent+1</code>. The children 3035 * of those children are printed at <code>indent+2</code> 3036 * and so on. 3037 * 3038 * @param out a print writer 3039 * @param indent the number of spaces to indent 3040 * @throws NullPointerException if {@code out} is {@code null} 3041 * @see Component#list(java.io.PrintWriter, int) 3042 * @since JDK1.1 3043 */ 3044 public void list(PrintWriter out, int indent) { 3045 super.list(out, indent); 3046 synchronized(getTreeLock()) { 3047 for (int i = 0; i < component.size(); i++) { 3048 Component comp = component.get(i); 3049 if (comp != null) { 3050 comp.list(out, indent+1); 3051 } 3052 } 3053 } 3054 } 3055 3056 /** 3057 * Sets the focus traversal keys for a given traversal operation for this 3058 * Container. 3059 * <p> 3060 * The default values for a Container's focus traversal keys are 3061 * implementation-dependent. Sun recommends that all implementations for a 3062 * particular native platform use the same default values. The 3063 * recommendations for Windows and Unix are listed below. These 3064 * recommendations are used in the Sun AWT implementations. 3065 * 3066 * <table border=1 summary="Recommended default values for a Container's focus traversal keys"> 3067 * <tr> 3068 * <th>Identifier</th> 3069 * <th>Meaning</th> 3070 * <th>Default</th> 3071 * </tr> 3072 * <tr> 3073 * <td>KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS</td> 3074 * <td>Normal forward keyboard traversal</td> 3075 * <td>TAB on KEY_PRESSED, CTRL-TAB on KEY_PRESSED</td> 3076 * </tr> 3077 * <tr> 3078 * <td>KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS</td> 3079 * <td>Normal reverse keyboard traversal</td> 3080 * <td>SHIFT-TAB on KEY_PRESSED, CTRL-SHIFT-TAB on KEY_PRESSED</td> 3081 * </tr> 3082 * <tr> 3083 * <td>KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS</td> 3084 * <td>Go up one focus traversal cycle</td> 3085 * <td>none</td> 3086 * </tr> 3087 * <tr> 3088 * <td>KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS<td> 3089 * <td>Go down one focus traversal cycle</td> 3090 * <td>none</td> 3091 * </tr> 3092 * </table> 3093 * 3094 * To disable a traversal key, use an empty Set; Collections.EMPTY_SET is 3095 * recommended. 3096 * <p> 3097 * Using the AWTKeyStroke API, client code can specify on which of two 3098 * specific KeyEvents, KEY_PRESSED or KEY_RELEASED, the focus traversal 3099 * operation will occur. Regardless of which KeyEvent is specified, 3100 * however, all KeyEvents related to the focus traversal key, including the 3101 * associated KEY_TYPED event, will be consumed, and will not be dispatched 3102 * to any Container. It is a runtime error to specify a KEY_TYPED event as 3103 * mapping to a focus traversal operation, or to map the same event to 3104 * multiple default focus traversal operations. 3105 * <p> 3106 * If a value of null is specified for the Set, this Container inherits the 3107 * Set from its parent. If all ancestors of this Container have null 3108 * specified for the Set, then the current KeyboardFocusManager's default 3109 * Set is used. 3110 * <p> 3111 * This method may throw a {@code ClassCastException} if any {@code Object} 3112 * in {@code keystrokes} is not an {@code AWTKeyStroke}. 3113 * 3114 * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 3115 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 3116 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or 3117 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS 3118 * @param keystrokes the Set of AWTKeyStroke for the specified operation 3119 * @see #getFocusTraversalKeys 3120 * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS 3121 * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS 3122 * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS 3123 * @see KeyboardFocusManager#DOWN_CYCLE_TRAVERSAL_KEYS 3124 * @throws IllegalArgumentException if id is not one of 3125 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 3126 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 3127 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or 3128 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, or if keystrokes 3129 * contains null, or if any keystroke represents a KEY_TYPED event, 3130 * or if any keystroke already maps to another focus traversal 3131 * operation for this Container 3132 * @since 1.4 3133 * @beaninfo 3134 * bound: true 3135 */ 3136 public void setFocusTraversalKeys(int id, 3137 Set<? extends AWTKeyStroke> keystrokes) 3138 { 3139 if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) { 3140 throw new IllegalArgumentException("invalid focus traversal key identifier"); 3141 } 3142 3143 // Don't call super.setFocusTraversalKey. The Component parameter check 3144 // does not allow DOWN_CYCLE_TRAVERSAL_KEYS, but we do. 3145 setFocusTraversalKeys_NoIDCheck(id, keystrokes); 3146 } 3147 3148 /** 3149 * Returns the Set of focus traversal keys for a given traversal operation 3150 * for this Container. (See 3151 * <code>setFocusTraversalKeys</code> for a full description of each key.) 3152 * <p> 3153 * If a Set of traversal keys has not been explicitly defined for this 3154 * Container, then this Container's parent's Set is returned. If no Set 3155 * has been explicitly defined for any of this Container's ancestors, then 3156 * the current KeyboardFocusManager's default Set is returned. 3157 * 3158 * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 3159 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 3160 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or 3161 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS 3162 * @return the Set of AWTKeyStrokes for the specified operation. The Set 3163 * will be unmodifiable, and may be empty. null will never be 3164 * returned. 3165 * @see #setFocusTraversalKeys 3166 * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS 3167 * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS 3168 * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS 3169 * @see KeyboardFocusManager#DOWN_CYCLE_TRAVERSAL_KEYS 3170 * @throws IllegalArgumentException if id is not one of 3171 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 3172 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 3173 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or 3174 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS 3175 * @since 1.4 3176 */ 3177 public Set<AWTKeyStroke> getFocusTraversalKeys(int id) { 3178 if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) { 3179 throw new IllegalArgumentException("invalid focus traversal key identifier"); 3180 } 3181 3182 // Don't call super.getFocusTraversalKey. The Component parameter check 3183 // does not allow DOWN_CYCLE_TRAVERSAL_KEY, but we do. 3184 return getFocusTraversalKeys_NoIDCheck(id); 3185 } 3186 3187 /** 3188 * Returns whether the Set of focus traversal keys for the given focus 3189 * traversal operation has been explicitly defined for this Container. If 3190 * this method returns <code>false</code>, this Container is inheriting the 3191 * Set from an ancestor, or from the current KeyboardFocusManager. 3192 * 3193 * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 3194 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 3195 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or 3196 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS 3197 * @return <code>true</code> if the the Set of focus traversal keys for the 3198 * given focus traversal operation has been explicitly defined for 3199 * this Component; <code>false</code> otherwise. 3200 * @throws IllegalArgumentException if id is not one of 3201 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 3202 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 3203 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or 3204 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS 3205 * @since 1.4 3206 */ 3207 public boolean areFocusTraversalKeysSet(int id) { 3208 if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) { 3209 throw new IllegalArgumentException("invalid focus traversal key identifier"); 3210 } 3211 3212 return (focusTraversalKeys != null && focusTraversalKeys[id] != null); 3213 } 3214 3215 /** 3216 * Returns whether the specified Container is the focus cycle root of this 3217 * Container's focus traversal cycle. Each focus traversal cycle has only 3218 * a single focus cycle root and each Container which is not a focus cycle 3219 * root belongs to only a single focus traversal cycle. Containers which 3220 * are focus cycle roots belong to two cycles: one rooted at the Container 3221 * itself, and one rooted at the Container's nearest focus-cycle-root 3222 * ancestor. This method will return <code>true</code> for both such 3223 * Containers in this case. 3224 * 3225 * @param container the Container to be tested 3226 * @return <code>true</code> if the specified Container is a focus-cycle- 3227 * root of this Container; <code>false</code> otherwise 3228 * @see #isFocusCycleRoot() 3229 * @since 1.4 3230 */ 3231 public boolean isFocusCycleRoot(Container container) { 3232 if (isFocusCycleRoot() && container == this) { 3233 return true; 3234 } else { 3235 return super.isFocusCycleRoot(container); 3236 } 3237 } 3238 3239 private Container findTraversalRoot() { 3240 // I potentially have two roots, myself and my root parent 3241 // If I am the current root, then use me 3242 // If none of my parents are roots, then use me 3243 // If my root parent is the current root, then use my root parent 3244 // If neither I nor my root parent is the current root, then 3245 // use my root parent (a guess) 3246 3247 Container currentFocusCycleRoot = KeyboardFocusManager. 3248 getCurrentKeyboardFocusManager().getCurrentFocusCycleRoot(); 3249 Container root; 3250 3251 if (currentFocusCycleRoot == this) { 3252 root = this; 3253 } else { 3254 root = getFocusCycleRootAncestor(); 3255 if (root == null) { 3256 root = this; 3257 } 3258 } 3259 3260 if (root != currentFocusCycleRoot) { 3261 KeyboardFocusManager.getCurrentKeyboardFocusManager(). 3262 setGlobalCurrentFocusCycleRootPriv(root); 3263 } 3264 return root; 3265 } 3266 3267 final boolean containsFocus() { 3268 final Component focusOwner = KeyboardFocusManager. 3269 getCurrentKeyboardFocusManager().getFocusOwner(); 3270 return isParentOf(focusOwner); 3271 } 3272 3273 /** 3274 * Check if this component is the child of this container or its children. 3275 * Note: this function acquires treeLock 3276 * Note: this function traverses children tree only in one Window. 3277 * @param comp a component in test, must not be null 3278 */ 3279 private boolean isParentOf(Component comp) { 3280 synchronized(getTreeLock()) { 3281 while (comp != null && comp != this && !(comp instanceof Window)) { 3282 comp = comp.getParent(); 3283 } 3284 return (comp == this); 3285 } 3286 } 3287 3288 void clearMostRecentFocusOwnerOnHide() { 3289 boolean reset = false; 3290 Window window = null; 3291 3292 synchronized (getTreeLock()) { 3293 window = getContainingWindow(); 3294 if (window != null) { 3295 Component comp = KeyboardFocusManager.getMostRecentFocusOwner(window); 3296 reset = ((comp == this) || isParentOf(comp)); 3297 // This synchronized should always be the second in a pair 3298 // (tree lock, KeyboardFocusManager.class) 3299 synchronized(KeyboardFocusManager.class) { 3300 Component storedComp = window.getTemporaryLostComponent(); 3301 if (isParentOf(storedComp) || storedComp == this) { 3302 window.setTemporaryLostComponent(null); 3303 } 3304 } 3305 } 3306 } 3307 3308 if (reset) { 3309 KeyboardFocusManager.setMostRecentFocusOwner(window, null); 3310 } 3311 } 3312 3313 void clearCurrentFocusCycleRootOnHide() { 3314 KeyboardFocusManager kfm = 3315 KeyboardFocusManager.getCurrentKeyboardFocusManager(); 3316 Container cont = kfm.getCurrentFocusCycleRoot(); 3317 3318 if (cont == this || isParentOf(cont)) { 3319 kfm.setGlobalCurrentFocusCycleRootPriv(null); 3320 } 3321 } 3322 3323 @Override 3324 void clearLightweightDispatcherOnRemove(Component removedComponent) { 3325 if (dispatcher != null) { 3326 dispatcher.removeReferences(removedComponent); 3327 } else { 3328 //It is a Lightweight Container, should clear parent`s Dispatcher 3329 super.clearLightweightDispatcherOnRemove(removedComponent); 3330 } 3331 } 3332 3333 final Container getTraversalRoot() { 3334 if (isFocusCycleRoot()) { 3335 return findTraversalRoot(); 3336 } 3337 3338 return super.getTraversalRoot(); 3339 } 3340 3341 /** 3342 * Sets the focus traversal policy that will manage keyboard traversal of 3343 * this Container's children, if this Container is a focus cycle root. If 3344 * the argument is null, this Container inherits its policy from its focus- 3345 * cycle-root ancestor. If the argument is non-null, this policy will be 3346 * inherited by all focus-cycle-root children that have no keyboard- 3347 * traversal policy of their own (as will, recursively, their focus-cycle- 3348 * root children). 3349 * <p> 3350 * If this Container is not a focus cycle root, the policy will be 3351 * remembered, but will not be used or inherited by this or any other 3352 * Containers until this Container is made a focus cycle root. 3353 * 3354 * @param policy the new focus traversal policy for this Container 3355 * @see #getFocusTraversalPolicy 3356 * @see #setFocusCycleRoot 3357 * @see #isFocusCycleRoot 3358 * @since 1.4 3359 * @beaninfo 3360 * bound: true 3361 */ 3362 public void setFocusTraversalPolicy(FocusTraversalPolicy policy) { 3363 FocusTraversalPolicy oldPolicy; 3364 synchronized (this) { 3365 oldPolicy = this.focusTraversalPolicy; 3366 this.focusTraversalPolicy = policy; 3367 } 3368 firePropertyChange("focusTraversalPolicy", oldPolicy, policy); 3369 } 3370 3371 /** 3372 * Returns the focus traversal policy that will manage keyboard traversal 3373 * of this Container's children, or null if this Container is not a focus 3374 * cycle root. If no traversal policy has been explicitly set for this 3375 * Container, then this Container's focus-cycle-root ancestor's policy is 3376 * returned. 3377 * 3378 * @return this Container's focus traversal policy, or null if this 3379 * Container is not a focus cycle root. 3380 * @see #setFocusTraversalPolicy 3381 * @see #setFocusCycleRoot 3382 * @see #isFocusCycleRoot 3383 * @since 1.4 3384 */ 3385 public FocusTraversalPolicy getFocusTraversalPolicy() { 3386 if (!isFocusTraversalPolicyProvider() && !isFocusCycleRoot()) { 3387 return null; 3388 } 3389 3390 FocusTraversalPolicy policy = this.focusTraversalPolicy; 3391 if (policy != null) { 3392 return policy; 3393 } 3394 3395 Container rootAncestor = getFocusCycleRootAncestor(); 3396 if (rootAncestor != null) { 3397 return rootAncestor.getFocusTraversalPolicy(); 3398 } else { 3399 return KeyboardFocusManager.getCurrentKeyboardFocusManager(). 3400 getDefaultFocusTraversalPolicy(); 3401 } 3402 } 3403 3404 /** 3405 * Returns whether the focus traversal policy has been explicitly set for 3406 * this Container. If this method returns <code>false</code>, this 3407 * Container will inherit its focus traversal policy from an ancestor. 3408 * 3409 * @return <code>true</code> if the focus traversal policy has been 3410 * explicitly set for this Container; <code>false</code> otherwise. 3411 * @since 1.4 3412 */ 3413 public boolean isFocusTraversalPolicySet() { 3414 return (focusTraversalPolicy != null); 3415 } 3416 3417 /** 3418 * Sets whether this Container is the root of a focus traversal cycle. Once 3419 * focus enters a traversal cycle, typically it cannot leave it via focus 3420 * traversal unless one of the up- or down-cycle keys is pressed. Normal 3421 * traversal is limited to this Container, and all of this Container's 3422 * descendants that are not descendants of inferior focus cycle roots. Note 3423 * that a FocusTraversalPolicy may bend these restrictions, however. For 3424 * example, ContainerOrderFocusTraversalPolicy supports implicit down-cycle 3425 * traversal. 3426 * <p> 3427 * The alternative way to specify the traversal order of this Container's 3428 * children is to make this Container a 3429 * <a href="doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus traversal policy provider</a>. 3430 * 3431 * @param focusCycleRoot indicates whether this Container is the root of a 3432 * focus traversal cycle 3433 * @see #isFocusCycleRoot() 3434 * @see #setFocusTraversalPolicy 3435 * @see #getFocusTraversalPolicy 3436 * @see ContainerOrderFocusTraversalPolicy 3437 * @see #setFocusTraversalPolicyProvider 3438 * @since 1.4 3439 * @beaninfo 3440 * bound: true 3441 */ 3442 public void setFocusCycleRoot(boolean focusCycleRoot) { 3443 boolean oldFocusCycleRoot; 3444 synchronized (this) { 3445 oldFocusCycleRoot = this.focusCycleRoot; 3446 this.focusCycleRoot = focusCycleRoot; 3447 } 3448 firePropertyChange("focusCycleRoot", oldFocusCycleRoot, 3449 focusCycleRoot); 3450 } 3451 3452 /** 3453 * Returns whether this Container is the root of a focus traversal cycle. 3454 * Once focus enters a traversal cycle, typically it cannot leave it via 3455 * focus traversal unless one of the up- or down-cycle keys is pressed. 3456 * Normal traversal is limited to this Container, and all of this 3457 * Container's descendants that are not descendants of inferior focus 3458 * cycle roots. Note that a FocusTraversalPolicy may bend these 3459 * restrictions, however. For example, ContainerOrderFocusTraversalPolicy 3460 * supports implicit down-cycle traversal. 3461 * 3462 * @return whether this Container is the root of a focus traversal cycle 3463 * @see #setFocusCycleRoot 3464 * @see #setFocusTraversalPolicy 3465 * @see #getFocusTraversalPolicy 3466 * @see ContainerOrderFocusTraversalPolicy 3467 * @since 1.4 3468 */ 3469 public boolean isFocusCycleRoot() { 3470 return focusCycleRoot; 3471 } 3472 3473 /** 3474 * Sets whether this container will be used to provide focus 3475 * traversal policy. Container with this property as 3476 * <code>true</code> will be used to acquire focus traversal policy 3477 * instead of closest focus cycle root ancestor. 3478 * @param provider indicates whether this container will be used to 3479 * provide focus traversal policy 3480 * @see #setFocusTraversalPolicy 3481 * @see #getFocusTraversalPolicy 3482 * @see #isFocusTraversalPolicyProvider 3483 * @since 1.5 3484 * @beaninfo 3485 * bound: true 3486 */ 3487 public final void setFocusTraversalPolicyProvider(boolean provider) { 3488 boolean oldProvider; 3489 synchronized(this) { 3490 oldProvider = focusTraversalPolicyProvider; 3491 focusTraversalPolicyProvider = provider; 3492 } 3493 firePropertyChange("focusTraversalPolicyProvider", oldProvider, provider); 3494 } 3495 3496 /** 3497 * Returns whether this container provides focus traversal 3498 * policy. If this property is set to <code>true</code> then when 3499 * keyboard focus manager searches container hierarchy for focus 3500 * traversal policy and encounters this container before any other 3501 * container with this property as true or focus cycle roots then 3502 * its focus traversal policy will be used instead of focus cycle 3503 * root's policy. 3504 * @see #setFocusTraversalPolicy 3505 * @see #getFocusTraversalPolicy 3506 * @see #setFocusCycleRoot 3507 * @see #setFocusTraversalPolicyProvider 3508 * @return <code>true</code> if this container provides focus traversal 3509 * policy, <code>false</code> otherwise 3510 * @since 1.5 3511 * @beaninfo 3512 * bound: true 3513 */ 3514 public final boolean isFocusTraversalPolicyProvider() { 3515 return focusTraversalPolicyProvider; 3516 } 3517 3518 /** 3519 * Transfers the focus down one focus traversal cycle. If this Container is 3520 * a focus cycle root, then the focus owner is set to this Container's 3521 * default Component to focus, and the current focus cycle root is set to 3522 * this Container. If this Container is not a focus cycle root, then no 3523 * focus traversal operation occurs. 3524 * 3525 * @see Component#requestFocus() 3526 * @see #isFocusCycleRoot 3527 * @see #setFocusCycleRoot 3528 * @since 1.4 3529 */ 3530 public void transferFocusDownCycle() { 3531 if (isFocusCycleRoot()) { 3532 KeyboardFocusManager.getCurrentKeyboardFocusManager(). 3533 setGlobalCurrentFocusCycleRootPriv(this); 3534 Component toFocus = getFocusTraversalPolicy(). 3535 getDefaultComponent(this); 3536 if (toFocus != null) { 3537 toFocus.requestFocus(CausedFocusEvent.Cause.TRAVERSAL_DOWN); 3538 } 3539 } 3540 } 3541 3542 void preProcessKeyEvent(KeyEvent e) { 3543 Container parent = this.parent; 3544 if (parent != null) { 3545 parent.preProcessKeyEvent(e); 3546 } 3547 } 3548 3549 void postProcessKeyEvent(KeyEvent e) { 3550 Container parent = this.parent; 3551 if (parent != null) { 3552 parent.postProcessKeyEvent(e); 3553 } 3554 } 3555 3556 boolean postsOldMouseEvents() { 3557 return true; 3558 } 3559 3560 /** 3561 * Sets the <code>ComponentOrientation</code> property of this container 3562 * and all components contained within it. 3563 * <p> 3564 * This method changes layout-related information, and therefore, 3565 * invalidates the component hierarchy. 3566 * 3567 * @param o the new component orientation of this container and 3568 * the components contained within it. 3569 * @exception NullPointerException if <code>orientation</code> is null. 3570 * @see Component#setComponentOrientation 3571 * @see Component#getComponentOrientation 3572 * @see #invalidate 3573 * @since 1.4 3574 */ 3575 public void applyComponentOrientation(ComponentOrientation o) { 3576 super.applyComponentOrientation(o); 3577 synchronized (getTreeLock()) { 3578 for (int i = 0; i < component.size(); i++) { 3579 Component comp = component.get(i); 3580 comp.applyComponentOrientation(o); 3581 } 3582 } 3583 } 3584 3585 /** 3586 * Adds a PropertyChangeListener to the listener list. The listener is 3587 * registered for all bound properties of this class, including the 3588 * following: 3589 * <ul> 3590 * <li>this Container's font ("font")</li> 3591 * <li>this Container's background color ("background")</li> 3592 * <li>this Container's foreground color ("foreground")</li> 3593 * <li>this Container's focusability ("focusable")</li> 3594 * <li>this Container's focus traversal keys enabled state 3595 * ("focusTraversalKeysEnabled")</li> 3596 * <li>this Container's Set of FORWARD_TRAVERSAL_KEYS 3597 * ("forwardFocusTraversalKeys")</li> 3598 * <li>this Container's Set of BACKWARD_TRAVERSAL_KEYS 3599 * ("backwardFocusTraversalKeys")</li> 3600 * <li>this Container's Set of UP_CYCLE_TRAVERSAL_KEYS 3601 * ("upCycleFocusTraversalKeys")</li> 3602 * <li>this Container's Set of DOWN_CYCLE_TRAVERSAL_KEYS 3603 * ("downCycleFocusTraversalKeys")</li> 3604 * <li>this Container's focus traversal policy ("focusTraversalPolicy") 3605 * </li> 3606 * <li>this Container's focus-cycle-root state ("focusCycleRoot")</li> 3607 * </ul> 3608 * Note that if this Container is inheriting a bound property, then no 3609 * event will be fired in response to a change in the inherited property. 3610 * <p> 3611 * If listener is null, no exception is thrown and no action is performed. 3612 * 3613 * @param listener the PropertyChangeListener to be added 3614 * 3615 * @see Component#removePropertyChangeListener 3616 * @see #addPropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener) 3617 */ 3618 public void addPropertyChangeListener(PropertyChangeListener listener) { 3619 super.addPropertyChangeListener(listener); 3620 } 3621 3622 /** 3623 * Adds a PropertyChangeListener to the listener list for a specific 3624 * property. The specified property may be user-defined, or one of the 3625 * following defaults: 3626 * <ul> 3627 * <li>this Container's font ("font")</li> 3628 * <li>this Container's background color ("background")</li> 3629 * <li>this Container's foreground color ("foreground")</li> 3630 * <li>this Container's focusability ("focusable")</li> 3631 * <li>this Container's focus traversal keys enabled state 3632 * ("focusTraversalKeysEnabled")</li> 3633 * <li>this Container's Set of FORWARD_TRAVERSAL_KEYS 3634 * ("forwardFocusTraversalKeys")</li> 3635 * <li>this Container's Set of BACKWARD_TRAVERSAL_KEYS 3636 * ("backwardFocusTraversalKeys")</li> 3637 * <li>this Container's Set of UP_CYCLE_TRAVERSAL_KEYS 3638 * ("upCycleFocusTraversalKeys")</li> 3639 * <li>this Container's Set of DOWN_CYCLE_TRAVERSAL_KEYS 3640 * ("downCycleFocusTraversalKeys")</li> 3641 * <li>this Container's focus traversal policy ("focusTraversalPolicy") 3642 * </li> 3643 * <li>this Container's focus-cycle-root state ("focusCycleRoot")</li> 3644 * <li>this Container's focus-traversal-policy-provider state("focusTraversalPolicyProvider")</li> 3645 * <li>this Container's focus-traversal-policy-provider state("focusTraversalPolicyProvider")</li> 3646 * </ul> 3647 * Note that if this Container is inheriting a bound property, then no 3648 * event will be fired in response to a change in the inherited property. 3649 * <p> 3650 * If listener is null, no exception is thrown and no action is performed. 3651 * 3652 * @param propertyName one of the property names listed above 3653 * @param listener the PropertyChangeListener to be added 3654 * 3655 * @see #addPropertyChangeListener(java.beans.PropertyChangeListener) 3656 * @see Component#removePropertyChangeListener 3657 */ 3658 public void addPropertyChangeListener(String propertyName, 3659 PropertyChangeListener listener) { 3660 super.addPropertyChangeListener(propertyName, listener); 3661 } 3662 3663 // Serialization support. A Container is responsible for restoring the 3664 // parent fields of its component children. 3665 3666 /** 3667 * Container Serial Data Version. 3668 */ 3669 private int containerSerializedDataVersion = 1; 3670 3671 /** 3672 * Serializes this <code>Container</code> to the specified 3673 * <code>ObjectOutputStream</code>. 3674 * <ul> 3675 * <li>Writes default serializable fields to the stream.</li> 3676 * <li>Writes a list of serializable ContainerListener(s) as optional 3677 * data. The non-serializable ContainerListner(s) are detected and 3678 * no attempt is made to serialize them.</li> 3679 * <li>Write this Container's FocusTraversalPolicy if and only if it 3680 * is Serializable; otherwise, <code>null</code> is written.</li> 3681 * </ul> 3682 * 3683 * @param s the <code>ObjectOutputStream</code> to write 3684 * @serialData <code>null</code> terminated sequence of 0 or more pairs; 3685 * the pair consists of a <code>String</code> and <code>Object</code>; 3686 * the <code>String</code> indicates the type of object and 3687 * is one of the following: 3688 * <code>containerListenerK</code> indicating an 3689 * <code>ContainerListener</code> object; 3690 * the <code>Container</code>'s <code>FocusTraversalPolicy</code>, 3691 * or <code>null</code> 3692 * 3693 * @see AWTEventMulticaster#save(java.io.ObjectOutputStream, java.lang.String, java.util.EventListener) 3694 * @see Container#containerListenerK 3695 * @see #readObject(ObjectInputStream) 3696 */ 3697 private void writeObject(ObjectOutputStream s) throws IOException { 3698 ObjectOutputStream.PutField f = s.putFields(); 3699 f.put("ncomponents", component.size()); 3700 f.put("component", getComponentsSync()); 3701 f.put("layoutMgr", layoutMgr); 3702 f.put("dispatcher", dispatcher); 3703 f.put("maxSize", maxSize); 3704 f.put("focusCycleRoot", focusCycleRoot); 3705 f.put("containerSerializedDataVersion", containerSerializedDataVersion); 3706 f.put("focusTraversalPolicyProvider", focusTraversalPolicyProvider); 3707 s.writeFields(); 3708 3709 AWTEventMulticaster.save(s, containerListenerK, containerListener); 3710 s.writeObject(null); 3711 3712 if (focusTraversalPolicy instanceof java.io.Serializable) { 3713 s.writeObject(focusTraversalPolicy); 3714 } else { 3715 s.writeObject(null); 3716 } 3717 } 3718 3719 /** 3720 * Deserializes this <code>Container</code> from the specified 3721 * <code>ObjectInputStream</code>. 3722 * <ul> 3723 * <li>Reads default serializable fields from the stream.</li> 3724 * <li>Reads a list of serializable ContainerListener(s) as optional 3725 * data. If the list is null, no Listeners are installed.</li> 3726 * <li>Reads this Container's FocusTraversalPolicy, which may be null, 3727 * as optional data.</li> 3728 * </ul> 3729 * 3730 * @param s the <code>ObjectInputStream</code> to read 3731 * @serial 3732 * @see #addContainerListener 3733 * @see #writeObject(ObjectOutputStream) 3734 */ 3735 private void readObject(ObjectInputStream s) 3736 throws ClassNotFoundException, IOException 3737 { 3738 ObjectInputStream.GetField f = s.readFields(); 3739 Component [] tmpComponent = (Component[])f.get("component", EMPTY_ARRAY); 3740 int ncomponents = (Integer) f.get("ncomponents", 0); 3741 component = new java.util.ArrayList<Component>(ncomponents); 3742 for (int i = 0; i < ncomponents; ++i) { 3743 component.add(tmpComponent[i]); 3744 } 3745 layoutMgr = (LayoutManager)f.get("layoutMgr", null); 3746 dispatcher = (LightweightDispatcher)f.get("dispatcher", null); 3747 // Old stream. Doesn't contain maxSize among Component's fields. 3748 if (maxSize == null) { 3749 maxSize = (Dimension)f.get("maxSize", null); 3750 } 3751 focusCycleRoot = f.get("focusCycleRoot", false); 3752 containerSerializedDataVersion = f.get("containerSerializedDataVersion", 1); 3753 focusTraversalPolicyProvider = f.get("focusTraversalPolicyProvider", false); 3754 java.util.List<Component> component = this.component; 3755 for(Component comp : component) { 3756 comp.parent = this; 3757 adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK, 3758 comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK)); 3759 adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 3760 comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)); 3761 adjustDescendants(comp.countHierarchyMembers()); 3762 } 3763 3764 Object keyOrNull; 3765 while(null != (keyOrNull = s.readObject())) { 3766 String key = ((String)keyOrNull).intern(); 3767 3768 if (containerListenerK == key) { 3769 addContainerListener((ContainerListener)(s.readObject())); 3770 } else { 3771 // skip value for unrecognized key 3772 s.readObject(); 3773 } 3774 } 3775 3776 try { 3777 Object policy = s.readObject(); 3778 if (policy instanceof FocusTraversalPolicy) { 3779 focusTraversalPolicy = (FocusTraversalPolicy)policy; 3780 } 3781 } catch (java.io.OptionalDataException e) { 3782 // JDK 1.1/1.2/1.3 instances will not have this optional data. 3783 // e.eof will be true to indicate that there is no more data 3784 // available for this object. If e.eof is not true, throw the 3785 // exception as it might have been caused by reasons unrelated to 3786 // focusTraversalPolicy. 3787 3788 if (!e.eof) { 3789 throw e; 3790 } 3791 } 3792 } 3793 3794 /* 3795 * --- Accessibility Support --- 3796 */ 3797 3798 /** 3799 * Inner class of Container used to provide default support for 3800 * accessibility. This class is not meant to be used directly by 3801 * application developers, but is instead meant only to be 3802 * subclassed by container developers. 3803 * <p> 3804 * The class used to obtain the accessible role for this object, 3805 * as well as implementing many of the methods in the 3806 * AccessibleContainer interface. 3807 * @since 1.3 3808 */ 3809 protected class AccessibleAWTContainer extends AccessibleAWTComponent { 3810 3811 /** 3812 * JDK1.3 serialVersionUID 3813 */ 3814 private static final long serialVersionUID = 5081320404842566097L; 3815 3816 /** 3817 * Returns the number of accessible children in the object. If all 3818 * of the children of this object implement <code>Accessible</code>, 3819 * then this method should return the number of children of this object. 3820 * 3821 * @return the number of accessible children in the object 3822 */ 3823 public int getAccessibleChildrenCount() { 3824 return Container.this.getAccessibleChildrenCount(); 3825 } 3826 3827 /** 3828 * Returns the nth <code>Accessible</code> child of the object. 3829 * 3830 * @param i zero-based index of child 3831 * @return the nth <code>Accessible</code> child of the object 3832 */ 3833 public Accessible getAccessibleChild(int i) { 3834 return Container.this.getAccessibleChild(i); 3835 } 3836 3837 /** 3838 * Returns the <code>Accessible</code> child, if one exists, 3839 * contained at the local coordinate <code>Point</code>. 3840 * 3841 * @param p the point defining the top-left corner of the 3842 * <code>Accessible</code>, given in the coordinate space 3843 * of the object's parent 3844 * @return the <code>Accessible</code>, if it exists, 3845 * at the specified location; else <code>null</code> 3846 */ 3847 public Accessible getAccessibleAt(Point p) { 3848 return Container.this.getAccessibleAt(p); 3849 } 3850 3851 /** 3852 * Number of PropertyChangeListener objects registered. It's used 3853 * to add/remove ContainerListener to track target Container's state. 3854 */ 3855 private volatile transient int propertyListenersCount = 0; 3856 3857 protected ContainerListener accessibleContainerHandler = null; 3858 3859 /** 3860 * Fire <code>PropertyChange</code> listener, if one is registered, 3861 * when children are added or removed. 3862 * @since 1.3 3863 */ 3864 protected class AccessibleContainerHandler 3865 implements ContainerListener { 3866 public void componentAdded(ContainerEvent e) { 3867 Component c = e.getChild(); 3868 if (c != null && c instanceof Accessible) { 3869 AccessibleAWTContainer.this.firePropertyChange( 3870 AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, 3871 null, ((Accessible) c).getAccessibleContext()); 3872 } 3873 } 3874 public void componentRemoved(ContainerEvent e) { 3875 Component c = e.getChild(); 3876 if (c != null && c instanceof Accessible) { 3877 AccessibleAWTContainer.this.firePropertyChange( 3878 AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, 3879 ((Accessible) c).getAccessibleContext(), null); 3880 } 3881 } 3882 } 3883 3884 /** 3885 * Adds a PropertyChangeListener to the listener list. 3886 * 3887 * @param listener the PropertyChangeListener to be added 3888 */ 3889 public void addPropertyChangeListener(PropertyChangeListener listener) { 3890 if (accessibleContainerHandler == null) { 3891 accessibleContainerHandler = new AccessibleContainerHandler(); 3892 } 3893 if (propertyListenersCount++ == 0) { 3894 Container.this.addContainerListener(accessibleContainerHandler); 3895 } 3896 super.addPropertyChangeListener(listener); 3897 } 3898 3899 /** 3900 * Remove a PropertyChangeListener from the listener list. 3901 * This removes a PropertyChangeListener that was registered 3902 * for all properties. 3903 * 3904 * @param listener the PropertyChangeListener to be removed 3905 */ 3906 public void removePropertyChangeListener(PropertyChangeListener listener) { 3907 if (--propertyListenersCount == 0) { 3908 Container.this.removeContainerListener(accessibleContainerHandler); 3909 } 3910 super.removePropertyChangeListener(listener); 3911 } 3912 3913 } // inner class AccessibleAWTContainer 3914 3915 /** 3916 * Returns the <code>Accessible</code> child contained at the local 3917 * coordinate <code>Point</code>, if one exists. Otherwise 3918 * returns <code>null</code>. 3919 * 3920 * @param p the point defining the top-left corner of the 3921 * <code>Accessible</code>, given in the coordinate space 3922 * of the object's parent 3923 * @return the <code>Accessible</code> at the specified location, 3924 * if it exists; otherwise <code>null</code> 3925 */ 3926 Accessible getAccessibleAt(Point p) { 3927 synchronized (getTreeLock()) { 3928 if (this instanceof Accessible) { 3929 Accessible a = (Accessible)this; 3930 AccessibleContext ac = a.getAccessibleContext(); 3931 if (ac != null) { 3932 AccessibleComponent acmp; 3933 Point location; 3934 int nchildren = ac.getAccessibleChildrenCount(); 3935 for (int i=0; i < nchildren; i++) { 3936 a = ac.getAccessibleChild(i); 3937 if ((a != null)) { 3938 ac = a.getAccessibleContext(); 3939 if (ac != null) { 3940 acmp = ac.getAccessibleComponent(); 3941 if ((acmp != null) && (acmp.isShowing())) { 3942 location = acmp.getLocation(); 3943 Point np = new Point(p.x-location.x, 3944 p.y-location.y); 3945 if (acmp.contains(np)){ 3946 return a; 3947 } 3948 } 3949 } 3950 } 3951 } 3952 } 3953 return (Accessible)this; 3954 } else { 3955 Component ret = this; 3956 if (!this.contains(p.x,p.y)) { 3957 ret = null; 3958 } else { 3959 int ncomponents = this.getComponentCount(); 3960 for (int i=0; i < ncomponents; i++) { 3961 Component comp = this.getComponent(i); 3962 if ((comp != null) && comp.isShowing()) { 3963 Point location = comp.getLocation(); 3964 if (comp.contains(p.x-location.x,p.y-location.y)) { 3965 ret = comp; 3966 } 3967 } 3968 } 3969 } 3970 if (ret instanceof Accessible) { 3971 return (Accessible) ret; 3972 } 3973 } 3974 return null; 3975 } 3976 } 3977 3978 /** 3979 * Returns the number of accessible children in the object. If all 3980 * of the children of this object implement <code>Accessible</code>, 3981 * then this method should return the number of children of this object. 3982 * 3983 * @return the number of accessible children in the object 3984 */ 3985 int getAccessibleChildrenCount() { 3986 synchronized (getTreeLock()) { 3987 int count = 0; 3988 Component[] children = this.getComponents(); 3989 for (int i = 0; i < children.length; i++) { 3990 if (children[i] instanceof Accessible) { 3991 count++; 3992 } 3993 } 3994 return count; 3995 } 3996 } 3997 3998 /** 3999 * Returns the nth <code>Accessible</code> child of the object. 4000 * 4001 * @param i zero-based index of child 4002 * @return the nth <code>Accessible</code> child of the object 4003 */ 4004 Accessible getAccessibleChild(int i) { 4005 synchronized (getTreeLock()) { 4006 Component[] children = this.getComponents(); 4007 int count = 0; 4008 for (int j = 0; j < children.length; j++) { 4009 if (children[j] instanceof Accessible) { 4010 if (count == i) { 4011 return (Accessible) children[j]; 4012 } else { 4013 count++; 4014 } 4015 } 4016 } 4017 return null; 4018 } 4019 } 4020 4021 // ************************** MIXING CODE ******************************* 4022 4023 final void increaseComponentCount(Component c) { 4024 synchronized (getTreeLock()) { 4025 if (!c.isDisplayable()) { 4026 throw new IllegalStateException( 4027 "Peer does not exist while invoking the increaseComponentCount() method" 4028 ); 4029 } 4030 4031 int addHW = 0; 4032 int addLW = 0; 4033 4034 if (c instanceof Container) { 4035 addLW = ((Container)c).numOfLWComponents; 4036 addHW = ((Container)c).numOfHWComponents; 4037 } 4038 if (c.isLightweight()) { 4039 addLW++; 4040 } else { 4041 addHW++; 4042 } 4043 4044 for (Container cont = this; cont != null; cont = cont.getContainer()) { 4045 cont.numOfLWComponents += addLW; 4046 cont.numOfHWComponents += addHW; 4047 } 4048 } 4049 } 4050 4051 final void decreaseComponentCount(Component c) { 4052 synchronized (getTreeLock()) { 4053 if (!c.isDisplayable()) { 4054 throw new IllegalStateException( 4055 "Peer does not exist while invoking the decreaseComponentCount() method" 4056 ); 4057 } 4058 4059 int subHW = 0; 4060 int subLW = 0; 4061 4062 if (c instanceof Container) { 4063 subLW = ((Container)c).numOfLWComponents; 4064 subHW = ((Container)c).numOfHWComponents; 4065 } 4066 if (c.isLightweight()) { 4067 subLW++; 4068 } else { 4069 subHW++; 4070 } 4071 4072 for (Container cont = this; cont != null; cont = cont.getContainer()) { 4073 cont.numOfLWComponents -= subLW; 4074 cont.numOfHWComponents -= subHW; 4075 } 4076 } 4077 } 4078 4079 private int getTopmostComponentIndex() { 4080 checkTreeLock(); 4081 if (getComponentCount() > 0) { 4082 return 0; 4083 } 4084 return -1; 4085 } 4086 4087 private int getBottommostComponentIndex() { 4088 checkTreeLock(); 4089 if (getComponentCount() > 0) { 4090 return getComponentCount() - 1; 4091 } 4092 return -1; 4093 } 4094 4095 /* 4096 * This method is overriden to handle opaque children in non-opaque 4097 * containers. 4098 */ 4099 @Override 4100 final Region getOpaqueShape() { 4101 checkTreeLock(); 4102 if (isLightweight() && isNonOpaqueForMixing() 4103 && hasLightweightDescendants()) 4104 { 4105 Region s = Region.EMPTY_REGION; 4106 for (int index = 0; index < getComponentCount(); index++) { 4107 Component c = getComponent(index); 4108 if (c.isLightweight() && c.isShowing()) { 4109 s = s.getUnion(c.getOpaqueShape()); 4110 } 4111 } 4112 return s.getIntersection(getNormalShape()); 4113 } 4114 return super.getOpaqueShape(); 4115 } 4116 4117 final void recursiveSubtractAndApplyShape(Region shape) { 4118 recursiveSubtractAndApplyShape(shape, getTopmostComponentIndex(), getBottommostComponentIndex()); 4119 } 4120 4121 final void recursiveSubtractAndApplyShape(Region shape, int fromZorder) { 4122 recursiveSubtractAndApplyShape(shape, fromZorder, getBottommostComponentIndex()); 4123 } 4124 4125 final void recursiveSubtractAndApplyShape(Region shape, int fromZorder, int toZorder) { 4126 checkTreeLock(); 4127 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4128 mixingLog.fine("this = " + this + 4129 "; shape=" + shape + "; fromZ=" + fromZorder + "; toZ=" + toZorder); 4130 } 4131 if (fromZorder == -1) { 4132 return; 4133 } 4134 if (shape.isEmpty()) { 4135 return; 4136 } 4137 // An invalid container with not-null layout should be ignored 4138 // by the mixing code, the container will be validated later 4139 // and the mixing code will be executed later. 4140 if (getLayout() != null && !isValid()) { 4141 return; 4142 } 4143 for (int index = fromZorder; index <= toZorder; index++) { 4144 Component comp = getComponent(index); 4145 if (!comp.isLightweight()) { 4146 comp.subtractAndApplyShape(shape); 4147 } else if (comp instanceof Container && 4148 ((Container)comp).hasHeavyweightDescendants() && comp.isShowing()) { 4149 ((Container)comp).recursiveSubtractAndApplyShape(shape); 4150 } 4151 } 4152 } 4153 4154 final void recursiveApplyCurrentShape() { 4155 recursiveApplyCurrentShape(getTopmostComponentIndex(), getBottommostComponentIndex()); 4156 } 4157 4158 final void recursiveApplyCurrentShape(int fromZorder) { 4159 recursiveApplyCurrentShape(fromZorder, getBottommostComponentIndex()); 4160 } 4161 4162 final void recursiveApplyCurrentShape(int fromZorder, int toZorder) { 4163 checkTreeLock(); 4164 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4165 mixingLog.fine("this = " + this + 4166 "; fromZ=" + fromZorder + "; toZ=" + toZorder); 4167 } 4168 if (fromZorder == -1) { 4169 return; 4170 } 4171 // An invalid container with not-null layout should be ignored 4172 // by the mixing code, the container will be validated later 4173 // and the mixing code will be executed later. 4174 if (getLayout() != null && !isValid()) { 4175 return; 4176 } 4177 for (int index = fromZorder; index <= toZorder; index++) { 4178 Component comp = getComponent(index); 4179 if (!comp.isLightweight()) { 4180 comp.applyCurrentShape(); 4181 } 4182 if (comp instanceof Container && 4183 ((Container)comp).hasHeavyweightDescendants()) { 4184 ((Container)comp).recursiveApplyCurrentShape(); 4185 } 4186 } 4187 } 4188 4189 private void recursiveShowHeavyweightChildren() { 4190 if (!hasHeavyweightDescendants() || !isVisible()) { 4191 return; 4192 } 4193 for (int index = 0; index < getComponentCount(); index++) { 4194 Component comp = getComponent(index); 4195 if (comp.isLightweight()) { 4196 if (comp instanceof Container) { 4197 ((Container)comp).recursiveShowHeavyweightChildren(); 4198 } 4199 } else { 4200 if (comp.isVisible()) { 4201 ComponentPeer peer = comp.getPeer(); 4202 if (peer != null) { 4203 peer.setVisible(true); 4204 } 4205 } 4206 } 4207 } 4208 } 4209 4210 private void recursiveHideHeavyweightChildren() { 4211 if (!hasHeavyweightDescendants()) { 4212 return; 4213 } 4214 for (int index = 0; index < getComponentCount(); index++) { 4215 Component comp = getComponent(index); 4216 if (comp.isLightweight()) { 4217 if (comp instanceof Container) { 4218 ((Container)comp).recursiveHideHeavyweightChildren(); 4219 } 4220 } else { 4221 if (comp.isVisible()) { 4222 ComponentPeer peer = comp.getPeer(); 4223 if (peer != null) { 4224 peer.setVisible(false); 4225 } 4226 } 4227 } 4228 } 4229 } 4230 4231 private void recursiveRelocateHeavyweightChildren(Point origin) { 4232 for (int index = 0; index < getComponentCount(); index++) { 4233 Component comp = getComponent(index); 4234 if (comp.isLightweight()) { 4235 if (comp instanceof Container && 4236 ((Container)comp).hasHeavyweightDescendants()) 4237 { 4238 final Point newOrigin = new Point(origin); 4239 newOrigin.translate(comp.getX(), comp.getY()); 4240 ((Container)comp).recursiveRelocateHeavyweightChildren(newOrigin); 4241 } 4242 } else { 4243 ComponentPeer peer = comp.getPeer(); 4244 if (peer != null) { 4245 peer.setBounds(origin.x + comp.getX(), origin.y + comp.getY(), 4246 comp.getWidth(), comp.getHeight(), 4247 ComponentPeer.SET_LOCATION); 4248 } 4249 } 4250 } 4251 } 4252 4253 /** 4254 * Checks if the container and its direct lightweight containers are 4255 * visible. 4256 * 4257 * Consider the heavyweight container hides or shows the HW descendants 4258 * automatically. Therefore we care of LW containers' visibility only. 4259 * 4260 * This method MUST be invoked under the TreeLock. 4261 */ 4262 final boolean isRecursivelyVisibleUpToHeavyweightContainer() { 4263 if (!isLightweight()) { 4264 return true; 4265 } 4266 4267 for (Container cont = this; 4268 cont != null && cont.isLightweight(); 4269 cont = cont.getContainer()) 4270 { 4271 if (!cont.isVisible()) { 4272 return false; 4273 } 4274 } 4275 return true; 4276 } 4277 4278 @Override 4279 void mixOnShowing() { 4280 synchronized (getTreeLock()) { 4281 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4282 mixingLog.fine("this = " + this); 4283 } 4284 4285 boolean isLightweight = isLightweight(); 4286 4287 if (isLightweight && isRecursivelyVisibleUpToHeavyweightContainer()) { 4288 recursiveShowHeavyweightChildren(); 4289 } 4290 4291 if (!isMixingNeeded()) { 4292 return; 4293 } 4294 4295 if (!isLightweight || (isLightweight && hasHeavyweightDescendants())) { 4296 recursiveApplyCurrentShape(); 4297 } 4298 4299 super.mixOnShowing(); 4300 } 4301 } 4302 4303 @Override 4304 void mixOnHiding(boolean isLightweight) { 4305 synchronized (getTreeLock()) { 4306 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4307 mixingLog.fine("this = " + this + 4308 "; isLightweight=" + isLightweight); 4309 } 4310 if (isLightweight) { 4311 recursiveHideHeavyweightChildren(); 4312 } 4313 super.mixOnHiding(isLightweight); 4314 } 4315 } 4316 4317 @Override 4318 void mixOnReshaping() { 4319 synchronized (getTreeLock()) { 4320 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4321 mixingLog.fine("this = " + this); 4322 } 4323 4324 boolean isMixingNeeded = isMixingNeeded(); 4325 4326 if (isLightweight() && hasHeavyweightDescendants()) { 4327 final Point origin = new Point(getX(), getY()); 4328 for (Container cont = getContainer(); 4329 cont != null && cont.isLightweight(); 4330 cont = cont.getContainer()) 4331 { 4332 origin.translate(cont.getX(), cont.getY()); 4333 } 4334 4335 recursiveRelocateHeavyweightChildren(origin); 4336 4337 if (!isMixingNeeded) { 4338 return; 4339 } 4340 4341 recursiveApplyCurrentShape(); 4342 } 4343 4344 if (!isMixingNeeded) { 4345 return; 4346 } 4347 4348 super.mixOnReshaping(); 4349 } 4350 } 4351 4352 @Override 4353 void mixOnZOrderChanging(int oldZorder, int newZorder) { 4354 synchronized (getTreeLock()) { 4355 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4356 mixingLog.fine("this = " + this + 4357 "; oldZ=" + oldZorder + "; newZ=" + newZorder); 4358 } 4359 4360 if (!isMixingNeeded()) { 4361 return; 4362 } 4363 4364 boolean becameHigher = newZorder < oldZorder; 4365 4366 if (becameHigher && isLightweight() && hasHeavyweightDescendants()) { 4367 recursiveApplyCurrentShape(); 4368 } 4369 super.mixOnZOrderChanging(oldZorder, newZorder); 4370 } 4371 } 4372 4373 @Override 4374 void mixOnValidating() { 4375 synchronized (getTreeLock()) { 4376 if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { 4377 mixingLog.fine("this = " + this); 4378 } 4379 4380 if (!isMixingNeeded()) { 4381 return; 4382 } 4383 4384 if (hasHeavyweightDescendants()) { 4385 recursiveApplyCurrentShape(); 4386 } 4387 4388 if (isLightweight() && isNonOpaqueForMixing()) { 4389 subtractAndApplyShapeBelowMe(); 4390 } 4391 4392 super.mixOnValidating(); 4393 } 4394 } 4395 4396 // ****************** END OF MIXING CODE ******************************** 4397 } 4398 4399 4400 /** 4401 * Class to manage the dispatching of MouseEvents to the lightweight descendants 4402 * and SunDropTargetEvents to both lightweight and heavyweight descendants 4403 * contained by a native container. 4404 * 4405 * NOTE: the class name is not appropriate anymore, but we cannot change it 4406 * because we must keep serialization compatibility. 4407 * 4408 * @author Timothy Prinzing 4409 */ 4410 class LightweightDispatcher implements java.io.Serializable, AWTEventListener { 4411 4412 /* 4413 * JDK 1.1 serialVersionUID 4414 */ 4415 private static final long serialVersionUID = 5184291520170872969L; 4416 /* 4417 * Our own mouse event for when we're dragged over from another hw 4418 * container 4419 */ 4420 private static final int LWD_MOUSE_DRAGGED_OVER = 1500; 4421 4422 private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.LightweightDispatcher"); 4423 4424 LightweightDispatcher(Container nativeContainer) { 4425 this.nativeContainer = nativeContainer; 4426 mouseEventTarget = null; 4427 eventMask = 0; 4428 } 4429 4430 /* 4431 * Clean up any resources allocated when dispatcher was created; 4432 * should be called from Container.removeNotify 4433 */ 4434 void dispose() { 4435 //System.out.println("Disposing lw dispatcher"); 4436 stopListeningForOtherDrags(); 4437 mouseEventTarget = null; 4438 targetLastEntered = null; 4439 targetLastEnteredDT = null; 4440 } 4441 4442 /** 4443 * Enables events to subcomponents. 4444 */ 4445 void enableEvents(long events) { 4446 eventMask |= events; 4447 } 4448 4449 /** 4450 * Dispatches an event to a sub-component if necessary, and 4451 * returns whether or not the event was forwarded to a 4452 * sub-component. 4453 * 4454 * @param e the event 4455 */ 4456 boolean dispatchEvent(AWTEvent e) { 4457 boolean ret = false; 4458 4459 /* 4460 * Fix for BugTraq Id 4389284. 4461 * Dispatch SunDropTargetEvents regardless of eventMask value. 4462 * Do not update cursor on dispatching SunDropTargetEvents. 4463 */ 4464 if (e instanceof SunDropTargetEvent) { 4465 4466 SunDropTargetEvent sdde = (SunDropTargetEvent) e; 4467 ret = processDropTargetEvent(sdde); 4468 4469 } else { 4470 if (e instanceof MouseEvent && (eventMask & MOUSE_MASK) != 0) { 4471 MouseEvent me = (MouseEvent) e; 4472 ret = processMouseEvent(me); 4473 } 4474 4475 if (e.getID() == MouseEvent.MOUSE_MOVED) { 4476 nativeContainer.updateCursorImmediately(); 4477 } 4478 } 4479 4480 return ret; 4481 } 4482 4483 /* This method effectively returns whether or not a mouse button was down 4484 * just BEFORE the event happened. A better method name might be 4485 * wasAMouseButtonDownBeforeThisEvent(). 4486 */ 4487 private boolean isMouseGrab(MouseEvent e) { 4488 int modifiers = e.getModifiersEx(); 4489 4490 if(e.getID() == MouseEvent.MOUSE_PRESSED 4491 || e.getID() == MouseEvent.MOUSE_RELEASED) 4492 { 4493 switch (e.getButton()) { 4494 case MouseEvent.BUTTON1: 4495 modifiers ^= InputEvent.BUTTON1_DOWN_MASK; 4496 break; 4497 case MouseEvent.BUTTON2: 4498 modifiers ^= InputEvent.BUTTON2_DOWN_MASK; 4499 break; 4500 case MouseEvent.BUTTON3: 4501 modifiers ^= InputEvent.BUTTON3_DOWN_MASK; 4502 break; 4503 } 4504 } 4505 /* modifiers now as just before event */ 4506 return ((modifiers & (InputEvent.BUTTON1_DOWN_MASK 4507 | InputEvent.BUTTON2_DOWN_MASK 4508 | InputEvent.BUTTON3_DOWN_MASK)) != 0); 4509 } 4510 4511 /** 4512 * This method attempts to distribute a mouse event to a lightweight 4513 * component. It tries to avoid doing any unnecessary probes down 4514 * into the component tree to minimize the overhead of determining 4515 * where to route the event, since mouse movement events tend to 4516 * come in large and frequent amounts. 4517 */ 4518 private boolean processMouseEvent(MouseEvent e) { 4519 int id = e.getID(); 4520 Component mouseOver = // sensitive to mouse events 4521 nativeContainer.getMouseEventTarget(e.getX(), e.getY(), 4522 Container.INCLUDE_SELF); 4523 4524 trackMouseEnterExit(mouseOver, e); 4525 4526 // 4508327 : MOUSE_CLICKED should only go to the recipient of 4527 // the accompanying MOUSE_PRESSED, so don't reset mouseEventTarget on a 4528 // MOUSE_CLICKED. 4529 if (!isMouseGrab(e) && id != MouseEvent.MOUSE_CLICKED) { 4530 mouseEventTarget = (mouseOver != nativeContainer) ? mouseOver: null; 4531 isCleaned = false; 4532 } 4533 4534 if (mouseEventTarget != null) { 4535 switch (id) { 4536 case MouseEvent.MOUSE_ENTERED: 4537 case MouseEvent.MOUSE_EXITED: 4538 break; 4539 case MouseEvent.MOUSE_PRESSED: 4540 retargetMouseEvent(mouseEventTarget, id, e); 4541 break; 4542 case MouseEvent.MOUSE_RELEASED: 4543 retargetMouseEvent(mouseEventTarget, id, e); 4544 break; 4545 case MouseEvent.MOUSE_CLICKED: 4546 // 4508327: MOUSE_CLICKED should never be dispatched to a Component 4547 // other than that which received the MOUSE_PRESSED event. If the 4548 // mouse is now over a different Component, don't dispatch the event. 4549 // The previous fix for a similar problem was associated with bug 4550 // 4155217. 4551 if (mouseOver == mouseEventTarget) { 4552 retargetMouseEvent(mouseOver, id, e); 4553 } 4554 break; 4555 case MouseEvent.MOUSE_MOVED: 4556 retargetMouseEvent(mouseEventTarget, id, e); 4557 break; 4558 case MouseEvent.MOUSE_DRAGGED: 4559 if (isMouseGrab(e)) { 4560 retargetMouseEvent(mouseEventTarget, id, e); 4561 } 4562 break; 4563 case MouseEvent.MOUSE_WHEEL: 4564 // This may send it somewhere that doesn't have MouseWheelEvents 4565 // enabled. In this case, Component.dispatchEventImpl() will 4566 // retarget the event to a parent that DOES have the events enabled. 4567 if (eventLog.isLoggable(PlatformLogger.Level.FINEST) && (mouseOver != null)) { 4568 eventLog.finest("retargeting mouse wheel to " + 4569 mouseOver.getName() + ", " + 4570 mouseOver.getClass()); 4571 } 4572 retargetMouseEvent(mouseOver, id, e); 4573 break; 4574 } 4575 //Consuming of wheel events is implemented in "retargetMouseEvent". 4576 if (id != MouseEvent.MOUSE_WHEEL) { 4577 e.consume(); 4578 } 4579 } else if (isCleaned && id != MouseEvent.MOUSE_WHEEL) { 4580 //After mouseEventTarget was removed and cleaned should consume all events 4581 //until new mouseEventTarget is found 4582 e.consume(); 4583 } 4584 return e.isConsumed(); 4585 } 4586 4587 private boolean processDropTargetEvent(SunDropTargetEvent e) { 4588 int id = e.getID(); 4589 int x = e.getX(); 4590 int y = e.getY(); 4591 4592 /* 4593 * Fix for BugTraq ID 4395290. 4594 * It is possible that SunDropTargetEvent's Point is outside of the 4595 * native container bounds. In this case we truncate coordinates. 4596 */ 4597 if (!nativeContainer.contains(x, y)) { 4598 final Dimension d = nativeContainer.getSize(); 4599 if (d.width <= x) { 4600 x = d.width - 1; 4601 } else if (x < 0) { 4602 x = 0; 4603 } 4604 if (d.height <= y) { 4605 y = d.height - 1; 4606 } else if (y < 0) { 4607 y = 0; 4608 } 4609 } 4610 Component mouseOver = // not necessarily sensitive to mouse events 4611 nativeContainer.getDropTargetEventTarget(x, y, 4612 Container.INCLUDE_SELF); 4613 trackMouseEnterExit(mouseOver, e); 4614 4615 if (mouseOver != nativeContainer && mouseOver != null) { 4616 switch (id) { 4617 case SunDropTargetEvent.MOUSE_ENTERED: 4618 case SunDropTargetEvent.MOUSE_EXITED: 4619 break; 4620 default: 4621 retargetMouseEvent(mouseOver, id, e); 4622 e.consume(); 4623 break; 4624 } 4625 } 4626 return e.isConsumed(); 4627 } 4628 4629 /* 4630 * Generates dnd enter/exit events as mouse moves over lw components 4631 * @param targetOver Target mouse is over (including native container) 4632 * @param e SunDropTarget mouse event in native container 4633 */ 4634 private void trackDropTargetEnterExit(Component targetOver, MouseEvent e) { 4635 int id = e.getID(); 4636 if (id == MouseEvent.MOUSE_ENTERED && isMouseDTInNativeContainer) { 4637 // This can happen if a lightweight component which initiated the 4638 // drag has an associated drop target. MOUSE_ENTERED comes when the 4639 // mouse is in the native container already. To propagate this event 4640 // properly we should null out targetLastEntered. 4641 targetLastEnteredDT = null; 4642 } else if (id == MouseEvent.MOUSE_ENTERED) { 4643 isMouseDTInNativeContainer = true; 4644 } else if (id == MouseEvent.MOUSE_EXITED) { 4645 isMouseDTInNativeContainer = false; 4646 } 4647 targetLastEnteredDT = retargetMouseEnterExit(targetOver, e, 4648 targetLastEnteredDT, 4649 isMouseDTInNativeContainer); 4650 } 4651 4652 /* 4653 * Generates enter/exit events as mouse moves over lw components 4654 * @param targetOver Target mouse is over (including native container) 4655 * @param e Mouse event in native container 4656 */ 4657 private void trackMouseEnterExit(Component targetOver, MouseEvent e) { 4658 if (e instanceof SunDropTargetEvent) { 4659 trackDropTargetEnterExit(targetOver, e); 4660 return; 4661 } 4662 int id = e.getID(); 4663 4664 if ( id != MouseEvent.MOUSE_EXITED && 4665 id != MouseEvent.MOUSE_DRAGGED && 4666 id != LWD_MOUSE_DRAGGED_OVER && 4667 !isMouseInNativeContainer) { 4668 // any event but an exit or drag means we're in the native container 4669 isMouseInNativeContainer = true; 4670 startListeningForOtherDrags(); 4671 } else if (id == MouseEvent.MOUSE_EXITED) { 4672 isMouseInNativeContainer = false; 4673 stopListeningForOtherDrags(); 4674 } 4675 targetLastEntered = retargetMouseEnterExit(targetOver, e, 4676 targetLastEntered, 4677 isMouseInNativeContainer); 4678 } 4679 4680 private Component retargetMouseEnterExit(Component targetOver, MouseEvent e, 4681 Component lastEntered, 4682 boolean inNativeContainer) { 4683 int id = e.getID(); 4684 Component targetEnter = inNativeContainer ? targetOver : null; 4685 4686 if (lastEntered != targetEnter) { 4687 if (lastEntered != null) { 4688 retargetMouseEvent(lastEntered, MouseEvent.MOUSE_EXITED, e); 4689 } 4690 if (id == MouseEvent.MOUSE_EXITED) { 4691 // consume native exit event if we generate one 4692 e.consume(); 4693 } 4694 4695 if (targetEnter != null) { 4696 retargetMouseEvent(targetEnter, MouseEvent.MOUSE_ENTERED, e); 4697 } 4698 if (id == MouseEvent.MOUSE_ENTERED) { 4699 // consume native enter event if we generate one 4700 e.consume(); 4701 } 4702 } 4703 return targetEnter; 4704 } 4705 4706 /* 4707 * Listens to global mouse drag events so even drags originating 4708 * from other heavyweight containers will generate enter/exit 4709 * events in this container 4710 */ 4711 private void startListeningForOtherDrags() { 4712 //System.out.println("Adding AWTEventListener"); 4713 java.security.AccessController.doPrivileged( 4714 new java.security.PrivilegedAction<Object>() { 4715 public Object run() { 4716 nativeContainer.getToolkit().addAWTEventListener( 4717 LightweightDispatcher.this, 4718 AWTEvent.MOUSE_EVENT_MASK | 4719 AWTEvent.MOUSE_MOTION_EVENT_MASK); 4720 return null; 4721 } 4722 } 4723 ); 4724 } 4725 4726 private void stopListeningForOtherDrags() { 4727 //System.out.println("Removing AWTEventListener"); 4728 java.security.AccessController.doPrivileged( 4729 new java.security.PrivilegedAction<Object>() { 4730 public Object run() { 4731 nativeContainer.getToolkit().removeAWTEventListener(LightweightDispatcher.this); 4732 return null; 4733 } 4734 } 4735 ); 4736 } 4737 4738 /* 4739 * (Implementation of AWTEventListener) 4740 * Listen for drag events posted in other hw components so we can 4741 * track enter/exit regardless of where a drag originated 4742 */ 4743 public void eventDispatched(AWTEvent e) { 4744 boolean isForeignDrag = (e instanceof MouseEvent) && 4745 !(e instanceof SunDropTargetEvent) && 4746 (e.id == MouseEvent.MOUSE_DRAGGED) && 4747 (e.getSource() != nativeContainer); 4748 4749 if (!isForeignDrag) { 4750 // only interested in drags from other hw components 4751 return; 4752 } 4753 4754 MouseEvent srcEvent = (MouseEvent)e; 4755 MouseEvent me; 4756 4757 synchronized (nativeContainer.getTreeLock()) { 4758 Component srcComponent = srcEvent.getComponent(); 4759 4760 // component may have disappeared since drag event posted 4761 // (i.e. Swing hierarchical menus) 4762 if ( !srcComponent.isShowing() ) { 4763 return; 4764 } 4765 4766 // see 5083555 4767 // check if srcComponent is in any modal blocked window 4768 Component c = nativeContainer; 4769 while ((c != null) && !(c instanceof Window)) { 4770 c = c.getParent_NoClientCode(); 4771 } 4772 if ((c == null) || ((Window)c).isModalBlocked()) { 4773 return; 4774 } 4775 4776 // 4777 // create an internal 'dragged-over' event indicating 4778 // we are being dragged over from another hw component 4779 // 4780 me = new MouseEvent(nativeContainer, 4781 LWD_MOUSE_DRAGGED_OVER, 4782 srcEvent.getWhen(), 4783 srcEvent.getModifiersEx() | srcEvent.getModifiers(), 4784 srcEvent.getX(), 4785 srcEvent.getY(), 4786 srcEvent.getXOnScreen(), 4787 srcEvent.getYOnScreen(), 4788 srcEvent.getClickCount(), 4789 srcEvent.isPopupTrigger(), 4790 srcEvent.getButton()); 4791 ((AWTEvent)srcEvent).copyPrivateDataInto(me); 4792 // translate coordinates to this native container 4793 final Point ptSrcOrigin = srcComponent.getLocationOnScreen(); 4794 4795 if (AppContext.getAppContext() != nativeContainer.appContext) { 4796 final MouseEvent mouseEvent = me; 4797 Runnable r = new Runnable() { 4798 public void run() { 4799 if (!nativeContainer.isShowing() ) { 4800 return; 4801 } 4802 4803 Point ptDstOrigin = nativeContainer.getLocationOnScreen(); 4804 mouseEvent.translatePoint(ptSrcOrigin.x - ptDstOrigin.x, 4805 ptSrcOrigin.y - ptDstOrigin.y ); 4806 Component targetOver = 4807 nativeContainer.getMouseEventTarget(mouseEvent.getX(), 4808 mouseEvent.getY(), 4809 Container.INCLUDE_SELF); 4810 trackMouseEnterExit(targetOver, mouseEvent); 4811 } 4812 }; 4813 SunToolkit.executeOnEventHandlerThread(nativeContainer, r); 4814 return; 4815 } else { 4816 if (!nativeContainer.isShowing() ) { 4817 return; 4818 } 4819 4820 Point ptDstOrigin = nativeContainer.getLocationOnScreen(); 4821 me.translatePoint( ptSrcOrigin.x - ptDstOrigin.x, ptSrcOrigin.y - ptDstOrigin.y ); 4822 } 4823 } 4824 //System.out.println("Track event: " + me); 4825 // feed the 'dragged-over' event directly to the enter/exit 4826 // code (not a real event so don't pass it to dispatchEvent) 4827 Component targetOver = 4828 nativeContainer.getMouseEventTarget(me.getX(), me.getY(), 4829 Container.INCLUDE_SELF); 4830 trackMouseEnterExit(targetOver, me); 4831 } 4832 4833 /** 4834 * Sends a mouse event to the current mouse event recipient using 4835 * the given event (sent to the windowed host) as a srcEvent. If 4836 * the mouse event target is still in the component tree, the 4837 * coordinates of the event are translated to those of the target. 4838 * If the target has been removed, we don't bother to send the 4839 * message. 4840 */ 4841 void retargetMouseEvent(Component target, int id, MouseEvent e) { 4842 if (target == null) { 4843 return; // mouse is over another hw component or target is disabled 4844 } 4845 4846 int x = e.getX(), y = e.getY(); 4847 Component component; 4848 4849 for(component = target; 4850 component != null && component != nativeContainer; 4851 component = component.getParent()) { 4852 x -= component.x; 4853 y -= component.y; 4854 } 4855 MouseEvent retargeted; 4856 if (component != null) { 4857 if (e instanceof SunDropTargetEvent) { 4858 retargeted = new SunDropTargetEvent(target, 4859 id, 4860 x, 4861 y, 4862 ((SunDropTargetEvent)e).getDispatcher()); 4863 } else if (id == MouseEvent.MOUSE_WHEEL) { 4864 retargeted = new MouseWheelEvent(target, 4865 id, 4866 e.getWhen(), 4867 e.getModifiersEx() | e.getModifiers(), 4868 x, 4869 y, 4870 e.getXOnScreen(), 4871 e.getYOnScreen(), 4872 e.getClickCount(), 4873 e.isPopupTrigger(), 4874 ((MouseWheelEvent)e).getScrollType(), 4875 ((MouseWheelEvent)e).getScrollAmount(), 4876 ((MouseWheelEvent)e).getWheelRotation(), 4877 ((MouseWheelEvent)e).getPreciseWheelRotation()); 4878 } 4879 else { 4880 retargeted = new MouseEvent(target, 4881 id, 4882 e.getWhen(), 4883 e.getModifiersEx() | e.getModifiers(), 4884 x, 4885 y, 4886 e.getXOnScreen(), 4887 e.getYOnScreen(), 4888 e.getClickCount(), 4889 e.isPopupTrigger(), 4890 e.getButton()); 4891 } 4892 4893 ((AWTEvent)e).copyPrivateDataInto(retargeted); 4894 4895 if (target == nativeContainer) { 4896 // avoid recursively calling LightweightDispatcher... 4897 ((Container)target).dispatchEventToSelf(retargeted); 4898 } else { 4899 assert AppContext.getAppContext() == target.appContext; 4900 4901 if (nativeContainer.modalComp != null) { 4902 if (((Container)nativeContainer.modalComp).isAncestorOf(target)) { 4903 target.dispatchEvent(retargeted); 4904 } else { 4905 e.consume(); 4906 } 4907 } else { 4908 target.dispatchEvent(retargeted); 4909 } 4910 } 4911 if (id == MouseEvent.MOUSE_WHEEL && retargeted.isConsumed()) { 4912 //An exception for wheel bubbling to the native system. 4913 //In "processMouseEvent" total event consuming for wheel events is skipped. 4914 //Protection from bubbling of Java-accepted wheel events. 4915 e.consume(); 4916 } 4917 } 4918 } 4919 4920 // --- member variables ------------------------------- 4921 4922 /** 4923 * The windowed container that might be hosting events for 4924 * subcomponents. 4925 */ 4926 private Container nativeContainer; 4927 4928 /** 4929 * This variable is not used, but kept for serialization compatibility 4930 */ 4931 private Component focus; 4932 4933 /** 4934 * The current subcomponent being hosted by this windowed 4935 * component that has events being forwarded to it. If this 4936 * is null, there are currently no events being forwarded to 4937 * a subcomponent. 4938 */ 4939 private transient Component mouseEventTarget; 4940 4941 /** 4942 * The last component entered by the {@code MouseEvent}. 4943 */ 4944 private transient Component targetLastEntered; 4945 4946 /** 4947 * The last component entered by the {@code SunDropTargetEvent}. 4948 */ 4949 private transient Component targetLastEnteredDT; 4950 4951 /** 4952 * Indicates whether {@code mouseEventTarget} was removed and nulled 4953 */ 4954 private transient boolean isCleaned; 4955 4956 /** 4957 * Is the mouse over the native container. 4958 */ 4959 private transient boolean isMouseInNativeContainer = false; 4960 4961 /** 4962 * Is DnD over the native container. 4963 */ 4964 private transient boolean isMouseDTInNativeContainer = false; 4965 4966 /** 4967 * This variable is not used, but kept for serialization compatibility 4968 */ 4969 private Cursor nativeCursor; 4970 4971 /** 4972 * The event mask for contained lightweight components. Lightweight 4973 * components need a windowed container to host window-related 4974 * events. This separate mask indicates events that have been 4975 * requested by contained lightweight components without effecting 4976 * the mask of the windowed component itself. 4977 */ 4978 private long eventMask; 4979 4980 /** 4981 * The kind of events routed to lightweight components from windowed 4982 * hosts. 4983 */ 4984 private static final long PROXY_EVENT_MASK = 4985 AWTEvent.FOCUS_EVENT_MASK | 4986 AWTEvent.KEY_EVENT_MASK | 4987 AWTEvent.MOUSE_EVENT_MASK | 4988 AWTEvent.MOUSE_MOTION_EVENT_MASK | 4989 AWTEvent.MOUSE_WHEEL_EVENT_MASK; 4990 4991 private static final long MOUSE_MASK = 4992 AWTEvent.MOUSE_EVENT_MASK | 4993 AWTEvent.MOUSE_MOTION_EVENT_MASK | 4994 AWTEvent.MOUSE_WHEEL_EVENT_MASK; 4995 4996 void removeReferences(Component removedComponent) { 4997 if (mouseEventTarget == removedComponent) { 4998 isCleaned = true; 4999 mouseEventTarget = null; 5000 } 5001 if (targetLastEntered == removedComponent) { 5002 targetLastEntered = null; 5003 } 5004 if (targetLastEnteredDT == removedComponent) { 5005 targetLastEnteredDT = null; 5006 } 5007 } 5008 }