Frames | No Frames |
1: /* AbstractButton.java -- Provides basic button functionality. 2: Copyright (C) 2002, 2004, 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: package javax.swing; 39: 40: import gnu.classpath.NotImplementedException; 41: 42: import java.awt.Component; 43: import java.awt.Graphics; 44: import java.awt.Image; 45: import java.awt.Insets; 46: import java.awt.ItemSelectable; 47: import java.awt.LayoutManager; 48: import java.awt.Point; 49: import java.awt.Rectangle; 50: import java.awt.Shape; 51: import java.awt.event.ActionEvent; 52: import java.awt.event.ActionListener; 53: import java.awt.event.ItemEvent; 54: import java.awt.event.ItemListener; 55: import java.awt.image.ImageObserver; 56: import java.beans.PropertyChangeEvent; 57: import java.beans.PropertyChangeListener; 58: import java.io.Serializable; 59: import java.util.Enumeration; 60: 61: import javax.accessibility.Accessible; 62: import javax.accessibility.AccessibleAction; 63: import javax.accessibility.AccessibleContext; 64: import javax.accessibility.AccessibleIcon; 65: import javax.accessibility.AccessibleRelation; 66: import javax.accessibility.AccessibleRelationSet; 67: import javax.accessibility.AccessibleState; 68: import javax.accessibility.AccessibleStateSet; 69: import javax.accessibility.AccessibleText; 70: import javax.accessibility.AccessibleValue; 71: import javax.swing.event.ChangeEvent; 72: import javax.swing.event.ChangeListener; 73: import javax.swing.plaf.ButtonUI; 74: import javax.swing.plaf.basic.BasicHTML; 75: import javax.swing.text.AttributeSet; 76: import javax.swing.text.BadLocationException; 77: import javax.swing.text.Position; 78: import javax.swing.text.View; 79: 80: 81: /** 82: * Provides an abstract implementation of common button behaviour, 83: * data model and look & feel. 84: * 85: * <p>This class is supposed to serve as a base class for 86: * several kinds of buttons with similar but non-identical semantics: 87: * toggle buttons (radio buttons and checkboxes), simple push buttons, 88: * menu items, etc.</p> 89: * 90: * <p>Buttons have many properties, some of which are stored in this class 91: * while others are delegated to the button's model. The following properties 92: * are available:</p> 93: * 94: * <table> 95: * <tr><th>Property </th><th>Stored in</th><th>Bound?</th></tr> 96: * 97: * <tr><td>action </td><td>button</td> <td>no</td></tr> 98: * <tr><td>actionCommand </td><td>model</td> <td>no</td></tr> 99: * <tr><td>borderPainted </td><td>button</td> <td>yes</td></tr> 100: * <tr><td>contentAreaFilled </td><td>button</td> <td>yes</td></tr> 101: * <tr><td>disabledIcon </td><td>button</td> <td>yes</td></tr> 102: * <tr><td>disabledSelectedIcon </td><td>button</td> <td>yes</td></tr> 103: * <tr><td>displayedMnemonicIndex </td><td>button</td> <td>no</td></tr> 104: * <tr><td>enabled </td><td>model</td> <td>no</td></tr> 105: * <tr><td>focusPainted </td><td>button</td> <td>yes</td></tr> 106: * <tr><td>horizontalAlignment </td><td>button</td> <td>yes</td></tr> 107: * <tr><td>horizontalTextPosition </td><td>button</td> <td>yes</td></tr> 108: * <tr><td>icon </td><td>button</td> <td>yes</td></tr> 109: * <tr><td>iconTextGap </td><td>button</td> <td>no</td></tr> 110: * <tr><td>label (same as text) </td><td>model</td> <td>yes</td></tr> 111: * <tr><td>margin </td><td>button</td> <td>yes</td></tr> 112: * <tr><td>multiClickThreshold </td><td>button</td> <td>no</td></tr> 113: * <tr><td>pressedIcon </td><td>button</td> <td>yes</td></tr> 114: * <tr><td>rolloverEnabled </td><td>button</td> <td>yes</td></tr> 115: * <tr><td>rolloverIcon </td><td>button</td> <td>yes</td></tr> 116: * <tr><td>rolloverSelectedIcon </td><td>button</td> <td>yes</td></tr> 117: * <tr><td>selected </td><td>model</td> <td>no</td></tr> 118: * <tr><td>selectedIcon </td><td>button</td> <td>yes</td></tr> 119: * <tr><td>selectedObjects </td><td>button</td> <td>no</td></tr> 120: * <tr><td>text </td><td>model</td> <td>yes</td></tr> 121: * <tr><td>UI </td><td>button</td> <td>yes</td></tr> 122: * <tr><td>verticalAlignment </td><td>button</td> <td>yes</td></tr> 123: * <tr><td>verticalTextPosition </td><td>button</td> <td>yes</td></tr> 124: * 125: * </table> 126: * 127: * <p>The various behavioral aspects of these properties follows:</p> 128: * 129: * <ul> 130: * 131: * <li>When non-bound properties stored in the button change, the button 132: * fires ChangeEvents to its ChangeListeners.</li> 133: * 134: * <li>When bound properties stored in the button change, the button fires 135: * PropertyChangeEvents to its PropertyChangeListeners</li> 136: * 137: * <li>If any of the model's properties change, it fires a ChangeEvent to 138: * its ChangeListeners, which include the button.</li> 139: * 140: * <li>If the button receives a ChangeEvent from its model, it will 141: * propagate the ChangeEvent to its ChangeListeners, with the ChangeEvent's 142: * "source" property set to refer to the button, rather than the model. The 143: * the button will request a repaint, to paint its updated state.</li> 144: * 145: * <li>If the model's "selected" property changes, the model will fire an 146: * ItemEvent to its ItemListeners, which include the button, in addition to 147: * the ChangeEvent which models the property change. The button propagates 148: * ItemEvents directly to its ItemListeners.</li> 149: * 150: * <li>If the model's armed and pressed properties are simultaneously 151: * <code>true</code>, the model will fire an ActionEvent to its 152: * ActionListeners, which include the button. The button will propagate 153: * this ActionEvent to its ActionListeners, with the ActionEvent's "source" 154: * property set to refer to the button, rather than the model.</li> 155: * 156: * </ul> 157: * 158: * @author Ronald Veldema (rveldema@cs.vu.nl) 159: * @author Graydon Hoare (graydon@redhat.com) 160: */ 161: 162: public abstract class AbstractButton extends JComponent 163: implements ItemSelectable, SwingConstants 164: { 165: private static final long serialVersionUID = -937921345538462020L; 166: 167: /** 168: * An extension of ChangeListener to be serializable. 169: */ 170: protected class ButtonChangeListener 171: implements ChangeListener, Serializable 172: { 173: private static final long serialVersionUID = 1471056094226600578L; 174: 175: /** 176: * The spec has no public/protected constructor for this class, so do we. 177: */ 178: ButtonChangeListener() 179: { 180: // Nothing to do here. 181: } 182: 183: /** 184: * Notified when the target of the listener changes its state. 185: * 186: * @param ev the ChangeEvent describing the change 187: */ 188: public void stateChanged(ChangeEvent ev) 189: { 190: AbstractButton.this.fireStateChanged(); 191: repaint(); 192: } 193: } 194: 195: /** The icon displayed by default. */ 196: Icon default_icon; 197: 198: /** The icon displayed when the button is pressed. */ 199: Icon pressed_icon; 200: 201: /** The icon displayed when the button is disabled. */ 202: Icon disabledIcon; 203: 204: /** The icon displayed when the button is selected. */ 205: Icon selectedIcon; 206: 207: /** The icon displayed when the button is selected but disabled. */ 208: Icon disabledSelectedIcon; 209: 210: /** The icon displayed when the button is rolled over. */ 211: Icon rolloverIcon; 212: 213: /** The icon displayed when the button is selected and rolled over. */ 214: Icon rolloverSelectedIcon; 215: 216: /** The icon currently displayed. */ 217: Icon current_icon; 218: 219: /** The text displayed in the button. */ 220: String text; 221: 222: /** 223: * The gap between icon and text, if both icon and text are 224: * non-<code>null</code>. 225: */ 226: int iconTextGap; 227: 228: /** The vertical alignment of the button's text and icon. */ 229: int verticalAlignment; 230: 231: /** The horizontal alignment of the button's text and icon. */ 232: int horizontalAlignment; 233: 234: /** The horizontal position of the button's text relative to its icon. */ 235: int horizontalTextPosition; 236: 237: /** The vertical position of the button's text relative to its icon. */ 238: int verticalTextPosition; 239: 240: /** Whether or not the button paints its border. */ 241: boolean borderPainted; 242: 243: /** Whether or not the button paints its focus state. */ 244: boolean focusPainted; 245: 246: /** Whether or not the button fills its content area. */ 247: boolean contentAreaFilled; 248: 249: /** Whether rollover is enabled. */ 250: boolean rollOverEnabled; 251: 252: /** The action taken when the button is clicked. */ 253: Action action; 254: 255: /** The button's current state. */ 256: protected ButtonModel model; 257: 258: /** The margin between the button's border and its label. */ 259: Insets margin; 260: 261: /** 262: * A hint to the look and feel class, suggesting which character in the 263: * button's label should be underlined when drawing the label. 264: */ 265: int mnemonicIndex; 266: 267: /** Listener the button uses to receive ActionEvents from its model. */ 268: protected ActionListener actionListener; 269: 270: /** Listener the button uses to receive ItemEvents from its model. */ 271: protected ItemListener itemListener; 272: 273: /** Listener the button uses to receive ChangeEvents from its model. */ 274: protected ChangeListener changeListener; 275: 276: /** 277: * The time in milliseconds in which clicks get coalesced into a single 278: * <code>ActionEvent</code>. 279: */ 280: long multiClickThreshhold; 281: 282: /** 283: * Listener the button uses to receive PropertyChangeEvents from its 284: * Action. 285: */ 286: PropertyChangeListener actionPropertyChangeListener; 287: 288: /** ChangeEvent that is fired to button's ChangeEventListeners */ 289: protected ChangeEvent changeEvent = new ChangeEvent(this); 290: 291: /** 292: * Indicates if the borderPainted property has been set by a client 293: * program or by the UI. 294: * 295: * @see #setUIProperty(String, Object) 296: * @see LookAndFeel#installProperty(JComponent, String, Object) 297: */ 298: private boolean clientBorderPaintedSet = false; 299: 300: /** 301: * Indicates if the rolloverEnabled property has been set by a client 302: * program or by the UI. 303: * 304: * @see #setUIProperty(String, Object) 305: * @see LookAndFeel#installProperty(JComponent, String, Object) 306: */ 307: private boolean clientRolloverEnabledSet = false; 308: 309: /** 310: * Indicates if the iconTextGap property has been set by a client 311: * program or by the UI. 312: * 313: * @see #setUIProperty(String, Object) 314: * @see LookAndFeel#installProperty(JComponent, String, Object) 315: */ 316: private boolean clientIconTextGapSet = false; 317: 318: /** 319: * Indicates if the contentAreaFilled property has been set by a client 320: * program or by the UI. 321: * 322: * @see #setUIProperty(String, Object) 323: * @see LookAndFeel#installProperty(JComponent, String, Object) 324: */ 325: private boolean clientContentAreaFilledSet = false; 326: 327: /** 328: * Fired in a PropertyChangeEvent when the "borderPainted" property changes. 329: */ 330: public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted"; 331: 332: /** 333: * Fired in a PropertyChangeEvent when the "contentAreaFilled" property 334: * changes. 335: */ 336: public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = 337: "contentAreaFilled"; 338: 339: /** 340: * Fired in a PropertyChangeEvent when the "disabledIcon" property changes. 341: */ 342: public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon"; 343: 344: /** 345: * Fired in a PropertyChangeEvent when the "disabledSelectedIcon" property 346: * changes. 347: */ 348: public static final String DISABLED_SELECTED_ICON_CHANGED_PROPERTY = 349: "disabledSelectedIcon"; 350: 351: /** 352: * Fired in a PropertyChangeEvent when the "focusPainted" property changes. 353: */ 354: public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted"; 355: 356: /** 357: * Fired in a PropertyChangeEvent when the "horizontalAlignment" property 358: * changes. 359: */ 360: public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = 361: "horizontalAlignment"; 362: 363: /** 364: * Fired in a PropertyChangeEvent when the "horizontalTextPosition" property 365: * changes. 366: */ 367: public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = 368: "horizontalTextPosition"; 369: 370: /** 371: * Fired in a PropertyChangeEvent when the "icon" property changes. */ 372: public static final String ICON_CHANGED_PROPERTY = "icon"; 373: 374: /** Fired in a PropertyChangeEvent when the "margin" property changes. */ 375: public static final String MARGIN_CHANGED_PROPERTY = "margin"; 376: 377: /** Fired in a PropertyChangeEvent when the "mnemonic" property changes. */ 378: public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic"; 379: 380: /** Fired in a PropertyChangeEvent when the "model" property changes. */ 381: public static final String MODEL_CHANGED_PROPERTY = "model"; 382: 383: /** Fired in a PropertyChangeEvent when the "pressedIcon" property changes. */ 384: public static final String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon"; 385: 386: /** 387: * Fired in a PropertyChangeEvent when the "rolloverEnabled" property 388: * changes. 389: */ 390: public static final String ROLLOVER_ENABLED_CHANGED_PROPERTY = 391: "rolloverEnabled"; 392: 393: /** 394: * Fired in a PropertyChangeEvent when the "rolloverIcon" property changes. 395: */ 396: public static final String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon"; 397: 398: /** 399: * Fired in a PropertyChangeEvent when the "rolloverSelectedIcon" property 400: * changes. 401: */ 402: public static final String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = 403: "rolloverSelectedIcon"; 404: 405: /** 406: * Fired in a PropertyChangeEvent when the "selectedIcon" property changes. 407: */ 408: public static final String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon"; 409: 410: /** Fired in a PropertyChangeEvent when the "text" property changes. */ 411: public static final String TEXT_CHANGED_PROPERTY = "text"; 412: 413: /** 414: * Fired in a PropertyChangeEvent when the "verticalAlignment" property 415: * changes. 416: */ 417: public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = 418: "verticalAlignment"; 419: 420: /** 421: * Fired in a PropertyChangeEvent when the "verticalTextPosition" property 422: * changes. 423: */ 424: public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = 425: "verticalTextPosition"; 426: 427: /** 428: * A Java Accessibility extension of the AbstractButton. 429: */ 430: protected abstract class AccessibleAbstractButton 431: extends AccessibleJComponent implements AccessibleAction, AccessibleValue, 432: AccessibleText 433: { 434: private static final long serialVersionUID = -5673062525319836790L; 435: 436: protected AccessibleAbstractButton() 437: { 438: // Nothing to do here yet. 439: } 440: 441: /** 442: * Returns the accessible state set of this object. In addition to the 443: * superclass's states, the <code>AccessibleAbstractButton</code> 444: * supports the following states: {@link AccessibleState#ARMED}, 445: * {@link AccessibleState#FOCUSED}, {@link AccessibleState#PRESSED} and 446: * {@link AccessibleState#CHECKED}. 447: * 448: * @return the current state of this accessible object 449: */ 450: public AccessibleStateSet getAccessibleStateSet() 451: { 452: AccessibleStateSet state = super.getAccessibleStateSet(); 453: 454: if (getModel().isArmed()) 455: state.add(AccessibleState.ARMED); 456: if (getModel().isPressed()) 457: state.add(AccessibleState.PRESSED); 458: if (isSelected()) 459: state.add(AccessibleState.CHECKED); 460: 461: return state; 462: } 463: 464: /** 465: * Returns the accessible name for the button. 466: */ 467: public String getAccessibleName() 468: { 469: String result = super.getAccessibleName(); 470: if (result == null) 471: result = text; 472: return result; 473: } 474: 475: /** 476: * Returns the accessible icons of this object. If the AbstractButton's 477: * icon is an Accessible, and it's AccessibleContext is an AccessibleIcon, 478: * then this AccessibleIcon is returned, otherwise <code>null</code>. 479: * 480: * @return the accessible icons of this object, or <code>null</code> if 481: * there is no accessible icon 482: */ 483: public AccessibleIcon[] getAccessibleIcon() 484: { 485: AccessibleIcon[] ret = null; 486: Icon icon = getIcon(); 487: if (icon instanceof Accessible) 488: { 489: AccessibleContext ctx = ((Accessible) icon).getAccessibleContext(); 490: if (ctx instanceof AccessibleIcon) 491: { 492: ret = new AccessibleIcon[]{ (AccessibleIcon) ctx }; 493: } 494: } 495: return ret; 496: } 497: 498: /** 499: * Returns the accessible relations of this AccessibleAbstractButton. 500: * If the AbstractButton is part of a ButtonGroup, then all the buttons 501: * in this button group are added as targets in a MEMBER_OF relation, 502: * otherwise an empty relation set is returned (from super). 503: * 504: * @return the accessible relations of this AccessibleAbstractButton 505: */ 506: public AccessibleRelationSet getAccessibleRelationSet() 507: { 508: AccessibleRelationSet relations = super.getAccessibleRelationSet(); 509: ButtonModel model = getModel(); 510: if (model instanceof DefaultButtonModel) 511: { 512: ButtonGroup group = ((DefaultButtonModel) model).getGroup(); 513: if (group != null) 514: { 515: Object[] target = new Object[group.getButtonCount()]; 516: Enumeration els = group.getElements(); 517: 518: for (int index = 0; els.hasMoreElements(); ++index) 519: { 520: target[index] = els.nextElement(); 521: } 522: 523: AccessibleRelation rel = 524: new AccessibleRelation(AccessibleRelation.MEMBER_OF); 525: rel.setTarget(target); 526: relations.add(rel); 527: } 528: } 529: return relations; 530: } 531: 532: /** 533: * Returns the accessible action associated with this object. For buttons, 534: * this will be <code>this</code>. 535: * 536: * @return <code>this</code> 537: */ 538: public AccessibleAction getAccessibleAction() 539: { 540: return this; 541: } 542: 543: /** 544: * Returns the accessible value of this AccessibleAbstractButton, which 545: * is always <code>this</code>. 546: * 547: * @return the accessible value of this AccessibleAbstractButton, which 548: * is always <code>this</code> 549: */ 550: public AccessibleValue getAccessibleValue() 551: { 552: return this; 553: } 554: 555: /** 556: * Returns the number of accessible actions that are supported by this 557: * object. Buttons support one action by default ('press button'), so this 558: * method always returns <code>1</code>. 559: * 560: * @return <code>1</code>, the number of supported accessible actions 561: */ 562: public int getAccessibleActionCount() 563: { 564: return 1; 565: } 566: 567: /** 568: * Returns a description for the action with the specified index or 569: * <code>null</code> if such action does not exist. 570: * 571: * @param actionIndex the zero based index to the actions 572: * 573: * @return a description for the action with the specified index or 574: * <code>null</code> if such action does not exist 575: */ 576: public String getAccessibleActionDescription(int actionIndex) 577: { 578: String descr = null; 579: if (actionIndex == 0) 580: { 581: // FIXME: Supply localized descriptions in the UIDefaults. 582: descr = UIManager.getString("AbstractButton.clickText"); 583: } 584: return descr; 585: } 586: 587: /** 588: * Performs the acccessible action with the specified index on this object. 589: * Since buttons have only one action by default (which is to press the 590: * button), this method performs a 'press button' when the specified index 591: * is <code>0</code> and nothing otherwise. 592: * 593: * @param actionIndex a zero based index into the actions of this button 594: * 595: * @return <code>true</code> if the specified action has been performed 596: * successfully, <code>false</code> otherwise 597: */ 598: public boolean doAccessibleAction(int actionIndex) 599: { 600: boolean retVal = false; 601: if (actionIndex == 0) 602: { 603: doClick(); 604: retVal = true; 605: } 606: return retVal; 607: } 608: 609: /** 610: * Returns the current value of this object as a number. This 611: * implementation returns an <code>Integer(1)</code> if the button is 612: * selected, <code>Integer(0)</code> if the button is not selected. 613: * 614: * @return the current value of this object as a number 615: */ 616: public Number getCurrentAccessibleValue() 617: { 618: Integer retVal; 619: if (isSelected()) 620: retVal = new Integer(1); 621: else 622: retVal = new Integer(0); 623: return retVal; 624: } 625: 626: /** 627: * Sets the current accessible value as object. If the specified number 628: * is 0 the button will be deselected, otherwise the button will 629: * be selected. 630: * 631: * @param value 0 for deselected button, other for selected button 632: * 633: * @return <code>true</code> if the value has been set, <code>false</code> 634: * otherwise 635: */ 636: public boolean setCurrentAccessibleValue(Number value) 637: { 638: boolean retVal = false; 639: if (value != null) 640: { 641: if (value.intValue() == 0) 642: setSelected(false); 643: else 644: setSelected(true); 645: retVal = true; 646: } 647: return retVal; 648: } 649: 650: /** 651: * Returns the minimum accessible value for the AccessibleAbstractButton, 652: * which is <code>0</code>. 653: * 654: * @return the minimimum accessible value for the AccessibleAbstractButton, 655: * which is <code>0</code> 656: */ 657: public Number getMinimumAccessibleValue() 658: { 659: return new Integer(0); 660: } 661: 662: /** 663: * Returns the maximum accessible value for the AccessibleAbstractButton, 664: * which is <code>1</code>. 665: * 666: * @return the maximum accessible value for the AccessibleAbstractButton, 667: * which is <code>1</code> 668: */ 669: public Number getMaximumAccessibleValue() 670: { 671: return new Integer(1); 672: } 673: 674: /** 675: * Returns the accessible text for this AccessibleAbstractButton. This 676: * will be <code>null</code> if the button has a non-HTML label, otherwise 677: * <code>this</code>. 678: * 679: * @return the accessible text for this AccessibleAbstractButton 680: */ 681: public AccessibleText getAccessibleText() 682: { 683: AccessibleText accessibleText = null; 684: if (getClientProperty(BasicHTML.propertyKey) != null) 685: accessibleText = this; 686: 687: return accessibleText; 688: } 689: 690: /** 691: * Returns the index of the label's character at the specified point, 692: * relative to the local bounds of the button. This only works for 693: * HTML labels. 694: * 695: * @param p the point, relative to the buttons local bounds 696: * 697: * @return the index of the label's character at the specified point 698: */ 699: public int getIndexAtPoint(Point p) 700: { 701: int index = -1; 702: View view = (View) getClientProperty(BasicHTML.propertyKey); 703: if (view != null) 704: { 705: Rectangle shape = new Rectangle(0, 0, getWidth(), getHeight()); 706: index = view.viewToModel(p.x, p.y, shape, new Position.Bias[1]); 707: } 708: return index; 709: } 710: 711: /** 712: * Returns the bounds of the character at the specified index of the 713: * button's label. This will only work for HTML labels. 714: * 715: * @param i the index of the character of the label 716: * 717: * @return the bounds of the character at the specified index of the 718: * button's label 719: */ 720: public Rectangle getCharacterBounds(int i) 721: { 722: Rectangle rect = null; 723: View view = (View) getClientProperty(BasicHTML.propertyKey); 724: if (view != null) 725: { 726: Rectangle shape = new Rectangle(0, 0, getWidth(), getHeight()); 727: try 728: { 729: Shape s = view.modelToView(i, shape, Position.Bias.Forward); 730: rect = s.getBounds(); 731: } 732: catch (BadLocationException ex) 733: { 734: rect = null; 735: } 736: } 737: return rect; 738: } 739: 740: /** 741: * Returns the number of characters in the button's label. 742: * 743: * @return the bounds of the character at the specified index of the 744: * button's label 745: */ 746: public int getCharCount() 747: { 748: int charCount; 749: View view = (View) getClientProperty(BasicHTML.propertyKey); 750: if (view != null) 751: { 752: charCount = view.getDocument().getLength(); 753: } 754: else 755: { 756: charCount = getAccessibleName().length(); 757: } 758: return charCount; 759: } 760: 761: /** 762: * This always returns <code>-1</code> since there is no caret in a button. 763: * 764: * @return <code>-1</code> since there is no caret in a button 765: */ 766: public int getCaretPosition() 767: { 768: return -1; 769: } 770: 771: public String getAtIndex(int value0, int value1) 772: throws NotImplementedException 773: { 774: return null; // TODO 775: } 776: 777: public String getAfterIndex(int value0, int value1) 778: throws NotImplementedException 779: { 780: return null; // TODO 781: } 782: 783: public String getBeforeIndex(int value0, int value1) 784: throws NotImplementedException 785: { 786: return null; // TODO 787: } 788: 789: /** 790: * Returns the text attribute for the character at the specified character 791: * index. 792: * 793: * @param i the character index 794: * 795: * @return the character attributes for the specified character or 796: * <code>null</code> if the character has no attributes 797: */ 798: public AttributeSet getCharacterAttribute(int i) 799: { 800: AttributeSet atts = null; 801: View view = (View) getClientProperty(BasicHTML.propertyKey); 802: if (view != null) 803: { 804: 805: } 806: return atts; 807: } 808: 809: /** 810: * This always returns <code>-1</code> since 811: * button labels can't be selected. 812: * 813: * @return <code>-1</code>, button labels can't be selected 814: */ 815: public int getSelectionStart() 816: { 817: return -1; 818: } 819: 820: /** 821: * This always returns <code>-1</code> since 822: * button labels can't be selected. 823: * 824: * @return <code>-1</code>, button labels can't be selected 825: */ 826: public int getSelectionEnd() 827: { 828: return -1; 829: } 830: 831: /** 832: * Returns the selected text. This always returns <code>null</code> since 833: * button labels can't be selected. 834: * 835: * @return <code>null</code>, button labels can't be selected 836: */ 837: public String getSelectedText() 838: { 839: return null; 840: } 841: } 842: 843: /** 844: * Creates a new AbstractButton object. Subclasses should call the following 845: * sequence in their constructor in order to initialize the button correctly: 846: * <pre> 847: * super(); 848: * init(text, icon); 849: * </pre> 850: * 851: * The {@link #init(String, Icon)} method is not called automatically by this 852: * constructor. 853: * 854: * @see #init(String, Icon) 855: */ 856: public AbstractButton() 857: { 858: actionListener = createActionListener(); 859: changeListener = createChangeListener(); 860: itemListener = createItemListener(); 861: 862: horizontalAlignment = CENTER; 863: horizontalTextPosition = TRAILING; 864: verticalAlignment = CENTER; 865: verticalTextPosition = CENTER; 866: borderPainted = true; 867: contentAreaFilled = true; 868: focusPainted = true; 869: setFocusable(true); 870: setAlignmentX(CENTER_ALIGNMENT); 871: setAlignmentY(CENTER_ALIGNMENT); 872: setDisplayedMnemonicIndex(-1); 873: setOpaque(true); 874: text = ""; 875: updateUI(); 876: } 877: 878: /** 879: * Get the model the button is currently using. 880: * 881: * @return The current model 882: */ 883: public ButtonModel getModel() 884: { 885: return model; 886: } 887: 888: /** 889: * Set the model the button is currently using. This un-registers all 890: * listeners associated with the current model, and re-registers them 891: * with the new model. 892: * 893: * @param newModel The new model 894: */ 895: public void setModel(ButtonModel newModel) 896: { 897: if (newModel == model) 898: return; 899: 900: if (model != null) 901: { 902: model.removeActionListener(actionListener); 903: model.removeChangeListener(changeListener); 904: model.removeItemListener(itemListener); 905: } 906: ButtonModel old = model; 907: model = newModel; 908: if (model != null) 909: { 910: model.addActionListener(actionListener); 911: model.addChangeListener(changeListener); 912: model.addItemListener(itemListener); 913: } 914: firePropertyChange(MODEL_CHANGED_PROPERTY, old, model); 915: revalidate(); 916: repaint(); 917: } 918: 919: protected void init(String text, Icon icon) 920: { 921: // If text is null, we fall back to the empty 922: // string (which is set using AbstractButton's 923: // constructor). 924: // This way the behavior of the JDK is matched. 925: if(text != null) 926: setText(text); 927: 928: if (icon != null) 929: default_icon = icon; 930: } 931: 932: /** 933: * <p>Returns the action command string for this button's model.</p> 934: * 935: * <p>If the action command was set to <code>null</code>, the button's 936: * text (label) is returned instead.</p> 937: * 938: * @return The current action command string from the button's model 939: */ 940: public String getActionCommand() 941: { 942: String ac = model.getActionCommand(); 943: if (ac != null) 944: return ac; 945: else 946: return text; 947: } 948: 949: /** 950: * Sets the action command string for this button's model. 951: * 952: * @param actionCommand The new action command string to set in the button's 953: * model. 954: */ 955: public void setActionCommand(String actionCommand) 956: { 957: if (model != null) 958: model.setActionCommand(actionCommand); 959: } 960: 961: /** 962: * Adds an ActionListener to the button's listener list. When the 963: * button's model is clicked it fires an ActionEvent, and these 964: * listeners will be called. 965: * 966: * @param l The new listener to add 967: */ 968: public void addActionListener(ActionListener l) 969: { 970: listenerList.add(ActionListener.class, l); 971: } 972: 973: /** 974: * Removes an ActionListener from the button's listener list. 975: * 976: * @param l The listener to remove 977: */ 978: public void removeActionListener(ActionListener l) 979: { 980: listenerList.remove(ActionListener.class, l); 981: } 982: 983: /** 984: * Returns all added <code>ActionListener</code> objects. 985: * 986: * @return an array of listeners 987: * 988: * @since 1.4 989: */ 990: public ActionListener[] getActionListeners() 991: { 992: return (ActionListener[]) listenerList.getListeners(ActionListener.class); 993: } 994: 995: /** 996: * Adds an ItemListener to the button's listener list. When the button's 997: * model changes state (between any of ARMED, ENABLED, PRESSED, ROLLOVER 998: * or SELECTED) it fires an ItemEvent, and these listeners will be 999: * called. 1000: * 1001: * @param l The new listener to add 1002: */ 1003: public void addItemListener(ItemListener l) 1004: { 1005: listenerList.add(ItemListener.class, l); 1006: } 1007: 1008: /** 1009: * Removes an ItemListener from the button's listener list. 1010: * 1011: * @param l The listener to remove 1012: */ 1013: public void removeItemListener(ItemListener l) 1014: { 1015: listenerList.remove(ItemListener.class, l); 1016: } 1017: 1018: /** 1019: * Returns all added <code>ItemListener</code> objects. 1020: * 1021: * @return an array of listeners 1022: * 1023: * @since 1.4 1024: */ 1025: public ItemListener[] getItemListeners() 1026: { 1027: return (ItemListener[]) listenerList.getListeners(ItemListener.class); 1028: } 1029: 1030: /** 1031: * Adds a ChangeListener to the button's listener list. When the button's 1032: * model changes any of its (non-bound) properties, these listeners will be 1033: * called. 1034: * 1035: * @param l The new listener to add 1036: */ 1037: public void addChangeListener(ChangeListener l) 1038: { 1039: listenerList.add(ChangeListener.class, l); 1040: } 1041: 1042: /** 1043: * Removes a ChangeListener from the button's listener list. 1044: * 1045: * @param l The listener to remove 1046: */ 1047: public void removeChangeListener(ChangeListener l) 1048: { 1049: listenerList.remove(ChangeListener.class, l); 1050: } 1051: 1052: /** 1053: * Returns all added <code>ChangeListener</code> objects. 1054: * 1055: * @return an array of listeners 1056: * 1057: * @since 1.4 1058: */ 1059: public ChangeListener[] getChangeListeners() 1060: { 1061: return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); 1062: } 1063: 1064: /** 1065: * Calls {@link ItemListener#itemStateChanged} on each ItemListener in 1066: * the button's listener list. 1067: * 1068: * @param e The event signifying that the button's model changed state 1069: */ 1070: protected void fireItemStateChanged(ItemEvent e) 1071: { 1072: e.setSource(this); 1073: ItemListener[] listeners = getItemListeners(); 1074: 1075: for (int i = 0; i < listeners.length; i++) 1076: listeners[i].itemStateChanged(e); 1077: } 1078: 1079: /** 1080: * Calls {@link ActionListener#actionPerformed} on each {@link 1081: * ActionListener} in the button's listener list. 1082: * 1083: * @param e The event signifying that the button's model was clicked 1084: */ 1085: protected void fireActionPerformed(ActionEvent e) 1086: { 1087: // Dispatch a copy of the given ActionEvent in order to 1088: // set the source and action command correctly. 1089: ActionEvent ae = new ActionEvent( 1090: this, 1091: e.getID(), 1092: getActionCommand(), 1093: e.getWhen(), 1094: e.getModifiers()); 1095: 1096: ActionListener[] listeners = getActionListeners(); 1097: 1098: for (int i = 0; i < listeners.length; i++) 1099: listeners[i].actionPerformed(ae); 1100: } 1101: 1102: /** 1103: * Calls {@link ChangeListener#stateChanged} on each {@link ChangeListener} 1104: * in the button's listener list. 1105: */ 1106: protected void fireStateChanged() 1107: { 1108: ChangeListener[] listeners = getChangeListeners(); 1109: 1110: for (int i = 0; i < listeners.length; i++) 1111: listeners[i].stateChanged(changeEvent); 1112: } 1113: 1114: /** 1115: * Get the current keyboard mnemonic value. This value corresponds to a 1116: * single key code (one of the {@link java.awt.event.KeyEvent} VK_* 1117: * codes) and is used to activate the button when pressed in conjunction 1118: * with the "mouseless modifier" of the button's look and feel class, and 1119: * when focus is in one of the button's ancestors. 1120: * 1121: * @return The button's current keyboard mnemonic 1122: */ 1123: public int getMnemonic() 1124: { 1125: ButtonModel mod = getModel(); 1126: if (mod != null) 1127: return mod.getMnemonic(); 1128: return -1; 1129: } 1130: 1131: /** 1132: * Set the current keyboard mnemonic value. This value corresponds to a 1133: * single key code (one of the {@link java.awt.event.KeyEvent} VK_* 1134: * codes) and is used to activate the button when pressed in conjunction 1135: * with the "mouseless modifier" of the button's look and feel class, and 1136: * when focus is in one of the button's ancestors. 1137: * 1138: * @param mne A new mnemonic to use for the button 1139: */ 1140: public void setMnemonic(char mne) 1141: { 1142: setMnemonic((int) mne); 1143: } 1144: 1145: /** 1146: * Set the current keyboard mnemonic value. This value corresponds to a 1147: * single key code (one of the {@link java.awt.event.KeyEvent} VK_* 1148: * codes) and is used to activate the button when pressed in conjunction 1149: * with the "mouseless modifier" of the button's look and feel class, and 1150: * when focus is in one of the button's ancestors. 1151: * 1152: * @param mne A new mnemonic to use for the button 1153: */ 1154: public void setMnemonic(int mne) 1155: { 1156: ButtonModel mod = getModel(); 1157: int old = -1; 1158: if (mod != null) 1159: old = mod.getMnemonic(); 1160: 1161: if (old != mne) 1162: { 1163: if (mod != null) 1164: mod.setMnemonic(mne); 1165: 1166: if (text != null && !text.equals("")) 1167: { 1168: // Since lower case char = upper case char for 1169: // mnemonic, we will convert both text and mnemonic 1170: // to upper case before checking if mnemonic character occurs 1171: // in the menu item text. 1172: int upperCaseMne = Character.toUpperCase((char) mne); 1173: String upperCaseText = text.toUpperCase(); 1174: setDisplayedMnemonicIndex(upperCaseText.indexOf(upperCaseMne)); 1175: } 1176: 1177: firePropertyChange(MNEMONIC_CHANGED_PROPERTY, old, mne); 1178: revalidate(); 1179: repaint(); 1180: } 1181: } 1182: 1183: /** 1184: * Sets the button's mnemonic index. The mnemonic index is a hint to the 1185: * look and feel class, suggesting which character in the button's label 1186: * should be underlined when drawing the label. If the mnemonic index is 1187: * -1, no mnemonic will be displayed. 1188: * 1189: * If no mnemonic index is set, the button will choose a mnemonic index 1190: * by default, which will be the first occurrence of the mnemonic 1191: * character in the button's text. 1192: * 1193: * @param index An offset into the "text" property of the button 1194: * @throws IllegalArgumentException If <code>index</code> is not within the 1195: * range of legal offsets for the "text" property of the button. 1196: * @since 1.4 1197: */ 1198: 1199: public void setDisplayedMnemonicIndex(int index) 1200: { 1201: if (index < -1 || (text != null && index >= text.length())) 1202: throw new IllegalArgumentException(); 1203: 1204: mnemonicIndex = index; 1205: } 1206: 1207: /** 1208: * Get the button's mnemonic index, which is an offset into the button's 1209: * "text" property. The character specified by this offset should be 1210: * underlined when the look and feel class draws this button. 1211: * 1212: * @return An index into the button's "text" property 1213: */ 1214: public int getDisplayedMnemonicIndex() 1215: { 1216: return mnemonicIndex; 1217: } 1218: 1219: 1220: /** 1221: * Set the "rolloverEnabled" property. When rollover is enabled, and the 1222: * look and feel supports it, the button will change its icon to 1223: * rolloverIcon, when the mouse passes over it. 1224: * 1225: * @param r Whether or not to enable rollover icon changes 1226: */ 1227: public void setRolloverEnabled(boolean r) 1228: { 1229: clientRolloverEnabledSet = true; 1230: if (rollOverEnabled != r) 1231: { 1232: rollOverEnabled = r; 1233: firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, !r, r); 1234: revalidate(); 1235: repaint(); 1236: } 1237: } 1238: 1239: /** 1240: * Returns whether or not rollover icon changes are enabled on the 1241: * button. 1242: * 1243: * @return The state of the "rolloverEnabled" property 1244: */ 1245: public boolean isRolloverEnabled() 1246: { 1247: return rollOverEnabled; 1248: } 1249: 1250: /** 1251: * Set the value of the button's "selected" property. Selection is only 1252: * meaningful for toggle-type buttons (check boxes, radio buttons). 1253: * 1254: * @param s New value for the property 1255: */ 1256: public void setSelected(boolean s) 1257: { 1258: ButtonModel mod = getModel(); 1259: if (mod != null) 1260: mod.setSelected(s); 1261: } 1262: 1263: /** 1264: * Get the value of the button's "selected" property. Selection is only 1265: * meaningful for toggle-type buttons (check boxes, radio buttons). 1266: * 1267: * @return The value of the property 1268: */ 1269: public boolean isSelected() 1270: { 1271: ButtonModel mod = getModel(); 1272: if (mod != null) 1273: return mod.isSelected(); 1274: return false; 1275: } 1276: 1277: /** 1278: * Enables or disables the button. A button will neither be selectable 1279: * nor preform any actions unless it is enabled. 1280: * 1281: * @param b Whether or not to enable the button 1282: */ 1283: public void setEnabled(boolean b) 1284: { 1285: // Do nothing if state does not change. 1286: if (b == isEnabled()) 1287: return; 1288: super.setEnabled(b); 1289: setFocusable(b); 1290: ButtonModel mod = getModel(); 1291: if (mod != null) 1292: mod.setEnabled(b); 1293: } 1294: 1295: /** 1296: * Set the horizontal alignment of the button's text and icon. The 1297: * alignment is a numeric constant from {@link SwingConstants}. It must 1298: * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>, 1299: * <code>LEADING</code> or <code>TRAILING</code>. The default is 1300: * <code>CENTER</code>. 1301: * 1302: * @return The current horizontal alignment 1303: * 1304: * @see #setHorizontalAlignment(int) 1305: */ 1306: public int getHorizontalAlignment() 1307: { 1308: return horizontalAlignment; 1309: } 1310: 1311: /** 1312: * Set the horizontal alignment of the button's text and icon. The 1313: * alignment is a numeric constant from {@link SwingConstants}. It must 1314: * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>, 1315: * <code>LEADING</code> or <code>TRAILING</code>. The default is 1316: * <code>CENTER</code>. 1317: * 1318: * @param a The new horizontal alignment 1319: * @throws IllegalArgumentException If alignment is not one of the legal 1320: * constants. 1321: * 1322: * @see #getHorizontalAlignment() 1323: */ 1324: public void setHorizontalAlignment(int a) 1325: { 1326: if (horizontalAlignment == a) 1327: return; 1328: if (a != LEFT && a != CENTER && a != RIGHT && a != LEADING 1329: && a != TRAILING) 1330: throw new IllegalArgumentException("Invalid alignment."); 1331: int old = horizontalAlignment; 1332: horizontalAlignment = a; 1333: firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY, old, a); 1334: revalidate(); 1335: repaint(); 1336: } 1337: 1338: /** 1339: * Get the horizontal position of the button's text relative to its 1340: * icon. The position is a numeric constant from {@link 1341: * SwingConstants}. It must be one of: <code>RIGHT</code>, 1342: * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or 1343: * <code>TRAILING</code>. The default is <code>TRAILING</code>. 1344: * 1345: * @return The current horizontal text position 1346: */ 1347: public int getHorizontalTextPosition() 1348: { 1349: return horizontalTextPosition; 1350: } 1351: 1352: /** 1353: * Set the horizontal position of the button's text relative to its 1354: * icon. The position is a numeric constant from {@link 1355: * SwingConstants}. It must be one of: <code>RIGHT</code>, 1356: * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or 1357: * <code>TRAILING</code>. The default is <code>TRAILING</code>. 1358: * 1359: * @param t The new horizontal text position 1360: * @throws IllegalArgumentException If position is not one of the legal 1361: * constants. 1362: */ 1363: public void setHorizontalTextPosition(int t) 1364: { 1365: if (horizontalTextPosition == t) 1366: return; 1367: if (t != LEFT && t != CENTER && t != RIGHT && t != LEADING 1368: && t != TRAILING) 1369: throw new IllegalArgumentException("Invalid alignment."); 1370: 1371: int old = horizontalTextPosition; 1372: horizontalTextPosition = t; 1373: firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY, old, t); 1374: revalidate(); 1375: repaint(); 1376: } 1377: 1378: /** 1379: * Get the vertical alignment of the button's text and icon. The 1380: * alignment is a numeric constant from {@link SwingConstants}. It must 1381: * be one of: <code>CENTER</code>, <code>TOP</code>, or 1382: * <code>BOTTOM</code>. The default is <code>CENTER</code>. 1383: * 1384: * @return The current vertical alignment 1385: * 1386: * @see #setVerticalAlignment(int) 1387: */ 1388: public int getVerticalAlignment() 1389: { 1390: return verticalAlignment; 1391: } 1392: 1393: /** 1394: * Set the vertical alignment of the button's text and icon. The 1395: * alignment is a numeric constant from {@link SwingConstants}. It must 1396: * be one of: <code>CENTER</code>, <code>TOP</code>, or 1397: * <code>BOTTOM</code>. The default is <code>CENTER</code>. 1398: * 1399: * @param a The new vertical alignment 1400: * @throws IllegalArgumentException If alignment is not one of the legal 1401: * constants. 1402: * 1403: * @see #getVerticalAlignment() 1404: */ 1405: public void setVerticalAlignment(int a) 1406: { 1407: if (verticalAlignment == a) 1408: return; 1409: if (a != TOP && a != CENTER && a != BOTTOM) 1410: throw new IllegalArgumentException("Invalid alignment."); 1411: 1412: int old = verticalAlignment; 1413: verticalAlignment = a; 1414: firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, old, a); 1415: revalidate(); 1416: repaint(); 1417: } 1418: 1419: /** 1420: * Get the vertical position of the button's text relative to its 1421: * icon. The alignment is a numeric constant from {@link 1422: * SwingConstants}. It must be one of: <code>CENTER</code>, 1423: * <code>TOP</code>, or <code>BOTTOM</code>. The default is 1424: * <code>CENTER</code>. 1425: * 1426: * @return The current vertical position 1427: */ 1428: public int getVerticalTextPosition() 1429: { 1430: return verticalTextPosition; 1431: } 1432: 1433: /** 1434: * Set the vertical position of the button's text relative to its 1435: * icon. The alignment is a numeric constant from {@link 1436: * SwingConstants}. It must be one of: <code>CENTER</code>, 1437: * <code>TOP</code>, or <code>BOTTOM</code>. The default is 1438: * <code>CENTER</code>. 1439: * 1440: * @param t The new vertical position 1441: * @throws IllegalArgumentException If position is not one of the legal 1442: * constants. 1443: */ 1444: public void setVerticalTextPosition(int t) 1445: { 1446: if (verticalTextPosition == t) 1447: return; 1448: if (t != TOP && t != CENTER && t != BOTTOM) 1449: throw new IllegalArgumentException("Invalid alignment."); 1450: 1451: int old = verticalTextPosition; 1452: verticalTextPosition = t; 1453: firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, old, t); 1454: revalidate(); 1455: repaint(); 1456: } 1457: 1458: /** 1459: * Set the value of the "borderPainted" property. If set to 1460: * <code>false</code>, the button's look and feel class should not paint 1461: * a border for the button. The default is <code>true</code>. 1462: * 1463: * @return The current value of the property. 1464: */ 1465: public boolean isBorderPainted() 1466: { 1467: return borderPainted; 1468: } 1469: 1470: /** 1471: * Set the value of the "borderPainted" property. If set to 1472: * <code>false</code>, the button's look and feel class should not paint 1473: * a border for the button. The default is <code>true</code>. 1474: * 1475: * @param b The new value of the property. 1476: */ 1477: public void setBorderPainted(boolean b) 1478: { 1479: clientBorderPaintedSet = true; 1480: if (borderPainted == b) 1481: return; 1482: boolean old = borderPainted; 1483: borderPainted = b; 1484: firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, old, b); 1485: revalidate(); 1486: repaint(); 1487: } 1488: 1489: /** 1490: * Get the value of the "action" property. 1491: * 1492: * @return The current value of the "action" property 1493: */ 1494: public Action getAction() 1495: { 1496: return action; 1497: } 1498: 1499: /** 1500: * <p>Set the button's "action" property, subscribing the new action to the 1501: * button, as an ActionListener, if it is not already subscribed. The old 1502: * Action, if it exists, is unsubscribed, and the button is unsubscribed 1503: * from the old Action if it was previously subscribed as a 1504: * PropertyChangeListener.</p> 1505: * 1506: * <p>This method also configures several of the button's properties from 1507: * the Action, by calling {@link #configurePropertiesFromAction}, and 1508: * subscribes the button to the Action as a PropertyChangeListener. 1509: * Subsequent changes to the Action will thus reconfigure the button 1510: * automatically.</p> 1511: * 1512: * @param a The new value of the "action" property 1513: */ 1514: public void setAction(Action a) 1515: { 1516: if (action != null) 1517: { 1518: action.removePropertyChangeListener(actionPropertyChangeListener); 1519: removeActionListener(action); 1520: if (actionPropertyChangeListener != null) 1521: { 1522: action.removePropertyChangeListener(actionPropertyChangeListener); 1523: actionPropertyChangeListener = null; 1524: } 1525: } 1526: 1527: Action old = action; 1528: action = a; 1529: configurePropertiesFromAction(action); 1530: if (action != null) 1531: { 1532: actionPropertyChangeListener = createActionPropertyChangeListener(a); 1533: action.addPropertyChangeListener(actionPropertyChangeListener); 1534: addActionListener(action); 1535: } 1536: } 1537: 1538: /** 1539: * Return the button's default "icon" property. 1540: * 1541: * @return The current default icon 1542: */ 1543: public Icon getIcon() 1544: { 1545: return default_icon; 1546: } 1547: 1548: /** 1549: * Set the button's default "icon" property. This icon is used as a basis 1550: * for the pressed and disabled icons, if none are explicitly set. 1551: * 1552: * @param i The new default icon 1553: */ 1554: public void setIcon(Icon i) 1555: { 1556: if (default_icon == i) 1557: return; 1558: 1559: Icon old = default_icon; 1560: default_icon = i; 1561: firePropertyChange(ICON_CHANGED_PROPERTY, old, i); 1562: revalidate(); 1563: repaint(); 1564: } 1565: 1566: /** 1567: * Return the button's "text" property. This property is synonymous with 1568: * the "label" property. 1569: * 1570: * @return The current "text" property 1571: */ 1572: public String getText() 1573: { 1574: return text; 1575: } 1576: 1577: /** 1578: * Set the button's "label" property. This property is synonymous with the 1579: * "text" property. 1580: * 1581: * @param label The new "label" property 1582: * 1583: * @deprecated use <code>setText(text)</code> 1584: */ 1585: public void setLabel(String label) 1586: { 1587: setText(label); 1588: } 1589: 1590: /** 1591: * Return the button's "label" property. This property is synonymous with 1592: * the "text" property. 1593: * 1594: * @return The current "label" property 1595: * 1596: * @deprecated use <code>getText()</code> 1597: */ 1598: public String getLabel() 1599: { 1600: return getText(); 1601: } 1602: 1603: /** 1604: * Set the button's "text" property. This property is synonymous with the 1605: * "label" property. 1606: * 1607: * @param t The new "text" property 1608: */ 1609: public void setText(String t) 1610: { 1611: if (text == t) 1612: return; 1613: 1614: String old = text; 1615: text = t; 1616: firePropertyChange(TEXT_CHANGED_PROPERTY, old, t); 1617: revalidate(); 1618: repaint(); 1619: } 1620: 1621: /** 1622: * Set the value of the {@link #iconTextGap} property. 1623: * 1624: * @param i The new value of the property 1625: * 1626: * @since 1.4 1627: */ 1628: public void setIconTextGap(int i) 1629: { 1630: clientIconTextGapSet = true; 1631: if (iconTextGap == i) 1632: return; 1633: 1634: int old = iconTextGap; 1635: iconTextGap = i; 1636: firePropertyChange("iconTextGap", new Integer(old), new Integer(i)); 1637: revalidate(); 1638: repaint(); 1639: } 1640: 1641: /** 1642: * Get the value of the {@link #iconTextGap} property. 1643: * 1644: * @return The current value of the property 1645: * 1646: * @since 1.4 1647: */ 1648: public int getIconTextGap() 1649: { 1650: return iconTextGap; 1651: } 1652: 1653: /** 1654: * Return the button's "margin" property, which is an {@link Insets} object 1655: * describing the distance between the button's border and its text and 1656: * icon. 1657: * 1658: * @return The current "margin" property 1659: */ 1660: public Insets getMargin() 1661: { 1662: return margin; 1663: } 1664: 1665: /** 1666: * Set the button's "margin" property, which is an {@link Insets} object 1667: * describing the distance between the button's border and its text and 1668: * icon. 1669: * 1670: * @param m The new "margin" property 1671: */ 1672: public void setMargin(Insets m) 1673: { 1674: if (margin == m) 1675: return; 1676: 1677: Insets old = margin; 1678: margin = m; 1679: firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m); 1680: revalidate(); 1681: repaint(); 1682: } 1683: 1684: /** 1685: * Return the button's "pressedIcon" property. The look and feel class 1686: * should paint this icon when the "pressed" property of the button's 1687: * {@link ButtonModel} is <code>true</code>. This property may be 1688: * <code>null</code>, in which case the default icon is used. 1689: * 1690: * @return The current "pressedIcon" property 1691: */ 1692: public Icon getPressedIcon() 1693: { 1694: return pressed_icon; 1695: } 1696: 1697: /** 1698: * Set the button's "pressedIcon" property. The look and feel class 1699: * should paint this icon when the "pressed" property of the button's 1700: * {@link ButtonModel} is <code>true</code>. This property may be 1701: * <code>null</code>, in which case the default icon is used. 1702: * 1703: * @param pressedIcon The new "pressedIcon" property 1704: */ 1705: public void setPressedIcon(Icon pressedIcon) 1706: { 1707: if (pressed_icon == pressedIcon) 1708: return; 1709: 1710: Icon old = pressed_icon; 1711: pressed_icon = pressedIcon; 1712: firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, old, pressed_icon); 1713: revalidate(); 1714: repaint(); 1715: } 1716: 1717: /** 1718: * Return the button's "disabledIcon" property. The look and feel class 1719: * should paint this icon when the "enabled" property of the button's 1720: * {@link ButtonModel} is <code>false</code>. This property may be 1721: * <code>null</code>, in which case an icon is constructed, based on the 1722: * default icon. 1723: * 1724: * @return The current "disabledIcon" property 1725: */ 1726: public Icon getDisabledIcon() 1727: { 1728: if (disabledIcon == null && default_icon instanceof ImageIcon) 1729: { 1730: Image iconImage = ((ImageIcon) default_icon).getImage(); 1731: Image grayImage = GrayFilter.createDisabledImage(iconImage); 1732: disabledIcon = new ImageIcon(grayImage); 1733: } 1734: 1735: return disabledIcon; 1736: } 1737: 1738: /** 1739: * Set the button's "disabledIcon" property. The look and feel class should 1740: * paint this icon when the "enabled" property of the button's {@link 1741: * ButtonModel} is <code>false</code>. This property may be 1742: * <code>null</code>, in which case an icon is constructed, based on the 1743: * default icon. 1744: * 1745: * @param d The new "disabledIcon" property 1746: */ 1747: public void setDisabledIcon(Icon d) 1748: { 1749: if (disabledIcon == d) 1750: return; 1751: Icon old = disabledIcon; 1752: disabledIcon = d; 1753: firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, old, d); 1754: revalidate(); 1755: repaint(); 1756: } 1757: 1758: /** 1759: * Return the button's "paintFocus" property. This property controls 1760: * whether or not the look and feel class will paint a special indicator 1761: * of focus state for the button. If it is false, the button still paints 1762: * when focused, but no special decoration is painted to indicate the 1763: * presence of focus. 1764: * 1765: * @return The current "paintFocus" property 1766: */ 1767: public boolean isFocusPainted() 1768: { 1769: return focusPainted; 1770: } 1771: 1772: /** 1773: * Set the button's "paintFocus" property. This property controls whether 1774: * or not the look and feel class will paint a special indicator of focus 1775: * state for the button. If it is false, the button still paints when 1776: * focused, but no special decoration is painted to indicate the presence 1777: * of focus. 1778: * 1779: * @param p The new "paintFocus" property 1780: */ 1781: public void setFocusPainted(boolean p) 1782: { 1783: if (focusPainted == p) 1784: return; 1785: 1786: boolean old = focusPainted; 1787: focusPainted = p; 1788: firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, old, p); 1789: revalidate(); 1790: repaint(); 1791: } 1792: 1793: /** 1794: * Verifies that a particular key is one of the valid constants used for 1795: * describing horizontal alignment and positioning. The valid constants 1796: * are the following members of {@link SwingConstants}: 1797: * <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>, 1798: * <code>LEADING</code> or <code>TRAILING</code>. 1799: * 1800: * @param key The key to check 1801: * @param exception A message to include in an IllegalArgumentException 1802: * 1803: * @return the value of key 1804: * 1805: * @throws IllegalArgumentException If key is not one of the valid constants 1806: * 1807: * @see #setHorizontalTextPosition(int) 1808: * @see #setHorizontalAlignment(int) 1809: */ 1810: protected int checkHorizontalKey(int key, String exception) 1811: { 1812: switch (key) 1813: { 1814: case SwingConstants.RIGHT: 1815: case SwingConstants.LEFT: 1816: case SwingConstants.CENTER: 1817: case SwingConstants.LEADING: 1818: case SwingConstants.TRAILING: 1819: break; 1820: default: 1821: throw new IllegalArgumentException(exception); 1822: } 1823: return key; 1824: } 1825: 1826: /** 1827: * Verifies that a particular key is one of the valid constants used for 1828: * describing vertical alignment and positioning. The valid constants are 1829: * the following members of {@link SwingConstants}: <code>TOP</code>, 1830: * <code>BOTTOM</code> or <code>CENTER</code>. 1831: * 1832: * @param key The key to check 1833: * @param exception A message to include in an IllegalArgumentException 1834: * 1835: * @return the value of key 1836: * 1837: * @throws IllegalArgumentException If key is not one of the valid constants 1838: * 1839: * @see #setVerticalTextPosition(int) 1840: * @see #setVerticalAlignment(int) 1841: */ 1842: protected int checkVerticalKey(int key, String exception) 1843: { 1844: switch (key) 1845: { 1846: case SwingConstants.TOP: 1847: case SwingConstants.BOTTOM: 1848: case SwingConstants.CENTER: 1849: break; 1850: default: 1851: throw new IllegalArgumentException(exception); 1852: } 1853: return key; 1854: } 1855: 1856: /** 1857: * Configure various properties of the button by reading properties 1858: * of an {@link Action}. The mapping of properties is as follows: 1859: * 1860: * <table> 1861: * 1862: * <tr><th>Action keyed property</th> <th>AbstractButton property</th></tr> 1863: * 1864: * <tr><td>NAME </td> <td>text </td></tr> 1865: * <tr><td>SMALL_ICON </td> <td>icon </td></tr> 1866: * <tr><td>SHORT_DESCRIPTION </td> <td>toolTipText </td></tr> 1867: * <tr><td>MNEMONIC_KEY </td> <td>mnemonic </td></tr> 1868: * <tr><td>ACTION_COMMAND_KEY </td> <td>actionCommand </td></tr> 1869: * 1870: * </table> 1871: * 1872: * <p>In addition, this method always sets the button's "enabled" property to 1873: * the value of the Action's "enabled" property.</p> 1874: * 1875: * <p>If the provided Action is <code>null</code>, the text, icon, and 1876: * toolTipText properties of the button are set to <code>null</code>, and 1877: * the "enabled" property is set to <code>true</code>; the mnemonic and 1878: * actionCommand properties are unchanged.</p> 1879: * 1880: * @param a An Action to configure the button from 1881: */ 1882: protected void configurePropertiesFromAction(Action a) 1883: { 1884: if (a == null) 1885: { 1886: setText(null); 1887: setIcon(null); 1888: setEnabled(true); 1889: setToolTipText(null); 1890: } 1891: else 1892: { 1893: setText((String) (a.getValue(Action.NAME))); 1894: setIcon((Icon) (a.getValue(Action.SMALL_ICON))); 1895: setEnabled(a.isEnabled()); 1896: setToolTipText((String) (a.getValue(Action.SHORT_DESCRIPTION))); 1897: if (a.getValue(Action.MNEMONIC_KEY) != null) 1898: setMnemonic(((Integer) (a.getValue(Action.MNEMONIC_KEY))).intValue()); 1899: String actionCommand = (String) (a.getValue(Action.ACTION_COMMAND_KEY)); 1900: 1901: // Set actionCommand to button's text by default if it is not specified 1902: if (actionCommand != null) 1903: setActionCommand((String) (a.getValue(Action.ACTION_COMMAND_KEY))); 1904: else 1905: setActionCommand(getText()); 1906: } 1907: } 1908: 1909: /** 1910: * <p>A factory method which should return an {@link ActionListener} that 1911: * propagates events from the button's {@link ButtonModel} to any of the 1912: * button's ActionListeners. By default, this is an inner class which 1913: * calls {@link AbstractButton#fireActionPerformed} with a modified copy 1914: * of the incoming model {@link ActionEvent}.</p> 1915: * 1916: * <p>The button calls this method during construction, stores the 1917: * resulting ActionListener in its <code>actionListener</code> member 1918: * field, and subscribes it to the button's model. If the button's model 1919: * is changed, this listener is unsubscribed from the old model and 1920: * subscribed to the new one.</p> 1921: * 1922: * @return A new ActionListener 1923: */ 1924: protected ActionListener createActionListener() 1925: { 1926: return new ActionListener() 1927: { 1928: public void actionPerformed(ActionEvent e) 1929: { 1930: AbstractButton.this.fireActionPerformed(e); 1931: } 1932: }; 1933: } 1934: 1935: /** 1936: * <p>A factory method which should return a {@link PropertyChangeListener} 1937: * that accepts changes to the specified {@link Action} and reconfigure 1938: * the {@link AbstractButton}, by default using the {@link 1939: * #configurePropertiesFromAction} method.</p> 1940: * 1941: * <p>The button calls this method whenever a new Action is assigned to 1942: * the button's "action" property, via {@link #setAction}, and stores the 1943: * resulting PropertyChangeListener in its 1944: * <code>actionPropertyChangeListener</code> member field. The button 1945: * then subscribes the listener to the button's new action. If the 1946: * button's action is changed subsequently, the listener is unsubscribed 1947: * from the old action and subscribed to the new one.</p> 1948: * 1949: * @param a The Action which will be listened to, and which should be 1950: * the same as the source of any PropertyChangeEvents received by the 1951: * new listener returned from this method. 1952: * 1953: * @return A new PropertyChangeListener 1954: */ 1955: protected PropertyChangeListener createActionPropertyChangeListener(Action a) 1956: { 1957: return new PropertyChangeListener() 1958: { 1959: public void propertyChange(PropertyChangeEvent e) 1960: { 1961: Action act = (Action) (e.getSource()); 1962: if (e.getPropertyName().equals("enabled")) 1963: setEnabled(act.isEnabled()); 1964: else if (e.getPropertyName().equals(Action.NAME)) 1965: setText((String) (act.getValue(Action.NAME))); 1966: else if (e.getPropertyName().equals(Action.SMALL_ICON)) 1967: setIcon((Icon) (act.getValue(Action.SMALL_ICON))); 1968: else if (e.getPropertyName().equals(Action.SHORT_DESCRIPTION)) 1969: setToolTipText((String) (act.getValue(Action.SHORT_DESCRIPTION))); 1970: else if (e.getPropertyName().equals(Action.MNEMONIC_KEY)) 1971: if (act.getValue(Action.MNEMONIC_KEY) != null) 1972: setMnemonic(((Integer) (act.getValue(Action.MNEMONIC_KEY))) 1973: .intValue()); 1974: else if (e.getPropertyName().equals(Action.ACTION_COMMAND_KEY)) 1975: setActionCommand((String) (act.getValue(Action.ACTION_COMMAND_KEY))); 1976: } 1977: }; 1978: } 1979: 1980: /** 1981: * <p>Factory method which creates a {@link ChangeListener}, used to 1982: * subscribe to ChangeEvents from the button's model. Subclasses of 1983: * AbstractButton may wish to override the listener used to subscribe to 1984: * such ChangeEvents. By default, the listener just propagates the 1985: * {@link ChangeEvent} to the button's ChangeListeners, via the {@link 1986: * AbstractButton#fireStateChanged} method.</p> 1987: * 1988: * <p>The button calls this method during construction, stores the 1989: * resulting ChangeListener in its <code>changeListener</code> member 1990: * field, and subscribes it to the button's model. If the button's model 1991: * is changed, this listener is unsubscribed from the old model and 1992: * subscribed to the new one.</p> 1993: * 1994: * @return The new ChangeListener 1995: */ 1996: protected ChangeListener createChangeListener() 1997: { 1998: return new ButtonChangeListener(); 1999: } 2000: 2001: /** 2002: * <p>Factory method which creates a {@link ItemListener}, used to 2003: * subscribe to ItemEvents from the button's model. Subclasses of 2004: * AbstractButton may wish to override the listener used to subscribe to 2005: * such ItemEvents. By default, the listener just propagates the 2006: * {@link ItemEvent} to the button's ItemListeners, via the {@link 2007: * AbstractButton#fireItemStateChanged} method.</p> 2008: * 2009: * <p>The button calls this method during construction, stores the 2010: * resulting ItemListener in its <code>changeListener</code> member 2011: * field, and subscribes it to the button's model. If the button's model 2012: * is changed, this listener is unsubscribed from the old model and 2013: * subscribed to the new one.</p> 2014: * 2015: * <p>Note that ItemEvents are only generated from the button's model 2016: * when the model's <em>selected</em> property changes. If you want to 2017: * subscribe to other properties of the model, you must subscribe to 2018: * ChangeEvents. 2019: * 2020: * @return The new ItemListener 2021: */ 2022: protected ItemListener createItemListener() 2023: { 2024: return new ItemListener() 2025: { 2026: public void itemStateChanged(ItemEvent e) 2027: { 2028: AbstractButton.this.fireItemStateChanged(e); 2029: } 2030: }; 2031: } 2032: 2033: /** 2034: * Programmatically perform a "click" on the button: arming, pressing, 2035: * waiting, un-pressing, and disarming the model. 2036: */ 2037: public void doClick() 2038: { 2039: doClick(100); 2040: } 2041: 2042: /** 2043: * Programmatically perform a "click" on the button: arming, pressing, 2044: * waiting, un-pressing, and disarming the model. 2045: * 2046: * @param pressTime The number of milliseconds to wait in the pressed state 2047: */ 2048: public void doClick(int pressTime) 2049: { 2050: ButtonModel mod = getModel(); 2051: if (mod != null) 2052: { 2053: mod.setArmed(true); 2054: mod.setPressed(true); 2055: try 2056: { 2057: java.lang.Thread.sleep(pressTime); 2058: } 2059: catch (java.lang.InterruptedException e) 2060: { 2061: // probably harmless 2062: } 2063: mod.setPressed(false); 2064: mod.setArmed(false); 2065: } 2066: } 2067: 2068: /** 2069: * Return the button's disabled selected icon. The look and feel class 2070: * should paint this icon when the "enabled" property of the button's model 2071: * is <code>false</code> and its "selected" property is 2072: * <code>true</code>. This icon can be <code>null</code>, in which case 2073: * it is synthesized from the button's selected icon. 2074: * 2075: * @return The current disabled selected icon 2076: */ 2077: public Icon getDisabledSelectedIcon() 2078: { 2079: return disabledSelectedIcon; 2080: } 2081: 2082: /** 2083: * Set the button's disabled selected icon. The look and feel class 2084: * should paint this icon when the "enabled" property of the button's model 2085: * is <code>false</code> and its "selected" property is 2086: * <code>true</code>. This icon can be <code>null</code>, in which case 2087: * it is synthesized from the button's selected icon. 2088: * 2089: * @param icon The new disabled selected icon 2090: */ 2091: public void setDisabledSelectedIcon(Icon icon) 2092: { 2093: if (disabledSelectedIcon == icon) 2094: return; 2095: 2096: Icon old = disabledSelectedIcon; 2097: disabledSelectedIcon = icon; 2098: firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, old, icon); 2099: revalidate(); 2100: repaint(); 2101: } 2102: 2103: /** 2104: * Return the button's rollover icon. The look and feel class should 2105: * paint this icon when the "rolloverEnabled" property of the button is 2106: * <code>true</code> and the mouse rolls over the button. 2107: * 2108: * @return The current rollover icon 2109: */ 2110: public Icon getRolloverIcon() 2111: { 2112: return rolloverIcon; 2113: } 2114: 2115: /** 2116: * Set the button's rollover icon and sets the <code>rolloverEnabled</code> 2117: * property to <code>true</code>. The look and feel class should 2118: * paint this icon when the "rolloverEnabled" property of the button is 2119: * <code>true</code> and the mouse rolls over the button. 2120: * 2121: * @param r The new rollover icon 2122: */ 2123: public void setRolloverIcon(Icon r) 2124: { 2125: if (rolloverIcon == r) 2126: return; 2127: 2128: Icon old = rolloverIcon; 2129: rolloverIcon = r; 2130: firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, old, rolloverIcon); 2131: setRolloverEnabled(true); 2132: revalidate(); 2133: repaint(); 2134: } 2135: 2136: /** 2137: * Return the button's rollover selected icon. The look and feel class 2138: * should paint this icon when the "rolloverEnabled" property of the button 2139: * is <code>true</code>, the "selected" property of the button's model is 2140: * <code>true</code>, and the mouse rolls over the button. 2141: * 2142: * @return The current rollover selected icon 2143: */ 2144: public Icon getRolloverSelectedIcon() 2145: { 2146: return rolloverSelectedIcon; 2147: } 2148: 2149: /** 2150: * Set the button's rollover selected icon and sets the 2151: * <code>rolloverEnabled</code> property to <code>true</code>. The look and 2152: * feel class should paint this icon when the "rolloverEnabled" property of 2153: * the button is <code>true</code>, the "selected" property of the button's 2154: * model is <code>true</code>, and the mouse rolls over the button. 2155: * 2156: * @param r The new rollover selected icon. 2157: */ 2158: public void setRolloverSelectedIcon(Icon r) 2159: { 2160: if (rolloverSelectedIcon == r) 2161: return; 2162: 2163: Icon old = rolloverSelectedIcon; 2164: rolloverSelectedIcon = r; 2165: firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, old, r); 2166: setRolloverEnabled(true); 2167: revalidate(); 2168: repaint(); 2169: } 2170: 2171: /** 2172: * Return the button's selected icon. The look and feel class should 2173: * paint this icon when the "selected" property of the button's model is 2174: * <code>true</code>, and either the "rolloverEnabled" property of the 2175: * button is <code>false</code> or the mouse is not currently rolled 2176: * over the button. 2177: * 2178: * @return The current selected icon 2179: */ 2180: public Icon getSelectedIcon() 2181: { 2182: return selectedIcon; 2183: } 2184: 2185: /** 2186: * Set the button's selected icon. The look and feel class should 2187: * paint this icon when the "selected" property of the button's model is 2188: * <code>true</code>, and either the "rolloverEnabled" property of the 2189: * button is <code>false</code> or the mouse is not currently rolled 2190: * over the button. 2191: * 2192: * @param s The new selected icon 2193: */ 2194: public void setSelectedIcon(Icon s) 2195: { 2196: if (selectedIcon == s) 2197: return; 2198: 2199: Icon old = selectedIcon; 2200: selectedIcon = s; 2201: firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, old, s); 2202: revalidate(); 2203: repaint(); 2204: } 2205: 2206: /** 2207: * Returns an single-element array containing the "text" property of the 2208: * button if the "selected" property of the button's model is 2209: * <code>true</code>, otherwise returns <code>null</code>. 2210: * 2211: * @return The button's "selected object" array 2212: */ 2213: public Object[] getSelectedObjects() 2214: { 2215: if (isSelected()) 2216: { 2217: Object[] objs = new Object[1]; 2218: objs[0] = getText(); 2219: return objs; 2220: } 2221: else 2222: { 2223: return null; 2224: } 2225: } 2226: 2227: /** 2228: * Called when image data becomes available for one of the button's icons. 2229: * 2230: * @param img The image being updated 2231: * @param infoflags One of the constant codes in {@link ImageObserver} used 2232: * to describe updated portions of an image. 2233: * @param x X coordinate of the region being updated 2234: * @param y Y coordinate of the region being updated 2235: * @param w Width of the region beign updated 2236: * @param h Height of the region being updated 2237: * 2238: * @return <code>true</code> if img is equal to the button's current icon, 2239: * otherwise <code>false</code> 2240: */ 2241: public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, 2242: int h) 2243: { 2244: return current_icon == img; 2245: } 2246: 2247: /** 2248: * Returns the value of the button's "contentAreaFilled" property. This 2249: * property indicates whether the area surrounding the text and icon of 2250: * the button should be filled by the look and feel class. If this 2251: * property is <code>false</code>, the look and feel class should leave 2252: * the content area transparent. 2253: * 2254: * @return The current value of the "contentAreaFilled" property 2255: */ 2256: public boolean isContentAreaFilled() 2257: { 2258: return contentAreaFilled; 2259: } 2260: 2261: /** 2262: * Sets the value of the button's "contentAreaFilled" property. This 2263: * property indicates whether the area surrounding the text and icon of 2264: * the button should be filled by the look and feel class. If this 2265: * property is <code>false</code>, the look and feel class should leave 2266: * the content area transparent. 2267: * 2268: * @param b The new value of the "contentAreaFilled" property 2269: */ 2270: public void setContentAreaFilled(boolean b) 2271: { 2272: clientContentAreaFilledSet = true; 2273: if (contentAreaFilled == b) 2274: return; 2275: 2276: // The JDK sets the opaque property to the value of the contentAreaFilled 2277: // property, so should we do. 2278: setOpaque(b); 2279: boolean old = contentAreaFilled; 2280: contentAreaFilled = b; 2281: firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, old, b); 2282: } 2283: 2284: /** 2285: * Paints the button's border, if the button's "borderPainted" property is 2286: * <code>true</code>, by out calling to the button's look and feel class. 2287: * 2288: * @param g The graphics context used to paint the border 2289: */ 2290: protected void paintBorder(Graphics g) 2291: { 2292: if (isBorderPainted()) 2293: super.paintBorder(g); 2294: } 2295: 2296: /** 2297: * Returns a string, used only for debugging, which identifies or somehow 2298: * represents this button. The exact value is implementation-defined. 2299: * 2300: * @return A string representation of the button 2301: */ 2302: protected String paramString() 2303: { 2304: StringBuffer sb = new StringBuffer(); 2305: sb.append(super.paramString()); 2306: sb.append(",defaultIcon="); 2307: if (getIcon() != null) 2308: sb.append(getIcon()); 2309: sb.append(",disabledIcon="); 2310: if (getDisabledIcon() != null) 2311: sb.append(getDisabledIcon()); 2312: sb.append(",disabledSelectedIcon="); 2313: if (getDisabledSelectedIcon() != null) 2314: sb.append(getDisabledSelectedIcon()); 2315: sb.append(",margin="); 2316: if (getMargin() != null) 2317: sb.append(getMargin()); 2318: sb.append(",paintBorder=").append(isBorderPainted()); 2319: sb.append(",paintFocus=").append(isFocusPainted()); 2320: sb.append(",pressedIcon="); 2321: if (getPressedIcon() != null) 2322: sb.append(getPressedIcon()); 2323: sb.append(",rolloverEnabled=").append(isRolloverEnabled()); 2324: sb.append(",rolloverIcon="); 2325: if (getRolloverIcon() != null) 2326: sb.append(getRolloverIcon()); 2327: sb.append(",rolloverSelected="); 2328: if (getRolloverSelectedIcon() != null) 2329: sb.append(getRolloverSelectedIcon()); 2330: sb.append(",selectedIcon="); 2331: if (getSelectedIcon() != null) 2332: sb.append(getSelectedIcon()); 2333: sb.append(",text="); 2334: if (getText() != null) 2335: sb.append(getText()); 2336: return sb.toString(); 2337: } 2338: 2339: /** 2340: * Set the "UI" property of the button, which is a look and feel class 2341: * responsible for handling the button's input events and painting it. 2342: * 2343: * @param ui The new "UI" property 2344: */ 2345: public void setUI(ButtonUI ui) 2346: { 2347: super.setUI(ui); 2348: } 2349: 2350: /** 2351: * Set the "UI" property of the button, which is a look and feel class 2352: * responsible for handling the button's input events and painting it. 2353: * 2354: * @return The current "UI" property 2355: */ 2356: public ButtonUI getUI() 2357: { 2358: return (ButtonUI) ui; 2359: } 2360: 2361: /** 2362: * Set the "UI" property to a class constructed, via the {@link 2363: * UIManager}, from the current look and feel. This should be overridden 2364: * for each subclass of AbstractButton, to retrieve a suitable {@link 2365: * ButtonUI} look and feel class. 2366: */ 2367: public void updateUI() 2368: { 2369: // TODO: What to do here? 2370: } 2371: 2372: /** 2373: * Returns the current time in milliseconds in which clicks gets coalesced 2374: * into a single <code>ActionEvent</code>. 2375: * 2376: * @return the time in milliseconds 2377: * 2378: * @since 1.4 2379: */ 2380: public long getMultiClickThreshhold() 2381: { 2382: return multiClickThreshhold; 2383: } 2384: 2385: /** 2386: * Sets the time in milliseconds in which clicks gets coalesced into a single 2387: * <code>ActionEvent</code>. 2388: * 2389: * @param threshhold the time in milliseconds 2390: * 2391: * @since 1.4 2392: */ 2393: public void setMultiClickThreshhold(long threshhold) 2394: { 2395: if (threshhold < 0) 2396: throw new IllegalArgumentException(); 2397: 2398: multiClickThreshhold = threshhold; 2399: } 2400: 2401: /** 2402: * Adds the specified component to this AbstractButton. This overrides the 2403: * default in order to install an {@link OverlayLayout} layout manager 2404: * before adding the component. The layout manager is only installed if 2405: * no other layout manager has been installed before. 2406: * 2407: * @param comp the component to be added 2408: * @param constraints constraints for the layout manager 2409: * @param index the index at which the component is added 2410: * 2411: * @since 1.5 2412: */ 2413: protected void addImpl(Component comp, Object constraints, int index) 2414: { 2415: // We use a client property here, so that no extra memory is used in 2416: // the common case with no layout manager. 2417: if (getClientProperty("AbstractButton.customLayoutSet") == null) 2418: setLayout(new OverlayLayout(this)); 2419: super.addImpl(comp, constraints, index); 2420: } 2421: 2422: /** 2423: * Sets a layout manager on this AbstractButton. This is overridden in order 2424: * to detect if the application sets a custom layout manager. If no custom 2425: * layout manager is set, {@link #addImpl(Component, Object, int)} installs 2426: * an OverlayLayout before adding a component. 2427: * 2428: * @param layout the layout manager to install 2429: * 2430: * @since 1.5 2431: */ 2432: public void setLayout(LayoutManager layout) 2433: { 2434: // We use a client property here, so that no extra memory is used in 2435: // the common case with no layout manager. 2436: putClientProperty("AbstractButton.customLayoutSet", Boolean.TRUE); 2437: super.setLayout(layout); 2438: } 2439: 2440: /** 2441: * Helper method for 2442: * {@link LookAndFeel#installProperty(JComponent, String, Object)}. 2443: * 2444: * @param propertyName the name of the property 2445: * @param value the value of the property 2446: * 2447: * @throws IllegalArgumentException if the specified property cannot be set 2448: * by this method 2449: * @throws ClassCastException if the property value does not match the 2450: * property type 2451: * @throws NullPointerException if <code>c</code> or 2452: * <code>propertyValue</code> is <code>null</code> 2453: */ 2454: void setUIProperty(String propertyName, Object value) 2455: { 2456: if (propertyName.equals("borderPainted")) 2457: { 2458: if (! clientBorderPaintedSet) 2459: { 2460: setBorderPainted(((Boolean) value).booleanValue()); 2461: clientBorderPaintedSet = false; 2462: } 2463: } 2464: else if (propertyName.equals("rolloverEnabled")) 2465: { 2466: if (! clientRolloverEnabledSet) 2467: { 2468: setRolloverEnabled(((Boolean) value).booleanValue()); 2469: clientRolloverEnabledSet = false; 2470: } 2471: } 2472: else if (propertyName.equals("iconTextGap")) 2473: { 2474: if (! clientIconTextGapSet) 2475: { 2476: setIconTextGap(((Integer) value).intValue()); 2477: clientIconTextGapSet = false; 2478: } 2479: } 2480: else if (propertyName.equals("contentAreaFilled")) 2481: { 2482: if (! clientContentAreaFilledSet) 2483: { 2484: setContentAreaFilled(((Boolean) value).booleanValue()); 2485: clientContentAreaFilledSet = false; 2486: } 2487: } 2488: else 2489: { 2490: super.setUIProperty(propertyName, value); 2491: } 2492: } 2493: }