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