KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > AbstractButton


1 /*
2  * @(#)AbstractButton.java 1.175 05/08/23
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing;
8
9 import java.awt.*;
10 import java.awt.event.*;
11 import java.awt.image.*;
12 import java.text.*;
13 import java.awt.geom.*;
14 import java.beans.*;
15 import java.util.Enumeration JavaDoc;
16 import java.util.Vector JavaDoc;
17 import java.io.Serializable JavaDoc;
18 import javax.swing.event.*;
19 import javax.swing.border.*;
20 import javax.swing.plaf.*;
21 import javax.accessibility.*;
22 import javax.swing.text.*;
23 import javax.swing.text.html.*;
24 import javax.swing.plaf.basic.*;
25 import java.util.*;
26
27 /**
28  * Defines common behaviors for buttons and menu items.
29  * For further information see
30  * <a
31  href="http://java.sun.com/docs/books/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons</a>,
32  * a section in <em>The Java Tutorial</em>.
33  *
34  * <p>
35  *
36  * <strong>Warning:</strong>
37  * Serialized objects of this class will not be compatible with
38  * future Swing releases. The current serialization support is
39  * appropriate for short term storage or RMI between applications running
40  * the same version of Swing. As of 1.4, support for long term storage
41  * of all JavaBeans<sup><font size="-2">TM</font></sup>
42  * has been added to the <code>java.beans</code> package.
43  * Please see {@link java.beans.XMLEncoder}.
44  *
45  * @version 1.175 08/23/05
46  * @author Jeff Dinkins
47  */

