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