Frames | No Frames |
1: /* Container.java -- parent container class in AWT 2: Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006 3: Free Software Foundation 4: 5: This file is part of GNU Classpath. 6: 7: GNU Classpath is free software; you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation; either version 2, or (at your option) 10: any later version. 11: 12: GNU Classpath is distributed in the hope that it will be useful, but 13: WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15: General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with GNU Classpath; see the file COPYING. If not, write to the 19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20: 02110-1301 USA. 21: 22: Linking this library statically or dynamically with other modules is 23: making a combined work based on this library. Thus, the terms and 24: conditions of the GNU General Public License cover the whole 25: combination. 26: 27: As a special exception, the copyright holders of this library give you 28: permission to link this library with independent modules to produce an 29: executable, regardless of the license terms of these independent 30: modules, and to copy and distribute the resulting executable under 31: terms of your choice, provided that you also meet, for each linked 32: independent module, the terms and conditions of the license of that 33: module. An independent module is a module which is not derived from 34: or based on this library. If you modify this library, you may extend 35: this exception to your version of the library, but you are not 36: obligated to do so. If you do not wish to do so, delete this 37: exception statement from your version. */ 38: 39: 40: package java.awt; 41: 42: import java.awt.event.ComponentListener; 43: import java.awt.event.ContainerEvent; 44: import java.awt.event.ContainerListener; 45: import java.awt.event.KeyEvent; 46: import java.awt.peer.ComponentPeer; 47: import java.awt.peer.ContainerPeer; 48: import java.awt.peer.LightweightPeer; 49: import java.beans.PropertyChangeListener; 50: import java.io.IOException; 51: import java.io.ObjectInputStream; 52: import java.io.ObjectOutputStream; 53: import java.io.PrintStream; 54: import java.io.PrintWriter; 55: import java.io.Serializable; 56: import java.util.Collections; 57: import java.util.EventListener; 58: import java.util.HashSet; 59: import java.util.Iterator; 60: import java.util.Set; 61: 62: import javax.accessibility.Accessible; 63: 64: /** 65: * A generic window toolkit object that acts as a container for other objects. 66: * Components are tracked in a list, and new elements are at the end of the 67: * list or bottom of the stacking order. 68: * 69: * @author original author unknown 70: * @author Eric Blake (ebb9@email.byu.edu) 71: * 72: * @since 1.0 73: * 74: * @status still missing 1.4 support 75: */ 76: public class Container extends Component 77: { 78: /** 79: * Compatible with JDK 1.0+. 80: */ 81: private static final long serialVersionUID = 4613797578919906343L; 82: 83: /* Serialized fields from the serialization spec. */ 84: int ncomponents; 85: Component[] component; 86: LayoutManager layoutMgr; 87: 88: Dimension maxSize; 89: 90: /** 91: * Keeps track if the Container was cleared during a paint/update. 92: */ 93: private boolean backCleared; 94: 95: /** 96: * @since 1.4 97: */ 98: boolean focusCycleRoot; 99: 100: int containerSerializedDataVersion; 101: 102: /* Anything else is non-serializable, and should be declared "transient". */ 103: transient ContainerListener containerListener; 104: 105: /** The focus traversal policy that determines how focus is 106: transferred between this Container and its children. */ 107: private FocusTraversalPolicy focusTraversalPolicy; 108: 109: /** 110: * The focus traversal keys, if not inherited from the parent or default 111: * keyboard manager. These sets will contain only AWTKeyStrokes that 112: * represent press and release events to use as focus control. 113: * 114: * @see #getFocusTraversalKeys(int) 115: * @see #setFocusTraversalKeys(int, Set) 116: * @since 1.4 117: */ 118: transient Set[] focusTraversalKeys; 119: 120: /** 121: * Default constructor for subclasses. 122: */ 123: public Container() 124: { 125: // Nothing to do here. 126: } 127: 128: /** 129: * Returns the number of components in this container. 130: * 131: * @return The number of components in this container. 132: */ 133: public int getComponentCount() 134: { 135: return countComponents (); 136: } 137: 138: /** 139: * Returns the number of components in this container. 140: * 141: * @return The number of components in this container. 142: * 143: * @deprecated use {@link #getComponentCount()} instead 144: */ 145: public int countComponents() 146: { 147: return ncomponents; 148: } 149: 150: /** 151: * Returns the component at the specified index. 152: * 153: * @param n The index of the component to retrieve. 154: * 155: * @return The requested component. 156: * 157: * @throws ArrayIndexOutOfBoundsException If the specified index is invalid 158: */ 159: public Component getComponent(int n) 160: { 161: synchronized (getTreeLock ()) 162: { 163: if (n < 0 || n >= ncomponents) 164: throw new ArrayIndexOutOfBoundsException("no such component"); 165: 166: return component[n]; 167: } 168: } 169: 170: /** 171: * Returns an array of the components in this container. 172: * 173: * @return The components in this container. 174: */ 175: public Component[] getComponents() 176: { 177: synchronized (getTreeLock ()) 178: { 179: Component[] result = new Component[ncomponents]; 180: 181: if (ncomponents > 0) 182: System.arraycopy(component, 0, result, 0, ncomponents); 183: 184: return result; 185: } 186: } 187: 188: /** 189: * Returns the insets for this container, which is the space used for 190: * borders, the margin, etc. 191: * 192: * @return The insets for this container. 193: */ 194: public Insets getInsets() 195: { 196: return insets (); 197: } 198: 199: /** 200: * Returns the insets for this container, which is the space used for 201: * borders, the margin, etc. 202: * 203: * @return The insets for this container. 204: * @deprecated use {@link #getInsets()} instead 205: */ 206: public Insets insets() 207: { 208: if (peer == null) 209: return new Insets (0, 0, 0, 0); 210: 211: return ((ContainerPeer) peer).getInsets (); 212: } 213: 214: /** 215: * Adds the specified component to this container at the end of the 216: * component list. 217: * 218: * @param comp The component to add to the container. 219: * 220: * @return The same component that was added. 221: */ 222: public Component add(Component comp) 223: { 224: addImpl(comp, null, -1); 225: return comp; 226: } 227: 228: /** 229: * Adds the specified component to the container at the end of the 230: * component list. This method should not be used. Instead, use 231: * <code>add(Component, Object)</code>. 232: * 233: * @param name The name of the component to be added. 234: * @param comp The component to be added. 235: * 236: * @return The same component that was added. 237: * 238: * @see #add(Component,Object) 239: */ 240: public Component add(String name, Component comp) 241: { 242: addImpl(comp, name, -1); 243: return comp; 244: } 245: 246: /** 247: * Adds the specified component to this container at the specified index 248: * in the component list. 249: * 250: * @param comp The component to be added. 251: * @param index The index in the component list to insert this child 252: * at, or -1 to add at the end of the list. 253: * 254: * @return The same component that was added. 255: * 256: * @throws ArrayIndexOutOfBoundsException If the specified index is invalid. 257: */ 258: public Component add(Component comp, int index) 259: { 260: addImpl(comp, null, index); 261: return comp; 262: } 263: 264: /** 265: * Adds the specified component to this container at the end of the 266: * component list. The layout manager will use the specified constraints 267: * when laying out this component. 268: * 269: * @param comp The component to be added to this container. 270: * @param constraints The layout constraints for this component. 271: */ 272: public void add(Component comp, Object constraints) 273: { 274: addImpl(comp, constraints, -1); 275: } 276: 277: /** 278: * Adds the specified component to this container at the specified index 279: * in the component list. The layout manager will use the specified 280: * constraints when layout out this component. 281: * 282: * @param comp The component to be added. 283: * @param constraints The layout constraints for this component. 284: * @param index The index in the component list to insert this child 285: * at, or -1 to add at the end of the list. 286: * 287: * @throws ArrayIndexOutOfBoundsException If the specified index is invalid. 288: */ 289: public void add(Component comp, Object constraints, int index) 290: { 291: addImpl(comp, constraints, index); 292: } 293: 294: /** 295: * This method is called by all the <code>add()</code> methods to perform 296: * the actual adding of the component. Subclasses who wish to perform 297: * their own processing when a component is added should override this 298: * method. Any subclass doing this must call the superclass version of 299: * this method in order to ensure proper functioning of the container. 300: * 301: * @param comp The component to be added. 302: * @param constraints The layout constraints for this component, or 303: * <code>null</code> if there are no constraints. 304: * @param index The index in the component list to insert this child 305: * at, or -1 to add at the end of the list. 306: * 307: * @throws ArrayIndexOutOfBoundsException If the specified index is invalid. 308: */ 309: protected void addImpl(Component comp, Object constraints, int index) 310: { 311: synchronized (getTreeLock ()) 312: { 313: if (index > ncomponents 314: || (index < 0 && index != -1) 315: || comp instanceof Window 316: || (comp instanceof Container 317: && ((Container) comp).isAncestorOf(this))) 318: throw new IllegalArgumentException(); 319: 320: // Reparent component, and make sure component is instantiated if 321: // we are. 322: if (comp.parent != null) 323: comp.parent.remove(comp); 324: comp.parent = this; 325: 326: if (peer != null) 327: { 328: // Notify the component that it has a new parent. 329: comp.addNotify(); 330: 331: if (comp.isLightweight ()) 332: { 333: enableEvents (comp.eventMask); 334: if (!isLightweight ()) 335: enableEvents (AWTEvent.PAINT_EVENT_MASK); 336: } 337: } 338: 339: // Invalidate the layout of the added component and its ancestors. 340: comp.invalidate(); 341: 342: if (component == null) 343: component = new Component[4]; // FIXME, better initial size? 344: 345: // This isn't the most efficient implementation. We could do less 346: // copying when growing the array. It probably doesn't matter. 347: if (ncomponents >= component.length) 348: { 349: int nl = component.length * 2; 350: Component[] c = new Component[nl]; 351: System.arraycopy(component, 0, c, 0, ncomponents); 352: component = c; 353: } 354: 355: if (index == -1) 356: component[ncomponents++] = comp; 357: else 358: { 359: System.arraycopy(component, index, component, index + 1, 360: ncomponents - index); 361: component[index] = comp; 362: ++ncomponents; 363: } 364: 365: // Notify the layout manager. 366: if (layoutMgr != null) 367: { 368: // If we have a LayoutManager2 the constraints are "real", 369: // otherwise they are the "name" of the Component to add. 370: if (layoutMgr instanceof LayoutManager2) 371: { 372: LayoutManager2 lm2 = (LayoutManager2) layoutMgr; 373: lm2.addLayoutComponent(comp, constraints); 374: } 375: else if (constraints instanceof String) 376: layoutMgr.addLayoutComponent((String) constraints, comp); 377: else 378: layoutMgr.addLayoutComponent("", comp); 379: } 380: 381: // We previously only sent an event when this container is showing. 382: // Also, the event was posted to the event queue. A Mauve test shows 383: // that this event is not delivered using the event queue and it is 384: // also sent when the container is not showing. 385: ContainerEvent ce = new ContainerEvent(this, 386: ContainerEvent.COMPONENT_ADDED, 387: comp); 388: ContainerListener[] listeners = getContainerListeners(); 389: for (int i = 0; i < listeners.length; i++) 390: listeners[i].componentAdded(ce); 391: } 392: } 393: 394: /** 395: * Removes the component at the specified index from this container. 396: * 397: * @param index The index of the component to remove. 398: */ 399: public void remove(int index) 400: { 401: synchronized (getTreeLock ()) 402: { 403: Component r = component[index]; 404: 405: ComponentListener[] list = r.getComponentListeners(); 406: for (int j = 0; j < list.length; j++) 407: r.removeComponentListener(list[j]); 408: 409: r.removeNotify(); 410: 411: System.arraycopy(component, index + 1, component, index, 412: ncomponents - index - 1); 413: component[--ncomponents] = null; 414: 415: invalidate(); 416: 417: if (layoutMgr != null) 418: layoutMgr.removeLayoutComponent(r); 419: 420: r.parent = null; 421: 422: if (isShowing ()) 423: { 424: // Post event to notify of removing the component. 425: ContainerEvent ce = new ContainerEvent(this, 426: ContainerEvent.COMPONENT_REMOVED, 427: r); 428: getToolkit().getSystemEventQueue().postEvent(ce); 429: } 430: } 431: } 432: 433: /** 434: * Removes the specified component from this container. 435: * 436: * @param comp The component to remove from this container. 437: */ 438: public void remove(Component comp) 439: { 440: synchronized (getTreeLock ()) 441: { 442: for (int i = 0; i < ncomponents; ++i) 443: { 444: if (component[i] == comp) 445: { 446: remove(i); 447: break; 448: } 449: } 450: } 451: } 452: 453: /** 454: * Removes all components from this container. 455: */ 456: public void removeAll() 457: { 458: synchronized (getTreeLock ()) 459: { 460: // In order to allow the same bad tricks to be used as in RI 461: // this code has to stay exactly that way: In a real-life app 462: // a Container subclass implemented its own vector for 463: // subcomponents, supplied additional addXYZ() methods 464: // and overrode remove(int) and removeAll (the latter calling 465: // super.removeAll() ). 466: // By doing it this way, user code cannot prevent the correct 467: // removal of components. 468: for ( int index = 0; index < ncomponents; index++) 469: { 470: Component r = component[index]; 471: 472: ComponentListener[] list = r.getComponentListeners(); 473: for (int j = 0; j < list.length; j++) 474: r.removeComponentListener(list[j]); 475: 476: r.removeNotify(); 477: 478: if (layoutMgr != null) 479: layoutMgr.removeLayoutComponent(r); 480: 481: r.parent = null; 482: 483: if (isShowing ()) 484: { 485: // Post event to notify of removing the component. 486: ContainerEvent ce 487: = new ContainerEvent(this, 488: ContainerEvent.COMPONENT_REMOVED, 489: r); 490: 491: getToolkit().getSystemEventQueue().postEvent(ce); 492: } 493: } 494: 495: invalidate(); 496: 497: ncomponents = 0; 498: } 499: } 500: 501: /** 502: * Returns the current layout manager for this container. 503: * 504: * @return The layout manager for this container. 505: */ 506: public LayoutManager getLayout() 507: { 508: return layoutMgr; 509: } 510: 511: /** 512: * Sets the layout manager for this container to the specified layout 513: * manager. 514: * 515: * @param mgr The new layout manager for this container. 516: */ 517: public void setLayout(LayoutManager mgr) 518: { 519: layoutMgr = mgr; 520: invalidate(); 521: } 522: 523: /** 524: * Layout the components in this container. 525: */ 526: public void doLayout() 527: { 528: layout (); 529: } 530: 531: /** 532: * Layout the components in this container. 533: * 534: * @deprecated use {@link #doLayout()} instead 535: */ 536: public void layout() 537: { 538: if (layoutMgr != null) 539: layoutMgr.layoutContainer (this); 540: } 541: 542: /** 543: * Invalidates this container to indicate that it (and all parent 544: * containers) need to be laid out. 545: */ 546: public void invalidate() 547: { 548: super.invalidate(); 549: if (layoutMgr != null && layoutMgr instanceof LayoutManager2) 550: { 551: LayoutManager2 lm2 = (LayoutManager2) layoutMgr; 552: lm2.invalidateLayout(this); 553: } 554: } 555: 556: /** 557: * Re-lays out the components in this container. 558: */ 559: public void validate() 560: { 561: synchronized (getTreeLock ()) 562: { 563: if (! isValid() && peer != null) 564: { 565: validateTree(); 566: } 567: } 568: } 569: 570: /** 571: * Recursively invalidates the container tree. 572: */ 573: void invalidateTree() 574: { 575: super.invalidate(); // Clean cached layout state. 576: for (int i = 0; i < ncomponents; i++) 577: { 578: Component comp = component[i]; 579: comp.invalidate(); 580: if (comp instanceof Container) 581: ((Container) comp).invalidateTree(); 582: } 583: 584: if (layoutMgr != null && layoutMgr instanceof LayoutManager2) 585: { 586: LayoutManager2 lm2 = (LayoutManager2) layoutMgr; 587: lm2.invalidateLayout(this); 588: } 589: } 590: 591: /** 592: * Recursively validates the container tree, recomputing any invalid 593: * layouts. 594: */ 595: protected void validateTree() 596: { 597: if (valid) 598: return; 599: 600: ContainerPeer cPeer = null; 601: if (peer != null && ! (peer instanceof LightweightPeer)) 602: { 603: cPeer = (ContainerPeer) peer; 604: cPeer.beginValidate(); 605: } 606: 607: for (int i = 0; i < ncomponents; ++i) 608: { 609: Component comp = component[i]; 610: 611: if (comp.getPeer () == null) 612: comp.addNotify(); 613: } 614: 615: doLayout (); 616: for (int i = 0; i < ncomponents; ++i) 617: { 618: Component comp = component[i]; 619: 620: if (! comp.isValid()) 621: { 622: if (comp instanceof Container) 623: { 624: ((Container) comp).validateTree(); 625: } 626: else 627: { 628: component[i].validate(); 629: } 630: } 631: } 632: 633: /* children will call invalidate() when they are layed out. It 634: is therefore important that valid is not set to true 635: until after the children have been layed out. */ 636: valid = true; 637: 638: if (cPeer != null) 639: cPeer.endValidate(); 640: } 641: 642: public void setFont(Font f) 643: { 644: if( (f != null && (font == null || !font.equals(f))) 645: || f == null) 646: { 647: super.setFont(f); 648: // FIXME: Although it might make more sense to invalidate only 649: // those children whose font == null, Sun invalidates all children. 650: // So we'll do the same. 651: invalidateTree(); 652: } 653: } 654: 655: /** 656: * Returns the preferred size of this container. 657: * 658: * @return The preferred size of this container. 659: */ 660: public Dimension getPreferredSize() 661: { 662: return preferredSize (); 663: } 664: 665: /** 666: * Returns the preferred size of this container. 667: * 668: * @return The preferred size of this container. 669: * 670: * @deprecated use {@link #getPreferredSize()} instead 671: */ 672: public Dimension preferredSize() 673: { 674: synchronized(treeLock) 675: { 676: if(valid && prefSize != null) 677: return new Dimension(prefSize); 678: LayoutManager layout = getLayout(); 679: if (layout != null) 680: { 681: Dimension layoutSize = layout.preferredLayoutSize(this); 682: if(valid) 683: prefSize = layoutSize; 684: return new Dimension(layoutSize); 685: } 686: else 687: return super.preferredSize (); 688: } 689: } 690: 691: /** 692: * Returns the minimum size of this container. 693: * 694: * @return The minimum size of this container. 695: */ 696: public Dimension getMinimumSize() 697: { 698: return minimumSize (); 699: } 700: 701: /** 702: * Returns the minimum size of this container. 703: * 704: * @return The minimum size of this container. 705: * 706: * @deprecated use {@link #getMinimumSize()} instead 707: */ 708: public Dimension minimumSize() 709: { 710: if(valid && minSize != null) 711: return new Dimension(minSize); 712: 713: LayoutManager layout = getLayout(); 714: if (layout != null) 715: { 716: minSize = layout.minimumLayoutSize (this); 717: return minSize; 718: } 719: else 720: return super.minimumSize (); 721: } 722: 723: /** 724: * Returns the maximum size of this container. 725: * 726: * @return The maximum size of this container. 727: */ 728: public Dimension getMaximumSize() 729: { 730: if (valid && maxSize != null) 731: return new Dimension(maxSize); 732: 733: LayoutManager layout = getLayout(); 734: if (layout != null && layout instanceof LayoutManager2) 735: { 736: LayoutManager2 lm2 = (LayoutManager2) layout; 737: maxSize = lm2.maximumLayoutSize(this); 738: return maxSize; 739: } 740: else 741: return super.getMaximumSize(); 742: } 743: 744: /** 745: * Returns the preferred alignment along the X axis. This is a value 746: * between 0 and 1 where 0 represents alignment flush left and 747: * 1 means alignment flush right, and 0.5 means centered. 748: * 749: * @return The preferred alignment along the X axis. 750: */ 751: public float getAlignmentX() 752: { 753: LayoutManager layout = getLayout(); 754: float alignmentX = 0.0F; 755: if (layout != null && layout instanceof LayoutManager2) 756: { 757: LayoutManager2 lm2 = (LayoutManager2) layout; 758: alignmentX = lm2.getLayoutAlignmentX(this); 759: } 760: else 761: alignmentX = super.getAlignmentX(); 762: return alignmentX; 763: } 764: 765: /** 766: * Returns the preferred alignment along the Y axis. This is a value 767: * between 0 and 1 where 0 represents alignment flush top and 768: * 1 means alignment flush bottom, and 0.5 means centered. 769: * 770: * @return The preferred alignment along the Y axis. 771: */ 772: public float getAlignmentY() 773: { 774: LayoutManager layout = getLayout(); 775: float alignmentY = 0.0F; 776: if (layout != null && layout instanceof LayoutManager2) 777: { 778: LayoutManager2 lm2 = (LayoutManager2) layout; 779: alignmentY = lm2.getLayoutAlignmentY(this); 780: } 781: else 782: alignmentY = super.getAlignmentY(); 783: return alignmentY; 784: } 785: 786: /** 787: * Paints this container. The implementation of this method in this 788: * class forwards to any lightweight components in this container. If 789: * this method is subclassed, this method should still be invoked as 790: * a superclass method so that lightweight components are properly 791: * drawn. 792: * 793: * @param g - The graphics context for this paint job. 794: */ 795: public void paint(Graphics g) 796: { 797: if (!isShowing()) 798: return; 799: 800: // Visit heavyweights if the background was cleared 801: // for this container. 802: visitChildren(g, GfxPaintVisitor.INSTANCE, !backCleared); 803: backCleared = false; 804: } 805: 806: /** 807: * Updates this container. The implementation of this method in this 808: * class forwards to any lightweight components in this container. If 809: * this method is subclassed, this method should still be invoked as 810: * a superclass method so that lightweight components are properly 811: * drawn. 812: * 813: * @param g The graphics context for this update. 814: * 815: * @specnote The specification suggests that this method forwards the 816: * update() call to all its lightweight children. Tests show 817: * that this is not done either in the JDK. The exact behaviour 818: * seems to be that the background is cleared in heavyweight 819: * Containers, and all other containers 820: * directly call paint(), causing the (lightweight) children to 821: * be painted. 822: */ 823: public void update(Graphics g) 824: { 825: // It seems that the JDK clears the background of containers like Panel 826: // and Window (within this method) but not of 'plain' Containers or 827: // JComponents. This could 828: // lead to the assumption that it only clears heavyweight containers. 829: // However that is not quite true. In a test with a custom Container 830: // that overrides isLightweight() to return false, the background is 831: // also not cleared. So we do a check on !(peer instanceof LightweightPeer) 832: // instead. 833: ComponentPeer p = peer; 834: if (p != null && ! (p instanceof LightweightPeer)) 835: { 836: g.clearRect(0, 0, getWidth(), getHeight()); 837: backCleared = true; 838: } 839: 840: paint(g); 841: } 842: 843: /** 844: * Prints this container. The implementation of this method in this 845: * class forwards to any lightweight components in this container. If 846: * this method is subclassed, this method should still be invoked as 847: * a superclass method so that lightweight components are properly 848: * drawn. 849: * 850: * @param g The graphics context for this print job. 851: */ 852: public void print(Graphics g) 853: { 854: super.print(g); 855: visitChildren(g, GfxPrintVisitor.INSTANCE, true); 856: } 857: 858: /** 859: * Paints all of the components in this container. 860: * 861: * @param g The graphics context for this paint job. 862: */ 863: public void paintComponents(Graphics g) 864: { 865: paint(g); 866: visitChildren(g, GfxPaintAllVisitor.INSTANCE, true); 867: } 868: 869: /** 870: * Prints all of the components in this container. 871: * 872: * @param g The graphics context for this print job. 873: */ 874: public void printComponents(Graphics g) 875: { 876: super.paint(g); 877: visitChildren(g, GfxPrintAllVisitor.INSTANCE, true); 878: } 879: 880: /** 881: * Adds the specified container listener to this object's list of 882: * container listeners. 883: * 884: * @param listener The listener to add. 885: */ 886: public synchronized void addContainerListener(ContainerListener listener) 887: { 888: containerListener = AWTEventMulticaster.add(containerListener, listener); 889: } 890: 891: /** 892: * Removes the specified container listener from this object's list of 893: * container listeners. 894: * 895: * @param listener The listener to remove. 896: */ 897: public synchronized void removeContainerListener(ContainerListener listener) 898: { 899: containerListener = AWTEventMulticaster.remove(containerListener, listener); 900: } 901: 902: /** 903: * @since 1.4 904: */ 905: public synchronized ContainerListener[] getContainerListeners() 906: { 907: return (ContainerListener[]) 908: AWTEventMulticaster.getListeners(containerListener, 909: ContainerListener.class); 910: } 911: 912: /** 913: * Returns all registered {@link EventListener}s of the given 914: * <code>listenerType</code>. 915: * 916: * @param listenerType the class of listeners to filter (<code>null</code> 917: * not permitted). 918: * 919: * @return An array of registered listeners. 920: * 921: * @throws ClassCastException if <code>listenerType</code> does not implement 922: * the {@link EventListener} interface. 923: * @throws NullPointerException if <code>listenerType</code> is 924: * <code>null</code>. 925: * 926: * @see #getContainerListeners() 927: * 928: * @since 1.3 929: */ 930: public EventListener[] getListeners(Class listenerType) 931: { 932: if (listenerType == ContainerListener.class) 933: return getContainerListeners(); 934: return super.getListeners(listenerType); 935: } 936: 937: /** 938: * Processes the specified event. This method calls 939: * <code>processContainerEvent()</code> if this method is a 940: * <code>ContainerEvent</code>, otherwise it calls the superclass 941: * method. 942: * 943: * @param e The event to be processed. 944: */ 945: protected void processEvent(AWTEvent e) 946: { 947: if (e instanceof ContainerEvent) 948: processContainerEvent((ContainerEvent) e); 949: else 950: super.processEvent(e); 951: } 952: 953: /** 954: * Called when a container event occurs if container events are enabled. 955: * This method calls any registered listeners. 956: * 957: * @param e The event that occurred. 958: */ 959: protected void processContainerEvent(ContainerEvent e) 960: { 961: if (containerListener == null) 962: return; 963: switch (e.id) 964: { 965: case ContainerEvent.COMPONENT_ADDED: 966: containerListener.componentAdded(e); 967: break; 968: 969: case ContainerEvent.COMPONENT_REMOVED: 970: containerListener.componentRemoved(e); 971: break; 972: } 973: } 974: 975: /** 976: * AWT 1.0 event processor. 977: * 978: * @param e The event that occurred. 979: * 980: * @deprecated use {@link #dispatchEvent(AWTEvent)} instead 981: */ 982: public void deliverEvent(Event e) 983: { 984: if (!handleEvent (e)) 985: { 986: synchronized (getTreeLock ()) 987: { 988: Component parent = getParent (); 989: 990: if (parent != null) 991: parent.deliverEvent (e); 992: } 993: } 994: } 995: 996: /** 997: * Returns the component located at the specified point. This is done 998: * by checking whether or not a child component claims to contain this 999: * point. The first child component that does is returned. If no 1000: * child component claims the point, the container itself is returned, 1001: * unless the point does not exist within this container, in which 1002: * case <code>null</code> is returned. 1003: * 1004: * When components overlap, the first component is returned. The component 1005: * that is closest to (x, y), containing that location, is returned. 1006: * Heavyweight components take precedence of lightweight components. 1007: * 1008: * This function does not ignore invisible components. If there is an invisible 1009: * component at (x,y), it will be returned. 1010: * 1011: * @param x The X coordinate of the point. 1012: * @param y The Y coordinate of the point. 1013: * 1014: * @return The component containing the specified point, or 1015: * <code>null</code> if there is no such point. 1016: */ 1017: public Component getComponentAt(int x, int y) 1018: { 1019: return locate (x, y); 1020: } 1021: 1022: /** 1023: * Returns the component located at the specified point. This is done 1024: * by checking whether or not a child component claims to contain this 1025: * point. The first child component that does is returned. If no 1026: * child component claims the point, the container itself is returned, 1027: * unless the point does not exist within this container, in which 1028: * case <code>null</code> is returned. 1029: * 1030: * When components overlap, the first component is returned. The component 1031: * that is closest to (x, y), containing that location, is returned. 1032: * Heavyweight components take precedence of lightweight components. 1033: * 1034: * This function does not ignore invisible components. If there is an invisible 1035: * component at (x,y), it will be returned. 1036: * 1037: * @param x The x position of the point to return the component at. 1038: * @param y The y position of the point to return the component at. 1039: * 1040: * @return The component containing the specified point, or <code>null</code> 1041: * if there is no such point. 1042: * 1043: * @deprecated use {@link #getComponentAt(int, int)} instead 1044: */ 1045: public Component locate(int x, int y) 1046: { 1047: synchronized (getTreeLock ()) 1048: { 1049: if (!contains (x, y)) 1050: return null; 1051: 1052: // First find the component closest to (x,y) that is a heavyweight. 1053: for (int i = 0; i < ncomponents; ++i) 1054: { 1055: Component comp = component[i]; 1056: int x2 = x - comp.x; 1057: int y2 = y - comp.y; 1058: if (comp.contains (x2, y2) && !comp.isLightweight()) 1059: return comp; 1060: } 1061: 1062: // if a heavyweight component is not found, look for a lightweight 1063: // closest to (x,y). 1064: for (int i = 0; i < ncomponents; ++i) 1065: { 1066: Component comp = component[i]; 1067: int x2 = x - comp.x; 1068: int y2 = y - comp.y; 1069: if (comp.contains (x2, y2) && comp.isLightweight()) 1070: return comp; 1071: } 1072: 1073: return this; 1074: } 1075: } 1076: 1077: /** 1078: * Returns the component located at the specified point. This is done 1079: * by checking whether or not a child component claims to contain this 1080: * point. The first child component that does is returned. If no 1081: * child component claims the point, the container itself is returned, 1082: * unless the point does not exist within this container, in which 1083: * case <code>null</code> is returned. 1084: * 1085: * The top-most child component is returned in the case where components overlap. 1086: * This is determined by finding the component closest to (x,y) and contains 1087: * that location. Heavyweight components take precedence of lightweight components. 1088: * 1089: * This function does not ignore invisible components. If there is an invisible 1090: * component at (x,y), it will be returned. 1091: * 1092: * @param p The point to return the component at. 1093: * @return The component containing the specified point, or <code>null</code> 1094: * if there is no such point. 1095: */ 1096: public Component getComponentAt(Point p) 1097: { 1098: return getComponentAt (p.x, p.y); 1099: } 1100: 1101: /** 1102: * Locates the visible child component that contains the specified position. 1103: * The top-most child component is returned in the case where there is overlap 1104: * in the components. If the containing child component is a Container, 1105: * this method will continue searching for the deepest nested child 1106: * component. Components which are not visible are ignored during the search. 1107: * 1108: * findComponentAt differs from getComponentAt, because it recursively 1109: * searches a Container's children. 1110: * 1111: * @param x - x coordinate 1112: * @param y - y coordinate 1113: * @return null if the component does not contain the position. 1114: * If there is no child component at the requested point and the point is 1115: * within the bounds of the container the container itself is returned. 1116: */ 1117: public Component findComponentAt(int x, int y) 1118: { 1119: synchronized (getTreeLock ()) 1120: { 1121: if (! contains(x, y)) 1122: return null; 1123: 1124: for (int i = 0; i < ncomponents; ++i) 1125: { 1126: // Ignore invisible children... 1127: if (!component[i].isVisible()) 1128: continue; 1129: 1130: int x2 = x - component[i].x; 1131: int y2 = y - component[i].y; 1132: // We don't do the contains() check right away because 1133: // findComponentAt would redundantly do it first thing. 1134: if (component[i] instanceof Container) 1135: { 1136: Container k = (Container) component[i]; 1137: Component r = k.findComponentAt(x2, y2); 1138: if (r != null) 1139: return r; 1140: } 1141: else if (component[i].contains(x2, y2)) 1142: return component[i]; 1143: } 1144: 1145: return this; 1146: } 1147: } 1148: 1149: /** 1150: * Locates the visible child component that contains the specified position. 1151: * The top-most child component is returned in the case where there is overlap 1152: * in the components. If the containing child component is a Container, 1153: * this method will continue searching for the deepest nested child 1154: * component. Components which are not visible are ignored during the search. 1155: * 1156: * findComponentAt differs from getComponentAt, because it recursively 1157: * searches a Container's children. 1158: * 1159: * @param p - the component's location 1160: * @return null if the component does not contain the position. 1161: * If there is no child component at the requested point and the point is 1162: * within the bounds of the container the container itself is returned. 1163: */ 1164: public Component findComponentAt(Point p) 1165: { 1166: return findComponentAt(p.x, p.y); 1167: } 1168: 1169: /** 1170: * Called when this container is added to another container to inform it 1171: * to create its peer. Peers for any child components will also be 1172: * created. 1173: */ 1174: public void addNotify() 1175: { 1176: super.addNotify(); 1177: addNotifyContainerChildren(); 1178: } 1179: 1180: /** 1181: * Called when this container is removed from its parent container to 1182: * inform it to destroy its peer. This causes the peers of all child 1183: * component to be destroyed as well. 1184: */ 1185: public void removeNotify() 1186: { 1187: synchronized (getTreeLock ()) 1188: { 1189: for (int i = 0; i < ncomponents; ++i) 1190: component[i].removeNotify(); 1191: super.removeNotify(); 1192: } 1193: } 1194: 1195: /** 1196: * Tests whether or not the specified component is contained within 1197: * this components subtree. 1198: * 1199: * @param comp The component to test. 1200: * 1201: * @return <code>true</code> if this container is an ancestor of the 1202: * specified component, <code>false</code> otherwise. 1203: */ 1204: public boolean isAncestorOf(Component comp) 1205: { 1206: synchronized (getTreeLock ()) 1207: { 1208: while (true) 1209: { 1210: if (comp == null) 1211: return false; 1212: if (comp == this) 1213: return true; 1214: comp = comp.getParent(); 1215: } 1216: } 1217: } 1218: 1219: /** 1220: * Returns a string representing the state of this container for 1221: * debugging purposes. 1222: * 1223: * @return A string representing the state of this container. 1224: */ 1225: protected String paramString() 1226: { 1227: if (layoutMgr == null) 1228: return super.paramString(); 1229: 1230: StringBuffer sb = new StringBuffer(); 1231: sb.append(super.paramString()); 1232: sb.append(",layout="); 1233: sb.append(layoutMgr.getClass().getName()); 1234: return sb.toString(); 1235: } 1236: 1237: /** 1238: * Writes a listing of this container to the specified stream starting 1239: * at the specified indentation point. 1240: * 1241: * @param out The <code>PrintStream</code> to write to. 1242: * @param indent The indentation point. 1243: */ 1244: public void list(PrintStream out, int indent) 1245: { 1246: synchronized (getTreeLock ()) 1247: { 1248: super.list(out, indent); 1249: for (int i = 0; i < ncomponents; ++i) 1250: component[i].list(out, indent + 2); 1251: } 1252: } 1253: 1254: /** 1255: * Writes a listing of this container to the specified stream starting 1256: * at the specified indentation point. 1257: * 1258: * @param out The <code>PrintWriter</code> to write to. 1259: * @param indent The indentation point. 1260: */ 1261: public void list(PrintWriter out, int indent) 1262: { 1263: synchronized (getTreeLock ()) 1264: { 1265: super.list(out, indent); 1266: for (int i = 0; i < ncomponents; ++i) 1267: component[i].list(out, indent + 2); 1268: } 1269: } 1270: 1271: /** 1272: * Sets the focus traversal keys for a given traversal operation for this 1273: * Container. 1274: * 1275: * @exception IllegalArgumentException If id is not one of 1276: * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 1277: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 1278: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, 1279: * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, 1280: * or if keystrokes contains null, or if any Object in keystrokes is not an 1281: * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event, or if any 1282: * keystroke already maps to another focus traversal operation for this 1283: * Container. 1284: * 1285: * @since 1.4 1286: */ 1287: public void setFocusTraversalKeys(int id, Set keystrokes) 1288: { 1289: if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && 1290: id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && 1291: id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && 1292: id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) 1293: throw new IllegalArgumentException (); 1294: 1295: if (keystrokes == null) 1296: { 1297: Container parent = getParent (); 1298: 1299: while (parent != null) 1300: { 1301: if (parent.areFocusTraversalKeysSet (id)) 1302: { 1303: keystrokes = parent.getFocusTraversalKeys (id); 1304: break; 1305: } 1306: parent = parent.getParent (); 1307: } 1308: 1309: if (keystrokes == null) 1310: keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager (). 1311: getDefaultFocusTraversalKeys (id); 1312: } 1313: 1314: Set sa; 1315: Set sb; 1316: Set sc; 1317: String name; 1318: switch (id) 1319: { 1320: case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: 1321: sa = getFocusTraversalKeys 1322: (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 1323: sb = getFocusTraversalKeys 1324: (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); 1325: sc = getFocusTraversalKeys 1326: (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); 1327: name = "forwardFocusTraversalKeys"; 1328: break; 1329: case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: 1330: sa = getFocusTraversalKeys 1331: (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 1332: sb = getFocusTraversalKeys 1333: (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); 1334: sc = getFocusTraversalKeys 1335: (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); 1336: name = "backwardFocusTraversalKeys"; 1337: break; 1338: case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: 1339: sa = getFocusTraversalKeys 1340: (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 1341: sb = getFocusTraversalKeys 1342: (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 1343: sc = getFocusTraversalKeys 1344: (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); 1345: name = "upCycleFocusTraversalKeys"; 1346: break; 1347: case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS: 1348: sa = getFocusTraversalKeys 1349: (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 1350: sb = getFocusTraversalKeys 1351: (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 1352: sc = getFocusTraversalKeys 1353: (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); 1354: name = "downCycleFocusTraversalKeys"; 1355: break; 1356: default: 1357: throw new IllegalArgumentException (); 1358: } 1359: 1360: int i = keystrokes.size (); 1361: Iterator iter = keystrokes.iterator (); 1362: 1363: while (--i >= 0) 1364: { 1365: Object o = iter.next (); 1366: if (!(o instanceof AWTKeyStroke) 1367: || sa.contains (o) || sb.contains (o) || sc.contains (o) 1368: || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) 1369: throw new IllegalArgumentException (); 1370: } 1371: 1372: if (focusTraversalKeys == null) 1373: focusTraversalKeys = new Set[4]; 1374: 1375: keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes)); 1376: firePropertyChange (name, focusTraversalKeys[id], keystrokes); 1377: 1378: focusTraversalKeys[id] = keystrokes; 1379: } 1380: 1381: /** 1382: * Returns the Set of focus traversal keys for a given traversal operation for 1383: * this Container. 1384: * 1385: * @exception IllegalArgumentException If id is not one of 1386: * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 1387: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 1388: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, 1389: * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. 1390: * 1391: * @since 1.4 1392: */ 1393: public Set getFocusTraversalKeys (int id) 1394: { 1395: if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && 1396: id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && 1397: id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && 1398: id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) 1399: throw new IllegalArgumentException (); 1400: 1401: Set s = null; 1402: 1403: if (focusTraversalKeys != null) 1404: s = focusTraversalKeys[id]; 1405: 1406: if (s == null && parent != null) 1407: s = parent.getFocusTraversalKeys (id); 1408: 1409: return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager() 1410: .getDefaultFocusTraversalKeys(id)) : s; 1411: } 1412: 1413: /** 1414: * Returns whether the Set of focus traversal keys for the given focus 1415: * traversal operation has been explicitly defined for this Container. 1416: * If this method returns false, this Container is inheriting the Set from 1417: * an ancestor, or from the current KeyboardFocusManager. 1418: * 1419: * @exception IllegalArgumentException If id is not one of 1420: * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 1421: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 1422: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, 1423: * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. 1424: * 1425: * @since 1.4 1426: */ 1427: public boolean areFocusTraversalKeysSet (int id) 1428: { 1429: if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && 1430: id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && 1431: id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && 1432: id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) 1433: throw new IllegalArgumentException (); 1434: 1435: return focusTraversalKeys != null && focusTraversalKeys[id] != null; 1436: } 1437: 1438: /** 1439: * Check whether the given Container is the focus cycle root of this 1440: * Container's focus traversal cycle. If this Container is a focus 1441: * cycle root itself, then it will be in two different focus cycles 1442: * -- it's own, and that of its ancestor focus cycle root's. In 1443: * that case, if <code>c</code> is either of those containers, this 1444: * method will return true. 1445: * 1446: * @param c the candidate Container 1447: * 1448: * @return true if c is the focus cycle root of the focus traversal 1449: * cycle to which this Container belongs, false otherwise 1450: * 1451: * @since 1.4 1452: */ 1453: public boolean isFocusCycleRoot (Container c) 1454: { 1455: if (this == c 1456: && isFocusCycleRoot ()) 1457: return true; 1458: 1459: Container ancestor = getFocusCycleRootAncestor (); 1460: 1461: if (c == ancestor) 1462: return true; 1463: 1464: return false; 1465: } 1466: 1467: /** 1468: * If this Container is a focus cycle root, set the focus traversal 1469: * policy that determines the focus traversal order for its 1470: * children. If non-null, this policy will be inherited by all 1471: * inferior focus cycle roots. If <code>policy</code> is null, this 1472: * Container will inherit its policy from the closest ancestor focus 1473: * cycle root that's had its policy set. 1474: * 1475: * @param policy the new focus traversal policy for this Container or null 1476: * 1477: * @since 1.4 1478: */ 1479: public void setFocusTraversalPolicy (FocusTraversalPolicy policy) 1480: { 1481: focusTraversalPolicy = policy; 1482: } 1483: 1484: /** 1485: * Return the focus traversal policy that determines the focus 1486: * traversal order for this Container's children. This method 1487: * returns null if this Container is not a focus cycle root. If the 1488: * focus traversal policy has not been set explicitly, then this 1489: * method will return an ancestor focus cycle root's policy instead. 1490: * 1491: * @return this Container's focus traversal policy or null 1492: * 1493: * @since 1.4 1494: */ 1495: public FocusTraversalPolicy getFocusTraversalPolicy () 1496: { 1497: if (!isFocusCycleRoot ()) 1498: return null; 1499: 1500: if (focusTraversalPolicy == null) 1501: { 1502: Container ancestor = getFocusCycleRootAncestor (); 1503: 1504: if (ancestor != this && ancestor != null) 1505: return ancestor.getFocusTraversalPolicy (); 1506: else 1507: { 1508: KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); 1509: 1510: return manager.getDefaultFocusTraversalPolicy (); 1511: } 1512: } 1513: else 1514: return focusTraversalPolicy; 1515: } 1516: 1517: /** 1518: * Check whether this Container's focus traversal policy has been 1519: * explicitly set. If it has not, then this Container will inherit 1520: * its focus traversal policy from one of its ancestor focus cycle 1521: * roots. 1522: * 1523: * @return true if focus traversal policy is set, false otherwise 1524: */ 1525: public boolean isFocusTraversalPolicySet () 1526: { 1527: return focusTraversalPolicy == null; 1528: } 1529: 1530: /** 1531: * Set whether or not this Container is the root of a focus 1532: * traversal cycle. This Container's focus traversal policy 1533: * determines the order of focus traversal. Some policies prevent 1534: * the focus from being transferred between two traversal cycles 1535: * until an up or down traversal operation is performed. In that 1536: * case, normal traversal (not up or down) is limited to this 1537: * Container and all of this Container's descendents that are not 1538: * descendents of inferior focus cycle roots. In the default case 1539: * however, ContainerOrderFocusTraversalPolicy is in effect, and it 1540: * supports implicit down-cycle traversal operations. 1541: * 1542: * @param focusCycleRoot true if this is a focus cycle root, false otherwise 1543: * 1544: * @since 1.4 1545: */ 1546: public void setFocusCycleRoot (boolean focusCycleRoot) 1547: { 1548: this.focusCycleRoot = focusCycleRoot; 1549: } 1550: 1551: /** 1552: * Check whether this Container is a focus cycle root. 1553: * 1554: * @return true if this is a focus cycle root, false otherwise 1555: * 1556: * @since 1.4 1557: */ 1558: public boolean isFocusCycleRoot () 1559: { 1560: return focusCycleRoot; 1561: } 1562: 1563: /** 1564: * Transfer focus down one focus traversal cycle. If this Container 1565: * is a focus cycle root, then its default component becomes the 1566: * focus owner, and this Container becomes the current focus cycle 1567: * root. No traversal will occur if this Container is not a focus 1568: * cycle root. 1569: * 1570: * @since 1.4 1571: */ 1572: public void transferFocusDownCycle () 1573: { 1574: if (isFocusCycleRoot()) 1575: { 1576: KeyboardFocusManager fm = 1577: KeyboardFocusManager.getCurrentKeyboardFocusManager(); 1578: fm.setGlobalCurrentFocusCycleRoot(this); 1579: FocusTraversalPolicy policy = getFocusTraversalPolicy(); 1580: Component defaultComponent = policy.getDefaultComponent(this); 1581: if (defaultComponent != null) 1582: defaultComponent.requestFocus(); 1583: } 1584: } 1585: 1586: /** 1587: * Sets the ComponentOrientation property of this container and all components 1588: * contained within it. 1589: * 1590: * @exception NullPointerException If orientation is null 1591: * 1592: * @since 1.4 1593: */ 1594: public void applyComponentOrientation (ComponentOrientation orientation) 1595: { 1596: if (orientation == null) 1597: throw new NullPointerException (); 1598: } 1599: 1600: public void addPropertyChangeListener (PropertyChangeListener listener) 1601: { 1602: // TODO: Why is this overridden? 1603: super.addPropertyChangeListener(listener); 1604: } 1605: 1606: public void addPropertyChangeListener (String propertyName, 1607: PropertyChangeListener listener) 1608: { 1609: // TODO: Why is this overridden? 1610: super.addPropertyChangeListener(propertyName, listener); 1611: } 1612: 1613: 1614: /** 1615: * Sets the Z ordering for the component <code>comp</code> to 1616: * <code>index</code>. Components with lower Z order paint above components 1617: * with higher Z order. 1618: * 1619: * @param comp the component for which to change the Z ordering 1620: * @param index the index to set 1621: * 1622: * @throws NullPointerException if <code>comp == null</code> 1623: * @throws IllegalArgumentException if comp is an ancestor of this container 1624: * @throws IllegalArgumentException if <code>index</code> is not in 1625: * <code>[0, getComponentCount()]</code> for moving between 1626: * containers or <code>[0, getComponentCount() - 1]</code> for moving 1627: * inside this container 1628: * @throws IllegalArgumentException if <code>comp == this</code> 1629: * @throws IllegalArgumentException if <code>comp</code> is a 1630: * <code>Window</code> 1631: * 1632: * @see #getComponentZOrder(Component) 1633: * 1634: * @since 1.5 1635: */ 1636: public final void setComponentZOrder(Component comp, int index) 1637: { 1638: if (comp == null) 1639: throw new NullPointerException("comp must not be null"); 1640: if (comp instanceof Container && ((Container) comp).isAncestorOf(this)) 1641: throw new IllegalArgumentException("comp must not be an ancestor of " 1642: + "this"); 1643: if (comp instanceof Window) 1644: throw new IllegalArgumentException("comp must not be a Window"); 1645: 1646: if (comp == this) 1647: throw new IllegalArgumentException("cannot add component to itself"); 1648: 1649: // FIXME: Implement reparenting. 1650: if ( comp.getParent() != this) 1651: throw new AssertionError("Reparenting is not implemented yet"); 1652: else 1653: { 1654: // Find current component index. 1655: int currentIndex = getComponentZOrder(comp); 1656: if (currentIndex < index) 1657: { 1658: System.arraycopy(component, currentIndex + 1, component, 1659: currentIndex, index - currentIndex); 1660: } 1661: else 1662: { 1663: System.arraycopy(component, index, component, index + 1, 1664: currentIndex - index); 1665: } 1666: component[index] = comp; 1667: } 1668: } 1669: 1670: /** 1671: * Returns the Z ordering index of <code>comp</code>. If <code>comp</code> 1672: * is not a child component of this Container, this returns <code>-1</code>. 1673: * 1674: * @param comp the component for which to query the Z ordering 1675: * 1676: * @return the Z ordering index of <code>comp</code> or <code>-1</code> if 1677: * <code>comp</code> is not a child of this Container 1678: * 1679: * @see #setComponentZOrder(Component, int) 1680: * 1681: * @since 1.5 1682: */ 1683: public final int getComponentZOrder(Component comp) 1684: { 1685: int index = -1; 1686: if (component != null) 1687: { 1688: for (int i = 0; i < component.length; i++) 1689: { 1690: if (component[i] == comp) 1691: { 1692: index = i; 1693: break; 1694: } 1695: } 1696: } 1697: return index; 1698: } 1699: 1700: // Hidden helper methods. 1701: 1702: /** 1703: * Perform a graphics operation on the children of this container. 1704: * For each applicable child, the visitChild() method will be called 1705: * to perform the graphics operation. 1706: * 1707: * @param gfx The graphics object that will be used to derive new 1708: * graphics objects for the children. 1709: * 1710: * @param visitor Object encapsulating the graphics operation that 1711: * should be performed. 1712: * 1713: * @param lightweightOnly If true, only lightweight components will 1714: * be visited. 1715: */ 1716: private void visitChildren(Graphics gfx, GfxVisitor visitor, 1717: boolean lightweightOnly) 1718: { 1719: synchronized (getTreeLock()) 1720: { 1721: for (int i = ncomponents - 1; i >= 0; --i) 1722: { 1723: Component comp = component[i]; 1724: boolean applicable = comp.isVisible() 1725: && (comp.isLightweight() || ! lightweightOnly); 1726: 1727: if (applicable) 1728: visitChild(gfx, visitor, comp); 1729: } 1730: } 1731: } 1732: 1733: /** 1734: * Perform a graphics operation on a child. A translated and clipped 1735: * graphics object will be created, and the visit() method of the 1736: * visitor will be called to perform the operation. 1737: * 1738: * @param gfx The graphics object that will be used to derive new 1739: * graphics objects for the child. 1740: * 1741: * @param visitor Object encapsulating the graphics operation that 1742: * should be performed. 1743: * 1744: * @param comp The child component that should be visited. 1745: */ 1746: private void visitChild(Graphics gfx, GfxVisitor visitor, 1747: Component comp) 1748: { 1749: Rectangle bounds = comp.getBounds(); 1750: 1751: if(!gfx.hitClip(bounds.x,bounds.y, bounds.width, bounds.height)) 1752: return; 1753: Graphics g2 = gfx.create(bounds.x, bounds.y, bounds.width, 1754: bounds.height); 1755: try 1756: { 1757: visitor.visit(comp, g2); 1758: } 1759: finally 1760: { 1761: g2.dispose(); 1762: } 1763: } 1764: 1765: void dispatchEventImpl(AWTEvent e) 1766: { 1767: boolean dispatched = 1768: LightweightDispatcher.getInstance().dispatchEvent(e); 1769: if (! dispatched) 1770: { 1771: if ((e.id <= ContainerEvent.CONTAINER_LAST 1772: && e.id >= ContainerEvent.CONTAINER_FIRST) 1773: && (containerListener != null 1774: || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0)) 1775: processEvent(e); 1776: else 1777: super.dispatchEventImpl(e); 1778: } 1779: } 1780: 1781: /** 1782: * Tests if this container has an interest in the given event id. 1783: * 1784: * @param eventId The event id to check. 1785: * 1786: * @return <code>true</code> if a listener for the event id exists or 1787: * if the eventMask is set for the event id. 1788: * 1789: * @see java.awt.Component#eventTypeEnabled(int) 1790: */ 1791: boolean eventTypeEnabled(int eventId) 1792: { 1793: if(eventId <= ContainerEvent.CONTAINER_LAST 1794: && eventId >= ContainerEvent.CONTAINER_FIRST) 1795: return containerListener != null 1796: || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0; 1797: else 1798: return super.eventTypeEnabled(eventId); 1799: } 1800: 1801: // This is used to implement Component.transferFocus. 1802: Component findNextFocusComponent(Component child) 1803: { 1804: synchronized (getTreeLock ()) 1805: { 1806: int start, end; 1807: if (child != null) 1808: { 1809: for (start = 0; start < ncomponents; ++start) 1810: { 1811: if (component[start] == child) 1812: break; 1813: } 1814: end = start; 1815: // This special case lets us be sure to terminate. 1816: if (end == 0) 1817: end = ncomponents; 1818: ++start; 1819: } 1820: else 1821: { 1822: start = 0; 1823: end = ncomponents; 1824: } 1825: 1826: for (int j = start; j != end; ++j) 1827: { 1828: if (j >= ncomponents) 1829: { 1830: // The JCL says that we should wrap here. However, that 1831: // seems wrong. To me it seems that focus order should be 1832: // global within in given window. So instead if we reach 1833: // the end we try to look in our parent, if we have one. 1834: if (parent != null) 1835: return parent.findNextFocusComponent(this); 1836: j -= ncomponents; 1837: } 1838: if (component[j] instanceof Container) 1839: { 1840: Component c = component[j]; 1841: c = c.findNextFocusComponent(null); 1842: if (c != null) 1843: return c; 1844: } 1845: else if (component[j].isFocusTraversable()) 1846: return component[j]; 1847: } 1848: 1849: return null; 1850: } 1851: } 1852: 1853: private void addNotifyContainerChildren() 1854: { 1855: synchronized (getTreeLock ()) 1856: { 1857: for (int i = ncomponents; --i >= 0; ) 1858: { 1859: component[i].addNotify(); 1860: if (component[i].isLightweight ()) 1861: { 1862: enableEvents(component[i].eventMask); 1863: if (peer != null && !isLightweight ()) 1864: enableEvents (AWTEvent.PAINT_EVENT_MASK); 1865: } 1866: } 1867: } 1868: } 1869: 1870: /** 1871: * Deserialize this Container: 1872: * <ol> 1873: * <li>Read from the stream the default serializable fields.</li> 1874: * <li>Read a list of serializable ContainerListeners as optional 1875: * data. If the list is null, no listeners will be registered.</li> 1876: * <li>Read this Container's FocusTraversalPolicy as optional data. 1877: * If this is null, then this Container will use a 1878: * DefaultFocusTraversalPolicy.</li> 1879: * </ol> 1880: * 1881: * @param s the stream to read from 1882: * @throws ClassNotFoundException if deserialization fails 1883: * @throws IOException if the stream fails 1884: */ 1885: private void readObject (ObjectInputStream s) 1886: throws ClassNotFoundException, IOException 1887: { 1888: s.defaultReadObject (); 1889: String key = (String) s.readObject (); 1890: while (key != null) 1891: { 1892: Object object = s.readObject (); 1893: if ("containerL".equals (key)) 1894: addContainerListener((ContainerListener) object); 1895: // FIXME: under what key is the focus traversal policy stored? 1896: else if ("focusTraversalPolicy".equals (key)) 1897: setFocusTraversalPolicy ((FocusTraversalPolicy) object); 1898: 1899: key = (String) s.readObject(); 1900: } 1901: } 1902: 1903: /** 1904: * Serialize this Container: 1905: * <ol> 1906: * <li>Write to the stream the default serializable fields.</li> 1907: * <li>Write the list of serializable ContainerListeners as optional 1908: * data.</li> 1909: * <li>Write this Container's FocusTraversalPolicy as optional data.</li> 1910: * </ol> 1911: * 1912: * @param s the stream to write to 1913: * @throws IOException if the stream fails 1914: */ 1915: private void writeObject (ObjectOutputStream s) throws IOException 1916: { 1917: s.defaultWriteObject (); 1918: AWTEventMulticaster.save (s, "containerL", containerListener); 1919: if (focusTraversalPolicy instanceof Serializable) 1920: s.writeObject (focusTraversalPolicy); 1921: else 1922: s.writeObject (null); 1923: } 1924: 1925: // Nested classes. 1926: 1927: /* The following classes are used in concert with the 1928: visitChildren() method to implement all the graphics operations 1929: that requires traversal of the containment hierarchy. */ 1930: 1931: abstract static class GfxVisitor 1932: { 1933: public abstract void visit(Component c, Graphics gfx); 1934: } 1935: 1936: static class GfxPaintVisitor extends GfxVisitor 1937: { 1938: public static final GfxVisitor INSTANCE = new GfxPaintVisitor(); 1939: 1940: public void visit(Component c, Graphics gfx) 1941: { 1942: c.paint(gfx); 1943: } 1944: } 1945: 1946: static class GfxPrintVisitor extends GfxVisitor 1947: { 1948: public static final GfxVisitor INSTANCE = new GfxPrintVisitor(); 1949: 1950: public void visit(Component c, Graphics gfx) 1951: { 1952: c.print(gfx); 1953: } 1954: } 1955: 1956: static class GfxPaintAllVisitor extends GfxVisitor 1957: { 1958: public static final GfxVisitor INSTANCE = new GfxPaintAllVisitor(); 1959: 1960: public void visit(Component c, Graphics gfx) 1961: { 1962: c.paintAll(gfx); 1963: } 1964: } 1965: 1966: static class GfxPrintAllVisitor extends GfxVisitor 1967: { 1968: public static final GfxVisitor INSTANCE = new GfxPrintAllVisitor(); 1969: 1970: public void visit(Component c, Graphics gfx) 1971: { 1972: c.printAll(gfx); 1973: } 1974: } 1975: 1976: /** 1977: * This class provides accessibility support for subclasses of container. 1978: * 1979: * @author Eric Blake (ebb9@email.byu.edu) 1980: * 1981: * @since 1.3 1982: */ 1983: protected class AccessibleAWTContainer extends AccessibleAWTComponent 1984: { 1985: /** 1986: * Compatible with JDK 1.4+. 1987: */ 1988: private static final long serialVersionUID = 5081320404842566097L; 1989: 1990: /** 1991: * The handler to fire PropertyChange when children are added or removed. 1992: * 1993: * @serial the handler for property changes 1994: */ 1995: protected ContainerListener accessibleContainerHandler 1996: = new AccessibleContainerHandler(); 1997: 1998: /** 1999: * The default constructor. 2000: */ 2001: protected AccessibleAWTContainer() 2002: { 2003: Container.this.addContainerListener(accessibleContainerHandler); 2004: } 2005: 2006: /** 2007: * Return the number of accessible children of the containing accessible 2008: * object (at most the total number of its children). 2009: * 2010: * @return the number of accessible children 2011: */ 2012: public int getAccessibleChildrenCount() 2013: { 2014: synchronized (getTreeLock ()) 2015: { 2016: int count = 0; 2017: int i = component == null ? 0 : component.length; 2018: while (--i >= 0) 2019: if (component[i] instanceof Accessible) 2020: count++; 2021: return count; 2022: } 2023: } 2024: 2025: /** 2026: * Return the nth accessible child of the containing accessible object. 2027: * 2028: * @param i the child to grab, zero-based 2029: * @return the accessible child, or null 2030: */ 2031: public Accessible getAccessibleChild(int i) 2032: { 2033: synchronized (getTreeLock ()) 2034: { 2035: if (component == null) 2036: return null; 2037: int index = -1; 2038: while (i >= 0 && ++index < component.length) 2039: if (component[index] instanceof Accessible) 2040: i--; 2041: if (i < 0) 2042: return (Accessible) component[index]; 2043: return null; 2044: } 2045: } 2046: 2047: /** 2048: * Return the accessible child located at point (in the parent's 2049: * coordinates), if one exists. 2050: * 2051: * @param p the point to look at 2052: * 2053: * @return an accessible object at that point, or null 2054: * 2055: * @throws NullPointerException if p is null 2056: */ 2057: public Accessible getAccessibleAt(Point p) 2058: { 2059: Component c = getComponentAt(p.x, p.y); 2060: return c != Container.this && c instanceof Accessible ? (Accessible) c 2061: : null; 2062: } 2063: 2064: /** 2065: * This class fires a <code>PropertyChange</code> listener, if registered, 2066: * when children are added or removed from the enclosing accessible object. 2067: * 2068: * @author Eric Blake (ebb9@email.byu.edu) 2069: * 2070: * @since 1.3 2071: */ 2072: protected class AccessibleContainerHandler implements ContainerListener 2073: { 2074: /** 2075: * Default constructor. 2076: */ 2077: protected AccessibleContainerHandler() 2078: { 2079: // Nothing to do here. 2080: } 2081: 2082: /** 2083: * Fired when a component is added; forwards to the PropertyChange 2084: * listener. 2085: * 2086: * @param e the container event for adding 2087: */ 2088: public void componentAdded(ContainerEvent e) 2089: { 2090: AccessibleAWTContainer.this.firePropertyChange 2091: (ACCESSIBLE_CHILD_PROPERTY, null, e.getChild()); 2092: } 2093: 2094: /** 2095: * Fired when a component is removed; forwards to the PropertyChange 2096: * listener. 2097: * 2098: * @param e the container event for removing 2099: */ 2100: public void componentRemoved(ContainerEvent e) 2101: { 2102: AccessibleAWTContainer.this.firePropertyChange 2103: (ACCESSIBLE_CHILD_PROPERTY, e.getChild(), null); 2104: } 2105: } // class AccessibleContainerHandler 2106: } // class AccessibleAWTContainer 2107: } // class Container