Save This Page
Home » openjdk-7 » javax » swing » [javadoc | source]
    1   /*
    2    * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   package javax.swing;
   26   
   27   import java.awt;
   28   import java.awt.event;
   29   import java.awt.image;
   30   import java.text;
   31   import java.awt.geom;
   32   import java.beans.PropertyChangeEvent;
   33   import java.beans.PropertyChangeListener;
   34   import java.beans.Transient;
   35   import java.util.Enumeration;
   36   import java.util.Vector;
   37   import java.io.Serializable;
   38   import javax.swing.event;
   39   import javax.swing.border;
   40   import javax.swing.plaf;
   41   import javax.accessibility;
   42   import javax.swing.text;
   43   import javax.swing.text.html;
   44   import javax.swing.plaf.basic;
   45   import java.util;
   46   
   47   /**
   48    * Defines common behaviors for buttons and menu items.
   49    * <p>
   50    * Buttons can be configured, and to some degree controlled, by
   51    * <code><a href="Action.html">Action</a></code>s.  Using an
   52    * <code>Action</code> with a button has many benefits beyond directly
   53    * configuring a button.  Refer to <a href="Action.html#buttonActions">
   54    * Swing Components Supporting <code>Action</code></a> for more
   55    * details, and you can find more information in <a
   56    * href="http://java.sun.com/docs/books/tutorial/uiswing/misc/action.html">How
   57    * to Use Actions</a>, a section in <em>The Java Tutorial</em>.
   58    * <p>
   59    * For further information see
   60    * <a
   61    href="http://java.sun.com/docs/books/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons</a>,
   62    * a section in <em>The Java Tutorial</em>.
   63    * <p>
   64    * <strong>Warning:</strong>
   65    * Serialized objects of this class will not be compatible with
   66    * future Swing releases. The current serialization support is
   67    * appropriate for short term storage or RMI between applications running
   68    * the same version of Swing.  As of 1.4, support for long term storage
   69    * of all JavaBeans<sup><font size="-2">TM</font></sup>
   70    * has been added to the <code>java.beans</code> package.
   71    * Please see {@link java.beans.XMLEncoder}.
   72    *
   73    * @author Jeff Dinkins
   74    */
   75   public abstract class AbstractButton extends JComponent implements ItemSelectable, SwingConstants {
   76   
   77       // *********************************
   78       // ******* Button properties *******
   79       // *********************************
   80   
   81       /** Identifies a change in the button model. */
   82       public static final String MODEL_CHANGED_PROPERTY = "model";
   83       /** Identifies a change in the button's text. */
   84       public static final String TEXT_CHANGED_PROPERTY = "text";
   85       /** Identifies a change to the button's mnemonic. */
   86       public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic";
   87   
   88       // Text positioning and alignment
   89       /** Identifies a change in the button's margins. */
   90       public static final String MARGIN_CHANGED_PROPERTY = "margin";
   91       /** Identifies a change in the button's vertical alignment. */
   92       public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";
   93       /** Identifies a change in the button's horizontal alignment. */
   94       public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = "horizontalAlignment";
   95   
   96       /** Identifies a change in the button's vertical text position. */
   97       public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = "verticalTextPosition";
   98       /** Identifies a change in the button's horizontal text position. */
   99       public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = "horizontalTextPosition";
  100   
  101       // Paint options
  102       /**
  103        * Identifies a change to having the border drawn,
  104        * or having it not drawn.
  105        */
  106       public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";
  107       /**
  108        * Identifies a change to having the border highlighted when focused,
  109        * or not.
  110        */
  111       public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
  112       /**
  113        * Identifies a change from rollover enabled to disabled or back
  114        * to enabled.
  115        */
  116       public static final String ROLLOVER_ENABLED_CHANGED_PROPERTY = "rolloverEnabled";
  117       /**
  118        * Identifies a change to having the button paint the content area.
  119        */
  120       public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled";
  121   
  122       // Icons
  123       /** Identifies a change to the icon that represents the button. */
  124       public static final String ICON_CHANGED_PROPERTY = "icon";
  125   
  126       /**
  127        * Identifies a change to the icon used when the button has been
  128        * pressed.
  129        */
  130       public static final String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";
  131       /**
  132        * Identifies a change to the icon used when the button has
  133        * been selected.
  134        */
  135       public static final String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";
  136   
  137       /**
  138        * Identifies a change to the icon used when the cursor is over
  139        * the button.
  140        */
  141       public static final String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";
  142       /**
  143        * Identifies a change to the icon used when the cursor is
  144        * over the button and it has been selected.
  145        */
  146       public static final String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = "rolloverSelectedIcon";
  147   
  148       /**
  149        * Identifies a change to the icon used when the button has
  150        * been disabled.
  151        */
  152       public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";
  153       /**
  154        * Identifies a change to the icon used when the button has been
  155        * disabled and selected.
  156        */
  157       public static final String DISABLED_SELECTED_ICON_CHANGED_PROPERTY = "disabledSelectedIcon";
  158   
  159   
  160       /** The data model that determines the button's state. */
  161       protected ButtonModel model                = null;
  162   
  163       private String     text                    = ""; // for BeanBox
  164       private Insets     margin                  = null;
  165       private Insets     defaultMargin           = null;
  166   
  167       // Button icons
  168       // PENDING(jeff) - hold icons in an array
  169       private Icon       defaultIcon             = null;
  170       private Icon       pressedIcon             = null;
  171       private Icon       disabledIcon            = null;
  172   
  173       private Icon       selectedIcon            = null;
  174       private Icon       disabledSelectedIcon    = null;
  175   
  176       private Icon       rolloverIcon            = null;
  177       private Icon       rolloverSelectedIcon    = null;
  178   
  179       // Display properties
  180       private boolean    paintBorder             = true;
  181       private boolean    paintFocus              = true;
  182       private boolean    rolloverEnabled         = false;
  183       private boolean    contentAreaFilled         = true;
  184   
  185       // Icon/Label Alignment
  186       private int        verticalAlignment       = CENTER;
  187       private int        horizontalAlignment     = CENTER;
  188   
  189       private int        verticalTextPosition    = CENTER;
  190       private int        horizontalTextPosition  = TRAILING;
  191   
  192       private int        iconTextGap             = 4;
  193   
  194       private int        mnemonic;
  195       private int        mnemonicIndex           = -1;
  196   
  197       private long       multiClickThreshhold    = 0;
  198   
  199       private boolean    borderPaintedSet        = false;
  200       private boolean    rolloverEnabledSet      = false;
  201       private boolean    iconTextGapSet          = false;
  202       private boolean    contentAreaFilledSet    = false;
  203   
  204       // Whether or not we've set the LayoutManager.
  205       private boolean setLayout = false;
  206   
  207       // This is only used by JButton, promoted to avoid an extra
  208       // boolean field in JButton
  209       boolean defaultCapable = true;
  210   
  211       /**
  212        * Combined listeners: ActionListener, ChangeListener, ItemListener.
  213        */
  214       private Handler handler;
  215   
  216       /**
  217        * The button model's <code>changeListener</code>.
  218        */
  219       protected ChangeListener changeListener = null;
  220       /**
  221        * The button model's <code>ActionListener</code>.
  222        */
  223       protected ActionListener actionListener = null;
  224       /**
  225        * The button model's <code>ItemListener</code>.
  226        */
  227       protected ItemListener itemListener = null;
  228   
  229       /**
  230        * Only one <code>ChangeEvent</code> is needed per button
  231        * instance since the
  232        * event's only state is the source property.  The source of events
  233        * generated is always "this".
  234        */
  235       protected transient ChangeEvent changeEvent;
  236   
  237       private boolean hideActionText = false;
  238   
  239       /**
  240        * Sets the <code>hideActionText</code> property, which determines
  241        * whether the button displays text from the <code>Action</code>.
  242        * This is useful only if an <code>Action</code> has been
  243        * installed on the button.
  244        *
  245        * @param hideActionText <code>true</code> if the button's
  246        *                       <code>text</code> property should not reflect
  247        *                       that of the <code>Action</code>; the default is
  248        *                       <code>false</code>
  249        * @see <a href="Action.html#buttonActions">Swing Components Supporting
  250        *      <code>Action</code></a>
  251        * @since 1.6
  252        * @beaninfo
  253        *        bound: true
  254        *    expert: true
  255        *  description: Whether the text of the button should come from
  256        *               the <code>Action</code>.
  257        */
  258       public void setHideActionText(boolean hideActionText) {
  259           if (hideActionText != this.hideActionText) {
  260               this.hideActionText = hideActionText;
  261               if (getAction() != null) {
  262                   setTextFromAction(getAction(), false);
  263               }
  264               firePropertyChange("hideActionText", !hideActionText,
  265                                  hideActionText);
  266           }
  267       }
  268   
  269       /**
  270        * Returns the value of the <code>hideActionText</code> property, which
  271        * determines whether the button displays text from the
  272        * <code>Action</code>.  This is useful only if an <code>Action</code>
  273        * has been installed on the button.
  274        *
  275        * @return <code>true</code> if the button's <code>text</code>
  276        *         property should not reflect that of the
  277        *         <code>Action</code>; the default is <code>false</code>
  278        * @since 1.6
  279        */
  280       public boolean getHideActionText() {
  281           return hideActionText;
  282       }
  283   
  284       /**
  285        * Returns the button's text.
  286        * @return the buttons text
  287        * @see #setText
  288        */
  289       public String getText() {
  290           return text;
  291       }
  292   
  293       /**
  294        * Sets the button's text.
  295        * @param text the string used to set the text
  296        * @see #getText
  297        * @beaninfo
  298        *        bound: true
  299        *    preferred: true
  300        *    attribute: visualUpdate true
  301        *  description: The button's text.
  302        */
  303       public void setText(String text) {
  304           String oldValue = this.text;
  305           this.text = text;
  306           firePropertyChange(TEXT_CHANGED_PROPERTY, oldValue, text);
  307           updateDisplayedMnemonicIndex(text, getMnemonic());
  308   
  309           if (accessibleContext != null) {
  310               accessibleContext.firePropertyChange(
  311                   AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  312                   oldValue, text);
  313           }
  314           if (text == null || oldValue == null || !text.equals(oldValue)) {
  315               revalidate();
  316               repaint();
  317           }
  318       }
  319   
  320   
  321       /**
  322        * Returns the state of the button. True if the
  323        * toggle button is selected, false if it's not.
  324        * @return true if the toggle button is selected, otherwise false
  325        */
  326       public boolean isSelected() {
  327           return model.isSelected();
  328       }
  329   
  330       /**
  331        * Sets the state of the button. Note that this method does not
  332        * trigger an <code>actionEvent</code>.
  333        * Call <code>doClick</code> to perform a programatic action change.
  334        *
  335        * @param b  true if the button is selected, otherwise false
  336        */
  337       public void setSelected(boolean b) {
  338           boolean oldValue = isSelected();
  339   
  340           // TIGER - 4840653
  341           // Removed code which fired an AccessibleState.SELECTED
  342           // PropertyChangeEvent since this resulted in two
  343           // identical events being fired since
  344           // AbstractButton.fireItemStateChanged also fires the
  345           // same event. This caused screen readers to speak the
  346           // name of the item twice.
  347   
  348           model.setSelected(b);
  349       }
  350   
  351       /**
  352        * Programmatically perform a "click". This does the same
  353        * thing as if the user had pressed and released the button.
  354        */
  355       public void doClick() {
  356           doClick(68);
  357       }
  358   
  359       /**
  360        * Programmatically perform a "click". This does the same
  361        * thing as if the user had pressed and released the button.
  362        * The button stays visually "pressed" for <code>pressTime</code>
  363        *  milliseconds.
  364        *
  365        * @param pressTime the time to "hold down" the button, in milliseconds
  366        */
  367       public void doClick(int pressTime) {
  368           Dimension size = getSize();
  369           model.setArmed(true);
  370           model.setPressed(true);
  371           paintImmediately(new Rectangle(0,0, size.width, size.height));
  372           try {
  373               Thread.currentThread().sleep(pressTime);
  374           } catch(InterruptedException ie) {
  375           }
  376           model.setPressed(false);
  377           model.setArmed(false);
  378       }
  379   
  380       /**
  381        * Sets space for margin between the button's border and
  382        * the label. Setting to <code>null</code> will cause the button to
  383        * use the default margin.  The button's default <code>Border</code>
  384        * object will use this value to create the proper margin.
  385        * However, if a non-default border is set on the button,
  386        * it is that <code>Border</code> object's responsibility to create the
  387        * appropriate margin space (else this property will
  388        * effectively be ignored).
  389        *
  390        * @param m the space between the border and the label
  391        *
  392        * @beaninfo
  393        *        bound: true
  394        *    attribute: visualUpdate true
  395        *  description: The space between the button's border and the label.
  396        */
  397       public void setMargin(Insets m) {
  398           // Cache the old margin if it comes from the UI
  399           if(m instanceof UIResource) {
  400               defaultMargin = m;
  401           } else if(margin instanceof UIResource) {
  402               defaultMargin = margin;
  403           }
  404   
  405           // If the client passes in a null insets, restore the margin
  406           // from the UI if possible
  407           if(m == null && defaultMargin != null) {
  408               m = defaultMargin;
  409           }
  410   
  411           Insets old = margin;
  412           margin = m;
  413           firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);
  414           if (old == null || !old.equals(m)) {
  415               revalidate();
  416               repaint();
  417           }
  418       }
  419   
  420       /**
  421        * Returns the margin between the button's border and
  422        * the label.
  423        *
  424        * @return an <code>Insets</code> object specifying the margin
  425        *          between the botton's border and the label
  426        * @see #setMargin
  427        */
  428       public Insets getMargin() {
  429           return (margin == null) ? null : (Insets) margin.clone();
  430       }
  431   
  432       /**
  433        * Returns the default icon.
  434        * @return the default <code>Icon</code>
  435        * @see #setIcon
  436        */
  437       public Icon getIcon() {
  438           return defaultIcon;
  439       }
  440   
  441       /**
  442        * Sets the button's default icon. This icon is
  443        * also used as the "pressed" and "disabled" icon if
  444        * there is no explicitly set pressed icon.
  445        *
  446        * @param defaultIcon the icon used as the default image
  447        * @see #getIcon
  448        * @see #setPressedIcon
  449        * @beaninfo
  450        *           bound: true
  451        *       attribute: visualUpdate true
  452        *     description: The button's default icon
  453        */
  454       public void setIcon(Icon defaultIcon) {
  455           Icon oldValue = this.defaultIcon;
  456           this.defaultIcon = defaultIcon;
  457   
  458           /* If the default icon has really changed and we had
  459            * generated the disabled icon for this component,
  460            * (i.e. setDisabledIcon() was never called) then
  461            * clear the disabledIcon field.
  462            */
  463           if (defaultIcon != oldValue && (disabledIcon instanceof UIResource)) {
  464               disabledIcon = null;
  465           }
  466   
  467           firePropertyChange(ICON_CHANGED_PROPERTY, oldValue, defaultIcon);
  468           if (accessibleContext != null) {
  469               accessibleContext.firePropertyChange(
  470                   AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  471                   oldValue, defaultIcon);
  472           }
  473           if (defaultIcon != oldValue) {
  474               if (defaultIcon == null || oldValue == null ||
  475                   defaultIcon.getIconWidth() != oldValue.getIconWidth() ||
  476                   defaultIcon.getIconHeight() != oldValue.getIconHeight()) {
  477                   revalidate();
  478               }
  479               repaint();
  480           }
  481       }
  482   
  483       /**
  484        * Returns the pressed icon for the button.
  485        * @return the <code>pressedIcon</code> property
  486        * @see #setPressedIcon
  487        */
  488       public Icon getPressedIcon() {
  489           return pressedIcon;
  490       }
  491   
  492       /**
  493        * Sets the pressed icon for the button.
  494        * @param pressedIcon the icon used as the "pressed" image
  495        * @see #getPressedIcon
  496        * @beaninfo
  497        *        bound: true
  498        *    attribute: visualUpdate true
  499        *  description: The pressed icon for the button.
  500        */
  501       public void setPressedIcon(Icon pressedIcon) {
  502           Icon oldValue = this.pressedIcon;
  503           this.pressedIcon = pressedIcon;
  504           firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, oldValue, pressedIcon);
  505           if (accessibleContext != null) {
  506               accessibleContext.firePropertyChange(
  507                   AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  508                   oldValue, pressedIcon);
  509           }
  510           if (pressedIcon != oldValue) {
  511               if (getModel().isPressed()) {
  512                   repaint();
  513               }
  514           }
  515       }
  516   
  517       /**
  518        * Returns the selected icon for the button.
  519        * @return the <code>selectedIcon</code> property
  520        * @see #setSelectedIcon
  521        */
  522       public Icon getSelectedIcon() {
  523           return selectedIcon;
  524       }
  525   
  526       /**
  527        * Sets the selected icon for the button.
  528        * @param selectedIcon the icon used as the "selected" image
  529        * @see #getSelectedIcon
  530        * @beaninfo
  531        *        bound: true
  532        *    attribute: visualUpdate true
  533        *  description: The selected icon for the button.
  534        */
  535       public void setSelectedIcon(Icon selectedIcon) {
  536           Icon oldValue = this.selectedIcon;
  537           this.selectedIcon = selectedIcon;
  538   
  539           /* If the default selected icon has really changed and we had
  540            * generated the disabled selected icon for this component,
  541            * (i.e. setDisabledSelectedIcon() was never called) then
  542            * clear the disabledSelectedIcon field.
  543            */
  544           if (selectedIcon != oldValue &&
  545               disabledSelectedIcon instanceof UIResource) {
  546   
  547               disabledSelectedIcon = null;
  548           }
  549   
  550           firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, oldValue, selectedIcon);
  551           if (accessibleContext != null) {
  552               accessibleContext.firePropertyChange(
  553                   AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  554                   oldValue, selectedIcon);
  555           }
  556           if (selectedIcon != oldValue) {
  557               if (isSelected()) {
  558                   repaint();
  559               }
  560           }
  561       }
  562   
  563       /**
  564        * Returns the rollover icon for the button.
  565        * @return the <code>rolloverIcon</code> property
  566        * @see #setRolloverIcon
  567        */
  568       public Icon getRolloverIcon() {
  569           return rolloverIcon;
  570       }
  571   
  572       /**
  573        * Sets the rollover icon for the button.
  574        * @param rolloverIcon the icon used as the "rollover" image
  575        * @see #getRolloverIcon
  576        * @beaninfo
  577        *        bound: true
  578        *    attribute: visualUpdate true
  579        *  description: The rollover icon for the button.
  580        */
  581       public void setRolloverIcon(Icon rolloverIcon) {
  582           Icon oldValue = this.rolloverIcon;
  583           this.rolloverIcon = rolloverIcon;
  584           firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, oldValue, rolloverIcon);
  585           if (accessibleContext != null) {
  586               accessibleContext.firePropertyChange(
  587                   AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  588                   oldValue, rolloverIcon);
  589           }
  590           setRolloverEnabled(true);
  591           if (rolloverIcon != oldValue) {
  592               // No way to determine whether we are currently in
  593               // a rollover state, so repaint regardless
  594               repaint();
  595           }
  596   
  597       }
  598   
  599       /**
  600        * Returns the rollover selection icon for the button.
  601        * @return the <code>rolloverSelectedIcon</code> property
  602        * @see #setRolloverSelectedIcon
  603        */
  604       public Icon getRolloverSelectedIcon() {
  605           return rolloverSelectedIcon;
  606       }
  607   
  608       /**
  609        * Sets the rollover selected icon for the button.
  610        * @param rolloverSelectedIcon the icon used as the
  611        *          "selected rollover" image
  612        * @see #getRolloverSelectedIcon
  613        * @beaninfo
  614        *        bound: true
  615        *    attribute: visualUpdate true
  616        *  description: The rollover selected icon for the button.
  617        */
  618       public void setRolloverSelectedIcon(Icon rolloverSelectedIcon) {
  619           Icon oldValue = this.rolloverSelectedIcon;
  620           this.rolloverSelectedIcon = rolloverSelectedIcon;
  621           firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, oldValue, rolloverSelectedIcon);
  622           if (accessibleContext != null) {
  623               accessibleContext.firePropertyChange(
  624                   AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  625                   oldValue, rolloverSelectedIcon);
  626           }
  627           setRolloverEnabled(true);
  628           if (rolloverSelectedIcon != oldValue) {
  629               // No way to determine whether we are currently in
  630               // a rollover state, so repaint regardless
  631               if (isSelected()) {
  632                   repaint();
  633               }
  634           }
  635       }
  636   
  637       /**
  638        * Returns the icon used by the button when it's disabled.
  639        * If no disabled icon has been set this will forward the call to
  640        * the look and feel to construct an appropriate disabled Icon.
  641        * <p>
  642        * Some look and feels might not render the disabled Icon, in which
  643        * case they will ignore this.
  644        *
  645        * @return the <code>disabledIcon</code> property
  646        * @see #getPressedIcon
  647        * @see #setDisabledIcon
  648        * @see javax.swing.LookAndFeel#getDisabledIcon
  649        */
  650       @Transient
  651       public Icon getDisabledIcon() {
  652           if (disabledIcon == null) {
  653               disabledIcon = UIManager.getLookAndFeel().getDisabledIcon(this, getIcon());
  654               if (disabledIcon != null) {
  655                   firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, null, disabledIcon);
  656               }
  657           }
  658           return disabledIcon;
  659       }
  660   
  661       /**
  662        * Sets the disabled icon for the button.
  663        * @param disabledIcon the icon used as the disabled image
  664        * @see #getDisabledIcon
  665        * @beaninfo
  666        *        bound: true
  667        *    attribute: visualUpdate true
  668        *  description: The disabled icon for the button.
  669        */
  670       public void setDisabledIcon(Icon disabledIcon) {
  671           Icon oldValue = this.disabledIcon;
  672           this.disabledIcon = disabledIcon;
  673           firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, oldValue, disabledIcon);
  674           if (accessibleContext != null) {
  675               accessibleContext.firePropertyChange(
  676                   AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  677                   oldValue, disabledIcon);
  678           }
  679           if (disabledIcon != oldValue) {
  680               if (!isEnabled()) {
  681                   repaint();
  682               }
  683           }
  684       }
  685   
  686       /**
  687        * Returns the icon used by the button when it's disabled and selected.
  688        * If no disabled selection icon has been set, this will forward
  689        * the call to the LookAndFeel to construct an appropriate disabled
  690        * Icon from the selection icon if it has been set and to
  691        * <code>getDisabledIcon()</code> otherwise.
  692        * <p>
  693        * Some look and feels might not render the disabled selected Icon, in
  694        * which case they will ignore this.
  695        *
  696        * @return the <code>disabledSelectedIcon</code> property
  697        * @see #getDisabledIcon
  698        * @see #setDisabledSelectedIcon
  699        * @see javax.swing.LookAndFeel#getDisabledSelectedIcon
  700        */
  701       public Icon getDisabledSelectedIcon() {
  702           if (disabledSelectedIcon == null) {
  703                if (selectedIcon != null) {
  704                    disabledSelectedIcon = UIManager.getLookAndFeel().
  705                            getDisabledSelectedIcon(this, getSelectedIcon());
  706                } else {
  707                    return getDisabledIcon();
  708                }
  709           }
  710           return disabledSelectedIcon;
  711       }
  712   
  713       /**
  714        * Sets the disabled selection icon for the button.
  715        * @param disabledSelectedIcon the icon used as the disabled
  716        *          selection image
  717        * @see #getDisabledSelectedIcon
  718        * @beaninfo
  719        *        bound: true
  720        *    attribute: visualUpdate true
  721        *  description: The disabled selection icon for the button.
  722        */
  723       public void setDisabledSelectedIcon(Icon disabledSelectedIcon) {
  724           Icon oldValue = this.disabledSelectedIcon;
  725           this.disabledSelectedIcon = disabledSelectedIcon;
  726           firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, oldValue, disabledSelectedIcon);
  727           if (accessibleContext != null) {
  728               accessibleContext.firePropertyChange(
  729                   AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  730                   oldValue, disabledSelectedIcon);
  731           }
  732           if (disabledSelectedIcon != oldValue) {
  733               if (disabledSelectedIcon == null || oldValue == null ||
  734                   disabledSelectedIcon.getIconWidth() != oldValue.getIconWidth() ||
  735                   disabledSelectedIcon.getIconHeight() != oldValue.getIconHeight()) {
  736                   revalidate();
  737               }
  738               if (!isEnabled() && isSelected()) {
  739                   repaint();
  740               }
  741           }
  742       }
  743   
  744       /**
  745        * Returns the vertical alignment of the text and icon.
  746        *
  747        * @return the <code>verticalAlignment</code> property, one of the
  748        *          following values:
  749        * <ul>
  750        * <li>{@code SwingConstants.CENTER} (the default)
  751        * <li>{@code SwingConstants.TOP}
  752        * <li>{@code SwingConstants.BOTTOM}
  753        * </ul>
  754        */
  755       public int getVerticalAlignment() {
  756           return verticalAlignment;
  757       }
  758   
  759       /**
  760        * Sets the vertical alignment of the icon and text.
  761        * @param alignment one of the following values:
  762        * <ul>
  763        * <li>{@code SwingConstants.CENTER} (the default)
  764        * <li>{@code SwingConstants.TOP}
  765        * <li>{@code SwingConstants.BOTTOM}
  766        * </ul>
  767        * @throws IllegalArgumentException if the alignment is not one of the legal
  768        *         values listed above
  769        * @beaninfo
  770        *        bound: true
  771        *         enum: TOP    SwingConstants.TOP
  772        *               CENTER SwingConstants.CENTER
  773        *               BOTTOM  SwingConstants.BOTTOM
  774        *    attribute: visualUpdate true
  775        *  description: The vertical alignment of the icon and text.
  776        */
  777       public void setVerticalAlignment(int alignment) {
  778           if (alignment == verticalAlignment) return;
  779           int oldValue = verticalAlignment;
  780           verticalAlignment = checkVerticalKey(alignment, "verticalAlignment");
  781           firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, oldValue, verticalAlignment);         repaint();
  782       }
  783   
  784       /**
  785        * Returns the horizontal alignment of the icon and text.
  786        * {@code AbstractButton}'s default is {@code SwingConstants.CENTER},
  787        * but subclasses such as {@code JCheckBox} may use a different default.
  788        *
  789        * @return the <code>horizontalAlignment</code> property,
  790        *             one of the following values:
  791        * <ul>
  792        *   <li>{@code SwingConstants.RIGHT}
  793        *   <li>{@code SwingConstants.LEFT}
  794        *   <li>{@code SwingConstants.CENTER}
  795        *   <li>{@code SwingConstants.LEADING}
  796        *   <li>{@code SwingConstants.TRAILING}
  797        * </ul>
  798        */
  799       public int getHorizontalAlignment() {
  800           return horizontalAlignment;
  801       }
  802   
  803       /**
  804        * Sets the horizontal alignment of the icon and text.
  805        * {@code AbstractButton}'s default is {@code SwingConstants.CENTER},
  806        * but subclasses such as {@code JCheckBox} may use a different default.
  807        *
  808        * @param alignment the alignment value, one of the following values:
  809        * <ul>
  810        *   <li>{@code SwingConstants.RIGHT}
  811        *   <li>{@code SwingConstants.LEFT}
  812        *   <li>{@code SwingConstants.CENTER}
  813        *   <li>{@code SwingConstants.LEADING}
  814        *   <li>{@code SwingConstants.TRAILING}
  815        * </ul>
  816        * @throws IllegalArgumentException if the alignment is not one of the
  817        *         valid values
  818        * @beaninfo
  819        *        bound: true
  820        *         enum: LEFT     SwingConstants.LEFT
  821        *               CENTER   SwingConstants.CENTER
  822        *               RIGHT    SwingConstants.RIGHT
  823        *               LEADING  SwingConstants.LEADING
  824        *               TRAILING SwingConstants.TRAILING
  825        *    attribute: visualUpdate true
  826        *  description: The horizontal alignment of the icon and text.
  827        */
  828       public void setHorizontalAlignment(int alignment) {
  829           if (alignment == horizontalAlignment) return;
  830           int oldValue = horizontalAlignment;
  831           horizontalAlignment = checkHorizontalKey(alignment,
  832                                                    "horizontalAlignment");
  833           firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY,
  834                              oldValue, horizontalAlignment);
  835           repaint();
  836       }
  837   
  838   
  839       /**
  840        * Returns the vertical position of the text relative to the icon.
  841        * @return the <code>verticalTextPosition</code> property,
  842        *          one of the following values:
  843        * <ul>
  844        * <li>{@code SwingConstants.CENTER} (the default)
  845        * <li>{@code SwingConstants.TOP}
  846        * <li>{@code SwingConstants.BOTTOM}
  847        * </ul>
  848        */
  849       public int getVerticalTextPosition() {
  850           return verticalTextPosition;
  851       }
  852   
  853       /**
  854        * Sets the vertical position of the text relative to the icon.
  855        * @param textPosition  one of the following values:
  856        * <ul>
  857        * <li>{@code SwingConstants.CENTER} (the default)
  858        * <li>{@code SwingConstants.TOP}
  859        * <li>{@code SwingConstants.BOTTOM}
  860        * </ul>
  861        * @beaninfo
  862        *        bound: true
  863        *         enum: TOP    SwingConstants.TOP
  864        *               CENTER SwingConstants.CENTER
  865        *               BOTTOM SwingConstants.BOTTOM
  866        *    attribute: visualUpdate true
  867        *  description: The vertical position of the text relative to the icon.
  868        */
  869       public void setVerticalTextPosition(int textPosition) {
  870           if (textPosition == verticalTextPosition) return;
  871           int oldValue = verticalTextPosition;
  872           verticalTextPosition = checkVerticalKey(textPosition, "verticalTextPosition");
  873           firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, oldValue, verticalTextPosition);
  874           revalidate();
  875           repaint();
  876       }
  877   
  878       /**
  879        * Returns the horizontal position of the text relative to the icon.
  880        * @return the <code>horizontalTextPosition</code> property,
  881        *          one of the following values:
  882        * <ul>
  883        * <li>{@code SwingConstants.RIGHT}
  884        * <li>{@code SwingConstants.LEFT}
  885        * <li>{@code SwingConstants.CENTER}
  886        * <li>{@code SwingConstants.LEADING}
  887        * <li>{@code SwingConstants.TRAILING} (the default)
  888        * </ul>
  889        */
  890       public int getHorizontalTextPosition() {
  891           return horizontalTextPosition;
  892       }
  893   
  894       /**
  895        * Sets the horizontal position of the text relative to the icon.
  896        * @param textPosition one of the following values:
  897        * <ul>
  898        * <li>{@code SwingConstants.RIGHT}
  899        * <li>{@code SwingConstants.LEFT}
  900        * <li>{@code SwingConstants.CENTER}
  901        * <li>{@code SwingConstants.LEADING}
  902        * <li>{@code SwingConstants.TRAILING} (the default)
  903        * </ul>
  904        * @exception IllegalArgumentException if <code>textPosition</code>
  905        *          is not one of the legal values listed above
  906        * @beaninfo
  907        *        bound: true
  908        *         enum: LEFT     SwingConstants.LEFT
  909        *               CENTER   SwingConstants.CENTER
  910        *               RIGHT    SwingConstants.RIGHT
  911        *               LEADING  SwingConstants.LEADING
  912        *               TRAILING SwingConstants.TRAILING
  913        *    attribute: visualUpdate true
  914        *  description: The horizontal position of the text relative to the icon.
  915        */
  916       public void setHorizontalTextPosition(int textPosition) {
  917           if (textPosition == horizontalTextPosition) return;
  918           int oldValue = horizontalTextPosition;
  919           horizontalTextPosition = checkHorizontalKey(textPosition,
  920                                                       "horizontalTextPosition");
  921           firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY,
  922                              oldValue,
  923                              horizontalTextPosition);
  924           revalidate();
  925           repaint();
  926       }
  927   
  928       /**
  929        * Returns the amount of space between the text and the icon
  930        * displayed in this button.
  931        *
  932        * @return an int equal to the number of pixels between the text
  933        *         and the icon.
  934        * @since 1.4
  935        * @see #setIconTextGap
  936        */
  937       public int getIconTextGap() {
  938           return iconTextGap;
  939       }
  940   
  941       /**
  942        * If both the icon and text properties are set, this property
  943        * defines the space between them.
  944        * <p>
  945        * The default value of this property is 4 pixels.
  946        * <p>
  947        * This is a JavaBeans bound property.
  948        *
  949        * @since 1.4
  950        * @see #getIconTextGap
  951        * @beaninfo
  952        *        bound: true
  953        *    attribute: visualUpdate true
  954        *  description: If both the icon and text properties are set, this
  955        *               property defines the space between them.
  956        */
  957       public void setIconTextGap(int iconTextGap) {
  958           int oldValue = this.iconTextGap;
  959           this.iconTextGap = iconTextGap;
  960           iconTextGapSet = true;
  961           firePropertyChange("iconTextGap", oldValue, iconTextGap);
  962           if (iconTextGap != oldValue) {
  963               revalidate();
  964               repaint();
  965           }
  966       }
  967   
  968       /**
  969        * Verify that the {@code key} argument is a legal value for the
  970        * {@code horizontalAlignment} and {@code horizontalTextPosition}
  971        * properties. Valid values are:
  972        * <ul>
  973        *   <li>{@code SwingConstants.RIGHT}
  974        *   <li>{@code SwingConstants.LEFT}
  975        *   <li>{@code SwingConstants.CENTER}
  976        *   <li>{@code SwingConstants.LEADING}
  977        *   <li>{@code SwingConstants.TRAILING}
  978        * </ul>
  979        *
  980        * @param key the property value to check
  981        * @param exception the message to use in the
  982        *        {@code IllegalArgumentException} that is thrown for an invalid
  983        *        value
  984        * @exception IllegalArgumentException if key is not one of the legal
  985        *            values listed above
  986        * @see #setHorizontalTextPosition
  987        * @see #setHorizontalAlignment
  988        */
  989       protected int checkHorizontalKey(int key, String exception) {
  990           if ((key == LEFT) ||
  991               (key == CENTER) ||
  992               (key == RIGHT) ||
  993               (key == LEADING) ||
  994               (key == TRAILING)) {
  995               return key;
  996           } else {
  997               throw new IllegalArgumentException(exception);
  998           }
  999       }
 1000   
 1001       /**
 1002        * Verify that the {@code key} argument is a legal value for the
 1003        * vertical properties. Valid values are:
 1004        * <ul>
 1005        *   <li>{@code SwingConstants.CENTER}
 1006        *   <li>{@code SwingConstants.TOP}
 1007        *   <li>{@code SwingConstants.BOTTOM}
 1008        * </ul>
 1009        *
 1010        * @param key the property value to check
 1011        * @param exception the message to use in the
 1012        *        {@code IllegalArgumentException} that is thrown for an invalid
 1013        *        value
 1014        * @exception IllegalArgumentException if key is not one of the legal
 1015        *            values listed above
 1016        */
 1017       protected int checkVerticalKey(int key, String exception) {
 1018           if ((key == TOP) || (key == CENTER) || (key == BOTTOM)) {
 1019               return key;
 1020           } else {
 1021               throw new IllegalArgumentException(exception);
 1022           }
 1023       }
 1024   
 1025       /**
 1026        *{@inheritDoc}
 1027        *
 1028        * @since 1.6
 1029        */
 1030       public void removeNotify() {
 1031           super.removeNotify();
 1032           if(isRolloverEnabled()) {
 1033               getModel().setRollover(false);
 1034           }
 1035       }
 1036   
 1037       /**
 1038        * Sets the action command for this button.
 1039        * @param actionCommand the action command for this button
 1040        */
 1041       public void setActionCommand(String actionCommand) {
 1042           getModel().setActionCommand(actionCommand);
 1043       }
 1044   
 1045       /**
 1046        * Returns the action command for this button.
 1047        * @return the action command for this button
 1048        */
 1049       public String getActionCommand() {
 1050           String ac = getModel().getActionCommand();
 1051           if(ac == null) {
 1052               ac = getText();
 1053           }
 1054           return ac;
 1055       }
 1056   
 1057       private Action action;
 1058       private PropertyChangeListener actionPropertyChangeListener;
 1059   
 1060       /**
 1061        * Sets the <code>Action</code>.
 1062        * The new <code>Action</code> replaces any previously set
 1063        * <code>Action</code> but does not affect <code>ActionListeners</code>
 1064        * independently added with <code>addActionListener</code>.
 1065        * If the <code>Action</code> is already a registered
 1066        * <code>ActionListener</code> for the button, it is not re-registered.
 1067        * <p>
 1068        * Setting the <code>Action</code> results in immediately changing
 1069        * all the properties described in <a href="Action.html#buttonActions">
 1070        * Swing Components Supporting <code>Action</code></a>.
 1071        * Subsequently, the button's properties are automatically updated
 1072        * as the <code>Action</code>'s properties change.
 1073        * <p>
 1074        * This method uses three other methods to set
 1075        * and help track the <code>Action</code>'s property values.
 1076        * It uses the <code>configurePropertiesFromAction</code> method
 1077        * to immediately change the button's properties.
 1078        * To track changes in the <code>Action</code>'s property values,
 1079        * this method registers the <code>PropertyChangeListener</code>
 1080        * returned by <code>createActionPropertyChangeListener</code>. The
 1081        * default {@code PropertyChangeListener} invokes the
 1082        * {@code actionPropertyChanged} method when a property in the
 1083        * {@code Action} changes.
 1084        *
 1085        * @param a the <code>Action</code> for the <code>AbstractButton</code>,
 1086        *          or <code>null</code>
 1087        * @since 1.3
 1088        * @see Action
 1089        * @see #getAction
 1090        * @see #configurePropertiesFromAction
 1091        * @see #createActionPropertyChangeListener
 1092        * @see #actionPropertyChanged
 1093        * @beaninfo
 1094        *        bound: true
 1095        *    attribute: visualUpdate true
 1096        *  description: the Action instance connected with this ActionEvent source
 1097        */
 1098       public void setAction(Action a) {
 1099           Action oldValue = getAction();
 1100           if (action==null || !action.equals(a)) {
 1101               action = a;
 1102               if (oldValue!=null) {
 1103                   removeActionListener(oldValue);
 1104                   oldValue.removePropertyChangeListener(actionPropertyChangeListener);
 1105                   actionPropertyChangeListener = null;
 1106               }
 1107               configurePropertiesFromAction(action);
 1108               if (action!=null) {
 1109                   // Don't add if it is already a listener
 1110                   if (!isListener(ActionListener.class, action)) {
 1111                       addActionListener(action);
 1112                   }
 1113                   // Reverse linkage:
 1114                   actionPropertyChangeListener = createActionPropertyChangeListener(action);
 1115                   action.addPropertyChangeListener(actionPropertyChangeListener);
 1116               }
 1117               firePropertyChange("action", oldValue, action);
 1118           }
 1119       }
 1120   
 1121       private boolean isListener(Class c, ActionListener a) {
 1122           boolean isListener = false;
 1123           Object[] listeners = listenerList.getListenerList();
 1124           for (int i = listeners.length-2; i>=0; i-=2) {
 1125               if (listeners[i]==c && listeners[i+1]==a) {
 1126                       isListener=true;
 1127               }
 1128           }
 1129           return isListener;
 1130       }
 1131   
 1132       /**
 1133        * Returns the currently set <code>Action</code> for this
 1134        * <code>ActionEvent</code> source, or <code>null</code>
 1135        * if no <code>Action</code> is set.
 1136        *
 1137        * @return the <code>Action</code> for this <code>ActionEvent</code>
 1138        *          source, or <code>null</code>
 1139        * @since 1.3
 1140        * @see Action
 1141        * @see #setAction
 1142        */
 1143       public Action getAction() {
 1144           return action;
 1145       }
 1146   
 1147       /**
 1148        * Sets the properties on this button to match those in the specified
 1149        * <code>Action</code>.  Refer to <a href="Action.html#buttonActions">
 1150        * Swing Components Supporting <code>Action</code></a> for more
 1151        * details as to which properties this sets.
 1152        *
 1153        * @param a the <code>Action</code> from which to get the properties,
 1154        *          or <code>null</code>
 1155        * @since 1.3
 1156        * @see Action
 1157        * @see #setAction
 1158        */
 1159       protected void configurePropertiesFromAction(Action a) {
 1160           setMnemonicFromAction(a);
 1161           setTextFromAction(a, false);
 1162           AbstractAction.setToolTipTextFromAction(this, a);
 1163           setIconFromAction(a);
 1164           setActionCommandFromAction(a);
 1165           AbstractAction.setEnabledFromAction(this, a);
 1166           if (AbstractAction.hasSelectedKey(a) &&
 1167                   shouldUpdateSelectedStateFromAction()) {
 1168               setSelectedFromAction(a);
 1169           }
 1170           setDisplayedMnemonicIndexFromAction(a, false);
 1171       }
 1172   
 1173       void clientPropertyChanged(Object key, Object oldValue,
 1174                                  Object newValue) {
 1175           if (key == "hideActionText") {
 1176               boolean current = (newValue instanceof Boolean) ?
 1177                                   (Boolean)newValue : false;
 1178               if (getHideActionText() != current) {
 1179                   setHideActionText(current);
 1180               }
 1181           }
 1182       }
 1183   
 1184       /**
 1185        * Button subclasses that support mirroring the selected state from
 1186        * the action should override this to return true.  AbstractButton's
 1187        * implementation returns false.
 1188        */
 1189       boolean shouldUpdateSelectedStateFromAction() {
 1190           return false;
 1191       }
 1192   
 1193       /**
 1194        * Updates the button's state in response to property changes in the
 1195        * associated action. This method is invoked from the
 1196        * {@code PropertyChangeListener} returned from
 1197        * {@code createActionPropertyChangeListener}. Subclasses do not normally
 1198        * need to invoke this. Subclasses that support additional {@code Action}
 1199        * properties should override this and
 1200        * {@code configurePropertiesFromAction}.
 1201        * <p>
 1202        * Refer to the table at <a href="Action.html#buttonActions">
 1203        * Swing Components Supporting <code>Action</code></a> for a list of
 1204        * the properties this method sets.
 1205        *
 1206        * @param action the <code>Action</code> associated with this button
 1207        * @param propertyName the name of the property that changed
 1208        * @since 1.6
 1209        * @see Action
 1210        * @see #configurePropertiesFromAction
 1211        */
 1212       protected void actionPropertyChanged(Action action, String propertyName) {
 1213           if (propertyName == Action.NAME) {
 1214               setTextFromAction(action, true);
 1215           } else if (propertyName == "enabled") {
 1216               AbstractAction.setEnabledFromAction(this, action);
 1217           } else if (propertyName == Action.SHORT_DESCRIPTION) {
 1218               AbstractAction.setToolTipTextFromAction(this, action);
 1219           } else if (propertyName == Action.SMALL_ICON) {
 1220               smallIconChanged(action);
 1221           } else if (propertyName == Action.MNEMONIC_KEY) {
 1222               setMnemonicFromAction(action);
 1223           } else if (propertyName == Action.ACTION_COMMAND_KEY) {
 1224               setActionCommandFromAction(action);
 1225           } else if (propertyName == Action.SELECTED_KEY &&
 1226                      AbstractAction.hasSelectedKey(action) &&
 1227                      shouldUpdateSelectedStateFromAction()) {
 1228               setSelectedFromAction(action);
 1229           } else if (propertyName == Action.DISPLAYED_MNEMONIC_INDEX_KEY) {
 1230               setDisplayedMnemonicIndexFromAction(action, true);
 1231           } else if (propertyName == Action.LARGE_ICON_KEY) {
 1232               largeIconChanged(action);
 1233           }
 1234       }
 1235   
 1236       private void setDisplayedMnemonicIndexFromAction(
 1237               Action a, boolean fromPropertyChange) {
 1238           Integer iValue = (a == null) ? null :
 1239                   (Integer)a.getValue(Action.DISPLAYED_MNEMONIC_INDEX_KEY);
 1240           if (fromPropertyChange || iValue != null) {
 1241               int value;
 1242               if (iValue == null) {
 1243                   value = -1;
 1244               } else {
 1245                   value = iValue;
 1246                   String text = getText();
 1247                   if (text == null || value >= text.length()) {
 1248                       value = -1;
 1249                   }
 1250               }
 1251               setDisplayedMnemonicIndex(value);
 1252           }
 1253       }
 1254   
 1255       private void setMnemonicFromAction(Action a) {
 1256           Integer n = (a == null) ? null :
 1257                                     (Integer)a.getValue(Action.MNEMONIC_KEY);
 1258           setMnemonic((n == null) ? '\0' : n);
 1259       }
 1260   
 1261       private void setTextFromAction(Action a, boolean propertyChange) {
 1262           boolean hideText = getHideActionText();
 1263           if (!propertyChange) {
 1264               setText((a != null && !hideText) ?
 1265                           (String)a.getValue(Action.NAME) : null);
 1266           }
 1267           else if (!hideText) {
 1268               setText((String)a.getValue(Action.NAME));
 1269           }
 1270       }
 1271   
 1272       void setIconFromAction(Action a) {
 1273           Icon icon = null;
 1274           if (a != null) {
 1275               icon = (Icon)a.getValue(Action.LARGE_ICON_KEY);
 1276               if (icon == null) {
 1277                   icon = (Icon)a.getValue(Action.SMALL_ICON);
 1278               }
 1279           }
 1280           setIcon(icon);
 1281       }
 1282   
 1283       void smallIconChanged(Action a) {
 1284           if (a.getValue(Action.LARGE_ICON_KEY) == null) {
 1285               setIconFromAction(a);
 1286           }
 1287       }
 1288   
 1289       void largeIconChanged(Action a) {
 1290           setIconFromAction(a);
 1291       }
 1292   
 1293       private void setActionCommandFromAction(Action a) {
 1294           setActionCommand((a != null) ?
 1295                                (String)a.getValue(Action.ACTION_COMMAND_KEY) :
 1296                                null);
 1297       }
 1298   
 1299       /**
 1300        * Sets the seleted state of the button from the action.  This is defined
 1301        * here, but not wired up.  Subclasses like JToggleButton and
 1302        * JCheckBoxMenuItem make use of it.
 1303        *
 1304        * @param a the Action
 1305        */
 1306       private void setSelectedFromAction(Action a) {
 1307           boolean selected = false;
 1308           if (a != null) {
 1309               selected = AbstractAction.isSelected(a);
 1310           }
 1311           if (selected != isSelected()) {
 1312               // This won't notify ActionListeners, but that should be
 1313               // ok as the change is coming from the Action.
 1314               setSelected(selected);
 1315               // Make sure the change actually took effect
 1316               if (!selected && isSelected()) {
 1317                   if (getModel() instanceof DefaultButtonModel) {
 1318                       ButtonGroup group = (ButtonGroup)
 1319                               ((DefaultButtonModel)getModel()).getGroup();
 1320                       if (group != null) {
 1321                           group.clearSelection();
 1322                       }
 1323                   }
 1324               }
 1325           }
 1326       }
 1327   
 1328       /**
 1329        * Creates and returns a <code>PropertyChangeListener</code> that is
 1330        * responsible for listening for changes from the specified
 1331        * <code>Action</code> and updating the appropriate properties.
 1332        * <p>
 1333        * <b>Warning:</b> If you subclass this do not create an anonymous
 1334        * inner class.  If you do the lifetime of the button will be tied to
 1335        * that of the <code>Action</code>.
 1336        *
 1337        * @param a the button's action
 1338        * @since 1.3
 1339        * @see <a href="#actions">Actions</a>
 1340        * @see Action
 1341        * @see #setAction
 1342        */
 1343       protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
 1344           return createActionPropertyChangeListener0(a);
 1345       }
 1346   
 1347   
 1348       PropertyChangeListener createActionPropertyChangeListener0(Action a) {
 1349           return new ButtonActionPropertyChangeListener(this, a);
 1350       }
 1351   
 1352       private static class ButtonActionPropertyChangeListener
 1353                    extends ActionPropertyChangeListener<AbstractButton> {
 1354           ButtonActionPropertyChangeListener(AbstractButton b, Action a) {
 1355               super(b, a);
 1356           }
 1357           protected void actionPropertyChanged(AbstractButton button,
 1358                                                Action action,
 1359                                                PropertyChangeEvent e) {
 1360               if (AbstractAction.shouldReconfigure(e)) {
 1361                   button.configurePropertiesFromAction(action);
 1362               } else {
 1363                   button.actionPropertyChanged(action, e.getPropertyName());
 1364               }
 1365           }
 1366       }
 1367   
 1368       /**
 1369        * Gets the <code>borderPainted</code> property.
 1370        *
 1371        * @return the value of the <code>borderPainted</code> property
 1372        * @see #setBorderPainted
 1373        */
 1374       public boolean isBorderPainted() {
 1375           return paintBorder;
 1376       }
 1377   
 1378       /**
 1379        * Sets the <code>borderPainted</code> property.
 1380        * If <code>true</code> and the button has a border,
 1381        * the border is painted. The default value for the
 1382        * <code>borderPainted</code> property is <code>true</code>.
 1383        *
 1384        * @param b if true and border property is not <code>null</code>,
 1385        *          the border is painted
 1386        * @see #isBorderPainted
 1387        * @beaninfo
 1388        *        bound: true
 1389        *    attribute: visualUpdate true
 1390        *  description: Whether the border should be painted.
 1391        */
 1392       public void setBorderPainted(boolean b) {
 1393           boolean oldValue = paintBorder;
 1394           paintBorder = b;
 1395           borderPaintedSet = true;
 1396           firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, oldValue, paintBorder);
 1397           if (b != oldValue) {
 1398               revalidate();
 1399               repaint();
 1400           }
 1401       }
 1402   
 1403       /**
 1404        * Paint the button's border if <code>BorderPainted</code>
 1405        * property is true and the button has a border.
 1406        * @param g the <code>Graphics</code> context in which to paint
 1407        *
 1408        * @see #paint
 1409        * @see #setBorder
 1410        */
 1411       protected void paintBorder(Graphics g) {
 1412           if (isBorderPainted()) {
 1413               super.paintBorder(g);
 1414           }
 1415       }
 1416   
 1417       /**
 1418        * Gets the <code>paintFocus</code> property.
 1419        *
 1420        * @return the <code>paintFocus</code> property
 1421        * @see #setFocusPainted
 1422        */
 1423       public boolean isFocusPainted() {
 1424           return paintFocus;
 1425       }
 1426   
 1427       /**
 1428        * Sets the <code>paintFocus</code> property, which must
 1429        * be <code>true</code> for the focus state to be painted.
 1430        * The default value for the <code>paintFocus</code> property
 1431        * is <code>true</code>.
 1432        * Some look and feels might not paint focus state;
 1433        * they will ignore this property.
 1434        *
 1435        * @param b if <code>true</code>, the focus state should be painted
 1436        * @see #isFocusPainted
 1437        * @beaninfo
 1438        *        bound: true
 1439        *    attribute: visualUpdate true
 1440        *  description: Whether focus should be painted
 1441        */
 1442       public void setFocusPainted(boolean b) {
 1443           boolean oldValue = paintFocus;
 1444           paintFocus = b;
 1445           firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, oldValue, paintFocus);
 1446           if (b != oldValue && isFocusOwner()) {
 1447               revalidate();
 1448               repaint();
 1449           }
 1450       }
 1451   
 1452       /**
 1453        * Gets the <code>contentAreaFilled</code> property.
 1454        *
 1455        * @return the <code>contentAreaFilled</code> property
 1456        * @see #setContentAreaFilled
 1457        */
 1458       public boolean isContentAreaFilled() {
 1459           return contentAreaFilled;
 1460       }
 1461   
 1462       /**
 1463        * Sets the <code>contentAreaFilled</code> property.
 1464        * If <code>true</code> the button will paint the content
 1465        * area.  If you wish to have a transparent button, such as
 1466        * an icon only button, for example, then you should set
 1467        * this to <code>false</code>. Do not call <code>setOpaque(false)</code>.
 1468        * The default value for the the <code>contentAreaFilled</code>
 1469        * property is <code>true</code>.
 1470        * <p>
 1471        * This function may cause the component's opaque property to change.
 1472        * <p>
 1473        * The exact behavior of calling this function varies on a
 1474        * component-by-component and L&F-by-L&F basis.
 1475        *
 1476        * @param b if true, the content should be filled; if false
 1477        *          the content area is not filled
 1478        * @see #isContentAreaFilled
 1479        * @see #setOpaque
 1480        * @beaninfo
 1481        *        bound: true
 1482        *    attribute: visualUpdate true
 1483        *  description: Whether the button should paint the content area
 1484        *               or leave it transparent.
 1485        */
 1486       public void setContentAreaFilled(boolean b) {
 1487           boolean oldValue = contentAreaFilled;
 1488           contentAreaFilled = b;
 1489           contentAreaFilledSet = true;
 1490           firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, oldValue, contentAreaFilled);
 1491           if (b != oldValue) {
 1492               repaint();
 1493           }
 1494       }
 1495   
 1496       /**
 1497        * Gets the <code>rolloverEnabled</code> property.
 1498        *
 1499        * @return the value of the <code>rolloverEnabled</code> property
 1500        * @see #setRolloverEnabled
 1501        */
 1502       public boolean isRolloverEnabled() {
 1503           return rolloverEnabled;
 1504       }
 1505   
 1506       /**
 1507        * Sets the <code>rolloverEnabled</code> property, which
 1508        * must be <code>true</code> for rollover effects to occur.
 1509        * The default value for the <code>rolloverEnabled</code>
 1510        * property is <code>false</code>.
 1511        * Some look and feels might not implement rollover effects;
 1512        * they will ignore this property.
 1513        *
 1514        * @param b if <code>true</code>, rollover effects should be painted
 1515        * @see #isRolloverEnabled
 1516        * @beaninfo
 1517        *        bound: true
 1518        *    attribute: visualUpdate true
 1519        *  description: Whether rollover effects should be enabled.
 1520        */
 1521       public void setRolloverEnabled(boolean b) {
 1522           boolean oldValue = rolloverEnabled;
 1523           rolloverEnabled = b;
 1524           rolloverEnabledSet = true;
 1525           firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, oldValue, rolloverEnabled);
 1526           if (b != oldValue) {
 1527               repaint();
 1528           }
 1529       }
 1530   
 1531       /**
 1532        * Returns the keyboard mnemonic from the the current model.
 1533        * @return the keyboard mnemonic from the model
 1534        */
 1535       public int getMnemonic() {
 1536           return mnemonic;
 1537       }
 1538   
 1539       /**
 1540        * Sets the keyboard mnemonic on the current model.
 1541        * The mnemonic is the key which when combined with the look and feel's
 1542        * mouseless modifier (usually Alt) will activate this button
 1543        * if focus is contained somewhere within this button's ancestor
 1544        * window.
 1545        * <p>
 1546        * A mnemonic must correspond to a single key on the keyboard
 1547        * and should be specified using one of the <code>VK_XXX</code>
 1548        * keycodes defined in <code>java.awt.event.KeyEvent</code>.
 1549        * Mnemonics are case-insensitive, therefore a key event
 1550        * with the corresponding keycode would cause the button to be
 1551        * activated whether or not the Shift modifier was pressed.
 1552        * <p>
 1553        * If the character defined by the mnemonic is found within
 1554        * the button's label string, the first occurrence of it
 1555        * will be underlined to indicate the mnemonic to the user.
 1556        *
 1557        * @param mnemonic the key code which represents the mnemonic
 1558        * @see     java.awt.event.KeyEvent
 1559        * @see     #setDisplayedMnemonicIndex
 1560        *
 1561        * @beaninfo
 1562        *        bound: true
 1563        *    attribute: visualUpdate true
 1564        *  description: the keyboard character mnemonic
 1565        */
 1566       public void setMnemonic(int mnemonic) {
 1567           int oldValue = getMnemonic();
 1568           model.setMnemonic(mnemonic);
 1569           updateMnemonicProperties();
 1570       }
 1571   
 1572       /**
 1573        * This method is now obsolete, please use <code>setMnemonic(int)</code>
 1574        * to set the mnemonic for a button.  This method is only designed
 1575        * to handle character values which fall between 'a' and 'z' or
 1576        * 'A' and 'Z'.
 1577        *
 1578        * @param mnemonic  a char specifying the mnemonic value
 1579        * @see #setMnemonic(int)
 1580        * @beaninfo
 1581        *        bound: true
 1582        *    attribute: visualUpdate true
 1583        *  description: the keyboard character mnemonic
 1584        */
 1585       public void setMnemonic(char mnemonic) {
 1586           int vk = (int) mnemonic;
 1587           if(vk >= 'a' && vk <='z')
 1588               vk -= ('a' - 'A');
 1589           setMnemonic(vk);
 1590       }
 1591   
 1592       /**
 1593        * Provides a hint to the look and feel as to which character in the
 1594        * text should be decorated to represent the mnemonic. Not all look and
 1595        * feels may support this. A value of -1 indicates either there is no
 1596        * mnemonic, the mnemonic character is not contained in the string, or
 1597        * the developer does not wish the mnemonic to be displayed.
 1598        * <p>
 1599        * The value of this is updated as the properties relating to the
 1600        * mnemonic change (such as the mnemonic itself, the text...).
 1601        * You should only ever have to call this if
 1602        * you do not wish the default character to be underlined. For example, if
 1603        * the text was 'Save As', with a mnemonic of 'a', and you wanted the 'A'
 1604        * to be decorated, as 'Save <u>A</u>s', you would have to invoke
 1605        * <code>setDisplayedMnemonicIndex(5)</code> after invoking
 1606        * <code>setMnemonic(KeyEvent.VK_A)</code>.
 1607        *
 1608        * @since 1.4
 1609        * @param index Index into the String to underline
 1610        * @exception IllegalArgumentException will be thrown if <code>index</code>
 1611        *            is &gt;= length of the text, or &lt; -1
 1612        * @see #getDisplayedMnemonicIndex
 1613        *
 1614        * @beaninfo
 1615        *        bound: true
 1616        *    attribute: visualUpdate true
 1617        *  description: the index into the String to draw the keyboard character
 1618        *               mnemonic at
 1619        */
 1620       public void setDisplayedMnemonicIndex(int index)
 1621                                             throws IllegalArgumentException {
 1622           int oldValue = mnemonicIndex;
 1623           if (index == -1) {
 1624               mnemonicIndex = -1;
 1625           } else {
 1626               String text = getText();
 1627               int textLength = (text == null) ? 0 : text.length();
 1628               if (index < -1 || index >= textLength) {  // index out of range
 1629                   throw new IllegalArgumentException("index == " + index);
 1630               }
 1631           }
 1632           mnemonicIndex = index;
 1633           firePropertyChange("displayedMnemonicIndex", oldValue, index);
 1634           if (index != oldValue) {
 1635               revalidate();
 1636               repaint();
 1637           }
 1638       }
 1639   
 1640       /**
 1641        * Returns the character, as an index, that the look and feel should
 1642        * provide decoration for as representing the mnemonic character.
 1643        *
 1644        * @since 1.4
 1645        * @return index representing mnemonic character
 1646        * @see #setDisplayedMnemonicIndex
 1647        */
 1648       public int getDisplayedMnemonicIndex() {
 1649           return mnemonicIndex;
 1650       }
 1651   
 1652       /**
 1653        * Update the displayedMnemonicIndex property. This method
 1654        * is called when either text or mnemonic changes. The new
 1655        * value of the displayedMnemonicIndex property is the index
 1656        * of the first occurrence of mnemonic in text.
 1657        */
 1658       private void updateDisplayedMnemonicIndex(String text, int mnemonic) {
 1659           setDisplayedMnemonicIndex(
 1660               SwingUtilities.findDisplayedMnemonicIndex(text, mnemonic));
 1661       }
 1662   
 1663       /**
 1664        * Brings the mnemonic property in accordance with model's mnemonic.
 1665        * This is called when model's mnemonic changes. Also updates the
 1666        * displayedMnemonicIndex property.
 1667        */
 1668       private void updateMnemonicProperties() {
 1669           int newMnemonic = model.getMnemonic();
 1670           if (mnemonic != newMnemonic) {
 1671               int oldValue = mnemonic;
 1672               mnemonic = newMnemonic;
 1673               firePropertyChange(MNEMONIC_CHANGED_PROPERTY,
 1674                                  oldValue, mnemonic);
 1675               updateDisplayedMnemonicIndex(getText(), mnemonic);
 1676               revalidate();
 1677               repaint();
 1678           }
 1679       }
 1680   
 1681       /**
 1682        * Sets the amount of time (in milliseconds) required between
 1683        * mouse press events for the button to generate the corresponding
 1684        * action events.  After the initial mouse press occurs (and action
 1685        * event generated) any subsequent mouse press events which occur
 1686        * on intervals less than the threshhold will be ignored and no
 1687        * corresponding action event generated.  By default the threshhold is 0,
 1688        * which means that for each mouse press, an action event will be
 1689        * fired, no matter how quickly the mouse clicks occur.  In buttons
 1690        * where this behavior is not desirable (for example, the "OK" button
 1691        * in a dialog), this threshhold should be set to an appropriate
 1692        * positive value.
 1693        *
 1694        * @see #getMultiClickThreshhold
 1695        * @param threshhold the amount of time required between mouse
 1696        *        press events to generate corresponding action events
 1697        * @exception   IllegalArgumentException if threshhold < 0
 1698        * @since 1.4
 1699        */
 1700       public void setMultiClickThreshhold(long threshhold) {
 1701           if (threshhold < 0) {
 1702               throw new IllegalArgumentException("threshhold must be >= 0");
 1703           }
 1704           this.multiClickThreshhold = threshhold;
 1705       }
 1706   
 1707       /**
 1708        * Gets the amount of time (in milliseconds) required between
 1709        * mouse press events for the button to generate the corresponding
 1710        * action events.
 1711        *
 1712        * @see #setMultiClickThreshhold
 1713        * @return the amount of time required between mouse press events
 1714        *         to generate corresponding action events
 1715        * @since 1.4
 1716        */
 1717       public long getMultiClickThreshhold() {
 1718           return multiClickThreshhold;
 1719       }
 1720   
 1721       /**
 1722        * Returns the model that this button represents.
 1723        * @return the <code>model</code> property
 1724        * @see #setModel
 1725        */
 1726       public ButtonModel getModel() {
 1727           return model;
 1728       }
 1729   
 1730       /**
 1731        * Sets the model that this button represents.
 1732        * @param newModel the new <code>ButtonModel</code>
 1733        * @see #getModel
 1734        * @beaninfo
 1735        *        bound: true
 1736        *  description: Model that the Button uses.
 1737        */
 1738       public void setModel(ButtonModel newModel) {
 1739   
 1740           ButtonModel oldModel = getModel();
 1741   
 1742           if (oldModel != null) {
 1743               oldModel.removeChangeListener(changeListener);
 1744               oldModel.removeActionListener(actionListener);
 1745               oldModel.removeItemListener(itemListener);
 1746               changeListener = null;
 1747               actionListener = null;
 1748               itemListener = null;
 1749           }
 1750   
 1751           model = newModel;
 1752   
 1753           if (newModel != null) {
 1754               changeListener = createChangeListener();
 1755               actionListener = createActionListener();
 1756               itemListener = createItemListener();
 1757               newModel.addChangeListener(changeListener);
 1758               newModel.addActionListener(actionListener);
 1759               newModel.addItemListener(itemListener);
 1760   
 1761               updateMnemonicProperties();
 1762               //We invoke setEnabled() from JComponent
 1763               //because setModel() can be called from a constructor
 1764               //when the button is not fully initialized
 1765               super.setEnabled(newModel.isEnabled());
 1766   
 1767           } else {
 1768               mnemonic = '\0';
 1769           }
 1770   
 1771           updateDisplayedMnemonicIndex(getText(), mnemonic);
 1772   
 1773           firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel);
 1774           if (newModel != oldModel) {
 1775               revalidate();
 1776               repaint();
 1777           }
 1778       }
 1779   
 1780   
 1781       /**
 1782        * Returns the L&F object that renders this component.
 1783        * @return the ButtonUI object
 1784        * @see #setUI
 1785        */
 1786       public ButtonUI getUI() {
 1787           return (ButtonUI) ui;
 1788       }
 1789   
 1790   
 1791       /**
 1792        * Sets the L&F object that renders this component.
 1793        * @param ui the <code>ButtonUI</code> L&F object
 1794        * @see #getUI
 1795        * @beaninfo
 1796        *        bound: true
 1797        *       hidden: true
 1798        *    attribute: visualUpdate true
 1799        *  description: The UI object that implements the LookAndFeel.
 1800        */
 1801       public void setUI(ButtonUI ui) {
 1802           super.setUI(ui);
 1803           // disabled icons are generated by the LF so they should be unset here
 1804           if (disabledIcon instanceof UIResource) {
 1805               setDisabledIcon(null);
 1806           }
 1807           if (disabledSelectedIcon instanceof UIResource) {
 1808               setDisabledSelectedIcon(null);
 1809           }
 1810       }
 1811   
 1812   
 1813       /**
 1814        * Resets the UI property to a value from the current look
 1815        * and feel.  Subtypes of <code>AbstractButton</code>
 1816        * should override this to update the UI. For
 1817        * example, <code>JButton</code> might do the following:
 1818        * <pre>
 1819        *      setUI((ButtonUI)UIManager.getUI(
 1820        *          "ButtonUI", "javax.swing.plaf.basic.BasicButtonUI", this));
 1821        * </pre>
 1822        */
 1823       public void updateUI() {
 1824       }
 1825   
 1826       /**
 1827        * Adds the specified component to this container at the specified
 1828        * index, refer to
 1829        * {@link java.awt.Container#addImpl(Component, Object, int)}
 1830        * for a complete description of this method.
 1831        *
 1832        * @param     comp the component to be added
 1833        * @param     constraints an object expressing layout constraints
 1834        *                 for this component
 1835        * @param     index the position in the container's list at which to
 1836        *                 insert the component, where <code>-1</code>
 1837        *                 means append to the end
 1838        * @exception IllegalArgumentException if <code>index</code> is invalid
 1839        * @exception IllegalArgumentException if adding the container's parent
 1840        *                  to itself
 1841        * @exception IllegalArgumentException if adding a window to a container
 1842        * @since 1.5
 1843        */
 1844       protected void addImpl(Component comp, Object constraints, int index) {
 1845           if (!setLayout) {
 1846               setLayout(new OverlayLayout(this));
 1847           }
 1848           super.addImpl(comp, constraints, index);
 1849       }
 1850   
 1851       /**
 1852        * Sets the layout manager for this container, refer to
 1853        * {@link java.awt.Container#setLayout(LayoutManager)}
 1854        * for a complete description of this method.
 1855        *
 1856        * @param mgr the specified layout manager
 1857        * @since 1.5
 1858        */
 1859       public void setLayout(LayoutManager mgr) {
 1860           setLayout = true;
 1861           super.setLayout(mgr);
 1862       }
 1863   
 1864       /**
 1865        * Adds a <code>ChangeListener</code> to the button.
 1866        * @param l the listener to be added
 1867        */
 1868       public void addChangeListener(ChangeListener l) {
 1869           listenerList.add(ChangeListener.class, l);
 1870       }
 1871   
 1872       /**
 1873        * Removes a ChangeListener from the button.
 1874        * @param l the listener to be removed
 1875        */
 1876       public void removeChangeListener(ChangeListener l) {
 1877           listenerList.remove(ChangeListener.class, l);
 1878       }
 1879   
 1880       /**
 1881        * Returns an array of all the <code>ChangeListener</code>s added
 1882        * to this AbstractButton with addChangeListener().
 1883        *
 1884        * @return all of the <code>ChangeListener</code>s added or an empty
 1885        *         array if no listeners have been added
 1886        * @since 1.4
 1887        */
 1888       public ChangeListener[] getChangeListeners() {
 1889           return (ChangeListener[])(listenerList.getListeners(
 1890               ChangeListener.class));
 1891       }
 1892   
 1893       /**
 1894        * Notifies all listeners that have registered interest for
 1895        * notification on this event type.  The event instance
 1896        * is lazily created.
 1897        * @see EventListenerList
 1898        */
 1899       protected void fireStateChanged() {
 1900           // Guaranteed to return a non-null array
 1901           Object[] listeners = listenerList.getListenerList();
 1902           // Process the listeners last to first, notifying
 1903           // those that are interested in this event
 1904           for (int i = listeners.length-2; i>=0; i-=2) {
 1905               if (listeners[i]==ChangeListener.class) {
 1906                   // Lazily create the event:
 1907                   if (changeEvent == null)
 1908                       changeEvent = new ChangeEvent(this);
 1909                   ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
 1910               }
 1911           }
 1912       }
 1913   
 1914       /**
 1915        * Adds an <code>ActionListener</code> to the button.
 1916        * @param l the <code>ActionListener</code> to be added
 1917        */
 1918       public void addActionListener(ActionListener l) {
 1919           listenerList.add(ActionListener.class, l);
 1920       }
 1921   
 1922       /**
 1923        * Removes an <code>ActionListener</code> from the button.
 1924        * If the listener is the currently set <code>Action</code>
 1925        * for the button, then the <code>Action</code>
 1926        * is set to <code>null</code>.
 1927        *
 1928        * @param l the listener to be removed
 1929        */
 1930       public void removeActionListener(ActionListener l) {
 1931           if ((l != null) && (getAction() == l)) {
 1932               setAction(null);
 1933           } else {
 1934               listenerList.remove(ActionListener.class, l);
 1935           }
 1936       }
 1937   
 1938       /**
 1939        * Returns an array of all the <code>ActionListener</code>s added
 1940        * to this AbstractButton with addActionListener().
 1941        *
 1942        * @return all of the <code>ActionListener</code>s added or an empty
 1943        *         array if no listeners have been added
 1944        * @since 1.4
 1945        */
 1946       public ActionListener[] getActionListeners() {
 1947           return (ActionListener[])(listenerList.getListeners(
 1948               ActionListener.class));
 1949       }
 1950   
 1951       /**
 1952        * Subclasses that want to handle <code>ChangeEvents</code> differently
 1953        * can override this to return another <code>ChangeListener</code>
 1954        * implementation.
 1955        *
 1956        * @return the new <code>ChangeListener</code>
 1957        */
 1958       protected ChangeListener createChangeListener() {
 1959           return getHandler();
 1960       }
 1961   
 1962       /**
 1963        * Extends <code>ChangeListener</code> to be serializable.
 1964        * <p>
 1965        * <strong>Warning:</strong>
 1966        * Serialized objects of this class will not be compatible with
 1967        * future Swing releases. The current serialization support is
 1968        * appropriate for short term storage or RMI between applications running
 1969        * the same version of Swing.  As of 1.4, support for long term storage
 1970        * of all JavaBeans<sup><font size="-2">TM</font></sup>
 1971        * has been added to the <code>java.beans</code> package.
 1972        * Please see {@link java.beans.XMLEncoder}.
 1973        */
 1974       protected class ButtonChangeListener implements ChangeListener, Serializable {
 1975           // NOTE: This class is NOT used, instead the functionality has
 1976           // been moved to Handler.
 1977           ButtonChangeListener() {
 1978           }
 1979   
 1980           public void stateChanged(ChangeEvent e) {
 1981               getHandler().stateChanged(e);
 1982           }
 1983       }
 1984   
 1985   
 1986       /**
 1987        * Notifies all listeners that have registered interest for
 1988        * notification on this event type.  The event instance
 1989        * is lazily created using the <code>event</code>
 1990        * parameter.
 1991        *
 1992        * @param event  the <code>ActionEvent</code> object
 1993        * @see EventListenerList
 1994        */
 1995       protected void fireActionPerformed(ActionEvent event) {
 1996           // Guaranteed to return a non-null array
 1997           Object[] listeners = listenerList.getListenerList();
 1998           ActionEvent e = null;
 1999           // Process the listeners last to first, notifying
 2000           // those that are interested in this event
 2001           for (int i = listeners.length-2; i>=0; i-=2) {
 2002               if (listeners[i]==ActionListener.class) {
 2003                   // Lazily create the event:
 2004                   if (e == null) {
 2005                         String actionCommand = event.getActionCommand();
 2006                         if(actionCommand == null) {
 2007                            actionCommand = getActionCommand();
 2008                         }
 2009                         e = new ActionEvent(AbstractButton.this,
 2010                                             ActionEvent.ACTION_PERFORMED,
 2011                                             actionCommand,
 2012                                             event.getWhen(),
 2013                                             event.getModifiers());
 2014                   }
 2015                   ((ActionListener)listeners[i+1]).actionPerformed(e);
 2016               }
 2017           }
 2018       }
 2019   
 2020       /**
 2021        * Notifies all listeners that have registered interest for
 2022        * notification on this event type.  The event instance
 2023        * is lazily created using the <code>event</code> parameter.
 2024        *
 2025        * @param event  the <code>ItemEvent</code> object
 2026        * @see EventListenerList
 2027        */
 2028       protected void fireItemStateChanged(ItemEvent event) {
 2029           // Guaranteed to return a non-null array
 2030           Object[] listeners = listenerList.getListenerList();
 2031           ItemEvent e = null;
 2032           // Process the listeners last to first, notifying
 2033           // those that are interested in this event
 2034           for (int i = listeners.length-2; i>=0; i-=2) {
 2035               if (listeners[i]==ItemListener.class) {
 2036                   // Lazily create the event:
 2037                   if (e == null) {
 2038                       e = new ItemEvent(AbstractButton.this,
 2039                                         ItemEvent.ITEM_STATE_CHANGED,
 2040                                         AbstractButton.this,
 2041                                         event.getStateChange());
 2042                   }
 2043                   ((ItemListener)listeners[i+1]).itemStateChanged(e);
 2044               }
 2045           }
 2046           if (accessibleContext != null) {
 2047               if (event.getStateChange() == ItemEvent.SELECTED) {
 2048                   accessibleContext.firePropertyChange(
 2049                       AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
 2050                       null, AccessibleState.SELECTED);
 2051                   accessibleContext.firePropertyChange(
 2052                       AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
 2053                       Integer.valueOf(0), Integer.valueOf(1));
 2054               } else {
 2055                   accessibleContext.firePropertyChange(
 2056                       AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
 2057                       AccessibleState.SELECTED, null);
 2058                   accessibleContext.firePropertyChange(
 2059                       AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
 2060                       Integer.valueOf(1), Integer.valueOf(0));
 2061               }
 2062           }
 2063       }
 2064   
 2065   
 2066       protected ActionListener createActionListener() {
 2067           return getHandler();
 2068       }
 2069   
 2070   
 2071       protected ItemListener createItemListener() {
 2072           return getHandler();
 2073       }
 2074   
 2075   
 2076       /**
 2077        * Enables (or disables) the button.
 2078        * @param b  true to enable the button, otherwise false
 2079        */
 2080       public void setEnabled(boolean b) {
 2081           if (!b && model.isRollover()) {
 2082               model.setRollover(false);
 2083           }
 2084           super.setEnabled(b);
 2085           model.setEnabled(b);
 2086       }
 2087   
 2088       // *** Deprecated java.awt.Button APIs below *** //
 2089   
 2090       /**
 2091        * Returns the label text.
 2092        *
 2093        * @return a <code>String</code> containing the label
 2094        * @deprecated - Replaced by <code>getText</code>
 2095        */
 2096       @Deprecated
 2097       public String getLabel() {
 2098           return getText();
 2099       }
 2100   
 2101       /**
 2102        * Sets the label text.
 2103        *
 2104        * @param label  a <code>String</code> containing the text
 2105        * @deprecated - Replaced by <code>setText(text)</code>
 2106        * @beaninfo
 2107        *        bound: true
 2108        *  description: Replace by setText(text)
 2109        */
 2110       @Deprecated
 2111       public void setLabel(String label) {
 2112           setText(label);
 2113       }
 2114   
 2115       /**
 2116        * Adds an <code>ItemListener</code> to the <code>checkbox</code>.
 2117        * @param l  the <code>ItemListener</code> to be added
 2118        */
 2119       public void addItemListener(ItemListener l) {
 2120           listenerList.add(ItemListener.class, l);
 2121       }
 2122   
 2123       /**
 2124        * Removes an <code>ItemListener</code> from the button.
 2125        * @param l the <code>ItemListener</code> to be removed
 2126        */
 2127       public void removeItemListener(ItemListener l) {
 2128           listenerList.remove(ItemListener.class, l);
 2129       }
 2130   
 2131       /**
 2132        * Returns an array of all the <code>ItemListener</code>s added
 2133        * to this AbstractButton with addItemListener().
 2134        *
 2135        * @return all of the <code>ItemListener</code>s added or an empty
 2136        *         array if no listeners have been added
 2137        * @since 1.4
 2138        */
 2139       public ItemListener[] getItemListeners() {
 2140           return (ItemListener[])listenerList.getListeners(ItemListener.class);
 2141       }
 2142   
 2143      /**
 2144        * Returns an array (length 1) containing the label or
 2145        * <code>null</code> if the button is not selected.
 2146        *
 2147        * @return an array containing 1 Object: the text of the button,
 2148        *         if the item is selected; otherwise <code>null</code>
 2149        */
 2150       public Object[] getSelectedObjects() {
 2151           if (isSelected() == false) {
 2152               return null;
 2153           }
 2154           Object[] selectedObjects = new Object[1];
 2155           selectedObjects[0] = getText();
 2156           return selectedObjects;
 2157       }
 2158   
 2159       protected void init(String text, Icon icon) {
 2160           if(text != null) {
 2161               setText(text);
 2162           }
 2163   
 2164           if(icon != null) {
 2165               setIcon(icon);
 2166           }
 2167   
 2168           // Set the UI
 2169           updateUI();
 2170   
 2171           setAlignmentX(LEFT_ALIGNMENT);
 2172           setAlignmentY(CENTER_ALIGNMENT);
 2173       }
 2174   
 2175   
 2176       /**
 2177        * This is overridden to return false if the current <code>Icon</code>'s
 2178        * <code>Image</code> is not equal to the
 2179        * passed in <code>Image</code> <code>img</code>.
 2180        *
 2181        * @param img  the <code>Image</code> to be compared
 2182        * @param infoflags flags used to repaint the button when the image
 2183        *          is updated and which determine how much is to be painted
 2184        * @param x  the x coordinate
 2185        * @param y  the y coordinate
 2186        * @param w  the width
 2187        * @param h  the height
 2188        * @see     java.awt.image.ImageObserver
 2189        * @see     java.awt.Component#imageUpdate(java.awt.Image, int, int, int, int, int)
 2190        */
 2191       public boolean imageUpdate(Image img, int infoflags,
 2192                                  int x, int y, int w, int h) {
 2193           Icon iconDisplayed = getIcon();
 2194           if (iconDisplayed == null) {
 2195               return false;
 2196           }
 2197   
 2198           if (!model.isEnabled()) {
 2199               if (model.isSelected()) {
 2200                   iconDisplayed = getDisabledSelectedIcon();
 2201               } else {
 2202                   iconDisplayed = getDisabledIcon();
 2203               }
 2204           } else if (model.isPressed() && model.isArmed()) {
 2205               iconDisplayed = getPressedIcon();
 2206           } else if (isRolloverEnabled() && model.isRollover()) {
 2207               if (model.isSelected()) {
 2208                   iconDisplayed = getRolloverSelectedIcon();
 2209               } else {
 2210                   iconDisplayed = getRolloverIcon();
 2211               }
 2212           } else if (model.isSelected()) {
 2213               iconDisplayed = getSelectedIcon();
 2214           }
 2215   
 2216           if (!SwingUtilities.doesIconReferenceImage(iconDisplayed, img)) {
 2217               // We don't know about this image, disable the notification so
 2218               // we don't keep repainting.
 2219               return false;
 2220           }
 2221           return super.imageUpdate(img, infoflags, x, y, w, h);
 2222       }
 2223   
 2224       void setUIProperty(String propertyName, Object value) {
 2225           if (propertyName == "borderPainted") {
 2226               if (!borderPaintedSet) {
 2227                   setBorderPainted(((Boolean)value).booleanValue());
 2228                   borderPaintedSet = false;
 2229               }
 2230           } else if (propertyName == "rolloverEnabled") {
 2231               if (!rolloverEnabledSet) {
 2232                   setRolloverEnabled(((Boolean)value).booleanValue());
 2233                   rolloverEnabledSet = false;
 2234               }
 2235           } else if (propertyName == "iconTextGap") {
 2236               if (!iconTextGapSet) {
 2237                   setIconTextGap(((Number)value).intValue());
 2238                   iconTextGapSet = false;
 2239               }
 2240           } else if (propertyName == "contentAreaFilled") {
 2241               if (!contentAreaFilledSet) {
 2242                   setContentAreaFilled(((Boolean)value).booleanValue());
 2243                   contentAreaFilledSet = false;
 2244               }
 2245           } else {
 2246               super.setUIProperty(propertyName, value);
 2247           }
 2248       }
 2249   
 2250       /**
 2251        * Returns a string representation of this <code>AbstractButton</code>.
 2252        * This method
 2253        * is intended to be used only for debugging purposes, and the
 2254        * content and format of the returned string may vary between
 2255        * implementations. The returned string may be empty but may not
 2256        * be <code>null</code>.
 2257        * <P>
 2258        * Overriding <code>paramString</code> to provide information about the
 2259        * specific new aspects of the JFC components.
 2260        *
 2261        * @return  a string representation of this <code>AbstractButton</code>
 2262        */
 2263       protected String paramString() {
 2264           String defaultIconString = ((defaultIcon != null)
 2265                                       && (defaultIcon != this) ?
 2266                                       defaultIcon.toString() : "");
 2267           String pressedIconString = ((pressedIcon != null)
 2268                                       && (pressedIcon != this) ?
 2269                                       pressedIcon.toString() : "");
 2270           String disabledIconString = ((disabledIcon != null)
 2271                                        && (disabledIcon != this) ?
 2272                                        disabledIcon.toString() : "");
 2273           String selectedIconString = ((selectedIcon != null)
 2274                                        && (selectedIcon != this) ?
 2275                                        selectedIcon.toString() : "");
 2276           String disabledSelectedIconString = ((disabledSelectedIcon != null) &&
 2277                                                (disabledSelectedIcon != this) ?
 2278                                                disabledSelectedIcon.toString()
 2279                                                : "");
 2280           String rolloverIconString = ((rolloverIcon != null)
 2281                                        && (rolloverIcon != this) ?
 2282                                        rolloverIcon.toString() : "");
 2283           String rolloverSelectedIconString = ((rolloverSelectedIcon != null) &&
 2284                                                (rolloverSelectedIcon != this) ?
 2285                                                rolloverSelectedIcon.toString()
 2286                                                : "");
 2287           String paintBorderString = (paintBorder ? "true" : "false");
 2288           String paintFocusString = (paintFocus ? "true" : "false");
 2289           String rolloverEnabledString = (rolloverEnabled ? "true" : "false");
 2290   
 2291           return super.paramString() +
 2292           ",defaultIcon=" + defaultIconString +
 2293           ",disabledIcon=" + disabledIconString +
 2294           ",disabledSelectedIcon=" + disabledSelectedIconString +
 2295           ",margin=" + margin +
 2296           ",paintBorder=" + paintBorderString +
 2297           ",paintFocus=" + paintFocusString +
 2298           ",pressedIcon=" + pressedIconString +
 2299           ",rolloverEnabled=" + rolloverEnabledString +
 2300           ",rolloverIcon=" + rolloverIconString +
 2301           ",rolloverSelectedIcon=" + rolloverSelectedIconString +
 2302           ",selectedIcon=" + selectedIconString +
 2303           ",text=" + text;
 2304       }
 2305   
 2306   
 2307       private Handler getHandler() {
 2308           if (handler == null) {
 2309               handler = new Handler();
 2310           }
 2311           return handler;
 2312       }
 2313   
 2314   
 2315       //
 2316       // Listeners that are added to model
 2317       //
 2318       class Handler implements ActionListener, ChangeListener, ItemListener,
 2319                                Serializable {
 2320           //
 2321           // ChangeListener
 2322           //
 2323           public void stateChanged(ChangeEvent e) {
 2324               Object source = e.getSource();
 2325   
 2326               updateMnemonicProperties();
 2327               if (isEnabled() != model.isEnabled()) {
 2328                   setEnabled(model.isEnabled());
 2329               }
 2330               fireStateChanged();
 2331               repaint();
 2332           }
 2333   
 2334           //
 2335           // ActionListener
 2336           //
 2337           public void actionPerformed(ActionEvent event) {
 2338               fireActionPerformed(event);
 2339           }
 2340   
 2341           //
 2342           // ItemListener
 2343           //
 2344           public void itemStateChanged(ItemEvent event) {
 2345               fireItemStateChanged(event);
 2346               if (shouldUpdateSelectedStateFromAction()) {
 2347                   Action action = getAction();
 2348                   if (action != null && AbstractAction.hasSelectedKey(action)) {
 2349                       boolean selected = isSelected();
 2350                       boolean isActionSelected = AbstractAction.isSelected(
 2351                                 action);
 2352                       if (isActionSelected != selected) {
 2353                           action.putValue(Action.SELECTED_KEY, selected);
 2354                       }
 2355                   }
 2356               }
 2357           }
 2358       }
 2359   
 2360   ///////////////////
 2361   // Accessibility support
 2362   ///////////////////
 2363       /**
 2364        * This class implements accessibility support for the
 2365        * <code>AbstractButton</code> class.  It provides an implementation of the
 2366        * Java Accessibility API appropriate to button and menu item
 2367        * user-interface elements.
 2368        * <p>
 2369        * <strong>Warning:</strong>
 2370        * Serialized objects of this class will not be compatible with
 2371        * future Swing releases. The current serialization support is
 2372        * appropriate for short term storage or RMI between applications running
 2373        * the same version of Swing.  As of 1.4, support for long term storage
 2374        * of all JavaBeans<sup><font size="-2">TM</font></sup>
 2375        * has been added to the <code>java.beans</code> package.
 2376        * Please see {@link java.beans.XMLEncoder}.
 2377        * @since 1.4
 2378        */
 2379       protected abstract class AccessibleAbstractButton
 2380           extends AccessibleJComponent implements AccessibleAction,
 2381           AccessibleValue, AccessibleText, AccessibleExtendedComponent {
 2382   
 2383           /**
 2384            * Returns the accessible name of this object.
 2385            *
 2386            * @return the localized name of the object -- can be
 2387            *              <code>null</code> if this
 2388            *              object does not have a name
 2389            */
 2390           public String getAccessibleName() {
 2391               String name = accessibleName;
 2392   
 2393               if (name == null) {
 2394                   name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
 2395               }
 2396               if (name == null) {
 2397                   name = AbstractButton.this.getText();
 2398               }
 2399               if (name == null) {
 2400                   name = super.getAccessibleName();
 2401               }
 2402               return name;
 2403           }
 2404   
 2405           /**
 2406            * Get the AccessibleIcons associated with this object if one
 2407            * or more exist.  Otherwise return null.
 2408            * @since 1.3
 2409            */
 2410           public AccessibleIcon [] getAccessibleIcon() {
 2411               Icon defaultIcon = getIcon();
 2412   
 2413               if (defaultIcon instanceof Accessible) {
 2414                   AccessibleContext ac =
 2415                       ((Accessible)defaultIcon).getAccessibleContext();
 2416                   if (ac != null && ac instanceof AccessibleIcon) {
 2417                       return new AccessibleIcon[] { (AccessibleIcon)ac };
 2418                   }
 2419               }
 2420               return null;
 2421           }
 2422   
 2423           /**
 2424            * Get the state set of this object.
 2425            *
 2426            * @return an instance of AccessibleState containing the current state
 2427            * of the object
 2428            * @see AccessibleState
 2429            */
 2430           public AccessibleStateSet getAccessibleStateSet() {
 2431           AccessibleStateSet states = super.get