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