48 public abstract class AbstractButton extends JComponent JavaDoc implements ItemSelectable, SwingConstants JavaDoc {
49
50     // *********************************
51
// ******* Button properties *******
52
// *********************************
53

54     /** Identifies a change in the button model. */
55     public static final String JavaDoc MODEL_CHANGED_PROPERTY = "model";
56     /** Identifies a change in the button's text. */
57     public static final String JavaDoc TEXT_CHANGED_PROPERTY = "text";
58     /** Identifies a change to the button's mnemonic. */
59     public static final String JavaDoc MNEMONIC_CHANGED_PROPERTY = "mnemonic";
60
61     // Text positioning and alignment
62
/** Identifies a change in the button's margins. */
63     public static final String JavaDoc MARGIN_CHANGED_PROPERTY = "margin";
64     /** Identifies a change in the button's vertical alignment. */
65     public static final String JavaDoc VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";
66     /** Identifies a change in the button's horizontal alignment. */
67     public static final String JavaDoc HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = "horizontalAlignment";
68
69     /** Identifies a change in the button's vertical text position. */
70     public static final String JavaDoc VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = "verticalTextPosition";
71     /** Identifies a change in the button's horizontal text position. */
72     public static final String JavaDoc HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = "horizontalTextPosition";
73
74     // Paint options
75
/**
76      * Identifies a change to having the border drawn,
77      * or having it not drawn.
78      */

79     public static final String JavaDoc BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";
80     /**
81      * Identifies a change to having the border highlighted when focused,
82      * or not.
83      */

84     public static final String JavaDoc FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
85     /**
86      * Identifies a change from rollover enabled to disabled or back
87      * to enabled.
88      */

89     public static final String JavaDoc ROLLOVER_ENABLED_CHANGED_PROPERTY = "rolloverEnabled";
90     /**
91      * Identifies a change to having the button paint the content area.
92      */

93     public static final String JavaDoc CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled";
94
95     // Icons
96
/** Identifies a change to the icon that represents the button. */
97     public static final String JavaDoc ICON_CHANGED_PROPERTY = "icon";
98
99     /**
100      * Identifies a change to the icon used when the button has been
101      * pressed.
102      */

103     public static final String JavaDoc PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";
104     /**
105      * Identifies a change to the icon used when the button has
106      * been selected.
107      */

108     public static final String JavaDoc SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";
109
110     /**
111      * Identifies a change to the icon used when the cursor is over
112      * the button.
113      */

114     public static final String JavaDoc ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";
115     /**
116      * Identifies a change to the icon used when the cursor is
117      * over the button and it has been selected.
118      */

119     public static final String JavaDoc ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = "rolloverSelectedIcon";
120
121     /**
122      * Identifies a change to the icon used when the button has
123      * been disabled.
124      */

125     public static final String JavaDoc DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";
126     /**
127      * Identifies a change to the icon used when the button has been
128      * disabled and selected.
129      */

130     public static final String JavaDoc DISABLED_SELECTED_ICON_CHANGED_PROPERTY = "disabledSelectedIcon";
131
132
133     /** The data model that determines the button's state. */
134     protected ButtonModel JavaDoc model = null;
135
136     private String JavaDoc text = ""; // for BeanBox
137
private Insets margin = null;
138     private Insets defaultMargin = null;
139
140     // Button icons
141
// PENDING(jeff) - hold icons in an array
142
private Icon JavaDoc defaultIcon = null;
143     private Icon JavaDoc pressedIcon = null;
144     private Icon JavaDoc disabledIcon = null;
145
146     private Icon JavaDoc selectedIcon = null;
147     private Icon JavaDoc disabledSelectedIcon = null;
148
149     private Icon JavaDoc rolloverIcon = null;
150     private Icon JavaDoc rolloverSelectedIcon = null;
151     
152     // Display properties
153
private boolean paintBorder = true;
154     private boolean paintFocus = true;
155     private boolean rolloverEnabled = false;
156     private boolean contentAreaFilled = true;
157
158     // Icon/Label Alignment
159
private int verticalAlignment = CENTER;
160     private int horizontalAlignment = CENTER;
161     
162     private int verticalTextPosition = CENTER;
163     private int horizontalTextPosition = TRAILING;
164
165     private int iconTextGap = 4;
166
167     private int mnemonic;
168     private int mnemonicIndex = -1;
169
170     private long multiClickThreshhold = 0;
171
172     private boolean borderPaintedSet = false;
173     private boolean rolloverEnabledSet = false;
174     private boolean iconTextGapSet = false;
175     private boolean contentAreaFilledSet = false;
176
177     // Whether or not we've set the LayoutManager.
178
private boolean setLayout = false;
179
180     // This is only used by JButton, promoted to avoid an extra
181
// boolean field in JButton
182
boolean defaultCapable = true;
183
184     /**
185      * Combined listeners: ActionListener, ChangeListener, ItemListener.
186      */

187     private Handler handler;
188     
189     /**
190      * The button model's <code>changeListener</code>.
191      */

192     protected ChangeListener changeListener = null;
193     /**
194      * The button model's <code>ActionListener</code>.
195      */

196     protected ActionListener actionListener = null;
197     /**
198      * The button model's <code>ItemListener</code>.
199      */

200     protected ItemListener itemListener = null;
201
202     /**
203      * Only one <code>ChangeEvent</code> is needed per button
204      * instance since the
205      * event's only state is the source property. The source of events
206      * generated is always "this".
207      */

208     protected transient ChangeEvent changeEvent;
209     
210     /**
211      * Returns the button's text.
212      * @return the buttons text
213      * @see #setText
214      */

215     public String JavaDoc getText() {
216         return text;
217     }
218     
219     /**
220      * Sets the button's text.
221      * @param text the string used to set the text
222      * @see #getText
223      * @beaninfo
224      * bound: true
225      * preferred: true
226      * attribute: visualUpdate true
227      * description: The button's text.
228      */

229     public void setText(String JavaDoc text) {
230         String JavaDoc oldValue = this.text;
231         this.text = text;
232         firePropertyChange(TEXT_CHANGED_PROPERTY, oldValue, text);
233         updateDisplayedMnemonicIndex(text, getMnemonic());
234
235         if (accessibleContext != null) {
236             accessibleContext.firePropertyChange(
237                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
238                 oldValue, text);
239         }
240         if (text == null || oldValue == null || !text.equals(oldValue)) {
241             revalidate();
242             repaint();
243         }
244     }
245
246
247     /**
248      * Returns the state of the button. True if the
249      * toggle button is selected, false if it's not.
250      * @return true if the toggle button is selected, otherwise false
251      */

252     public boolean isSelected() {
253         return model.isSelected();
254     }
255  
256     /**
257      * Sets the state of the button. Note that this method does not
258      * trigger an <code>actionEvent</code>.
259      * Call <code>doClick</code> to perform a programatic action change.
260      *
261      * @param b true if the button is selected, otherwise false
262      */

263     public void setSelected(boolean b) {
264         boolean oldValue = isSelected();
265
266         // TIGER - 4840653
267
// Removed code which fired an AccessibleState.SELECTED
268
// PropertyChangeEvent since this resulted in two
269
// identical events being fired since
270
// AbstractButton.fireItemStateChanged also fires the
271
// same event. This caused screen readers to speak the
272
// name of the item twice.
273

274         model.setSelected(b);
275     }
276
277     /**
278      * Programmatically perform a "click". This does the same
279      * thing as if the user had pressed and released the button.
280      */

281     public void doClick() {
282         doClick(68);
283     }
284
285     /**
286      * Programmatically perform a "click". This does the same
287      * thing as if the user had pressed and released the button.
288      * The button stays visually "pressed" for <code>pressTime</code>
289      * milliseconds.
290      *
291      * @param pressTime the time to "hold down" the button, in milliseconds
292      */

293     public void doClick(int pressTime) {
294         Dimension size = getSize();
295         model.setArmed(true);
296         model.setPressed(true);
297         paintImmediately(new Rectangle(0,0, size.width, size.height));
298         try {
299             Thread.currentThread().sleep(pressTime);
300         } catch(InterruptedException JavaDoc ie) {
301         }
302         model.setPressed(false);
303         model.setArmed(false);
304     }
305
306     /**
307      * Sets space for margin between the button's border and
308      * the label. Setting to <code>null</code> will cause the button to
309      * use the default margin. The button's default <code>Border</code>
310      * object will use this value to create the proper margin.
311      * However, if a non-default border is set on the button,
312      * it is that <code>Border</code> object's responsibility to create the
313      * appropriate margin space (else this property will
314      * effectively be ignored).
315      *
316      * @param m the space between the border and the label
317      *
318      * @beaninfo
319      * bound: true
320      * attribute: visualUpdate true
321      * description: The space between the button's border and the label.
322      */

323     public void setMargin(Insets m) {
324         // Cache the old margin if it comes from the UI
325
if(m instanceof UIResource) {
326             defaultMargin = m;
327         } else if(margin instanceof UIResource) {
328             defaultMargin = margin;
329         }
330             
331         // If the client passes in a null insets, restore the margin
332
// from the UI if possible
333
if(m == null && defaultMargin != null) {
334             m = defaultMargin;
335         }
336
337         Insets old = margin;
338         margin = m;
339         firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);
340         if (old == null || !old.equals(m)) {
341             revalidate();
342             repaint();
343         }
344     }
345
346     /**
347      * Returns the margin between the button's border and
348      * the label.
349      *
350      * @return an <code>Insets</code> object specifying the margin
351      * between the botton's border and the label
352      * @see #setMargin
353      */

