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