Frames | No Frames |
1: /* JComponent.java -- Every component in swing inherits from this class. 2: Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing; 40: 41: import java.applet.Applet; 42: import java.awt.AWTEvent; 43: import java.awt.Color; 44: import java.awt.Component; 45: import java.awt.Container; 46: import java.awt.Dimension; 47: import java.awt.EventQueue; 48: import java.awt.FocusTraversalPolicy; 49: import java.awt.Font; 50: import java.awt.Graphics; 51: import java.awt.Graphics2D; 52: import java.awt.Image; 53: import java.awt.Insets; 54: import java.awt.Point; 55: import java.awt.Rectangle; 56: import java.awt.Shape; 57: import java.awt.Window; 58: import java.awt.dnd.DropTarget; 59: import java.awt.event.ActionEvent; 60: import java.awt.event.ActionListener; 61: import java.awt.event.ContainerEvent; 62: import java.awt.event.ContainerListener; 63: import java.awt.event.FocusEvent; 64: import java.awt.event.FocusListener; 65: import java.awt.event.KeyEvent; 66: import java.awt.event.MouseEvent; 67: import java.awt.peer.LightweightPeer; 68: import java.beans.PropertyChangeEvent; 69: import java.beans.PropertyChangeListener; 70: import java.beans.PropertyVetoException; 71: import java.beans.VetoableChangeListener; 72: import java.io.Serializable; 73: import java.util.ArrayList; 74: import java.util.EventListener; 75: import java.util.Hashtable; 76: import java.util.Locale; 77: import java.util.Set; 78: 79: import javax.accessibility.Accessible; 80: import javax.accessibility.AccessibleContext; 81: import javax.accessibility.AccessibleExtendedComponent; 82: import javax.accessibility.AccessibleKeyBinding; 83: import javax.accessibility.AccessibleRole; 84: import javax.accessibility.AccessibleState; 85: import javax.accessibility.AccessibleStateSet; 86: import javax.swing.border.Border; 87: import javax.swing.border.CompoundBorder; 88: import javax.swing.border.TitledBorder; 89: import javax.swing.event.AncestorEvent; 90: import javax.swing.event.AncestorListener; 91: import javax.swing.event.EventListenerList; 92: import javax.swing.plaf.ComponentUI; 93: 94: /** 95: * The base class of all Swing components. 96: * It contains generic methods to manage events, properties and sizes. Actual 97: * drawing of the component is channeled to a look-and-feel class that is 98: * implemented elsewhere. 99: * 100: * @author Ronald Veldema (rveldema&064;cs.vu.nl) 101: * @author Graydon Hoare (graydon&064;redhat.com) 102: */ 103: public abstract class JComponent extends Container implements Serializable 104: { 105: private static final long serialVersionUID = -7908749299918704233L; 106: 107: /** 108: * The accessible context of this <code>JComponent</code>. 109: */ 110: protected AccessibleContext accessibleContext; 111: 112: /** 113: * Basic accessibility support for <code>JComponent</code> derived 114: * widgets. 115: */ 116: public abstract class AccessibleJComponent 117: extends AccessibleAWTContainer 118: implements AccessibleExtendedComponent 119: { 120: /** 121: * Receives notification if the focus on the JComponent changes and 122: * fires appropriate PropertyChangeEvents to listeners registered with 123: * the AccessibleJComponent. 124: */ 125: protected class AccessibleFocusHandler 126: implements FocusListener 127: { 128: /** 129: * Creates a new AccessibleFocusHandler. 130: */ 131: protected AccessibleFocusHandler() 132: { 133: // Nothing to do here. 134: } 135: 136: /** 137: * Receives notification when the JComponent gained focus and fires 138: * a PropertyChangeEvent to listeners registered on the 139: * AccessibleJComponent with a property name of 140: * {@link AccessibleContext#ACCESSIBLE_STATE_PROPERTY} and a new value 141: * of {@link AccessibleState#FOCUSED}. 142: */ 143: public void focusGained(FocusEvent event) 144: { 145: AccessibleJComponent.this.firePropertyChange 146: (AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null, 147: AccessibleState.FOCUSED); 148: } 149: 150: /** 151: * Receives notification when the JComponent lost focus and fires 152: * a PropertyChangeEvent to listeners registered on the 153: * AccessibleJComponent with a property name of 154: * {@link AccessibleContext#ACCESSIBLE_STATE_PROPERTY} and an old value 155: * of {@link AccessibleState#FOCUSED}. 156: */ 157: public void focusLost(FocusEvent valevent) 158: { 159: AccessibleJComponent.this.firePropertyChange 160: (AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 161: AccessibleState.FOCUSED, null); 162: } 163: } 164: 165: /** 166: * Receives notification if there are child components are added or removed 167: * from the JComponent and fires appropriate PropertyChangeEvents to 168: * interested listeners on the AccessibleJComponent. 169: */ 170: protected class AccessibleContainerHandler 171: implements ContainerListener 172: { 173: /** 174: * Creates a new AccessibleContainerHandler. 175: */ 176: protected AccessibleContainerHandler() 177: { 178: // Nothing to do here. 179: } 180: 181: /** 182: * Receives notification when a child component is added to the 183: * JComponent and fires a PropertyChangeEvent on listeners registered 184: * with the AccessibleJComponent with a property name of 185: * {@link AccessibleContext#ACCESSIBLE_CHILD_PROPERTY}. 186: * 187: * @param event the container event 188: */ 189: public void componentAdded(ContainerEvent event) 190: { 191: Component c = event.getChild(); 192: if (c != null && c instanceof Accessible) 193: { 194: AccessibleContext childCtx = c.getAccessibleContext(); 195: AccessibleJComponent.this.firePropertyChange 196: (AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, null, childCtx); 197: } 198: } 199: 200: /** 201: * Receives notification when a child component is removed from the 202: * JComponent and fires a PropertyChangeEvent on listeners registered 203: * with the AccessibleJComponent with a property name of 204: * {@link AccessibleContext#ACCESSIBLE_CHILD_PROPERTY}. 205: * 206: * @param event the container event 207: */ 208: public void componentRemoved(ContainerEvent event) 209: { 210: Component c = event.getChild(); 211: if (c != null && c instanceof Accessible) 212: { 213: AccessibleContext childCtx = c.getAccessibleContext(); 214: AccessibleJComponent.this.firePropertyChange 215: (AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, childCtx, null); 216: } 217: } 218: } 219: 220: private static final long serialVersionUID = -7047089700479897799L; 221: 222: /** 223: * Receives notification when a child component is added to the 224: * JComponent and fires a PropertyChangeEvent on listeners registered 225: * with the AccessibleJComponent. 226: * 227: * @specnote AccessibleAWTContainer has a protected field with the same 228: * name. Looks like a bug or nasty misdesign to me. 229: */ 230: protected ContainerListener accessibleContainerHandler; 231: 232: /** 233: * Receives notification if the focus on the JComponent changes and 234: * fires appropriate PropertyChangeEvents to listeners registered with 235: * the AccessibleJComponent. 236: * 237: * @specnote AccessibleAWTComponent has a protected field 238: * accessibleAWTFocusHandler. Looks like a bug or nasty misdesign 239: * to me. 240: */ 241: protected FocusListener accessibleFocusHandler; 242: 243: /** 244: * Creates a new AccessibleJComponent. 245: */ 246: protected AccessibleJComponent() 247: { 248: // Nothing to do here. 249: } 250: 251: /** 252: * Adds a property change listener to the list of registered listeners. 253: * 254: * This sets up the {@link #accessibleContainerHandler} and 255: * {@link #accessibleFocusHandler} fields and calls 256: * <code>super.addPropertyChangeListener(listener)</code>. 257: * 258: * @param listener the listener to add 259: */ 260: public void addPropertyChangeListener(PropertyChangeListener listener) 261: { 262: // Tests seem to indicate that this method also sets up the other two 263: // handlers. 264: if (accessibleContainerHandler == null) 265: { 266: accessibleContainerHandler = new AccessibleContainerHandler(); 267: addContainerListener(accessibleContainerHandler); 268: } 269: if (accessibleFocusHandler == null) 270: { 271: accessibleFocusHandler = new AccessibleFocusHandler(); 272: addFocusListener(accessibleFocusHandler); 273: } 274: super.addPropertyChangeListener(listener); 275: } 276: 277: /** 278: * Removes a property change listener from the list of registered listeners. 279: * 280: * This uninstalls the {@link #accessibleContainerHandler} and 281: * {@link #accessibleFocusHandler} fields and calls 282: * <code>super.removePropertyChangeListener(listener)</code>. 283: * 284: * @param listener the listener to remove 285: */ 286: public void removePropertyChangeListener(PropertyChangeListener listener) 287: { 288: // Tests seem to indicate that this method also resets the other two 289: // handlers. 290: if (accessibleContainerHandler != null) 291: { 292: removeContainerListener(accessibleContainerHandler); 293: accessibleContainerHandler = null; 294: } 295: if (accessibleFocusHandler != null) 296: { 297: removeFocusListener(accessibleFocusHandler); 298: accessibleFocusHandler = null; 299: } 300: super.removePropertyChangeListener(listener); 301: } 302: 303: /** 304: * Returns the number of accessible children of this object. 305: * 306: * @return the number of accessible children of this object 307: */ 308: public int getAccessibleChildrenCount() 309: { 310: // TODO: The functionality should be performed in the superclass. 311: // Find out why this is overridden. However, it is very well possible 312: // that this is left over from times when there was no such superclass 313: // method. 314: return super.getAccessibleChildrenCount(); 315: } 316: 317: /** 318: * Returns the accessible child component at index <code>i</code>. 319: * 320: * @param i the index of the accessible child to return 321: * 322: * @return the accessible child component at index <code>i</code> 323: */ 324: public Accessible getAccessibleChild(int i) 325: { 326: // TODO: The functionality should be performed in the superclass. 327: // Find out why this is overridden. However, it is very well possible 328: // that this is left over from times when there was no such superclass 329: // method. 330: return super.getAccessibleChild(i); 331: } 332: 333: /** 334: * Returns the accessible state set of this component. 335: * 336: * @return the accessible state set of this component 337: */ 338: public AccessibleStateSet getAccessibleStateSet() 339: { 340: // Note: While the java.awt.Component has an 'opaque' property, it 341: // seems that it is not added to the accessible state set there, even 342: // if this property is true. However, it is handled for JComponent, so 343: // we add it here. 344: AccessibleStateSet state = super.getAccessibleStateSet(); 345: if (isOpaque()) 346: state.add(AccessibleState.OPAQUE); 347: return state; 348: } 349: 350: /** 351: * Returns the localized name for this object. Generally this should 352: * almost never return {@link Component#getName()} since that is not 353: * a localized name. If the object is some kind of text component (like 354: * a menu item), then the value of the object may be returned. Also, if 355: * the object has a tooltip, the value of the tooltip may also be 356: * appropriate. 357: * 358: * @return the localized name for this object or <code>null</code> if this 359: * object has no name 360: */ 361: public String getAccessibleName() 362: { 363: String name = super.getAccessibleName(); 364: 365: // There are two fallbacks provided by the JComponent in the case the 366: // superclass returns null: 367: // - If the component is inside a titled border, then it inherits the 368: // name from the border title. 369: // - If the component is not inside a titled border but has a label 370: // (via JLabel.setLabelFor()), then it gets the name from the label's 371: // accessible context. 372: 373: if (name == null) 374: { 375: name = getTitledBorderText(); 376: } 377: 378: if (name == null) 379: { 380: Object l = getClientProperty(JLabel.LABEL_PROPERTY); 381: if (l instanceof Accessible) 382: { 383: AccessibleContext labelCtx = 384: ((Accessible) l).getAccessibleContext(); 385: name = labelCtx.getAccessibleName(); 386: } 387: } 388: 389: return name; 390: } 391: 392: /** 393: * Returns the localized description of this object. 394: * 395: * @return the localized description of this object or <code>null</code> 396: * if this object has no description 397: */ 398: public String getAccessibleDescription() 399: { 400: // There are two fallbacks provided by the JComponent in the case the 401: // superclass returns null: 402: // - If the component has a tooltip, then inherit the description from 403: // the tooltip. 404: // - If the component is not inside a titled border but has a label 405: // (via JLabel.setLabelFor()), then it gets the name from the label's 406: // accessible context. 407: String descr = super.getAccessibleDescription(); 408: 409: if (descr == null) 410: { 411: descr = getToolTipText(); 412: } 413: 414: if (descr == null) 415: { 416: Object l = getClientProperty(JLabel.LABEL_PROPERTY); 417: if (l instanceof Accessible) 418: { 419: AccessibleContext labelCtx = 420: ((Accessible) l).getAccessibleContext(); 421: descr = labelCtx.getAccessibleName(); 422: } 423: } 424: 425: return descr; 426: } 427: 428: /** 429: * Returns the accessible role of this component. 430: * 431: * @return the accessible role of this component 432: * 433: * @see AccessibleRole 434: */ 435: public AccessibleRole getAccessibleRole() 436: { 437: return AccessibleRole.SWING_COMPONENT; 438: } 439: 440: /** 441: * Recursivly searches a border hierarchy (starting at <code>border) for 442: * a titled border and returns the title if one is found, <code>null</code> 443: * otherwise. 444: * 445: * @param border the border to start search from 446: * 447: * @return the border title of a possibly found titled border 448: */ 449: protected String getBorderTitle(Border border) 450: { 451: String title = null; 452: if (border instanceof CompoundBorder) 453: { 454: CompoundBorder compound = (CompoundBorder) border; 455: Border inner = compound.getInsideBorder(); 456: title = getBorderTitle(inner); 457: if (title == null) 458: { 459: Border outer = compound.getOutsideBorder(); 460: title = getBorderTitle(outer); 461: } 462: } 463: else if (border instanceof TitledBorder) 464: { 465: TitledBorder titled = (TitledBorder) border; 466: title = titled.getTitle(); 467: } 468: return title; 469: } 470: 471: /** 472: * Returns the tooltip text for this accessible component. 473: * 474: * @return the tooltip text for this accessible component 475: */ 476: public String getToolTipText() 477: { 478: return JComponent.this.getToolTipText(); 479: } 480: 481: /** 482: * Returns the title of the border of this accessible component if 483: * this component has a titled border, otherwise returns <code>null</code>. 484: * 485: * @return the title of the border of this accessible component if 486: * this component has a titled border, otherwise returns 487: * <code>null</code> 488: */ 489: public String getTitledBorderText() 490: { 491: return getBorderTitle(getBorder()); 492: } 493: 494: /** 495: * Returns the keybindings associated with this accessible component or 496: * <code>null</code> if the component does not support key bindings. 497: * 498: * @return the keybindings associated with this accessible component 499: */ 500: public AccessibleKeyBinding getAccessibleKeyBinding() 501: { 502: // The reference implementation seems to always return null here, 503: // independent of the key bindings of the JComponent. So do we. 504: return null; 505: } 506: } 507: 508: /** 509: * An explicit value for the component's preferred size; if not set by a 510: * user, this is calculated on the fly by delegating to the {@link 511: * ComponentUI#getPreferredSize} method on the {@link #ui} property. 512: */ 513: Dimension preferredSize; 514: 515: /** 516: * An explicit value for the component's minimum size; if not set by a 517: * user, this is calculated on the fly by delegating to the {@link 518: * ComponentUI#getMinimumSize} method on the {@link #ui} property. 519: */ 520: Dimension minimumSize; 521: 522: /** 523: * An explicit value for the component's maximum size; if not set by a 524: * user, this is calculated on the fly by delegating to the {@link 525: * ComponentUI#getMaximumSize} method on the {@link #ui} property. 526: */ 527: Dimension maximumSize; 528: 529: /** 530: * A value between 0.0 and 1.0 indicating the preferred horizontal 531: * alignment of the component, relative to its siblings. The values 532: * {@link #LEFT_ALIGNMENT}, {@link #CENTER_ALIGNMENT}, and {@link 533: * #RIGHT_ALIGNMENT} can also be used, as synonyms for <code>0.0</code>, 534: * <code>0.5</code>, and <code>1.0</code>, respectively. Not all layout 535: * managers use this property. 536: * 537: * @see #getAlignmentX 538: * @see #setAlignmentX 539: * @see javax.swing.OverlayLayout 540: * @see javax.swing.BoxLayout 541: */ 542: float alignmentX = -1.0F; 543: 544: /** 545: * A value between 0.0 and 1.0 indicating the preferred vertical 546: * alignment of the component, relative to its siblings. The values 547: * {@link #TOP_ALIGNMENT}, {@link #CENTER_ALIGNMENT}, and {@link 548: * #BOTTOM_ALIGNMENT} can also be used, as synonyms for <code>0.0</code>, 549: * <code>0.5</code>, and <code>1.0</code>, respectively. Not all layout 550: * managers use this property. 551: * 552: * @see #getAlignmentY 553: * @see #setAlignmentY 554: * @see javax.swing.OverlayLayout 555: * @see javax.swing.BoxLayout 556: */ 557: float alignmentY = -1.0F; 558: 559: /** 560: * The border painted around this component. 561: * 562: * @see #paintBorder 563: */ 564: Border border; 565: 566: /** 567: * The text to show in the tooltip associated with this component. 568: * 569: * @see #setToolTipText 570: * @see #getToolTipText() 571: */ 572: String toolTipText; 573: 574: /** 575: * <p>Whether to double buffer this component when painting. This flag 576: * should generally be <code>true</code>, to ensure good painting 577: * performance.</p> 578: * 579: * <p>All children of a double buffered component are painted into the 580: * double buffer automatically, so only the top widget in a window needs 581: * to be double buffered.</p> 582: * 583: * @see #setDoubleBuffered 584: * @see #isDoubleBuffered 585: * @see #paint 586: */ 587: boolean doubleBuffered = true; 588: 589: /** 590: * A set of flags indicating which debugging graphics facilities should 591: * be enabled on this component. The values should be a combination of 592: * {@link DebugGraphics#NONE_OPTION}, {@link DebugGraphics#LOG_OPTION}, 593: * {@link DebugGraphics#FLASH_OPTION}, or {@link 594: * DebugGraphics#BUFFERED_OPTION}. 595: * 596: * @see #setDebugGraphicsOptions 597: * @see #getDebugGraphicsOptions 598: * @see DebugGraphics 599: * @see #getComponentGraphics 600: */ 601: int debugGraphicsOptions; 602: 603: /** 604: * <p>This property controls two independent behaviors simultaneously.</p> 605: * 606: * <p>First, it controls whether to fill the background of this widget 607: * when painting its body. This affects calls to {@link 608: * JComponent#paintComponent}, which in turn calls {@link 609: * ComponentUI#update} on the component's {@link #ui} property. If the 610: * component is opaque during this call, the background will be filled 611: * before calling {@link ComponentUI#paint}. This happens merely as a 612: * convenience; you may fill the component's background yourself too, 613: * but there is no need to do so if you will be filling with the same 614: * color.</p> 615: * 616: * <p>Second, it the opaque property informs swing's repaint system 617: * whether it will be necessary to paint the components "underneath" this 618: * component, in Z-order. If the component is opaque, it is considered to 619: * completely occlude components "underneath" it, so they will not be 620: * repainted along with the opaque component.</p> 621: * 622: * <p>The default value for this property is <code>false</code>, but most 623: * components will want to set it to <code>true</code> when installing UI 624: * defaults in {@link ComponentUI#installUI}.</p> 625: * 626: * @see #setOpaque 627: * @see #isOpaque 628: * @see #paintComponent 629: */ 630: boolean opaque = false; 631: 632: /** 633: * The user interface delegate for this component. Event delivery and 634: * repainting of the component are usually delegated to this object. 635: * 636: * @see #setUI 637: * @see #getUIClassID 638: * @see #updateUI 639: */ 640: protected ComponentUI ui; 641: 642: /** 643: * A hint to the focus system that this component should or should not 644: * get focus. If this is <code>false</code>, swing will not try to 645: * request focus on this component; if <code>true</code>, swing might 646: * try to request focus, but the request might fail. Thus it is only 647: * a hint guiding swing's behavior. 648: * 649: * @see #requestFocus() 650: * @see #isRequestFocusEnabled 651: * @see #setRequestFocusEnabled 652: */ 653: boolean requestFocusEnabled; 654: 655: /** 656: * Flag indicating behavior of this component when the mouse is dragged 657: * outside the component and the mouse <em>stops moving</em>. If 658: * <code>true</code>, synthetic mouse events will be delivered on regular 659: * timed intervals, continuing off in the direction the mouse exited the 660: * component, until the mouse is released or re-enters the component. 661: * 662: * @see #setAutoscrolls 663: * @see #getAutoscrolls 664: */ 665: boolean autoscrolls = false; 666: 667: /** 668: * Indicates whether the current paint call is already double buffered or 669: * not. 670: */ 671: static boolean isPaintingDoubleBuffered = false; 672: 673: /** 674: * Listeners for events other than {@link PropertyChangeEvent} are 675: * handled by this listener list. PropertyChangeEvents are handled in 676: * {@link #changeSupport}. 677: */ 678: protected EventListenerList listenerList = new EventListenerList(); 679: 680: /** 681: * Storage for "client properties", which are key/value pairs associated 682: * with this component by a "client", such as a user application or a 683: * layout manager. This is lazily constructed when the component gets its 684: * first client property. 685: */ 686: private Hashtable clientProperties; 687: 688: private InputMap inputMap_whenFocused; 689: private InputMap inputMap_whenAncestorOfFocused; 690: private ComponentInputMap inputMap_whenInFocusedWindow; 691: private ActionMap actionMap; 692: /** @since 1.3 */ 693: private boolean verifyInputWhenFocusTarget; 694: private InputVerifier inputVerifier; 695: 696: private TransferHandler transferHandler; 697: 698: /** 699: * Indicates if this component is currently painting a tile or not. 700: */ 701: private boolean paintingTile; 702: 703: /** 704: * A temporary buffer used for fast dragging of components. 705: */ 706: private Image dragBuffer; 707: 708: /** 709: * Indicates if the dragBuffer is already initialized. 710: */ 711: private boolean dragBufferInitialized; 712: 713: /** 714: * A cached Rectangle object to be reused. Be careful when you use that, 715: * so that it doesn't get modified in another context within the same 716: * method call chain. 717: */ 718: private static transient Rectangle rectCache; 719: 720: /** 721: * The default locale of the component. 722: * 723: * @see #getDefaultLocale 724: * @see #setDefaultLocale 725: */ 726: private static Locale defaultLocale; 727: 728: public static final String TOOL_TIP_TEXT_KEY = "ToolTipText"; 729: 730: /** 731: * Constant used to indicate that no condition has been assigned to a 732: * particular action. 733: * 734: * @see #registerKeyboardAction(ActionListener, KeyStroke, int) 735: */ 736: public static final int UNDEFINED_CONDITION = -1; 737: 738: /** 739: * Constant used to indicate that an action should be performed only when 740: * the component has focus. 741: * 742: * @see #registerKeyboardAction(ActionListener, KeyStroke, int) 743: */ 744: public static final int WHEN_FOCUSED = 0; 745: 746: /** 747: * Constant used to indicate that an action should be performed only when 748: * the component is an ancestor of the component which has focus. 749: * 750: * @see #registerKeyboardAction(ActionListener, KeyStroke, int) 751: */ 752: public static final int WHEN_ANCESTOR_OF_FOCUSED_COMPONENT = 1; 753: 754: /** 755: * Constant used to indicate that an action should be performed only when 756: * the component is in the window which has focus. 757: * 758: * @see #registerKeyboardAction(ActionListener, KeyStroke, int) 759: */ 760: public static final int WHEN_IN_FOCUSED_WINDOW = 2; 761: 762: /** 763: * Indicates if the opaque property has been set by a client program or by 764: * the UI. 765: * 766: * @see #setUIProperty(String, Object) 767: * @see LookAndFeel#installProperty(JComponent, String, Object) 768: */ 769: private boolean clientOpaqueSet = false; 770: 771: /** 772: * Indicates if the autoscrolls property has been set by a client program or 773: * by the UI. 774: * 775: * @see #setUIProperty(String, Object) 776: * @see LookAndFeel#installProperty(JComponent, String, Object) 777: */ 778: private boolean clientAutoscrollsSet = false; 779: 780: /** 781: * Creates a new <code>JComponent</code> instance. 782: */ 783: public JComponent() 784: { 785: super(); 786: setDropTarget(new DropTarget()); 787: defaultLocale = Locale.getDefault(); 788: debugGraphicsOptions = DebugGraphics.NONE_OPTION; 789: setRequestFocusEnabled(true); 790: } 791: 792: /** 793: * Helper to lazily construct and return the client properties table. 794: * 795: * @return The current client properties table 796: * 797: * @see #clientProperties 798: * @see #getClientProperty 799: * @see #putClientProperty 800: */ 801: private Hashtable getClientProperties() 802: { 803: if (clientProperties == null) 804: clientProperties = new Hashtable(); 805: return clientProperties; 806: } 807: 808: /** 809: * Get a client property associated with this component and a particular 810: * key. 811: * 812: * @param key The key with which to look up the client property 813: * 814: * @return A client property associated with this object and key 815: * 816: * @see #clientProperties 817: * @see #getClientProperties 818: * @see #putClientProperty 819: */ 820: public final Object getClientProperty(Object key) 821: { 822: return getClientProperties().get(key); 823: } 824: 825: /** 826: * Add a client property <code>value</code> to this component, associated 827: * with <code>key</code>. If there is an existing client property 828: * associated with <code>key</code>, it will be replaced. A 829: * {@link PropertyChangeEvent} is sent to registered listeners (with the 830: * name of the property being <code>key.toString()</code>). 831: * 832: * @param key The key of the client property association to add 833: * @param value The value of the client property association to add 834: * 835: * @see #clientProperties 836: * @see #getClientProperties 837: * @see #getClientProperty 838: */ 839: public final void putClientProperty(Object key, Object value) 840: { 841: Hashtable t = getClientProperties(); 842: Object old = t.get(key); 843: if (value != null) 844: t.put(key, value); 845: else 846: t.remove(key); 847: firePropertyChange(key.toString(), old, value); 848: } 849: 850: /** 851: * Unregister an <code>AncestorListener</code>. 852: * 853: * @param listener The listener to unregister 854: * 855: * @see #addAncestorListener 856: */ 857: public void removeAncestorListener(AncestorListener listener) 858: { 859: listenerList.remove(AncestorListener.class, listener); 860: } 861: 862: /** 863: * Unregister a <code>VetoableChangeChangeListener</code>. 864: * 865: * @param listener The listener to unregister 866: * 867: * @see #addVetoableChangeListener 868: */ 869: public void removeVetoableChangeListener(VetoableChangeListener listener) 870: { 871: listenerList.remove(VetoableChangeListener.class, listener); 872: } 873: 874: /** 875: * Register an <code>AncestorListener</code>. 876: * 877: * @param listener The listener to register 878: * 879: * @see #removeVetoableChangeListener 880: */ 881: public void addAncestorListener(AncestorListener listener) 882: { 883: listenerList.add(AncestorListener.class, listener); 884: } 885: 886: /** 887: * Register a <code>PropertyChangeListener</code> for a specific, named 888: * property. To listen to all property changes, regardless of name, use 889: * {@link #addPropertyChangeListener(PropertyChangeListener)} instead. 890: * 891: * @param propertyName The property name to listen to 892: * @param listener The listener to register 893: * 894: * @see #removePropertyChangeListener(String, PropertyChangeListener) 895: * @see #changeSupport 896: */ 897: public void addPropertyChangeListener(String propertyName, 898: PropertyChangeListener listener) 899: { 900: listenerList.add(PropertyChangeListener.class, listener); 901: } 902: 903: /** 904: * Register a <code>VetoableChangeListener</code>. 905: * 906: * @param listener The listener to register 907: * 908: * @see #removeVetoableChangeListener 909: * @see #listenerList 910: */ 911: public void addVetoableChangeListener(VetoableChangeListener listener) 912: { 913: listenerList.add(VetoableChangeListener.class, listener); 914: } 915: 916: /** 917: * Returns all registered {@link EventListener}s of the given 918: * <code>listenerType</code>. 919: * 920: * @param listenerType the class of listeners to filter (<code>null</code> 921: * not permitted). 922: * 923: * @return An array of registered listeners. 924: * 925: * @throws ClassCastException if <code>listenerType</code> does not implement 926: * the {@link EventListener} interface. 927: * @throws NullPointerException if <code>listenerType</code> is 928: * <code>null</code>. 929: * 930: * @see #getAncestorListeners() 931: * @see #listenerList 932: * 933: * @since 1.3 934: */ 935: public EventListener[] getListeners(Class listenerType) 936: { 937: if (listenerType == PropertyChangeListener.class) 938: return getPropertyChangeListeners(); 939: else 940: return listenerList.getListeners(listenerType); 941: } 942: 943: /** 944: * Return all registered <code>AncestorListener</code> objects. 945: * 946: * @return The set of <code>AncestorListener</code> objects in {@link 947: * #listenerList} 948: */ 949: public AncestorListener[] getAncestorListeners() 950: { 951: return (AncestorListener[]) getListeners(AncestorListener.class); 952: } 953: 954: /** 955: * Return all registered <code>VetoableChangeListener</code> objects. 956: * 957: * @return The set of <code>VetoableChangeListener</code> objects in {@link 958: * #listenerList} 959: */ 960: public VetoableChangeListener[] getVetoableChangeListeners() 961: { 962: return (VetoableChangeListener[]) getListeners(VetoableChangeListener.class); 963: } 964: 965: /** 966: * A variant of {@link #firePropertyChange(String,Object,Object)} 967: * for properties with <code>boolean</code> values. 968: * 969: * @specnote It seems that in JDK1.5 all property related methods have been 970: * moved to java.awt.Component, except this and 2 others. We call 971: * super here. I guess this will also be removed in one of the next 972: * releases. 973: */ 974: public void firePropertyChange(String propertyName, boolean oldValue, 975: boolean newValue) 976: { 977: super.firePropertyChange(propertyName, oldValue, newValue); 978: } 979: 980: /** 981: * A variant of {@link #firePropertyChange(String,Object,Object)} 982: * for properties with <code>char</code> values. 983: * 984: * @specnote It seems that in JDK1.5 all property related methods have been 985: * moved to java.awt.Component, except this and 2 others. We call 986: * super here. I guess this will also be removed in one of the next 987: * releases. 988: */ 989: public void firePropertyChange(String propertyName, char oldValue, 990: char newValue) 991: { 992: super.firePropertyChange(propertyName, oldValue, newValue); 993: } 994: 995: /** 996: * A variant of {@link #firePropertyChange(String,Object,Object)} 997: * for properties with <code>int</code> values. 998: * 999: * @specnote It seems that in JDK1.5 all property related methods have been 1000: * moved to java.awt.Component, except this and 2 others. We call 1001: * super here. I guess this will also be removed in one of the next 1002: * releases. 1003: */ 1004: public void firePropertyChange(String propertyName, int oldValue, 1005: int newValue) 1006: { 1007: super.firePropertyChange(propertyName, oldValue, newValue); 1008: } 1009: 1010: /** 1011: * Call {@link VetoableChangeListener#vetoableChange} on all listeners 1012: * registered to listen to a given property. Any method which changes 1013: * the specified property of this component should call this method. 1014: * 1015: * @param propertyName The property which changed 1016: * @param oldValue The old value of the property 1017: * @param newValue The new value of the property 1018: * 1019: * @throws PropertyVetoException if the change was vetoed by a listener 1020: * 1021: * @see #addVetoableChangeListener 1022: * @see #removeVetoableChangeListener 1023: */ 1024: protected void fireVetoableChange(String propertyName, Object oldValue, 1025: Object newValue) 1026: throws PropertyVetoException 1027: { 1028: VetoableChangeListener[] listeners = getVetoableChangeListeners(); 1029: 1030: PropertyChangeEvent evt = 1031: new PropertyChangeEvent(this, propertyName, oldValue, newValue); 1032: 1033: for (int i = 0; i < listeners.length; i++) 1034: listeners[i].vetoableChange(evt); 1035: } 1036: 1037: /** 1038: * Get the value of the accessibleContext property for this component. 1039: * 1040: * @return the current value of the property 1041: */ 1042: public AccessibleContext getAccessibleContext() 1043: { 1044: return null; 1045: } 1046: 1047: /** 1048: * Get the value of the {@link #alignmentX} property. 1049: * 1050: * @return The current value of the property. 1051: * 1052: * @see #setAlignmentX 1053: * @see #alignmentY 1054: */ 1055: public float getAlignmentX() 1056: { 1057: float ret = alignmentX; 1058: if (alignmentX < 0) 1059: // alignment has not been set explicitly. 1060: ret = super.getAlignmentX(); 1061: 1062: return ret; 1063: } 1064: 1065: /** 1066: * Get the value of the {@link #alignmentY} property. 1067: * 1068: * @return The current value of the property. 1069: * 1070: * @see #setAlignmentY 1071: * @see #alignmentX 1072: */ 1073: public float getAlignmentY() 1074: { 1075: float ret = alignmentY; 1076: if (alignmentY < 0) 1077: // alignment has not been set explicitly. 1078: ret = super.getAlignmentY(); 1079: 1080: return ret; 1081: } 1082: 1083: /** 1084: * Get the current value of the {@link #autoscrolls} property. 1085: * 1086: * @return The current value of the property 1087: */ 1088: public boolean getAutoscrolls() 1089: { 1090: return autoscrolls; 1091: } 1092: 1093: /** 1094: * Set the value of the {@link #border} property. 1095: * 1096: * @param newBorder The new value of the property 1097: * 1098: * @see #getBorder 1099: */ 1100: public void setBorder(Border newBorder) 1101: { 1102: Border oldBorder = getBorder(); 1103: if (oldBorder == newBorder) 1104: return; 1105: 1106: border = newBorder; 1107: firePropertyChange("border", oldBorder, newBorder); 1108: repaint(); 1109: } 1110: 1111: /** 1112: * Get the value of the {@link #border} property. 1113: * 1114: * @return The property's current value 1115: * 1116: * @see #setBorder 1117: */ 1118: public Border getBorder() 1119: { 1120: return border; 1121: } 1122: 1123: /** 1124: * Get the component's current bounding box. If a rectangle is provided, 1125: * use this as the return value (adjusting its fields in place); 1126: * otherwise (of <code>null</code> is provided) return a new {@link 1127: * Rectangle}. 1128: * 1129: * @param rv Optional return value to use 1130: * 1131: * @return A rectangle bounding the component 1132: */ 1133: public Rectangle getBounds(Rectangle rv) 1134: { 1135: if (rv == null) 1136: return new Rectangle(getX(), getY(), getWidth(), getHeight()); 1137: else 1138: { 1139: rv.setBounds(getX(), getY(), getWidth(), getHeight()); 1140: return rv; 1141: } 1142: } 1143: 1144: /** 1145: * Prepares a graphics context for painting this object. If {@link 1146: * #debugGraphicsOptions} is not equal to {@link 1147: * DebugGraphics#NONE_OPTION}, produce a new {@link DebugGraphics} object 1148: * wrapping the parameter. Otherwise configure the parameter with this 1149: * component's foreground color and font. 1150: * 1151: * @param g The graphics context to wrap or configure 1152: * 1153: * @return A graphics context to paint this object with 1154: * 1155: * @see #debugGraphicsOptions 1156: * @see #paint 1157: */ 1158: protected Graphics getComponentGraphics(Graphics g) 1159: { 1160: Graphics g2 = g; 1161: int options = getDebugGraphicsOptions(); 1162: if (options != DebugGraphics.NONE_OPTION) 1163: { 1164: if (!(g2 instanceof DebugGraphics)) 1165: g2 = new DebugGraphics(g); 1166: DebugGraphics dg = (DebugGraphics) g2; 1167: dg.setDebugOptions(dg.getDebugOptions() | options); 1168: } 1169: g2.setFont(this.getFont()); 1170: g2.setColor(this.getForeground()); 1171: return g2; 1172: } 1173: 1174: /** 1175: * Get the value of the {@link #debugGraphicsOptions} property. 1176: * 1177: * @return The current value of the property. 1178: * 1179: * @see #setDebugGraphicsOptions 1180: * @see #debugGraphicsOptions 1181: */ 1182: public int getDebugGraphicsOptions() 1183: { 1184: String option = System.getProperty("gnu.javax.swing.DebugGraphics"); 1185: int options = debugGraphicsOptions; 1186: if (option != null && option.length() != 0) 1187: { 1188: if (options < 0) 1189: options = 0; 1190: 1191: if (option.equals("LOG")) 1192: options |= DebugGraphics.LOG_OPTION; 1193: else if (option.equals("FLASH")) 1194: options |= DebugGraphics.FLASH_OPTION; 1195: } 1196: return options; 1197: } 1198: 1199: /** 1200: * Get the component's insets, which are calculated from 1201: * the {@link #border} property. If the border is <code>null</code>, 1202: * calls {@link Container#getInsets}. 1203: * 1204: * @return The component's current insets 1205: */ 1206: public Insets getInsets() 1207: { 1208: if (border == null) 1209: return super.getInsets(); 1210: return getBorder().getBorderInsets(this); 1211: } 1212: 1213: /** 1214: * Get the component's insets, which are calculated from the {@link 1215: * #border} property. If the border is <code>null</code>, calls {@link 1216: * Container#getInsets}. The passed-in {@link Insets} value will be 1217: * used as the return value, if possible. 1218: * 1219: * @param insets Return value object to reuse, if possible 1220: * 1221: * @return The component's current insets 1222: */ 1223: public Insets getInsets(Insets insets) 1224: { 1225: Insets t = getInsets(); 1226: 1227: if (insets == null) 1228: return t; 1229: 1230: insets.left = t.left; 1231: insets.right = t.right; 1232: insets.top = t.top; 1233: insets.bottom = t.bottom; 1234: return insets; 1235: } 1236: 1237: /** 1238: * Get the component's location. The passed-in {@link Point} value 1239: * will be used as the return value, if possible. 1240: * 1241: * @param rv Return value object to reuse, if possible 1242: * 1243: * @return The component's current location 1244: */ 1245: public Point getLocation(Point rv) 1246: { 1247: if (rv == null) 1248: return new Point(getX(), getY()); 1249: 1250: rv.setLocation(getX(), getY()); 1251: return rv; 1252: } 1253: 1254: /** 1255: * Get the component's maximum size. If the {@link #maximumSize} property 1256: * has been explicitly set, it is returned. If the {@link #maximumSize} 1257: * property has not been set but the {@link #ui} property has been, the 1258: * result of {@link ComponentUI#getMaximumSize} is returned. If neither 1259: * property has been set, the result of {@link Container#getMaximumSize} 1260: * is returned. 1261: * 1262: * @return The maximum size of the component 1263: * 1264: * @see #maximumSize 1265: * @see #setMaximumSize 1266: */ 1267: public Dimension getMaximumSize() 1268: { 1269: if (maximumSize != null) 1270: return maximumSize; 1271: 1272: if (ui != null) 1273: { 1274: Dimension s = ui.getMaximumSize(this); 1275: if (s != null) 1276: return s; 1277: } 1278: 1279: Dimension p = super.getMaximumSize(); 1280: return p; 1281: } 1282: 1283: /** 1284: * Get the component's minimum size. If the {@link #minimumSize} property 1285: * has been explicitly set, it is returned. If the {@link #minimumSize} 1286: * property has not been set but the {@link #ui} property has been, the 1287: * result of {@link ComponentUI#getMinimumSize} is returned. If neither 1288: * property has been set, the result of {@link Container#getMinimumSize} 1289: * is returned. 1290: * 1291: * @return The minimum size of the component 1292: * 1293: * @see #minimumSize 1294: * @see #setMinimumSize 1295: */ 1296: public Dimension getMinimumSize() 1297: { 1298: if (minimumSize != null) 1299: return minimumSize; 1300: 1301: if (ui != null) 1302: { 1303: Dimension s = ui.getMinimumSize(this); 1304: if (s != null) 1305: return s; 1306: } 1307: 1308: Dimension p = super.getMinimumSize(); 1309: return p; 1310: } 1311: 1312: /** 1313: * Get the component's preferred size. If the {@link #preferredSize} 1314: * property has been explicitly set, it is returned. If the {@link 1315: * #preferredSize} property has not been set but the {@link #ui} property 1316: * has been, the result of {@link ComponentUI#getPreferredSize} is 1317: * returned. If neither property has been set, the result of {@link 1318: * Container#getPreferredSize} is returned. 1319: * 1320: * @return The preferred size of the component 1321: * 1322: * @see #preferredSize 1323: * @see #setPreferredSize 1324: */ 1325: public Dimension getPreferredSize() 1326: { 1327: Dimension prefSize = null; 1328: if (preferredSize != null) 1329: prefSize = new Dimension(preferredSize); 1330: 1331: else if (ui != null) 1332: { 1333: Dimension s = ui.getPreferredSize(this); 1334: if (s != null) 1335: prefSize = s; 1336: } 1337: 1338: if (prefSize == null) 1339: prefSize = super.getPreferredSize(); 1340: 1341: return prefSize; 1342: } 1343: 1344: /** 1345: * Checks if a maximum size was explicitely set on the component. 1346: * 1347: * @return <code>true</code> if a maximum size was set, 1348: * <code>false</code> otherwise 1349: * 1350: * @since 1.3 1351: */ 1352: public boolean isMaximumSizeSet() 1353: { 1354: return maximumSize != null; 1355: } 1356: 1357: /** 1358: * Checks if a minimum size was explicitely set on the component. 1359: * 1360: * @return <code>true</code> if a minimum size was set, 1361: * <code>false</code> otherwise 1362: * 1363: * @since 1.3 1364: */ 1365: public boolean isMinimumSizeSet() 1366: { 1367: return minimumSize != null; 1368: } 1369: 1370: /** 1371: * Checks if a preferred size was explicitely set on the component. 1372: * 1373: * @return <code>true</code> if a preferred size was set, 1374: * <code>false</code> otherwise 1375: * 1376: * @since 1.3 1377: */ 1378: public boolean isPreferredSizeSet() 1379: { 1380: return preferredSize != null; 1381: } 1382: 1383: /** 1384: * Return the value of the <code>nextFocusableComponent</code> property. 1385: * 1386: * @return The current value of the property, or <code>null</code> 1387: * if none has been set. 1388: * 1389: * @deprecated See {@link java.awt.FocusTraversalPolicy} 1390: */ 1391: public Component getNextFocusableComponent() 1392: { 1393: Container focusRoot = this; 1394: if (! this.isFocusCycleRoot()) 1395: focusRoot = getFocusCycleRootAncestor(); 1396: 1397: FocusTraversalPolicy policy = focusRoot.getFocusTraversalPolicy(); 1398: return policy.getComponentAfter(focusRoot, this); 1399: } 1400: 1401: /** 1402: * Return the set of {@link KeyStroke} objects which are registered 1403: * to initiate actions on this component. 1404: * 1405: * @return An array of the registered keystrokes 1406: */ 1407: public KeyStroke[] getRegisteredKeyStrokes() 1408: { 1409: return null; 1410: } 1411: 1412: /** 1413: * Returns the first ancestor of this component which is a {@link JRootPane}. 1414: * Equivalent to calling <code>SwingUtilities.getRootPane(this);</code>. 1415: * 1416: * @return An ancestral JRootPane, or <code>null</code> if none exists. 1417: */ 1418: public JRootPane getRootPane() 1419: { 1420: JRootPane p = SwingUtilities.getRootPane(this); 1421: return p; 1422: } 1423: 1424: /** 1425: * Get the component's size. The passed-in {@link Dimension} value 1426: * will be used as the return value, if possible. 1427: * 1428: * @param rv Return value object to reuse, if possible 1429: * 1430: * @return The component's current size 1431: */ 1432: public Dimension getSize(Dimension rv) 1433: { 1434: if (rv == null) 1435: return new Dimension(getWidth(), getHeight()); 1436: else 1437: { 1438: rv.setSize(getWidth(), getHeight()); 1439: return rv; 1440: } 1441: } 1442: 1443: /** 1444: * Return the <code>toolTip</code> property of this component, creating it and 1445: * setting it if it is currently <code>null</code>. This method can be 1446: * overridden in subclasses which wish to control the exact form of 1447: * tooltip created. 1448: * 1449: * @return The current toolTip 1450: */ 1451: public JToolTip createToolTip() 1452: { 1453: JToolTip toolTip = new JToolTip(); 1454: toolTip.setComponent(this); 1455: toolTip.setTipText(toolTipText); 1456: 1457: return toolTip; 1458: } 1459: 1460: /** 1461: * Return the location at which the {@link #toolTipText} property should be 1462: * displayed, when triggered by a particular mouse event. 1463: * 1464: * @param event The event the tooltip is being presented in response to 1465: * 1466: * @return The point at which to display a tooltip, or <code>null</code> 1467: * if swing is to choose a default location. 1468: */ 1469: public Point getToolTipLocation(MouseEvent event) 1470: { 1471: return null; 1472: } 1473: 1474: /** 1475: * Set the value of the {@link #toolTipText} property. 1476: * 1477: * @param text The new property value 1478: * 1479: * @see #getToolTipText() 1480: */ 1481: public void setToolTipText(String text) 1482: { 1483: if (text == null) 1484: { 1485: ToolTipManager.sharedInstance().unregisterComponent(this); 1486: toolTipText = null; 1487: return; 1488: } 1489: 1490: // XXX: The tip text doesn't get updated unless you set it to null 1491: // and then to something not-null. This is consistent with the behaviour 1492: // of Sun's ToolTipManager. 1493: 1494: String oldText = toolTipText; 1495: toolTipText = text; 1496: 1497: if (oldText == null) 1498: ToolTipManager.sharedInstance().registerComponent(this); 1499: } 1500: 1501: /** 1502: * Get the value of the {@link #toolTipText} property. 1503: * 1504: * @return The current property value 1505: * 1506: * @see #setToolTipText 1507: */ 1508: public String getToolTipText() 1509: { 1510: return toolTipText; 1511: } 1512: 1513: /** 1514: * Get the value of the {@link #toolTipText} property, in response to a 1515: * particular mouse event. 1516: * 1517: * @param event The mouse event which triggered the tooltip 1518: * 1519: * @return The current property value 1520: * 1521: * @see #setToolTipText 1522: */ 1523: public String getToolTipText(MouseEvent event) 1524: { 1525: return getToolTipText(); 1526: } 1527: 1528: /** 1529: * Return the top level ancestral container (usually a {@link 1530: * java.awt.Window} or {@link java.applet.Applet}) which this component is 1531: * contained within, or <code>null</code> if no ancestors exist. 1532: * 1533: * @return The top level container, if it exists 1534: */ 1535: public Container getTopLevelAncestor() 1536: { 1537: Container c = getParent(); 1538: for (Container peek = c; peek != null; peek = peek.getParent()) 1539: c = peek; 1540: return c; 1541: } 1542: 1543: /** 1544: * Compute the component's visible rectangle, which is defined 1545: * recursively as either the component's bounds, if it has no parent, or 1546: * the intersection of the component's bounds with the visible rectangle 1547: * of its parent. 1548: * 1549: * @param rect The return value slot to place the visible rectangle in 1550: */ 1551: public void computeVisibleRect(Rectangle rect) 1552: { 1553: Component c = getParent(); 1554: if (c != null && c instanceof JComponent) 1555: { 1556: ((JComponent) c).computeVisibleRect(rect); 1557: rect.translate(-getX(), -getY()); 1558: rect = SwingUtilities.computeIntersection(0, 0, getWidth(), 1559: getHeight(), rect); 1560: } 1561: else 1562: rect.setRect(0, 0, getWidth(), getHeight()); 1563: } 1564: 1565: /** 1566: * Return the component's visible rectangle in a new {@link Rectangle}, 1567: * rather than via a return slot. 1568: * 1569: * @return the component's visible rectangle 1570: * 1571: * @see #computeVisibleRect(Rectangle) 1572: */ 1573: public Rectangle getVisibleRect() 1574: { 1575: Rectangle r = new Rectangle(); 1576: computeVisibleRect(r); 1577: return r; 1578: } 1579: 1580: /** 1581: * <p>Requests that this component receive input focus, giving window 1582: * focus to the top level ancestor of this component. Only works on 1583: * displayable, focusable, visible components.</p> 1584: * 1585: * <p>This method should not be called by clients; it is intended for 1586: * focus implementations. Use {@link Component#requestFocus()} instead.</p> 1587: * 1588: * @see Component#requestFocus() 1589: */ 1590: public void grabFocus() 1591: { 1592: requestFocus(); 1593: } 1594: 1595: /** 1596: * Get the value of the {@link #doubleBuffered} property. 1597: * 1598: * @return The property's current value 1599: */ 1600: public boolean isDoubleBuffered() 1601: { 1602: return doubleBuffered; 1603: } 1604: 1605: /** 1606: * Return <code>true</code> if the provided component has no native peer; 1607: * in other words, if it is a "lightweight component". 1608: * 1609: * @param c The component to test for lightweight-ness 1610: * 1611: * @return Whether or not the component is lightweight 1612: */ 1613: public static boolean isLightweightComponent(Component c) 1614: { 1615: return c.getPeer() instanceof LightweightPeer; 1616: } 1617: 1618: /** 1619: * Return <code>true</code> if you wish this component to manage its own 1620: * focus. In particular: if you want this component to be sent 1621: * <code>TAB</code> and <code>SHIFT+TAB</code> key events, and to not 1622: * have its children considered as focus transfer targets. If 1623: * <code>true</code>, focus traversal around this component changes to 1624: * <code>CTRL+TAB</code> and <code>CTRL+SHIFT+TAB</code>. 1625: * 1626: * @return <code>true</code> if you want this component to manage its own 1627: * focus, otherwise (by default) <code>false</code> 1628: * 1629: * @deprecated 1.4 Use {@link Component#setFocusTraversalKeys(int, Set)} and 1630: * {@link Container#setFocusCycleRoot(boolean)} instead 1631: */ 1632: public boolean isManagingFocus() 1633: { 1634: return false; 1635: } 1636: 1637: /** 1638: * Return the current value of the {@link #opaque} property. 1639: * 1640: * @return The current property value 1641: */ 1642: public boolean isOpaque() 1643: { 1644: return opaque; 1645: } 1646: 1647: /** 1648: * Return <code>true</code> if the component can guarantee that none of its 1649: * children will overlap in Z-order. This is a hint to the painting system. 1650: * The default is to return <code>true</code>, but some components such as 1651: * {@link JLayeredPane} should override this to return <code>false</code>. 1652: * 1653: * @return Whether the component tiles its children 1654: */ 1655: public boolean isOptimizedDrawingEnabled() 1656: { 1657: return true; 1658: } 1659: 1660: /** 1661: * Return <code>true</code> if this component is currently painting a tile, 1662: * this means that paint() is called again on another child component. This 1663: * method returns <code>false</code> if this component does not paint a tile 1664: * or if the last tile is currently painted. 1665: * 1666: * @return whether the component is painting a tile 1667: */ 1668: public boolean isPaintingTile() 1669: { 1670: return paintingTile; 1671: } 1672: 1673: /** 1674: * Get the value of the {@link #requestFocusEnabled} property. 1675: * 1676: * @return The current value of the property 1677: */ 1678: public boolean isRequestFocusEnabled() 1679: { 1680: return requestFocusEnabled; 1681: } 1682: 1683: /** 1684: * Return <code>true</code> if this component is a validation root; this 1685: * will cause calls to {@link #invalidate()} in this component's children 1686: * to be "captured" at this component, and not propagate to its parents. 1687: * For most components this should return <code>false</code>, but some 1688: * components such as {@link JViewport} will want to return 1689: * <code>true</code>. 1690: * 1691: * @return Whether this component is a validation root 1692: */ 1693: public boolean isValidateRoot() 1694: { 1695: return false; 1696: } 1697: 1698: /** 1699: * <p>Paint the component. This is a delicate process, and should only be 1700: * called from the repaint thread, under control of the {@link 1701: * RepaintManager}. Client code should usually call {@link #repaint()} to 1702: * trigger painting.</p> 1703: * 1704: * <p>The body of the <code>paint</code> call involves calling {@link 1705: * #paintComponent}, {@link #paintBorder}, and {@link #paintChildren} in 1706: * order. If you want to customize painting behavior, you should override 1707: * one of these methods rather than <code>paint</code>.</p> 1708: * 1709: * <p>For more details on the painting sequence, see <a 1710: * href="http://java.sun.com/products/jfc/tsc/articles/painting/index.html"> 1711: * this article</a>.</p> 1712: * 1713: * @param g The graphics context to paint with 1714: * 1715: * @see #paintImmediately(Rectangle) 1716: */ 1717: public void paint(Graphics g) 1718: { 1719: RepaintManager rm = RepaintManager.currentManager(this); 1720: // We do a little stunt act here to switch on double buffering if it's 1721: // not already on. If we are not already doublebuffered, then we jump 1722: // into the method paintDoubleBuffered, which turns on the double buffer 1723: // and then calls paint(g) again. In the second call we go into the else 1724: // branch of this if statement and actually paint things to the double 1725: // buffer. When this method completes, the call stack unwinds back to 1726: // paintDoubleBuffered, where the buffer contents is finally drawn to the 1727: // screen. 1728: if (!isPaintingDoubleBuffered && isDoubleBuffered() 1729: && rm.isDoubleBufferingEnabled()) 1730: { 1731: Rectangle clip = g.getClipBounds(); 1732: paintDoubleBuffered(clip); 1733: } 1734: else 1735: { 1736: if (getClientProperty("bufferedDragging") != null 1737: && dragBuffer == null) 1738: { 1739: initializeDragBuffer(); 1740: } 1741: else if (getClientProperty("bufferedDragging") == null 1742: && dragBuffer != null) 1743: { 1744: dragBuffer = null; 1745: } 1746: 1747: if (g.getClip() == null) 1748: g.setClip(0, 0, getWidth(), getHeight()); 1749: if (dragBuffer != null && dragBufferInitialized) 1750: { 1751: g.drawImage(dragBuffer, 0, 0, this); 1752: } 1753: else 1754: { 1755: Graphics g2 = getComponentGraphics(g); 1756: paintComponent(g2); 1757: paintBorder(g2); 1758: paintChildren(g2); 1759: } 1760: } 1761: } 1762: 1763: /** 1764: * Initializes the drag buffer by creating a new image and painting this 1765: * component into it. 1766: */ 1767: private void initializeDragBuffer() 1768: { 1769: dragBufferInitialized = false; 1770: // Allocate new dragBuffer if the current one is too small. 1771: if (dragBuffer == null || dragBuffer.getWidth(this) < getWidth() 1772: || dragBuffer.getHeight(this) < getHeight()) 1773: { 1774: dragBuffer = createImage(getWidth(), getHeight()); 1775: } 1776: Graphics g = dragBuffer.getGraphics(); 1777: paint(g); 1778: g.dispose(); 1779: dragBufferInitialized = true; 1780: } 1781: 1782: /** 1783: * Paint the component's border. This usually means calling {@link 1784: * Border#paintBorder} on the {@link #border} property, if it is 1785: * non-<code>null</code>. You may override this if you wish to customize 1786: * border painting behavior. The border is painted after the component's 1787: * body, but before the component's children. 1788: * 1789: * @param g The graphics context with which to paint the border 1790: * 1791: * @see #paint 1792: * @see #paintChildren 1793: * @see #paintComponent 1794: */ 1795: protected void paintBorder(Graphics g) 1796: { 1797: if (getBorder() != null) 1798: getBorder().paintBorder(this, g, 0, 0, getWidth(), getHeight()); 1799: } 1800: 1801: /** 1802: * Paint the component's children. This usually means calling {@link 1803: * Container#paint}, which recursively calls {@link #paint} on any of the 1804: * component's children, with appropriate changes to coordinate space and 1805: * clipping region. You may override this if you wish to customize 1806: * children painting behavior. The children are painted after the 1807: * component's body and border. 1808: * 1809: * @param g The graphics context with which to paint the children 1810: * 1811: * @see #paint 1812: * @see #paintBorder 1813: * @see #paintComponent 1814: */ 1815: protected void paintChildren(Graphics g) 1816: { 1817: if (getComponentCount() > 0) 1818: { 1819: if (isOptimizedDrawingEnabled()) 1820: paintChildrenOptimized(g); 1821: else 1822: paintChildrenWithOverlap(g); 1823: } 1824: } 1825: 1826: /** 1827: * Paints the children of this JComponent in the case when the component 1828: * is not marked as optimizedDrawingEnabled, that means the container cannot 1829: * guarantee that it's children are tiled. For this case we must 1830: * perform a more complex optimization to determine the minimal rectangle 1831: * to be painted for each child component. 1832: * 1833: * @param g the graphics context to use 1834: */ 1835: private void paintChildrenWithOverlap(Graphics g) 1836: { 1837: Shape originalClip = g.getClip(); 1838: Rectangle inner = SwingUtilities.calculateInnerArea(this, rectCache); 1839: g.clipRect(inner.x, inner.y, inner.width, inner.height); 1840: Component[] children = getComponents(); 1841: 1842: // Find the rectangles that need to be painted for each child component. 1843: // We push on this list arrays that have the Rectangles to be painted as 1844: // the first elements and the component to be painted as the last one. 1845: // Later we go through that list in reverse order and paint the rectangles. 1846: ArrayList paintRegions = new ArrayList(children.length); 1847: ArrayList paintRectangles = new ArrayList(); 1848: ArrayList newPaintRects = new ArrayList(); 1849: paintRectangles.add(g.getClipBounds()); 1850: ArrayList componentRectangles = new ArrayList(); 1851: 1852: // Go through children from top to bottom and find out their paint 1853: // rectangles. 1854: for (int index = 0; paintRectangles.size() > 0 && 1855: index < children.length; index++) 1856: { 1857: Component comp = children[index]; 1858: if (! comp.isVisible()) 1859: continue; 1860: 1861: Rectangle compBounds = comp.getBounds(); 1862: boolean isOpaque = comp instanceof JComponent 1863: && ((JComponent) comp).isOpaque(); 1864: 1865: // Add all the current paint rectangles that intersect with the 1866: // component to the component's paint rectangle array. 1867: for (int i = paintRectangles.size() - 1; i >= 0; i--) 1868: { 1869: Rectangle r = (Rectangle) paintRectangles.get(i); 1870: if (r.intersects(compBounds)) 1871: { 1872: Rectangle compRect = r.intersection(compBounds); 1873: componentRectangles.add(compRect); 1874: // If the component is opaque, split up each paint rect and 1875: // add paintRect - compBounds to the newPaintRects array. 1876: if (isOpaque) 1877: { 1878: int x, y, w, h; 1879: Rectangle rect = new Rectangle(); 1880: 1881: // The north retangle. 1882: x = Math.max(compBounds.x, r.x); 1883: y = r.y; 1884: w = Math.min(compBounds.width, r.width + r.x - x); 1885: h = compBounds.y - r.y; 1886: rect.setBounds(x, y, w, h); 1887: if (! rect.isEmpty()) 1888: { 1889: newPaintRects.add(rect); 1890: rect = new Rectangle(); 1891: } 1892: 1893: // The south rectangle. 1894: x = Math.max(compBounds.x, r.x); 1895: y = compBounds.y + compBounds.height; 1896: w = Math.min(compBounds.width, r.width + r.x - x); 1897: h = r.height - (compBounds.y - r.y) - compBounds.height; 1898: rect.setBounds(x, y, w, h); 1899: if (! rect.isEmpty()) 1900: { 1901: newPaintRects.add(rect); 1902: rect = new Rectangle(); 1903: } 1904: 1905: // The west rectangle. 1906: x = r.x; 1907: y = r.y; 1908: w = compBounds.x - r.x; 1909: h = r.height; 1910: rect.setBounds(x, y, w, h); 1911: if (! rect.isEmpty()) 1912: { 1913: newPaintRects.add(rect); 1914: rect = new Rectangle(); 1915: } 1916: 1917: // The east rectangle. 1918: x = compBounds.x + compBounds.width; 1919: y = r.y; 1920: w = r.width - (compBounds.x - r.x) - compBounds.width; 1921: h = r.height; 1922: rect.setBounds(x, y, w, h); 1923: if (! rect.isEmpty()) 1924: { 1925: newPaintRects.add(rect); 1926: } 1927: } 1928: else 1929: { 1930: // Not opaque, need to reuse the current paint rectangles 1931: // for the next component. 1932: newPaintRects.add(r); 1933: } 1934: 1935: } 1936: else 1937: { 1938: newPaintRects.add(r); 1939: } 1940: } 1941: 1942: // Replace the paintRectangles with the new split up 1943: // paintRectangles. 1944: paintRectangles.clear(); 1945: paintRectangles.addAll(newPaintRects); 1946: newPaintRects.clear(); 1947: 1948: // Store paint rectangles if there are any for the current component. 1949: int compRectsSize = componentRectangles.size(); 1950: if (compRectsSize > 0) 1951: { 1952: componentRectangles.add(comp); 1953: paintRegions.add(componentRectangles); 1954: componentRectangles = new ArrayList(); 1955: } 1956: } 1957: 1958: // paintingTile becomes true just before we start painting the component's 1959: // children. 1960: paintingTile = true; 1961: 1962: // We must go through the painting regions backwards, because the 1963: // topmost components have been added first, followed by the components 1964: // below. 1965: int prEndIndex = paintRegions.size() - 1; 1966: for (int i = prEndIndex; i >= 0; i--) 1967: { 1968: // paintingTile must be set to false before we begin to start painting 1969: // the last tile. 1970: if (i == 0) 1971: paintingTile = false; 1972: 1973: ArrayList paintingRects = (ArrayList) paintRegions.get(i); 1974: // The last element is always the component. 1975: Component c = (Component) paintingRects.get(paintingRects.size() - 1); 1976: int endIndex = paintingRects.size() - 2; 1977: for (int j = 0; j <= endIndex; j++) 1978: { 1979: Rectangle cBounds = c.getBounds(); 1980: Rectangle bounds = (Rectangle) paintingRects.get(j); 1981: Rectangle oldClip = g.getClipBounds(); 1982: if (oldClip == null) 1983: oldClip = bounds; 1984: 1985: boolean translated = false; 1986: try 1987: { 1988: g.setClip(bounds); 1989: g.translate(cBounds.x, cBounds.y); 1990: translated = true; 1991: c.paint(g); 1992: } 1993: finally 1994: { 1995: if (translated) 1996: g.translate(-cBounds.x, -cBounds.y); 1997: g.setClip(oldClip); 1998: } 1999: } 2000: } 2001: g.setClip(originalClip); 2002: } 2003: 2004: /** 2005: * Paints the children of this container when it is marked as 2006: * optimizedDrawingEnabled. In this case the container can guarantee that 2007: * it's children are tiled, which allows for a much more efficient 2008: * algorithm to determine the minimum rectangles to be painted for 2009: * each child. 2010: * 2011: * @param g the graphics context to use 2012: */ 2013: private void paintChildrenOptimized(Graphics g) 2014: { 2015: Shape originalClip = g.getClip(); 2016: Rectangle inner = SwingUtilities.calculateInnerArea(this, rectCache); 2017: g.clipRect(inner.x, inner.y, inner.width, inner.height); 2018: Component[] children = getComponents(); 2019: 2020: // paintingTile becomes true just before we start painting the component's 2021: // children. 2022: paintingTile = true; 2023: for (int i = children.length - 1; i >= 0; i--) //children.length; i++) 2024: { 2025: // paintingTile must be set to false before we begin to start painting 2026: // the last tile. 2027: if (i == children.length - 1) 2028: paintingTile = false; 2029: 2030: if (!children[i].isVisible()) 2031: continue; 2032: 2033: Rectangle bounds = children[i].getBounds(rectCache); 2034: Rectangle oldClip = g.getClipBounds(); 2035: if (oldClip == null) 2036: oldClip = bounds; 2037: 2038: if (!g.hitClip(bounds.x, bounds.y, bounds.width, bounds.height)) 2039: continue; 2040: 2041: boolean translated = false; 2042: Graphics g2 = g.create(bounds.x, bounds.y, bounds.width, 2043: bounds.height); 2044: children[i].paint(g2); 2045: g2.dispose(); 2046: } 2047: g.setClip(originalClip); 2048: } 2049: 2050: /** 2051: * Paint the component's body. This usually means calling {@link 2052: * ComponentUI#update} on the {@link #ui} property of the component, if 2053: * it is non-<code>null</code>. You may override this if you wish to 2054: * customize the component's body-painting behavior. The component's body 2055: * is painted first, before the border and children. 2056: * 2057: * @param g The graphics context with which to paint the body 2058: * 2059: * @see #paint 2060: * @see #paintBorder 2061: * @see #paintChildren 2062: */ 2063: protected void paintComponent(Graphics g) 2064: { 2065: if (ui != null) 2066: { 2067: Graphics g2 = g; 2068: if (!(g instanceof Graphics2D)) 2069: g2 = g.create(); 2070: ui.update(g2, this); 2071: if (!(g instanceof Graphics2D)) 2072: g2.dispose(); 2073: } 2074: } 2075: 2076: /** 2077: * A variant of {@link #paintImmediately(Rectangle)} which takes 2078: * integer parameters. 2079: * 2080: * @param x The left x coordinate of the dirty region 2081: * @param y The top y coordinate of the dirty region 2082: * @param w The width of the dirty region 2083: * @param h The height of the dirty region 2084: */ 2085: public void paintImmediately(int x, int y, int w, int h) 2086: { 2087: paintImmediately(new Rectangle(x, y, w, h)); 2088: } 2089: 2090: /** 2091: * Transform the provided dirty rectangle for this component into the 2092: * appropriate ancestral {@link JRootPane} and call {@link #paint} on 2093: * that root pane. This method is called from the {@link RepaintManager} 2094: * and should always be called within the painting thread. 2095: * 2096: * <p>This method will acquire a double buffer from the {@link 2097: * RepaintManager} if the component's {@link #doubleBuffered} property is 2098: * <code>true</code> and the <code>paint</code> call is the 2099: * <em>first</em> recursive <code>paint</code> call inside swing.</p> 2100: * 2101: * <p>The method will also modify the provided {@link Graphics} context 2102: * via the {@link #getComponentGraphics} method. If you want to customize 2103: * the graphics object used for painting, you should override that method 2104: * rather than <code>paint</code>.</p> 2105: * 2106: * @param r The dirty rectangle to paint 2107: */ 2108: public void paintImmediately(Rectangle r) 2109: { 2110: // Try to find a root pane for this component. 2111: //Component root = findPaintRoot(r); 2112: Component root = findPaintRoot(r); 2113: // If no paint root is found, then this component is completely overlapped 2114: // by another component and we don't need repainting. 2115: if (root == null) 2116: return; 2117: if (root == null || !root.isShowing()) 2118: return; 2119: 2120: Rectangle rootClip = SwingUtilities.convertRectangle(this, r, root); 2121: if (root instanceof JComponent) 2122: ((JComponent) root).paintImmediately2(rootClip); 2123: else 2124: root.repaint(rootClip.x, rootClip.y, rootClip.width, rootClip.height); 2125: } 2126: 2127: /** 2128: * Performs the actual work of paintImmediatly on the repaint root. 2129: * 2130: * @param r the area to be repainted 2131: */ 2132: void paintImmediately2(Rectangle r) 2133: { 2134: RepaintManager rm = RepaintManager.currentManager(this); 2135: if (rm.isDoubleBufferingEnabled() && isDoubleBuffered()) 2136: paintDoubleBuffered(r); 2137: else 2138: paintSimple(r); 2139: } 2140: 2141: /** 2142: * Gets the root of the component given. If a parent of the 2143: * component is an instance of Applet, then the applet is 2144: * returned. The applet is considered the root for painting 2145: * and adding/removing components. Otherwise, the root Window 2146: * is returned if it exists. 2147: * 2148: * @param comp - The component to get the root for. 2149: * @return the parent root. An applet if it is a parent, 2150: * or the root window. If neither exist, null is returned. 2151: */ 2152: private Component getRoot(Component comp) 2153: { 2154: Applet app = null; 2155: 2156: while (comp != null) 2157: { 2158: if (app == null && comp instanceof Window) 2159: return comp; 2160: else if (comp instanceof Applet) 2161: app = (Applet) comp; 2162: comp = comp.getParent(); 2163: } 2164: 2165: return app; 2166: } 2167: 2168: /** 2169: * Performs double buffered repainting. 2170: */ 2171: private void paintDoubleBuffered(Rectangle r) 2172: { 2173: RepaintManager rm = RepaintManager.currentManager(this); 2174: 2175: // Paint on the offscreen buffer. 2176: Component root = getRoot(this); 2177: Image buffer = rm.getVolatileOffscreenBuffer(this, root.getWidth(), 2178: root.getHeight()); 2179: 2180: // The volatile offscreen buffer may be null when that's not supported 2181: // by the AWT backend. Fall back to normal backbuffer in this case. 2182: if (buffer == null) 2183: buffer = rm.getOffscreenBuffer(this, root.getWidth(), root.getHeight()); 2184: 2185: //Rectangle targetClip = SwingUtilities.convertRectangle(this, r, root); 2186: Point translation = SwingUtilities.convertPoint(this, 0, 0, root); 2187: Graphics g2 = buffer.getGraphics(); 2188: clipAndTranslateGraphics(root, this, g2); 2189: g2.clipRect(r.x, r.y, r.width, r.height); 2190: g2 = getComponentGraphics(g2); 2191: isPaintingDoubleBuffered = true; 2192: try 2193: { 2194: paint(g2); 2195: } 2196: finally 2197: { 2198: isPaintingDoubleBuffered = false; 2199: g2.dispose(); 2200: } 2201: 2202: // Paint the buffer contents on screen. 2203: rm.commitBuffer(root, new Rectangle(translation.x + r.x, 2204: translation.y + r.y, r.width, 2205: r.height)); 2206: } 2207: 2208: /** 2209: * Clips and translates the Graphics instance for painting on the double 2210: * buffer. This has to be done, so that it reflects the component clip of the 2211: * target component. 2212: * 2213: * @param root the root component (top-level container usually) 2214: * @param target the component to be painted 2215: * @param g the Graphics instance 2216: */ 2217: private void clipAndTranslateGraphics(Component root, Component target, 2218: Graphics g) 2219: { 2220: Component parent = target.getParent(); 2221: if (parent != root) 2222: clipAndTranslateGraphics(root, parent, g); 2223: 2224: g.translate(target.getX(), target.getY()); 2225: g.clipRect(0, 0, target.getWidth(), target.getHeight()); 2226: } 2227: 2228: /** 2229: * Performs normal painting without double buffering. 2230: * 2231: * @param r the area that should be repainted 2232: */ 2233: void paintSimple(Rectangle r) 2234: { 2235: Graphics g = getGraphics(); 2236: Graphics g2 = getComponentGraphics(g); 2237: g2.setClip(r); 2238: paint(g2); 2239: g2.dispose(); 2240: if (g != g2) 2241: g.dispose(); 2242: } 2243: 2244: /** 2245: * Return a string representation for this component, for use in 2246: * debugging. 2247: * 2248: * @return A string describing this component. 2249: */ 2250: protected String paramString() 2251: { 2252: StringBuffer sb = new StringBuffer(); 2253: sb.append(super.paramString()); 2254: sb.append(",alignmentX=").append(getAlignmentX()); 2255: sb.append(",alignmentY=").append(getAlignmentY()); 2256: sb.append(",border="); 2257: if (getBorder() != null) 2258: sb.append(getBorder()); 2259: sb.append(",maximumSize="); 2260: if (getMaximumSize() != null) 2261: sb.append(getMaximumSize()); 2262: sb.append(",minimumSize="); 2263: if (getMinimumSize() != null) 2264: sb.append(getMinimumSize()); 2265: sb.append(",preferredSize="); 2266: if (getPreferredSize() != null) 2267: sb.append(getPreferredSize()); 2268: return sb.toString(); 2269: } 2270: 2271: /** 2272: * A variant of {@link 2273: * #registerKeyboardAction(ActionListener,String,KeyStroke,int)} which 2274: * provides <code>null</code> for the command name. 2275: */ 2276: public void registerKeyboardAction(ActionListener act, 2277: KeyStroke stroke, 2278: int cond) 2279: { 2280: registerKeyboardAction(act, null, stroke, cond); 2281: } 2282: 2283: /* 2284: * There is some charmingly undocumented behavior sun seems to be using 2285: * to simulate the old register/unregister keyboard binding API. It's not 2286: * clear to me why this matters, but we shall endeavour to follow suit. 2287: * 2288: * Two main thing seem to be happening when you do registerKeyboardAction(): 2289: * 2290: * - no actionMap() entry gets created, just an entry in inputMap() 2291: * 2292: * - the inputMap() entry is a proxy class which invokes the the 2293: * binding's actionListener as a target, and which clobbers the command 2294: * name sent in the ActionEvent, providing the binding command name 2295: * instead. 2296: * 2297: * This much you can work out just by asking the input and action maps 2298: * what they contain after making bindings, and watching the event which 2299: * gets delivered to the recipient. Beyond that, it seems to be a 2300: * sun-private solution so I will only immitate it as much as it matters 2301: * to external observers. 2302: */ 2303: private static class ActionListenerProxy 2304: extends AbstractAction 2305: { 2306: ActionListener target; 2307: String bindingCommandName; 2308: 2309: public ActionListenerProxy(ActionListener li, 2310: String cmd) 2311: { 2312: target = li; 2313: bindingCommandName = cmd; 2314: } 2315: 2316: public void actionPerformed(ActionEvent e) 2317: { 2318: ActionEvent derivedEvent = new ActionEvent(e.getSource(), 2319: e.getID(), 2320: bindingCommandName, 2321: e.getModifiers()); 2322: target.actionPerformed(derivedEvent); 2323: } 2324: } 2325: 2326: 2327: /** 2328: * An obsolete method to register a keyboard action on this component. 2329: * You should use <code>getInputMap</code> and <code>getActionMap</code> 2330: * to fetch mapping tables from keystrokes to commands, and commands to 2331: * actions, respectively, and modify those mappings directly. 2332: * 2333: * @param act The action to be registered 2334: * @param cmd The command to deliver in the delivered {@link 2335: * java.awt.event.ActionEvent} 2336: * @param stroke The keystroke to register on 2337: * @param cond One of the values {@link #UNDEFINED_CONDITION}, 2338: * {@link #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}, {@link #WHEN_FOCUSED}, or 2339: * {@link #WHEN_IN_FOCUSED_WINDOW}, indicating the condition which must 2340: * be met for the action to be fired 2341: * 2342: * @see #unregisterKeyboardAction 2343: * @see #getConditionForKeyStroke 2344: * @see #resetKeyboardActions 2345: */ 2346: public void registerKeyboardAction(ActionListener act, 2347: String cmd, 2348: KeyStroke stroke, 2349: int cond) 2350: { 2351: getInputMap(cond).put(stroke, new ActionListenerProxy(act, cmd)); 2352: } 2353: 2354: public final void setInputMap(int condition, InputMap map) 2355: { 2356: enableEvents(AWTEvent.KEY_EVENT_MASK); 2357: switch (condition) 2358: { 2359: case WHEN_FOCUSED: 2360: inputMap_whenFocused = map; 2361: break; 2362: 2363: case WHEN_ANCESTOR_OF_FOCUSED_COMPONENT: 2364: inputMap_whenAncestorOfFocused = map; 2365: break; 2366: 2367: case WHEN_IN_FOCUSED_WINDOW: 2368: if (map != null && !(map instanceof ComponentInputMap)) 2369: throw new 2370: IllegalArgumentException("WHEN_IN_FOCUSED_WINDOW " + 2371: "InputMap must be a ComponentInputMap"); 2372: inputMap_whenInFocusedWindow = (ComponentInputMap)map; 2373: break; 2374: 2375: case UNDEFINED_CONDITION: 2376: default: 2377: throw new IllegalArgumentException(); 2378: } 2379: } 2380: 2381: /** 2382: * Returns the input map associated with this component for the given 2383: * state/condition. 2384: * 2385: * @param condition the state (one of {@link #WHEN_FOCUSED}, 2386: * {@link #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT} and 2387: * {@link #WHEN_IN_FOCUSED_WINDOW}). 2388: * 2389: * @return The input map. 2390: * @throws IllegalArgumentException if <code>condition</code> is not one of 2391: * the specified values. 2392: * @since 1.3 2393: */ 2394: public final InputMap getInputMap(int condition) 2395: { 2396: enableEvents(AWTEvent.KEY_EVENT_MASK); 2397: switch (condition) 2398: { 2399: case WHEN_FOCUSED: 2400: if (inputMap_whenFocused == null) 2401: inputMap_whenFocused = new InputMap(); 2402: return inputMap_whenFocused; 2403: 2404: case WHEN_ANCESTOR_OF_FOCUSED_COMPONENT: 2405: if (inputMap_whenAncestorOfFocused == null) 2406: inputMap_whenAncestorOfFocused = new InputMap(); 2407: return inputMap_whenAncestorOfFocused; 2408: 2409: case WHEN_IN_FOCUSED_WINDOW: 2410: if (inputMap_whenInFocusedWindow == null) 2411: inputMap_whenInFocusedWindow = new ComponentInputMap(this); 2412: return inputMap_whenInFocusedWindow; 2413: 2414: case UNDEFINED_CONDITION: 2415: default: 2416: throw new IllegalArgumentException("Invalid 'condition' argument: " 2417: + condition); 2418: } 2419: } 2420: 2421: /** 2422: * Returns the input map associated with this component for the 2423: * {@link #WHEN_FOCUSED} state. 2424: * 2425: * @return The input map. 2426: * 2427: * @since 1.3 2428: * @see #getInputMap(int) 2429: */ 2430: public final InputMap getInputMap() 2431: { 2432: return getInputMap(WHEN_FOCUSED); 2433: } 2434: 2435: public final ActionMap getActionMap() 2436: { 2437: if (actionMap == null) 2438: actionMap = new ActionMap(); 2439: return actionMap; 2440: } 2441: 2442: public final void setActionMap(ActionMap map) 2443: { 2444: actionMap = map; 2445: } 2446: 2447: /** 2448: * Return the condition that determines whether a registered action 2449: * occurs in response to the specified keystroke. 2450: * 2451: * As of 1.3 KeyStrokes can be registered with multiple simultaneous 2452: * conditions. 2453: * 2454: * @param ks The keystroke to return the condition of 2455: * 2456: * @return One of the values {@link #UNDEFINED_CONDITION}, {@link 2457: * #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}, {@link #WHEN_FOCUSED}, or {@link 2458: * #WHEN_IN_FOCUSED_WINDOW} 2459: * 2460: * @see #registerKeyboardAction(ActionListener, KeyStroke, int) 2461: * @see #unregisterKeyboardAction 2462: * @see #resetKeyboardActions 2463: */ 2464: public int getConditionForKeyStroke(KeyStroke ks) 2465: { 2466: if (inputMap_whenFocused != null 2467: && inputMap_whenFocused.get(ks) != null) 2468: return WHEN_FOCUSED; 2469: else if (inputMap_whenAncestorOfFocused != null 2470: && inputMap_whenAncestorOfFocused.get(ks) != null) 2471: return WHEN_ANCESTOR_OF_FOCUSED_COMPONENT; 2472: else if (inputMap_whenInFocusedWindow != null 2473: && inputMap_whenInFocusedWindow.get(ks) != null) 2474: return WHEN_IN_FOCUSED_WINDOW; 2475: else 2476: return UNDEFINED_CONDITION; 2477: } 2478: 2479: /** 2480: * Get the ActionListener (typically an {@link Action} object) which is 2481: * associated with a particular keystroke. 2482: * 2483: * @param ks The keystroke to retrieve the action of 2484: * 2485: * @return The action associated with the specified keystroke 2486: */ 2487: public ActionListener getActionForKeyStroke(KeyStroke ks) 2488: { 2489: Object cmd = getInputMap().get(ks); 2490: if (cmd != null) 2491: { 2492: if (cmd instanceof ActionListenerProxy) 2493: return (ActionListenerProxy) cmd; 2494: else if (cmd instanceof String) 2495: return getActionMap().get(cmd); 2496: } 2497: return null; 2498: } 2499: 2500: /** 2501: * A hook for subclasses which want to customize event processing. 2502: */ 2503: protected void processComponentKeyEvent(KeyEvent e) 2504: { 2505: // This method does nothing, it is meant to be overridden by subclasses. 2506: } 2507: 2508: /** 2509: * Override the default key dispatch system from Component to hook into 2510: * the swing {@link InputMap} / {@link ActionMap} system. 2511: * 2512: * See <a 2513: * href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html"> 2514: * this report</a> for more details, it's somewhat complex. 2515: */ 2516: protected void processKeyEvent(KeyEvent e) 2517: { 2518: // let the AWT event processing send KeyEvents to registered listeners 2519: super.processKeyEvent(e); 2520: processComponentKeyEvent(e); 2521: 2522: if (e.isConsumed()) 2523: return; 2524: 2525: // Input maps are checked in this order: 2526: // 1. The focused component's WHEN_FOCUSED map is checked. 2527: // 2. The focused component's WHEN_ANCESTOR_OF_FOCUSED_COMPONENT map. 2528: // 3. The WHEN_ANCESTOR_OF_FOCUSED_COMPONENT maps of the focused 2529: // component's parent, then its parent's parent, and so on. 2530: // Note: Input maps for disabled components are skipped. 2531: // 4. The WHEN_IN_FOCUSED_WINDOW maps of all the enabled components in 2532: // the focused window are searched. 2533: 2534: KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e); 2535: boolean pressed = e.getID() == KeyEvent.KEY_PRESSED; 2536: 2537: if (processKeyBinding(keyStroke, e, WHEN_FOCUSED, pressed)) 2538: { 2539: // This is step 1 from above comment. 2540: e.consume(); 2541: return; 2542: } 2543: else if (processKeyBinding 2544: (keyStroke, e, WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, pressed)) 2545: { 2546: // This is step 2 from above comment. 2547: e.consume(); 2548: return; 2549: } 2550: 2551: // This is step 3 from above comment. 2552: Container current = getParent(); 2553: while (current != null) 2554: { 2555: // If current is a JComponent, see if it handles the event in its 2556: // WHEN_ANCESTOR_OF_FOCUSED_COMPONENT maps. 2557: if ((current instanceof JComponent) && 2558: ((JComponent)current).processKeyBinding 2559: (keyStroke, e,WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, pressed)) 2560: { 2561: e.consume(); 2562: return; 2563: } 2564: 2565: // Stop when we've tried a top-level container and it didn't handle it 2566: if (current instanceof Window || current instanceof Applet) 2567: break; 2568: 2569: // Move up the hierarchy 2570: current = current.getParent(); 2571: } 2572: 2573: // Current being null means the JComponent does not currently have a 2574: // top-level ancestor, in which case we don't need to check 2575: // WHEN_IN_FOCUSED_WINDOW bindings. 2576: if (current == null || e.isConsumed()) 2577: return; 2578: 2579: // This is step 4 from above comment. KeyboardManager maintains mappings 2580: // related to WHEN_IN_FOCUSED_WINDOW bindings so that we don't have to 2581: // traverse the containment hierarchy each time. 2582: if (KeyboardManager.getManager().processKeyStroke(current, keyStroke, e)) 2583: e.consume(); 2584: } 2585: 2586: protected boolean processKeyBinding(KeyStroke ks, 2587: KeyEvent e, 2588: int condition, 2589: boolean pressed) 2590: { 2591: if (isEnabled()) 2592: { 2593: Action act = null; 2594: InputMap map = getInputMap(condition); 2595: if (map != null) 2596: { 2597: Object cmd = map.get(ks); 2598: if (cmd != null) 2599: { 2600: if (cmd instanceof ActionListenerProxy) 2601: act = (Action) cmd; 2602: else 2603: act = (Action) getActionMap().get(cmd); 2604: } 2605: } 2606: if (act != null && act.isEnabled()) 2607: return SwingUtilities.notifyAction(act, ks, e, this, e.getModifiers()); 2608: } 2609: return false; 2610: } 2611: 2612: /** 2613: * Remove a keyboard action registry. 2614: * 2615: * @param aKeyStroke The keystroke to unregister 2616: * 2617: * @see #registerKeyboardAction(ActionListener, KeyStroke, int) 2618: * @see #getConditionForKeyStroke 2619: * @see #resetKeyboardActions 2620: */ 2621: public void unregisterKeyboardAction(KeyStroke aKeyStroke) 2622: { 2623: ActionMap am = getActionMap(); 2624: // This loops through the conditions WHEN_FOCUSED, 2625: // WHEN_ANCESTOR_OF_FOCUSED_COMPONENT and WHEN_IN_FOCUSED_WINDOW. 2626: for (int cond = 0; cond < 3; cond++) 2627: { 2628: InputMap im = getInputMap(cond); 2629: if (im != null) 2630: { 2631: Object action = im.get(aKeyStroke); 2632: if (action != null && am != null) 2633: am.remove(action); 2634: im.remove(aKeyStroke); 2635: } 2636: } 2637: } 2638: 2639: 2640: /** 2641: * Reset all keyboard action registries. 2642: * 2643: * @see #registerKeyboardAction(ActionListener, KeyStroke, int) 2644: * @see #unregisterKeyboardAction 2645: * @see #getConditionForKeyStroke 2646: */ 2647: public void resetKeyboardActions() 2648: { 2649: if (inputMap_whenFocused != null) 2650: inputMap_whenFocused.clear(); 2651: if (inputMap_whenAncestorOfFocused != null) 2652: inputMap_whenAncestorOfFocused.clear(); 2653: if (inputMap_whenInFocusedWindow != null) 2654: inputMap_whenInFocusedWindow.clear(); 2655: if (actionMap != null) 2656: actionMap.clear(); 2657: } 2658: 2659: /** 2660: * Mark the described region of this component as dirty in the current 2661: * {@link RepaintManager}. This will queue an asynchronous repaint using 2662: * the system painting thread in the near future. 2663: * 2664: * @param tm ignored 2665: * @param x coordinate of the region to mark as dirty 2666: * @param y coordinate of the region to mark as dirty 2667: * @param width dimension of the region to mark as dirty 2668: * @param height dimension of the region to mark as dirty 2669: */ 2670: public void repaint(long tm, int x, int y, int width, int height) 2671: { 2672: RepaintManager.currentManager(this).addDirtyRegion(this, x, y, width, 2673: height); 2674: } 2675: 2676: /** 2677: * Mark the described region of this component as dirty in the current 2678: * {@link RepaintManager}. This will queue an asynchronous repaint using 2679: * the system painting thread in the near future. 2680: * 2681: * @param r The rectangle to mark as dirty 2682: */ 2683: public void repaint(Rectangle r) 2684: { 2685: RepaintManager.currentManager(this).addDirtyRegion(this, r.x, r.y, r.width, 2686: r.height); 2687: } 2688: 2689: /** 2690: * Request focus on the default component of this component's {@link 2691: * FocusTraversalPolicy}. 2692: * 2693: * @return The result of {@link #requestFocus()} 2694: * 2695: * @deprecated Use {@link #requestFocus()} on the default component provided 2696: * from the {@link FocusTraversalPolicy} instead. 2697: */ 2698: public boolean requestDefaultFocus() 2699: { 2700: return false; 2701: } 2702: 2703: /** 2704: * Queue a an invalidation and revalidation of this component, using 2705: * {@link RepaintManager#addInvalidComponent}. 2706: */ 2707: public void revalidate() 2708: { 2709: if (! EventQueue.isDispatchThread()) 2710: SwingUtilities.invokeLater(new Runnable() 2711: { 2712: public void run() 2713: { 2714: revalidate(); 2715: } 2716: }); 2717: else 2718: { 2719: invalidate(); 2720: RepaintManager.currentManager(this).addInvalidComponent(this); 2721: } 2722: } 2723: 2724: /** 2725: * Calls <code>scrollRectToVisible</code> on the component's parent. 2726: * Components which can service this call should override. 2727: * 2728: * @param r The rectangle to make visible 2729: */ 2730: public void scrollRectToVisible(Rectangle r) 2731: { 2732: Component p = getParent(); 2733: if (p instanceof JComponent) 2734: ((JComponent) p).scrollRectToVisible(r); 2735: } 2736: 2737: /** 2738: * Set the value of the {@link #alignmentX} property. 2739: * 2740: * @param a The new value of the property 2741: */ 2742: public void setAlignmentX(float a) 2743: { 2744: if (a < 0.0F) 2745: alignmentX = 0.0F; 2746: else if (a > 1.0) 2747: alignmentX = 1.0F; 2748: else 2749: alignmentX = a; 2750: } 2751: 2752: /** 2753: * Set the value of the {@link #alignmentY} property. 2754: * 2755: * @param a The new value of the property 2756: */ 2757: public void setAlignmentY(float a) 2758: { 2759: if (a < 0.0F) 2760: alignmentY = 0.0F; 2761: else if (a > 1.0) 2762: alignmentY = 1.0F; 2763: else 2764: alignmentY = a; 2765: } 2766: 2767: /** 2768: * Set the value of the {@link #autoscrolls} property. 2769: * 2770: * @param a The new value of the property 2771: */ 2772: public void setAutoscrolls(boolean a) 2773: { 2774: autoscrolls = a; 2775: clientAutoscrollsSet = true; 2776: } 2777: 2778: /** 2779: * Set the value of the {@link #debugGraphicsOptions} property. 2780: * 2781: * @param debugOptions The new value of the property 2782: */ 2783: public void setDebugGraphicsOptions(int debugOptions) 2784: { 2785: debugGraphicsOptions = debugOptions; 2786: } 2787: 2788: /** 2789: * Set the value of the {@link #doubleBuffered} property. 2790: * 2791: * @param db The new value of the property 2792: */ 2793: public void setDoubleBuffered(boolean db) 2794: { 2795: doubleBuffered = db; 2796: } 2797: 2798: /** 2799: * Set the value of the <code>enabled</code> property. 2800: * 2801: * @param enable The new value of the property 2802: */ 2803: public void setEnabled(boolean enable) 2804: { 2805: if (enable == isEnabled()) 2806: return; 2807: super.setEnabled(enable); 2808: firePropertyChange("enabled", !enable, enable); 2809: repaint(); 2810: } 2811: 2812: /** 2813: * Set the value of the <code>font</code> property. 2814: * 2815: * @param f The new value of the property 2816: */ 2817: public void setFont(Font f) 2818: { 2819: if (f == getFont()) 2820: return; 2821: super.setFont(f); 2822: revalidate(); 2823: repaint(); 2824: } 2825: 2826: /** 2827: * Set the value of the <code>background</code> property. 2828: * 2829: * @param bg The new value of the property 2830: */ 2831: public void setBackground(Color bg) 2832: { 2833: if (bg == getBackground()) 2834: return; 2835: super.setBackground(bg); 2836: repaint(); 2837: } 2838: 2839: /** 2840: * Set the value of the <code>foreground</code> property. 2841: * 2842: * @param fg The new value of the property 2843: */ 2844: public void setForeground(Color fg) 2845: { 2846: if (fg == getForeground()) 2847: return; 2848: super.setForeground(fg); 2849: repaint(); 2850: } 2851: 2852: /** 2853: * Set the value of the {@link #maximumSize} property. The passed value is 2854: * copied, the later direct changes on the argument have no effect on the 2855: * property value. 2856: * 2857: * @param max The new value of the property 2858: */ 2859: public void setMaximumSize(Dimension max) 2860: { 2861: Dimension oldMaximumSize = maximumSize; 2862: if (max != null) 2863: maximumSize = new Dimension(max); 2864: else 2865: maximumSize = null; 2866: firePropertyChange("maximumSize", oldMaximumSize, maximumSize); 2867: } 2868: 2869: /** 2870: * Set the value of the {@link #minimumSize} property. The passed value is 2871: * copied, the later direct changes on the argument have no effect on the 2872: * property value. 2873: * 2874: * @param min The new value of the property 2875: */ 2876: public void setMinimumSize(Dimension min) 2877: { 2878: Dimension oldMinimumSize = minimumSize; 2879: if (min != null) 2880: minimumSize = new Dimension(min); 2881: else 2882: minimumSize = null; 2883: firePropertyChange("minimumSize", oldMinimumSize, minimumSize); 2884: } 2885: 2886: /** 2887: * Set the value of the {@link #preferredSize} property. The passed value is 2888: * copied, the later direct changes on the argument have no effect on the 2889: * property value. 2890: * 2891: * @param pref The new value of the property 2892: */ 2893: public void setPreferredSize(Dimension pref) 2894: { 2895: Dimension oldPreferredSize = preferredSize; 2896: if (pref != null) 2897: preferredSize = new Dimension(pref); 2898: else 2899: preferredSize = null; 2900: firePropertyChange("preferredSize", oldPreferredSize, preferredSize); 2901: } 2902: 2903: /** 2904: * Set the specified component to be the next component in the 2905: * focus cycle, overriding the {@link FocusTraversalPolicy} for 2906: * this component. 2907: * 2908: * @param aComponent The component to set as the next focusable 2909: * 2910: * @deprecated Use FocusTraversalPolicy instead 2911: */ 2912: public void setNextFocusableComponent(Component aComponent) 2913: { 2914: Container focusRoot = this; 2915: if (! this.isFocusCycleRoot()) 2916: focusRoot = getFocusCycleRootAncestor(); 2917: 2918: FocusTraversalPolicy policy = focusRoot.getFocusTraversalPolicy(); 2919: if (policy instanceof CompatibilityFocusTraversalPolicy) 2920: { 2921: policy = new CompatibilityFocusTraversalPolicy(policy); 2922: focusRoot.setFocusTraversalPolicy(policy); 2923: } 2924: CompatibilityFocusTraversalPolicy p = 2925: (CompatibilityFocusTraversalPolicy) policy; 2926: 2927: Component old = getNextFocusableComponent(); 2928: if (old != null) 2929: { 2930: p.removeNextFocusableComponent(this, old); 2931: } 2932: 2933: if (aComponent != null) 2934: { 2935: p.addNextFocusableComponent(this, aComponent); 2936: } 2937: } 2938: 2939: /** 2940: * Set the value of the {@link #requestFocusEnabled} property. 2941: * 2942: * @param e The new value of the property 2943: */ 2944: public void setRequestFocusEnabled(boolean e) 2945: { 2946: requestFocusEnabled = e; 2947: } 2948: 2949: /** 2950: * Get the value of the {@link #transferHandler} property. 2951: * 2952: * @return The current value of the property 2953: * 2954: * @see #setTransferHandler 2955: */ 2956: 2957: public TransferHandler getTransferHandler() 2958: { 2959: return transferHandler; 2960: } 2961: 2962: /** 2963: * Set the value of the {@link #transferHandler} property. 2964: * 2965: * @param newHandler The new value of the property 2966: * 2967: * @see #getTransferHandler 2968: */ 2969: 2970: public void setTransferHandler(TransferHandler newHandler) 2971: { 2972: if (transferHandler == newHandler) 2973: return; 2974: 2975: TransferHandler oldHandler = transferHandler; 2976: transferHandler = newHandler; 2977: firePropertyChange("transferHandler", oldHandler, newHandler); 2978: } 2979: 2980: /** 2981: * Set if the component should paint all pixels withing its bounds. 2982: * If this property is set to false, the component expects the cleared 2983: * background. 2984: * 2985: * @param isOpaque if true, paint all pixels. If false, expect the clean 2986: * background. 2987: * 2988: * @see ComponentUI#update 2989: */ 2990: public void setOpaque(boolean isOpaque) 2991: { 2992: boolean oldOpaque = opaque; 2993: opaque = isOpaque; 2994: clientOpaqueSet = true; 2995: firePropertyChange("opaque", oldOpaque, opaque); 2996: } 2997: 2998: /** 2999: * Set the value of the visible property. 3000: * 3001: * If the value is changed, then the AncestorListeners of this component 3002: * and all its children (recursivly) are notified. 3003: * 3004: * @param v The new value of the property 3005: */ 3006: public void setVisible(boolean v) 3007: { 3008: // No need to do anything if the actual value doesn't change. 3009: if (isVisible() == v) 3010: return; 3011: 3012: super.setVisible(v); 3013: 3014: // Notify AncestorListeners. 3015: if (v == true) 3016: fireAncestorEvent(this, AncestorEvent.ANCESTOR_ADDED); 3017: else 3018: fireAncestorEvent(this, AncestorEvent.ANCESTOR_REMOVED); 3019: 3020: Container parent = getParent(); 3021: if (parent != null) 3022: parent.repaint(getX(), getY(), getWidth(), getHeight()); 3023: revalidate(); 3024: } 3025: 3026: /** 3027: * Call {@link #paint}. 3028: * 3029: * @param g The graphics context to paint into 3030: */ 3031: public void update(Graphics g) 3032: { 3033: paint(g); 3034: } 3035: 3036: /** 3037: * Get the value of the UIClassID property. This property should be a key 3038: * in the {@link UIDefaults} table managed by {@link UIManager}, the 3039: * value of which is the name of a class to load for the component's 3040: * {@link #ui} property. 3041: * 3042: * @return A "symbolic" name which will map to a class to use for the 3043: * component's UI, such as <code>"ComponentUI"</code> 3044: * 3045: * @see #setUI 3046: * @see #updateUI 3047: */ 3048: public String getUIClassID() 3049: { 3050: return "ComponentUI"; 3051: } 3052: 3053: /** 3054: * Install a new UI delegate as the component's {@link #ui} property. In 3055: * the process, this will call {@link ComponentUI#uninstallUI} on any 3056: * existing value for the {@link #ui} property, and {@link 3057: * ComponentUI#installUI} on the new UI delegate. 3058: * 3059: * @param newUI The new UI delegate to install 3060: * 3061: * @see #updateUI 3062: * @see #getUIClassID 3063: */ 3064: protected void setUI(ComponentUI newUI) 3065: { 3066: if (ui != null) 3067: ui.uninstallUI(this); 3068: 3069: ComponentUI oldUI = ui; 3070: ui = newUI; 3071: 3072: if (ui != null) 3073: ui.installUI(this); 3074: 3075: firePropertyChange("UI", oldUI, newUI); 3076: revalidate(); 3077: repaint(); 3078: } 3079: 3080: /** 3081: * This method should be overridden in subclasses. In JComponent, the 3082: * method does nothing. In subclasses, it should a UI delegate 3083: * (corresponding to the symbolic name returned from {@link 3084: * #getUIClassID}) from the {@link UIManager}, and calls {@link #setUI} 3085: * with the new delegate. 3086: */ 3087: public void updateUI() 3088: { 3089: // Nothing to do here. 3090: } 3091: 3092: public static Locale getDefaultLocale() 3093: { 3094: return defaultLocale; 3095: } 3096: 3097: public static void setDefaultLocale(Locale l) 3098: { 3099: defaultLocale = l; 3100: } 3101: 3102: /** 3103: * Returns the currently set input verifier for this component. 3104: * 3105: * @return the input verifier, or <code>null</code> if none 3106: */ 3107: public InputVerifier getInputVerifier() 3108: { 3109: return inputVerifier; 3110: } 3111: 3112: /** 3113: * Sets the input verifier to use by this component. 3114: * 3115: * @param verifier the input verifier, or <code>null</code> 3116: */ 3117: public void setInputVerifier(InputVerifier verifier) 3118: { 3119: InputVerifier oldVerifier = inputVerifier; 3120: inputVerifier = verifier; 3121: firePropertyChange("inputVerifier", oldVerifier, verifier); 3122: } 3123: 3124: /** 3125: * @since 1.3 3126: */ 3127: public boolean getVerifyInputWhenFocusTarget() 3128: { 3129: return verifyInputWhenFocusTarget; 3130: } 3131: 3132: /** 3133: * @since 1.3 3134: */ 3135: public void setVerifyInputWhenFocusTarget(boolean verifyInputWhenFocusTarget) 3136: { 3137: if (this.verifyInputWhenFocusTarget == verifyInputWhenFocusTarget) 3138: return; 3139: 3140: this.verifyInputWhenFocusTarget = verifyInputWhenFocusTarget; 3141: firePropertyChange("verifyInputWhenFocusTarget", 3142: ! verifyInputWhenFocusTarget, 3143: verifyInputWhenFocusTarget); 3144: } 3145: 3146: /** 3147: * Requests that this component gets the input focus if the 3148: * requestFocusEnabled property is set to <code>true</code>. 3149: * This also means that this component's top-level window becomes 3150: * the focused window, if that is not already the case. 3151: * 3152: * The preconditions that have to be met to become a focus owner is that 3153: * the component must be displayable, visible and focusable. 3154: * 3155: * Note that this signals only a request for becoming focused. There are 3156: * situations in which it is not possible to get the focus. So developers 3157: * should not assume that the component has the focus until it receives 3158: * a {@link java.awt.event.FocusEvent} with a value of 3159: * {@link java.awt.event.FocusEvent#FOCUS_GAINED}. 3160: * 3161: * @see Component#requestFocus() 3162: */ 3163: public void requestFocus() 3164: { 3165: if (isRequestFocusEnabled()) 3166: super.requestFocus(); 3167: } 3168: 3169: /** 3170: * This method is overridden to make it public so that it can be used 3171: * by look and feel implementations. 3172: * 3173: * You should not use this method directly. Instead you are strongly 3174: * encouraged to call {@link #requestFocus()} or 3175: * {@link #requestFocusInWindow()} instead. 3176: * 3177: * @param temporary if the focus change is temporary 3178: * 3179: * @return <code>false</code> if the focus change request will definitly 3180: * fail, <code>true</code> if it will likely succeed 3181: * 3182: * @see Component#requestFocus(boolean) 3183: * 3184: * @since 1.4 3185: */ 3186: public boolean requestFocus(boolean temporary) 3187: { 3188: return super.requestFocus(temporary); 3189: } 3190: 3191: /** 3192: * Requests that this component gets the input focus if the top level 3193: * window that contains this component has the focus and the 3194: * requestFocusEnabled property is set to <code>true</code>. 3195: * 3196: * The preconditions that have to be met to become a focus owner is that 3197: * the component must be displayable, visible and focusable. 3198: * 3199: * Note that this signals only a request for becoming focused. There are 3200: * situations in which it is not possible to get the focus. So developers 3201: * should not assume that the component has the focus until it receives 3202: * a {@link java.awt.event.FocusEvent} with a value of 3203: * {@link java.awt.event.FocusEvent#FOCUS_GAINED}. 3204: * 3205: * @return <code>false</code> if the focus change request will definitly 3206: * fail, <code>true</code> if it will likely succeed 3207: * 3208: * @see Component#requestFocusInWindow() 3209: */ 3210: public boolean requestFocusInWindow() 3211: { 3212: if (isRequestFocusEnabled()) 3213: return super.requestFocusInWindow(); 3214: else 3215: return false; 3216: } 3217: 3218: /** 3219: * This method is overridden to make it public so that it can be used 3220: * by look and feel implementations. 3221: * 3222: * You should not use this method directly. Instead you are strongly 3223: * encouraged to call {@link #requestFocus()} or 3224: * {@link #requestFocusInWindow()} instead. 3225: * 3226: * @param temporary if the focus change is temporary 3227: * 3228: * @return <code>false</code> if the focus change request will definitly 3229: * fail, <code>true</code> if it will likely succeed 3230: * 3231: * @see Component#requestFocus(boolean) 3232: * 3233: * @since 1.4 3234: */ 3235: protected boolean requestFocusInWindow(boolean temporary) 3236: { 3237: return super.requestFocusInWindow(temporary); 3238: } 3239: 3240: /** 3241: * Receives notification if this component is added to a parent component. 3242: * 3243: * Notification is sent to all registered AncestorListeners about the 3244: * new parent. 3245: * 3246: * This method sets up ActionListeners for all registered KeyStrokes of 3247: * this component in the chain of parent components. 3248: * 3249: * A PropertyChange event is fired to indicate that the ancestor property 3250: * has changed. 3251: * 3252: * This method is used internally and should not be used in applications. 3253: */ 3254: public void addNotify() 3255: { 3256: // Register the WHEN_IN_FOCUSED_WINDOW keyboard bindings 3257: // Note that here we unregister all bindings associated with 3258: // this component and then re-register them. This may be more than 3259: // necessary if the top-level ancestor hasn't changed. Should 3260: // maybe improve this. 3261: KeyboardManager km = KeyboardManager.getManager(); 3262: km.clearBindingsForComp(this); 3263: km.registerEntireMap((ComponentInputMap) 3264: this.getInputMap(WHEN_IN_FOCUSED_WINDOW)); 3265: super.addNotify(); 3266: 3267: // Notify AncestorListeners. 3268: fireAncestorEvent(this, AncestorEvent.ANCESTOR_ADDED); 3269: 3270: // fire property change event for 'ancestor' 3271: firePropertyChange("ancestor", null, getParent()); 3272: } 3273: 3274: /** 3275: * Receives notification that this component no longer has a parent. 3276: * 3277: * This method sends an AncestorEvent to all registered AncestorListeners, 3278: * notifying them that the parent is gone. 3279: * 3280: * The keybord actions of this component are removed from the parent and 3281: * its ancestors. 3282: * 3283: * A PropertyChangeEvent is fired to indicate that the 'ancestor' property 3284: * has changed. 3285: * 3286: * This method is called before the component is actually removed from 3287: * its parent, so the parent is still visible through 3288: * {@link Component#getParent}. 3289: */ 3290: public void removeNotify() 3291: { 3292: super.removeNotify(); 3293: 3294: KeyboardManager.getManager().clearBindingsForComp(this); 3295: 3296: // Notify ancestor listeners. 3297: fireAncestorEvent(this, AncestorEvent.ANCESTOR_REMOVED); 3298: 3299: // fire property change event for 'ancestor' 3300: firePropertyChange("ancestor", getParent(), null); 3301: } 3302: 3303: /** 3304: * Returns <code>true</code> if the coordinates (x, y) lie within 3305: * the bounds of this component and <code>false</code> otherwise. 3306: * x and y are relative to the coordinate space of the component. 3307: * 3308: * @param x the X coordinate of the point to check 3309: * @param y the Y coordinate of the point to check 3310: * 3311: * @return <code>true</code> if the specified point lies within the bounds 3312: * of this component, <code>false</code> otherwise 3313: */ 3314: public boolean contains(int x, int y) 3315: { 3316: if (ui == null) 3317: return super.contains(x, y); 3318: else 3319: return ui.contains(this, x, y); 3320: } 3321: 3322: /** 3323: * Disables this component. 3324: * 3325: * @deprecated replaced by {@link #setEnabled(boolean)} 3326: */ 3327: public void disable() 3328: { 3329: super.disable(); 3330: } 3331: 3332: /** 3333: * Enables this component. 3334: * 3335: * @deprecated replaced by {@link #setEnabled(boolean)} 3336: */ 3337: public void enable() 3338: { 3339: super.enable(); 3340: } 3341: 3342: /** 3343: * Returns the Graphics context for this component. This can be used 3344: * to draw on a component. 3345: * 3346: * @return the Graphics context for this component 3347: */ 3348: public Graphics getGraphics() 3349: { 3350: return super.getGraphics(); 3351: } 3352: 3353: /** 3354: * Returns the X coordinate of the upper left corner of this component. 3355: * Prefer this method over {@link #getBounds} or {@link #getLocation} 3356: * because it does not cause any heap allocation. 3357: * 3358: * @return the X coordinate of the upper left corner of the component 3359: */ 3360: public int getX() 3361: { 3362: return super.getX(); 3363: } 3364: 3365: /** 3366: * Returns the Y coordinate of the upper left corner of this component. 3367: * Prefer this method over {@link #getBounds} or {@link #getLocation} 3368: * because it does not cause any heap allocation. 3369: * 3370: * @return the Y coordinate of the upper left corner of the component 3371: */ 3372: public int getY() 3373: { 3374: return super.getY(); 3375: } 3376: 3377: /** 3378: * Returns the height of this component. Prefer this method over 3379: * {@link #getBounds} or {@link #getSize} because it does not cause 3380: * any heap allocation. 3381: * 3382: * @return the height of the component 3383: */ 3384: public int getHeight() 3385: { 3386: return super.getHeight(); 3387: } 3388: 3389: /** 3390: * Returns the width of this component. Prefer this method over 3391: * {@link #getBounds} or {@link #getSize} because it does not cause 3392: * any heap allocation. 3393: * 3394: * @return the width of the component 3395: */ 3396: public int getWidth() 3397: { 3398: return super.getWidth(); 3399: } 3400: 3401: /** 3402: * Prints this component to the given Graphics context. A call to this 3403: * method results in calls to the methods {@link #printComponent}, 3404: * {@link #printBorder} and {@link #printChildren} in this order. 3405: * 3406: * Double buffering is temporarily turned off so the painting goes directly 3407: * to the supplied Graphics context. 3408: * 3409: * @param g the Graphics context to print onto 3410: */ 3411: public void print(Graphics g) 3412: { 3413: boolean doubleBufferState = isDoubleBuffered(); 3414: setDoubleBuffered(false); 3415: printComponent(g); 3416: printBorder(g); 3417: printChildren(g); 3418: setDoubleBuffered(doubleBufferState); 3419: } 3420: 3421: /** 3422: * Prints this component to the given Graphics context. This invokes 3423: * {@link #print}. 3424: * 3425: * @param g the Graphics context to print onto 3426: */ 3427: public void printAll(Graphics g) 3428: { 3429: print(g); 3430: } 3431: 3432: /** 3433: * Prints this component to the specified Graphics context. The default 3434: * behaviour is to invoke {@link #paintComponent}. Override this 3435: * if you want special behaviour for printing. 3436: * 3437: * @param g the Graphics context to print onto 3438: * 3439: * @since 1.3 3440: */ 3441: protected void printComponent(Graphics g) 3442: { 3443: paintComponent(g); 3444: } 3445: 3446: /** 3447: * Print this component's children to the specified Graphics context. 3448: * The default behaviour is to invoke {@link #paintChildren}. Override this 3449: * if you want special behaviour for printing. 3450: * 3451: * @param g the Graphics context to print onto 3452: * 3453: * @since 1.3 3454: */ 3455: protected void printChildren(Graphics g) 3456: { 3457: paintChildren(g); 3458: } 3459: 3460: /** 3461: * Print this component's border to the specified Graphics context. 3462: * The default behaviour is to invoke {@link #paintBorder}. Override this 3463: * if you want special behaviour for printing. 3464: * 3465: * @param g the Graphics context to print onto 3466: * 3467: * @since 1.3 3468: */ 3469: protected void printBorder(Graphics g) 3470: { 3471: paintBorder(g); 3472: } 3473: 3474: /** 3475: * Processes mouse motion event, like dragging and moving. 3476: * 3477: * @param ev the MouseEvent describing the mouse motion 3478: */ 3479: protected void processMouseMotionEvent(MouseEvent ev) 3480: { 3481: super.processMouseMotionEvent(ev); 3482: } 3483: 3484: /** 3485: * Moves and resizes the component. 3486: * 3487: * @param x the new horizontal location 3488: * @param y the new vertial location 3489: * @param w the new width 3490: * @param h the new height 3491: */ 3492: public void reshape(int x, int y, int w, int h) 3493: { 3494: int oldX = getX(); 3495: int oldY = getY(); 3496: super.reshape(x, y, w, h); 3497: // Notify AncestorListeners. 3498: if (oldX != getX() || oldY != getY()) 3499: fireAncestorEvent(this, AncestorEvent.ANCESTOR_MOVED); 3500: } 3501: 3502: /** 3503: * Fires an AncestorEvent to this component's and all of its child 3504: * component's AncestorListeners. 3505: * 3506: * @param ancestor the component that triggered the event 3507: * @param id the kind of ancestor event that should be fired 3508: */ 3509: void fireAncestorEvent(JComponent ancestor, int id) 3510: { 3511: // Fire event for registered ancestor listeners of this component. 3512: AncestorListener[] listeners = getAncestorListeners(); 3513: if (listeners.length > 0) 3514: { 3515: AncestorEvent ev = new AncestorEvent(this, id, 3516: ancestor, ancestor.getParent()); 3517: for (int i = 0; i < listeners.length; i++) 3518: { 3519: switch (id) 3520: { 3521: case AncestorEvent.ANCESTOR_MOVED: 3522: listeners[i].ancestorMoved(ev); 3523: break; 3524: case AncestorEvent.ANCESTOR_ADDED: 3525: listeners[i].ancestorAdded(ev); 3526: break; 3527: case AncestorEvent.ANCESTOR_REMOVED: 3528: listeners[i].ancestorRemoved(ev); 3529: break; 3530: } 3531: } 3532: } 3533: // Dispatch event to all children. 3534: Component[] children = getComponents(); 3535: for (int i = 0; i < children.length; i++) 3536: { 3537: if (!(children[i] instanceof JComponent)) 3538: continue; 3539: JComponent jc = (JComponent) children[i]; 3540: jc.fireAncestorEvent(ancestor, id); 3541: } 3542: } 3543: 3544: /** 3545: * Finds a suitable paint root for painting this component. This method first 3546: * checks if this component is overlapped using 3547: * {@link #findOverlapFreeParent(Rectangle)}. The returned paint root is then 3548: * feeded to {@link #findOpaqueParent(Component)} to find the nearest opaque 3549: * component for this paint root. If no paint is necessary, then we return 3550: * <code>null</code>. 3551: * 3552: * @param c the clip of this component 3553: * 3554: * @return the paint root or <code>null</code> if no painting is necessary 3555: */ 3556: private Component findPaintRoot(Rectangle c) 3557: { 3558: Component p = findOverlapFreeParent(c); 3559: if (p == null) 3560: return null; 3561: Component root = findOpaqueParent(p); 3562: return root; 3563: } 3564: 3565: /** 3566: * Scans the containment hierarchy upwards for components that overlap the 3567: * this component in the specified clip. This method returns 3568: * <code>this</code>, if no component overlaps this component. It returns 3569: * <code>null</code> if another component completely covers this component 3570: * in the specified clip (no repaint necessary). If another component partly 3571: * overlaps this component in the specified clip, then the parent of this 3572: * component is returned (this is the component that must be used as repaint 3573: * root). For efficient lookup, the method 3574: * {@link #isOptimizedDrawingEnabled()} is used. 3575: * 3576: * @param clip the clip of this component 3577: * 3578: * @return the paint root, or <code>null</code> if no paint is necessary 3579: */ 3580: private Component findOverlapFreeParent(Rectangle clip) 3581: { 3582: Rectangle currentClip = clip; 3583: Component found = this; 3584: Container parent = this; 3585: 3586: while (parent != null && !(parent instanceof Window)) 3587: { 3588: Container newParent = parent.getParent(); 3589: if (newParent == null || newParent instanceof Window) 3590: break; 3591: // If the parent is optimizedDrawingEnabled, then its children are 3592: // tiled and cannot have an overlapping child. Go directly to next 3593: // parent. 3594: if ((newParent instanceof JComponent 3595: && ((JComponent) newParent).isOptimizedDrawingEnabled())) 3596: 3597: { 3598: parent = newParent; 3599: continue; 3600: } 3601: 3602: // If the parent is not optimizedDrawingEnabled, we must check if the 3603: // parent or some neighbor overlaps the current clip. 3604: 3605: // This is the current clip converted to the parent's coordinate 3606: // system. TODO: We can do this more efficiently by succesively 3607: // cumulating the parent-child translations. 3608: Rectangle target = SwingUtilities.convertRectangle(found, 3609: currentClip, 3610: newParent); 3611: 3612: // We have an overlap if either: 3613: // - The new parent itself doesn't completely cover the clip 3614: // (this can be the case with viewports). 3615: // - If some higher-level (than the current) children of the new parent 3616: // intersect the target rectangle. 3617: Rectangle parentRect = SwingUtilities.getLocalBounds(newParent); 3618: boolean haveOverlap = 3619: ! SwingUtilities.isRectangleContainingRectangle(parentRect, target); 3620: if (! haveOverlap) 3621: { 3622: Component[] children = newParent.getComponents(); 3623: for (int i = 0; children[i] != parent && !haveOverlap; i++) 3624: { 3625: Rectangle childRect = children[i].getBounds(); 3626: haveOverlap = target.intersects(childRect); 3627: } 3628: } 3629: if (haveOverlap) 3630: { 3631: found = newParent; 3632: currentClip = target; 3633: } 3634: parent = newParent; 3635: } 3636: //System.err.println("overlapfree parent: " + found); 3637: return found; 3638: } 3639: 3640: /** 3641: * Finds the nearest component to <code>c</code> (upwards in the containment 3642: * hierarchy), that is opaque. If <code>c</code> itself is opaque, 3643: * this returns <code>c</code> itself. 3644: * 3645: * @param c the start component for the search 3646: * @return the nearest component to <code>c</code> (upwards in the containment 3647: * hierarchy), that is opaque; If <code>c</code> itself is opaque, 3648: * this returns <code>c</code> itself 3649: */ 3650: private Component findOpaqueParent(Component c) 3651: { 3652: Component found = c; 3653: while (true) 3654: { 3655: if ((found instanceof JComponent) && ((JComponent) found).isOpaque()) 3656: break; 3657: else if (!(found instanceof JComponent)) 3658: break; 3659: Container p = found.getParent(); 3660: if (p == null) 3661: break; 3662: else 3663: found = p; 3664: } 3665: return found; 3666: } 3667: 3668: /** 3669: * This is the method that gets called when the WHEN_IN_FOCUSED_WINDOW map 3670: * is changed. 3671: * 3672: * @param changed the JComponent associated with the WHEN_IN_FOCUSED_WINDOW 3673: * map 3674: */ 3675: void updateComponentInputMap(ComponentInputMap changed) 3676: { 3677: // Since you can change a component's input map via 3678: // setInputMap, we have to check if <code>changed</code> 3679: // is still in our WHEN_IN_FOCUSED_WINDOW map hierarchy 3680: InputMap curr = getInputMap(WHEN_IN_FOCUSED_WINDOW); 3681: while (curr != null && curr != changed) 3682: curr = curr.getParent(); 3683: 3684: // If curr is null then changed is not in the hierarchy 3685: if (curr == null) 3686: return; 3687: 3688: // Now we have to update the keyboard manager's hashtable 3689: KeyboardManager km = KeyboardManager.getManager(); 3690: 3691: // This is a poor strategy, should be improved. We currently 3692: // delete all the old bindings for the component and then register 3693: // the current bindings. 3694: km.clearBindingsForComp(changed.getComponent()); 3695: km.registerEntireMap((ComponentInputMap) 3696: getInputMap(WHEN_IN_FOCUSED_WINDOW)); 3697: } 3698: 3699: /** 3700: * Helper method for 3701: * {@link LookAndFeel#installProperty(JComponent, String, Object)}. 3702: * 3703: * @param propertyName the name of the property 3704: * @param value the value of the property 3705: * 3706: * @throws IllegalArgumentException if the specified property cannot be set 3707: * by this method 3708: * @throws ClassCastException if the property value does not match the 3709: * property type 3710: * @throws NullPointerException if <code>c</code> or 3711: * <code>propertyValue</code> is <code>null</code> 3712: */ 3713: void setUIProperty(String propertyName, Object value) 3714: { 3715: if (propertyName.equals("opaque")) 3716: { 3717: if (! clientOpaqueSet) 3718: { 3719: setOpaque(((Boolean) value).booleanValue()); 3720: clientOpaqueSet = false; 3721: } 3722: } 3723: else if (propertyName.equals("autoscrolls")) 3724: { 3725: if (! clientAutoscrollsSet) 3726: { 3727: setAutoscrolls(((Boolean) value).booleanValue()); 3728: clientAutoscrollsSet = false; 3729: } 3730: } 3731: else 3732: { 3733: throw new IllegalArgumentException 3734: ("Unsupported property for LookAndFeel.installProperty(): " 3735: + propertyName); 3736: } 3737: } 3738: }