354     public Insets getMargin() {
355         return (margin == null) ? null : (Insets) margin.clone();
356     }
357
358     /**
359      * Returns the default icon.
360      * @return the default <code>Icon</code>
361      * @see #setIcon
362      */

363     public Icon JavaDoc getIcon() {
364         return defaultIcon;
365     }
366     
367     /**
368      * Sets the button's default icon. This icon is
369      * also used as the "pressed" and "disabled" icon if
370      * there is no explicitly set pressed icon.
371      *
372      * @param defaultIcon the icon used as the default image
373      * @see #getIcon
374      * @see #setPressedIcon
375      * @beaninfo
376      * bound: true
377      * attribute: visualUpdate true
378      * description: The button's default icon
379      */

380     public void setIcon(Icon JavaDoc defaultIcon) {
381         Icon JavaDoc oldValue = this.defaultIcon;
382         this.defaultIcon = defaultIcon;
383
384         /* If the default icon has really changed and we had
385          * generated the disabled icon for this component,
386          * (i.e. setDisabledIcon() was never called) then
387          * clear the disabledIcon field.
388          */

389         if (defaultIcon != oldValue && (disabledIcon instanceof UIResource)) {
390             disabledIcon = null;
391         }
392
393         firePropertyChange(ICON_CHANGED_PROPERTY, oldValue, defaultIcon);
394         if (accessibleContext != null) {
395             accessibleContext.firePropertyChange(
396                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
397                 oldValue, defaultIcon);
398         }
399         if (defaultIcon != oldValue) {
400             if (defaultIcon == null || oldValue == null ||
401                 defaultIcon.getIconWidth() != oldValue.getIconWidth() ||
402                 defaultIcon.getIconHeight() != oldValue.getIconHeight()) {
403                 revalidate();
404             }
405             repaint();
406         }
407     }
408     
409     /**
410      * Returns the pressed icon for the button.
411      * @return the <code>pressedIcon</code> property
412      * @see #setPressedIcon
413      */

