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