GNU Classpath (0.20) | |
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: setFocusable(b); 960: ButtonModel mod = getModel(); 961: if (mod != null) 962: mod.setEnabled(b); 963: } 964: 965: /** 966: * Set the horizontal alignment of the button's text and icon. The 967: * alignment is a numeric constant from {@link SwingConstants}. It must 968: * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>, 969: * <code>LEADING</code> or <code>TRAILING</code>. The default is 970: * <code>RIGHT</code>. 971: * 972: * @return The current horizontal alignment 973: */ 974: public int getHorizontalAlignment() 975: { 976: return horizontalAlignment; 977: } 978: 979: /** 980: * Set the horizontal alignment of the button's text and icon. The 981: * alignment is a numeric constant from {@link SwingConstants}. It must 982: * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>, 983: * <code>LEADING</code> or <code>TRAILING</code>. The default is 984: * <code>RIGHT</code>. 985: * 986: * @param a The new horizontal alignment 987: * @throws IllegalArgumentException If alignment is not one of the legal 988: * constants. 989: */ 990: public void setHorizontalAlignment(int a) 991: { 992: if (horizontalAlignment == a) 993: return; 994: 995: int old = horizontalAlignment; 996: horizontalAlignment = a; 997: firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY, old, a); 998: revalidate(); 999: repaint(); 1000: } 1001: 1002: /** 1003: * Get the horizontal position of the button's text relative to its 1004: * icon. The position is a numeric constant from {@link 1005: * SwingConstants}. It must be one of: <code>RIGHT</code>, 1006: * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or 1007: * <code>TRAILING</code>. The default is <code>TRAILING</code>. 1008: * 1009: * @return The current horizontal text position 1010: */ 1011: public int getHorizontalTextPosition() 1012: { 1013: return horizontalTextPosition; 1014: } 1015: 1016: /** 1017: * Set the horizontal position of the button's text relative to its 1018: * icon. The position is a numeric constant from {@link 1019: * SwingConstants}. It must be one of: <code>RIGHT</code>, 1020: * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or 1021: * <code>TRAILING</code>. The default is <code>TRAILING</code>. 1022: * 1023: * @param t The new horizontal text position 1024: * @throws IllegalArgumentException If position is not one of the legal 1025: * constants. 1026: */ 1027: public void setHorizontalTextPosition(int t) 1028: { 1029: if (horizontalTextPosition == t) 1030: return; 1031: 1032: int old = horizontalTextPosition; 1033: horizontalTextPosition = t; 1034: firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY, old, t); 1035: revalidate(); 1036: repaint(); 1037: } 1038: 1039: /** 1040: * Get the vertical alignment of the button's text and icon. The 1041: * alignment is a numeric constant from {@link SwingConstants}. It must 1042: * be one of: <code>CENTER</code>, <code>TOP</code>, or 1043: * <code>BOTTOM</code>. The default is <code>CENTER</code>. 1044: * 1045: * @return The current vertical alignment 1046: */ 1047: public int getVerticalAlignment() 1048: { 1049: return verticalAlignment; 1050: } 1051: 1052: /** 1053: * Set the vertical alignment of the button's text and icon. The 1054: * alignment is a numeric constant from {@link SwingConstants}. It must 1055: * be one of: <code>CENTER</code>, <code>TOP</code>, or 1056: * <code>BOTTOM</code>. The default is <code>CENTER</code>. 1057: * 1058: * @param a The new vertical alignment 1059: * @throws IllegalArgumentException If alignment is not one of the legal 1060: * constants. 1061: */ 1062: public void setVerticalAlignment(int a) 1063: { 1064: if (verticalAlignment == a) 1065: return; 1066: 1067: int old = verticalAlignment; 1068: verticalAlignment = a; 1069: firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, old, a); 1070: revalidate(); 1071: repaint(); 1072: } 1073: 1074: /** 1075: * Get the vertical position of the button's text relative to its 1076: * icon. The alignment is a numeric constant from {@link 1077: * SwingConstants}. It must be one of: <code>CENTER</code>, 1078: * <code>TOP</code>, or <code>BOTTOM</code>. The default is 1079: * <code>CENTER</code>. 1080: * 1081: * @return The current vertical position 1082: */ 1083: public int getVerticalTextPosition() 1084: { 1085: return verticalTextPosition; 1086: } 1087: 1088: /** 1089: * Set the vertical position of the button's text relative to its 1090: * icon. The alignment is a numeric constant from {@link 1091: * SwingConstants}. It must be one of: <code>CENTER</code>, 1092: * <code>TOP</code>, or <code>BOTTOM</code>. The default is 1093: * <code>CENTER</code>. 1094: * 1095: * @param t The new vertical position 1096: * @throws IllegalArgumentException If position is not one of the legal 1097: * constants. 1098: */ 1099: public void setVerticalTextPosition(int t) 1100: { 1101: if (verticalTextPosition == t) 1102: return; 1103: 1104: int old = verticalTextPosition; 1105: verticalTextPosition = t; 1106: firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, old, t); 1107: revalidate(); 1108: repaint(); 1109: } 1110: 1111: /** 1112: * Set the value of the "borderPainted" property. If set to 1113: * <code>false</code>, the button's look and feel class should not paint 1114: * a border for the button. The default is <code>true</code>. 1115: * 1116: * @return The current value of the property. 1117: */ 1118: public boolean isBorderPainted() 1119: { 1120: return borderPainted; 1121: } 1122: 1123: /** 1124: * Set the value of the "borderPainted" property. If set to 1125: * <code>false</code>, the button's look and feel class should not paint 1126: * a border for the button. The default is <code>true</code>. 1127: * 1128: * @param b The new value of the property. 1129: */ 1130: public void setBorderPainted(boolean b) 1131: { 1132: if (borderPainted == b) 1133: return; 1134: 1135: boolean old = borderPainted; 1136: borderPainted = b; 1137: firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, old, b); 1138: revalidate(); 1139: repaint(); 1140: } 1141: 1142: /** 1143: * Get the value of the "action" property. 1144: * 1145: * @return The current value of the "action" property 1146: */ 1147: public Action getAction() 1148: { 1149: return action; 1150: } 1151: 1152: /** 1153: * <p>Set the button's "action" property, subscribing the new action to the 1154: * button, as an ActionListener, if it is not already subscribed. The old 1155: * Action, if it exists, is unsubscribed, and the button is unsubscribed 1156: * from the old Action if it was previously subscribed as a 1157: * PropertyChangeListener.</p> 1158: * 1159: * <p>This method also configures several of the button's properties from 1160: * the Action, by calling {@link #configurePropertiesFromAction}, and 1161: * subscribes the button to the Action as a PropertyChangeListener. 1162: * Subsequent changes to the Action will thus reconfigure the button 1163: * automatically.</p> 1164: * 1165: * @param a The new value of the "action" property 1166: */ 1167: public void setAction(Action a) 1168: { 1169: if (action != null) 1170: { 1171: action.removePropertyChangeListener(actionPropertyChangeListener); 1172: removeActionListener(action); 1173: if (actionPropertyChangeListener != null) 1174: { 1175: action.removePropertyChangeListener(actionPropertyChangeListener); 1176: actionPropertyChangeListener = null; 1177: } 1178: } 1179: 1180: Action old = action; 1181: action = a; 1182: configurePropertiesFromAction(action); 1183: if (action != null) 1184: { 1185: actionPropertyChangeListener = createActionPropertyChangeListener(a); 1186: action.addPropertyChangeListener(actionPropertyChangeListener); 1187: addActionListener(action); 1188: } 1189: } 1190: 1191: /** 1192: * Return the button's default "icon" property. 1193: * 1194: * @return The current default icon 1195: */ 1196: public Icon getIcon() 1197: { 1198: return default_icon; 1199: } 1200: 1201: /** 1202: * Set the button's default "icon" property. This icon is used as a basis 1203: * for the pressed and disabled icons, if none are explicitly set. 1204: * 1205: * @param i The new default icon 1206: */ 1207: public void setIcon(Icon i) 1208: { 1209: if (default_icon == i) 1210: return; 1211: 1212: Icon old = default_icon; 1213: default_icon = i; 1214: firePropertyChange(ICON_CHANGED_PROPERTY, old, i); 1215: revalidate(); 1216: repaint(); 1217: } 1218: 1219: /** 1220: * Return the button's "text" property. This property is synonymous with 1221: * the "label" property. 1222: * 1223: * @return The current "text" property 1224: */ 1225: public String getText() 1226: { 1227: return text; 1228: } 1229: 1230: /** 1231: * Set the button's "label" property. This property is synonymous with the 1232: * "text" property. 1233: * 1234: * @param label The new "label" property 1235: * 1236: * @deprecated use <code>setText(text)</code> 1237: */ 1238: public void setLabel(String label) 1239: { 1240: setText(label); 1241: } 1242: 1243: /** 1244: * Return the button's "label" property. This property is synonymous with 1245: * the "text" property. 1246: * 1247: * @return The current "label" property 1248: * 1249: * @deprecated use <code>getText()</code> 1250: */ 1251: public String getLabel() 1252: { 1253: return getText(); 1254: } 1255: 1256: /** 1257: * Set the button's "text" property. This property is synonymous with the 1258: * "label" property. 1259: * 1260: * @param t The new "text" property 1261: */ 1262: public void setText(String t) 1263: { 1264: if (text == t) 1265: return; 1266: 1267: String old = text; 1268: text = t; 1269: firePropertyChange(TEXT_CHANGED_PROPERTY, old, t); 1270: revalidate(); 1271: repaint(); 1272: } 1273: 1274: /** 1275: * Set the value of the {@link #iconTextGap} property. 1276: * 1277: * @param i The new value of the property 1278: */ 1279: public void setIconTextGap(int i) 1280: { 1281: if (iconTextGap == i) 1282: return; 1283: 1284: int old = iconTextGap; 1285: iconTextGap = i; 1286: fireStateChanged(); 1287: revalidate(); 1288: repaint(); 1289: } 1290: 1291: /** 1292: * Get the value of the {@link #iconTextGap} property. 1293: * 1294: * @return The current value of the property 1295: */ 1296: public int getIconTextGap() 1297: { 1298: return iconTextGap; 1299: } 1300: 1301: /** 1302: * Return the button's "margin" property, which is an {@link Insets} object 1303: * describing the distance between the button's border and its text and 1304: * icon. 1305: * 1306: * @return The current "margin" property 1307: */ 1308: public Insets getMargin() 1309: { 1310: return margin; 1311: } 1312: 1313: /** 1314: * Set the button's "margin" property, which is an {@link Insets} object 1315: * describing the distance between the button's border and its text and 1316: * icon. 1317: * 1318: * @param m The new "margin" property 1319: */ 1320: public void setMargin(Insets m) 1321: { 1322: if (margin == m) 1323: return; 1324: 1325: Insets old = margin; 1326: margin = m; 1327: firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m); 1328: revalidate(); 1329: repaint(); 1330: } 1331: 1332: /** 1333: * Return the button's "pressedIcon" property. The look and feel class 1334: * should paint this icon when the "pressed" property of the button's 1335: * {@link ButtonModel} is <code>true</code>. This property may be 1336: * <code>null</code>, in which case the default icon is used. 1337: * 1338: * @return The current "pressedIcon" property 1339: */ 1340: public Icon getPressedIcon() 1341: { 1342: return pressed_icon; 1343: } 1344: 1345: /** 1346: * Set the button's "pressedIcon" property. The look and feel class 1347: * should paint this icon when the "pressed" property of the button's 1348: * {@link ButtonModel} is <code>true</code>. This property may be 1349: * <code>null</code>, in which case the default icon is used. 1350: * 1351: * @param pressedIcon The new "pressedIcon" property 1352: */ 1353: public void setPressedIcon(Icon pressedIcon) 1354: { 1355: if (pressed_icon == pressedIcon) 1356: return; 1357: 1358: Icon old = pressed_icon; 1359: pressed_icon = pressedIcon; 1360: firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, old, pressed_icon); 1361: revalidate(); 1362: repaint(); 1363: } 1364: 1365: /** 1366: * Return the button's "disabledIcon" property. The look and feel class 1367: * should paint this icon when the "enabled" property of the button's 1368: * {@link ButtonModel} is <code>false</code>. This property may be 1369: * <code>null</code>, in which case an icon is constructed, based on the 1370: * default icon. 1371: * 1372: * @return The current "disabledIcon" property 1373: */ 1374: public Icon getDisabledIcon() 1375: { 1376: if (disabeldIcon == null && default_icon instanceof ImageIcon) 1377: { 1378: Image iconImage = ((ImageIcon) default_icon).getImage(); 1379: Image grayImage = GrayFilter.createDisabledImage(iconImage); 1380: disabeldIcon = new ImageIcon(grayImage); 1381: } 1382: 1383: return disabeldIcon; 1384: } 1385: 1386: /** 1387: * Set the button's "disabledIcon" property. The look and feel class should 1388: * paint this icon when the "enabled" property of the button's {@link 1389: * ButtonModel} is <code>false</code>. This property may be 1390: * <code>null</code>, in which case an icon is constructed, based on the 1391: * default icon. 1392: * 1393: * @param d The new "disabledIcon" property 1394: */ 1395: public void setDisabledIcon(Icon d) 1396: { 1397: disabeldIcon = d; 1398: revalidate(); 1399: repaint(); 1400: } 1401: 1402: /** 1403: * Return the button's "paintFocus" property. This property controls 1404: * whether or not the look and feel class will paint a special indicator 1405: * of focus state for the button. If it is false, the button still paints 1406: * when focused, but no special decoration is painted to indicate the 1407: * presence of focus. 1408: * 1409: * @return The current "paintFocus" property 1410: */ 1411: public boolean isFocusPainted() 1412: { 1413: return focusPainted; 1414: } 1415: 1416: /** 1417: * Set the button's "paintFocus" property. This property controls whether 1418: * or not the look and feel class will paint a special indicator of focus 1419: * state for the button. If it is false, the button still paints when 1420: * focused, but no special decoration is painted to indicate the presence 1421: * of focus. 1422: * 1423: * @param p The new "paintFocus" property 1424: */ 1425: public void setFocusPainted(boolean p) 1426: { 1427: if (focusPainted == p) 1428: return; 1429: 1430: boolean old = focusPainted; 1431: focusPainted = p; 1432: firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, old, p); 1433: revalidate(); 1434: repaint(); 1435: } 1436: 1437: /** 1438: * Verifies that a particular key is one of the valid constants used for 1439: * describing horizontal alignment and positioning. The valid constants 1440: * are the following members of {@link SwingConstants}: 1441: * <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>, 1442: * <code>LEADING</code> or <code>TRAILING</code>. 1443: * 1444: * @param key The key to check 1445: * @param exception A message to include in an IllegalArgumentException 1446: * 1447: * @return the value of key 1448: * 1449: * @throws IllegalArgumentException If key is not one of the valid constants 1450: * 1451: * @see #setHorizontalTextPosition(int) 1452: * @see #setHorizontalAlignment(int) 1453: */ 1454: protected int checkHorizontalKey(int key, String exception) 1455: { 1456: switch (key) 1457: { 1458: case SwingConstants.RIGHT: 1459: case SwingConstants.LEFT: 1460: case SwingConstants.CENTER: 1461: case SwingConstants.LEADING: 1462: case SwingConstants.TRAILING: 1463: break; 1464: default: 1465: throw new IllegalArgumentException(exception); 1466: } 1467: return key; 1468: } 1469: 1470: /** 1471: * Verifies that a particular key is one of the valid constants used for 1472: * describing vertical alignment and positioning. The valid constants are 1473: * the following members of {@link SwingConstants}: <code>TOP</code>, 1474: * <code>BOTTOM</code> or <code>CENTER</code>. 1475: * 1476: * @param key The key to check 1477: * @param exception A message to include in an IllegalArgumentException 1478: * 1479: * @return the value of key 1480: * 1481: * @throws IllegalArgumentException If key is not one of the valid constants 1482: * 1483: * @see #setVerticalTextPosition(int) 1484: * @see #setVerticalAlignment(int) 1485: */ 1486: protected int checkVerticalKey(int key, String exception) 1487: { 1488: switch (key) 1489: { 1490: case SwingConstants.TOP: 1491: case SwingConstants.BOTTOM: 1492: case SwingConstants.CENTER: 1493: break; 1494: default: 1495: throw new IllegalArgumentException(exception); 1496: } 1497: return key; 1498: } 1499: 1500: /** 1501: * Configure various properties of the button by reading properties 1502: * of an {@link Action}. The mapping of properties is as follows: 1503: * 1504: * <table> 1505: * 1506: * <tr><th>Action keyed property</th> <th>AbstractButton property</th></tr> 1507: * 1508: * <tr><td>NAME </td> <td>text </td></tr> 1509: * <tr><td>SMALL_ICON </td> <td>icon </td></tr> 1510: * <tr><td>SHORT_DESCRIPTION </td> <td>toolTipText </td></tr> 1511: * <tr><td>MNEMONIC_KEY </td> <td>mnemonic </td></tr> 1512: * <tr><td>ACTION_COMMAND_KEY </td> <td>actionCommand </td></tr> 1513: * 1514: * </table> 1515: * 1516: * <p>In addition, this method always sets the button's "enabled" property to 1517: * the value of the Action's "enabled" property.</p> 1518: * 1519: * <p>If the provided Action is <code>null</code>, the text, icon, and 1520: * toolTipText properties of the button are set to <code>null</code>, and 1521: * the "enabled" property is set to <code>true</code>; the mnemonic and 1522: * actionCommand properties are unchanged.</p> 1523: * 1524: * @param a An Action to configure the button from 1525: */ 1526: protected void configurePropertiesFromAction(Action a) 1527: { 1528: if (a == null) 1529: { 1530: setText(null); 1531: setIcon(null); 1532: setEnabled(true); 1533: setToolTipText(null); 1534: } 1535: else 1536: { 1537: setText((String) (a.getValue(Action.NAME))); 1538: setIcon((Icon) (a.getValue(Action.SMALL_ICON))); 1539: setEnabled(a.isEnabled()); 1540: setToolTipText((String) (a.getValue(Action.SHORT_DESCRIPTION))); 1541: if (a.getValue(Action.MNEMONIC_KEY) != null) 1542: setMnemonic(((Integer) (a.getValue(Action.MNEMONIC_KEY))).intValue()); 1543: String actionCommand = (String) (a.getValue(Action.ACTION_COMMAND_KEY)); 1544: 1545: // Set actionCommand to button's text by default if it is not specified 1546: if (actionCommand != null) 1547: setActionCommand((String) (a.getValue(Action.ACTION_COMMAND_KEY))); 1548: else 1549: setActionCommand(getText()); 1550: } 1551: } 1552: 1553: /** 1554: * <p>A factory method which should return an {@link ActionListener} that 1555: * propagates events from the button's {@link ButtonModel} to any of the 1556: * button's ActionListeners. By default, this is an inner class which 1557: * calls {@link AbstractButton#fireActionPerformed} with a modified copy 1558: * of the incoming model {@link ActionEvent}.</p> 1559: * 1560: * <p>The button calls this method during construction, stores the 1561: * resulting ActionListener in its <code>actionListener</code> member 1562: * field, and subscribes it to the button's model. If the button's model 1563: * is changed, this listener is unsubscribed from the old model and 1564: * subscribed to the new one.</p> 1565: * 1566: * @return A new ActionListener 1567: */ 1568: protected ActionListener createActionListener() 1569: { 1570: return new ActionListener() 1571: { 1572: public void actionPerformed(ActionEvent e) 1573: { 1574: AbstractButton.this.fireActionPerformed(e); 1575: } 1576: }; 1577: } 1578: 1579: /** 1580: * <p>A factory method which should return a {@link PropertyChangeListener} 1581: * that accepts changes to the specified {@link Action} and reconfigure 1582: * the {@link AbstractButton}, by default using the {@link 1583: * #configurePropertiesFromAction} method.</p> 1584: * 1585: * <p>The button calls this method whenever a new Action is assigned to 1586: * the button's "action" property, via {@link #setAction}, and stores the 1587: * resulting PropertyChangeListener in its 1588: * <code>actionPropertyChangeListener</code> member field. The button 1589: * then subscribes the listener to the button's new action. If the 1590: * button's action is changed subsequently, the listener is unsubscribed 1591: * from the old action and subscribed to the new one.</p> 1592: * 1593: * @param a The Action which will be listened to, and which should be 1594: * the same as the source of any PropertyChangeEvents received by the 1595: * new listener returned from this method. 1596: * 1597: * @return A new PropertyChangeListener 1598: */ 1599: protected PropertyChangeListener createActionPropertyChangeListener(Action a) 1600: { 1601: return new PropertyChangeListener() 1602: { 1603: public void propertyChange(PropertyChangeEvent e) 1604: { 1605: Action act = (Action) (e.getSource()); 1606: if (e.getPropertyName().equals("enabled")) 1607: setEnabled(act.isEnabled()); 1608: else if (e.getPropertyName().equals(Action.NAME)) 1609: setText((String) (act.getValue(Action.NAME))); 1610: else if (e.getPropertyName().equals(Action.SMALL_ICON)) 1611: setIcon((Icon) (act.getValue(Action.SMALL_ICON))); 1612: else if (e.getPropertyName().equals(Action.SHORT_DESCRIPTION)) 1613: setToolTipText((String) (act.getValue(Action.SHORT_DESCRIPTION))); 1614: else if (e.getPropertyName().equals(Action.MNEMONIC_KEY)) 1615: if (act.getValue(Action.MNEMONIC_KEY) != null) 1616: setMnemonic(((Integer) (act.getValue(Action.MNEMONIC_KEY))) 1617: .intValue()); 1618: else if (e.getPropertyName().equals(Action.ACTION_COMMAND_KEY)) 1619: setActionCommand((String) (act.getValue(Action.ACTION_COMMAND_KEY))); 1620: } 1621: }; 1622: } 1623: 1624: /** 1625: * <p>Factory method which creates a {@link ChangeListener}, used to 1626: * subscribe to ChangeEvents from the button's model. Subclasses of 1627: * AbstractButton may wish to override the listener used to subscribe to 1628: * such ChangeEvents. By default, the listener just propagates the 1629: * {@link ChangeEvent} to the button's ChangeListeners, via the {@link 1630: * AbstractButton#fireStateChanged} method.</p> 1631: * 1632: * <p>The button calls this method during construction, stores the 1633: * resulting ChangeListener in its <code>changeListener</code> member 1634: * field, and subscribes it to the button's model. If the button's model 1635: * is changed, this listener is unsubscribed from the old model and 1636: * subscribed to the new one.</p> 1637: * 1638: * @return The new ChangeListener 1639: */ 1640: protected ChangeListener createChangeListener() 1641: { 1642: return new ButtonChangeListener(); 1643: } 1644: 1645: /** 1646: * <p>Factory method which creates a {@link ItemListener}, used to 1647: * subscribe to ItemEvents from the button's model. Subclasses of 1648: * AbstractButton may wish to override the listener used to subscribe to 1649: * such ItemEvents. By default, the listener just propagates the 1650: * {@link ItemEvent} to the button's ItemListeners, via the {@link 1651: * AbstractButton#fireItemStateChanged} method.</p> 1652: * 1653: * <p>The button calls this method during construction, stores the 1654: * resulting ItemListener in its <code>changeListener</code> member 1655: * field, and subscribes it to the button's model. If the button's model 1656: * is changed, this listener is unsubscribed from the old model and 1657: * subscribed to the new one.</p> 1658: * 1659: * <p>Note that ItemEvents are only generated from the button's model 1660: * when the model's <em>selected</em> property changes. If you want to 1661: * subscribe to other properties of the model, you must subscribe to 1662: * ChangeEvents. 1663: * 1664: * @return The new ItemListener 1665: */ 1666: protected ItemListener createItemListener() 1667: { 1668: return new ItemListener() 1669: { 1670: public void itemStateChanged(ItemEvent e) 1671: { 1672: AbstractButton.this.fireItemStateChanged(e); 1673: } 1674: }; 1675: } 1676: 1677: /** 1678: * Programmatically perform a "click" on the button: arming, pressing, 1679: * waiting, un-pressing, and disarming the model. 1680: */ 1681: public void doClick() 1682: { 1683: doClick(100); 1684: } 1685: 1686: /** 1687: * Programmatically perform a "click" on the button: arming, pressing, 1688: * waiting, un-pressing, and disarming the model. 1689: * 1690: * @param pressTime The number of milliseconds to wait in the pressed state 1691: */ 1692: public void doClick(int pressTime) 1693: { 1694: ButtonModel mod = getModel(); 1695: if (mod != null) 1696: { 1697: mod.setArmed(true); 1698: mod.setPressed(true); 1699: try 1700: { 1701: java.lang.Thread.sleep(pressTime); 1702: } 1703: catch (java.lang.InterruptedException e) 1704: { 1705: // probably harmless 1706: } 1707: mod.setPressed(false); 1708: mod.setArmed(false); 1709: } 1710: } 1711: 1712: /** 1713: * Return the button's disabled selected icon. The look and feel class 1714: * should paint this icon when the "enabled" property of the button's model 1715: * is <code>false</code> and its "selected" property is 1716: * <code>true</code>. This icon can be <code>null</code>, in which case 1717: * it is synthesized from the button's selected icon. 1718: * 1719: * @return The current disabled selected icon 1720: */ 1721: public Icon getDisabledSelectedIcon() 1722: { 1723: return disabledSelectedIcon; 1724: } 1725: 1726: /** 1727: * Set the button's disabled selected icon. The look and feel class 1728: * should paint this icon when the "enabled" property of the button's model 1729: * is <code>false</code> and its "selected" property is 1730: * <code>true</code>. This icon can be <code>null</code>, in which case 1731: * it is synthesized from the button's selected icon. 1732: * 1733: * @param icon The new disabled selected icon 1734: */ 1735: public void setDisabledSelectedIcon(Icon icon) 1736: { 1737: if (disabledSelectedIcon == icon) 1738: return; 1739: 1740: Icon old = disabledSelectedIcon; 1741: disabledSelectedIcon = icon; 1742: firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, old, icon); 1743: revalidate(); 1744: repaint(); 1745: } 1746: 1747: /** 1748: * Return the button's rollover icon. The look and feel class should 1749: * paint this icon when the "rolloverEnabled" property of the button is 1750: * <code>true</code> and the mouse rolls over the button. 1751: * 1752: * @return The current rollover icon 1753: */ 1754: public Icon getRolloverIcon() 1755: { 1756: return rolloverIcon; 1757: } 1758: 1759: /** 1760: * Set the button's rollover icon. The look and feel class should 1761: * paint this icon when the "rolloverEnabled" property of the button is 1762: * <code>true</code> and the mouse rolls over the button. 1763: * 1764: * @param r The new rollover icon 1765: */ 1766: public void setRolloverIcon(Icon r) 1767: { 1768: if (rolloverIcon == r) 1769: return; 1770: 1771: Icon old = rolloverIcon; 1772: rolloverIcon = r; 1773: firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, old, rolloverIcon); 1774: revalidate(); 1775: repaint(); 1776: } 1777: 1778: /** 1779: * Return the button's rollover selected icon. The look and feel class 1780: * should paint this icon when the "rolloverEnabled" property of the button 1781: * is <code>true</code>, the "selected" property of the button's model is 1782: * <code>true</code>, and the mouse rolls over the button. 1783: * 1784: * @return The current rollover selected icon 1785: */ 1786: public Icon getRolloverSelectedIcon() 1787: { 1788: return rolloverSelectedIcon; 1789: } 1790: 1791: /** 1792: * Set the button's rollover selected icon. The look and feel class 1793: * should paint this icon when the "rolloverEnabled" property of the button 1794: * is <code>true</code>, the "selected" property of the button's model is 1795: * <code>true</code>, and the mouse rolls over the button. 1796: * 1797: * @param r The new rollover selected icon 1798: */ 1799: public void setRolloverSelectedIcon(Icon r) 1800: { 1801: if (rolloverSelectedIcon == r) 1802: return; 1803: 1804: Icon old = rolloverSelectedIcon; 1805: rolloverSelectedIcon = r; 1806: firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, old, r); 1807: revalidate(); 1808: repaint(); 1809: } 1810: 1811: /** 1812: * Return the button's selected icon. The look and feel class should 1813: * paint this icon when the "selected" property of the button's model is 1814: * <code>true</code>, and either the "rolloverEnabled" property of the 1815: * button is <code>false</code> or the mouse is not currently rolled 1816: * over the button. 1817: * 1818: * @return The current selected icon 1819: */ 1820: public Icon getSelectedIcon() 1821: { 1822: return selectedIcon; 1823: } 1824: 1825: /** 1826: * Set the button's selected icon. The look and feel class should 1827: * paint this icon when the "selected" property of the button's model is 1828: * <code>true</code>, and either the "rolloverEnabled" property of the 1829: * button is <code>false</code> or the mouse is not currently rolled 1830: * over the button. 1831: * 1832: * @param s The new selected icon 1833: */ 1834: public void setSelectedIcon(Icon s) 1835: { 1836: if (selectedIcon == s) 1837: return; 1838: 1839: Icon old = selectedIcon; 1840: selectedIcon = s; 1841: firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, old, s); 1842: revalidate(); 1843: repaint(); 1844: } 1845: 1846: /** 1847: * Returns an single-element array containing the "text" property of the 1848: * button if the "selected" property of the button's model is 1849: * <code>true</code>, otherwise returns <code>null</code>. 1850: * 1851: * @return The button's "selected object" array 1852: */ 1853: public Object[] getSelectedObjects() 1854: { 1855: if (isSelected()) 1856: { 1857: Object[] objs = new Object[1]; 1858: objs[0] = getText(); 1859: return objs; 1860: } 1861: else 1862: { 1863: return null; 1864: } 1865: } 1866: 1867: /** 1868: * Called when image data becomes available for one of the button's icons. 1869: * 1870: * @param img The image being updated 1871: * @param infoflags One of the constant codes in {@link ImageObserver} used 1872: * to describe updated portions of an image. 1873: * @param x X coordinate of the region being updated 1874: * @param y Y coordinate of the region being updated 1875: * @param w Width of the region beign updated 1876: * @param h Height of the region being updated 1877: * 1878: * @return <code>true</code> if img is equal to the button's current icon, 1879: * otherwise <code>false</code> 1880: */ 1881: public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, 1882: int h) 1883: { 1884: return current_icon == img; 1885: } 1886: 1887: /** 1888: * Returns the value of the button's "contentAreaFilled" property. This 1889: * property indicates whether the area surrounding the text and icon of 1890: * the button should be filled by the look and feel class. If this 1891: * property is <code>false</code>, the look and feel class should leave 1892: * the content area transparent. 1893: * 1894: * @return The current value of the "contentAreaFilled" property 1895: */ 1896: public boolean isContentAreaFilled() 1897: { 1898: return contentAreaFilled; 1899: } 1900: 1901: /** 1902: * Sets the value of the button's "contentAreaFilled" property. This 1903: * property indicates whether the area surrounding the text and icon of 1904: * the button should be filled by the look and feel class. If this 1905: * property is <code>false</code>, the look and feel class should leave 1906: * the content area transparent. 1907: * 1908: * @param b The new value of the "contentAreaFilled" property 1909: */ 1910: public void setContentAreaFilled(boolean b) 1911: { 1912: if (contentAreaFilled == b) 1913: return; 1914: 1915: boolean old = contentAreaFilled; 1916: contentAreaFilled = b; 1917: firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, old, b); 1918: // The JDK sets the opaque property to the value of the contentAreaFilled 1919: // property, so should we do. 1920: setOpaque(b); 1921: } 1922: 1923: /** 1924: * Paints the button's border, if the button's "borderPainted" property is 1925: * <code>true</code>, by out calling to the button's look and feel class. 1926: * 1927: * @param g The graphics context used to paint the border 1928: */ 1929: protected void paintBorder(Graphics g) 1930: { 1931: if (isBorderPainted()) 1932: super.paintBorder(g); 1933: } 1934: 1935: /** 1936: * Returns a string, used only for debugging, which identifies or somehow 1937: * represents this button. The exact value is implementation-defined. 1938: * 1939: * @return A string representation of the button 1940: */ 1941: protected String paramString() 1942: { 1943: StringBuffer sb = new StringBuffer(); 1944: sb.append(super.paramString()); 1945: sb.append(",defaultIcon="); 1946: if (getIcon() != null) 1947: sb.append(getIcon()); 1948: sb.append(",disabledIcon="); 1949: if (getDisabledIcon() != null) 1950: sb.append(getDisabledIcon()); 1951: sb.append(",disabledSelectedIcon="); 1952: if (getDisabledSelectedIcon() != null) 1953: sb.append(getDisabledSelectedIcon()); 1954: sb.append(",margin="); 1955: if (getMargin() != null) 1956: sb.append(getMargin()); 1957: sb.append(",paintBorder=").append(isBorderPainted()); 1958: sb.append(",paintFocus=").append(isFocusPainted()); 1959: sb.append(",pressedIcon="); 1960: if (getPressedIcon() != null) 1961: sb.append(getPressedIcon()); 1962: sb.append(",rolloverEnabled=").append(isRolloverEnabled()); 1963: sb.append(",rolloverIcon="); 1964: if (getRolloverIcon() != null) 1965: sb.append(getRolloverIcon()); 1966: sb.append(",rolloverSelected="); 1967: if (getRolloverSelectedIcon() != null) 1968: sb.append(getRolloverSelectedIcon()); 1969: sb.append(",selectedIcon="); 1970: if (getSelectedIcon() != null) 1971: sb.append(getSelectedIcon()); 1972: sb.append(",text="); 1973: if (getText() != null) 1974: sb.append(getText()); 1975: return sb.toString(); 1976: } 1977: 1978: /** 1979: * Set the "UI" property of the button, which is a look and feel class 1980: * responsible for handling the button's input events and painting it. 1981: * 1982: * @param ui The new "UI" property 1983: */ 1984: public void setUI(ButtonUI ui) 1985: { 1986: super.setUI(ui); 1987: } 1988: 1989: /** 1990: * Set the "UI" property of the button, which is a look and feel class 1991: * responsible for handling the button's input events and painting it. 1992: * 1993: * @return The current "UI" property 1994: */ 1995: public ButtonUI getUI() 1996: { 1997: return (ButtonUI) ui; 1998: } 1999: 2000: /** 2001: * Set the "UI" property to a class constructed, via the {@link 2002: * UIManager}, from the current look and feel. This should be overridden 2003: * for each subclass of AbstractButton, to retrieve a suitable {@link 2004: * ButtonUI} look and feel class. 2005: */ 2006: public void updateUI() 2007: { 2008: // TODO: What to do here? 2009: } 2010: 2011: /** 2012: * Returns the current time in milliseconds in which clicks gets coalesced 2013: * into a single <code>ActionEvent</code>. 2014: * 2015: * @return the time in milliseconds 2016: * 2017: * @since 1.4 2018: */ 2019: public long getMultiClickThreshhold() 2020: { 2021: return multiClickThreshhold; 2022: } 2023: 2024: /** 2025: * Sets the time in milliseconds in which clicks gets coalesced into a single 2026: * <code>ActionEvent</code>. 2027: * 2028: * @param threshhold the time in milliseconds 2029: * 2030: * @since 1.4 2031: */ 2032: public void setMultiClickThreshhold(long threshhold) 2033: { 2034: if (threshhold < 0) 2035: throw new IllegalArgumentException(); 2036: 2037: multiClickThreshhold = threshhold; 2038: } 2039: }
GNU Classpath (0.20) |