414     public Icon JavaDoc getPressedIcon() {
415         return pressedIcon;
416     }
417     
418     /**
419      * Sets the pressed icon for the button.
420      * @param pressedIcon the icon used as the "pressed" image
421      * @see #getPressedIcon
422      * @beaninfo
423      * bound: true
424      * attribute: visualUpdate true
425      * description: The pressed icon for the button.
426      */

427     public void setPressedIcon(Icon JavaDoc pressedIcon) {
428         Icon JavaDoc oldValue = this.pressedIcon;
429         this.pressedIcon = pressedIcon;
430         firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, oldValue, pressedIcon);
431         if (accessibleContext != null) {
432             accessibleContext.firePropertyChange(
433                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
434                 oldValue, pressedIcon);
435         }
436         if (pressedIcon != oldValue) {
437             if (getModel().isPressed()) {
438                 repaint();
439             }
440         }
441     }
442
443     /**
444      * Returns the selected icon for the button.
445      * @return the <code>selectedIcon</code> property
446      * @see #setSelectedIcon
447      */

448     public Icon JavaDoc getSelectedIcon() {
449         return selectedIcon;
450     }
451     
452     /**
453      * Sets the selected icon for the button.
454      * @param selectedIcon the icon used as the "selected" image
455      * @see #getSelectedIcon
456      * @beaninfo
457      * bound: true
458      * attribute: visualUpdate true
459      * description: The selected icon for the button.
460      */

461     public void setSelectedIcon(Icon JavaDoc selectedIcon) {
462         Icon JavaDoc oldValue = this.selectedIcon;
463         this.selectedIcon = selectedIcon;
464
465         /* If the default selected icon has really changed and we had
466          * generated the disabled selected icon for this component,
467          * (i.e. setDisabledSelectedIcon() was never called) then
468          * clear the disabledSelectedIcon field.
469          */

470         if (selectedIcon != oldValue &&
471             disabledSelectedIcon instanceof UIResource) {
472
473             disabledSelectedIcon = null;
474         }
475
476         firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, oldValue, selectedIcon);
477         if (accessibleContext != null) {
478             accessibleContext.firePropertyChange(
479                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
480                 oldValue, selectedIcon);
481         }
482         if (selectedIcon != oldValue) {
483             if (isSelected()) {
484                 repaint();
485             }
486         }
487     }
488
489     /**
490      * Returns the rollover icon for the button.
491      * @return the <code>rolloverIcon</code> property
492      * @see #setRolloverIcon
493      */

494     public Icon JavaDoc getRolloverIcon() {
495         return rolloverIcon;
496     }
497     
498     /**
499      * Sets the rollover icon for the button.
500      * @param rolloverIcon the icon used as the "rollover" image
501      * @see #getRolloverIcon
502      * @beaninfo
503      * bound: true
504      * attribute: visualUpdate true
505      * description: The rollover icon for the button.
506      */

