1 /* AbstractButton.java -- Provides basic button functionality.
2 Copyright (C) 2002, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
40 import java.awt.Graphics;
41 import java.awt.Image;
42 import java.awt.Insets;
43 import java.awt.ItemSelectable;
44 import java.awt.Point;
45 import java.awt.Rectangle;
46 import java.awt.event.ActionEvent;
47 import java.awt.event.ActionListener;
48 import java.awt.event.FocusEvent;
49 import java.awt.event.FocusListener;
50 import java.awt.event.ItemEvent;
51 import java.awt.event.ItemListener;
52 import java.beans.PropertyChangeEvent;
53 import java.beans.PropertyChangeListener;
54 import java.util.EventListener;
56 import javax.accessibility.AccessibleAction;
57 import javax.accessibility.AccessibleIcon;
58 import javax.accessibility.AccessibleRelationSet;
59 import javax.accessibility.AccessibleStateSet;
60 import javax.accessibility.AccessibleText;
61 import javax.accessibility.AccessibleValue;
62 import javax.swing.event.ChangeEvent;
63 import javax.swing.event.ChangeListener;
64 import javax.swing.plaf.ButtonUI;
65 import javax.swing.text.AttributeSet;
69 * <p>The purpose of this class is to serve as a facade over a number of
70 * classes which collectively represent the semantics of a button: the
71 * button's model, its listeners, its action, and its look and feel. Some
72 * parts of a button's state are stored explicitly in this class, other
73 * parts are delegates to the model. Some methods related to buttons are
74 * implemented in this class, other methods pass through to the current
75 * model or look and feel.</p>
77 * <p>Furthermore this class is supposed to serve as a base class for
78 * several kinds of buttons with similar but non-identical semantics:
79 * toggle buttons (radio buttons and checkboxes), simple "push" buttons,
82 * <p>Buttons have many properties, some of which are stored in this class
83 * while others are delegated to the button's model. The following properties
87 * <tr><th>Property </th><th>Stored in</th><th>Bound?</th></tr>
89 * <tr><td>action </td><td>button</td> <td>no</td></tr>
90 * <tr><td>actionCommand </td><td>model</td> <td>no</td></tr>
91 * <tr><td>borderPainted </td><td>button</td> <td>yes</td></tr>
92 * <tr><td>contentAreaFilled </td><td>button</td> <td>yes</td></tr>
93 * <tr><td>disabledIcon </td><td>button</td> <td>yes</td></tr>
94 * <tr><td>disabledSelectedIcon </td><td>button</td> <td>yes</td></tr>
95 * <tr><td>displayedMnemonicIndex </td><td>button</td> <td>no</td></tr>
96 * <tr><td>enabled </td><td>model</td> <td>no</td></tr>
97 * <tr><td>focusPainted </td><td>button</td> <td>yes</td></tr>
98 * <tr><td>horizontalAlignment </td><td>button</td> <td>yes</td></tr>
99 * <tr><td>horizontalTextPosition </td><td>button</td> <td>yes</td></tr>
100 * <tr><td>icon </td><td>button</td> <td>yes</td></tr>
101 * <tr><td>iconTextGap </td><td>button</td> <td>no</td></tr>
102 * <tr><td>label (same as text) </td><td>model</td> <td>yes</td></tr>
103 * <tr><td>margin </td><td>button</td> <td>yes</td></tr>
104 * <tr><td>multiClickThreshold </td><td>button</td> <td>no</td></tr>
105 * <tr><td>pressedIcon </td><td>button</td> <td>yes</td></tr>
106 * <tr><td>rolloverEnabled </td><td>button</td> <td>yes</td></tr>
107 * <tr><td>rolloverIcon </td><td>button</td> <td>yes</td></tr>
108 * <tr><td>rolloverSelectedIcon </td><td>button</td> <td>yes</td></tr>
109 * <tr><td>selected </td><td>model</td> <td>no</td></tr>
110 * <tr><td>selectedIcon </td><td>button</td> <td>yes</td></tr>
111 * <tr><td>selectedObjects </td><td>button</td> <td>no</td></tr>
112 * <tr><td>text </td><td>model</td> <td>yes</td></tr>
113 * <tr><td>UI </td><td>button</td> <td>yes</td></tr>
114 * <tr><td>verticalAlignment </td><td>button</td> <td>yes</td></tr>
115 * <tr><td>verticalTextPosition </td><td>button</td> <td>yes</td></tr>
119 * <p>The various behavioral aspects of these properties follows:</p>
123 * <li>When non-bound properties stored in the button change, the button
124 * fires ChangeEvents to its ChangeListeners.</li>
126 * <li>When bound properties stored in the button change, the button fires
127 * PropertyChangeEvents to its PropertyChangeListeners</li>
129 * <li>If any of the model's properties change, it fires a ChangeEvent to
130 * its ChangeListeners, which include the button.</li>
132 * <li>If the button receives a ChangeEvent from its model, it will
133 * propagate the ChangeEvent to its ChangeListeners, with the ChangeEvent's
134 * "source" property set to refer to the button, rather than the model. The
135 * the button will request a repaint, to paint its updated state.</li>
137 * <li>If the model's "selected" property changes, the model will fire an
138 * ItemEvent to its ItemListeners, which include the button, in addition to
139 * the ChangeEvent which models the property change. The button propagates
140 * ItemEvents directly to its ItemListeners.</li>
142 * <li>If the model's armed and pressed properties are simultaneously
143 * <code>true</code>, the model will fire an ActionEvent to its
144 * ActionListeners, which include the button. The button will propagate
145 * this ActionEvent to its ActionListeners, with the ActionEvent's "source"
146 * property set to refer to the button, rather than the model.</li>
150 * @author Ronald Veldema (rveldema@cs.vu.nl)
151 * @author Graydon Hoare (graydon@redhat.com)
154 public abstract class AbstractButton extends JComponent
155 implements ItemSelectable, SwingConstants
157 /** The icon displayed by default. */
160 /** The icon displayed when the button is pressed. */
163 /** The icon displayed when the button is disabled. */
166 /** The icon displayed when the button is selected. */
169 /** The icon displayed when the button is selected but disabled. */
170 Icon disabled_selected_icon;
172 /** The icon displayed when the button is rolled over. */
175 /** The icon displayed when the button is selected and rolled over. */
176 Icon rollover_selected_icon;
178 /** The icon currently displayed. */
181 /** The text displayed in the button. */
184 /** The vertical alignment of the button's text and icon. */
187 /** The horizontal alignment of the button's text and icon. */
190 /** The horizontal position of the button's text relative to its icon. */
193 /** The vertical position of the button's text relative to its icon. */
196 /** Whether or not the button paints its border. */
197 boolean paint_border;
199 /** Whether or not the button paints its focus state. */
202 /** Whether or not the button fills its content area. */
203 boolean content_area_filled;
205 /** The action taken when the button is clicked. */
208 /** The button's current state. */
211 /** The margin between the button's border and its label. */
214 /** a hint to the look and feel class, suggesting which character in the
215 * button's label should be underlined when drawing the label. */
218 /** Listener the button uses to receive ActionEvents from its model. */
219 ActionListener actionListener;
221 /** Listener the button uses to receive ItemEvents from its model. */
222 ItemListener itemListener;
224 /** Listener the button uses to receive ChangeEvents from its model. */
225 ChangeListener changeListener;
227 /** Listener the button uses to receive PropertyChangeEvents from its
229 PropertyChangeListener actionPropertyChangeListener;
231 /** Fired in a PropertyChangeEvent when the "borderPainted" property changes. */
232 public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";
234 /** Fired in a PropertyChangeEvent when the "contentAreaFilled" property changes. */
235 public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled";
237 /** Fired in a PropertyChangeEvent when the "disabledIcon" property changes. */
238 public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";
240 /** Fired in a PropertyChangeEvent when the "disabledSelectedIcon" property changes. */
241 public static final String DISABLED_SELECTED_ICON_CHANGED_PROPERTY = "disabledSelectedIcon";
243 /** Fired in a PropertyChangeEvent when the "focusPainted" property changes. */
244 public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
246 /** Fired in a PropertyChangeEvent when the "horizontalAlignment" property changes. */
247 public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = "horizontalAlignment";
249 /** Fired in a PropertyChangeEvent when the "horizontalTextPosition" property changes. */
250 public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = "horizontalTextPosition";
252 /** Fired in a PropertyChangeEvent when the "icon" property changes. */
253 public static final String ICON_CHANGED_PROPERTY = "icon";
255 /** Fired in a PropertyChangeEvent when the "margin" property changes. */
256 public static final String MARGIN_CHANGED_PROPERTY = "margin";
258 /** Fired in a PropertyChangeEvent when the "mnemonic" property changes. */
259 public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic";
261 /** Fired in a PropertyChangeEvent when the "model" property changes. */
262 public static final String MODEL_CHANGED_PROPERTY = "model";
264 /** Fired in a PropertyChangeEvent when the "pressedIcon" property changes. */
265 public static final String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";
267 /** Fired in a PropertyChangeEvent when the "rolloverEnabled" property changes. */
268 public static final String ROLLOVER_ENABLED_CHANGED_PROPERTY = "rolloverEnabled";
270 /** Fired in a PropertyChangeEvent when the "rolloverIcon" property changes. */
271 public static final String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";
273 /** Fired in a PropertyChangeEvent when the "rolloverSelectedIcon" property changes. */
274 public static final String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = "rolloverSelectedIcon";
276 /** Fired in a PropertyChangeEvent when the "selectedIcon" property changes. */
277 public static final String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";
279 /** Fired in a PropertyChangeEvent when the "text" property changes. */
280 public static final String TEXT_CHANGED_PROPERTY = "text";
282 /** Fired in a PropertyChangeEvent when the "verticalAlignment" property changes. */
283 public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";
285 /** Fired in a PropertyChangeEvent when the "verticalTextPosition" property changes. */
286 public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = "verticalTextPosition";
289 * A Java Accessibility extension of the AbstractButton.
291 protected abstract class AccessibleAbstractButton
292 extends AccessibleJComponent implements AccessibleAction, AccessibleValue,
295 protected AccessibleAbstractButton(JComponent c)
300 public AccessibleStateSet getAccessibleStateSet()
305 public String getAccessibleName()
310 public AccessibleIcon[] getAccessibleIcon()
315 public AccessibleRelationSet getAccessibleRelationSet()
320 public AccessibleAction getAccessibleAction()
325 public AccessibleValue getAccessibleValue()
330 public int getAccessibleActionCount()
335 public String getAccessibleActionDescription(int value0)
340 public boolean doAccessibleAction(int value0)
342 return false; // TODO
345 public Number getCurrentAccessibleValue()
350 public boolean setCurrentAccessibleValue(Number value0)
352 return false; // TODO
355 public Number getMinimumAccessibleValue()
360 public Number getMaximumAccessibleValue()
365 public AccessibleText getAccessibleText()
370 public int getIndexAtPoint(Point value0)
375 public Rectangle getCharacterBounds(int value0)
380 public int getCharCount()
385 public int getCaretPosition()
390 public String getAtIndex(int value0, int value1)
395 public String getAfterIndex(int value0, int value1)
400 public String getBeforeIndex(int value0, int value1)
405 public AttributeSet getCharacterAttribute(int value0)
410 public int getSelectionStart()
415 public int getSelectionEnd()
420 public String getSelectedText()
425 private Rectangle getTextRectangle()
432 * Helper class used to subscribe to FocusEvents received by the button.
434 private class ButtonFocusListener implements FocusListener
437 * Possibly repaint the model in response to loss of focus.
439 * @param event The loss-of-focus event
441 public void focusLost(FocusEvent event)
443 if (AbstractButton.this.isFocusPainted())
444 AbstractButton.this.repaint();
448 * Possibly repaint the button in response to acquisition of focus.
450 * @param event The gained-focus event
452 public void focusGained(FocusEvent event)
454 if (AbstractButton.this.isFocusPainted())
455 AbstractButton.this.repaint();
460 * Creates a new AbstractButton object.
468 * Creates a new AbstractButton object.
470 * @param txt Value to use for the button's "text" property
471 * @param icon Value to use for the button's "defaultIcon" property
473 AbstractButton(String txt, Icon icon)
477 model = new DefaultButtonModel();
478 actionListener = createActionListener();
479 changeListener = createChangeListener();
480 itemListener = createItemListener();
482 model.addActionListener(actionListener);
483 model.addChangeListener(changeListener);
484 model.addItemListener(itemListener);
487 hori_text_pos = TRAILING;
489 vert_text_pos = CENTER;
491 content_area_filled = true;
493 setAlignmentX(LEFT_ALIGNMENT);
494 setAlignmentY(CENTER_ALIGNMENT);
496 addFocusListener(new ButtonFocusListener());
501 * Get the model the button is currently using.
503 * @return The current model
505 public ButtonModel getModel()
511 * Set the model the button is currently using. This un-registers all
512 * listeners associated with the current model, and re-registers them
513 * with the new model.
515 * @param newModel The new model
517 public void setModel(ButtonModel newModel)
519 if (newModel == model)
524 model.removeActionListener(actionListener);
525 model.removeChangeListener(changeListener);
526 model.removeItemListener(itemListener);
528 ButtonModel old = model;
532 model.addActionListener(actionListener);
533 model.addChangeListener(changeListener);
534 model.addItemListener(itemListener);
536 firePropertyChange(MODEL_CHANGED_PROPERTY, old, model);
542 * Get the action command string for this button's model.
544 * @return The current action command string from the button's model
546 public String getActionCommand()
548 return getModel().getActionCommand();
552 * Set the action command string for this button's model.
554 * @param aCommand The new action command string to set in the button's
557 public void setActionCommand(String aCommand)
559 getModel().setActionCommand(aCommand);
563 * Adds an ActionListener to the button's listener list. When the
564 * button's model is clicked it fires an ActionEvent, and these
565 * listeners will be called.
567 * @param l The new listener to add
569 public void addActionListener(ActionListener l)
571 listenerList.add(ActionListener.class, l);
575 * Removes an ActionListener from the button's listener list.
577 * @param l The listener to remove
579 public void removeActionListener(ActionListener l)
581 listenerList.remove(ActionListener.class, l);
585 * Adds an ItemListener to the button's listener list. When the button's
586 * model changes state (between any of ARMED, ENABLED, PRESSED, ROLLOVER
587 * or SELECTED) it fires an ItemEvent, and these listeners will be
590 * @param l The new listener to add
592 public void addItemListener(ItemListener l)
594 listenerList.add(ItemListener.class, l);
598 * Removes an ItemListener from the button's listener list.
600 * @param l The listener to remove
602 public void removeItemListener(ItemListener l)
604 listenerList.remove(ItemListener.class, l);
608 * Adds a ChangeListener to the button's listener list. When the button's
609 * model changes any of its (non-bound) properties, these listeners will be
612 * @param l The new listener to add
614 public void addChangeListener(ChangeListener l)
616 listenerList.add(ChangeListener.class, l);
620 * Removes a ChangeListener from the button's listener list.
622 * @param l The listener to remove
624 public void removeChangeListener(ChangeListener l)
626 listenerList.remove(ChangeListener.class, l);
630 * Calls {@link ItemListener.itemStateChanged} on each ItemListener in
631 * the button's listener list.
633 * @param e The event signifying that the button's model changed state
635 public void fireItemStateChanged(ItemEvent e)
637 EventListener[] ll = listenerList.getListeners(ItemListener.class);
638 for (int i = 0; i < ll.length; i++)
639 ((ItemListener)ll[i]).itemStateChanged(e);
643 * Calls {@link ActionListener.actionPerformed} on each {@link
644 * ActionListener} in the button's listener list.
646 * @param e The event signifying that the button's model was clicked
648 public void fireActionPerformed(ActionEvent e)
650 EventListener[] ll = listenerList.getListeners(ActionListener.class);
651 for (int i = 0; i < ll.length; i++)
652 ((ActionListener)ll[i]).actionPerformed(e);
656 * Calls {@link ChangeEvent.stateChanged} on each {@link ChangeListener}
657 * in the button's listener list.
659 * @param e The event signifying a change in one of the (non-bound)
660 * properties of the button's model.
662 public void fireStateChanged(ChangeEvent e)
664 EventListener[] ll = listenerList.getListeners(ChangeListener.class);
665 for (int i = 0; i < ll.length; i++)
666 ((ChangeListener)ll[i]).stateChanged(e);
670 * Get the current keyboard mnemonic value. This value corresponds to a
671 * single key code (one of the {@link java.awt.event.KeyEvent} VK_*
672 * codes) and is used to activate the button when pressed in conjunction
673 * with the "mouseless modifier" of the button's look and feel class, and
674 * when focus is in one of the button's ancestors.
676 * @return The button's current keyboard mnemonic
678 public int getMnemonic()
680 return getModel().getMnemonic();
684 * Set the current keyboard mnemonic value. This value corresponds to a
685 * single key code (one of the {@link java.awt.event.KeyEvent} VK_*
686 * codes) and is used to activate the button when pressed in conjunction
687 * with the "mouseless modifier" of the button's look and feel class, and
688 * when focus is in one of the button's ancestors.
690 * @param mne A new mnemonic to use for the button
692 public void setMnemonic(char mne)
694 int old = getModel().getMnemonic();
695 getModel().setMnemonic(mne);
696 if (old != getModel().getMnemonic())
698 firePropertyChange(MNEMONIC_CHANGED_PROPERTY, old, (int) mne);
705 * Set the current keyboard mnemonic value. This value corresponds to a
706 * single key code (one of the {@link java.awt.event.KeyEvent} VK_*
707 * codes) and is used to activate the button when pressed in conjunction
708 * with the "mouseless modifier" of the button's look and feel class, and
709 * when focus is in one of the button's ancestors.
711 * @param mne A new mnemonic to use for the button
713 public void setMnemonic(int mne)
716 getModel().setMnemonic(mne);
717 if (old != getModel().getMnemonic())
719 firePropertyChange(MNEMONIC_CHANGED_PROPERTY, old, mne);
726 * Sets the button's mnemonic index. The mnemonic index is a hint to the
727 * look and feel class, suggesting which character in the button's label
728 * should be underlined when drawing the label. If the mnemonic index is
729 * -1, no mnemonic will be displayed.
731 * If no mnemonic index is set, the button will choose a mnemonic index
732 * by default, which will be the first occurrence of the mnemonic
733 * character in the button's text.
735 * @param index An offset into the "text" property of the button
736 * @throws IllegalArgumentException If <code>index</code> is not within the
737 * range of legal offsets for the "text" property of the button.
741 public void setDisplayedMnemonicIndex(int index)
743 if (index < -1 || index >= text.length())
744 throw new IllegalArgumentException();
746 mnemonicIndex = index;
750 * Get the button's mnemonic index, which is an offset into the button's
751 * "text" property. The character specified by this offset should be
752 * underlined when the look and feel class draws this button.
754 * @return An index into the button's "text" property
756 public int getDisplayedMnemonicIndex(int index)
758 return mnemonicIndex;
763 * Set the "rolloverEnabled" property. When rollover is enabled, and the
764 * look and feel supports it, the button will change its icon to
765 * rollover_icon, when the mouse passes over it.
767 * @param r Whether or not to enable rollover icon changes
769 public void setRolloverEnabled(boolean r)
771 boolean old = getModel().isRollover();
772 getModel().setRollover(r);
773 if (old != getModel().isRollover())
775 firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, old, r);
782 * Returns whether or not rollover icon changes are enabled on the
785 * @return The state of the "rolloverEnabled" property
787 public boolean isRolloverEnabled()
789 return getModel().isRollover();
793 * Set the value of the button's "selected" property. Selection is only
794 * meaningful for toggle-type buttons (check boxes, radio buttons).
796 * @param s New value for the property
798 public void setSelected(boolean s)
800 getModel().setSelected(s);
804 * Get the value of the button's "selected" property. Selection is only
805 * meaningful for toggle-type buttons (check boxes, radio buttons).
807 * @return The value of the property
809 public boolean isSelected()
811 return getModel().isSelected();
815 * Enables or disables the button. A button will neither be selectable
816 * nor preform any actions unless it is enabled.
818 * @param b Whether or not to enable the button
820 public void setEnabled(boolean b)
823 getModel().setEnabled(b);
827 * Set the horizontal alignment of the button's text and icon. The
828 * alignment is a numeric constant from {@link SwingConstants}. It must
829 * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
830 * <code>LEADING</code> or <code>TRAILING</code>. The default is
831 * <code>RIGHT</code>.
833 * @return The current horizontal alignment
835 public int getHorizontalAlignment()
841 * Set the horizontal alignment of the button's text and icon. The
842 * alignment is a numeric constant from {@link SwingConstants}. It must
843 * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
844 * <code>LEADING</code> or <code>TRAILING</code>. The default is
845 * <code>RIGHT</code>.
847 * @param a The new horizontal alignment
848 * @throws IllegalArgumentException If alignment is not one of the legal
851 public void setHorizontalAlignment(int a)
853 int old = hori_align;
857 firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY, old, a);
864 * Get the horizontal position of the button's text relative to its
865 * icon. The position is a numeric constant from {@link
866 * SwingConstants}. It must be one of: <code>RIGHT</code>,
867 * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or
868 * <code>TRAILING</code>. The default is <code>TRAILING</code>.
870 * @return The current horizontal text position
872 public int getHorizontalTextPosition()
874 return hori_text_pos;
878 * Set the horizontal position of the button's text relative to its
879 * icon. The position is a numeric constant from {@link
880 * SwingConstants}. It must be one of: <code>RIGHT</code>,
881 * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or
882 * <code>TRAILING</code>. The default is <code>TRAILING</code>.
884 * @param t The new horizontal text position
885 * @throws IllegalArgumentException If position is not one of the legal
888 public void setHorizontalTextPosition(int t)
890 int old = hori_text_pos;
894 firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY, old, t);
901 * Get the vertical alignment of the button's text and icon. The
902 * alignment is a numeric constant from {@link SwingConstants}. It must
903 * be one of: <code>CENTER</code>, <code>TOP</code>, or
904 * <code>BOTTOM</code>. The default is <code>CENTER</code>.
906 * @return The current vertical alignment
908 public int getVerticalAlignment()
914 * Set the vertical alignment of the button's text and icon. The
915 * alignment is a numeric constant from {@link SwingConstants}. It must
916 * be one of: <code>CENTER</code>, <code>TOP</code>, or
917 * <code>BOTTOM</code>. The default is <code>CENTER</code>.
919 * @param a The new vertical alignment
920 * @throws IllegalArgumentException If alignment is not one of the legal
923 public void setVerticalAlignment(int a)
925 int old = vert_align;
929 firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, old, a);
936 * Get the vertical position of the button's text relative to its
937 * icon. The alignment is a numeric constant from {@link
938 * SwingConstants}. It must be one of: <code>CENTER</code>,
939 * <code>TOP</code>, or <code>BOTTOM</code>. The default is
940 * <code>CENTER</code>.
942 * @return The current vertical position
944 public int getVerticalTextPosition()
946 return vert_text_pos;
950 * Set the vertical position of the button's text relative to its
951 * icon. The alignment is a numeric constant from {@link
952 * SwingConstants}. It must be one of: <code>CENTER</code>,
953 * <code>TOP</code>, or <code>BOTTOM</code>. The default is
954 * <code>CENTER</code>.
956 * @param t The new vertical position
957 * @throws IllegalArgumentException If position is not one of the legal
960 public void setVerticalTextPosition(int t)
962 int old = vert_text_pos;
966 firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, old, t);
973 * Set the value of the "borderPainted" property. If set to
974 * <code>false</code>, the button's look and feel class should not paint
975 * a border for the button. The default is <code>true</code>.
977 * @return The current value of the property.
979 public boolean isBorderPainted()
985 * Set the value of the "borderPainted" property. If set to
986 * <code>false</code>, the button's look and feel class should not paint
987 * a border for the button. The default is <code>true</code>.
989 * @param b The new value of the property.
991 public void setBorderPainted(boolean b)
993 boolean old = paint_border;
997 firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, old, b);
1004 * Get the value of the "action" property.
1006 * @return The current value of the "action" property
1008 public Action getAction()
1014 * <p>Set the button's "action" property, subscribing the new action to the
1015 * button, as an ActionListener, if it is not already subscribed. The old
1016 * Action, if it exists, is unsubscribed, and the button is unsubscribed
1017 * from the old Action if it was previously subscribed as a
1018 * PropertyChangeListener.</p>
1020 * <p>This method also configures several of the button's properties from
1021 * the Action, by calling {@link configurePropertiesFromAction}, and
1022 * subscribes the button to the Action as a PropertyChangeListener.
1023 * Subsequent changes to the Action will thus reconfigure the button
1024 * automatically.</p>
1026 * @param a The new value of the "action" property
1028 public void setAction(Action a)
1032 action.removePropertyChangeListener(actionPropertyChangeListener);
1033 removeActionListener(action);
1034 if (actionPropertyChangeListener != null)
1036 action.removePropertyChangeListener(actionPropertyChangeListener);
1037 actionPropertyChangeListener = null;
1039 actionPropertyChangeListener = createActionPropertyChangeListener(a);
1042 Action old = action;
1044 configurePropertiesFromAction(action);
1048 action.addPropertyChangeListener(actionPropertyChangeListener);
1049 addActionListener(action);
1054 * Return the button's default "icon" property.
1056 * @return The current default icon
1058 public Icon getIcon()
1060 return default_icon;
1064 * Set the button's default "icon" property. This icon is used as a basis
1065 * for the pressed and disabled icons, if none are explicitly set.
1067 * @param i The new default icon
1069 public void setIcon(Icon i)
1071 Icon old = default_icon;
1075 firePropertyChange(ICON_CHANGED_PROPERTY, old, i);
1082 * Return the button's "text" property. This property is synonymous with
1083 * the "label" property.
1085 * @return The current "text" property
1087 public String getText()
1093 * Set the button's "label" property. This property is synonymous with the
1096 * @param label The new "label" property
1098 public void setLabel(String label)
1104 * Return the button's "label" property. This property is synonymous with
1105 * the "text" property.
1107 * @return The current "label" property
1109 public String getLabel()
1115 * Set the button's "text" property. This property is synonymous with the
1118 * @param t The new "text" property
1120 public void setText(String t)
1126 firePropertyChange(TEXT_CHANGED_PROPERTY, old, t);
1133 * Return the button's "margin" property, which is an {@link Insets} object
1134 * describing the distance between the button's border and its text and
1137 * @return The current "margin" property
1139 public Insets getMargin()
1145 * Set the button's "margin" property, which is an {@link Insets} object
1146 * describing the distance between the button's border and its text and
1149 * @param m The new "margin" property
1151 public void setMargin(Insets m)
1153 Insets old = margin;
1157 firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);
1164 * Return the button's "pressedIcon" property. The look and feel class
1165 * should paint this icon when the "pressed" property of the button's
1166 * {@link ButtonModel} is <code>true</code>. This property may be
1167 * <code>null</code>, in which case the default icon is used.
1169 * @return The current "pressedIcon" property
1171 public Icon getPressedIcon()
1173 return pressed_icon;
1177 * Set the button's "pressedIcon" property. The look and feel class
1178 * should paint this icon when the "pressed" property of the button's
1179 * {@link ButtonModel} is <code>true</code>. This property may be
1180 * <code>null</code>, in which case the default icon is used.
1182 * @param pressedIcon The new "pressedIcon" property
1184 public void setPressedIcon(Icon pressedIcon)
1186 Icon old = pressed_icon;
1187 pressed_icon = pressedIcon;
1188 if (pressed_icon != old)
1190 firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, old, pressed_icon);
1197 * Return the button's "disabledIcon" property. The look and feel class
1198 * should paint this icon when the "enabled" property of the button's
1199 * {@link ButtonModel} is <code>false</code>. This property may be
1200 * <code>null</code>, in which case an icon is constructed, based on the
1203 * @return The current "disabledIcon" property
1205 public Icon getDisabledIcon()
1207 return disabled_icon;
1211 * Set the button's "disabledIcon" property. The look and feel class should
1212 * paint this icon when the "enabled" property of the button's {@link
1213 * ButtonModel} is <code>false</code>. This property may be
1214 * <code>null</code>, in which case an icon is constructed, based on the
1217 * @param disabledIcon The new "disabledIcon" property
1219 public void setDisabledIcon(Icon disabledIcon)
1221 disabled_icon = disabledIcon;
1227 * Return the button's "paintFocus" property. This property controls
1228 * whether or not the look and feel class will paint a special indicator
1229 * of focus state for the button. If it is false, the button still paints
1230 * when focused, but no special decoration is painted to indicate the
1231 * presence of focus.
1233 * @return The current "paintFocus" property
1235 public boolean isFocusPainted()
1241 * Set the button's "paintFocus" property. This property controls whether
1242 * or not the look and feel class will paint a special indicator of focus
1243 * state for the button. If it is false, the button still paints when
1244 * focused, but no special decoration is painted to indicate the presence
1247 * @param b The new "paintFocus" property
1249 public void setFocusPainted(boolean b)
1251 boolean old = paint_focus;
1256 firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, old, b);
1263 * Return the button's "focusTraversable" property. This property controls
1264 * whether or not the button can receive focus when the user attempts to
1265 * traverse the focus hierarchy.
1267 * @return The current "focusTraversable" property
1269 public boolean isFocusTraversable()
1275 * Verifies that a particular key is one of the valid constants used for
1276 * describing horizontal alignment and positioning. The valid constants
1277 * are the following members of {@link SwingConstants}:
1278 * <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
1279 * <code>LEADING</code> or <code>TRAILING</code>.
1281 * @param key The key to check
1282 * @param exception A message to include in an IllegalArgumentException
1284 * @return the value of key
1286 * @throws IllegalArgumentException If key is not one of the valid constants
1288 * @see setHorizontalTextPosition()
1289 * @see setHorizontalAlignment()
1291 protected int checkHorizontalKey(int key, String exception)
1295 case SwingConstants.RIGHT:
1296 case SwingConstants.LEFT:
1297 case SwingConstants.CENTER:
1298 case SwingConstants.LEADING:
1299 case SwingConstants.TRAILING:
1302 throw new IllegalArgumentException(exception);
1308 * Verifies that a particular key is one of the valid constants used for
1309 * describing vertical alignment and positioning. The valid constants are
1310 * the following members of {@link SwingConstants}: <code>TOP</code>,
1311 * <code>BOTTOM</code> or <code>CENTER</code>.
1313 * @param key The key to check
1314 * @param exception A message to include in an IllegalArgumentException
1316 * @return the value of key
1318 * @throws IllegalArgumentException If key is not one of the valid constants
1320 * @see setVerticalTextPosition()
1321 * @see setVerticalAlignment()
1323 protected int checkVerticalKey(int key, String exception)
1327 case SwingConstants.TOP:
1328 case SwingConstants.BOTTOM:
1329 case SwingConstants.CENTER:
1332 throw new IllegalArgumentException(exception);
1338 * Configure various properties of the button by reading properties
1339 * of an {@link Action}. The mapping of properties is as follows:
1343 * <tr><th>Action keyed property</th> <th>AbstractButton property</th></tr>
1345 * <tr><td>NAME </td> <td>text </td></tr>
1346 * <tr><td>SMALL_ICON </td> <td>icon </td></tr>
1347 * <tr><td>SHORT_DESCRIPTION </td> <td>toolTipText </td></tr>
1348 * <tr><td>MNEMONIC_KEY </td> <td>mnemonic </td></tr>
1349 * <tr><td>ACTION_COMMAND_KEY </td> <td>actionCommand </td></tr>
1353 * <p>In addition, this method always sets the button's "enabled" property to
1354 * the value of the Action's "enabled" property.</p>
1356 * <p>If the provided Action is <code>null</code>, the text, icon, and
1357 * toolTipText properties of the button are set to <code>null</code>, and
1358 * the "enabled" property is set to <code>true</code>; the mnemonic and
1359 * actionCommand properties are unchanged.</p>
1361 * @param a An Action to configure the button from
1363 protected void configurePropertiesFromAction(Action a)
1370 setToolTipText(null);
1374 setText((String)(a.getValue(Action.NAME)));
1375 setIcon((Icon)(a.getValue(Action.SMALL_ICON)));
1376 setEnabled(a.isEnabled());
1377 setToolTipText((String)(a.getValue(Action.SHORT_DESCRIPTION)));
1378 setMnemonic(((Integer)(a.getValue(Action.MNEMONIC_KEY))).intValue());
1379 setActionCommand((String)(a.getValue(Action.ACTION_COMMAND_KEY)));
1384 * <p>A factory method which should return an {@link ActionListener} that
1385 * propagates events from the button's {@link ButtonModel} to any of the
1386 * button's ActionListeners. By default, this is an inner class which
1387 * calls {@link AbstractButton.fireActionPerformed} with a modified copy
1388 * of the incoming model {@link ActionEvent}.</p>
1390 * <p>The button calls this method during construction, stores the
1391 * resulting ActionListener in its <code>actionListener</code> member
1392 * field, and subscribes it to the button's model. If the button's model
1393 * is changed, this listener is unsubscribed from the old model and
1394 * subscribed to the new one.</p>
1396 * @return A new ActionListener
1398 protected ActionListener createActionListener()
1400 return new ActionListener()
1402 public void actionPerformed(ActionEvent e)
1404 e.setSource(AbstractButton.this);
1405 AbstractButton.this.fireActionPerformed(e);
1411 * <p>A factory method which should return a {@link PropertyChangeListener}
1412 * that accepts changes to the specified {@link Action} and reconfigure
1413 * the {@link AbstractButton}, by default using the {@link
1414 * configurePropertiesFromAction} method.</p>
1416 * <p>The button calls this method whenever a new Action is assigned to
1417 * the button's "action" property, via {@link setAction}, and stores the
1418 * resulting PropertyChangeListener in its
1419 * <code>actionPropertyChangeListener</code> member field. The button
1420 * then subscribes the listener to the button's new action. If the
1421 * button's action is changed subsequently, the listener is unsubscribed
1422 * from the old action and subscribed to the new one.</p>
1424 * @param a The Action which will be listened to, and which should be
1425 * the same as the source of any PropertyChangeEvents received by the
1426 * new listener returned from this method.
1428 * @return A new PropertyChangeListener
1430 protected PropertyChangeListener createActionPropertyChangeListener(Action a)
1432 return new PropertyChangeListener()
1434 public void propertyChange(PropertyChangeEvent e)
1436 Action act = (Action)(e.getSource());
1437 AbstractButton.this.configurePropertiesFromAction(act);
1443 * <p>Factory method which creates a {@link ChangeListener}, used to
1444 * subscribe to ChangeEvents from the button's model. Subclasses of
1445 * AbstractButton may wish to override the listener used to subscribe to
1446 * such ChangeEvents. By default, the listener just propagates the
1447 * {@link ChangeEvent} to the button's ChangeListeners, via the {@link
1448 * AbstractButton.fireStateChanged} method.</p>
1450 * <p>The button calls this method during construction, stores the
1451 * resulting ChangeListener in its <code>changeListener</code> member
1452 * field, and subscribes it to the button's model. If the button's model
1453 * is changed, this listener is unsubscribed from the old model and
1454 * subscribed to the new one.</p>
1456 * @return The new ChangeListener
1458 protected ChangeListener createChangeListener()
1460 return new ChangeListener()
1462 public void stateChanged(ChangeEvent e)
1464 AbstractButton.this.fireStateChanged(e);
1465 AbstractButton.this.revalidate();
1466 AbstractButton.this.repaint();
1472 * <p>Factory method which creates a {@link ItemListener}, used to
1473 * subscribe to ItemEvents from the button's model. Subclasses of
1474 * AbstractButton may wish to override the listener used to subscribe to
1475 * such ItemEvents. By default, the listener just propagates the
1476 * {@link ItemEvent} to the button's ItemListeners, via the {@link
1477 * AbstractButton.fireItemStateChanged} method.</p>
1479 * <p>The button calls this method during construction, stores the
1480 * resulting ItemListener in its <code>changeListener</code> member
1481 * field, and subscribes it to the button's model. If the button's model
1482 * is changed, this listener is unsubscribed from the old model and
1483 * subscribed to the new one.</p>
1485 * <p>Note that ItemEvents are only generated from the button's model
1486 * when the model's <em>selected</em> property changes. If you want to
1487 * subscribe to other properties of the model, you must subscribe to
1490 * @return The new ItemListener
1492 protected ItemListener createItemListener()
1494 return new ItemListener()
1496 public void itemStateChanged(ItemEvent e)
1498 AbstractButton.this.fireItemStateChanged(e);
1504 * Programmatically perform a "click" on the button: arming, pressing,
1505 * waiting, un-pressing, and disarming the model.
1507 public void doClick()
1513 * Programmatically perform a "click" on the button: arming, pressing,
1514 * waiting, un-pressing, and disarming the model.
1516 * @param pressTime The number of milliseconds to wait in the pressed state
1518 public void doClick(int pressTime)
1520 getModel().setArmed(true);
1521 getModel().setPressed(true);
1524 java.lang.Thread.sleep(pressTime);
1526 catch (java.lang.InterruptedException e)
1528 // probably harmless
1530 getModel().setPressed(false);
1531 getModel().setArmed(false);
1535 * Return the button's disabled selected icon. The look and feel class
1536 * should paint this icon when the "enabled" property of the button's model
1537 * is <code>false</code> and its "selected" property is
1538 * <code>true</code>. This icon can be <code>null</code>, in which case
1539 * it is synthesized from the button's selected icon.
1541 * @return The current disabled selected icon
1543 public Icon getDisabledSelectedIcon()
1545 return disabled_selected_icon;
1549 * Set the button's disabled selected icon. The look and feel class
1550 * should paint this icon when the "enabled" property of the button's model
1551 * is <code>false</code> and its "selected" property is
1552 * <code>true</code>. This icon can be <code>null</code>, in which case
1553 * it is synthesized from the button's selected icon.
1555 * @param disabledSelectedIcon The new disabled selected icon
1557 public void setDisabledSelectedIcon(Icon disabledSelectedIcon)
1559 Icon old = disabled_selected_icon;
1560 disabled_selected_icon = disabledSelectedIcon;
1561 if (old != disabledSelectedIcon)
1563 firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, old,
1564 disabledSelectedIcon);
1572 * Return the button's rollover icon. The look and feel class should
1573 * paint this icon when the "rolloverEnabled" property of the button is
1574 * <code>true</code> and the mouse rolls over the button.
1576 * @return The current rollover icon
1578 public Icon getRolloverIcon()
1580 return rollover_icon;
1584 * Set the button's rollover icon. The look and feel class should
1585 * paint this icon when the "rolloverEnabled" property of the button is
1586 * <code>true</code> and the mouse rolls over the button.
1588 * @param rolloverIcon The new rollover icon
1590 public void setRolloverIcon(Icon rolloverIcon)
1592 Icon old = rollover_icon;
1593 rollover_icon = rolloverIcon;
1594 if (old != rolloverIcon)
1596 firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, old,
1604 * Return the button's rollover selected icon. The look and feel class
1605 * should paint this icon when the "rolloverEnabled" property of the button
1606 * is <code>true</code>, the "selected" property of the button's model is
1607 * <code>true</code>, and the mouse rolls over the button.
1609 * @return The current rollover selected icon
1611 public Icon getRolloverSelectedIcon()
1613 return rollover_selected_icon;
1617 * Set the button's rollover selected icon. The look and feel class
1618 * should paint this icon when the "rolloverEnabled" property of the button
1619 * is <code>true</code>, the "selected" property of the button's model is
1620 * <code>true</code>, and the mouse rolls over the button.
1622 * @param rolloverSelectedIcon The new rollover selected icon
1624 public void setRolloverSelectedIcon(Icon rolloverSelectedIcon)
1626 Icon old = rollover_selected_icon;
1627 rollover_selected_icon = rolloverSelectedIcon;
1628 if (old != rolloverSelectedIcon)
1630 firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, old,
1631 rolloverSelectedIcon);
1639 * Return the button's selected icon. The look and feel class should
1640 * paint this icon when the "selected" property of the button's model is
1641 * <code>true</code>, and either the "rolloverEnabled" property of the
1642 * button is <code>false</code> or the mouse is not currently rolled
1645 * @return The current selected icon
1647 public Icon getSelectedIcon()
1649 return selected_icon;
1653 * Set the button's selected icon. The look and feel class should
1654 * paint this icon when the "selected" property of the button's model is
1655 * <code>true</code>, and either the "rolloverEnabled" property of the
1656 * button is <code>false</code> or the mouse is not currently rolled
1659 * @param selectedIcon The new selected icon
1661 public void setSelectedIcon(Icon selectedIcon)
1663 Icon old = selected_icon;
1664 selected_icon = selectedIcon;
1665 if (old != selectedIcon)
1667 firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, old,
1675 * Returns an single-element array containing the "text" property of the
1676 * button if the "selected" property of the button's model is
1677 * <code>true</code>, otherwise returns <code>null</code>.
1679 * @return The button's "selected object" array
1681 public Object[] getSelectedObjects()
1685 Object[] objs = new Object[1];
1686 objs[0] = getText();
1696 * Called when image data becomes available for one of the button's icons.
1698 * @param img The image being updated
1699 * @param infoflags One of the constant codes in {@link ImageObserver} used to describe
1700 * updated portions of an image.
1701 * @param x X coordinate of the region being updated
1702 * @param y Y coordinate of the region being updated
1703 * @param w Width of the region beign updated
1704 * @param h Height of the region being updated
1706 * @return <code>true</code> if img is equal to the button's current
1707 * icon, otherwise <code>false</code>
1709 public boolean imageUpdate(Image img, int infoflags, int x, int y, int w,
1712 return current_icon == img;
1716 * Returns the value of the button's "contentAreaFilled" property. This
1717 * property indicates whether the area surrounding the text and icon of
1718 * the button should be filled by the look and feel class. If this
1719 * property is <code>false</code>, the look and feel class should leave
1720 * the content area transparent.
1722 * @return The current value of the "contentAreaFilled" property
1724 public boolean isContentAreaFilled()
1726 return content_area_filled;
1730 * Sets the value of the button's "contentAreaFilled" property. This
1731 * property indicates whether the area surrounding the text and icon of
1732 * the button should be filled by the look and feel class. If this
1733 * property is <code>false</code>, the look and feel class should leave
1734 * the content area transparent.
1736 * @param b The new value of the "contentAreaFilled" property
1738 public void setContentAreaFilled(boolean b)
1740 boolean old = content_area_filled;
1741 content_area_filled = b;
1744 firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, old, b);
1751 * Paints the button's border, if the button's "borderPainted" property is
1752 * <code>true</code>, by out calling to the button's look and feel class.
1754 * @param g The graphics context used to paint the border
1756 protected void paintBorder(Graphics g)
1758 if (isBorderPainted())
1759 super.paintBorder(g);
1763 * Returns a string, used only for debugging, which identifies or somehow
1764 * represents this button. The exact value is implementation-defined.
1766 * @return A string representation of the button
1768 protected String paramString()
1770 return "AbstractButton";
1775 * Set the "UI" property of the button, which is a look and feel class
1776 * responsible for handling the button's input events and painting it.
1778 * @param ui The new "UI" property
1780 public void setUI(ButtonUI ui)
1786 * Set the "UI" property of the button, which is a look and feel class
1787 * responsible for handling the button's input events and painting it.
1789 * @return The current "UI" property
1791 public ButtonUI getUI()
1793 return (ButtonUI) ui;
1797 * Set the "UI" property to a class constructed, via the {@link
1798 * UIManager}, from the current look and feel. This should be overridden
1799 * for each subclass of AbstractButton, to retrieve a suitable {@link
1800 * ButtonUI} look and feel class.
1802 public void updateUI()