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