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