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