507     public void setRolloverIcon(Icon JavaDoc rolloverIcon) {
508         Icon JavaDoc oldValue = this.rolloverIcon;
509         this.rolloverIcon = rolloverIcon;
510         firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, oldValue, rolloverIcon);
511         if (accessibleContext != null) {
512             accessibleContext.firePropertyChange(
513                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
514                 oldValue, rolloverIcon);
515         }
516         setRolloverEnabled(true);
517         if (rolloverIcon != oldValue) {
518             // No way to determine whether we are currently in
519
// a rollover state, so repaint regardless
520
repaint();
521         }
522       
523     }
524     
525     /**
526      * Returns the rollover selection icon for the button.
527      * @return the <code>rolloverSelectedIcon</code> property
528      * @see #setRolloverSelectedIcon
529      */

530     public Icon JavaDoc getRolloverSelectedIcon() {
531         return rolloverSelectedIcon;
532     }
533     
534     /**
535      * Sets the rollover selected icon for the button.
536      * @param rolloverSelectedIcon the icon used as the
537      * "selected rollover" image
538      * @see #getRolloverSelectedIcon
539      * @beaninfo
540      * bound: true
541      * attribute: visualUpdate true
542      * description: The rollover selected icon for the button.
543      */

544     public void setRolloverSelectedIcon(Icon JavaDoc rolloverSelectedIcon) {
545         Icon JavaDoc oldValue = this.rolloverSelectedIcon;
546         this.rolloverSelectedIcon = rolloverSelectedIcon;
547         firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, oldValue, rolloverSelectedIcon);
548         if (accessibleContext != null) {
549             accessibleContext.firePropertyChange(
550                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
551                 oldValue, rolloverSelectedIcon);
552         }
553         setRolloverEnabled(true);
554         if (rolloverSelectedIcon != oldValue) {
555             // No way to determine whether we are currently in
556
// a rollover state, so repaint regardless
557
if (isSelected()) {
558                 repaint();
559             }
560         }
561     }
562     
563     /**
564      * Returns the icon used by the button when it's disabled.
565      * If no disabled icon has been set this will forward the call to
566      * the look and feel to construct an appropriate disabled Icon.
567      * <p>
568      * Some look and feels might not render the disabled Icon, in which
569      * case they will ignore this.
570      *
571      * @return the <code>disabledIcon</code> property
572      * @see #getPressedIcon
573      * @see #setDisabledIcon
574      * @see javax.swing.LookAndFeel#getDisabledIcon
575      */

576     public Icon JavaDoc getDisabledIcon() {
577         if (disabledIcon == null) {
578             disabledIcon = UIManager.getLookAndFeel().getDisabledIcon(this, getIcon());
579             if (disabledIcon != null) {
580                 firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, null, disabledIcon);
581             }
582         }
583         return disabledIcon;
584     }
585     
586     /**
587      * Sets the disabled icon for the button.
588      * @param disabledIcon the icon used as the disabled image
589      * @see #getDisabledIcon
590      * @beaninfo
591      * bound: true
592      * attribute: visualUpdate true
593      * description: The disabled icon for the button.
594      */

595     public void setDisabledIcon(Icon JavaDoc disabledIcon) {
596         Icon JavaDoc oldValue = this.disabledIcon;
597         this.disabledIcon = disabledIcon;
598         firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, oldValue, disabledIcon);
599         if (accessibleContext != null) {
600             accessibleContext.firePropertyChange(
601                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
602                 oldValue, disabledIcon);
603         }
604         if (disabledIcon != oldValue) {
605             if (!isEnabled()) {
606                 repaint();
607             }
608         }
609     }
610     
611     /**
612      * Returns the icon used by the button when it's disabled and selected.
613      * If no disabled selection icon has been set, this will forward
614      * the call to the LookAndFeel to construct an appropriate disabled
615      * Icon from the selection icon if it has been set and to
616      * <code>getDisabledIcon()</code> otherwise.
617      * <p>
618      * Some look and feels might not render the disabled selected Icon, in
619      * which case they will ignore this.
620      *
621      * @return the <code>disabledSelectedIcon</code> property
622      * @see #getDisabledIcon
623      * @see #setDisabledSelectedIcon
624      * @see javax.swing.LookAndFeel#getDisabledSelectedIcon
625      */

