Save This Page
Home » openjdk-7 » javax » swing » [javadoc | source]
    1   /*
    2    * Copyright (c) 1997, 2011, Oracle and/or its affiliates. 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.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * 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 = ((DefaultButtonModel)getModel()).getGroup();
 1319                       if (group != null) {
 1320                           group.clearSelection();
 1321                       }
 1322                   }
 1323               }
 1324           }
 1325       }
 1326   
 1327       /**
 1328        * Creates and returns a <code>PropertyChangeListener</code> that is
 1329        * responsible for listening for changes from the specified
 1330        * <code>Action</code> and updating the appropriate properties.
 1331        * <p>
 1332        * <b>Warning:</b> If you subclass this do not create an anonymous
 1333        * inner class.  If you do the lifetime of the button will be tied to
 1334        * that of the <code>Action</code>.
 1335        *
 1336        * @param a the button's action
 1337        * @since 1.3
 1338        * @see Action
 1339        * @see #setAction
 1340        */
 1341       protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
 1342           return createActionPropertyChangeListener0(a);
 1343       }
 1344   
 1345   
 1346       PropertyChangeListener createActionPropertyChangeListener0(Action a) {
 1347           return new ButtonActionPropertyChangeListener(this, a);
 1348       }
 1349   
 1350       private static class ButtonActionPropertyChangeListener
 1351                    extends ActionPropertyChangeListener<AbstractButton> {
 1352           ButtonActionPropertyChangeListener(AbstractButton b, Action a) {
 1353               super(b, a);
 1354           }
 1355           protected void actionPropertyChanged(AbstractButton button,
 1356                                                Action action,
 1357                                                PropertyChangeEvent e) {
 1358               if (AbstractAction.shouldReconfigure(e)) {
 1359                   button.configurePropertiesFromAction(action);
 1360               } else {
 1361                   button.actionPropertyChanged(action, e.getPropertyName());
 1362               }
 1363           }
 1364       }
 1365   
 1366       /**
 1367        * Gets the <code>borderPainted</code> property.
 1368        *
 1369        * @return the value of the <code>borderPainted</code> property
 1370        * @see #setBorderPainted
 1371        */
 1372       public boolean isBorderPainted() {
 1373           return paintBorder;
 1374       }
 1375   
 1376       /**
 1377        * Sets the <code>borderPainted</code> property.
 1378        * If <code>true</code> and the button has a border,
 1379        * the border is painted. The default value for the
 1380        * <code>borderPainted</code> property is <code>true</code>.
 1381        * <p/>
 1382        * Some look and feels might not support
 1383        * the <code>borderPainted</code> property,
 1384        * in which case they ignore this.
 1385        *
 1386        * @param b if true and border property is not <code>null</code>,
 1387        *          the border is painted
 1388        * @see #isBorderPainted
 1389        * @beaninfo
 1390        *        bound: true
 1391        *    attribute: visualUpdate true
 1392        *  description: Whether the border should be painted.
 1393        */
 1394       public void setBorderPainted(boolean b) {
 1395           boolean oldValue = paintBorder;
 1396           paintBorder = b;
 1397           borderPaintedSet = true;
 1398           firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, oldValue, paintBorder);
 1399           if (b != oldValue) {
 1400               revalidate();
 1401               repaint();
 1402           }
 1403       }
 1404   
 1405       /**
 1406        * Paint the button's border if <code>BorderPainted</code>
 1407        * property is true and the button has a border.
 1408        * @param g the <code>Graphics</code> context in which to paint
 1409        *
 1410        * @see #paint
 1411        * @see #setBorder
 1412        */
 1413       protected void paintBorder(Graphics g) {
 1414           if (isBorderPainted()) {
 1415               super.paintBorder(g);
 1416           }
 1417       }
 1418   
 1419       /**
 1420        * Gets the <code>paintFocus</code> property.
 1421        *
 1422        * @return the <code>paintFocus</code> property
 1423        * @see #setFocusPainted
 1424        */
 1425       public boolean isFocusPainted() {
 1426           return paintFocus;
 1427       }
 1428   
 1429       /**
 1430        * Sets the <code>paintFocus</code> property, which must
 1431        * be <code>true</code> for the focus state to be painted.
 1432        * The default value for the <code>paintFocus</code> property
 1433        * is <code>true</code>.
 1434        * Some look and feels might not paint focus state;
 1435        * they will ignore this property.
 1436        *
 1437        * @param b if <code>true</code>, the focus state should be painted
 1438        * @see #isFocusPainted
 1439        * @beaninfo
 1440        *        bound: true
 1441        *    attribute: visualUpdate true
 1442        *  description: Whether focus should be painted
 1443        */
 1444       public void setFocusPainted(boolean b) {
 1445           boolean oldValue = paintFocus;
 1446           paintFocus = b;
 1447           firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, oldValue, paintFocus);
 1448           if (b != oldValue && isFocusOwner()) {
 1449               revalidate();
 1450               repaint();
 1451           }
 1452       }
 1453   
 1454       /**
 1455        * Gets the <code>contentAreaFilled</code> property.
 1456        *
 1457        * @return the <code>contentAreaFilled</code> property
 1458        * @see #setContentAreaFilled
 1459        */
 1460       public boolean isContentAreaFilled() {
 1461           return contentAreaFilled;
 1462       }
 1463   
 1464       /**
 1465        * Sets the <code>contentAreaFilled</code> property.
 1466        * If <code>true</code> the button will paint the content
 1467        * area.  If you wish to have a transparent button, such as
 1468        * an icon only button, for example, then you should set
 1469        * this to <code>false</code>. Do not call <code>setOpaque(false)</code>.
 1470        * The default value for the the <code>contentAreaFilled</code>
 1471        * property is <code>true</code>.
 1472        * <p>
 1473        * This function may cause the component's opaque property to change.
 1474        * <p>
 1475        * The exact behavior of calling this function varies on a
 1476        * component-by-component and L&F-by-L&F basis.
 1477        *
 1478        * @param b if true, the content should be filled; if false
 1479        *          the content area is not filled
 1480        * @see #isContentAreaFilled
 1481        * @see #setOpaque
 1482        * @beaninfo
 1483        *        bound: true
 1484        *    attribute: visualUpdate true
 1485        *  description: Whether the button should paint the content area
 1486        *               or leave it transparent.
 1487        */
 1488       public void setContentAreaFilled(boolean b) {
 1489           boolean oldValue = contentAreaFilled;
 1490           contentAreaFilled = b;
 1491           contentAreaFilledSet = true;
 1492           firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, oldValue, contentAreaFilled);
 1493           if (b != oldValue) {
 1494               repaint();
 1495           }
 1496       }
 1497   
 1498       /**
 1499        * Gets the <code>rolloverEnabled</code> property.
 1500        *
 1501        * @return the value of the <code>rolloverEnabled</code> property
 1502        * @see #setRolloverEnabled
 1503        */
 1504       public boolean isRolloverEnabled() {
 1505           return rolloverEnabled;
 1506       }
 1507   
 1508       /**
 1509        * Sets the <code>rolloverEnabled</code> property, which
 1510        * must be <code>true</code> for rollover effects to occur.
 1511        * The default value for the <code>rolloverEnabled</code>
 1512        * property is <code>false</code>.
 1513        * Some look and feels might not implement rollover effects;
 1514        * they will ignore this property.
 1515        *
 1516        * @param b if <code>true</code>, rollover effects should be painted
 1517        * @see #isRolloverEnabled
 1518        * @beaninfo
 1519        *        bound: true
 1520        *    attribute: visualUpdate true
 1521        *  description: Whether rollover effects should be enabled.
 1522        */
 1523       public void setRolloverEnabled(boolean b) {
 1524           boolean oldValue = rolloverEnabled;
 1525           rolloverEnabled = b;
 1526           rolloverEnabledSet = true;
 1527           firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, oldValue, rolloverEnabled);
 1528           if (b != oldValue) {
 1529               repaint();
 1530           }
 1531       }
 1532   
 1533       /**
 1534        * Returns the keyboard mnemonic from the the current model.
 1535        * @return the keyboard mnemonic from the model
 1536        */
 1537       public int getMnemonic() {
 1538           return mnemonic;
 1539       }
 1540   
 1541       /**
 1542        * Sets the keyboard mnemonic on the current model.
 1543        * The mnemonic is the key which when combined with the look and feel's
 1544        * mouseless modifier (usually Alt) will activate this button
 1545        * if focus is contained somewhere within this button's ancestor
 1546        * window.
 1547        * <p>
 1548        * A mnemonic must correspond to a single key on the keyboard
 1549        * and should be specified using one of the <code>VK_XXX</code>
 1550        * keycodes defined in <code>java.awt.event.KeyEvent</code>.
 1551        * These codes and the wider array of codes for international
 1552        * keyboards may be obtained through
 1553        * <code>java.awt.event.KeyEvent.getExtendedKeyCodeForChar</code>.
 1554        * Mnemonics are case-insensitive, therefore a key event
 1555        * with the corresponding keycode would cause the button to be
 1556        * activated whether or not the Shift modifier was pressed.
 1557        * <p>
 1558        * If the character defined by the mnemonic is found within
 1559        * the button's label string, the first occurrence of it
 1560        * will be underlined to indicate the mnemonic to the user.
 1561        *
 1562        * @param mnemonic the key code which represents the mnemonic
 1563        * @see     java.awt.event.KeyEvent
 1564        * @see     #setDisplayedMnemonicIndex
 1565        *
 1566        * @beaninfo
 1567        *        bound: true
 1568        *    attribute: visualUpdate true
 1569        *  description: the keyboard character mnemonic
 1570        */
 1571       public void setMnemonic(int mnemonic) {
 1572           int oldValue = getMnemonic();
 1573           model.setMnemonic(mnemonic);
 1574           updateMnemonicProperties();
 1575       }
 1576   
 1577       /**
 1578        * This method is now obsolete, please use <code>setMnemonic(int)</code>
 1579        * to set the mnemonic for a button.  This method is only designed
 1580        * to handle character values which fall between 'a' and 'z' or
 1581        * 'A' and 'Z'.
 1582        *
 1583        * @param mnemonic  a char specifying the mnemonic value
 1584        * @see #setMnemonic(int)
 1585        * @beaninfo
 1586        *        bound: true
 1587        *    attribute: visualUpdate true
 1588        *  description: the keyboard character mnemonic
 1589        */
 1590       public void setMnemonic(char mnemonic) {
 1591           int vk = (int) mnemonic;
 1592           if(vk >= 'a' && vk <='z')
 1593               vk -= ('a' - 'A');
 1594           setMnemonic(vk);
 1595       }
 1596   
 1597       /**
 1598        * Provides a hint to the look and feel as to which character in the
 1599        * text should be decorated to represent the mnemonic. Not all look and
 1600        * feels may support this. A value of -1 indicates either there is no
 1601        * mnemonic, the mnemonic character is not contained in the string, or
 1602        * the developer does not wish the mnemonic to be displayed.
 1603        * <p>
 1604        * The value of this is updated as the properties relating to the
 1605        * mnemonic change (such as the mnemonic itself, the text...).
 1606        * You should only ever have to call this if
 1607        * you do not wish the default character to be underlined. For example, if
 1608        * the text was 'Save As', with a mnemonic of 'a', and you wanted the 'A'
 1609        * to be decorated, as 'Save <u>A</u>s', you would have to invoke
 1610        * <code>setDisplayedMnemonicIndex(5)</code> after invoking
 1611        * <code>setMnemonic(KeyEvent.VK_A)</code>.
 1612        *
 1613        * @since 1.4
 1614        * @param index Index into the String to underline
 1615        * @exception IllegalArgumentException will be thrown if <code>index</code>
 1616        *            is &gt;= length of the text, or &lt; -1
 1617        * @see #getDisplayedMnemonicIndex
 1618        *
 1619        * @beaninfo
 1620        *        bound: true
 1621        *    attribute: visualUpdate true
 1622        *  description: the index into the String to draw the keyboard character
 1623        *               mnemonic at
 1624        */
 1625       public void setDisplayedMnemonicIndex(int index)
 1626                                             throws IllegalArgumentException {
 1627           int oldValue = mnemonicIndex;
 1628           if (index == -1) {
 1629               mnemonicIndex = -1;
 1630           } else {
 1631               String text = getText();
 1632               int textLength = (text == null) ? 0 : text.length();
 1633               if (index < -1 || index >= textLength) {  // index out of range
 1634                   throw new IllegalArgumentException("index == " + index);
 1635               }
 1636           }
 1637           mnemonicIndex = index;
 1638           firePropertyChange("displayedMnemonicIndex", oldValue, index);
 1639           if (index != oldValue) {
 1640               revalidate();
 1641               repaint();
 1642           }
 1643       }
 1644   
 1645       /**
 1646        * Returns the character, as an index, that the look and feel should
 1647        * provide decoration for as representing the mnemonic character.
 1648        *
 1649        * @since 1.4
 1650        * @return index representing mnemonic character
 1651        * @see #setDisplayedMnemonicIndex
 1652        */
 1653       public int getDisplayedMnemonicIndex() {
 1654           return mnemonicIndex;
 1655       }
 1656   
 1657       /**
 1658        * Update the displayedMnemonicIndex property. This method
 1659        * is called when either text or mnemonic changes. The new
 1660        * value of the displayedMnemonicIndex property is the index
 1661        * of the first occurrence of mnemonic in text.
 1662        */
 1663       private void updateDisplayedMnemonicIndex(String text, int mnemonic) {
 1664           setDisplayedMnemonicIndex(
 1665               SwingUtilities.findDisplayedMnemonicIndex(text, mnemonic));
 1666       }
 1667   
 1668       /**
 1669        * Brings the mnemonic property in accordance with model's mnemonic.
 1670        * This is called when model's mnemonic changes. Also updates the
 1671        * displayedMnemonicIndex property.
 1672        */
 1673       private void updateMnemonicProperties() {
 1674           int newMnemonic = model.getMnemonic();
 1675           if (mnemonic != newMnemonic) {
 1676               int oldValue = mnemonic;
 1677               mnemonic = newMnemonic;
 1678               firePropertyChange(MNEMONIC_CHANGED_PROPERTY,
 1679                                  oldValue, mnemonic);
 1680               updateDisplayedMnemonicIndex(getText(), mnemonic);
 1681               revalidate();
 1682               repaint();
 1683           }
 1684       }
 1685   
 1686       /**
 1687        * Sets the amount of time (in milliseconds) required between
 1688        * mouse press events for the button to generate the corresponding
 1689        * action events.  After the initial mouse press occurs (and action
 1690        * event generated) any subsequent mouse press events which occur
 1691        * on intervals less than the threshhold will be ignored and no
 1692        * corresponding action event generated.  By default the threshhold is 0,
 1693        * which means that for each mouse press, an action event will be
 1694        * fired, no matter how quickly the mouse clicks occur.  In buttons
 1695        * where this behavior is not desirable (for example, the "OK" button
 1696        * in a dialog), this threshhold should be set to an appropriate
 1697        * positive value.
 1698        *
 1699        * @see #getMultiClickThreshhold
 1700        * @param threshhold the amount of time required between mouse
 1701        *        press events to generate corresponding action events
 1702        * @exception   IllegalArgumentException if threshhold < 0
 1703        * @since 1.4
 1704        */
 1705       public void setMultiClickThreshhold(long threshhold) {
 1706           if (threshhold < 0) {
 1707               throw new IllegalArgumentException("threshhold must be >= 0");
 1708           }
 1709           this.multiClickThreshhold = threshhold;
 1710       }
 1711   
 1712       /**
 1713        * Gets the amount of time (in milliseconds) required between
 1714        * mouse press events for the button to generate the corresponding
 1715        * action events.
 1716        *
 1717        * @see #setMultiClickThreshhold
 1718        * @return the amount of time required between mouse press events
 1719        *         to generate corresponding action events
 1720        * @since 1.4
 1721        */
 1722       public long getMultiClickThreshhold() {
 1723           return multiClickThreshhold;
 1724       }
 1725   
 1726       /**
 1727        * Returns the model that this button represents.
 1728        * @return the <code>model</code> property
 1729        * @see #setModel
 1730        */
 1731       public ButtonModel getModel() {
 1732           return model;
 1733       }
 1734   
 1735       /**
 1736        * Sets the model that this button represents.
 1737        * @param newModel the new <code>ButtonModel</code>
 1738        * @see #getModel
 1739        * @beaninfo
 1740        *        bound: true
 1741        *  description: Model that the Button uses.
 1742        */
 1743       public void setModel(ButtonModel newModel) {
 1744   
 1745           ButtonModel oldModel = getModel();
 1746   
 1747           if (oldModel != null) {
 1748               oldModel.removeChangeListener(changeListener);
 1749               oldModel.removeActionListener(actionListener);
 1750               oldModel.removeItemListener(itemListener);
 1751               changeListener = null;
 1752               actionListener = null;
 1753               itemListener = null;
 1754           }
 1755   
 1756           model = newModel;
 1757   
 1758           if (newModel != null) {
 1759               changeListener = createChangeListener();
 1760               actionListener = createActionListener();
 1761               itemListener = createItemListener();
 1762               newModel.addChangeListener(changeListener);
 1763               newModel.addActionListener(actionListener);
 1764               newModel.addItemListener(itemListener);
 1765   
 1766               updateMnemonicProperties();
 1767               //We invoke setEnabled() from JComponent
 1768               //because setModel() can be called from a constructor
 1769               //when the button is not fully initialized
 1770               super.setEnabled(newModel.isEnabled());
 1771   
 1772           } else {
 1773               mnemonic = '\0';
 1774           }
 1775   
 1776           updateDisplayedMnemonicIndex(getText(), mnemonic);
 1777   
 1778           firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel);
 1779           if (newModel != oldModel) {
 1780               revalidate();
 1781               repaint();
 1782           }
 1783       }
 1784   
 1785   
 1786       /**
 1787        * Returns the L&F object that renders this component.
 1788        * @return the ButtonUI object
 1789        * @see #setUI
 1790        */
 1791       public ButtonUI getUI() {
 1792           return (ButtonUI) ui;
 1793       }
 1794   
 1795   
 1796       /**
 1797        * Sets the L&F object that renders this component.
 1798        * @param ui the <code>ButtonUI</code> L&F object
 1799        * @see #getUI
 1800        * @beaninfo
 1801        *        bound: true
 1802        *       hidden: true
 1803        *    attribute: visualUpdate true
 1804        *  description: The UI object that implements the LookAndFeel.
 1805        */
 1806       public void setUI(ButtonUI ui) {
 1807           super.setUI(ui);
 1808           // disabled icons are generated by the LF so they should be unset here
 1809           if (disabledIcon instanceof UIResource) {
 1810               setDisabledIcon(null);
 1811           }
 1812           if (disabledSelectedIcon instanceof UIResource) {
 1813               setDisabledSelectedIcon(null);
 1814           }
 1815       }
 1816   
 1817   
 1818       /**
 1819        * Resets the UI property to a value from the current look
 1820        * and feel.  Subtypes of <code>AbstractButton</code>
 1821        * should override this to update the UI. For
 1822        * example, <code>JButton</code> might do the following:
 1823        * <pre>
 1824        *      setUI((ButtonUI)UIManager.getUI(
 1825        *          "ButtonUI", "javax.swing.plaf.basic.BasicButtonUI", this));
 1826        * </pre>
 1827        */
 1828       public void updateUI() {
 1829       }
 1830   
 1831       /**
 1832        * Adds the specified component to this container at the specified
 1833        * index, refer to
 1834        * {@link java.awt.Container#addImpl(Component, Object, int)}
 1835        * for a complete description of this method.
 1836        *
 1837        * @param     comp the component to be added
 1838        * @param     constraints an object expressing layout constraints
 1839        *                 for this component
 1840        * @param     index the position in the container's list at which to
 1841        *                 insert the component, where <code>-1</code>
 1842        *                 means append to the end
 1843        * @exception IllegalArgumentException if <code>index</code> is invalid
 1844        * @exception IllegalArgumentException if adding the container's parent
 1845        *                  to itself
 1846        * @exception IllegalArgumentException if adding a window to a container
 1847        * @since 1.5
 1848        */
 1849       protected void addImpl(Component comp, Object constraints, int index) {
 1850           if (!setLayout) {
 1851               setLayout(new OverlayLayout(this));
 1852           }
 1853           super.addImpl(comp, constraints, index);
 1854       }
 1855   
 1856       /**
 1857        * Sets the layout manager for this container, refer to
 1858        * {@link java.awt.Container#setLayout(LayoutManager)}
 1859        * for a complete description of this method.
 1860        *
 1861        * @param mgr the specified layout manager
 1862        * @since 1.5
 1863        */
 1864       public void setLayout(LayoutManager mgr) {
 1865           setLayout = true;
 1866           super.setLayout(mgr);
 1867       }
 1868   
 1869       /**
 1870        * Adds a <code>ChangeListener</code> to the button.
 1871        * @param l the listener to be added
 1872        */
 1873       public void addChangeListener(ChangeListener l) {
 1874           listenerList.add(ChangeListener.class, l);
 1875       }
 1876   
 1877       /**
 1878        * Removes a ChangeListener from the button.
 1879        * @param l the listener to be removed
 1880        */
 1881       public void removeChangeListener(ChangeListener l) {
 1882           listenerList.remove(ChangeListener.class, l);
 1883       }
 1884   
 1885       /**
 1886        * Returns an array of all the <code>ChangeListener</code>s added
 1887        * to this AbstractButton with addChangeListener().
 1888        *
 1889        * @return all of the <code>ChangeListener</code>s added or an empty
 1890        *         array if no listeners have been added
 1891        * @since 1.4
 1892        */
 1893       public ChangeListener[] getChangeListeners() {
 1894           return listenerList.getListeners(ChangeListener.class);
 1895       }
 1896   
 1897       /**
 1898        * Notifies all listeners that have registered interest for
 1899        * notification on this event type.  The event instance
 1900        * is lazily created.
 1901        * @see EventListenerList
 1902        */
 1903       protected void fireStateChanged() {
 1904           // Guaranteed to return a non-null array
 1905           Object[] listeners = listenerList.getListenerList();
 1906           // Process the listeners last to first, notifying
 1907           // those that are interested in this event
 1908           for (int i = listeners.length-2; i>=0; i-=2) {
 1909               if (listeners[i]==ChangeListener.class) {
 1910                   // Lazily create the event:
 1911                   if (changeEvent == null)
 1912                       changeEvent = new ChangeEvent(this);
 1913                   ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
 1914               }
 1915           }
 1916       }
 1917   
 1918       /**
 1919        * Adds an <code>ActionListener</code> to the button.
 1920        * @param l the <code>ActionListener</code> to be added
 1921        */
 1922       public void addActionListener(ActionListener l) {
 1923           listenerList.add(ActionListener.class, l);
 1924       }
 1925   
 1926       /**
 1927        * Removes an <code>ActionListener</code> from the button.
 1928        * If the listener is the currently set <code>Action</code>
 1929        * for the button, then the <code>Action</code>
 1930        * is set to <code>null</code>.
 1931        *
 1932        * @param l the listener to be removed
 1933        */
 1934       public void removeActionListener(ActionListener l) {
 1935           if ((l != null) && (getAction() == l)) {
 1936               setAction(null);
 1937           } else {
 1938               listenerList.remove(ActionListener.class, l);
 1939           }
 1940       }
 1941   
 1942       /**
 1943        * Returns an array of all the <code>ActionListener</code>s added
 1944        * to this AbstractButton with addActionListener().
 1945        *
 1946        * @return all of the <code>ActionListener</code>s added or an empty
 1947        *         array if no listeners have been added
 1948        * @since 1.4
 1949        */
 1950       public ActionListener[] getActionListeners() {
 1951           return listenerList.getListeners(ActionListener.class);
 1952       }
 1953   
 1954       /**
 1955        * Subclasses that want to handle <code>ChangeEvents</code> differently
 1956        * can override this to return another <code>ChangeListener</code>
 1957        * implementation.
 1958        *
 1959        * @return the new <code>ChangeListener</code>
 1960        */
 1961       protected ChangeListener createChangeListener() {
 1962           return getHandler();
 1963       }
 1964   
 1965       /**
 1966        * Extends <code>ChangeListener</code> to be serializable.
 1967        * <p>
 1968        * <strong>Warning:</strong>
 1969        * Serialized objects of this class will not be compatible with
 1970        * future Swing releases. The current serialization support is
 1971        * appropriate for short term storage or RMI between applications running
 1972        * the same version of Swing.  As of 1.4, support for long term storage
 1973        * of all JavaBeans<sup><font size="-2">TM</font></sup>
 1974        * has been added to the <code>java.beans</code> package.
 1975        * Please see {@link java.beans.XMLEncoder}.
 1976        */
 1977       protected class ButtonChangeListener implements ChangeListener, Serializable {
 1978           // NOTE: This class is NOT used, instead the functionality has
 1979           // been moved to Handler.
 1980           ButtonChangeListener() {
 1981           }
 1982   
 1983           public void stateChanged(ChangeEvent e) {
 1984               getHandler().stateChanged(e);
 1985           }
 1986       }
 1987   
 1988   
 1989       /**
 1990        * Notifies all listeners that have registered interest for
 1991        * notification on this event type.  The event instance
 1992        * is lazily created using the <code>event</code>
 1993        * parameter.
 1994        *
 1995        * @param event  the <code>ActionEvent</code> object
 1996        * @see EventListenerList
 1997        */
 1998       protected void fireActionPerformed(ActionEvent event) {
 1999           // Guaranteed to return a non-null array
 2000           Object[] listeners = listenerList.getListenerList();
 2001           ActionEvent e = null;
 2002           // Process the listeners last to first, notifying
 2003           // those that are interested in this event
 2004           for (int i = listeners.length-2; i>=0; i-=2) {
 2005               if (listeners[i]==ActionListener.class) {
 2006                   // Lazily create the event:
 2007                   if (e == null) {
 2008                         String actionCommand = event.getActionCommand();
 2009                         if(actionCommand == null) {
 2010                            actionCommand = getActionCommand();
 2011                         }
 2012                         e = new ActionEvent(AbstractButton.this,
 2013                                             ActionEvent.ACTION_PERFORMED,
 2014                                             actionCommand,
 2015                                             event.getWhen(),
 2016                                             event.getModifiers());
 2017                   }
 2018                   ((ActionListener)listeners[i+1]).actionPerformed(e);
 2019               }
 2020           }
 2021       }
 2022   
 2023       /**
 2024        * Notifies all listeners that have registered interest for
 2025        * notification on this event type.  The event instance
 2026        * is lazily created using the <code>event</code> parameter.
 2027        *
 2028        * @param event  the <code>ItemEvent</code> object
 2029        * @see EventListenerList
 2030        */
 2031       protected void fireItemStateChanged(ItemEvent event) {
 2032           // Guaranteed to return a non-null array
 2033           Object[] listeners = listenerList.getListenerList();
 2034           ItemEvent e = null;
 2035           // Process the listeners last to first, notifying
 2036           // those that are interested in this event
 2037           for (int i = listeners.length-2; i>=0; i-=2) {
 2038               if (listeners[i]==ItemListener.class) {
 2039                   // Lazily create the event:
 2040                   if (e == null) {
 2041                       e = new ItemEvent(AbstractButton.this,
 2042                                         ItemEvent.ITEM_STATE_CHANGED,
 2043                                         AbstractButton.this,
 2044                                         event.getStateChange());
 2045                   }
 2046                   ((ItemListener)listeners[i+1]).itemStateChanged(e);
 2047               }
 2048           }
 2049           if (accessibleContext != null) {
 2050               if (event.getStateChange() == ItemEvent.SELECTED) {
 2051                   accessibleContext.firePropertyChange(
 2052                       AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
 2053                       null, AccessibleState.SELECTED);
 2054                   accessibleContext.firePropertyChange(
 2055                       AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
 2056                       Integer.valueOf(0), Integer.valueOf(1));
 2057               } else {
 2058                   accessibleContext.firePropertyChange(
 2059                       AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
 2060                       AccessibleState.SELECTED, null);
 2061                   accessibleContext.firePropertyChange(
 2062                       AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
 2063                       Integer.valueOf(1), Integer.valueOf(0));
 2064               }
 2065           }
 2066       }
 2067   
 2068   
 2069       protected ActionListener createActionListener() {
 2070           return getHandler();
 2071       }
 2072   
 2073   
 2074       protected ItemListener createItemListener() {
 2075           return getHandler();
 2076       }
 2077   
 2078   
 2079       /**
 2080        * Enables (or disables) the button.
 2081        * @param b  true to enable the button, otherwise false
 2082        */
 2083       public void setEnabled(boolean b) {
 2084           if (!b && model.isRollover()) {
 2085               model.setRollover(false);
 2086           }
 2087           super.setEnabled(b);
 2088           model.setEnabled(b);
 2089       }
 2090   
 2091       // *** Deprecated java.awt.Button APIs below *** //
 2092   
 2093       /**
 2094        * Returns the label text.
 2095        *
 2096        * @return a <code>String</code> containing the label
 2097        * @deprecated - Replaced by <code>getText</code>
 2098        */
 2099       @Deprecated
 2100       public String getLabel() {
 2101           return getText();
 2102       }
 2103   
 2104       /**
 2105        * Sets the label text.
 2106        *
 2107        * @param label  a <code>String</code> containing the text
 2108        * @deprecated - Replaced by <code>setText(text)</code>
 2109        * @beaninfo
 2110        *        bound: true
 2111        *  description: Replace by setText(text)
 2112        */
 2113       @Deprecated
 2114       public void setLabel(String label) {
 2115           setText(label);
 2116       }
 2117   
 2118       /**
 2119        * Adds an <code>ItemListener</code> to the <code>checkbox</code>.
 2120        * @param l  the <code>ItemListener</code> to be added
 2121        */
 2122       public void addItemListener(ItemListener l) {
 2123           listenerList.add(ItemListener.class, l);
 2124       }
 2125   
 2126       /**
 2127        * Removes an <code>ItemListener</code> from the button.
 2128        * @param l the <code>ItemListener</code> to be removed
 2129        */
 2130       public void removeItemListener(ItemListener l) {
 2131           listenerList.remove(ItemListener.class, l);
 2132       }
 2133   
 2134       /**
 2135        * Returns an array of all the <code>ItemListener</code>s added
 2136        * to this AbstractButton with addItemListener().
 2137        *
 2138        * @return all of the <code>ItemListener</code>s added or an empty
 2139        *         array if no listeners have been added
 2140        * @since 1.4
 2141        */
 2142       public ItemListener[] getItemListeners() {
 2143           return listenerList.getListeners(ItemListener.class);
 2144       }
 2145   
 2146      /**
 2147        * Returns an array (length 1) containing the label or
 2148        * <code>null</code> if the button is not selected.
 2149        *
 2150        * @return an array containing 1 Object: the text of the button,
 2151        *         if the item is selected; otherwise <code>null</code>
 2152        */
 2153       public Object[] getSelectedObjects() {
 2154           if (isSelected() == false) {
 2155               return null;
 2156           }
 2157           Object[] selectedObjects = new Object[1];
 2158           selectedObjects[0] = getText();
 2159           return selectedObjects;
 2160       }
 2161   
 2162       protected void init(String text, Icon icon) {
 2163           if(text != null) {
 2164               setText(text);
 2165           }
 2166   
 2167           if(icon != null) {
 2168               setIcon(icon);
 2169           }
 2170   
 2171           // Set the UI
 2172           updateUI();
 2173   
 2174           setAlignmentX(LEFT_ALIGNMENT);
 2175           setAlignmentY(CENTER_ALIGNMENT);
 2176       }
 2177   
 2178   
 2179       /**
 2180        * This is overridden to return false if the current <code>Icon</code>'s
 2181        * <code>Image</code> is not equal to the
 2182        * passed in <code>Image</code> <code>img</code>.
 2183        *
 2184        * @param img  the <code>Image</code> to be compared
 2185        * @param infoflags flags used to repaint the button when the image
 2186        *          is updated and which determine how much is to be painted
 2187        * @param x  the x coordinate
 2188        * @param y  the y coordinate
 2189        * @param w  the width
 2190        * @param h  the height
 2191        * @see     java.awt.image.ImageObserver
 2192        * @see     java.awt.Component#imageUpdate(java.awt.Image, int, int, int, int, int)
 2193        */
 2194       public boolean imageUpdate(Image img, int infoflags,
 2195                                  int x, int y, int w, int h) {
 2196           Icon iconDisplayed = getIcon();
 2197           if (iconDisplayed == null) {
 2198               return false;
 2199           }
 2200   
 2201           if (!model.isEnabled()) {
 2202               if (model.isSelected()) {
 2203                   iconDisplayed = getDisabledSelectedIcon();
 2204               } else {
 2205                   iconDisplayed = getDisabledIcon();
 2206               }
 2207           } else if (model.isPressed() && model.isArmed()) {
 2208               iconDisplayed = getPressedIcon();
 2209           } else if (isRolloverEnabled() && model.isRollover()) {
 2210               if (model.isSelected()) {
 2211                   iconDisplayed = getRolloverSelectedIcon();
 2212               } else {
 2213                   iconDisplayed = getRolloverIcon();
 2214               }
 2215           } else if (model.isSelected()) {
 2216               iconDisplayed = getSelectedIcon();
 2217           }
 2218   
 2219           if (!SwingUtilities.doesIconReferenceImage(iconDisplayed, img)) {
 2220               // We don't know about this image, disable the notification so
 2221               // we don't keep repainting.
 2222               return false;
 2223           }
 2224           return super.imageUpdate(img, infoflags, x, y, w, h);
 2225       }
 2226   
 2227       void setUIProperty(String propertyName, Object value) {
 2228           if (propertyName == "borderPainted") {
 2229               if (!borderPaintedSet) {
 2230                   setBorderPainted(((Boolean)value).booleanValue());
 2231                   borderPaintedSet = false;
 2232               }
 2233           } else if (propertyName == "rolloverEnabled") {
 2234               if (!rolloverEnabledSet) {
 2235                   setRolloverEnabled(((Boolean)value).booleanValue());
 2236                   rolloverEnabledSet = false;
 2237               }
 2238           } else if (propertyName == "iconTextGap") {
 2239               if (!iconTextGapSet) {
 2240                   setIconTextGap(((Number)value).intValue());
 2241                   iconTextGapSet = false;
 2242               }
 2243           } else if (propertyName == "contentAreaFilled") {
 2244               if (!contentAreaFilledSet) {
 2245                   setContentAreaFilled(((Boolean)value).booleanValue());
 2246                   contentAreaFilledSet = false;
 2247               }
 2248           } else {
 2249               super.setUIProperty(propertyName, value);
 2250           }
 2251       }
 2252   
 2253       /**
 2254        * Returns a string representation of this <code>AbstractButton</code>.
 2255        * This method
 2256        * is intended to be used only for debugging purposes, and the
 2257        * content and format of the returned string may vary between
 2258        * implementations. The returned string may be empty but may not
 2259        * be <code>null</code>.
 2260        * <P>
 2261        * Overriding <code>paramString</code> to provide information about the
 2262        * specific new aspects of the JFC components.
 2263        *
 2264        * @return  a string representation of this <code>AbstractButton</code>
 2265        */
 2266       protected String paramString() {
 2267           String defaultIconString = ((defaultIcon != null)
 2268                                       && (defaultIcon != this) ?
 2269                                       defaultIcon.toString() : "");
 2270           String pressedIconString = ((pressedIcon != null)
 2271                                       && (pressedIcon != this) ?
 2272                                       pressedIcon.toString() : "");
 2273           String disabledIconString = ((disabledIcon != null)
 2274                                        && (disabledIcon != this) ?
 2275                                        disabledIcon.toString() : "");
 2276           String selectedIconString = ((selectedIcon != null)
 2277                                        && (selectedIcon != this) ?
 2278                                        selectedIcon.toString() : "");
 2279           String disabledSelectedIconString = ((disabledSelectedIcon != null) &&
 2280                                                (disabledSelectedIcon != this) ?
 2281                                                disabledSelectedIcon.toString()
 2282                                                : "");
 2283           String rolloverIconString = ((rolloverIcon != null)
 2284                                        && (rolloverIcon != this) ?
 2285                                        rolloverIcon.toString() : "");
 2286           String rolloverSelectedIconString = ((rolloverSelectedIcon != null) &&
 2287                                                (rolloverSelectedIcon != this) ?
 2288                                                rolloverSelectedIcon.toString()
 2289                                                : "");
 2290           String paintBorderString = (paintBorder ? "true" : "false");
 2291           String paintFocusString = (paintFocus ? "true" : "false");
 2292           String rolloverEnabledString = (rolloverEnabled ? "true" : "false");
 2293   
 2294           return super.paramString() +
 2295           ",defaultIcon=" + defaultIconString +
 2296           ",disabledIcon=" + disabledIconString +
 2297           ",disabledSelectedIcon=" + disabledSelectedIconString +
 2298           ",margin=" + margin +
 2299           ",paintBorder=" + paintBorderString +
 2300           ",paintFocus=" + paintFocusString +
 2301           ",pressedIcon=" + pressedIconString +
 2302           ",rolloverEnabled=" + rolloverEnabledString +
 2303           ",rolloverIcon=" + rolloverIconString +
 2304           ",rolloverSelectedIcon=" + rolloverSelectedIconString +
 2305           ",selectedIcon=" + selectedIconString +
 2306           ",text=" + text;
 2307       }
 2308   
 2309   
 2310       private Handler getHandler() {
 2311           if (handler == null) {
 2312               handler = new Handler();
 2313           }
 2314           return handler;
 2315       }
 2316   
 2317   
 2318       //
 2319       // Listeners that are added to model
 2320       //
 2321       class Handler implements ActionListener, ChangeListener, ItemListener,
 2322                                Serializable {
 2323           //
 2324           // ChangeListener
 2325           //
 2326           public void stateChanged(ChangeEvent e) {
 2327               Object source = e.getSource();
 2328   
 2329               updateMnemonicProperties();
 2330               if (isEnabled() != model.isEnabled()) {
 2331                   setEnabled(model.isEnabled());
 2332               }
 2333               fireStateChanged();
 2334               repaint();
 2335           }
 2336   
 2337           //
 2338           // ActionListener
 2339           //
 2340           public void actionPerformed(ActionEvent event) {
 2341               fireActionPerformed(event);
 2342           }
 2343   
 2344           //
 2345           // ItemListener
 2346           //
 2347           public void itemStateChanged(ItemEvent event) {
 2348               fireItemStateChanged(event);
 2349               if (shouldUpdateSelectedStateFromAction()) {
 2350                   Action action = getAction();
 2351                   if (action != null && AbstractAction.hasSelectedKey(action)) {
 2352                       boolean selected = isSelected();
 2353                       boolean isActionSelected = AbstractAction.isSelected(
 2354                                 action);
 2355                       if (isActionSelected != selected) {
 2356                           action.putValue(Action.SELECTED_KEY, selected);
 2357                       }
 2358                   }
 2359               }
 2360           }
 2361       }
 2362   
 2363   ///////////////////
 2364   // Accessibility support
 2365   ///////////////////
 2366       /**
 2367        * This class implements accessibility support for the
 2368        * <code>AbstractButton</code> class.  It provides an implementation of the
 2369        * Java Accessibility API appropriate to button and menu item
 2370        * user-interface elements.
 2371        * <p>
 2372        * <strong>Warning:</strong>
 2373        * Serialized objects of this class will not be compatible with
 2374        * future Swing releases. The current serialization support is
 2375        * appropriate for short term storage or RMI between applications running
 2376        * the same version of Swing.  As of 1.4, support for long term storage
 2377        * of all JavaBeans<sup><font size="-2">TM</font></sup>
 2378        * has been added to the <code>java.beans</code> package.
 2379        * Please see {@link java.beans.XMLEncoder}.
 2380        * @since 1.4
 2381        */
 2382       protected abstract class AccessibleAbstractButton
 2383           extends AccessibleJComponent implements AccessibleAction,
 2384           AccessibleValue, AccessibleText, AccessibleExtendedComponent {
 2385   
 2386           /**
 2387            * Returns the accessible name of this object.
 2388            *
 2389            * @return the localized name of the object -- can be
 2390            *              <code>null</code> if this
 2391            *              object does not have a name
 2392            */
 2393           public String getAccessibleName() {
 2394               String name = accessibleName;
 2395   
 2396               if (name == null) {
 2397                   name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
 2398               }
 2399               if (name == null) {
 2400                   name = AbstractButton.this.getText();
 2401               }
 2402               if (name == null) {
 2403                   name = super.getAccessibleName();
 2404               }
 2405               return name;
 2406           }
 2407   
 2408           /**
 2409            * Get the AccessibleIcons associated with this object if one
 2410            * or more exist.  Otherwise return null.
 2411            * @since 1.3
 2412            */
 2413           public AccessibleIcon [] getAccessibleIcon() {
 2414               Icon defaultIcon = getIcon();
 2415   
 2416               if (defaultIcon instanceof Accessible) {
 2417                   AccessibleContext ac =
 2418                       ((Accessible)defaultIcon).getAccessibleContext();
 2419                   if (ac != null && ac instanceof AccessibleIcon) {
 2420                       return new AccessibleIcon[] { (AccessibleIcon)ac };
 2421                   }
 2422               }
 2423               return null;
 2424           }
 2425   
 2426           /**
 2427            * Get the state set of this object.
 2428            *
 2429            * @return an instance of AccessibleState containing the current state
 2430            * of the object
 2431            * @see AccessibleState
 2432            */
 2433           public AccessibleStateSet getAccessibleStateSet() {
 2434           AccessibleStateSet states = super.getAccessibleStateSet();
 2435               if (getModel().isArmed()) {
 2436                   states.add(AccessibleState.ARMED);
 2437               }
 2438               if (isFocusOwner()) {
 2439                   states.add(AccessibleState.FOCUSED);
 2440               }
 2441               if (getModel().isPressed()) {
 2442                   states.add(AccessibleState.PRESSED);
 2443               }
 2444               if (isSelected()) {
 2445                   states.add(AccessibleState.CHECKED);
 2446               }
 2447               return states;
 2448           }
 2449   
 2450           /**
 2451            * Get the AccessibleRelationSet associated with this object if one
 2452            * exists.  Otherwise return null.
 2453            * @see AccessibleRelation
 2454            * @since 1.3
 2455            */
 2456           public AccessibleRelationSet getAccessibleRelationSet() {
 2457   
 2458               // Check where the AccessibleContext's relation
 2459               // set already contains a MEMBER_OF relation.
 2460               AccessibleRelationSet relationSet
 2461                   = super.getAccessibleRelationSet();
 2462   
 2463               if (!relationSet.contains(AccessibleRelation.MEMBER_OF)) {
 2464                   // get the members of the button group if one exists
 2465                   ButtonModel model = getModel();
 2466                   if (model != null && model instanceof DefaultButtonModel) {
 2467                       ButtonGroup group = ((DefaultButtonModel)model).getGroup();
 2468                       if (group != null) {
 2469                           // set the target of the MEMBER_OF relation to be
 2470                           // the members of the button group.
 2471                           int len = group.getButtonCount();
 2472                           Object [] target = new Object[len];
 2473                           Enumeration elem = group.getElements();
 2474                           for (int i = 0; i < len; i++) {
 2475                               if (elem.hasMoreElements()) {
 2476                                   target[i] = elem.nextElement();
 2477                               }
 2478                           }
 2479                           AccessibleRelation relation =
 2480                               new AccessibleRelation(AccessibleRelation.MEMBER_OF);
 2481                           relation.setTarget(target);
 2482                           relationSet.add(relation);
 2483                       }
 2484                   }
 2485               }
 2486               return relationSet;
 2487           }
 2488   
 2489           /**
 2490            * Get the AccessibleAction associated with this object.  In the
 2491            * implementation of the Java Accessibility API for this class,
 2492            * return this object, which is responsible for implementing the
 2493            * AccessibleAction interface on behalf of itself.
 2494            *
 2495            * @return this object
 2496            */
 2497           public AccessibleAction getAccessibleAction() {
 2498               return this;
 2499           }
 2500   
 2501           /**
 2502            * Get the AccessibleValue associated with this object.  In the
 2503            * implementation of the Java Accessibility API for this class,
 2504            * return this object, which is responsible for implementing the
 2505            * AccessibleValue interface on behalf of itself.
 2506            *
 2507            * @return this object
 2508            */
 2509           public AccessibleValue getAccessibleValue() {
 2510               return this;
 2511           }
 2512   
 2513           /**
 2514            * Returns the number of Actions available in this object.  The
 2515            * default behavior of a button is to have one action - toggle
 2516            * the button.
 2517            *
 2518            * @return 1, the number of Actions in this object
 2519            */
 2520           public int getAccessibleActionCount() {
 2521               return 1;
 2522           }
 2523   
 2524           /**
 2525            * Return a description of the specified action of the object.
 2526            *
 2527            * @param i zero-based index of the actions
 2528            */
 2529           public String getAccessibleActionDescription(int i) {
 2530               if (i == 0) {
 2531                   return UIManager.getString("AbstractButton.clickText");
 2532               } else {
 2533                   return null;
 2534               }
 2535           }
 2536   
 2537           /**
 2538            * Perform the specified Action on the object
 2539            *
 2540            * @param i zero-based index of actions
 2541            * @return true if the the action was performed; else false.
 2542            */
 2543           public boolean doAccessibleAction(int i) {
 2544               if (i == 0) {
 2545                   doClick();
 2546                   return true;
 2547               } else {
 2548                   return false;
 2549               }
 2550           }
 2551   
 2552           /**
 2553            * Get the value of this object as a Number.
 2554            *
 2555            * @return An Integer of 0 if this isn't selected or an Integer of 1 if
 2556            * this is selected.
 2557            * @see AbstractButton#isSelected
 2558            */
 2559           public Number getCurrentAccessibleValue() {
 2560               if (isSelected()) {
 2561                   return Integer.valueOf(1);
 2562               } else {
 2563                   return Integer.valueOf(0);
 2564               }
 2565           }
 2566   
 2567           /**
 2568            * Set the value of this object as a Number.
 2569            *
 2570            * @return True if the value was set.
 2571            */
 2572           public boolean setCurrentAccessibleValue(Number n) {
 2573               // TIGER - 4422535
 2574               if (n == null) {
 2575                   return false;
 2576               }
 2577               int i = n.intValue();
 2578               if (i == 0) {
 2579                   setSelected(false);
 2580               } else {
 2581                   setSelected(true);
 2582               }
 2583               return true;
 2584           }
 2585   
 2586           /**
 2587            * Get the minimum value of this object as a Number.
 2588            *
 2589            * @return an Integer of 0.
 2590            */
 2591           public Number getMinimumAccessibleValue() {
 2592               return Integer.valueOf(0);
 2593           }
 2594   
 2595           /**
 2596            * Get the maximum value of this object as a Number.
 2597            *
 2598            * @return An Integer of 1.
 2599            */
 2600           public Number getMaximumAccessibleValue() {
 2601               return Integer.valueOf(1);
 2602           }
 2603   
 2604   
 2605           /* AccessibleText ---------- */
 2606   
 2607           public AccessibleText getAccessibleText() {
 2608               View view = (View)AbstractButton.this.getClientProperty("html");
 2609               if (view != null) {
 2610                   return this;
 2611               } else {
 2612                   return null;
 2613               }
 2614           }
 2615   
 2616           /**
 2617            * Given a point in local coordinates, return the zero-based index
 2618            * of the character under that Point.  If the point is invalid,
 2619            * this method returns -1.
 2620            *
 2621            * Note: the AbstractButton must have a valid size (e.g. have
 2622            * been added to a parent container whose ancestor container
 2623            * is a valid top-level window) for this method to be able
 2624            * to return a meaningful value.
 2625            *
 2626            * @param p the Point in local coordinates
 2627            * @return the zero-based index of the character under Point p; if
 2628            * Point is invalid returns -1.
 2629            * @since 1.3
 2630            */
 2631           public int getIndexAtPoint(Point p) {
 2632               View view = (View) AbstractButton.this.getClientProperty("html");
 2633               if (view != null) {
 2634                   Rectangle r = getTextRectangle();
 2635                   if (r == null) {
 2636                       return -1;
 2637                   }
 2638                   Rectangle2D.Float shape =
 2639                       new Rectangle2D.Float(r.x, r.y, r.width, r.height);
 2640                   Position.Bias bias[] = new Position.Bias[1];
 2641                   return view.viewToModel(p.x, p.y, shape, bias);
 2642               } else {
 2643                   return -1;
 2644               }
 2645           }
 2646   
 2647           /**
 2648            * Determine the bounding box of the character at the given
 2649            * index into the string.  The bounds are returned in local
 2650            * coordinates.  If the index is invalid an empty rectangle is
 2651            * returned.
 2652            *
 2653            * Note: the AbstractButton must have a valid size (e.g. have
 2654            * been added to a parent container whose ancestor container
 2655            * is a valid top-level window) for this method to be able
 2656            * to return a meaningful value.
 2657            *
 2658            * @param i the index into the String
 2659            * @return the screen coordinates of the character's the bounding box,
 2660            * if index is invalid returns an empty rectangle.
 2661            * @since 1.3
 2662            */
 2663           public Rectangle getCharacterBounds(int i) {
 2664               View view = (View) AbstractButton.this.getClientProperty("html");
 2665               if (view != null) {
 2666                   Rectangle r = getTextRectangle();
 2667                   if (r == null) {
 2668                       return null;
 2669                   }
 2670                   Rectangle2D.Float shape =
 2671                       new Rectangle2D.Float(r.x, r.y, r.width, r.height);
 2672                   try {
 2673                       Shape charShape =
 2674                           view.modelToView(i, shape, Position.Bias.Forward);
 2675                       return charShape.getBounds();
 2676                   } catch (BadLocationException e) {
 2677                       return null;
 2678                   }
 2679               } else {
 2680                   return null;
 2681               }
 2682           }
 2683   
 2684           /**
 2685            * Return the number of characters (valid indicies)
 2686            *
 2687            * @return the number of characters
 2688            * @since 1.3
 2689            */
 2690           public int getCharCount() {
 2691               View view = (View) AbstractButton.this.getClientProperty("html");
 2692               if (view != null) {
 2693                   Document d = view.getDocument();
 2694                   if (d instanceof StyledDocument) {
 2695                       StyledDocument doc = (StyledDocument)d;
 2696                       return doc.getLength();
 2697                   }
 2698               }
 2699               return accessibleContext.getAccessibleName().length();
 2700           }
 2701   
 2702           /**
 2703            * Return the zero-based offset of the caret.
 2704            *
 2705            * Note: That to the right of the caret will have the same index
 2706            * value as the offset (the caret is between two characters).
 2707            * @return the zero-based offset of the caret.
 2708            * @since 1.3
 2709            */
 2710           public int getCaretPosition() {
 2711               // There is no caret.
 2712               return -1;
 2713           }
 2714   
 2715           /**
 2716            * Returns the String at a given index.
 2717            *
 2718            * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
 2719            * or AccessibleText.SENTENCE to retrieve
 2720            * @param index an index within the text >= 0
 2721            * @return the letter, word, or sentence,
 2722            *   null for an invalid index or part
 2723            * @since 1.3
 2724            */
 2725           public String getAtIndex(int part, int index) {
 2726               if (index < 0 || index >= getCharCount()) {
 2727                   return null;
 2728               }
 2729               switch (part) {
 2730               case AccessibleText.CHARACTER:
 2731                   try {
 2732                       return getText(index, 1);
 2733                   } catch (BadLocationException e) {
 2734                       return null;
 2735                   }
 2736               case AccessibleText.WORD:
 2737                   try {
 2738                       String s = getText(0, getCharCount());
 2739                       BreakIterator words = BreakIterator.getWordInstance(getLocale());
 2740                       words.setText(s);
 2741                       int end = words.following(index);
 2742                       return s.substring(words.previous(), end);
 2743                   } catch (BadLocationException e) {
 2744                       return null;
 2745                   }
 2746               case AccessibleText.SENTENCE:
 2747                   try {
 2748                       String s = getText(0, getCharCount());
 2749                       BreakIterator sentence =
 2750                           BreakIterator.getSentenceInstance(getLocale());
 2751                       sentence.setText(s);
 2752                       int end = sentence.following(index);
 2753                       return s.substring(sentence.previous(), end);
 2754                   } catch (BadLocationException e) {
 2755                       return null;
 2756                   }
 2757               default:
 2758                   return null;
 2759               }
 2760           }
 2761   
 2762           /**
 2763            * Returns the String after a given index.
 2764            *
 2765            * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
 2766            * or AccessibleText.SENTENCE to retrieve
 2767            * @param index an index within the text >= 0
 2768            * @return the letter, word, or sentence, null for an invalid
 2769            *  index or part
 2770            * @since 1.3
 2771            */
 2772           public String getAfterIndex(int part, int index) {
 2773               if (index < 0 || index >= getCharCount()) {
 2774                   return null;
 2775               }
 2776               switch (part) {
 2777               case AccessibleText.CHARACTER:
 2778                   if (index+1 >= getCharCount()) {
 2779                      return null;
 2780                   }
 2781                   try {
 2782                       return getText(index+1, 1);
 2783                   } catch (BadLocationException e) {
 2784                       return null;
 2785                   }
 2786               case AccessibleText.WORD:
 2787                   try {
 2788                       String s = getText(0, getCharCount());
 2789                       BreakIterator words = BreakIterator.getWordInstance(getLocale());
 2790                       words.setText(s);
 2791                       int start = words.following(index);
 2792                       if (start == BreakIterator.DONE || start >= s.length()) {
 2793                           return null;
 2794                       }
 2795                       int end = words.following(start);
 2796                       if (end == BreakIterator.DONE || end >= s.length()) {
 2797                           return null;
 2798                       }
 2799                       return s.substring(start, end);
 2800                   } catch (BadLocationException e) {
 2801                       return null;
 2802                   }
 2803               case AccessibleText.SENTENCE:
 2804                   try {
 2805                       String s = getText(0, getCharCount());
 2806                       BreakIterator sentence =
 2807                           BreakIterator.getSentenceInstance(getLocale());
 2808                       sentence.setText(s);
 2809                       int start = sentence.following(index);
 2810                       if (start == BreakIterator.DONE || start > s.length()) {
 2811                           return null;
 2812                       }
 2813                       int end = sentence.following(start);
 2814                       if (end == BreakIterator.DONE || end > s.length()) {
 2815                           return null;
 2816                       }
 2817                       return s.substring(start, end);
 2818                   } catch (BadLocationException e) {
 2819                       return null;
 2820                   }
 2821               default:
 2822                   return null;
 2823               }
 2824           }
 2825   
 2826           /**
 2827            * Returns the String before a given index.
 2828            *
 2829            * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
 2830            *   or AccessibleText.SENTENCE to retrieve
 2831            * @param index an index within the text >= 0
 2832            * @return the letter, word, or sentence, null for an invalid index
 2833            *  or part
 2834            * @since 1.3
 2835            */
 2836           public String getBeforeIndex(int part, int index) {
 2837               if (index < 0 || index > getCharCount()-1) {
 2838                   return null;
 2839               }
 2840               switch (part) {
 2841               case AccessibleText.CHARACTER:
 2842                   if (index == 0) {
 2843                       return null;
 2844                   }
 2845                   try {
 2846                       return getText(index-1, 1);
 2847                   } catch (BadLocationException e) {
 2848                       return null;
 2849                   }
 2850               case AccessibleText.WORD:
 2851                   try {
 2852                       String s = getText(0, getCharCount());
 2853                       BreakIterator words = BreakIterator.getWordInstance(getLocale());
 2854                       words.setText(s);
 2855                       int end = words.following(index);
 2856                       end = words.previous();
 2857                       int start = words.previous();
 2858                       if (start == BreakIterator.DONE) {
 2859                           return null;
 2860                       }
 2861                       return s.substring(start, end);
 2862                   } catch (BadLocationException e) {
 2863                       return null;
 2864                   }
 2865               case AccessibleText.SENTENCE:
 2866                   try {
 2867                       String s = getText(0, getCharCount());
 2868                       BreakIterator sentence =
 2869                           BreakIterator.getSentenceInstance(getLocale());
 2870                       sentence.setText(s);
 2871                       int end = sentence.following(index);
 2872                       end = sentence.previous();
 2873                       int start = sentence.previous();
 2874                       if (start == BreakIterator.DONE) {
 2875                           return null;
 2876                       }
 2877                       return s.substring(start, end);
 2878                   } catch (BadLocationException e) {
 2879                       return null;
 2880                   }
 2881               default:
 2882                   return null;
 2883               }
 2884           }
 2885   
 2886           /**
 2887            * Return the AttributeSet for a given character at a given index
 2888            *
 2889            * @param i the zero-based index into the text
 2890            * @return the AttributeSet of the character
 2891            * @since 1.3
 2892            */
 2893           public AttributeSet getCharacterAttribute(int i) {
 2894               View view = (View) AbstractButton.this.getClientProperty("html");
 2895               if (view != null) {
 2896                   Document d = view.getDocument();
 2897                   if (d instanceof StyledDocument) {
 2898                       StyledDocument doc = (StyledDocument)d;
 2899                       Element elem = doc.getCharacterElement(i);
 2900                       if (elem != null) {
 2901                           return elem.getAttributes();
 2902                       }
 2903                   }
 2904               }
 2905               return null;
 2906           }
 2907   
 2908           /**
 2909            * Returns the start offset within the selected text.
 2910            * If there is no selection, but there is
 2911            * a caret, the start and end offsets will be the same.
 2912            *
 2913            * @return the index into the text of the start of the selection
 2914            * @since 1.3
 2915            */
 2916           public int getSelectionStart() {
 2917               // Text cannot be selected.
 2918               return -1;
 2919           }
 2920   
 2921           /**
 2922            * Returns the end offset within the selected text.
 2923            * If there is no selection, but there is
 2924            * a caret, the start and end offsets will be the same.
 2925            *
 2926            * @return the index into teh text of the end of the selection
 2927            * @since 1.3
 2928            */
 2929           public int getSelectionEnd() {
 2930               // Text cannot be selected.
 2931               return -1;
 2932           }
 2933   
 2934           /**
 2935            * Returns the portion of the text that is selected.
 2936            *
 2937            * @return the String portion of the text that is selected
 2938            * @since 1.3
 2939            */
 2940           public String getSelectedText() {
 2941               // Text cannot be selected.
 2942               return null;
 2943           }
 2944   
 2945           /*
 2946            * Returns the text substring starting at the specified
 2947            * offset with the specified length.
 2948            */
 2949           private String getText(int offset, int length)
 2950               throws BadLocationException {
 2951   
 2952               View view = (View) AbstractButton.this.getClientProperty("html");
 2953               if (view != null) {
 2954                   Document d = view.getDocument();
 2955                   if (d instanceof StyledDocument) {
 2956                       StyledDocument doc = (StyledDocument)d;
 2957                       return doc.getText(offset, length);
 2958                   }
 2959               }
 2960               return null;
 2961           }
 2962   
 2963           /*
 2964            * Returns the bounding rectangle for the component text.
 2965            */
 2966           private Rectangle getTextRectangle() {
 2967   
 2968               String text = AbstractButton.this.getText();
 2969               Icon icon = (AbstractButton.this.isEnabled()) ? AbstractButton.this.getIcon() : AbstractButton.this.getDisabledIcon();
 2970   
 2971               if ((icon == null) && (text == null)) {
 2972                   return null;
 2973               }
 2974   
 2975               Rectangle paintIconR = new Rectangle();
 2976               Rectangle paintTextR = new Rectangle();
 2977               Rectangle paintViewR = new Rectangle();
 2978               Insets paintViewInsets = new Insets(0, 0, 0, 0);
 2979   
 2980               paintViewInsets = AbstractButton.this.getInsets(paintViewInsets);
 2981               paintViewR.x = paintViewInsets.left;
 2982               paintViewR.y = paintViewInsets.top;
 2983               paintViewR.width = AbstractButton.this.getWidth() - (paintViewInsets.left + paintViewInsets.right);
 2984               paintViewR.height = AbstractButton.this.getHeight() - (paintViewInsets.top + paintViewInsets.bottom);
 2985   
 2986               String clippedText = SwingUtilities.layoutCompoundLabel(
 2987                   AbstractButton.this,
 2988                   getFontMetrics(getFont()),
 2989                   text,
 2990                   icon,
 2991                   AbstractButton.this.getVerticalAlignment(),
 2992                   AbstractButton.this.getHorizontalAlignment(),
 2993                   AbstractButton.this.getVerticalTextPosition(),
 2994                   AbstractButton.this.getHorizontalTextPosition(),
 2995                   paintViewR,
 2996                   paintIconR,
 2997                   paintTextR,
 2998                   0);
 2999   
 3000               return paintTextR;
 3001           }
 3002   
 3003           // ----- AccessibleExtendedComponent
 3004   
 3005           /**
 3006            * Returns the AccessibleExtendedComponent
 3007            *
 3008            * @return the AccessibleExtendedComponent
 3009            */
 3010           AccessibleExtendedComponent getAccessibleExtendedComponent() {
 3011               return this;
 3012           }
 3013   
 3014           /**
 3015            * Returns the tool tip text
 3016            *
 3017            * @return the tool tip text, if supported, of the object;
 3018            * otherwise, null
 3019            * @since 1.4
 3020            */
 3021           public String getToolTipText() {
 3022               return AbstractButton.this.getToolTipText();
 3023           }
 3024   
 3025           /**
 3026            * Returns the titled border text
 3027            *
 3028            * @return the titled border text, if supported, of the object;
 3029            * otherwise, null
 3030            * @since 1.4
 3031            */
 3032           public String getTitledBorderText() {
 3033               return super.getTitledBorderText();
 3034           }
 3035   
 3036           /**
 3037            * Returns key bindings associated with this object
 3038            *
 3039            * @return the key bindings, if supported, of the object;
 3040            * otherwise, null
 3041            * @see AccessibleKeyBinding
 3042            * @since 1.4
 3043            */
 3044           public AccessibleKeyBinding getAccessibleKeyBinding() {
 3045               int mnemonic = AbstractButton.this.getMnemonic();
 3046               if (mnemonic == 0) {
 3047                   return null;
 3048               }
 3049               return new ButtonKeyBinding(mnemonic);
 3050           }
 3051   
 3052           class ButtonKeyBinding implements AccessibleKeyBinding {
 3053               int mnemonic;
 3054   
 3055               ButtonKeyBinding(int mnemonic) {
 3056                   this.mnemonic = mnemonic;
 3057               }
 3058   
 3059               /**
 3060                * Returns the number of key bindings for this object
 3061                *
 3062                * @return the zero-based number of key bindings for this object
 3063                */
 3064               public int getAccessibleKeyBindingCount() {
 3065                   return 1;
 3066               }
 3067   
 3068               /**
 3069                * Returns a key binding for this object.  The value returned is an
 3070                * java.lang.Object which must be cast to appropriate type depending
 3071                * on the underlying implementation of the key.  For example, if the
 3072                * Object returned is a javax.swing.KeyStroke, the user of this
 3073                * method should do the following:
 3074                * <nf><code>
 3075                * Component c = <get the component that has the key bindings>
 3076                * AccessibleContext ac = c.getAccessibleContext();
 3077                * AccessibleKeyBinding akb = ac.getAccessibleKeyBinding();
 3078                * for (int i = 0; i < akb.getAccessibleKeyBindingCount(); i++) {
 3079                *     Object o = akb.getAccessibleKeyBinding(i);
 3080                *     if (o instanceof javax.swing.KeyStroke) {
 3081                *         javax.swing.KeyStroke keyStroke = (javax.swing.KeyStroke)o;
 3082                *         <do something with the key binding>
 3083                *     }
 3084                * }
 3085                * </code></nf>
 3086                *
 3087                * @param i zero-based index of the key bindings
 3088                * @return a javax.lang.Object which specifies the key binding
 3089                * @exception IllegalArgumentException if the index is
 3090                * out of bounds
 3091                * @see #getAccessibleKeyBindingCount
 3092                */
 3093               public java.lang.Object getAccessibleKeyBinding(int i) {
 3094                   if (i != 0) {
 3095                       throw new IllegalArgumentException();
 3096                   }
 3097                   return KeyStroke.getKeyStroke(mnemonic, 0);
 3098               }
 3099           }
 3100       }
 3101   }

Save This Page
Home » openjdk-7 » javax » swing » [javadoc | source]