Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/swing/AbstractButton.java
38829 views
/*1* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package javax.swing;2526import java.awt.*;27import java.awt.event.*;28import java.awt.image.*;29import java.text.*;30import java.awt.geom.*;31import java.beans.PropertyChangeEvent;32import java.beans.PropertyChangeListener;33import java.beans.Transient;34import java.util.Enumeration;35import java.util.Vector;36import java.io.Serializable;37import javax.swing.event.*;38import javax.swing.border.*;39import javax.swing.plaf.*;40import javax.accessibility.*;41import javax.swing.text.*;42import javax.swing.text.html.*;43import javax.swing.plaf.basic.*;44import java.util.*;4546/**47* Defines common behaviors for buttons and menu items.48* <p>49* Buttons can be configured, and to some degree controlled, by50* <code><a href="Action.html">Action</a></code>s. Using an51* <code>Action</code> with a button has many benefits beyond directly52* configuring a button. Refer to <a href="Action.html#buttonActions">53* Swing Components Supporting <code>Action</code></a> for more54* details, and you can find more information in <a55* href="https://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How56* to Use Actions</a>, a section in <em>The Java Tutorial</em>.57* <p>58* For further information see59* <a60href="https://docs.oracle.com/javase/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons</a>,61* a section in <em>The Java Tutorial</em>.62* <p>63* <strong>Warning:</strong>64* Serialized objects of this class will not be compatible with65* future Swing releases. The current serialization support is66* appropriate for short term storage or RMI between applications running67* the same version of Swing. As of 1.4, support for long term storage68* of all JavaBeans™69* has been added to the <code>java.beans</code> package.70* Please see {@link java.beans.XMLEncoder}.71*72* @author Jeff Dinkins73*/74public abstract class AbstractButton extends JComponent implements ItemSelectable, SwingConstants {7576// *********************************77// ******* Button properties *******78// *********************************7980/** Identifies a change in the button model. */81public static final String MODEL_CHANGED_PROPERTY = "model";82/** Identifies a change in the button's text. */83public static final String TEXT_CHANGED_PROPERTY = "text";84/** Identifies a change to the button's mnemonic. */85public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic";8687// Text positioning and alignment88/** Identifies a change in the button's margins. */89public static final String MARGIN_CHANGED_PROPERTY = "margin";90/** Identifies a change in the button's vertical alignment. */91public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";92/** Identifies a change in the button's horizontal alignment. */93public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = "horizontalAlignment";9495/** Identifies a change in the button's vertical text position. */96public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = "verticalTextPosition";97/** Identifies a change in the button's horizontal text position. */98public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = "horizontalTextPosition";99100// Paint options101/**102* Identifies a change to having the border drawn,103* or having it not drawn.104*/105public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";106/**107* Identifies a change to having the border highlighted when focused,108* or not.109*/110public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";111/**112* Identifies a change from rollover enabled to disabled or back113* to enabled.114*/115public static final String ROLLOVER_ENABLED_CHANGED_PROPERTY = "rolloverEnabled";116/**117* Identifies a change to having the button paint the content area.118*/119public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled";120121// Icons122/** Identifies a change to the icon that represents the button. */123public static final String ICON_CHANGED_PROPERTY = "icon";124125/**126* Identifies a change to the icon used when the button has been127* pressed.128*/129public static final String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";130/**131* Identifies a change to the icon used when the button has132* been selected.133*/134public static final String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";135136/**137* Identifies a change to the icon used when the cursor is over138* the button.139*/140public static final String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";141/**142* Identifies a change to the icon used when the cursor is143* over the button and it has been selected.144*/145public static final String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = "rolloverSelectedIcon";146147/**148* Identifies a change to the icon used when the button has149* been disabled.150*/151public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";152/**153* Identifies a change to the icon used when the button has been154* disabled and selected.155*/156public static final String DISABLED_SELECTED_ICON_CHANGED_PROPERTY = "disabledSelectedIcon";157158159/** The data model that determines the button's state. */160protected ButtonModel model = null;161162private String text = ""; // for BeanBox163private Insets margin = null;164private Insets defaultMargin = null;165166// Button icons167// PENDING(jeff) - hold icons in an array168private Icon defaultIcon = null;169private Icon pressedIcon = null;170private Icon disabledIcon = null;171172private Icon selectedIcon = null;173private Icon disabledSelectedIcon = null;174175private Icon rolloverIcon = null;176private Icon rolloverSelectedIcon = null;177178// Display properties179private boolean paintBorder = true;180private boolean paintFocus = true;181private boolean rolloverEnabled = false;182private boolean contentAreaFilled = true;183184// Icon/Label Alignment185private int verticalAlignment = CENTER;186private int horizontalAlignment = CENTER;187188private int verticalTextPosition = CENTER;189private int horizontalTextPosition = TRAILING;190191private int iconTextGap = 4;192193private int mnemonic;194private int mnemonicIndex = -1;195196private long multiClickThreshhold = 0;197198private boolean borderPaintedSet = false;199private boolean rolloverEnabledSet = false;200private boolean iconTextGapSet = false;201private boolean contentAreaFilledSet = false;202203// Whether or not we've set the LayoutManager.204private boolean setLayout = false;205206// This is only used by JButton, promoted to avoid an extra207// boolean field in JButton208boolean defaultCapable = true;209210/**211* Combined listeners: ActionListener, ChangeListener, ItemListener.212*/213private Handler handler;214215/**216* The button model's <code>changeListener</code>.217*/218protected ChangeListener changeListener = null;219/**220* The button model's <code>ActionListener</code>.221*/222protected ActionListener actionListener = null;223/**224* The button model's <code>ItemListener</code>.225*/226protected ItemListener itemListener = null;227228/**229* Only one <code>ChangeEvent</code> is needed per button230* instance since the231* event's only state is the source property. The source of events232* generated is always "this".233*/234protected transient ChangeEvent changeEvent;235236private boolean hideActionText = false;237238/**239* Sets the <code>hideActionText</code> property, which determines240* whether the button displays text from the <code>Action</code>.241* This is useful only if an <code>Action</code> has been242* installed on the button.243*244* @param hideActionText <code>true</code> if the button's245* <code>text</code> property should not reflect246* that of the <code>Action</code>; the default is247* <code>false</code>248* @see <a href="Action.html#buttonActions">Swing Components Supporting249* <code>Action</code></a>250* @since 1.6251* @beaninfo252* bound: true253* expert: true254* description: Whether the text of the button should come from255* the <code>Action</code>.256*/257public void setHideActionText(boolean hideActionText) {258if (hideActionText != this.hideActionText) {259this.hideActionText = hideActionText;260if (getAction() != null) {261setTextFromAction(getAction(), false);262}263firePropertyChange("hideActionText", !hideActionText,264hideActionText);265}266}267268/**269* Returns the value of the <code>hideActionText</code> property, which270* determines whether the button displays text from the271* <code>Action</code>. This is useful only if an <code>Action</code>272* has been installed on the button.273*274* @return <code>true</code> if the button's <code>text</code>275* property should not reflect that of the276* <code>Action</code>; the default is <code>false</code>277* @since 1.6278*/279public boolean getHideActionText() {280return hideActionText;281}282283/**284* Returns the button's text.285* @return the buttons text286* @see #setText287*/288public String getText() {289return text;290}291292/**293* Sets the button's text.294* @param text the string used to set the text295* @see #getText296* @beaninfo297* bound: true298* preferred: true299* attribute: visualUpdate true300* description: The button's text.301*/302public void setText(String text) {303String oldValue = this.text;304this.text = text;305firePropertyChange(TEXT_CHANGED_PROPERTY, oldValue, text);306updateDisplayedMnemonicIndex(text, getMnemonic());307308if (accessibleContext != null) {309accessibleContext.firePropertyChange(310AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,311oldValue, text);312}313if (text == null || oldValue == null || !text.equals(oldValue)) {314revalidate();315repaint();316}317}318319320/**321* Returns the state of the button. True if the322* toggle button is selected, false if it's not.323* @return true if the toggle button is selected, otherwise false324*/325public boolean isSelected() {326return model.isSelected();327}328329/**330* Sets the state of the button. Note that this method does not331* trigger an <code>actionEvent</code>.332* Call <code>doClick</code> to perform a programmatic action change.333*334* @param b true if the button is selected, otherwise false335*/336public void setSelected(boolean b) {337boolean oldValue = isSelected();338339// TIGER - 4840653340// Removed code which fired an AccessibleState.SELECTED341// PropertyChangeEvent since this resulted in two342// identical events being fired since343// AbstractButton.fireItemStateChanged also fires the344// same event. This caused screen readers to speak the345// name of the item twice.346347model.setSelected(b);348}349350/**351* Programmatically perform a "click". This does the same352* thing as if the user had pressed and released the button.353*/354public void doClick() {355doClick(68);356}357358/**359* Programmatically perform a "click". This does the same360* thing as if the user had pressed and released the button.361* The button stays visually "pressed" for <code>pressTime</code>362* milliseconds.363*364* @param pressTime the time to "hold down" the button, in milliseconds365*/366public void doClick(int pressTime) {367Dimension size = getSize();368model.setArmed(true);369model.setPressed(true);370paintImmediately(new Rectangle(0,0, size.width, size.height));371try {372Thread.currentThread().sleep(pressTime);373} catch(InterruptedException ie) {374}375model.setPressed(false);376model.setArmed(false);377}378379/**380* Sets space for margin between the button's border and381* the label. Setting to <code>null</code> will cause the button to382* use the default margin. The button's default <code>Border</code>383* object will use this value to create the proper margin.384* However, if a non-default border is set on the button,385* it is that <code>Border</code> object's responsibility to create the386* appropriate margin space (else this property will387* effectively be ignored).388*389* @param m the space between the border and the label390*391* @beaninfo392* bound: true393* attribute: visualUpdate true394* description: The space between the button's border and the label.395*/396public void setMargin(Insets m) {397// Cache the old margin if it comes from the UI398if(m instanceof UIResource) {399defaultMargin = m;400} else if(margin instanceof UIResource) {401defaultMargin = margin;402}403404// If the client passes in a null insets, restore the margin405// from the UI if possible406if(m == null && defaultMargin != null) {407m = defaultMargin;408}409410Insets old = margin;411margin = m;412firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);413if (old == null || !old.equals(m)) {414revalidate();415repaint();416}417}418419/**420* Returns the margin between the button's border and421* the label.422*423* @return an <code>Insets</code> object specifying the margin424* between the botton's border and the label425* @see #setMargin426*/427public Insets getMargin() {428return (margin == null) ? null : (Insets) margin.clone();429}430431/**432* Returns the default icon.433* @return the default <code>Icon</code>434* @see #setIcon435*/436public Icon getIcon() {437return defaultIcon;438}439440/**441* Sets the button's default icon. This icon is442* also used as the "pressed" and "disabled" icon if443* there is no explicitly set pressed icon.444*445* @param defaultIcon the icon used as the default image446* @see #getIcon447* @see #setPressedIcon448* @beaninfo449* bound: true450* attribute: visualUpdate true451* description: The button's default icon452*/453public void setIcon(Icon defaultIcon) {454Icon oldValue = this.defaultIcon;455this.defaultIcon = defaultIcon;456457/* If the default icon has really changed and we had458* generated the disabled icon for this component,459* (i.e. setDisabledIcon() was never called) then460* clear the disabledIcon field.461*/462if (defaultIcon != oldValue && (disabledIcon instanceof UIResource)) {463disabledIcon = null;464}465466firePropertyChange(ICON_CHANGED_PROPERTY, oldValue, defaultIcon);467if (accessibleContext != null) {468accessibleContext.firePropertyChange(469AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,470oldValue, defaultIcon);471}472if (defaultIcon != oldValue) {473if (defaultIcon == null || oldValue == null ||474defaultIcon.getIconWidth() != oldValue.getIconWidth() ||475defaultIcon.getIconHeight() != oldValue.getIconHeight()) {476revalidate();477}478repaint();479}480}481482/**483* Returns the pressed icon for the button.484* @return the <code>pressedIcon</code> property485* @see #setPressedIcon486*/487public Icon getPressedIcon() {488return pressedIcon;489}490491/**492* Sets the pressed icon for the button.493* @param pressedIcon the icon used as the "pressed" image494* @see #getPressedIcon495* @beaninfo496* bound: true497* attribute: visualUpdate true498* description: The pressed icon for the button.499*/500public void setPressedIcon(Icon pressedIcon) {501Icon oldValue = this.pressedIcon;502this.pressedIcon = pressedIcon;503firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, oldValue, pressedIcon);504if (accessibleContext != null) {505accessibleContext.firePropertyChange(506AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,507oldValue, pressedIcon);508}509if (pressedIcon != oldValue) {510if (getModel().isPressed()) {511repaint();512}513}514}515516/**517* Returns the selected icon for the button.518* @return the <code>selectedIcon</code> property519* @see #setSelectedIcon520*/521public Icon getSelectedIcon() {522return selectedIcon;523}524525/**526* Sets the selected icon for the button.527* @param selectedIcon the icon used as the "selected" image528* @see #getSelectedIcon529* @beaninfo530* bound: true531* attribute: visualUpdate true532* description: The selected icon for the button.533*/534public void setSelectedIcon(Icon selectedIcon) {535Icon oldValue = this.selectedIcon;536this.selectedIcon = selectedIcon;537538/* If the default selected icon has really changed and we had539* generated the disabled selected icon for this component,540* (i.e. setDisabledSelectedIcon() was never called) then541* clear the disabledSelectedIcon field.542*/543if (selectedIcon != oldValue &&544disabledSelectedIcon instanceof UIResource) {545546disabledSelectedIcon = null;547}548549firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, oldValue, selectedIcon);550if (accessibleContext != null) {551accessibleContext.firePropertyChange(552AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,553oldValue, selectedIcon);554}555if (selectedIcon != oldValue) {556if (isSelected()) {557repaint();558}559}560}561562/**563* Returns the rollover icon for the button.564* @return the <code>rolloverIcon</code> property565* @see #setRolloverIcon566*/567public Icon getRolloverIcon() {568return rolloverIcon;569}570571/**572* Sets the rollover icon for the button.573* @param rolloverIcon the icon used as the "rollover" image574* @see #getRolloverIcon575* @beaninfo576* bound: true577* attribute: visualUpdate true578* description: The rollover icon for the button.579*/580public void setRolloverIcon(Icon rolloverIcon) {581Icon oldValue = this.rolloverIcon;582this.rolloverIcon = rolloverIcon;583firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, oldValue, rolloverIcon);584if (accessibleContext != null) {585accessibleContext.firePropertyChange(586AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,587oldValue, rolloverIcon);588}589setRolloverEnabled(true);590if (rolloverIcon != oldValue) {591// No way to determine whether we are currently in592// a rollover state, so repaint regardless593repaint();594}595596}597598/**599* Returns the rollover selection icon for the button.600* @return the <code>rolloverSelectedIcon</code> property601* @see #setRolloverSelectedIcon602*/603public Icon getRolloverSelectedIcon() {604return rolloverSelectedIcon;605}606607/**608* Sets the rollover selected icon for the button.609* @param rolloverSelectedIcon the icon used as the610* "selected rollover" image611* @see #getRolloverSelectedIcon612* @beaninfo613* bound: true614* attribute: visualUpdate true615* description: The rollover selected icon for the button.616*/617public void setRolloverSelectedIcon(Icon rolloverSelectedIcon) {618Icon oldValue = this.rolloverSelectedIcon;619this.rolloverSelectedIcon = rolloverSelectedIcon;620firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, oldValue, rolloverSelectedIcon);621if (accessibleContext != null) {622accessibleContext.firePropertyChange(623AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,624oldValue, rolloverSelectedIcon);625}626setRolloverEnabled(true);627if (rolloverSelectedIcon != oldValue) {628// No way to determine whether we are currently in629// a rollover state, so repaint regardless630if (isSelected()) {631repaint();632}633}634}635636/**637* Returns the icon used by the button when it's disabled.638* If no disabled icon has been set this will forward the call to639* the look and feel to construct an appropriate disabled Icon.640* <p>641* Some look and feels might not render the disabled Icon, in which642* case they will ignore this.643*644* @return the <code>disabledIcon</code> property645* @see #getPressedIcon646* @see #setDisabledIcon647* @see javax.swing.LookAndFeel#getDisabledIcon648*/649@Transient650public Icon getDisabledIcon() {651if (disabledIcon == null) {652disabledIcon = UIManager.getLookAndFeel().getDisabledIcon(this, getIcon());653if (disabledIcon != null) {654firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, null, disabledIcon);655}656}657return disabledIcon;658}659660/**661* Sets the disabled icon for the button.662* @param disabledIcon the icon used as the disabled image663* @see #getDisabledIcon664* @beaninfo665* bound: true666* attribute: visualUpdate true667* description: The disabled icon for the button.668*/669public void setDisabledIcon(Icon disabledIcon) {670Icon oldValue = this.disabledIcon;671this.disabledIcon = disabledIcon;672firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, oldValue, disabledIcon);673if (accessibleContext != null) {674accessibleContext.firePropertyChange(675AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,676oldValue, disabledIcon);677}678if (disabledIcon != oldValue) {679if (!isEnabled()) {680repaint();681}682}683}684685/**686* Returns the icon used by the button when it's disabled and selected.687* If no disabled selection icon has been set, this will forward688* the call to the LookAndFeel to construct an appropriate disabled689* Icon from the selection icon if it has been set and to690* <code>getDisabledIcon()</code> otherwise.691* <p>692* Some look and feels might not render the disabled selected Icon, in693* which case they will ignore this.694*695* @return the <code>disabledSelectedIcon</code> property696* @see #getDisabledIcon697* @see #setDisabledSelectedIcon698* @see javax.swing.LookAndFeel#getDisabledSelectedIcon699*/700public Icon getDisabledSelectedIcon() {701if (disabledSelectedIcon == null) {702if (selectedIcon != null) {703disabledSelectedIcon = UIManager.getLookAndFeel().704getDisabledSelectedIcon(this, getSelectedIcon());705} else {706return getDisabledIcon();707}708}709return disabledSelectedIcon;710}711712/**713* Sets the disabled selection icon for the button.714* @param disabledSelectedIcon the icon used as the disabled715* selection image716* @see #getDisabledSelectedIcon717* @beaninfo718* bound: true719* attribute: visualUpdate true720* description: The disabled selection icon for the button.721*/722public void setDisabledSelectedIcon(Icon disabledSelectedIcon) {723Icon oldValue = this.disabledSelectedIcon;724this.disabledSelectedIcon = disabledSelectedIcon;725firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, oldValue, disabledSelectedIcon);726if (accessibleContext != null) {727accessibleContext.firePropertyChange(728AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,729oldValue, disabledSelectedIcon);730}731if (disabledSelectedIcon != oldValue) {732if (disabledSelectedIcon == null || oldValue == null ||733disabledSelectedIcon.getIconWidth() != oldValue.getIconWidth() ||734disabledSelectedIcon.getIconHeight() != oldValue.getIconHeight()) {735revalidate();736}737if (!isEnabled() && isSelected()) {738repaint();739}740}741}742743/**744* Returns the vertical alignment of the text and icon.745*746* @return the <code>verticalAlignment</code> property, one of the747* following values:748* <ul>749* <li>{@code SwingConstants.CENTER} (the default)750* <li>{@code SwingConstants.TOP}751* <li>{@code SwingConstants.BOTTOM}752* </ul>753*/754public int getVerticalAlignment() {755return verticalAlignment;756}757758/**759* Sets the vertical alignment of the icon and text.760* @param alignment one of the following values:761* <ul>762* <li>{@code SwingConstants.CENTER} (the default)763* <li>{@code SwingConstants.TOP}764* <li>{@code SwingConstants.BOTTOM}765* </ul>766* @throws IllegalArgumentException if the alignment is not one of the legal767* values listed above768* @beaninfo769* bound: true770* enum: TOP SwingConstants.TOP771* CENTER SwingConstants.CENTER772* BOTTOM SwingConstants.BOTTOM773* attribute: visualUpdate true774* description: The vertical alignment of the icon and text.775*/776public void setVerticalAlignment(int alignment) {777if (alignment == verticalAlignment) return;778int oldValue = verticalAlignment;779verticalAlignment = checkVerticalKey(alignment, "verticalAlignment");780firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, oldValue, verticalAlignment); repaint();781}782783/**784* Returns the horizontal alignment of the icon and text.785* {@code AbstractButton}'s default is {@code SwingConstants.CENTER},786* but subclasses such as {@code JCheckBox} may use a different default.787*788* @return the <code>horizontalAlignment</code> property,789* one of the following values:790* <ul>791* <li>{@code SwingConstants.RIGHT}792* <li>{@code SwingConstants.LEFT}793* <li>{@code SwingConstants.CENTER}794* <li>{@code SwingConstants.LEADING}795* <li>{@code SwingConstants.TRAILING}796* </ul>797*/798public int getHorizontalAlignment() {799return horizontalAlignment;800}801802/**803* Sets the horizontal alignment of the icon and text.804* {@code AbstractButton}'s default is {@code SwingConstants.CENTER},805* but subclasses such as {@code JCheckBox} may use a different default.806*807* @param alignment the alignment value, one of the following values:808* <ul>809* <li>{@code SwingConstants.RIGHT}810* <li>{@code SwingConstants.LEFT}811* <li>{@code SwingConstants.CENTER}812* <li>{@code SwingConstants.LEADING}813* <li>{@code SwingConstants.TRAILING}814* </ul>815* @throws IllegalArgumentException if the alignment is not one of the816* valid values817* @beaninfo818* bound: true819* enum: LEFT SwingConstants.LEFT820* CENTER SwingConstants.CENTER821* RIGHT SwingConstants.RIGHT822* LEADING SwingConstants.LEADING823* TRAILING SwingConstants.TRAILING824* attribute: visualUpdate true825* description: The horizontal alignment of the icon and text.826*/827public void setHorizontalAlignment(int alignment) {828if (alignment == horizontalAlignment) return;829int oldValue = horizontalAlignment;830horizontalAlignment = checkHorizontalKey(alignment,831"horizontalAlignment");832firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY,833oldValue, horizontalAlignment);834repaint();835}836837838/**839* Returns the vertical position of the text relative to the icon.840* @return the <code>verticalTextPosition</code> property,841* one of the following values:842* <ul>843* <li>{@code SwingConstants.CENTER} (the default)844* <li>{@code SwingConstants.TOP}845* <li>{@code SwingConstants.BOTTOM}846* </ul>847*/848public int getVerticalTextPosition() {849return verticalTextPosition;850}851852/**853* Sets the vertical position of the text relative to the icon.854* @param textPosition one of the following values:855* <ul>856* <li>{@code SwingConstants.CENTER} (the default)857* <li>{@code SwingConstants.TOP}858* <li>{@code SwingConstants.BOTTOM}859* </ul>860* @beaninfo861* bound: true862* enum: TOP SwingConstants.TOP863* CENTER SwingConstants.CENTER864* BOTTOM SwingConstants.BOTTOM865* attribute: visualUpdate true866* description: The vertical position of the text relative to the icon.867*/868public void setVerticalTextPosition(int textPosition) {869if (textPosition == verticalTextPosition) return;870int oldValue = verticalTextPosition;871verticalTextPosition = checkVerticalKey(textPosition, "verticalTextPosition");872firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, oldValue, verticalTextPosition);873revalidate();874repaint();875}876877/**878* Returns the horizontal position of the text relative to the icon.879* @return the <code>horizontalTextPosition</code> property,880* one of the following values:881* <ul>882* <li>{@code SwingConstants.RIGHT}883* <li>{@code SwingConstants.LEFT}884* <li>{@code SwingConstants.CENTER}885* <li>{@code SwingConstants.LEADING}886* <li>{@code SwingConstants.TRAILING} (the default)887* </ul>888*/889public int getHorizontalTextPosition() {890return horizontalTextPosition;891}892893/**894* Sets the horizontal position of the text relative to the icon.895* @param textPosition one of the following values:896* <ul>897* <li>{@code SwingConstants.RIGHT}898* <li>{@code SwingConstants.LEFT}899* <li>{@code SwingConstants.CENTER}900* <li>{@code SwingConstants.LEADING}901* <li>{@code SwingConstants.TRAILING} (the default)902* </ul>903* @exception IllegalArgumentException if <code>textPosition</code>904* is not one of the legal values listed above905* @beaninfo906* bound: true907* enum: LEFT SwingConstants.LEFT908* CENTER SwingConstants.CENTER909* RIGHT SwingConstants.RIGHT910* LEADING SwingConstants.LEADING911* TRAILING SwingConstants.TRAILING912* attribute: visualUpdate true913* description: The horizontal position of the text relative to the icon.914*/915public void setHorizontalTextPosition(int textPosition) {916if (textPosition == horizontalTextPosition) return;917int oldValue = horizontalTextPosition;918horizontalTextPosition = checkHorizontalKey(textPosition,919"horizontalTextPosition");920firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY,921oldValue,922horizontalTextPosition);923revalidate();924repaint();925}926927/**928* Returns the amount of space between the text and the icon929* displayed in this button.930*931* @return an int equal to the number of pixels between the text932* and the icon.933* @since 1.4934* @see #setIconTextGap935*/936public int getIconTextGap() {937return iconTextGap;938}939940/**941* If both the icon and text properties are set, this property942* defines the space between them.943* <p>944* The default value of this property is 4 pixels.945* <p>946* This is a JavaBeans bound property.947*948* @since 1.4949* @see #getIconTextGap950* @beaninfo951* bound: true952* attribute: visualUpdate true953* description: If both the icon and text properties are set, this954* property defines the space between them.955*/956public void setIconTextGap(int iconTextGap) {957int oldValue = this.iconTextGap;958this.iconTextGap = iconTextGap;959iconTextGapSet = true;960firePropertyChange("iconTextGap", oldValue, iconTextGap);961if (iconTextGap != oldValue) {962revalidate();963repaint();964}965}966967/**968* Verify that the {@code key} argument is a legal value for the969* {@code horizontalAlignment} and {@code horizontalTextPosition}970* properties. Valid values are:971* <ul>972* <li>{@code SwingConstants.RIGHT}973* <li>{@code SwingConstants.LEFT}974* <li>{@code SwingConstants.CENTER}975* <li>{@code SwingConstants.LEADING}976* <li>{@code SwingConstants.TRAILING}977* </ul>978*979* @param key the property value to check980* @param exception the message to use in the981* {@code IllegalArgumentException} that is thrown for an invalid982* value983* @return the {@code key} argument984* @exception IllegalArgumentException if key is not one of the legal985* values listed above986* @see #setHorizontalTextPosition987* @see #setHorizontalAlignment988*/989protected int checkHorizontalKey(int key, String exception) {990if ((key == LEFT) ||991(key == CENTER) ||992(key == RIGHT) ||993(key == LEADING) ||994(key == TRAILING)) {995return key;996} else {997throw new IllegalArgumentException(exception);998}999}10001001/**1002* Verify that the {@code key} argument is a legal value for the1003* 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 check1011* @param exception the message to use in the1012* {@code IllegalArgumentException} that is thrown for an invalid1013* value1014* @return the {@code key} argument1015* @exception IllegalArgumentException if key is not one of the legal1016* values listed above1017*/1018protected int checkVerticalKey(int key, String exception) {1019if ((key == TOP) || (key == CENTER) || (key == BOTTOM)) {1020return key;1021} else {1022throw new IllegalArgumentException(exception);1023}1024}10251026/**1027*{@inheritDoc}1028*1029* @since 1.61030*/1031public void removeNotify() {1032super.removeNotify();1033if(isRolloverEnabled()) {1034getModel().setRollover(false);1035}1036}10371038/**1039* Sets the action command for this button.1040* @param actionCommand the action command for this button1041*/1042public void setActionCommand(String actionCommand) {1043getModel().setActionCommand(actionCommand);1044}10451046/**1047* Returns the action command for this button.1048* @return the action command for this button1049*/1050public String getActionCommand() {1051String ac = getModel().getActionCommand();1052if(ac == null) {1053ac = getText();1054}1055return ac;1056}10571058private Action action;1059private PropertyChangeListener actionPropertyChangeListener;10601061/**1062* Sets the <code>Action</code>.1063* The new <code>Action</code> replaces any previously set1064* <code>Action</code> but does not affect <code>ActionListeners</code>1065* independently added with <code>addActionListener</code>.1066* If the <code>Action</code> is already a registered1067* <code>ActionListener</code> for the button, it is not re-registered.1068* <p>1069* Setting the <code>Action</code> results in immediately changing1070* all the properties described in <a href="Action.html#buttonActions">1071* Swing Components Supporting <code>Action</code></a>.1072* Subsequently, the button's properties are automatically updated1073* as the <code>Action</code>'s properties change.1074* <p>1075* This method uses three other methods to set1076* and help track the <code>Action</code>'s property values.1077* It uses the <code>configurePropertiesFromAction</code> method1078* to immediately change the button's properties.1079* To track changes in the <code>Action</code>'s property values,1080* this method registers the <code>PropertyChangeListener</code>1081* returned by <code>createActionPropertyChangeListener</code>. The1082* default {@code PropertyChangeListener} invokes the1083* {@code actionPropertyChanged} method when a property in the1084* {@code Action} changes.1085*1086* @param a the <code>Action</code> for the <code>AbstractButton</code>,1087* or <code>null</code>1088* @since 1.31089* @see Action1090* @see #getAction1091* @see #configurePropertiesFromAction1092* @see #createActionPropertyChangeListener1093* @see #actionPropertyChanged1094* @beaninfo1095* bound: true1096* attribute: visualUpdate true1097* description: the Action instance connected with this ActionEvent source1098*/1099public void setAction(Action a) {1100Action oldValue = getAction();1101if (action==null || !action.equals(a)) {1102action = a;1103if (oldValue!=null) {1104removeActionListener(oldValue);1105oldValue.removePropertyChangeListener(actionPropertyChangeListener);1106actionPropertyChangeListener = null;1107}1108configurePropertiesFromAction(action);1109if (action!=null) {1110// Don't add if it is already a listener1111if (!isListener(ActionListener.class, action)) {1112addActionListener(action);1113}1114// Reverse linkage:1115actionPropertyChangeListener = createActionPropertyChangeListener(action);1116action.addPropertyChangeListener(actionPropertyChangeListener);1117}1118firePropertyChange("action", oldValue, action);1119}1120}11211122private boolean isListener(Class c, ActionListener a) {1123boolean isListener = false;1124Object[] listeners = listenerList.getListenerList();1125for (int i = listeners.length-2; i>=0; i-=2) {1126if (listeners[i]==c && listeners[i+1]==a) {1127isListener=true;1128}1129}1130return isListener;1131}11321133/**1134* Returns the currently set <code>Action</code> for this1135* <code>ActionEvent</code> source, or <code>null</code>1136* if no <code>Action</code> is set.1137*1138* @return the <code>Action</code> for this <code>ActionEvent</code>1139* source, or <code>null</code>1140* @since 1.31141* @see Action1142* @see #setAction1143*/1144public Action getAction() {1145return action;1146}11471148/**1149* Sets the properties on this button to match those in the specified1150* <code>Action</code>. Refer to <a href="Action.html#buttonActions">1151* Swing Components Supporting <code>Action</code></a> for more1152* details as to which properties this sets.1153*1154* @param a the <code>Action</code> from which to get the properties,1155* or <code>null</code>1156* @since 1.31157* @see Action1158* @see #setAction1159*/1160protected void configurePropertiesFromAction(Action a) {1161setMnemonicFromAction(a);1162setTextFromAction(a, false);1163AbstractAction.setToolTipTextFromAction(this, a);1164setIconFromAction(a);1165setActionCommandFromAction(a);1166AbstractAction.setEnabledFromAction(this, a);1167if (AbstractAction.hasSelectedKey(a) &&1168shouldUpdateSelectedStateFromAction()) {1169setSelectedFromAction(a);1170}1171setDisplayedMnemonicIndexFromAction(a, false);1172}11731174void clientPropertyChanged(Object key, Object oldValue,1175Object newValue) {1176if (key == "hideActionText") {1177boolean current = (newValue instanceof Boolean) ?1178(Boolean)newValue : false;1179if (getHideActionText() != current) {1180setHideActionText(current);1181}1182}1183}11841185/**1186* Button subclasses that support mirroring the selected state from1187* the action should override this to return true. AbstractButton's1188* implementation returns false.1189*/1190boolean shouldUpdateSelectedStateFromAction() {1191return false;1192}11931194/**1195* Updates the button's state in response to property changes in the1196* associated action. This method is invoked from the1197* {@code PropertyChangeListener} returned from1198* {@code createActionPropertyChangeListener}. Subclasses do not normally1199* need to invoke this. Subclasses that support additional {@code Action}1200* properties should override this and1201* {@code configurePropertiesFromAction}.1202* <p>1203* Refer to the table at <a href="Action.html#buttonActions">1204* Swing Components Supporting <code>Action</code></a> for a list of1205* the properties this method sets.1206*1207* @param action the <code>Action</code> associated with this button1208* @param propertyName the name of the property that changed1209* @since 1.61210* @see Action1211* @see #configurePropertiesFromAction1212*/1213protected void actionPropertyChanged(Action action, String propertyName) {1214if (propertyName == Action.NAME) {1215setTextFromAction(action, true);1216} else if (propertyName == "enabled") {1217AbstractAction.setEnabledFromAction(this, action);1218} else if (propertyName == Action.SHORT_DESCRIPTION) {1219AbstractAction.setToolTipTextFromAction(this, action);1220} else if (propertyName == Action.SMALL_ICON) {1221smallIconChanged(action);1222} else if (propertyName == Action.MNEMONIC_KEY) {1223setMnemonicFromAction(action);1224} else if (propertyName == Action.ACTION_COMMAND_KEY) {1225setActionCommandFromAction(action);1226} else if (propertyName == Action.SELECTED_KEY &&1227AbstractAction.hasSelectedKey(action) &&1228shouldUpdateSelectedStateFromAction()) {1229setSelectedFromAction(action);1230} else if (propertyName == Action.DISPLAYED_MNEMONIC_INDEX_KEY) {1231setDisplayedMnemonicIndexFromAction(action, true);1232} else if (propertyName == Action.LARGE_ICON_KEY) {1233largeIconChanged(action);1234}1235}12361237private void setDisplayedMnemonicIndexFromAction(1238Action a, boolean fromPropertyChange) {1239Integer iValue = (a == null) ? null :1240(Integer)a.getValue(Action.DISPLAYED_MNEMONIC_INDEX_KEY);1241if (fromPropertyChange || iValue != null) {1242int value;1243if (iValue == null) {1244value = -1;1245} else {1246value = iValue;1247String text = getText();1248if (text == null || value >= text.length()) {1249value = -1;1250}1251}1252setDisplayedMnemonicIndex(value);1253}1254}12551256private void setMnemonicFromAction(Action a) {1257Integer n = (a == null) ? null :1258(Integer)a.getValue(Action.MNEMONIC_KEY);1259setMnemonic((n == null) ? '\0' : n);1260}12611262private void setTextFromAction(Action a, boolean propertyChange) {1263boolean hideText = getHideActionText();1264if (!propertyChange) {1265setText((a != null && !hideText) ?1266(String)a.getValue(Action.NAME) : null);1267}1268else if (!hideText) {1269setText((String)a.getValue(Action.NAME));1270}1271}12721273void setIconFromAction(Action a) {1274Icon icon = null;1275if (a != null) {1276icon = (Icon)a.getValue(Action.LARGE_ICON_KEY);1277if (icon == null) {1278icon = (Icon)a.getValue(Action.SMALL_ICON);1279}1280}1281setIcon(icon);1282}12831284void smallIconChanged(Action a) {1285if (a.getValue(Action.LARGE_ICON_KEY) == null) {1286setIconFromAction(a);1287}1288}12891290void largeIconChanged(Action a) {1291setIconFromAction(a);1292}12931294private void setActionCommandFromAction(Action a) {1295setActionCommand((a != null) ?1296(String)a.getValue(Action.ACTION_COMMAND_KEY) :1297null);1298}12991300/**1301* Sets the seleted state of the button from the action. This is defined1302* here, but not wired up. Subclasses like JToggleButton and1303* JCheckBoxMenuItem make use of it.1304*1305* @param a the Action1306*/1307private void setSelectedFromAction(Action a) {1308boolean selected = false;1309if (a != null) {1310selected = AbstractAction.isSelected(a);1311}1312if (selected != isSelected()) {1313// This won't notify ActionListeners, but that should be1314// ok as the change is coming from the Action.1315setSelected(selected);1316// Make sure the change actually took effect1317if (!selected && isSelected()) {1318if (getModel() instanceof DefaultButtonModel) {1319ButtonGroup group = ((DefaultButtonModel)getModel()).getGroup();1320if (group != null) {1321group.clearSelection();1322}1323}1324}1325}1326}13271328/**1329* Creates and returns a <code>PropertyChangeListener</code> that is1330* responsible for listening for changes from the specified1331* <code>Action</code> and updating the appropriate properties.1332* <p>1333* <b>Warning:</b> If you subclass this do not create an anonymous1334* inner class. If you do the lifetime of the button will be tied to1335* that of the <code>Action</code>.1336*1337* @param a the button's action1338* @since 1.31339* @see Action1340* @see #setAction1341*/1342protected PropertyChangeListener createActionPropertyChangeListener(Action a) {1343return createActionPropertyChangeListener0(a);1344}134513461347PropertyChangeListener createActionPropertyChangeListener0(Action a) {1348return new ButtonActionPropertyChangeListener(this, a);1349}13501351@SuppressWarnings("serial")1352private static class ButtonActionPropertyChangeListener1353extends ActionPropertyChangeListener<AbstractButton> {1354ButtonActionPropertyChangeListener(AbstractButton b, Action a) {1355super(b, a);1356}1357protected void actionPropertyChanged(AbstractButton button,1358Action action,1359PropertyChangeEvent e) {1360if (AbstractAction.shouldReconfigure(e)) {1361button.configurePropertiesFromAction(action);1362} else {1363button.actionPropertyChanged(action, e.getPropertyName());1364}1365}1366}13671368/**1369* Gets the <code>borderPainted</code> property.1370*1371* @return the value of the <code>borderPainted</code> property1372* @see #setBorderPainted1373*/1374public boolean isBorderPainted() {1375return paintBorder;1376}13771378/**1379* Sets the <code>borderPainted</code> property.1380* If <code>true</code> and the button has a border,1381* the border is painted. The default value for the1382* <code>borderPainted</code> property is <code>true</code>.1383* <p>1384* Some look and feels might not support1385* the <code>borderPainted</code> property,1386* in which case they ignore this.1387*1388* @param b if true and border property is not <code>null</code>,1389* the border is painted1390* @see #isBorderPainted1391* @beaninfo1392* bound: true1393* attribute: visualUpdate true1394* description: Whether the border should be painted.1395*/1396public void setBorderPainted(boolean b) {1397boolean oldValue = paintBorder;1398paintBorder = b;1399borderPaintedSet = true;1400firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, oldValue, paintBorder);1401if (b != oldValue) {1402revalidate();1403repaint();1404}1405}14061407/**1408* Paint the button's border if <code>BorderPainted</code>1409* property is true and the button has a border.1410* @param g the <code>Graphics</code> context in which to paint1411*1412* @see #paint1413* @see #setBorder1414*/1415protected void paintBorder(Graphics g) {1416if (isBorderPainted()) {1417super.paintBorder(g);1418}1419}14201421/**1422* Gets the <code>paintFocus</code> property.1423*1424* @return the <code>paintFocus</code> property1425* @see #setFocusPainted1426*/1427public boolean isFocusPainted() {1428return paintFocus;1429}14301431/**1432* Sets the <code>paintFocus</code> property, which must1433* be <code>true</code> for the focus state to be painted.1434* The default value for the <code>paintFocus</code> property1435* is <code>true</code>.1436* Some look and feels might not paint focus state;1437* they will ignore this property.1438*1439* @param b if <code>true</code>, the focus state should be painted1440* @see #isFocusPainted1441* @beaninfo1442* bound: true1443* attribute: visualUpdate true1444* description: Whether focus should be painted1445*/1446public void setFocusPainted(boolean b) {1447boolean oldValue = paintFocus;1448paintFocus = b;1449firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, oldValue, paintFocus);1450if (b != oldValue && isFocusOwner()) {1451revalidate();1452repaint();1453}1454}14551456/**1457* Gets the <code>contentAreaFilled</code> property.1458*1459* @return the <code>contentAreaFilled</code> property1460* @see #setContentAreaFilled1461*/1462public boolean isContentAreaFilled() {1463return contentAreaFilled;1464}14651466/**1467* Sets the <code>contentAreaFilled</code> property.1468* If <code>true</code> the button will paint the content1469* area. If you wish to have a transparent button, such as1470* an icon only button, for example, then you should set1471* this to <code>false</code>. Do not call <code>setOpaque(false)</code>.1472* The default value for the the <code>contentAreaFilled</code>1473* property is <code>true</code>.1474* <p>1475* This function may cause the component's opaque property to change.1476* <p>1477* The exact behavior of calling this function varies on a1478* component-by-component and L&F-by-L&F basis.1479*1480* @param b if true, the content should be filled; if false1481* the content area is not filled1482* @see #isContentAreaFilled1483* @see #setOpaque1484* @beaninfo1485* bound: true1486* attribute: visualUpdate true1487* description: Whether the button should paint the content area1488* or leave it transparent.1489*/1490public void setContentAreaFilled(boolean b) {1491boolean oldValue = contentAreaFilled;1492contentAreaFilled = b;1493contentAreaFilledSet = true;1494firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, oldValue, contentAreaFilled);1495if (b != oldValue) {1496repaint();1497}1498}14991500/**1501* Gets the <code>rolloverEnabled</code> property.1502*1503* @return the value of the <code>rolloverEnabled</code> property1504* @see #setRolloverEnabled1505*/1506public boolean isRolloverEnabled() {1507return rolloverEnabled;1508}15091510/**1511* Sets the <code>rolloverEnabled</code> property, which1512* must be <code>true</code> for rollover effects to occur.1513* The default value for the <code>rolloverEnabled</code>1514* property is <code>false</code>.1515* Some look and feels might not implement rollover effects;1516* they will ignore this property.1517*1518* @param b if <code>true</code>, rollover effects should be painted1519* @see #isRolloverEnabled1520* @beaninfo1521* bound: true1522* attribute: visualUpdate true1523* description: Whether rollover effects should be enabled.1524*/1525public void setRolloverEnabled(boolean b) {1526boolean oldValue = rolloverEnabled;1527rolloverEnabled = b;1528rolloverEnabledSet = true;1529firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, oldValue, rolloverEnabled);1530if (b != oldValue) {1531repaint();1532}1533}15341535/**1536* Returns the keyboard mnemonic from the the current model.1537* @return the keyboard mnemonic from the model1538*/1539public int getMnemonic() {1540return mnemonic;1541}15421543/**1544* Sets the keyboard mnemonic on the current model.1545* The mnemonic is the key which when combined with the look and feel's1546* mouseless modifier (usually Alt) will activate this button1547* if focus is contained somewhere within this button's ancestor1548* window.1549* <p>1550* A mnemonic must correspond to a single key on the keyboard1551* and should be specified using one of the <code>VK_XXX</code>1552* keycodes defined in <code>java.awt.event.KeyEvent</code>.1553* These codes and the wider array of codes for international1554* keyboards may be obtained through1555* <code>java.awt.event.KeyEvent.getExtendedKeyCodeForChar</code>.1556* Mnemonics are case-insensitive, therefore a key event1557* with the corresponding keycode would cause the button to be1558* activated whether or not the Shift modifier was pressed.1559* <p>1560* If the character defined by the mnemonic is found within1561* the button's label string, the first occurrence of it1562* will be underlined to indicate the mnemonic to the user.1563*1564* @param mnemonic the key code which represents the mnemonic1565* @see java.awt.event.KeyEvent1566* @see #setDisplayedMnemonicIndex1567*1568* @beaninfo1569* bound: true1570* attribute: visualUpdate true1571* description: the keyboard character mnemonic1572*/1573public void setMnemonic(int mnemonic) {1574int oldValue = getMnemonic();1575model.setMnemonic(mnemonic);1576updateMnemonicProperties();1577}15781579/**1580* This method is now obsolete, please use <code>setMnemonic(int)</code>1581* to set the mnemonic for a button. This method is only designed1582* to handle character values which fall between 'a' and 'z' or1583* 'A' and 'Z'.1584*1585* @param mnemonic a char specifying the mnemonic value1586* @see #setMnemonic(int)1587* @beaninfo1588* bound: true1589* attribute: visualUpdate true1590* description: the keyboard character mnemonic1591*/1592public void setMnemonic(char mnemonic) {1593int vk = (int) mnemonic;1594if(vk >= 'a' && vk <='z')1595vk -= ('a' - 'A');1596setMnemonic(vk);1597}15981599/**1600* Provides a hint to the look and feel as to which character in the1601* text should be decorated to represent the mnemonic. Not all look and1602* feels may support this. A value of -1 indicates either there is no1603* mnemonic, the mnemonic character is not contained in the string, or1604* the developer does not wish the mnemonic to be displayed.1605* <p>1606* The value of this is updated as the properties relating to the1607* mnemonic change (such as the mnemonic itself, the text...).1608* You should only ever have to call this if1609* you do not wish the default character to be underlined. For example, if1610* the text was 'Save As', with a mnemonic of 'a', and you wanted the 'A'1611* to be decorated, as 'Save <u>A</u>s', you would have to invoke1612* <code>setDisplayedMnemonicIndex(5)</code> after invoking1613* <code>setMnemonic(KeyEvent.VK_A)</code>.1614*1615* @since 1.41616* @param index Index into the String to underline1617* @exception IllegalArgumentException will be thrown if <code>index</code>1618* is >= length of the text, or < -11619* @see #getDisplayedMnemonicIndex1620*1621* @beaninfo1622* bound: true1623* attribute: visualUpdate true1624* description: the index into the String to draw the keyboard character1625* mnemonic at1626*/1627public void setDisplayedMnemonicIndex(int index)1628throws IllegalArgumentException {1629int oldValue = mnemonicIndex;1630if (index == -1) {1631mnemonicIndex = -1;1632} else {1633String text = getText();1634int textLength = (text == null) ? 0 : text.length();1635if (index < -1 || index >= textLength) { // index out of range1636throw new IllegalArgumentException("index == " + index);1637}1638}1639mnemonicIndex = index;1640firePropertyChange("displayedMnemonicIndex", oldValue, index);1641if (index != oldValue) {1642revalidate();1643repaint();1644}1645}16461647/**1648* Returns the character, as an index, that the look and feel should1649* provide decoration for as representing the mnemonic character.1650*1651* @since 1.41652* @return index representing mnemonic character1653* @see #setDisplayedMnemonicIndex1654*/1655public int getDisplayedMnemonicIndex() {1656return mnemonicIndex;1657}16581659/**1660* Update the displayedMnemonicIndex property. This method1661* is called when either text or mnemonic changes. The new1662* value of the displayedMnemonicIndex property is the index1663* of the first occurrence of mnemonic in text.1664*/1665private void updateDisplayedMnemonicIndex(String text, int mnemonic) {1666setDisplayedMnemonicIndex(1667SwingUtilities.findDisplayedMnemonicIndex(text, mnemonic));1668}16691670/**1671* Brings the mnemonic property in accordance with model's mnemonic.1672* This is called when model's mnemonic changes. Also updates the1673* displayedMnemonicIndex property.1674*/1675private void updateMnemonicProperties() {1676int newMnemonic = model.getMnemonic();1677if (mnemonic != newMnemonic) {1678int oldValue = mnemonic;1679mnemonic = newMnemonic;1680firePropertyChange(MNEMONIC_CHANGED_PROPERTY,1681oldValue, mnemonic);1682updateDisplayedMnemonicIndex(getText(), mnemonic);1683revalidate();1684repaint();1685}1686}16871688/**1689* Sets the amount of time (in milliseconds) required between1690* mouse press events for the button to generate the corresponding1691* action events. After the initial mouse press occurs (and action1692* event generated) any subsequent mouse press events which occur1693* on intervals less than the threshhold will be ignored and no1694* corresponding action event generated. By default the threshhold is 0,1695* which means that for each mouse press, an action event will be1696* fired, no matter how quickly the mouse clicks occur. In buttons1697* where this behavior is not desirable (for example, the "OK" button1698* in a dialog), this threshhold should be set to an appropriate1699* positive value.1700*1701* @see #getMultiClickThreshhold1702* @param threshhold the amount of time required between mouse1703* press events to generate corresponding action events1704* @exception IllegalArgumentException if threshhold < 01705* @since 1.41706*/1707public void setMultiClickThreshhold(long threshhold) {1708if (threshhold < 0) {1709throw new IllegalArgumentException("threshhold must be >= 0");1710}1711this.multiClickThreshhold = threshhold;1712}17131714/**1715* Gets the amount of time (in milliseconds) required between1716* mouse press events for the button to generate the corresponding1717* action events.1718*1719* @see #setMultiClickThreshhold1720* @return the amount of time required between mouse press events1721* to generate corresponding action events1722* @since 1.41723*/1724public long getMultiClickThreshhold() {1725return multiClickThreshhold;1726}17271728/**1729* Returns the model that this button represents.1730* @return the <code>model</code> property1731* @see #setModel1732*/1733public ButtonModel getModel() {1734return model;1735}17361737/**1738* Sets the model that this button represents.1739* @param newModel the new <code>ButtonModel</code>1740* @see #getModel1741* @beaninfo1742* bound: true1743* description: Model that the Button uses.1744*/1745public void setModel(ButtonModel newModel) {17461747ButtonModel oldModel = getModel();17481749if (oldModel != null) {1750oldModel.removeChangeListener(changeListener);1751oldModel.removeActionListener(actionListener);1752oldModel.removeItemListener(itemListener);1753changeListener = null;1754actionListener = null;1755itemListener = null;1756}17571758model = newModel;17591760if (newModel != null) {1761changeListener = createChangeListener();1762actionListener = createActionListener();1763itemListener = createItemListener();1764newModel.addChangeListener(changeListener);1765newModel.addActionListener(actionListener);1766newModel.addItemListener(itemListener);17671768updateMnemonicProperties();1769//We invoke setEnabled() from JComponent1770//because setModel() can be called from a constructor1771//when the button is not fully initialized1772super.setEnabled(newModel.isEnabled());17731774} else {1775mnemonic = '\0';1776}17771778updateDisplayedMnemonicIndex(getText(), mnemonic);17791780firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel);1781if (newModel != oldModel) {1782revalidate();1783repaint();1784}1785}178617871788/**1789* Returns the L&F object that renders this component.1790* @return the ButtonUI object1791* @see #setUI1792*/1793public ButtonUI getUI() {1794return (ButtonUI) ui;1795}179617971798/**1799* Sets the L&F object that renders this component.1800* @param ui the <code>ButtonUI</code> L&F object1801* @see #getUI1802* @beaninfo1803* bound: true1804* hidden: true1805* attribute: visualUpdate true1806* description: The UI object that implements the LookAndFeel.1807*/1808public void setUI(ButtonUI ui) {1809super.setUI(ui);1810// disabled icons are generated by the LF so they should be unset here1811if (disabledIcon instanceof UIResource) {1812setDisabledIcon(null);1813}1814if (disabledSelectedIcon instanceof UIResource) {1815setDisabledSelectedIcon(null);1816}1817}181818191820/**1821* Resets the UI property to a value from the current look1822* and feel. Subtypes of <code>AbstractButton</code>1823* should override this to update the UI. For1824* example, <code>JButton</code> might do the following:1825* <pre>1826* setUI((ButtonUI)UIManager.getUI(1827* "ButtonUI", "javax.swing.plaf.basic.BasicButtonUI", this));1828* </pre>1829*/1830public void updateUI() {1831}18321833/**1834* Adds the specified component to this container at the specified1835* index, refer to1836* {@link java.awt.Container#addImpl(Component, Object, int)}1837* for a complete description of this method.1838*1839* @param comp the component to be added1840* @param constraints an object expressing layout constraints1841* for this component1842* @param index the position in the container's list at which to1843* insert the component, where <code>-1</code>1844* means append to the end1845* @exception IllegalArgumentException if <code>index</code> is invalid1846* @exception IllegalArgumentException if adding the container's parent1847* to itself1848* @exception IllegalArgumentException if adding a window to a container1849* @since 1.51850*/1851protected void addImpl(Component comp, Object constraints, int index) {1852if (!setLayout) {1853setLayout(new OverlayLayout(this));1854}1855super.addImpl(comp, constraints, index);1856}18571858/**1859* Sets the layout manager for this container, refer to1860* {@link java.awt.Container#setLayout(LayoutManager)}1861* for a complete description of this method.1862*1863* @param mgr the specified layout manager1864* @since 1.51865*/1866public void setLayout(LayoutManager mgr) {1867setLayout = true;1868super.setLayout(mgr);1869}18701871/**1872* Adds a <code>ChangeListener</code> to the button.1873* @param l the listener to be added1874*/1875public void addChangeListener(ChangeListener l) {1876listenerList.add(ChangeListener.class, l);1877}18781879/**1880* Removes a ChangeListener from the button.1881* @param l the listener to be removed1882*/1883public void removeChangeListener(ChangeListener l) {1884listenerList.remove(ChangeListener.class, l);1885}18861887/**1888* Returns an array of all the <code>ChangeListener</code>s added1889* to this AbstractButton with addChangeListener().1890*1891* @return all of the <code>ChangeListener</code>s added or an empty1892* array if no listeners have been added1893* @since 1.41894*/1895public ChangeListener[] getChangeListeners() {1896return listenerList.getListeners(ChangeListener.class);1897}18981899/**1900* Notifies all listeners that have registered interest for1901* notification on this event type. The event instance1902* is lazily created.1903* @see EventListenerList1904*/1905protected void fireStateChanged() {1906// Guaranteed to return a non-null array1907Object[] listeners = listenerList.getListenerList();1908// Process the listeners last to first, notifying1909// those that are interested in this event1910for (int i = listeners.length-2; i>=0; i-=2) {1911if (listeners[i]==ChangeListener.class) {1912// Lazily create the event:1913if (changeEvent == null)1914changeEvent = new ChangeEvent(this);1915((ChangeListener)listeners[i+1]).stateChanged(changeEvent);1916}1917}1918}19191920/**1921* Adds an <code>ActionListener</code> to the button.1922* @param l the <code>ActionListener</code> to be added1923*/1924public void addActionListener(ActionListener l) {1925listenerList.add(ActionListener.class, l);1926}19271928/**1929* Removes an <code>ActionListener</code> from the button.1930* If the listener is the currently set <code>Action</code>1931* for the button, then the <code>Action</code>1932* is set to <code>null</code>.1933*1934* @param l the listener to be removed1935*/1936public void removeActionListener(ActionListener l) {1937if ((l != null) && (getAction() == l)) {1938setAction(null);1939} else {1940listenerList.remove(ActionListener.class, l);1941}1942}19431944/**1945* Returns an array of all the <code>ActionListener</code>s added1946* to this AbstractButton with addActionListener().1947*1948* @return all of the <code>ActionListener</code>s added or an empty1949* array if no listeners have been added1950* @since 1.41951*/1952public ActionListener[] getActionListeners() {1953return listenerList.getListeners(ActionListener.class);1954}19551956/**1957* Subclasses that want to handle <code>ChangeEvents</code> differently1958* can override this to return another <code>ChangeListener</code>1959* implementation.1960*1961* @return the new <code>ChangeListener</code>1962*/1963protected ChangeListener createChangeListener() {1964return getHandler();1965}19661967/**1968* Extends <code>ChangeListener</code> to be serializable.1969* <p>1970* <strong>Warning:</strong>1971* Serialized objects of this class will not be compatible with1972* future Swing releases. The current serialization support is1973* appropriate for short term storage or RMI between applications running1974* the same version of Swing. As of 1.4, support for long term storage1975* of all JavaBeans™1976* has been added to the <code>java.beans</code> package.1977* Please see {@link java.beans.XMLEncoder}.1978*/1979@SuppressWarnings("serial")1980protected class ButtonChangeListener implements ChangeListener, Serializable {1981// NOTE: This class is NOT used, instead the functionality has1982// been moved to Handler.1983ButtonChangeListener() {1984}19851986public void stateChanged(ChangeEvent e) {1987getHandler().stateChanged(e);1988}1989}199019911992/**1993* Notifies all listeners that have registered interest for1994* notification on this event type. The event instance1995* is lazily created using the <code>event</code>1996* parameter.1997*1998* @param event the <code>ActionEvent</code> object1999* @see EventListenerList2000*/2001protected void fireActionPerformed(ActionEvent event) {2002// Guaranteed to return a non-null array2003Object[] listeners = listenerList.getListenerList();2004ActionEvent e = null;2005// Process the listeners last to first, notifying2006// those that are interested in this event2007for (int i = listeners.length-2; i>=0; i-=2) {2008if (listeners[i]==ActionListener.class) {2009// Lazily create the event:2010if (e == null) {2011String actionCommand = event.getActionCommand();2012if(actionCommand == null) {2013actionCommand = getActionCommand();2014}2015e = new ActionEvent(AbstractButton.this,2016ActionEvent.ACTION_PERFORMED,2017actionCommand,2018event.getWhen(),2019event.getModifiers());2020}2021((ActionListener)listeners[i+1]).actionPerformed(e);2022}2023}2024}20252026/**2027* Notifies all listeners that have registered interest for2028* notification on this event type. The event instance2029* is lazily created using the <code>event</code> parameter.2030*2031* @param event the <code>ItemEvent</code> object2032* @see EventListenerList2033*/2034protected void fireItemStateChanged(ItemEvent event) {2035// Guaranteed to return a non-null array2036Object[] listeners = listenerList.getListenerList();2037ItemEvent e = null;2038// Process the listeners last to first, notifying2039// those that are interested in this event2040for (int i = listeners.length-2; i>=0; i-=2) {2041if (listeners[i]==ItemListener.class) {2042// Lazily create the event:2043if (e == null) {2044e = new ItemEvent(AbstractButton.this,2045ItemEvent.ITEM_STATE_CHANGED,2046AbstractButton.this,2047event.getStateChange());2048}2049((ItemListener)listeners[i+1]).itemStateChanged(e);2050}2051}2052if (accessibleContext != null) {2053if (event.getStateChange() == ItemEvent.SELECTED) {2054accessibleContext.firePropertyChange(2055AccessibleContext.ACCESSIBLE_STATE_PROPERTY,2056null, AccessibleState.SELECTED);2057accessibleContext.firePropertyChange(2058AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,2059Integer.valueOf(0), Integer.valueOf(1));2060} else {2061accessibleContext.firePropertyChange(2062AccessibleContext.ACCESSIBLE_STATE_PROPERTY,2063AccessibleState.SELECTED, null);2064accessibleContext.firePropertyChange(2065AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,2066Integer.valueOf(1), Integer.valueOf(0));2067}2068}2069}207020712072protected ActionListener createActionListener() {2073return getHandler();2074}207520762077protected ItemListener createItemListener() {2078return getHandler();2079}208020812082/**2083* Enables (or disables) the button.2084* @param b true to enable the button, otherwise false2085*/2086public void setEnabled(boolean b) {2087if (!b && model.isRollover()) {2088model.setRollover(false);2089}2090super.setEnabled(b);2091model.setEnabled(b);2092}20932094// *** Deprecated java.awt.Button APIs below *** //20952096/**2097* Returns the label text.2098*2099* @return a <code>String</code> containing the label2100* @deprecated - Replaced by <code>getText</code>2101*/2102@Deprecated2103public String getLabel() {2104return getText();2105}21062107/**2108* Sets the label text.2109*2110* @param label a <code>String</code> containing the text2111* @deprecated - Replaced by <code>setText(text)</code>2112* @beaninfo2113* bound: true2114* description: Replace by setText(text)2115*/2116@Deprecated2117public void setLabel(String label) {2118setText(label);2119}21202121/**2122* Adds an <code>ItemListener</code> to the <code>checkbox</code>.2123* @param l the <code>ItemListener</code> to be added2124*/2125public void addItemListener(ItemListener l) {2126listenerList.add(ItemListener.class, l);2127}21282129/**2130* Removes an <code>ItemListener</code> from the button.2131* @param l the <code>ItemListener</code> to be removed2132*/2133public void removeItemListener(ItemListener l) {2134listenerList.remove(ItemListener.class, l);2135}21362137/**2138* Returns an array of all the <code>ItemListener</code>s added2139* to this AbstractButton with addItemListener().2140*2141* @return all of the <code>ItemListener</code>s added or an empty2142* array if no listeners have been added2143* @since 1.42144*/2145public ItemListener[] getItemListeners() {2146return listenerList.getListeners(ItemListener.class);2147}21482149/**2150* Returns an array (length 1) containing the label or2151* <code>null</code> if the button is not selected.2152*2153* @return an array containing 1 Object: the text of the button,2154* if the item is selected; otherwise <code>null</code>2155*/2156public Object[] getSelectedObjects() {2157if (isSelected() == false) {2158return null;2159}2160Object[] selectedObjects = new Object[1];2161selectedObjects[0] = getText();2162return selectedObjects;2163}21642165protected void init(String text, Icon icon) {2166if(text != null) {2167setText(text);2168}21692170if(icon != null) {2171setIcon(icon);2172}21732174// Set the UI2175updateUI();21762177setAlignmentX(LEFT_ALIGNMENT);2178setAlignmentY(CENTER_ALIGNMENT);2179}218021812182/**2183* This is overridden to return false if the current <code>Icon</code>'s2184* <code>Image</code> is not equal to the2185* passed in <code>Image</code> <code>img</code>.2186*2187* @param img the <code>Image</code> to be compared2188* @param infoflags flags used to repaint the button when the image2189* is updated and which determine how much is to be painted2190* @param x the x coordinate2191* @param y the y coordinate2192* @param w the width2193* @param h the height2194* @see java.awt.image.ImageObserver2195* @see java.awt.Component#imageUpdate(java.awt.Image, int, int, int, int, int)2196*/2197public boolean imageUpdate(Image img, int infoflags,2198int x, int y, int w, int h) {2199Icon iconDisplayed = null;22002201if (!model.isEnabled()) {2202if (model.isSelected()) {2203iconDisplayed = getDisabledSelectedIcon();2204} else {2205iconDisplayed = getDisabledIcon();2206}2207} else if (model.isPressed() && model.isArmed()) {2208iconDisplayed = getPressedIcon();2209} else if (isRolloverEnabled() && model.isRollover()) {2210if (model.isSelected()) {2211iconDisplayed = getRolloverSelectedIcon();2212} else {2213iconDisplayed = getRolloverIcon();2214}2215} else if (model.isSelected()) {2216iconDisplayed = getSelectedIcon();2217}22182219if (iconDisplayed == null) {2220iconDisplayed = getIcon();2221}22222223if (iconDisplayed == null2224|| !SwingUtilities.doesIconReferenceImage(iconDisplayed, img)) {2225// We don't know about this image, disable the notification so2226// we don't keep repainting.2227return false;2228}2229return super.imageUpdate(img, infoflags, x, y, w, h);2230}22312232void setUIProperty(String propertyName, Object value) {2233if (propertyName == "borderPainted") {2234if (!borderPaintedSet) {2235setBorderPainted(((Boolean)value).booleanValue());2236borderPaintedSet = false;2237}2238} else if (propertyName == "rolloverEnabled") {2239if (!rolloverEnabledSet) {2240setRolloverEnabled(((Boolean)value).booleanValue());2241rolloverEnabledSet = false;2242}2243} else if (propertyName == "iconTextGap") {2244if (!iconTextGapSet) {2245setIconTextGap(((Number)value).intValue());2246iconTextGapSet = false;2247}2248} else if (propertyName == "contentAreaFilled") {2249if (!contentAreaFilledSet) {2250setContentAreaFilled(((Boolean)value).booleanValue());2251contentAreaFilledSet = false;2252}2253} else {2254super.setUIProperty(propertyName, value);2255}2256}22572258/**2259* Returns a string representation of this <code>AbstractButton</code>.2260* This method2261* is intended to be used only for debugging purposes, and the2262* content and format of the returned string may vary between2263* implementations. The returned string may be empty but may not2264* be <code>null</code>.2265* <P>2266* Overriding <code>paramString</code> to provide information about the2267* specific new aspects of the JFC components.2268*2269* @return a string representation of this <code>AbstractButton</code>2270*/2271protected String paramString() {2272String defaultIconString = ((defaultIcon != null)2273&& (defaultIcon != this) ?2274defaultIcon.toString() : "");2275String pressedIconString = ((pressedIcon != null)2276&& (pressedIcon != this) ?2277pressedIcon.toString() : "");2278String disabledIconString = ((disabledIcon != null)2279&& (disabledIcon != this) ?2280disabledIcon.toString() : "");2281String selectedIconString = ((selectedIcon != null)2282&& (selectedIcon != this) ?2283selectedIcon.toString() : "");2284String disabledSelectedIconString = ((disabledSelectedIcon != null) &&2285(disabledSelectedIcon != this) ?2286disabledSelectedIcon.toString()2287: "");2288String rolloverIconString = ((rolloverIcon != null)2289&& (rolloverIcon != this) ?2290rolloverIcon.toString() : "");2291String rolloverSelectedIconString = ((rolloverSelectedIcon != null) &&2292(rolloverSelectedIcon != this) ?2293rolloverSelectedIcon.toString()2294: "");2295String paintBorderString = (paintBorder ? "true" : "false");2296String paintFocusString = (paintFocus ? "true" : "false");2297String rolloverEnabledString = (rolloverEnabled ? "true" : "false");22982299return super.paramString() +2300",defaultIcon=" + defaultIconString +2301",disabledIcon=" + disabledIconString +2302",disabledSelectedIcon=" + disabledSelectedIconString +2303",margin=" + margin +2304",paintBorder=" + paintBorderString +2305",paintFocus=" + paintFocusString +2306",pressedIcon=" + pressedIconString +2307",rolloverEnabled=" + rolloverEnabledString +2308",rolloverIcon=" + rolloverIconString +2309",rolloverSelectedIcon=" + rolloverSelectedIconString +2310",selectedIcon=" + selectedIconString +2311",text=" + text;2312}231323142315private Handler getHandler() {2316if (handler == null) {2317handler = new Handler();2318}2319return handler;2320}232123222323//2324// Listeners that are added to model2325//2326@SuppressWarnings("serial")2327class Handler implements ActionListener, ChangeListener, ItemListener,2328Serializable {2329//2330// ChangeListener2331//2332public void stateChanged(ChangeEvent e) {2333Object source = e.getSource();23342335updateMnemonicProperties();2336if (isEnabled() != model.isEnabled()) {2337setEnabled(model.isEnabled());2338}2339fireStateChanged();2340repaint();2341}23422343//2344// ActionListener2345//2346public void actionPerformed(ActionEvent event) {2347fireActionPerformed(event);2348}23492350//2351// ItemListener2352//2353public void itemStateChanged(ItemEvent event) {2354fireItemStateChanged(event);2355if (shouldUpdateSelectedStateFromAction()) {2356Action action = getAction();2357if (action != null && AbstractAction.hasSelectedKey(action)) {2358boolean selected = isSelected();2359boolean isActionSelected = AbstractAction.isSelected(2360action);2361if (isActionSelected != selected) {2362action.putValue(Action.SELECTED_KEY, selected);2363}2364}2365}2366}2367}23682369///////////////////2370// Accessibility support2371///////////////////2372/**2373* This class implements accessibility support for the2374* <code>AbstractButton</code> class. It provides an implementation of the2375* Java Accessibility API appropriate to button and menu item2376* user-interface elements.2377* <p>2378* <strong>Warning:</strong>2379* Serialized objects of this class will not be compatible with2380* future Swing releases. The current serialization support is2381* appropriate for short term storage or RMI between applications running2382* the same version of Swing. As of 1.4, support for long term storage2383* of all JavaBeans™2384* has been added to the <code>java.beans</code> package.2385* Please see {@link java.beans.XMLEncoder}.2386* @since 1.42387*/2388protected abstract class AccessibleAbstractButton2389extends AccessibleJComponent implements AccessibleAction,2390AccessibleValue, AccessibleText, AccessibleExtendedComponent {23912392/**2393* Returns the accessible name of this object.2394*2395* @return the localized name of the object -- can be2396* <code>null</code> if this2397* object does not have a name2398*/2399public String getAccessibleName() {2400String name = accessibleName;24012402if (name == null) {2403name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);2404}2405if (name == null) {2406name = AbstractButton.this.getText();2407}2408if (name == null) {2409name = super.getAccessibleName();2410}2411return name;2412}24132414/**2415* Get the AccessibleIcons associated with this object if one2416* or more exist. Otherwise return null.2417* @since 1.32418*/2419public AccessibleIcon [] getAccessibleIcon() {2420Icon defaultIcon = getIcon();24212422if (defaultIcon instanceof Accessible) {2423AccessibleContext ac =2424((Accessible)defaultIcon).getAccessibleContext();2425if (ac != null && ac instanceof AccessibleIcon) {2426return new AccessibleIcon[] { (AccessibleIcon)ac };2427}2428}2429return null;2430}24312432/**2433* Get the state set of this object.2434*2435* @return an instance of AccessibleState containing the current state2436* of the object2437* @see AccessibleState2438*/2439public AccessibleStateSet getAccessibleStateSet() {2440AccessibleStateSet states = super.getAccessibleStateSet();2441if (getModel().isArmed()) {2442states.add(AccessibleState.ARMED);2443}2444if (isFocusOwner()) {2445states.add(AccessibleState.FOCUSED);2446}2447if (getModel().isPressed()) {2448states.add(AccessibleState.PRESSED);2449}2450if (isSelected()) {2451states.add(AccessibleState.CHECKED);2452}2453return states;2454}24552456/**2457* Get the AccessibleRelationSet associated with this object if one2458* exists. Otherwise return null.2459* @see AccessibleRelation2460* @since 1.32461*/2462public AccessibleRelationSet getAccessibleRelationSet() {24632464// Check where the AccessibleContext's relation2465// set already contains a MEMBER_OF relation.2466AccessibleRelationSet relationSet2467= super.getAccessibleRelationSet();24682469if (!relationSet.contains(AccessibleRelation.MEMBER_OF)) {2470// get the members of the button group if one exists2471ButtonModel model = getModel();2472if (model != null && model instanceof DefaultButtonModel) {2473ButtonGroup group = ((DefaultButtonModel)model).getGroup();2474if (group != null) {2475// set the target of the MEMBER_OF relation to be2476// the members of the button group.2477int len = group.getButtonCount();2478Object [] target = new Object[len];2479Enumeration<AbstractButton> elem = group.getElements();2480for (int i = 0; i < len; i++) {2481if (elem.hasMoreElements()) {2482target[i] = elem.nextElement();2483}2484}2485AccessibleRelation relation =2486new AccessibleRelation(AccessibleRelation.MEMBER_OF);2487relation.setTarget(target);2488relationSet.add(relation);2489}2490}2491}2492return relationSet;2493}24942495/**2496* Get the AccessibleAction associated with this object. In the2497* implementation of the Java Accessibility API for this class,2498* return this object, which is responsible for implementing the2499* AccessibleAction interface on behalf of itself.2500*2501* @return this object2502*/2503public AccessibleAction getAccessibleAction() {2504return this;2505}25062507/**2508* Get the AccessibleValue associated with this object. In the2509* implementation of the Java Accessibility API for this class,2510* return this object, which is responsible for implementing the2511* AccessibleValue interface on behalf of itself.2512*2513* @return this object2514*/2515public AccessibleValue getAccessibleValue() {2516return this;2517}25182519/**2520* Returns the number of Actions available in this object. The2521* default behavior of a button is to have one action - toggle2522* the button.2523*2524* @return 1, the number of Actions in this object2525*/2526public int getAccessibleActionCount() {2527return 1;2528}25292530/**2531* Return a description of the specified action of the object.2532*2533* @param i zero-based index of the actions2534*/2535public String getAccessibleActionDescription(int i) {2536if (i == 0) {2537return UIManager.getString("AbstractButton.clickText");2538} else {2539return null;2540}2541}25422543/**2544* Perform the specified Action on the object2545*2546* @param i zero-based index of actions2547* @return true if the the action was performed; else false.2548*/2549public boolean doAccessibleAction(int i) {2550if (i == 0) {2551doClick();2552return true;2553} else {2554return false;2555}2556}25572558/**2559* Get the value of this object as a Number.2560*2561* @return An Integer of 0 if this isn't selected or an Integer of 1 if2562* this is selected.2563* @see AbstractButton#isSelected2564*/2565public Number getCurrentAccessibleValue() {2566if (isSelected()) {2567return Integer.valueOf(1);2568} else {2569return Integer.valueOf(0);2570}2571}25722573/**2574* Set the value of this object as a Number.2575*2576* @return True if the value was set.2577*/2578public boolean setCurrentAccessibleValue(Number n) {2579// TIGER - 44225352580if (n == null) {2581return false;2582}2583int i = n.intValue();2584if (i == 0) {2585setSelected(false);2586} else {2587setSelected(true);2588}2589return true;2590}25912592/**2593* Get the minimum value of this object as a Number.2594*2595* @return an Integer of 0.2596*/2597public Number getMinimumAccessibleValue() {2598return Integer.valueOf(0);2599}26002601/**2602* Get the maximum value of this object as a Number.2603*2604* @return An Integer of 1.2605*/2606public Number getMaximumAccessibleValue() {2607return Integer.valueOf(1);2608}260926102611/* AccessibleText ---------- */26122613public AccessibleText getAccessibleText() {2614View view = (View)AbstractButton.this.getClientProperty("html");2615if (view != null) {2616return this;2617} else {2618return null;2619}2620}26212622/**2623* Given a point in local coordinates, return the zero-based index2624* of the character under that Point. If the point is invalid,2625* this method returns -1.2626*2627* Note: the AbstractButton must have a valid size (e.g. have2628* been added to a parent container whose ancestor container2629* is a valid top-level window) for this method to be able2630* to return a meaningful value.2631*2632* @param p the Point in local coordinates2633* @return the zero-based index of the character under Point p; if2634* Point is invalid returns -1.2635* @since 1.32636*/2637public int getIndexAtPoint(Point p) {2638View view = (View) AbstractButton.this.getClientProperty("html");2639if (view != null) {2640Rectangle r = getTextRectangle();2641if (r == null) {2642return -1;2643}2644Rectangle2D.Float shape =2645new Rectangle2D.Float(r.x, r.y, r.width, r.height);2646Position.Bias bias[] = new Position.Bias[1];2647return view.viewToModel(p.x, p.y, shape, bias);2648} else {2649return -1;2650}2651}26522653/**2654* Determine the bounding box of the character at the given2655* index into the string. The bounds are returned in local2656* coordinates. If the index is invalid an empty rectangle is2657* returned.2658*2659* Note: the AbstractButton must have a valid size (e.g. have2660* been added to a parent container whose ancestor container2661* is a valid top-level window) for this method to be able2662* to return a meaningful value.2663*2664* @param i the index into the String2665* @return the screen coordinates of the character's the bounding box,2666* if index is invalid returns an empty rectangle.2667* @since 1.32668*/2669public Rectangle getCharacterBounds(int i) {2670View view = (View) AbstractButton.this.getClientProperty("html");2671if (view != null) {2672Rectangle r = getTextRectangle();2673if (r == null) {2674return null;2675}2676Rectangle2D.Float shape =2677new Rectangle2D.Float(r.x, r.y, r.width, r.height);2678try {2679Shape charShape =2680view.modelToView(i, shape, Position.Bias.Forward);2681return charShape.getBounds();2682} catch (BadLocationException e) {2683return null;2684}2685} else {2686return null;2687}2688}26892690/**2691* Return the number of characters (valid indicies)2692*2693* @return the number of characters2694* @since 1.32695*/2696public int getCharCount() {2697View view = (View) AbstractButton.this.getClientProperty("html");2698if (view != null) {2699Document d = view.getDocument();2700if (d instanceof StyledDocument) {2701StyledDocument doc = (StyledDocument)d;2702return doc.getLength();2703}2704}2705return accessibleContext.getAccessibleName().length();2706}27072708/**2709* Return the zero-based offset of the caret.2710*2711* Note: That to the right of the caret will have the same index2712* value as the offset (the caret is between two characters).2713* @return the zero-based offset of the caret.2714* @since 1.32715*/2716public int getCaretPosition() {2717// There is no caret.2718return -1;2719}27202721/**2722* Returns the String at a given index.2723*2724* @param part the AccessibleText.CHARACTER, AccessibleText.WORD,2725* or AccessibleText.SENTENCE to retrieve2726* @param index an index within the text >= 02727* @return the letter, word, or sentence,2728* null for an invalid index or part2729* @since 1.32730*/2731public String getAtIndex(int part, int index) {2732if (index < 0 || index >= getCharCount()) {2733return null;2734}2735switch (part) {2736case AccessibleText.CHARACTER:2737try {2738return getText(index, 1);2739} catch (BadLocationException e) {2740return null;2741}2742case AccessibleText.WORD:2743try {2744String s = getText(0, getCharCount());2745BreakIterator words = BreakIterator.getWordInstance(getLocale());2746words.setText(s);2747int end = words.following(index);2748return s.substring(words.previous(), end);2749} catch (BadLocationException e) {2750return null;2751}2752case AccessibleText.SENTENCE:2753try {2754String s = getText(0, getCharCount());2755BreakIterator sentence =2756BreakIterator.getSentenceInstance(getLocale());2757sentence.setText(s);2758int end = sentence.following(index);2759return s.substring(sentence.previous(), end);2760} catch (BadLocationException e) {2761return null;2762}2763default:2764return null;2765}2766}27672768/**2769* Returns the String after a given index.2770*2771* @param part the AccessibleText.CHARACTER, AccessibleText.WORD,2772* or AccessibleText.SENTENCE to retrieve2773* @param index an index within the text >= 02774* @return the letter, word, or sentence, null for an invalid2775* index or part2776* @since 1.32777*/2778public String getAfterIndex(int part, int index) {2779if (index < 0 || index >= getCharCount()) {2780return null;2781}2782switch (part) {2783case AccessibleText.CHARACTER:2784if (index+1 >= getCharCount()) {2785return null;2786}2787try {2788return getText(index+1, 1);2789} catch (BadLocationException e) {2790return null;2791}2792case AccessibleText.WORD:2793try {2794String s = getText(0, getCharCount());2795BreakIterator words = BreakIterator.getWordInstance(getLocale());2796words.setText(s);2797int start = words.following(index);2798if (start == BreakIterator.DONE || start >= s.length()) {2799return null;2800}2801int end = words.following(start);2802if (end == BreakIterator.DONE || end >= s.length()) {2803return null;2804}2805return s.substring(start, end);2806} catch (BadLocationException e) {2807return null;2808}2809case AccessibleText.SENTENCE:2810try {2811String s = getText(0, getCharCount());2812BreakIterator sentence =2813BreakIterator.getSentenceInstance(getLocale());2814sentence.setText(s);2815int start = sentence.following(index);2816if (start == BreakIterator.DONE || start > s.length()) {2817return null;2818}2819int end = sentence.following(start);2820if (end == BreakIterator.DONE || end > s.length()) {2821return null;2822}2823return s.substring(start, end);2824} catch (BadLocationException e) {2825return null;2826}2827default:2828return null;2829}2830}28312832/**2833* Returns the String before a given index.2834*2835* @param part the AccessibleText.CHARACTER, AccessibleText.WORD,2836* or AccessibleText.SENTENCE to retrieve2837* @param index an index within the text >= 02838* @return the letter, word, or sentence, null for an invalid index2839* or part2840* @since 1.32841*/2842public String getBeforeIndex(int part, int index) {2843if (index < 0 || index > getCharCount()-1) {2844return null;2845}2846switch (part) {2847case AccessibleText.CHARACTER:2848if (index == 0) {2849return null;2850}2851try {2852return getText(index-1, 1);2853} catch (BadLocationException e) {2854return null;2855}2856case AccessibleText.WORD:2857try {2858String s = getText(0, getCharCount());2859BreakIterator words = BreakIterator.getWordInstance(getLocale());2860words.setText(s);2861int end = words.following(index);2862end = words.previous();2863int start = words.previous();2864if (start == BreakIterator.DONE) {2865return null;2866}2867return s.substring(start, end);2868} catch (BadLocationException e) {2869return null;2870}2871case AccessibleText.SENTENCE:2872try {2873String s = getText(0, getCharCount());2874BreakIterator sentence =2875BreakIterator.getSentenceInstance(getLocale());2876sentence.setText(s);2877int end = sentence.following(index);2878end = sentence.previous();2879int start = sentence.previous();2880if (start == BreakIterator.DONE) {2881return null;2882}2883return s.substring(start, end);2884} catch (BadLocationException e) {2885return null;2886}2887default:2888return null;2889}2890}28912892/**2893* Return the AttributeSet for a given character at a given index2894*2895* @param i the zero-based index into the text2896* @return the AttributeSet of the character2897* @since 1.32898*/2899public AttributeSet getCharacterAttribute(int i) {2900View view = (View) AbstractButton.this.getClientProperty("html");2901if (view != null) {2902Document d = view.getDocument();2903if (d instanceof StyledDocument) {2904StyledDocument doc = (StyledDocument)d;2905Element elem = doc.getCharacterElement(i);2906if (elem != null) {2907return elem.getAttributes();2908}2909}2910}2911return null;2912}29132914/**2915* Returns the start offset within the selected text.2916* If there is no selection, but there is2917* a caret, the start and end offsets will be the same.2918*2919* @return the index into the text of the start of the selection2920* @since 1.32921*/2922public int getSelectionStart() {2923// Text cannot be selected.2924return -1;2925}29262927/**2928* Returns the end offset within the selected text.2929* If there is no selection, but there is2930* a caret, the start and end offsets will be the same.2931*2932* @return the index into the text of the end of the selection2933* @since 1.32934*/2935public int getSelectionEnd() {2936// Text cannot be selected.2937return -1;2938}29392940/**2941* Returns the portion of the text that is selected.2942*2943* @return the String portion of the text that is selected2944* @since 1.32945*/2946public String getSelectedText() {2947// Text cannot be selected.2948return null;2949}29502951/*2952* Returns the text substring starting at the specified2953* offset with the specified length.2954*/2955private String getText(int offset, int length)2956throws BadLocationException {29572958View view = (View) AbstractButton.this.getClientProperty("html");2959if (view != null) {2960Document d = view.getDocument();2961if (d instanceof StyledDocument) {2962StyledDocument doc = (StyledDocument)d;2963return doc.getText(offset, length);2964}2965}2966return null;2967}29682969/*2970* Returns the bounding rectangle for the component text.2971*/2972private Rectangle getTextRectangle() {29732974String text = AbstractButton.this.getText();2975Icon icon = (AbstractButton.this.isEnabled()) ? AbstractButton.this.getIcon() : AbstractButton.this.getDisabledIcon();29762977if ((icon == null) && (text == null)) {2978return null;2979}29802981Rectangle paintIconR = new Rectangle();2982Rectangle paintTextR = new Rectangle();2983Rectangle paintViewR = new Rectangle();2984Insets paintViewInsets = new Insets(0, 0, 0, 0);29852986paintViewInsets = AbstractButton.this.getInsets(paintViewInsets);2987paintViewR.x = paintViewInsets.left;2988paintViewR.y = paintViewInsets.top;2989paintViewR.width = AbstractButton.this.getWidth() - (paintViewInsets.left + paintViewInsets.right);2990paintViewR.height = AbstractButton.this.getHeight() - (paintViewInsets.top + paintViewInsets.bottom);29912992String clippedText = SwingUtilities.layoutCompoundLabel(2993AbstractButton.this,2994getFontMetrics(getFont()),2995text,2996icon,2997AbstractButton.this.getVerticalAlignment(),2998AbstractButton.this.getHorizontalAlignment(),2999AbstractButton.this.getVerticalTextPosition(),3000AbstractButton.this.getHorizontalTextPosition(),3001paintViewR,3002paintIconR,3003paintTextR,30040);30053006return paintTextR;3007}30083009// ----- AccessibleExtendedComponent30103011/**3012* Returns the AccessibleExtendedComponent3013*3014* @return the AccessibleExtendedComponent3015*/3016AccessibleExtendedComponent getAccessibleExtendedComponent() {3017return this;3018}30193020/**3021* Returns the tool tip text3022*3023* @return the tool tip text, if supported, of the object;3024* otherwise, null3025* @since 1.43026*/3027public String getToolTipText() {3028return AbstractButton.this.getToolTipText();3029}30303031/**3032* Returns the titled border text3033*3034* @return the titled border text, if supported, of the object;3035* otherwise, null3036* @since 1.43037*/3038public String getTitledBorderText() {3039return super.getTitledBorderText();3040}30413042/**3043* Returns key bindings associated with this object3044*3045* @return the key bindings, if supported, of the object;3046* otherwise, null3047* @see AccessibleKeyBinding3048* @since 1.43049*/3050public AccessibleKeyBinding getAccessibleKeyBinding() {3051int mnemonic = AbstractButton.this.getMnemonic();3052if (mnemonic == 0) {3053return null;3054}3055return new ButtonKeyBinding(mnemonic);3056}30573058class ButtonKeyBinding implements AccessibleKeyBinding {3059int mnemonic;30603061ButtonKeyBinding(int mnemonic) {3062this.mnemonic = mnemonic;3063}30643065/**3066* Returns the number of key bindings for this object3067*3068* @return the zero-based number of key bindings for this object3069*/3070public int getAccessibleKeyBindingCount() {3071return 1;3072}30733074/**3075* Returns a key binding for this object. The value returned is an3076* java.lang.Object which must be cast to appropriate type depending3077* on the underlying implementation of the key. For example, if the3078* Object returned is a javax.swing.KeyStroke, the user of this3079* method should do the following:3080* <nf><code>3081* Component c = <get the component that has the key bindings>3082* AccessibleContext ac = c.getAccessibleContext();3083* AccessibleKeyBinding akb = ac.getAccessibleKeyBinding();3084* for (int i = 0; i < akb.getAccessibleKeyBindingCount(); i++) {3085* Object o = akb.getAccessibleKeyBinding(i);3086* if (o instanceof javax.swing.KeyStroke) {3087* javax.swing.KeyStroke keyStroke = (javax.swing.KeyStroke)o;3088* <do something with the key binding>3089* }3090* }3091* </code></nf>3092*3093* @param i zero-based index of the key bindings3094* @return a javax.lang.Object which specifies the key binding3095* @exception IllegalArgumentException if the index is3096* out of bounds3097* @see #getAccessibleKeyBindingCount3098*/3099public java.lang.Object getAccessibleKeyBinding(int i) {3100if (i != 0) {3101throw new IllegalArgumentException();3102}3103return KeyStroke.getKeyStroke(mnemonic, 0);3104}3105}3106}3107}310831093110