626     public Icon JavaDoc getDisabledSelectedIcon() {
627         if (disabledSelectedIcon == null) {
628              if (selectedIcon != null) {
629                  disabledSelectedIcon = UIManager.getLookAndFeel().
630                          getDisabledSelectedIcon(this, getSelectedIcon());
631              } else {
632                  return getDisabledIcon();
633              }
634         }
635         return disabledSelectedIcon;
636     }
637
638     /**
639      * Sets the disabled selection icon for the button.
640      * @param disabledSelectedIcon the icon used as the disabled
641      * selection image
642      * @see #getDisabledSelectedIcon
643      * @beaninfo
644      * bound: true
645      * attribute: visualUpdate true
646      * description: The disabled selection icon for the button.
647      */

648     public void setDisabledSelectedIcon(Icon JavaDoc disabledSelectedIcon) {
649         Icon JavaDoc oldValue = this.disabledSelectedIcon;
650         this.disabledSelectedIcon = disabledSelectedIcon;
651         firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, oldValue, disabledSelectedIcon);
652         if (accessibleContext != null) {
653             accessibleContext.firePropertyChange(
654                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
655                 oldValue, disabledSelectedIcon);
656         }
657         if (disabledSelectedIcon != oldValue) {
658             if (disabledSelectedIcon == null || oldValue == null ||
659                 disabledSelectedIcon.getIconWidth() != oldValue.getIconWidth() ||
660                 disabledSelectedIcon.getIconHeight() != oldValue.getIconHeight()) {
661                 revalidate();
662             }
663             if (!isEnabled() && isSelected()) {
664                 repaint();
665             }
666         }
667     }
668
669     /**
670      * Returns the vertical alignment of the text and icon.
671      *
672      * @return the <code>verticalAlignment</code> property, one of the
673      * following values:
674      * <ul>
675      * <li>SwingConstants.CENTER (the default)
676      * <li>SwingConstants.TOP
677      * <li>SwingConstants.BOTTOM
678      * </ul>
679      */

680     public int getVerticalAlignment() {
681         return verticalAlignment;
682     }
683     
684     /**
685      * Sets the vertical alignment of the icon and text.
686      * @param alignment one of the following values:
687      * <ul>
688      * <li>SwingConstants.CENTER (the default)
689      * <li>SwingConstants.TOP
690      * <li>SwingConstants.BOTTOM
691      * </ul>
692      * @beaninfo
693      * bound: true
694      * enum: TOP SwingConstants.TOP
695      * CENTER SwingConstants.CENTER
696      * BOTTOM SwingConstants.BOTTOM
697      * attribute: visualUpdate true
698      * description: The vertical alignment of the icon and text.
699      */

700     public void setVerticalAlignment(int alignment) {
701         if (alignment == verticalAlignment) return;
702         int oldValue = verticalAlignment;
703         verticalAlignment = checkVerticalKey(alignment, "verticalAlignment");
704         firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, oldValue, verticalAlignment); repaint();
705     }
706     
707     /**
708      * Returns the horizontal alignment of the icon and text.
709      * @return the <code>horizontalAlignment</code> property,
710      * one of the following values:
711      * <ul>
712      * <li>SwingConstants.RIGHT (the default)
713      * <li>SwingConstants.LEFT
714      * <li>SwingConstants.CENTER
715      * <li>SwingConstants.LEADING
716      * <li>SwingConstants.TRAILING
717      * </ul>
718      */

