GNU Classpath (0.91) | |
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: while (ncomponents > 0) 461: remove(0); 462: } 463: } 464: 465: /** 466: * Returns the current layout manager for this container. 467: * 468: * @return The layout manager for this container. 469: */ 470: public LayoutManager getLayout() 471: { 472: return layoutMgr; 473: } 474: 475: /** 476: * Sets the layout manager for this container to the specified layout 477: * manager. 478: * 479: * @param mgr The new layout manager for this container. 480: */ 481: public void setLayout(LayoutManager mgr) 482: { 483: layoutMgr = mgr; 484: invalidate(); 485: } 486: 487: /** 488: * Layout the components in this container. 489: */ 490: public void doLayout() 491: { 492: layout (); 493: } 494: 495: /** 496: * Layout the components in this container. 497: * 498: * @deprecated use {@link #doLayout()} instead 499: */ 500: public void layout() 501: { 502: if (layoutMgr != null) 503: layoutMgr.layoutContainer (this); 504: } 505: 506: /** 507: * Invalidates this container to indicate that it (and all parent 508: * containers) need to be laid out. 509: */ 510: public void invalidate() 511: { 512: super.invalidate(); 513: if (layoutMgr != null && layoutMgr instanceof LayoutManager2) 514: { 515: LayoutManager2 lm2 = (LayoutManager2) layoutMgr; 516: lm2.invalidateLayout(this); 517: } 518: } 519: 520: /** 521: * Re-lays out the components in this container. 522: */ 523: public void validate() 524: { 525: synchronized (getTreeLock ()) 526: { 527: if (! isValid() && peer != null) 528: { 529: validateTree(); 530: } 531: } 532: } 533: 534: /** 535: * Recursively invalidates the container tree. 536: */ 537: void invalidateTree() 538: { 539: super.invalidate(); // Clean cached layout state. 540: for (int i = 0; i < ncomponents; i++) 541: { 542: Component comp = component[i]; 543: comp.invalidate(); 544: if (comp instanceof Container) 545: ((Container) comp).invalidateTree(); 546: } 547: 548: if (layoutMgr != null && layoutMgr instanceof LayoutManager2) 549: { 550: LayoutManager2 lm2 = (LayoutManager2) layoutMgr; 551: lm2.invalidateLayout(this); 552: } 553: } 554: 555: /** 556: * Recursively validates the container tree, recomputing any invalid 557: * layouts. 558: */ 559: protected void validateTree() 560: { 561: if (valid) 562: return; 563: 564: ContainerPeer cPeer = null; 565: if (peer != null && ! (peer instanceof LightweightPeer)) 566: { 567: cPeer = (ContainerPeer) peer; 568: cPeer.beginValidate(); 569: } 570: 571: for (int i = 0; i < ncomponents; ++i) 572: { 573: Component comp = component[i]; 574: 575: if (comp.getPeer () == null) 576: comp.addNotify(); 577: } 578: 579: doLayout (); 580: for (int i = 0; i < ncomponents; ++i) 581: { 582: Component comp = component[i]; 583: 584: if (! comp.isValid()) 585: { 586: if (comp instanceof Container) 587: { 588: ((Container) comp).validateTree(); 589: } 590: else 591: { 592: component[i].validate(); 593: } 594: } 595: } 596: 597: /* children will call invalidate() when they are layed out. It 598: is therefore important that valid is not set to true 599: until after the children have been layed out. */ 600: valid = true; 601: 602: if (cPeer != null) 603: cPeer.endValidate(); 604: } 605: 606: public void setFont(Font f) 607: { 608: if( (f != null && (font == null || !font.equals(f))) 609: || f == null) 610: { 611: super.setFont(f); 612: // FIXME: Although it might make more sense to invalidate only 613: // those children whose font == null, Sun invalidates all children. 614: // So we'll do the same. 615: invalidateTree(); 616: } 617: } 618: 619: /** 620: * Returns the preferred size of this container. 621: * 622: * @return The preferred size of this container. 623: */ 624: public Dimension getPreferredSize() 625: { 626: return preferredSize (); 627: } 628: 629: /** 630: * Returns the preferred size of this container. 631: * 632: * @return The preferred size of this container. 633: * 634: * @deprecated use {@link #getPreferredSize()} instead 635: */ 636: public Dimension preferredSize() 637: { 638: synchronized(treeLock) 639: { 640: if(valid && prefSize != null) 641: return new Dimension(prefSize); 642: LayoutManager layout = getLayout(); 643: if (layout != null) 644: { 645: Dimension layoutSize = layout.preferredLayoutSize(this); 646: if(valid) 647: prefSize = layoutSize; 648: return new Dimension(layoutSize); 649: } 650: else 651: return super.preferredSize (); 652: } 653: } 654: 655: /** 656: * Returns the minimum size of this container. 657: * 658: * @return The minimum size of this container. 659: */ 660: public Dimension getMinimumSize() 661: { 662: return minimumSize (); 663: } 664: 665: /** 666: * Returns the minimum size of this container. 667: * 668: * @return The minimum size of this container. 669: * 670: * @deprecated use {@link #getMinimumSize()} instead 671: */ 672: public Dimension minimumSize() 673: { 674: if(valid && minSize != null) 675: return new Dimension(minSize); 676: 677: LayoutManager layout = getLayout(); 678: if (layout != null) 679: { 680: minSize = layout.minimumLayoutSize (this); 681: return minSize; 682: } 683: else 684: return super.minimumSize (); 685: } 686: 687: /** 688: * Returns the maximum size of this container. 689: * 690: * @return The maximum size of this container. 691: */ 692: public Dimension getMaximumSize() 693: { 694: if (valid && maxSize != null) 695: return new Dimension(maxSize); 696: 697: LayoutManager layout = getLayout(); 698: if (layout != null && layout instanceof LayoutManager2) 699: { 700: LayoutManager2 lm2 = (LayoutManager2) layout; 701: maxSize = lm2.maximumLayoutSize(this); 702: return maxSize; 703: } 704: else 705: return super.getMaximumSize(); 706: } 707: 708: /** 709: * Returns the preferred alignment along the X axis. This is a value 710: * between 0 and 1 where 0 represents alignment flush left and 711: * 1 means alignment flush right, and 0.5 means centered. 712: * 713: * @return The preferred alignment along the X axis. 714: */ 715: public float getAlignmentX() 716: { 717: LayoutManager layout = getLayout(); 718: float alignmentX = 0.0F; 719: if (layout != null && layout instanceof LayoutManager2) 720: { 721: LayoutManager2 lm2 = (LayoutManager2) layout; 722: alignmentX = lm2.getLayoutAlignmentX(this); 723: } 724: else 725: alignmentX = super.getAlignmentX(); 726: return alignmentX; 727: } 728: 729: /** 730: * Returns the preferred alignment along the Y axis. This is a value 731: * between 0 and 1 where 0 represents alignment flush top and 732: * 1 means alignment flush bottom, and 0.5 means centered. 733: * 734: * @return The preferred alignment along the Y axis. 735: */ 736: public float getAlignmentY() 737: { 738: LayoutManager layout = getLayout(); 739: float alignmentY = 0.0F; 740: if (layout != null && layout instanceof LayoutManager2) 741: { 742: LayoutManager2 lm2 = (LayoutManager2) layout; 743: alignmentY = lm2.getLayoutAlignmentY(this); 744: } 745: else 746: alignmentY = super.getAlignmentY(); 747: return alignmentY; 748: } 749: 750: /** 751: * Paints this container. The implementation of this method in this 752: * class forwards to any lightweight components in this container. If 753: * this method is subclassed, this method should still be invoked as 754: * a superclass method so that lightweight components are properly 755: * drawn. 756: * 757: * @param g - The graphics context for this paint job. 758: */ 759: public void paint(Graphics g) 760: { 761: if (!isShowing()) 762: return; 763: 764: // Visit heavyweights if the background was cleared 765: // for this container. 766: visitChildren(g, GfxPaintVisitor.INSTANCE, !backCleared); 767: backCleared = false; 768: } 769: 770: /** 771: * Updates this container. The implementation of this method in this 772: * class forwards to any lightweight components in this container. If 773: * this method is subclassed, this method should still be invoked as 774: * a superclass method so that lightweight components are properly 775: * drawn. 776: * 777: * @param g The graphics context for this update. 778: * 779: * @specnote The specification suggests that this method forwards the 780: * update() call to all its lightweight children. Tests show 781: * that this is not done either in the JDK. The exact behaviour 782: * seems to be that the background is cleared in heavyweight 783: * Containers, and all other containers 784: * directly call paint(), causing the (lightweight) children to 785: * be painted. 786: */ 787: public void update(Graphics g) 788: { 789: // It seems that the JDK clears the background of containers like Panel 790: // and Window (within this method) but not of 'plain' Containers or 791: // JComponents. This could 792: // lead to the assumption that it only clears heavyweight containers. 793: // However that is not quite true. In a test with a custom Container 794: // that overrides isLightweight() to return false, the background is 795: // also not cleared. So we do a check on !(peer instanceof LightweightPeer) 796: // instead. 797: ComponentPeer p = peer; 798: if (p != null && ! (p instanceof LightweightPeer)) 799: { 800: g.clearRect(0, 0, getWidth(), getHeight()); 801: backCleared = true; 802: } 803: 804: paint(g); 805: } 806: 807: /** 808: * Prints this container. The implementation of this method in this 809: * class forwards to any lightweight components in this container. If 810: * this method is subclassed, this method should still be invoked as 811: * a superclass method so that lightweight components are properly 812: * drawn. 813: * 814: * @param g The graphics context for this print job. 815: */ 816: public void print(Graphics g) 817: { 818: super.print(g); 819: visitChildren(g, GfxPrintVisitor.INSTANCE, true); 820: } 821: 822: /** 823: * Paints all of the components in this container. 824: * 825: * @param g The graphics context for this paint job. 826: */ 827: public void paintComponents(Graphics g) 828: { 829: paint(g); 830: visitChildren(g, GfxPaintAllVisitor.INSTANCE, true); 831: } 832: 833: /** 834: * Prints all of the components in this container. 835: * 836: * @param g The graphics context for this print job. 837: */ 838: public void printComponents(Graphics g) 839: { 840: super.paint(g); 841: visitChildren(g, GfxPrintAllVisitor.INSTANCE, true); 842: } 843: 844: /** 845: * Adds the specified container listener to this object's list of 846: * container listeners. 847: * 848: * @param listener The listener to add. 849: */ 850: public synchronized void addContainerListener(ContainerListener listener) 851: { 852: containerListener = AWTEventMulticaster.add(containerListener, listener); 853: } 854: 855: /** 856: * Removes the specified container listener from this object's list of 857: * container listeners. 858: * 859: * @param listener The listener to remove. 860: */ 861: public synchronized void removeContainerListener(ContainerListener listener) 862: { 863: containerListener = AWTEventMulticaster.remove(containerListener, listener); 864: } 865: 866: /** 867: * @since 1.4 868: */ 869: public synchronized ContainerListener[] getContainerListeners() 870: { 871: return (ContainerListener[]) 872: AWTEventMulticaster.getListeners(containerListener, 873: ContainerListener.class); 874: } 875: 876: /** 877: * Returns all registered {@link EventListener}s of the given 878: * <code>listenerType</code>. 879: * 880: * @param listenerType the class of listeners to filter (<code>null</code> 881: * not permitted). 882: * 883: * @return An array of registered listeners. 884: * 885: * @throws ClassCastException if <code>listenerType</code> does not implement 886: * the {@link EventListener} interface. 887: * @throws NullPointerException if <code>listenerType</code> is 888: * <code>null</code>. 889: * 890: * @see #getContainerListeners() 891: * 892: * @since 1.3 893: */ 894: public EventListener[] getListeners(Class listenerType) 895: { 896: if (listenerType == ContainerListener.class) 897: return getContainerListeners(); 898: return super.getListeners(listenerType); 899: } 900: 901: /** 902: * Processes the specified event. This method calls 903: * <code>processContainerEvent()</code> if this method is a 904: * <code>ContainerEvent</code>, otherwise it calls the superclass 905: * method. 906: * 907: * @param e The event to be processed. 908: */ 909: protected void processEvent(AWTEvent e) 910: { 911: if (e instanceof ContainerEvent) 912: processContainerEvent((ContainerEvent) e); 913: else 914: super.processEvent(e); 915: } 916: 917: /** 918: * Called when a container event occurs if container events are enabled. 919: * This method calls any registered listeners. 920: * 921: * @param e The event that occurred. 922: */ 923: protected void processContainerEvent(ContainerEvent e) 924: { 925: if (containerListener == null) 926: return; 927: switch (e.id) 928: { 929: case ContainerEvent.COMPONENT_ADDED: 930: containerListener.componentAdded(e); 931: break; 932: 933: case ContainerEvent.COMPONENT_REMOVED: 934: containerListener.componentRemoved(e); 935: break; 936: } 937: } 938: 939: /** 940: * AWT 1.0 event processor. 941: * 942: * @param e The event that occurred. 943: * 944: * @deprecated use {@link #dispatchEvent(AWTEvent)} instead 945: */ 946: public void deliverEvent(Event e) 947: { 948: if (!handleEvent (e)) 949: { 950: synchronized (getTreeLock ()) 951: { 952: Component parent = getParent (); 953: 954: if (parent != null) 955: parent.deliverEvent (e); 956: } 957: } 958: } 959: 960: /** 961: * Returns the component located at the specified point. This is done 962: * by checking whether or not a child component claims to contain this 963: * point. The first child component that does is returned. If no 964: * child component claims the point, the container itself is returned, 965: * unless the point does not exist within this container, in which 966: * case <code>null</code> is returned. 967: * 968: * When components overlap, the first component is returned. The component 969: * that is closest to (x, y), containing that location, is returned. 970: * Heavyweight components take precedence of lightweight components. 971: * 972: * This function does not ignore invisible components. If there is an invisible 973: * component at (x,y), it will be returned. 974: * 975: * @param x The X coordinate of the point. 976: * @param y The Y coordinate of the point. 977: * 978: * @return The component containing the specified point, or 979: * <code>null</code> if there is no such point. 980: */ 981: public Component getComponentAt(int x, int y) 982: { 983: return locate (x, y); 984: } 985: 986: /** 987: * Returns the component located at the specified point. This is done 988: * by checking whether or not a child component claims to contain this 989: * point. The first child component that does is returned. If no 990: * child component claims the point, the container itself is returned, 991: * unless the point does not exist within this container, in which 992: * case <code>null</code> is returned. 993: * 994: * When components overlap, the first component is returned. The component 995: * that is closest to (x, y), containing that location, is returned. 996: * Heavyweight components take precedence of lightweight components. 997: * 998: * This function does not ignore invisible components. If there is an invisible 999: * component at (x,y), it will be returned. 1000: * 1001: * @param x The x position of the point to return the component at. 1002: * @param y The y position of the point to return the component at. 1003: * 1004: * @return The component containing the specified point, or <code>null</code> 1005: * if there is no such point. 1006: * 1007: * @deprecated use {@link #getComponentAt(int, int)} instead 1008: */ 1009: public Component locate(int x, int y) 1010: { 1011: synchronized (getTreeLock ()) 1012: { 1013: if (!contains (x, y)) 1014: return null; 1015: 1016: // First find the component closest to (x,y) that is a heavyweight. 1017: for (int i = 0; i < ncomponents; ++i) 1018: { 1019: Component comp = component[i]; 1020: int x2 = x - comp.x; 1021: int y2 = y - comp.y; 1022: if (comp.contains (x2, y2) && !comp.isLightweight()) 1023: return comp; 1024: } 1025: 1026: // if a heavyweight component is not found, look for a lightweight 1027: // closest to (x,y). 1028: for (int i = 0; i < ncomponents; ++i) 1029: { 1030: Component comp = component[i]; 1031: int x2 = x - comp.x; 1032: int y2 = y - comp.y; 1033: if (comp.contains (x2, y2) && comp.isLightweight()) 1034: return comp; 1035: } 1036: 1037: return this; 1038: } 1039: } 1040: 1041: /** 1042: * Returns the component located at the specified point. This is done 1043: * by checking whether or not a child component claims to contain this 1044: * point. The first child component that does is returned. If no 1045: * child component claims the point, the container itself is returned, 1046: * unless the point does not exist within this container, in which 1047: * case <code>null</code> is returned. 1048: * 1049: * The top-most child component is returned in the case where components overlap. 1050: * This is determined by finding the component closest to (x,y) and contains 1051: * that location. Heavyweight components take precedence of lightweight components. 1052: * 1053: * This function does not ignore invisible components. If there is an invisible 1054: * component at (x,y), it will be returned. 1055: * 1056: * @param p The point to return the component at. 1057: * @return The component containing the specified point, or <code>null</code> 1058: * if there is no such point. 1059: */ 1060: public Component getComponentAt(Point p) 1061: { 1062: return getComponentAt (p.x, p.y); 1063: } 1064: 1065: /** 1066: * Locates the visible child component that contains the specified position. 1067: * The top-most child component is returned in the case where there is overlap 1068: * in the components. If the containing child component is a Container, 1069: * this method will continue searching for the deepest nested child 1070: * component. Components which are not visible are ignored during the search. 1071: * 1072: * findComponentAt differs from getComponentAt, because it recursively 1073: * searches a Container's children. 1074: * 1075: * @param x - x coordinate 1076: * @param y - y coordinate 1077: * @return null if the component does not contain the position. 1078: * If there is no child component at the requested point and the point is 1079: * within the bounds of the container the container itself is returned. 1080: */ 1081: public Component findComponentAt(int x, int y) 1082: { 1083: synchronized (getTreeLock ()) 1084: { 1085: if (! contains(x, y)) 1086: return null; 1087: 1088: for (int i = 0; i < ncomponents; ++i) 1089: { 1090: // Ignore invisible children... 1091: if (!component[i].isVisible()) 1092: continue; 1093: 1094: int x2 = x - component[i].x; 1095: int y2 = y - component[i].y; 1096: // We don't do the contains() check right away because 1097: // findComponentAt would redundantly do it first thing. 1098: if (component[i] instanceof Container) 1099: { 1100: Container k = (Container) component[i]; 1101: Component r = k.findComponentAt(x2, y2); 1102: if (r != null) 1103: return r; 1104: } 1105: else if (component[i].contains(x2, y2)) 1106: return component[i]; 1107: } 1108: 1109: return this; 1110: } 1111: } 1112: 1113: /** 1114: * Locates the visible child component that contains the specified position. 1115: * The top-most child component is returned in the case where there is overlap 1116: * in the components. If the containing child component is a Container, 1117: * this method will continue searching for the deepest nested child 1118: * component. Components which are not visible are ignored during the search. 1119: * 1120: * findComponentAt differs from getComponentAt, because it recursively 1121: * searches a Container's children. 1122: * 1123: * @param p - the component's location 1124: * @return null if the component does not contain the position. 1125: * If there is no child component at the requested point and the point is 1126: * within the bounds of the container the container itself is returned. 1127: */ 1128: public Component findComponentAt(Point p) 1129: { 1130: return findComponentAt(p.x, p.y); 1131: } 1132: 1133: /** 1134: * Called when this container is added to another container to inform it 1135: * to create its peer. Peers for any child components will also be 1136: * created. 1137: */ 1138: public void addNotify() 1139: { 1140: super.addNotify(); 1141: addNotifyContainerChildren(); 1142: } 1143: 1144: /** 1145: * Called when this container is removed from its parent container to 1146: * inform it to destroy its peer. This causes the peers of all child 1147: * component to be destroyed as well. 1148: */ 1149: public void removeNotify() 1150: { 1151: synchronized (getTreeLock ()) 1152: { 1153: for (int i = 0; i < ncomponents; ++i) 1154: component[i].removeNotify(); 1155: super.removeNotify(); 1156: } 1157: } 1158: 1159: /** 1160: * Tests whether or not the specified component is contained within 1161: * this components subtree. 1162: * 1163: * @param comp The component to test. 1164: * 1165: * @return <code>true</code> if this container is an ancestor of the 1166: * specified component, <code>false</code> otherwise. 1167: */ 1168: public boolean isAncestorOf(Component comp) 1169: { 1170: synchronized (getTreeLock ()) 1171: { 1172: while (true) 1173: { 1174: if (comp == null) 1175: return false; 1176: if (comp == this) 1177: return true; 1178: comp = comp.getParent(); 1179: } 1180: } 1181: } 1182: 1183: /** 1184: * Returns a string representing the state of this container for 1185: * debugging purposes. 1186: * 1187: * @return A string representing the state of this container. 1188: */ 1189: protected String paramString() 1190: { 1191: if (layoutMgr == null) 1192: return super.paramString(); 1193: 1194: StringBuffer sb = new StringBuffer(); 1195: sb.append(super.paramString()); 1196: sb.append(",layout="); 1197: sb.append(layoutMgr.getClass().getName()); 1198: return sb.toString(); 1199: } 1200: 1201: /** 1202: * Writes a listing of this container to the specified stream starting 1203: * at the specified indentation point. 1204: * 1205: * @param out The <code>PrintStream</code> to write to. 1206: * @param indent The indentation point. 1207: */ 1208: public void list(PrintStream out, int indent) 1209: { 1210: synchronized (getTreeLock ()) 1211: { 1212: super.list(out, indent); 1213: for (int i = 0; i < ncomponents; ++i) 1214: component[i].list(out, indent + 2); 1215: } 1216: } 1217: 1218: /** 1219: * Writes a listing of this container to the specified stream starting 1220: * at the specified indentation point. 1221: * 1222: * @param out The <code>PrintWriter</code> to write to. 1223: * @param indent The indentation point. 1224: */ 1225: public void list(PrintWriter out, int indent) 1226: { 1227: synchronized (getTreeLock ()) 1228: { 1229: super.list(out, indent); 1230: for (int i = 0; i < ncomponents; ++i) 1231: component[i].list(out, indent + 2); 1232: } 1233: } 1234: 1235: /** 1236: * Sets the focus traversal keys for a given traversal operation for this 1237: * Container. 1238: * 1239: * @exception IllegalArgumentException If id is not one of 1240: * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 1241: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 1242: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, 1243: * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, 1244: * or if keystrokes contains null, or if any Object in keystrokes is not an 1245: * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event, or if any 1246: * keystroke already maps to another focus traversal operation for this 1247: * Container. 1248: * 1249: * @since 1.4 1250: */ 1251: public void setFocusTraversalKeys(int id, Set keystrokes) 1252: { 1253: if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && 1254: id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && 1255: id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && 1256: id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) 1257: throw new IllegalArgumentException (); 1258: 1259: if (keystrokes == null) 1260: { 1261: Container parent = getParent (); 1262: 1263: while (parent != null) 1264: { 1265: if (parent.areFocusTraversalKeysSet (id)) 1266: { 1267: keystrokes = parent.getFocusTraversalKeys (id); 1268: break; 1269: } 1270: parent = parent.getParent (); 1271: } 1272: 1273: if (keystrokes == null) 1274: keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager (). 1275: getDefaultFocusTraversalKeys (id); 1276: } 1277: 1278: Set sa; 1279: Set sb; 1280: Set sc; 1281: String name; 1282: switch (id) 1283: { 1284: case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: 1285: sa = getFocusTraversalKeys 1286: (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 1287: sb = getFocusTraversalKeys 1288: (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); 1289: sc = getFocusTraversalKeys 1290: (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); 1291: name = "forwardFocusTraversalKeys"; 1292: break; 1293: case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: 1294: sa = getFocusTraversalKeys 1295: (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 1296: sb = getFocusTraversalKeys 1297: (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); 1298: sc = getFocusTraversalKeys 1299: (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); 1300: name = "backwardFocusTraversalKeys"; 1301: break; 1302: case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: 1303: sa = getFocusTraversalKeys 1304: (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 1305: sb = getFocusTraversalKeys 1306: (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 1307: sc = getFocusTraversalKeys 1308: (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); 1309: name = "upCycleFocusTraversalKeys"; 1310: break; 1311: case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS: 1312: sa = getFocusTraversalKeys 1313: (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 1314: sb = getFocusTraversalKeys 1315: (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 1316: sc = getFocusTraversalKeys 1317: (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); 1318: name = "downCycleFocusTraversalKeys"; 1319: break; 1320: default: 1321: throw new IllegalArgumentException (); 1322: } 1323: 1324: int i = keystrokes.size (); 1325: Iterator iter = keystrokes.iterator (); 1326: 1327: while (--i >= 0) 1328: { 1329: Object o = iter.next (); 1330: if (!(o instanceof AWTKeyStroke) 1331: || sa.contains (o) || sb.contains (o) || sc.contains (o) 1332: || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) 1333: throw new IllegalArgumentException (); 1334: } 1335: 1336: if (focusTraversalKeys == null) 1337: focusTraversalKeys = new Set[4]; 1338: 1339: keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes)); 1340: firePropertyChange (name, focusTraversalKeys[id], keystrokes); 1341: 1342: focusTraversalKeys[id] = keystrokes; 1343: } 1344: 1345: /** 1346: * Returns the Set of focus traversal keys for a given traversal operation for 1347: * this Container. 1348: * 1349: * @exception IllegalArgumentException If id is not one of 1350: * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 1351: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 1352: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, 1353: * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. 1354: * 1355: * @since 1.4 1356: */ 1357: public Set getFocusTraversalKeys (int id) 1358: { 1359: if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && 1360: id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && 1361: id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && 1362: id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) 1363: throw new IllegalArgumentException (); 1364: 1365: Set s = null; 1366: 1367: if (focusTraversalKeys != null) 1368: s = focusTraversalKeys[id]; 1369: 1370: if (s == null && parent != null) 1371: s = parent.getFocusTraversalKeys (id); 1372: 1373: return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager() 1374: .getDefaultFocusTraversalKeys(id)) : s; 1375: } 1376: 1377: /** 1378: * Returns whether the Set of focus traversal keys for the given focus 1379: * traversal operation has been explicitly defined for this Container. 1380: * If this method returns false, this Container is inheriting the Set from 1381: * an ancestor, or from the current KeyboardFocusManager. 1382: * 1383: * @exception IllegalArgumentException If id is not one of 1384: * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 1385: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 1386: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, 1387: * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. 1388: * 1389: * @since 1.4 1390: */ 1391: public boolean areFocusTraversalKeysSet (int id) 1392: { 1393: if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && 1394: id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && 1395: id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && 1396: id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) 1397: throw new IllegalArgumentException (); 1398: 1399: return focusTraversalKeys != null && focusTraversalKeys[id] != null; 1400: } 1401: 1402: /** 1403: * Check whether the given Container is the focus cycle root of this 1404: * Container's focus traversal cycle. If this Container is a focus 1405: * cycle root itself, then it will be in two different focus cycles 1406: * -- it's own, and that of its ancestor focus cycle root's. In 1407: * that case, if <code>c</code> is either of those containers, this 1408: * method will return true. 1409: * 1410: * @param c the candidate Container 1411: * 1412: * @return true if c is the focus cycle root of the focus traversal 1413: * cycle to which this Container belongs, false otherwise 1414: * 1415: * @since 1.4 1416: */ 1417: public boolean isFocusCycleRoot (Container c) 1418: { 1419: if (this == c 1420: && isFocusCycleRoot ()) 1421: return true; 1422: 1423: Container ancestor = getFocusCycleRootAncestor (); 1424: 1425: if (c == ancestor) 1426: return true; 1427: 1428: return false; 1429: } 1430: 1431: /** 1432: * If this Container is a focus cycle root, set the focus traversal 1433: * policy that determines the focus traversal order for its 1434: * children. If non-null, this policy will be inherited by all 1435: * inferior focus cycle roots. If <code>policy</code> is null, this 1436: * Container will inherit its policy from the closest ancestor focus 1437: * cycle root that's had its policy set. 1438: * 1439: * @param policy the new focus traversal policy for this Container or null 1440: * 1441: * @since 1.4 1442: */ 1443: public void setFocusTraversalPolicy (FocusTraversalPolicy policy) 1444: { 1445: focusTraversalPolicy = policy; 1446: } 1447: 1448: /** 1449: * Return the focus traversal policy that determines the focus 1450: * traversal order for this Container's children. This method 1451: * returns null if this Container is not a focus cycle root. If the 1452: * focus traversal policy has not been set explicitly, then this 1453: * method will return an ancestor focus cycle root's policy instead. 1454: * 1455: * @return this Container's focus traversal policy or null 1456: * 1457: * @since 1.4 1458: */ 1459: public FocusTraversalPolicy getFocusTraversalPolicy () 1460: { 1461: if (!isFocusCycleRoot ()) 1462: return null; 1463: 1464: if (focusTraversalPolicy == null) 1465: { 1466: Container ancestor = getFocusCycleRootAncestor (); 1467: 1468: if (ancestor != this && ancestor != null) 1469: return ancestor.getFocusTraversalPolicy (); 1470: else 1471: { 1472: KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); 1473: 1474: return manager.getDefaultFocusTraversalPolicy (); 1475: } 1476: } 1477: else 1478: return focusTraversalPolicy; 1479: } 1480: 1481: /** 1482: * Check whether this Container's focus traversal policy has been 1483: * explicitly set. If it has not, then this Container will inherit 1484: * its focus traversal policy from one of its ancestor focus cycle 1485: * roots. 1486: * 1487: * @return true if focus traversal policy is set, false otherwise 1488: */ 1489: public boolean isFocusTraversalPolicySet () 1490: { 1491: return focusTraversalPolicy == null; 1492: } 1493: 1494: /** 1495: * Set whether or not this Container is the root of a focus 1496: * traversal cycle. This Container's focus traversal policy 1497: * determines the order of focus traversal. Some policies prevent 1498: * the focus from being transferred between two traversal cycles 1499: * until an up or down traversal operation is performed. In that 1500: * case, normal traversal (not up or down) is limited to this 1501: * Container and all of this Container's descendents that are not 1502: * descendents of inferior focus cycle roots. In the default case 1503: * however, ContainerOrderFocusTraversalPolicy is in effect, and it 1504: * supports implicit down-cycle traversal operations. 1505: * 1506: * @param focusCycleRoot true if this is a focus cycle root, false otherwise 1507: * 1508: * @since 1.4 1509: */ 1510: public void setFocusCycleRoot (boolean focusCycleRoot) 1511: { 1512: this.focusCycleRoot = focusCycleRoot; 1513: } 1514: 1515: /** 1516: * Check whether this Container is a focus cycle root. 1517: * 1518: * @return true if this is a focus cycle root, false otherwise 1519: * 1520: * @since 1.4 1521: */ 1522: public boolean isFocusCycleRoot () 1523: { 1524: return focusCycleRoot; 1525: } 1526: 1527: /** 1528: * Transfer focus down one focus traversal cycle. If this Container 1529: * is a focus cycle root, then its default component becomes the 1530: * focus owner, and this Container becomes the current focus cycle 1531: * root. No traversal will occur if this Container is not a focus 1532: * cycle root. 1533: * 1534: * @since 1.4 1535: */ 1536: public void transferFocusDownCycle () 1537: { 1538: if (isFocusCycleRoot()) 1539: { 1540: KeyboardFocusManager fm = 1541: KeyboardFocusManager.getCurrentKeyboardFocusManager(); 1542: fm.setGlobalCurrentFocusCycleRoot(this); 1543: FocusTraversalPolicy policy = getFocusTraversalPolicy(); 1544: Component defaultComponent = policy.getDefaultComponent(this); 1545: if (defaultComponent != null) 1546: defaultComponent.requestFocus(); 1547: } 1548: } 1549: 1550: /** 1551: * Sets the ComponentOrientation property of this container and all components 1552: * contained within it. 1553: * 1554: * @exception NullPointerException If orientation is null 1555: * 1556: * @since 1.4 1557: */ 1558: public void applyComponentOrientation (ComponentOrientation orientation) 1559: { 1560: if (orientation == null) 1561: throw new NullPointerException (); 1562: } 1563: 1564: public void addPropertyChangeListener (PropertyChangeListener listener) 1565: { 1566: // TODO: Why is this overridden? 1567: super.addPropertyChangeListener(listener); 1568: } 1569: 1570: public void addPropertyChangeListener (String propertyName, 1571: PropertyChangeListener listener) 1572: { 1573: // TODO: Why is this overridden? 1574: super.addPropertyChangeListener(propertyName, listener); 1575: } 1576: 1577: 1578: /** 1579: * Sets the Z ordering for the component <code>comp</code> to 1580: * <code>index</code>. Components with lower Z order paint above components 1581: * with higher Z order. 1582: * 1583: * @param comp the component for which to change the Z ordering 1584: * @param index the index to set 1585: * 1586: * @throws NullPointerException if <code>comp == null</code> 1587: * @throws IllegalArgumentException if comp is an ancestor of this container 1588: * @throws IllegalArgumentException if <code>index</code> is not in 1589: * <code>[0, getComponentCount()]</code> for moving between 1590: * containers or <code>[0, getComponentCount() - 1]</code> for moving 1591: * inside this container 1592: * @throws IllegalArgumentException if <code>comp == this</code> 1593: * @throws IllegalArgumentException if <code>comp</code> is a 1594: * <code>Window</code> 1595: * 1596: * @see #getComponentZOrder(Component) 1597: * 1598: * @since 1.5 1599: */ 1600: public final void setComponentZOrder(Component comp, int index) 1601: { 1602: if (comp == null) 1603: throw new NullPointerException("comp must not be null"); 1604: if (comp instanceof Container && ((Container) comp).isAncestorOf(this)) 1605: throw new IllegalArgumentException("comp must not be an ancestor of " 1606: + "this"); 1607: if (comp instanceof Window) 1608: throw new IllegalArgumentException("comp must not be a Window"); 1609: 1610: if (comp == this) 1611: throw new IllegalArgumentException("cannot add component to itself"); 1612: 1613: // FIXME: Implement reparenting. 1614: if ( comp.getParent() != this) 1615: throw new AssertionError("Reparenting is not implemented yet"); 1616: else 1617: { 1618: // Find current component index. 1619: int currentIndex = getComponentZOrder(comp); 1620: if (currentIndex < index) 1621: { 1622: System.arraycopy(component, currentIndex + 1, component, 1623: currentIndex, index - currentIndex); 1624: } 1625: else 1626: { 1627: System.arraycopy(component, index, component, index + 1, 1628: currentIndex - index); 1629: } 1630: component[index] = comp; 1631: } 1632: } 1633: 1634: /** 1635: * Returns the Z ordering index of <code>comp</code>. If <code>comp</code> 1636: * is not a child component of this Container, this returns <code>-1</code>. 1637: * 1638: * @param comp the component for which to query the Z ordering 1639: * 1640: * @return the Z ordering index of <code>comp</code> or <code>-1</code> if 1641: * <code>comp</code> is not a child of this Container 1642: * 1643: * @see #setComponentZOrder(Component, int) 1644: * 1645: * @since 1.5 1646: */ 1647: public final int getComponentZOrder(Component comp) 1648: { 1649: int index = -1; 1650: if (component != null) 1651: { 1652: for (int i = 0; i < component.length; i++) 1653: { 1654: if (component[i] == comp) 1655: { 1656: index = i; 1657: break; 1658: } 1659: } 1660: } 1661: return index; 1662: } 1663: 1664: // Hidden helper methods. 1665: 1666: /** 1667: * Perform a graphics operation on the children of this container. 1668: * For each applicable child, the visitChild() method will be called 1669: * to perform the graphics operation. 1670: * 1671: * @param gfx The graphics object that will be used to derive new 1672: * graphics objects for the children. 1673: * 1674: * @param visitor Object encapsulating the graphics operation that 1675: * should be performed. 1676: * 1677: * @param lightweightOnly If true, only lightweight components will 1678: * be visited. 1679: */ 1680: private void visitChildren(Graphics gfx, GfxVisitor visitor, 1681: boolean lightweightOnly) 1682: { 1683: synchronized (getTreeLock()) 1684: { 1685: for (int i = ncomponents - 1; i >= 0; --i) 1686: { 1687: Component comp = component[i]; 1688: boolean applicable = comp.isVisible() 1689: && (comp.isLightweight() || ! lightweightOnly); 1690: 1691: if (applicable) 1692: visitChild(gfx, visitor, comp); 1693: } 1694: } 1695: } 1696: 1697: /** 1698: * Perform a graphics operation on a child. A translated and clipped 1699: * graphics object will be created, and the visit() method of the 1700: * visitor will be called to perform the operation. 1701: * 1702: * @param gfx The graphics object that will be used to derive new 1703: * graphics objects for the child. 1704: * 1705: * @param visitor Object encapsulating the graphics operation that 1706: * should be performed. 1707: * 1708: * @param comp The child component that should be visited. 1709: */ 1710: private void visitChild(Graphics gfx, GfxVisitor visitor, 1711: Component comp) 1712: { 1713: Rectangle bounds = comp.getBounds(); 1714: 1715: if(!gfx.hitClip(bounds.x,bounds.y, bounds.width, bounds.height)) 1716: return; 1717: Graphics g2 = gfx.create(bounds.x, bounds.y, bounds.width, 1718: bounds.height); 1719: try 1720: { 1721: visitor.visit(comp, g2); 1722: } 1723: finally 1724: { 1725: g2.dispose(); 1726: } 1727: } 1728: 1729: void dispatchEventImpl(AWTEvent e) 1730: { 1731: boolean dispatched = 1732: LightweightDispatcher.getInstance().dispatchEvent(e); 1733: if (! dispatched) 1734: { 1735: if ((e.id <= ContainerEvent.CONTAINER_LAST 1736: && e.id >= ContainerEvent.CONTAINER_FIRST) 1737: && (containerListener != null 1738: || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0)) 1739: processEvent(e); 1740: else 1741: super.dispatchEventImpl(e); 1742: } 1743: } 1744: 1745: /** 1746: * Tests if this container has an interest in the given event id. 1747: * 1748: * @param eventId The event id to check. 1749: * 1750: * @return <code>true</code> if a listener for the event id exists or 1751: * if the eventMask is set for the event id. 1752: * 1753: * @see java.awt.Component#eventTypeEnabled(int) 1754: */ 1755: boolean eventTypeEnabled(int eventId) 1756: { 1757: if(eventId <= ContainerEvent.CONTAINER_LAST 1758: && eventId >= ContainerEvent.CONTAINER_FIRST) 1759: return containerListener != null 1760: || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0; 1761: else 1762: return super.eventTypeEnabled(eventId); 1763: } 1764: 1765: // This is used to implement Component.transferFocus. 1766: Component findNextFocusComponent(Component child) 1767: { 1768: synchronized (getTreeLock ()) 1769: { 1770: int start, end; 1771: if (child != null) 1772: { 1773: for (start = 0; start < ncomponents; ++start) 1774: { 1775: if (component[start] == child) 1776: break; 1777: } 1778: end = start; 1779: // This special case lets us be sure to terminate. 1780: if (end == 0) 1781: end = ncomponents; 1782: ++start; 1783: } 1784: else 1785: { 1786: start = 0; 1787: end = ncomponents; 1788: } 1789: 1790: for (int j = start; j != end; ++j) 1791: { 1792: if (j >= ncomponents) 1793: { 1794: // The JCL says that we should wrap here. However, that 1795: // seems wrong. To me it seems that focus order should be 1796: // global within in given window. So instead if we reach 1797: // the end we try to look in our parent, if we have one. 1798: if (parent != null) 1799: return parent.findNextFocusComponent(this); 1800: j -= ncomponents; 1801: } 1802: if (component[j] instanceof Container) 1803: { 1804: Component c = component[j]; 1805: c = c.findNextFocusComponent(null); 1806: if (c != null) 1807: return c; 1808: } 1809: else if (component[j].isFocusTraversable()) 1810: return component[j]; 1811: } 1812: 1813: return null; 1814: } 1815: } 1816: 1817: private void addNotifyContainerChildren() 1818: { 1819: synchronized (getTreeLock ()) 1820: { 1821: for (int i = ncomponents; --i >= 0; ) 1822: { 1823: component[i].addNotify(); 1824: if (component[i].isLightweight ()) 1825: { 1826: enableEvents(component[i].eventMask); 1827: if (peer != null && !isLightweight ()) 1828: enableEvents (AWTEvent.PAINT_EVENT_MASK); 1829: } 1830: } 1831: } 1832: } 1833: 1834: /** 1835: * Deserialize this Container: 1836: * <ol> 1837: * <li>Read from the stream the default serializable fields.</li> 1838: * <li>Read a list of serializable ContainerListeners as optional 1839: * data. If the list is null, no listeners will be registered.</li> 1840: * <li>Read this Container's FocusTraversalPolicy as optional data. 1841: * If this is null, then this Container will use a 1842: * DefaultFocusTraversalPolicy.</li> 1843: * </ol> 1844: * 1845: * @param s the stream to read from 1846: * @throws ClassNotFoundException if deserialization fails 1847: * @throws IOException if the stream fails 1848: */ 1849: private void readObject (ObjectInputStream s) 1850: throws ClassNotFoundException, IOException 1851: { 1852: s.defaultReadObject (); 1853: String key = (String) s.readObject (); 1854: while (key != null) 1855: { 1856: Object object = s.readObject (); 1857: if ("containerL".equals (key)) 1858: addContainerListener((ContainerListener) object); 1859: // FIXME: under what key is the focus traversal policy stored? 1860: else if ("focusTraversalPolicy".equals (key)) 1861: setFocusTraversalPolicy ((FocusTraversalPolicy) object); 1862: 1863: key = (String) s.readObject(); 1864: } 1865: } 1866: 1867: /** 1868: * Serialize this Container: 1869: * <ol> 1870: * <li>Write to the stream the default serializable fields.</li> 1871: * <li>Write the list of serializable ContainerListeners as optional 1872: * data.</li> 1873: * <li>Write this Container's FocusTraversalPolicy as optional data.</li> 1874: * </ol> 1875: * 1876: * @param s the stream to write to 1877: * @throws IOException if the stream fails 1878: */ 1879: private void writeObject (ObjectOutputStream s) throws IOException 1880: { 1881: s.defaultWriteObject (); 1882: AWTEventMulticaster.save (s, "containerL", containerListener); 1883: if (focusTraversalPolicy instanceof Serializable) 1884: s.writeObject (focusTraversalPolicy); 1885: else 1886: s.writeObject (null); 1887: } 1888: 1889: // Nested classes. 1890: 1891: /* The following classes are used in concert with the 1892: visitChildren() method to implement all the graphics operations 1893: that requires traversal of the containment hierarchy. */ 1894: 1895: abstract static class GfxVisitor 1896: { 1897: public abstract void visit(Component c, Graphics gfx); 1898: } 1899: 1900: static class GfxPaintVisitor extends GfxVisitor 1901: { 1902: public static final GfxVisitor INSTANCE = new GfxPaintVisitor(); 1903: 1904: public void visit(Component c, Graphics gfx) 1905: { 1906: c.paint(gfx); 1907: } 1908: } 1909: 1910: static class GfxPrintVisitor extends GfxVisitor 1911: { 1912: public static final GfxVisitor INSTANCE = new GfxPrintVisitor(); 1913: 1914: public void visit(Component c, Graphics gfx) 1915: { 1916: c.print(gfx); 1917: } 1918: } 1919: 1920: static class GfxPaintAllVisitor extends GfxVisitor 1921: { 1922: public static final GfxVisitor INSTANCE = new GfxPaintAllVisitor(); 1923: 1924: public void visit(Component c, Graphics gfx) 1925: { 1926: c.paintAll(gfx); 1927: } 1928: } 1929: 1930: static class GfxPrintAllVisitor extends GfxVisitor 1931: { 1932: public static final GfxVisitor INSTANCE = new GfxPrintAllVisitor(); 1933: 1934: public void visit(Component c, Graphics gfx) 1935: { 1936: c.printAll(gfx); 1937: } 1938: } 1939: 1940: /** 1941: * This class provides accessibility support for subclasses of container. 1942: * 1943: * @author Eric Blake (ebb9@email.byu.edu) 1944: * 1945: * @since 1.3 1946: */ 1947: protected class AccessibleAWTContainer extends AccessibleAWTComponent 1948: { 1949: /** 1950: * Compatible with JDK 1.4+. 1951: */ 1952: private static final long serialVersionUID = 5081320404842566097L; 1953: 1954: /** 1955: * The handler to fire PropertyChange when children are added or removed. 1956: * 1957: * @serial the handler for property changes 1958: */ 1959: protected ContainerListener accessibleContainerHandler 1960: = new AccessibleContainerHandler(); 1961: 1962: /** 1963: * The default constructor. 1964: */ 1965: protected AccessibleAWTContainer() 1966: { 1967: Container.this.addContainerListener(accessibleContainerHandler); 1968: } 1969: 1970: /** 1971: * Return the number of accessible children of the containing accessible 1972: * object (at most the total number of its children). 1973: * 1974: * @return the number of accessible children 1975: */ 1976: public int getAccessibleChildrenCount() 1977: { 1978: synchronized (getTreeLock ()) 1979: { 1980: int count = 0; 1981: int i = component == null ? 0 : component.length; 1982: while (--i >= 0) 1983: if (component[i] instanceof Accessible) 1984: count++; 1985: return count; 1986: } 1987: } 1988: 1989: /** 1990: * Return the nth accessible child of the containing accessible object. 1991: * 1992: * @param i the child to grab, zero-based 1993: * @return the accessible child, or null 1994: */ 1995: public Accessible getAccessibleChild(int i) 1996: { 1997: synchronized (getTreeLock ()) 1998: { 1999: if (component == null) 2000: return null; 2001: int index = -1; 2002: while (i >= 0 && ++index < component.length) 2003: if (component[index] instanceof Accessible) 2004: i--; 2005: if (i < 0) 2006: return (Accessible) component[index]; 2007: return null; 2008: } 2009: } 2010: 2011: /** 2012: * Return the accessible child located at point (in the parent's 2013: * coordinates), if one exists. 2014: * 2015: * @param p the point to look at 2016: * 2017: * @return an accessible object at that point, or null 2018: * 2019: * @throws NullPointerException if p is null 2020: */ 2021: public Accessible getAccessibleAt(Point p) 2022: { 2023: Component c = getComponentAt(p.x, p.y); 2024: return c != Container.this && c instanceof Accessible ? (Accessible) c 2025: : null; 2026: } 2027: 2028: /** 2029: * This class fires a <code>PropertyChange</code> listener, if registered, 2030: * when children are added or removed from the enclosing accessible object. 2031: * 2032: * @author Eric Blake (ebb9@email.byu.edu) 2033: * 2034: * @since 1.3 2035: */ 2036: protected class AccessibleContainerHandler implements ContainerListener 2037: { 2038: /** 2039: * Default constructor. 2040: */ 2041: protected AccessibleContainerHandler() 2042: { 2043: // Nothing to do here. 2044: } 2045: 2046: /** 2047: * Fired when a component is added; forwards to the PropertyChange 2048: * listener. 2049: * 2050: * @param e the container event for adding 2051: */ 2052: public void componentAdded(ContainerEvent e) 2053: { 2054: AccessibleAWTContainer.this.firePropertyChange 2055: (ACCESSIBLE_CHILD_PROPERTY, null, e.getChild()); 2056: } 2057: 2058: /** 2059: * Fired when a component is removed; forwards to the PropertyChange 2060: * listener. 2061: * 2062: * @param e the container event for removing 2063: */ 2064: public void componentRemoved(ContainerEvent e) 2065: { 2066: AccessibleAWTContainer.this.firePropertyChange 2067: (ACCESSIBLE_CHILD_PROPERTY, e.getChild(), null); 2068: } 2069: } // class AccessibleContainerHandler 2070: } // class AccessibleAWTContainer 2071: } // class Container
GNU Classpath (0.91) |