719     public int getHorizontalAlignment() {
720         return horizontalAlignment;
721     }
722     
723     /**
724      * Sets the horizontal alignment of the icon and text.
725      * @param alignment one of the following values:
726      * <ul>
727      * <li>SwingConstants.RIGHT (the default)
728      * <li>SwingConstants.LEFT
729      * <li>SwingConstants.CENTER
730      * <li>SwingConstants.LEADING
731      * <li>SwingConstants.TRAILING
732      * </ul>
733      * @beaninfo
734      * bound: true
735      * enum: LEFT SwingConstants.LEFT
736      * CENTER SwingConstants.CENTER
737      * RIGHT SwingConstants.RIGHT
738      * LEADING SwingConstants.LEADING
739      * TRAILING SwingConstants.TRAILING
740      * attribute: visualUpdate true
741      * description: The horizontal alignment of the icon and text.
742      */

743     public void setHorizontalAlignment(int alignment) {
744         if (alignment == horizontalAlignment) return;
745         int oldValue = horizontalAlignment;
746         horizontalAlignment = checkHorizontalKey(alignment,
747                                                  "horizontalAlignment");
748         firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY,
749                            oldValue, horizontalAlignment);
750         repaint();
751     }
752
753     
754     /**
755      * Returns the vertical position of the text relative to the icon.
756      * @return the <code>verticalTextPosition</code> property,
757      * one of the following values:
758      * <ul>
759      * <li>SwingConstants.CENTER (the default)
760      * <li>SwingConstants.TOP
761      * <li>SwingConstants.BOTTOM
762      * </ul>
763      */

764     public int getVerticalTextPosition() {
765         return verticalTextPosition;
766     }
767     
768     /**
769      * Sets the vertical position of the text relative to the icon.
770      * @param textPosition one of the following values:
771      * <ul>
772      * <li>SwingConstants.CENTER (the default)
773      * <li>SwingConstants.TOP
774      * <li>SwingConstants.BOTTOM
775      * </ul>
776      * @beaninfo
777      * bound: true
778      * enum: TOP SwingConstants.TOP
779      * CENTER SwingConstants.CENTER
780      * BOTTOM SwingConstants.BOTTOM
781      * attribute: visualUpdate true
782      * description: The vertical position of the text relative to the icon.
783      */

784     public void setVerticalTextPosition(int textPosition) {
785         if (textPosition == verticalTextPosition) return;
786         int oldValue = verticalTextPosition;
787         verticalTextPosition = checkVerticalKey(textPosition, "verticalTextPosition");
788         firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, oldValue, verticalTextPosition);
789         repaint();
790     }
791     
792     /**
793      * Returns the horizontal position of the text relative to the icon.
794      * @return the <code>horizontalTextPosition</code> property,
795      * one of the following values:
796      * <ul>
797      * <li>SwingConstants.RIGHT
798      * <li>SwingConstants.LEFT
799      * <li>SwingConstants.CENTER
800      * <li>SwingConstants.LEADING
801      * <li>SwingConstants.TRAILING (the default)
802      * </ul>
803      */

804     public int getHorizontalTextPosition() {
805         return horizontalTextPosition;
806     }
807     
808     /**
809      * Sets the horizontal position of the text relative to the icon.
810      * @param textPosition one of the following values:
811      * <ul>
812      * <li>SwingConstants.RIGHT
813      * <li>SwingConstants.LEFT
814      * <li>SwingConstants.CENTER
815      * <li>SwingConstants.LEADING
816      * <li>SwingConstants.TRAILING (the default)
817      * </ul>
818      * @exception IllegalArgumentException if <code>textPosition</code>
819      * is not one of the legal values listed above
820      * @beaninfo
821      * bound: true
822      * enum: LEFT SwingConstants.LEFT
823      * CENTER SwingConstants.CENTER
824      * RIGHT SwingConstants.RIGHT
825      * LEADING SwingConstants.LEADING
826      * TRAILING SwingConstants.TRAILING
827      * attribute: visualUpdate true
828      * description: The horizontal position of the text relative to the icon.
829      */

830     public void setHorizontalTextPosition(int textPosition) {
831         if (textPosition == horizontalTextPosition) return;
832         int oldValue = horizontalTextPosition;
833         horizontalTextPosition = checkHorizontalKey(textPosition,
834                                                     "horizontalTextPosition");
835         firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY,
836                            oldValue,
837                            horizontalTextPosition);
838         repaint();
839     }
840     
841     /**
842      * Returns the amount of space between the text and the icon
843      * displayed in this button.
844      *
845      * @return an int equal to the number of pixels between the text
846      * and the icon.
847      * @since 1.4
848      * @see #setIconTextGap
849      */

850     public int getIconTextGap() {
851         return iconTextGap;
852     }
853
854     /**
855      * If both the icon and text properties are set, this property
856      * defines the space between them.
857      * <p>
858      * The default value of this property is 4 pixels.
859      * <p>
860      * This is a JavaBeans bound property.
861      *
862      * @since 1.4
863      * @see #getIconTextGap
864      * @beaninfo
865      * bound: true
866      * attribute: visualUpdate true
867      * description: If both the icon and text properties are set, this
868      * property defines the space between them.
869      */

870     public void setIconTextGap(int iconTextGap) {
871         int oldValue = this.iconTextGap;
872         this.iconTextGap = iconTextGap;
873     iconTextGapSet = true;
874         firePropertyChange("iconTextGap", oldValue, iconTextGap);
875         if (iconTextGap != oldValue) {
876             revalidate();
877             repaint();
878         }
879     }
880
881     /**
882      * Verify that key is a legal value for the
883      * <code>horizontalAlignment</code> properties.
884      *
885      * @param key the property value to check, one of the following values:
886      * <ul>
887      * <li>SwingConstants.RIGHT (the default)
888      * <li>SwingConstants.LEFT
889      * <li>SwingConstants.CENTER
890      * <li>SwingConstants.LEADING
891      * <li>SwingConstants.TRAILING
892      * </ul>
893      * @param exception the <code>IllegalArgumentException</code>
894      * detail message
895      * @exception IllegalArgumentException if key is not one of the legal
896      * values listed above
897      * @see #setHorizontalTextPosition
898      * @see #setHorizontalAlignment
899      */

900     protected int checkHorizontalKey(int key, String JavaDoc exception) {
901         if ((key == LEFT) ||
902             (key == CENTER) ||
903             (key == RIGHT) ||
904             (key == LEADING) ||
905             (key == TRAILING)) {
906             return key;
907         } else {
908             throw new IllegalArgumentException JavaDoc(exception);
909         }
910     }
911     
912     /**
913      * Ensures that the key is a valid. Throws an
914      * <code>IllegalArgumentException</code>
915      * exception otherwise.
916      *
917      * @param key the value to check, one of the following values:
918      * <ul>
919      * <li>SwingConstants.CENTER (the default)
920      * <li>SwingConstants.TOP
921      * <li>SwingConstants.BOTTOM
922      * </ul>
923      * @param exception a string to be passed to the
924      * <code>IllegalArgumentException</code> call if key
925      * is not one of the valid values listed above
926      * @exception IllegalArgumentException if key is not one of the legal
927      * values listed above
928      */

929     protected int checkVerticalKey(int key, String JavaDoc exception) {
930         if ((key == TOP) || (key == CENTER) || (key == BOTTOM)) {
931             return key;
932         } else {
933             throw new IllegalArgumentException JavaDoc(exception);
934         }
935     }
936     
937     /**
938      * Sets the action command for this button.
939      * @param actionCommand the action command for this button
940      */

941     public void setActionCommand(String JavaDoc actionCommand) {
942         getModel().setActionCommand(actionCommand);
943     }
944     
945     /**
946      * Returns the action command for this button.
947      * @return the action command for this button
948      */

949     public String JavaDoc getActionCommand() {
950         String JavaDoc ac = getModel().getActionCommand();
951         if(ac == null) {
952             ac = getText();
953         }
954         return ac;
955     }
956     
957     private Action JavaDoc action;
958     private PropertyChangeListener actionPropertyChangeListener;
959