9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package javax.swing;
26
27 import java.awt.*;
28 import java.awt.event.*;
29 import java.awt.image.*;
30 import java.text.*;
31 import java.awt.geom.*;
32 import java.beans.PropertyChangeEvent;
33 import java.beans.PropertyChangeListener;
34 import java.beans.Transient;
35 import java.util.Enumeration;
36 import java.util.Vector;
37 import java.io.Serializable;
38 import javax.swing.event.*;
39 import javax.swing.border.*;
40 import javax.swing.plaf.*;
41 import javax.accessibility.*;
42 import javax.swing.text.*;
43 import javax.swing.text.html.*;
44 import javax.swing.plaf.basic.*;
45 import java.util.*;
46
47 /**
48 * Defines common behaviors for buttons and menu items.
49 * <p>
50 * Buttons can be configured, and to some degree controlled, by
51 * <code><a href="Action.html">Action</a></code>s. Using an
52 * <code>Action</code> with a button has many benefits beyond directly
53 * configuring a button. Refer to <a href="Action.html#buttonActions">
54 * Swing Components Supporting <code>Action</code></a> for more
55 * details, and you can find more information in <a
56 * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
57 * to Use Actions</a>, a section in <em>The Java Tutorial</em>.
58 * <p>
59 * For further information see
60 * <a
61 href="http://docs.oracle.com/javase/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons</a>,
62 * a section in <em>The Java Tutorial</em>.
63 * <p>
64 * <strong>Warning:</strong>
65 * Serialized objects of this class will not be compatible with
66 * future Swing releases. The current serialization support is
67 * appropriate for short term storage or RMI between applications running
68 * the same version of Swing. As of 1.4, support for long term storage
69 * of all JavaBeans™
70 * has been added to the <code>java.beans</code> package.
71 * Please see {@link java.beans.XMLEncoder}.
72 *
73 * @author Jeff Dinkins
74 * @since 1.2
75 */
76 @SuppressWarnings("serial") // Same-version serialization only
77 public abstract class AbstractButton extends JComponent implements ItemSelectable, SwingConstants {
78
79 // *********************************
80 // ******* Button properties *******
81 // *********************************
82
83 /** Identifies a change in the button model. */
84 public static final String MODEL_CHANGED_PROPERTY = "model";
85 /** Identifies a change in the button's text. */
86 public static final String TEXT_CHANGED_PROPERTY = "text";
87 /** Identifies a change to the button's mnemonic. */
88 public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic";
89
90 // Text positioning and alignment
91 /** Identifies a change in the button's margins. */
92 public static final String MARGIN_CHANGED_PROPERTY = "margin";
93 /** Identifies a change in the button's vertical alignment. */
94 public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";
95 /** Identifies a change in the button's horizontal alignment. */
234 * event's only state is the source property. The source of events
235 * generated is always "this".
236 */
237 protected transient ChangeEvent changeEvent;
238
239 private boolean hideActionText = false;
240
241 /**
242 * Sets the <code>hideActionText</code> property, which determines
243 * whether the button displays text from the <code>Action</code>.
244 * This is useful only if an <code>Action</code> has been
245 * installed on the button.
246 *
247 * @param hideActionText <code>true</code> if the button's
248 * <code>text</code> property should not reflect
249 * that of the <code>Action</code>; the default is
250 * <code>false</code>
251 * @see <a href="Action.html#buttonActions">Swing Components Supporting
252 * <code>Action</code></a>
253 * @since 1.6
254 * @beaninfo
255 * bound: true
256 * expert: true
257 * description: Whether the text of the button should come from
258 * the <code>Action</code>.
259 */
260 public void setHideActionText(boolean hideActionText) {
261 if (hideActionText != this.hideActionText) {
262 this.hideActionText = hideActionText;
263 if (getAction() != null) {
264 setTextFromAction(getAction(), false);
265 }
266 firePropertyChange("hideActionText", !hideActionText,
267 hideActionText);
268 }
269 }
270
271 /**
272 * Returns the value of the <code>hideActionText</code> property, which
273 * determines whether the button displays text from the
274 * <code>Action</code>. This is useful only if an <code>Action</code>
275 * has been installed on the button.
276 *
277 * @return <code>true</code> if the button's <code>text</code>
278 * property should not reflect that of the
279 * <code>Action</code>; the default is <code>false</code>
280 * @since 1.6
281 */
282 public boolean getHideActionText() {
283 return hideActionText;
284 }
285
286 /**
287 * Returns the button's text.
288 * @return the buttons text
289 * @see #setText
290 */
291 public String getText() {
292 return text;
293 }
294
295 /**
296 * Sets the button's text.
297 * @param text the string used to set the text
298 * @see #getText
299 * @beaninfo
300 * bound: true
301 * preferred: true
302 * attribute: visualUpdate true
303 * description: The button's text.
304 */
305 public void setText(String text) {
306 String oldValue = this.text;
307 this.text = text;
308 firePropertyChange(TEXT_CHANGED_PROPERTY, oldValue, text);
309 updateDisplayedMnemonicIndex(text, getMnemonic());
310
311 if (accessibleContext != null) {
312 accessibleContext.firePropertyChange(
313 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
314 oldValue, text);
315 }
316 if (text == null || oldValue == null || !text.equals(oldValue)) {
317 revalidate();
318 repaint();
319 }
320 }
321
322
323 /**
324 * Returns the state of the button. True if the
373 paintImmediately(new Rectangle(0,0, size.width, size.height));
374 try {
375 Thread.sleep(pressTime);
376 } catch(InterruptedException ie) {
377 }
378 model.setPressed(false);
379 model.setArmed(false);
380 }
381
382 /**
383 * Sets space for margin between the button's border and
384 * the label. Setting to <code>null</code> will cause the button to
385 * use the default margin. The button's default <code>Border</code>
386 * object will use this value to create the proper margin.
387 * However, if a non-default border is set on the button,
388 * it is that <code>Border</code> object's responsibility to create the
389 * appropriate margin space (else this property will
390 * effectively be ignored).
391 *
392 * @param m the space between the border and the label
393 *
394 * @beaninfo
395 * bound: true
396 * attribute: visualUpdate true
397 * description: The space between the button's border and the label.
398 */
399 public void setMargin(Insets m) {
400 // Cache the old margin if it comes from the UI
401 if(m instanceof UIResource) {
402 defaultMargin = m;
403 } else if(margin instanceof UIResource) {
404 defaultMargin = margin;
405 }
406
407 // If the client passes in a null insets, restore the margin
408 // from the UI if possible
409 if(m == null && defaultMargin != null) {
410 m = defaultMargin;
411 }
412
413 Insets old = margin;
414 margin = m;
415 firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);
416 if (old == null || !old.equals(m)) {
417 revalidate();
418 repaint();
431 return (margin == null) ? null : (Insets) margin.clone();
432 }
433
434 /**
435 * Returns the default icon.
436 * @return the default <code>Icon</code>
437 * @see #setIcon
438 */
439 public Icon getIcon() {
440 return defaultIcon;
441 }
442
443 /**
444 * Sets the button's default icon. This icon is
445 * also used as the "pressed" and "disabled" icon if
446 * there is no explicitly set pressed icon.
447 *
448 * @param defaultIcon the icon used as the default image
449 * @see #getIcon
450 * @see #setPressedIcon
451 * @beaninfo
452 * bound: true
453 * attribute: visualUpdate true
454 * description: The button's default icon
455 */
456 public void setIcon(Icon defaultIcon) {
457 Icon oldValue = this.defaultIcon;
458 this.defaultIcon = defaultIcon;
459
460 /* If the default icon has really changed and we had
461 * generated the disabled icon for this component,
462 * (i.e. setDisabledIcon() was never called) then
463 * clear the disabledIcon field.
464 */
465 if (defaultIcon != oldValue && (disabledIcon instanceof UIResource)) {
466 disabledIcon = null;
467 }
468
469 firePropertyChange(ICON_CHANGED_PROPERTY, oldValue, defaultIcon);
470 if (accessibleContext != null) {
471 accessibleContext.firePropertyChange(
472 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
473 oldValue, defaultIcon);
474 }
475 if (defaultIcon != oldValue) {
478 defaultIcon.getIconHeight() != oldValue.getIconHeight()) {
479 revalidate();
480 }
481 repaint();
482 }
483 }
484
485 /**
486 * Returns the pressed icon for the button.
487 * @return the <code>pressedIcon</code> property
488 * @see #setPressedIcon
489 */
490 public Icon getPressedIcon() {
491 return pressedIcon;
492 }
493
494 /**
495 * Sets the pressed icon for the button.
496 * @param pressedIcon the icon used as the "pressed" image
497 * @see #getPressedIcon
498 * @beaninfo
499 * bound: true
500 * attribute: visualUpdate true
501 * description: The pressed icon for the button.
502 */
503 public void setPressedIcon(Icon pressedIcon) {
504 Icon oldValue = this.pressedIcon;
505 this.pressedIcon = pressedIcon;
506 firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, oldValue, pressedIcon);
507 if (accessibleContext != null) {
508 accessibleContext.firePropertyChange(
509 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
510 oldValue, pressedIcon);
511 }
512 if (pressedIcon != oldValue) {
513 if (getModel().isPressed()) {
514 repaint();
515 }
516 }
517 }
518
519 /**
520 * Returns the selected icon for the button.
521 * @return the <code>selectedIcon</code> property
522 * @see #setSelectedIcon
523 */
524 public Icon getSelectedIcon() {
525 return selectedIcon;
526 }
527
528 /**
529 * Sets the selected icon for the button.
530 * @param selectedIcon the icon used as the "selected" image
531 * @see #getSelectedIcon
532 * @beaninfo
533 * bound: true
534 * attribute: visualUpdate true
535 * description: The selected icon for the button.
536 */
537 public void setSelectedIcon(Icon selectedIcon) {
538 Icon oldValue = this.selectedIcon;
539 this.selectedIcon = selectedIcon;
540
541 /* If the default selected icon has really changed and we had
542 * generated the disabled selected icon for this component,
543 * (i.e. setDisabledSelectedIcon() was never called) then
544 * clear the disabledSelectedIcon field.
545 */
546 if (selectedIcon != oldValue &&
547 disabledSelectedIcon instanceof UIResource) {
548
549 disabledSelectedIcon = null;
550 }
551
552 firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, oldValue, selectedIcon);
553 if (accessibleContext != null) {
554 accessibleContext.firePropertyChange(
555 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
556 oldValue, selectedIcon);
558 if (selectedIcon != oldValue) {
559 if (isSelected()) {
560 repaint();
561 }
562 }
563 }
564
565 /**
566 * Returns the rollover icon for the button.
567 * @return the <code>rolloverIcon</code> property
568 * @see #setRolloverIcon
569 */
570 public Icon getRolloverIcon() {
571 return rolloverIcon;
572 }
573
574 /**
575 * Sets the rollover icon for the button.
576 * @param rolloverIcon the icon used as the "rollover" image
577 * @see #getRolloverIcon
578 * @beaninfo
579 * bound: true
580 * attribute: visualUpdate true
581 * description: The rollover icon for the button.
582 */
583 public void setRolloverIcon(Icon rolloverIcon) {
584 Icon oldValue = this.rolloverIcon;
585 this.rolloverIcon = rolloverIcon;
586 firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, oldValue, rolloverIcon);
587 if (accessibleContext != null) {
588 accessibleContext.firePropertyChange(
589 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
590 oldValue, rolloverIcon);
591 }
592 setRolloverEnabled(true);
593 if (rolloverIcon != oldValue) {
594 // No way to determine whether we are currently in
595 // a rollover state, so repaint regardless
596 repaint();
597 }
598
599 }
600
601 /**
602 * Returns the rollover selection icon for the button.
603 * @return the <code>rolloverSelectedIcon</code> property
604 * @see #setRolloverSelectedIcon
605 */
606 public Icon getRolloverSelectedIcon() {
607 return rolloverSelectedIcon;
608 }
609
610 /**
611 * Sets the rollover selected icon for the button.
612 * @param rolloverSelectedIcon the icon used as the
613 * "selected rollover" image
614 * @see #getRolloverSelectedIcon
615 * @beaninfo
616 * bound: true
617 * attribute: visualUpdate true
618 * description: The rollover selected icon for the button.
619 */
620 public void setRolloverSelectedIcon(Icon rolloverSelectedIcon) {
621 Icon oldValue = this.rolloverSelectedIcon;
622 this.rolloverSelectedIcon = rolloverSelectedIcon;
623 firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, oldValue, rolloverSelectedIcon);
624 if (accessibleContext != null) {
625 accessibleContext.firePropertyChange(
626 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
627 oldValue, rolloverSelectedIcon);
628 }
629 setRolloverEnabled(true);
630 if (rolloverSelectedIcon != oldValue) {
631 // No way to determine whether we are currently in
632 // a rollover state, so repaint regardless
633 if (isSelected()) {
634 repaint();
635 }
636 }
637 }
638
639 /**
647 * @return the <code>disabledIcon</code> property
648 * @see #getPressedIcon
649 * @see #setDisabledIcon
650 * @see javax.swing.LookAndFeel#getDisabledIcon
651 */
652 @Transient
653 public Icon getDisabledIcon() {
654 if (disabledIcon == null) {
655 disabledIcon = UIManager.getLookAndFeel().getDisabledIcon(this, getIcon());
656 if (disabledIcon != null) {
657 firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, null, disabledIcon);
658 }
659 }
660 return disabledIcon;
661 }
662
663 /**
664 * Sets the disabled icon for the button.
665 * @param disabledIcon the icon used as the disabled image
666 * @see #getDisabledIcon
667 * @beaninfo
668 * bound: true
669 * attribute: visualUpdate true
670 * description: The disabled icon for the button.
671 */
672 public void setDisabledIcon(Icon disabledIcon) {
673 Icon oldValue = this.disabledIcon;
674 this.disabledIcon = disabledIcon;
675 firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, oldValue, disabledIcon);
676 if (accessibleContext != null) {
677 accessibleContext.firePropertyChange(
678 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
679 oldValue, disabledIcon);
680 }
681 if (disabledIcon != oldValue) {
682 if (!isEnabled()) {
683 repaint();
684 }
685 }
686 }
687
688 /**
689 * Returns the icon used by the button when it's disabled and selected.
690 * If no disabled selection icon has been set, this will forward
691 * the call to the LookAndFeel to construct an appropriate disabled
700 * @see #setDisabledSelectedIcon
701 * @see javax.swing.LookAndFeel#getDisabledSelectedIcon
702 */
703 public Icon getDisabledSelectedIcon() {
704 if (disabledSelectedIcon == null) {
705 if (selectedIcon != null) {
706 disabledSelectedIcon = UIManager.getLookAndFeel().
707 getDisabledSelectedIcon(this, getSelectedIcon());
708 } else {
709 return getDisabledIcon();
710 }
711 }
712 return disabledSelectedIcon;
713 }
714
715 /**
716 * Sets the disabled selection icon for the button.
717 * @param disabledSelectedIcon the icon used as the disabled
718 * selection image
719 * @see #getDisabledSelectedIcon
720 * @beaninfo
721 * bound: true
722 * attribute: visualUpdate true
723 * description: The disabled selection icon for the button.
724 */
725 public void setDisabledSelectedIcon(Icon disabledSelectedIcon) {
726 Icon oldValue = this.disabledSelectedIcon;
727 this.disabledSelectedIcon = disabledSelectedIcon;
728 firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, oldValue, disabledSelectedIcon);
729 if (accessibleContext != null) {
730 accessibleContext.firePropertyChange(
731 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
732 oldValue, disabledSelectedIcon);
733 }
734 if (disabledSelectedIcon != oldValue) {
735 if (disabledSelectedIcon == null || oldValue == null ||
736 disabledSelectedIcon.getIconWidth() != oldValue.getIconWidth() ||
737 disabledSelectedIcon.getIconHeight() != oldValue.getIconHeight()) {
738 revalidate();
739 }
740 if (!isEnabled() && isSelected()) {
741 repaint();
742 }
743 }
744 }
751 * <ul>
752 * <li>{@code SwingConstants.CENTER} (the default)
753 * <li>{@code SwingConstants.TOP}
754 * <li>{@code SwingConstants.BOTTOM}
755 * </ul>
756 */
757 public int getVerticalAlignment() {
758 return verticalAlignment;
759 }
760
761 /**
762 * Sets the vertical alignment of the icon and text.
763 * @param alignment one of the following values:
764 * <ul>
765 * <li>{@code SwingConstants.CENTER} (the default)
766 * <li>{@code SwingConstants.TOP}
767 * <li>{@code SwingConstants.BOTTOM}
768 * </ul>
769 * @throws IllegalArgumentException if the alignment is not one of the legal
770 * values listed above
771 * @beaninfo
772 * bound: true
773 * enum: TOP SwingConstants.TOP
774 * CENTER SwingConstants.CENTER
775 * BOTTOM SwingConstants.BOTTOM
776 * attribute: visualUpdate true
777 * description: The vertical alignment of the icon and text.
778 */
779 public void setVerticalAlignment(int alignment) {
780 if (alignment == verticalAlignment) return;
781 int oldValue = verticalAlignment;
782 verticalAlignment = checkVerticalKey(alignment, "verticalAlignment");
783 firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, oldValue, verticalAlignment); repaint();
784 }
785
786 /**
787 * Returns the horizontal alignment of the icon and text.
788 * {@code AbstractButton}'s default is {@code SwingConstants.CENTER},
789 * but subclasses such as {@code JCheckBox} may use a different default.
790 *
791 * @return the <code>horizontalAlignment</code> property,
792 * one of the following values:
793 * <ul>
794 * <li>{@code SwingConstants.RIGHT}
795 * <li>{@code SwingConstants.LEFT}
796 * <li>{@code SwingConstants.CENTER}
797 * <li>{@code SwingConstants.LEADING}
798 * <li>{@code SwingConstants.TRAILING}
800 */
801 public int getHorizontalAlignment() {
802 return horizontalAlignment;
803 }
804
805 /**
806 * Sets the horizontal alignment of the icon and text.
807 * {@code AbstractButton}'s default is {@code SwingConstants.CENTER},
808 * but subclasses such as {@code JCheckBox} may use a different default.
809 *
810 * @param alignment the alignment value, one of the following values:
811 * <ul>
812 * <li>{@code SwingConstants.RIGHT}
813 * <li>{@code SwingConstants.LEFT}
814 * <li>{@code SwingConstants.CENTER}
815 * <li>{@code SwingConstants.LEADING}
816 * <li>{@code SwingConstants.TRAILING}
817 * </ul>
818 * @throws IllegalArgumentException if the alignment is not one of the
819 * valid values
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 alignment of the icon and text.
829 */
830 public void setHorizontalAlignment(int alignment) {
831 if (alignment == horizontalAlignment) return;
832 int oldValue = horizontalAlignment;
833 horizontalAlignment = checkHorizontalKey(alignment,
834 "horizontalAlignment");
835 firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY,
836 oldValue, horizontalAlignment);
837 repaint();
838 }
839
840
841 /**
842 * Returns the vertical position of the text relative to the icon.
843 * @return the <code>verticalTextPosition</code> property,
844 * one of the following values:
845 * <ul>
846 * <li>{@code SwingConstants.CENTER} (the default)
847 * <li>{@code SwingConstants.TOP}
848 * <li>{@code SwingConstants.BOTTOM}
849 * </ul>
850 */
851 public int getVerticalTextPosition() {
852 return verticalTextPosition;
853 }
854
855 /**
856 * Sets the vertical position of the text relative to the icon.
857 * @param textPosition one of the following values:
858 * <ul>
859 * <li>{@code SwingConstants.CENTER} (the default)
860 * <li>{@code SwingConstants.TOP}
861 * <li>{@code SwingConstants.BOTTOM}
862 * </ul>
863 * @beaninfo
864 * bound: true
865 * enum: TOP SwingConstants.TOP
866 * CENTER SwingConstants.CENTER
867 * BOTTOM SwingConstants.BOTTOM
868 * attribute: visualUpdate true
869 * description: The vertical position of the text relative to the icon.
870 */
871 public void setVerticalTextPosition(int textPosition) {
872 if (textPosition == verticalTextPosition) return;
873 int oldValue = verticalTextPosition;
874 verticalTextPosition = checkVerticalKey(textPosition, "verticalTextPosition");
875 firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, oldValue, verticalTextPosition);
876 revalidate();
877 repaint();
878 }
879
880 /**
881 * Returns the horizontal position of the text relative to the icon.
882 * @return the <code>horizontalTextPosition</code> property,
883 * one of the following values:
884 * <ul>
885 * <li>{@code SwingConstants.RIGHT}
886 * <li>{@code SwingConstants.LEFT}
887 * <li>{@code SwingConstants.CENTER}
888 * <li>{@code SwingConstants.LEADING}
889 * <li>{@code SwingConstants.TRAILING} (the default)
890 * </ul>
891 */
892 public int getHorizontalTextPosition() {
893 return horizontalTextPosition;
894 }
895
896 /**
897 * Sets the horizontal position of the text relative to the icon.
898 * @param textPosition one of the following values:
899 * <ul>
900 * <li>{@code SwingConstants.RIGHT}
901 * <li>{@code SwingConstants.LEFT}
902 * <li>{@code SwingConstants.CENTER}
903 * <li>{@code SwingConstants.LEADING}
904 * <li>{@code SwingConstants.TRAILING} (the default)
905 * </ul>
906 * @exception IllegalArgumentException if <code>textPosition</code>
907 * is not one of the legal values listed above
908 * @beaninfo
909 * bound: true
910 * enum: LEFT SwingConstants.LEFT
911 * CENTER SwingConstants.CENTER
912 * RIGHT SwingConstants.RIGHT
913 * LEADING SwingConstants.LEADING
914 * TRAILING SwingConstants.TRAILING
915 * attribute: visualUpdate true
916 * description: The horizontal position of the text relative to the icon.
917 */
918 public void setHorizontalTextPosition(int textPosition) {
919 if (textPosition == horizontalTextPosition) return;
920 int oldValue = horizontalTextPosition;
921 horizontalTextPosition = checkHorizontalKey(textPosition,
922 "horizontalTextPosition");
923 firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY,
924 oldValue,
925 horizontalTextPosition);
926 revalidate();
927 repaint();
928 }
929
930 /**
931 * Returns the amount of space between the text and the icon
932 * displayed in this button.
933 *
934 * @return an int equal to the number of pixels between the text
935 * and the icon.
936 * @since 1.4
937 * @see #setIconTextGap
938 */
939 public int getIconTextGap() {
940 return iconTextGap;
941 }
942
943 /**
944 * If both the icon and text properties are set, this property
945 * defines the space between them.
946 * <p>
947 * The default value of this property is 4 pixels.
948 * <p>
949 * This is a JavaBeans bound property.
950 *
951 * @param iconTextGap the space between icon and text if these properties are set.
952 * @since 1.4
953 * @see #getIconTextGap
954 * @beaninfo
955 * bound: true
956 * attribute: visualUpdate true
957 * description: If both the icon and text properties are set, this
958 * property defines the space between them.
959 */
960 public void setIconTextGap(int iconTextGap) {
961 int oldValue = this.iconTextGap;
962 this.iconTextGap = iconTextGap;
963 iconTextGapSet = true;
964 firePropertyChange("iconTextGap", oldValue, iconTextGap);
965 if (iconTextGap != oldValue) {
966 revalidate();
967 repaint();
968 }
969 }
970
971 /**
972 * Verify that the {@code key} argument is a legal value for the
973 * {@code horizontalAlignment} and {@code horizontalTextPosition}
974 * properties. Valid values are:
975 * <ul>
976 * <li>{@code SwingConstants.RIGHT}
977 * <li>{@code SwingConstants.LEFT}
978 * <li>{@code SwingConstants.CENTER}
979 * <li>{@code SwingConstants.LEADING}
1078 * <p>
1079 * This method uses three other methods to set
1080 * and help track the <code>Action</code>'s property values.
1081 * It uses the <code>configurePropertiesFromAction</code> method
1082 * to immediately change the button's properties.
1083 * To track changes in the <code>Action</code>'s property values,
1084 * this method registers the <code>PropertyChangeListener</code>
1085 * returned by <code>createActionPropertyChangeListener</code>. The
1086 * default {@code PropertyChangeListener} invokes the
1087 * {@code actionPropertyChanged} method when a property in the
1088 * {@code Action} changes.
1089 *
1090 * @param a the <code>Action</code> for the <code>AbstractButton</code>,
1091 * or <code>null</code>
1092 * @since 1.3
1093 * @see Action
1094 * @see #getAction
1095 * @see #configurePropertiesFromAction
1096 * @see #createActionPropertyChangeListener
1097 * @see #actionPropertyChanged
1098 * @beaninfo
1099 * bound: true
1100 * attribute: visualUpdate true
1101 * description: the Action instance connected with this ActionEvent source
1102 */
1103 public void setAction(Action a) {
1104 Action oldValue = getAction();
1105 if (action==null || !action.equals(a)) {
1106 action = a;
1107 if (oldValue!=null) {
1108 removeActionListener(oldValue);
1109 oldValue.removePropertyChangeListener(actionPropertyChangeListener);
1110 actionPropertyChangeListener = null;
1111 }
1112 configurePropertiesFromAction(action);
1113 if (action!=null) {
1114 // Don't add if it is already a listener
1115 if (!isListener(ActionListener.class, action)) {
1116 addActionListener(action);
1117 }
1118 // Reverse linkage:
1119 actionPropertyChangeListener = createActionPropertyChangeListener(action);
1120 action.addPropertyChangeListener(actionPropertyChangeListener);
1121 }
1122 firePropertyChange("action", oldValue, action);
1376 * @return the value of the <code>borderPainted</code> property
1377 * @see #setBorderPainted
1378 */
1379 public boolean isBorderPainted() {
1380 return paintBorder;
1381 }
1382
1383 /**
1384 * Sets the <code>borderPainted</code> property.
1385 * If <code>true</code> and the button has a border,
1386 * the border is painted. The default value for the
1387 * <code>borderPainted</code> property is <code>true</code>.
1388 * <p>
1389 * Some look and feels might not support
1390 * the <code>borderPainted</code> property,
1391 * in which case they ignore this.
1392 *
1393 * @param b if true and border property is not <code>null</code>,
1394 * the border is painted
1395 * @see #isBorderPainted
1396 * @beaninfo
1397 * bound: true
1398 * attribute: visualUpdate true
1399 * description: Whether the border should be painted.
1400 */
1401 public void setBorderPainted(boolean b) {
1402 boolean oldValue = paintBorder;
1403 paintBorder = b;
1404 borderPaintedSet = true;
1405 firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, oldValue, paintBorder);
1406 if (b != oldValue) {
1407 revalidate();
1408 repaint();
1409 }
1410 }
1411
1412 /**
1413 * Paint the button's border if <code>BorderPainted</code>
1414 * property is true and the button has a border.
1415 * @param g the <code>Graphics</code> context in which to paint
1416 *
1417 * @see #paint
1418 * @see #setBorder
1419 */
1420 protected void paintBorder(Graphics g) {
1426 /**
1427 * Gets the <code>paintFocus</code> property.
1428 *
1429 * @return the <code>paintFocus</code> property
1430 * @see #setFocusPainted
1431 */
1432 public boolean isFocusPainted() {
1433 return paintFocus;
1434 }
1435
1436 /**
1437 * Sets the <code>paintFocus</code> property, which must
1438 * be <code>true</code> for the focus state to be painted.
1439 * The default value for the <code>paintFocus</code> property
1440 * is <code>true</code>.
1441 * Some look and feels might not paint focus state;
1442 * they will ignore this property.
1443 *
1444 * @param b if <code>true</code>, the focus state should be painted
1445 * @see #isFocusPainted
1446 * @beaninfo
1447 * bound: true
1448 * attribute: visualUpdate true
1449 * description: Whether focus should be painted
1450 */
1451 public void setFocusPainted(boolean b) {
1452 boolean oldValue = paintFocus;
1453 paintFocus = b;
1454 firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, oldValue, paintFocus);
1455 if (b != oldValue && isFocusOwner()) {
1456 revalidate();
1457 repaint();
1458 }
1459 }
1460
1461 /**
1462 * Gets the <code>contentAreaFilled</code> property.
1463 *
1464 * @return the <code>contentAreaFilled</code> property
1465 * @see #setContentAreaFilled
1466 */
1467 public boolean isContentAreaFilled() {
1468 return contentAreaFilled;
1469 }
1470
1471 /**
1472 * Sets the <code>contentAreaFilled</code> property.
1473 * If <code>true</code> the button will paint the content
1474 * area. If you wish to have a transparent button, such as
1475 * an icon only button, for example, then you should set
1476 * this to <code>false</code>. Do not call <code>setOpaque(false)</code>.
1477 * The default value for the the <code>contentAreaFilled</code>
1478 * property is <code>true</code>.
1479 * <p>
1480 * This function may cause the component's opaque property to change.
1481 * <p>
1482 * The exact behavior of calling this function varies on a
1483 * component-by-component and L&F-by-L&F basis.
1484 *
1485 * @param b if true, the content should be filled; if false
1486 * the content area is not filled
1487 * @see #isContentAreaFilled
1488 * @see #setOpaque
1489 * @beaninfo
1490 * bound: true
1491 * attribute: visualUpdate true
1492 * description: Whether the button should paint the content area
1493 * or leave it transparent.
1494 */
1495 public void setContentAreaFilled(boolean b) {
1496 boolean oldValue = contentAreaFilled;
1497 contentAreaFilled = b;
1498 contentAreaFilledSet = true;
1499 firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, oldValue, contentAreaFilled);
1500 if (b != oldValue) {
1501 repaint();
1502 }
1503 }
1504
1505 /**
1506 * Gets the <code>rolloverEnabled</code> property.
1507 *
1508 * @return the value of the <code>rolloverEnabled</code> property
1509 * @see #setRolloverEnabled
1510 */
1511 public boolean isRolloverEnabled() {
1512 return rolloverEnabled;
1513 }
1514
1515 /**
1516 * Sets the <code>rolloverEnabled</code> property, which
1517 * must be <code>true</code> for rollover effects to occur.
1518 * The default value for the <code>rolloverEnabled</code>
1519 * property is <code>false</code>.
1520 * Some look and feels might not implement rollover effects;
1521 * they will ignore this property.
1522 *
1523 * @param b if <code>true</code>, rollover effects should be painted
1524 * @see #isRolloverEnabled
1525 * @beaninfo
1526 * bound: true
1527 * attribute: visualUpdate true
1528 * description: Whether rollover effects should be enabled.
1529 */
1530 public void setRolloverEnabled(boolean b) {
1531 boolean oldValue = rolloverEnabled;
1532 rolloverEnabled = b;
1533 rolloverEnabledSet = true;
1534 firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, oldValue, rolloverEnabled);
1535 if (b != oldValue) {
1536 repaint();
1537 }
1538 }
1539
1540 /**
1541 * Returns the keyboard mnemonic from the the current model.
1542 * @return the keyboard mnemonic from the model
1543 */
1544 public int getMnemonic() {
1545 return mnemonic;
1546 }
1547
1548 /**
1549 * Sets the keyboard mnemonic on the current model.
1552 * if focus is contained somewhere within this button's ancestor
1553 * window.
1554 * <p>
1555 * A mnemonic must correspond to a single key on the keyboard
1556 * and should be specified using one of the <code>VK_XXX</code>
1557 * keycodes defined in <code>java.awt.event.KeyEvent</code>.
1558 * These codes and the wider array of codes for international
1559 * keyboards may be obtained through
1560 * <code>java.awt.event.KeyEvent.getExtendedKeyCodeForChar</code>.
1561 * Mnemonics are case-insensitive, therefore a key event
1562 * with the corresponding keycode would cause the button to be
1563 * activated whether or not the Shift modifier was pressed.
1564 * <p>
1565 * If the character defined by the mnemonic is found within
1566 * the button's label string, the first occurrence of it
1567 * will be underlined to indicate the mnemonic to the user.
1568 *
1569 * @param mnemonic the key code which represents the mnemonic
1570 * @see java.awt.event.KeyEvent
1571 * @see #setDisplayedMnemonicIndex
1572 *
1573 * @beaninfo
1574 * bound: true
1575 * attribute: visualUpdate true
1576 * description: the keyboard character mnemonic
1577 */
1578 public void setMnemonic(int mnemonic) {
1579 int oldValue = getMnemonic();
1580 model.setMnemonic(mnemonic);
1581 updateMnemonicProperties();
1582 }
1583
1584 /**
1585 * This method is now obsolete, please use <code>setMnemonic(int)</code>
1586 * to set the mnemonic for a button. This method is only designed
1587 * to handle character values which fall between 'a' and 'z' or
1588 * 'A' and 'Z'.
1589 *
1590 * @param mnemonic a char specifying the mnemonic value
1591 * @see #setMnemonic(int)
1592 * @beaninfo
1593 * bound: true
1594 * attribute: visualUpdate true
1595 * description: the keyboard character mnemonic
1596 */
1597 public void setMnemonic(char mnemonic) {
1598 int vk = (int) mnemonic;
1599 if(vk >= 'a' && vk <='z')
1600 vk -= ('a' - 'A');
1601 setMnemonic(vk);
1602 }
1603
1604 /**
1605 * Provides a hint to the look and feel as to which character in the
1606 * text should be decorated to represent the mnemonic. Not all look and
1607 * feels may support this. A value of -1 indicates either there is no
1608 * mnemonic, the mnemonic character is not contained in the string, or
1609 * the developer does not wish the mnemonic to be displayed.
1610 * <p>
1611 * The value of this is updated as the properties relating to the
1612 * mnemonic change (such as the mnemonic itself, the text...).
1613 * You should only ever have to call this if
1614 * you do not wish the default character to be underlined. For example, if
1615 * the text was 'Save As', with a mnemonic of 'a', and you wanted the 'A'
1616 * to be decorated, as 'Save <u>A</u>s', you would have to invoke
1617 * <code>setDisplayedMnemonicIndex(5)</code> after invoking
1618 * <code>setMnemonic(KeyEvent.VK_A)</code>.
1619 *
1620 * @since 1.4
1621 * @param index Index into the String to underline
1622 * @exception IllegalArgumentException will be thrown if <code>index</code>
1623 * is >= length of the text, or < -1
1624 * @see #getDisplayedMnemonicIndex
1625 *
1626 * @beaninfo
1627 * bound: true
1628 * attribute: visualUpdate true
1629 * description: the index into the String to draw the keyboard character
1630 * mnemonic at
1631 */
1632 public void setDisplayedMnemonicIndex(int index)
1633 throws IllegalArgumentException {
1634 int oldValue = mnemonicIndex;
1635 if (index == -1) {
1636 mnemonicIndex = -1;
1637 } else {
1638 String text = getText();
1639 int textLength = (text == null) ? 0 : text.length();
1640 if (index < -1 || index >= textLength) { // index out of range
1641 throw new IllegalArgumentException("index == " + index);
1642 }
1643 }
1644 mnemonicIndex = index;
1645 firePropertyChange("displayedMnemonicIndex", oldValue, index);
1646 if (index != oldValue) {
1647 revalidate();
1648 repaint();
1649 }
1650 }
1651
1726 * to generate corresponding action events
1727 * @since 1.4
1728 */
1729 public long getMultiClickThreshhold() {
1730 return multiClickThreshhold;
1731 }
1732
1733 /**
1734 * Returns the model that this button represents.
1735 * @return the <code>model</code> property
1736 * @see #setModel
1737 */
1738 public ButtonModel getModel() {
1739 return model;
1740 }
1741
1742 /**
1743 * Sets the model that this button represents.
1744 * @param newModel the new <code>ButtonModel</code>
1745 * @see #getModel
1746 * @beaninfo
1747 * bound: true
1748 * description: Model that the Button uses.
1749 */
1750 public void setModel(ButtonModel newModel) {
1751
1752 ButtonModel oldModel = getModel();
1753
1754 if (oldModel != null) {
1755 oldModel.removeChangeListener(changeListener);
1756 oldModel.removeActionListener(actionListener);
1757 oldModel.removeItemListener(itemListener);
1758 changeListener = null;
1759 actionListener = null;
1760 itemListener = null;
1761 }
1762
1763 model = newModel;
1764
1765 if (newModel != null) {
1766 changeListener = createChangeListener();
1767 actionListener = createActionListener();
1768 itemListener = createItemListener();
1769 newModel.addChangeListener(changeListener);
1787 revalidate();
1788 repaint();
1789 }
1790 }
1791
1792
1793 /**
1794 * Returns the L&F object that renders this component.
1795 * @return the ButtonUI object
1796 * @see #setUI
1797 */
1798 public ButtonUI getUI() {
1799 return (ButtonUI) ui;
1800 }
1801
1802
1803 /**
1804 * Sets the L&F object that renders this component.
1805 * @param ui the <code>ButtonUI</code> L&F object
1806 * @see #getUI
1807 * @beaninfo
1808 * bound: true
1809 * hidden: true
1810 * attribute: visualUpdate true
1811 * description: The UI object that implements the LookAndFeel.
1812 */
1813 public void setUI(ButtonUI ui) {
1814 super.setUI(ui);
1815 // disabled icons are generated by the LF so they should be unset here
1816 if (disabledIcon instanceof UIResource) {
1817 setDisabledIcon(null);
1818 }
1819 if (disabledSelectedIcon instanceof UIResource) {
1820 setDisabledSelectedIcon(null);
1821 }
1822 }
1823
1824
1825 /**
1826 * Resets the UI property to a value from the current look
1827 * and feel. Subtypes of <code>AbstractButton</code>
1828 * should override this to update the UI. For
1829 * example, <code>JButton</code> might do the following:
1830 * <pre>
1831 * setUI((ButtonUI)UIManager.getUI(
1832 * "ButtonUI", "javax.swing.plaf.basic.BasicButtonUI", this));
1880 public void addChangeListener(ChangeListener l) {
1881 listenerList.add(ChangeListener.class, l);
1882 }
1883
1884 /**
1885 * Removes a ChangeListener from the button.
1886 * @param l the listener to be removed
1887 */
1888 public void removeChangeListener(ChangeListener l) {
1889 listenerList.remove(ChangeListener.class, l);
1890 }
1891
1892 /**
1893 * Returns an array of all the <code>ChangeListener</code>s added
1894 * to this AbstractButton with addChangeListener().
1895 *
1896 * @return all of the <code>ChangeListener</code>s added or an empty
1897 * array if no listeners have been added
1898 * @since 1.4
1899 */
1900 public ChangeListener[] getChangeListeners() {
1901 return listenerList.getListeners(ChangeListener.class);
1902 }
1903
1904 /**
1905 * Notifies all listeners that have registered interest for
1906 * notification on this event type. The event instance
1907 * is lazily created.
1908 * @see EventListenerList
1909 */
1910 protected void fireStateChanged() {
1911 // Guaranteed to return a non-null array
1912 Object[] listeners = listenerList.getListenerList();
1913 // Process the listeners last to first, notifying
1914 // those that are interested in this event
1915 for (int i = listeners.length-2; i>=0; i-=2) {
1916 if (listeners[i]==ChangeListener.class) {
1917 // Lazily create the event:
1918 if (changeEvent == null)
1919 changeEvent = new ChangeEvent(this);
1937 * is set to <code>null</code>.
1938 *
1939 * @param l the listener to be removed
1940 */
1941 public void removeActionListener(ActionListener l) {
1942 if ((l != null) && (getAction() == l)) {
1943 setAction(null);
1944 } else {
1945 listenerList.remove(ActionListener.class, l);
1946 }
1947 }
1948
1949 /**
1950 * Returns an array of all the <code>ActionListener</code>s added
1951 * to this AbstractButton with addActionListener().
1952 *
1953 * @return all of the <code>ActionListener</code>s added or an empty
1954 * array if no listeners have been added
1955 * @since 1.4
1956 */
1957 public ActionListener[] getActionListeners() {
1958 return listenerList.getListeners(ActionListener.class);
1959 }
1960
1961 /**
1962 * Subclasses that want to handle <code>ChangeEvents</code> differently
1963 * can override this to return another <code>ChangeListener</code>
1964 * implementation.
1965 *
1966 * @return the new <code>ChangeListener</code>
1967 */
1968 protected ChangeListener createChangeListener() {
1969 return getHandler();
1970 }
1971
1972 /**
1973 * Extends <code>ChangeListener</code> to be serializable.
1974 * <p>
1975 * <strong>Warning:</strong>
1976 * Serialized objects of this class will not be compatible with
2105 }
2106
2107 // *** Deprecated java.awt.Button APIs below *** //
2108
2109 /**
2110 * Returns the label text.
2111 *
2112 * @return a <code>String</code> containing the label
2113 * @deprecated - Replaced by <code>getText</code>
2114 */
2115 @Deprecated
2116 public String getLabel() {
2117 return getText();
2118 }
2119
2120 /**
2121 * Sets the label text.
2122 *
2123 * @param label a <code>String</code> containing the text
2124 * @deprecated - Replaced by <code>setText(text)</code>
2125 * @beaninfo
2126 * bound: true
2127 * description: Replace by setText(text)
2128 */
2129 @Deprecated
2130 public void setLabel(String label) {
2131 setText(label);
2132 }
2133
2134 /**
2135 * Adds an <code>ItemListener</code> to the <code>checkbox</code>.
2136 * @param l the <code>ItemListener</code> to be added
2137 */
2138 public void addItemListener(ItemListener l) {
2139 listenerList.add(ItemListener.class, l);
2140 }
2141
2142 /**
2143 * Removes an <code>ItemListener</code> from the button.
2144 * @param l the <code>ItemListener</code> to be removed
2145 */
2146 public void removeItemListener(ItemListener l) {
2147 listenerList.remove(ItemListener.class, l);
2148 }
2149
2150 /**
2151 * Returns an array of all the <code>ItemListener</code>s added
2152 * to this AbstractButton with addItemListener().
2153 *
2154 * @return all of the <code>ItemListener</code>s added or an empty
2155 * array if no listeners have been added
2156 * @since 1.4
2157 */
2158 public ItemListener[] getItemListeners() {
2159 return listenerList.getListeners(ItemListener.class);
2160 }
2161
2162 /**
2163 * Returns an array (length 1) containing the label or
2164 * <code>null</code> if the button is not selected.
2165 *
2166 * @return an array containing 1 Object: the text of the button,
2167 * if the item is selected; otherwise <code>null</code>
2168 */
2169 public Object[] getSelectedObjects() {
2170 if (isSelected() == false) {
2171 return null;
2172 }
2173 Object[] selectedObjects = new Object[1];
2174 selectedObjects[0] = getText();
2175 return selectedObjects;
2176 }
2177
2178 /**
2179 * Initialization of the {@code AbstractButton}.
2180 *
2181 * @param text the text of the button
2182 * @param icon the Icon image to display on the button
2183 */
2184 protected void init(String text, Icon icon) {
2185 if(text != null) {
2186 setText(text);
2187 }
2188
|
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package javax.swing;
26
27 import java.awt.*;
28 import java.awt.event.*;
29 import java.text.*;
30 import java.awt.geom.*;
31 import java.beans.JavaBean;
32 import java.beans.BeanProperty;
33 import java.beans.PropertyChangeEvent;
34 import java.beans.PropertyChangeListener;
35 import java.beans.Transient;
36 import java.util.Enumeration;
37 import java.io.Serializable;
38 import javax.swing.event.*;
39 import javax.swing.plaf.*;
40 import javax.accessibility.*;
41 import javax.swing.text.*;
42
43 /**
44 * Defines common behaviors for buttons and menu items.
45 * <p>
46 * Buttons can be configured, and to some degree controlled, by
47 * <code><a href="Action.html">Action</a></code>s. Using an
48 * <code>Action</code> with a button has many benefits beyond directly
49 * configuring a button. Refer to <a href="Action.html#buttonActions">
50 * Swing Components Supporting <code>Action</code></a> for more
51 * details, and you can find more information in <a
52 * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
53 * to Use Actions</a>, a section in <em>The Java Tutorial</em>.
54 * <p>
55 * For further information see
56 * <a
57 href="http://docs.oracle.com/javase/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons</a>,
58 * a section in <em>The Java Tutorial</em>.
59 * <p>
60 * <strong>Warning:</strong>
61 * Serialized objects of this class will not be compatible with
62 * future Swing releases. The current serialization support is
63 * appropriate for short term storage or RMI between applications running
64 * the same version of Swing. As of 1.4, support for long term storage
65 * of all JavaBeans™
66 * has been added to the <code>java.beans</code> package.
67 * Please see {@link java.beans.XMLEncoder}.
68 *
69 * @author Jeff Dinkins
70 * @since 1.2
71 */
72 @JavaBean(defaultProperty = "UI")
73 @SuppressWarnings("serial") // Same-version serialization only
74 public abstract class AbstractButton extends JComponent implements ItemSelectable, SwingConstants {
75
76 // *********************************
77 // ******* Button properties *******
78 // *********************************
79
80 /** Identifies a change in the button model. */
81 public static final String MODEL_CHANGED_PROPERTY = "model";
82 /** Identifies a change in the button's text. */
83 public static final String TEXT_CHANGED_PROPERTY = "text";
84 /** Identifies a change to the button's mnemonic. */
85 public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic";
86
87 // Text positioning and alignment
88 /** Identifies a change in the button's margins. */
89 public static final String MARGIN_CHANGED_PROPERTY = "margin";
90 /** Identifies a change in the button's vertical alignment. */
91 public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";
92 /** Identifies a change in the button's horizontal alignment. */
231 * event's only state is the source property. The source of events
232 * generated is always "this".
233 */
234 protected transient ChangeEvent changeEvent;
235
236 private boolean hideActionText = false;
237
238 /**
239 * Sets the <code>hideActionText</code> property, which determines
240 * whether the button displays text from the <code>Action</code>.
241 * This is useful only if an <code>Action</code> has been
242 * installed on the button.
243 *
244 * @param hideActionText <code>true</code> if the button's
245 * <code>text</code> property should not reflect
246 * that of the <code>Action</code>; the default is
247 * <code>false</code>
248 * @see <a href="Action.html#buttonActions">Swing Components Supporting
249 * <code>Action</code></a>
250 * @since 1.6
251 */
252 @BeanProperty(expert = true, description
253 = "Whether the text of the button should come from the <code>Action</code>.")
254 public void setHideActionText(boolean hideActionText) {
255 if (hideActionText != this.hideActionText) {
256 this.hideActionText = hideActionText;
257 if (getAction() != null) {
258 setTextFromAction(getAction(), false);
259 }
260 firePropertyChange("hideActionText", !hideActionText,
261 hideActionText);
262 }
263 }
264
265 /**
266 * Returns the value of the <code>hideActionText</code> property, which
267 * determines whether the button displays text from the
268 * <code>Action</code>. This is useful only if an <code>Action</code>
269 * has been installed on the button.
270 *
271 * @return <code>true</code> if the button's <code>text</code>
272 * property should not reflect that of the
273 * <code>Action</code>; the default is <code>false</code>
274 * @since 1.6
275 */
276 public boolean getHideActionText() {
277 return hideActionText;
278 }
279
280 /**
281 * Returns the button's text.
282 * @return the buttons text
283 * @see #setText
284 */
285 public String getText() {
286 return text;
287 }
288
289 /**
290 * Sets the button's text.
291 * @param text the string used to set the text
292 * @see #getText
293 */
294 @BeanProperty(preferred = true, visualUpdate = true, description
295 = "The button's text.")
296 public void setText(String text) {
297 String oldValue = this.text;
298 this.text = text;
299 firePropertyChange(TEXT_CHANGED_PROPERTY, oldValue, text);
300 updateDisplayedMnemonicIndex(text, getMnemonic());
301
302 if (accessibleContext != null) {
303 accessibleContext.firePropertyChange(
304 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
305 oldValue, text);
306 }
307 if (text == null || oldValue == null || !text.equals(oldValue)) {
308 revalidate();
309 repaint();
310 }
311 }
312
313
314 /**
315 * Returns the state of the button. True if the
364 paintImmediately(new Rectangle(0,0, size.width, size.height));
365 try {
366 Thread.sleep(pressTime);
367 } catch(InterruptedException ie) {
368 }
369 model.setPressed(false);
370 model.setArmed(false);
371 }
372
373 /**
374 * Sets space for margin between the button's border and
375 * the label. Setting to <code>null</code> will cause the button to
376 * use the default margin. The button's default <code>Border</code>
377 * object will use this value to create the proper margin.
378 * However, if a non-default border is set on the button,
379 * it is that <code>Border</code> object's responsibility to create the
380 * appropriate margin space (else this property will
381 * effectively be ignored).
382 *
383 * @param m the space between the border and the label
384 */
385 @BeanProperty(visualUpdate = true, description
386 = "The space between the button's border and the label.")
387 public void setMargin(Insets m) {
388 // Cache the old margin if it comes from the UI
389 if(m instanceof UIResource) {
390 defaultMargin = m;
391 } else if(margin instanceof UIResource) {
392 defaultMargin = margin;
393 }
394
395 // If the client passes in a null insets, restore the margin
396 // from the UI if possible
397 if(m == null && defaultMargin != null) {
398 m = defaultMargin;
399 }
400
401 Insets old = margin;
402 margin = m;
403 firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);
404 if (old == null || !old.equals(m)) {
405 revalidate();
406 repaint();
419 return (margin == null) ? null : (Insets) margin.clone();
420 }
421
422 /**
423 * Returns the default icon.
424 * @return the default <code>Icon</code>
425 * @see #setIcon
426 */
427 public Icon getIcon() {
428 return defaultIcon;
429 }
430
431 /**
432 * Sets the button's default icon. This icon is
433 * also used as the "pressed" and "disabled" icon if
434 * there is no explicitly set pressed icon.
435 *
436 * @param defaultIcon the icon used as the default image
437 * @see #getIcon
438 * @see #setPressedIcon
439 */
440 @BeanProperty(visualUpdate = true, description
441 = "The button's default icon")
442 public void setIcon(Icon defaultIcon) {
443 Icon oldValue = this.defaultIcon;
444 this.defaultIcon = defaultIcon;
445
446 /* If the default icon has really changed and we had
447 * generated the disabled icon for this component,
448 * (i.e. setDisabledIcon() was never called) then
449 * clear the disabledIcon field.
450 */
451 if (defaultIcon != oldValue && (disabledIcon instanceof UIResource)) {
452 disabledIcon = null;
453 }
454
455 firePropertyChange(ICON_CHANGED_PROPERTY, oldValue, defaultIcon);
456 if (accessibleContext != null) {
457 accessibleContext.firePropertyChange(
458 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
459 oldValue, defaultIcon);
460 }
461 if (defaultIcon != oldValue) {
464 defaultIcon.getIconHeight() != oldValue.getIconHeight()) {
465 revalidate();
466 }
467 repaint();
468 }
469 }
470
471 /**
472 * Returns the pressed icon for the button.
473 * @return the <code>pressedIcon</code> property
474 * @see #setPressedIcon
475 */
476 public Icon getPressedIcon() {
477 return pressedIcon;
478 }
479
480 /**
481 * Sets the pressed icon for the button.
482 * @param pressedIcon the icon used as the "pressed" image
483 * @see #getPressedIcon
484 */
485 @BeanProperty(visualUpdate = true, description
486 = "The pressed icon for the button.")
487 public void setPressedIcon(Icon pressedIcon) {
488 Icon oldValue = this.pressedIcon;
489 this.pressedIcon = pressedIcon;
490 firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, oldValue, pressedIcon);
491 if (accessibleContext != null) {
492 accessibleContext.firePropertyChange(
493 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
494 oldValue, pressedIcon);
495 }
496 if (pressedIcon != oldValue) {
497 if (getModel().isPressed()) {
498 repaint();
499 }
500 }
501 }
502
503 /**
504 * Returns the selected icon for the button.
505 * @return the <code>selectedIcon</code> property
506 * @see #setSelectedIcon
507 */
508 public Icon getSelectedIcon() {
509 return selectedIcon;
510 }
511
512 /**
513 * Sets the selected icon for the button.
514 * @param selectedIcon the icon used as the "selected" image
515 * @see #getSelectedIcon
516 */
517 @BeanProperty(visualUpdate = true, description
518 = "The selected icon for the button.")
519 public void setSelectedIcon(Icon selectedIcon) {
520 Icon oldValue = this.selectedIcon;
521 this.selectedIcon = selectedIcon;
522
523 /* If the default selected icon has really changed and we had
524 * generated the disabled selected icon for this component,
525 * (i.e. setDisabledSelectedIcon() was never called) then
526 * clear the disabledSelectedIcon field.
527 */
528 if (selectedIcon != oldValue &&
529 disabledSelectedIcon instanceof UIResource) {
530
531 disabledSelectedIcon = null;
532 }
533
534 firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, oldValue, selectedIcon);
535 if (accessibleContext != null) {
536 accessibleContext.firePropertyChange(
537 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
538 oldValue, selectedIcon);
540 if (selectedIcon != oldValue) {
541 if (isSelected()) {
542 repaint();
543 }
544 }
545 }
546
547 /**
548 * Returns the rollover icon for the button.
549 * @return the <code>rolloverIcon</code> property
550 * @see #setRolloverIcon
551 */
552 public Icon getRolloverIcon() {
553 return rolloverIcon;
554 }
555
556 /**
557 * Sets the rollover icon for the button.
558 * @param rolloverIcon the icon used as the "rollover" image
559 * @see #getRolloverIcon
560 */
561 @BeanProperty(visualUpdate = true, description
562 = "The rollover icon for the button.")
563 public void setRolloverIcon(Icon rolloverIcon) {
564 Icon oldValue = this.rolloverIcon;
565 this.rolloverIcon = rolloverIcon;
566 firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, oldValue, rolloverIcon);
567 if (accessibleContext != null) {
568 accessibleContext.firePropertyChange(
569 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
570 oldValue, rolloverIcon);
571 }
572 setRolloverEnabled(true);
573 if (rolloverIcon != oldValue) {
574 // No way to determine whether we are currently in
575 // a rollover state, so repaint regardless
576 repaint();
577 }
578
579 }
580
581 /**
582 * Returns the rollover selection icon for the button.
583 * @return the <code>rolloverSelectedIcon</code> property
584 * @see #setRolloverSelectedIcon
585 */
586 public Icon getRolloverSelectedIcon() {
587 return rolloverSelectedIcon;
588 }
589
590 /**
591 * Sets the rollover selected icon for the button.
592 * @param rolloverSelectedIcon the icon used as the
593 * "selected rollover" image
594 * @see #getRolloverSelectedIcon
595 */
596 @BeanProperty(visualUpdate = true, description
597 = "The rollover selected icon for the button.")
598 public void setRolloverSelectedIcon(Icon rolloverSelectedIcon) {
599 Icon oldValue = this.rolloverSelectedIcon;
600 this.rolloverSelectedIcon = rolloverSelectedIcon;
601 firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, oldValue, rolloverSelectedIcon);
602 if (accessibleContext != null) {
603 accessibleContext.firePropertyChange(
604 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
605 oldValue, rolloverSelectedIcon);
606 }
607 setRolloverEnabled(true);
608 if (rolloverSelectedIcon != oldValue) {
609 // No way to determine whether we are currently in
610 // a rollover state, so repaint regardless
611 if (isSelected()) {
612 repaint();
613 }
614 }
615 }
616
617 /**
625 * @return the <code>disabledIcon</code> property
626 * @see #getPressedIcon
627 * @see #setDisabledIcon
628 * @see javax.swing.LookAndFeel#getDisabledIcon
629 */
630 @Transient
631 public Icon getDisabledIcon() {
632 if (disabledIcon == null) {
633 disabledIcon = UIManager.getLookAndFeel().getDisabledIcon(this, getIcon());
634 if (disabledIcon != null) {
635 firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, null, disabledIcon);
636 }
637 }
638 return disabledIcon;
639 }
640
641 /**
642 * Sets the disabled icon for the button.
643 * @param disabledIcon the icon used as the disabled image
644 * @see #getDisabledIcon
645 */
646 @BeanProperty(visualUpdate = true, description
647 = "The disabled icon for the button.")
648 public void setDisabledIcon(Icon disabledIcon) {
649 Icon oldValue = this.disabledIcon;
650 this.disabledIcon = disabledIcon;
651 firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, oldValue, disabledIcon);
652 if (accessibleContext != null) {
653 accessibleContext.firePropertyChange(
654 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
655 oldValue, disabledIcon);
656 }
657 if (disabledIcon != oldValue) {
658 if (!isEnabled()) {
659 repaint();
660 }
661 }
662 }
663
664 /**
665 * Returns the icon used by the button when it's disabled and selected.
666 * If no disabled selection icon has been set, this will forward
667 * the call to the LookAndFeel to construct an appropriate disabled
676 * @see #setDisabledSelectedIcon
677 * @see javax.swing.LookAndFeel#getDisabledSelectedIcon
678 */
679 public Icon getDisabledSelectedIcon() {
680 if (disabledSelectedIcon == null) {
681 if (selectedIcon != null) {
682 disabledSelectedIcon = UIManager.getLookAndFeel().
683 getDisabledSelectedIcon(this, getSelectedIcon());
684 } else {
685 return getDisabledIcon();
686 }
687 }
688 return disabledSelectedIcon;
689 }
690
691 /**
692 * Sets the disabled selection icon for the button.
693 * @param disabledSelectedIcon the icon used as the disabled
694 * selection image
695 * @see #getDisabledSelectedIcon
696 */
697 @BeanProperty(visualUpdate = true, description
698 = "The disabled selection icon for the button.")
699 public void setDisabledSelectedIcon(Icon disabledSelectedIcon) {
700 Icon oldValue = this.disabledSelectedIcon;
701 this.disabledSelectedIcon = disabledSelectedIcon;
702 firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, oldValue, disabledSelectedIcon);
703 if (accessibleContext != null) {
704 accessibleContext.firePropertyChange(
705 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
706 oldValue, disabledSelectedIcon);
707 }
708 if (disabledSelectedIcon != oldValue) {
709 if (disabledSelectedIcon == null || oldValue == null ||
710 disabledSelectedIcon.getIconWidth() != oldValue.getIconWidth() ||
711 disabledSelectedIcon.getIconHeight() != oldValue.getIconHeight()) {
712 revalidate();
713 }
714 if (!isEnabled() && isSelected()) {
715 repaint();
716 }
717 }
718 }
725 * <ul>
726 * <li>{@code SwingConstants.CENTER} (the default)
727 * <li>{@code SwingConstants.TOP}
728 * <li>{@code SwingConstants.BOTTOM}
729 * </ul>
730 */
731 public int getVerticalAlignment() {
732 return verticalAlignment;
733 }
734
735 /**
736 * Sets the vertical alignment of the icon and text.
737 * @param alignment one of the following values:
738 * <ul>
739 * <li>{@code SwingConstants.CENTER} (the default)
740 * <li>{@code SwingConstants.TOP}
741 * <li>{@code SwingConstants.BOTTOM}
742 * </ul>
743 * @throws IllegalArgumentException if the alignment is not one of the legal
744 * values listed above
745 */
746 @BeanProperty(visualUpdate = true, enumerationValues = {
747 "SwingConstants.TOP",
748 "SwingConstants.CENTER",
749 "SwingConstants.BOTTOM"}, description
750 = "The vertical alignment of the icon and text.")
751 public void setVerticalAlignment(int alignment) {
752 if (alignment == verticalAlignment) return;
753 int oldValue = verticalAlignment;
754 verticalAlignment = checkVerticalKey(alignment, "verticalAlignment");
755 firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, oldValue, verticalAlignment); repaint();
756 }
757
758 /**
759 * Returns the horizontal alignment of the icon and text.
760 * {@code AbstractButton}'s default is {@code SwingConstants.CENTER},
761 * but subclasses such as {@code JCheckBox} may use a different default.
762 *
763 * @return the <code>horizontalAlignment</code> property,
764 * one of the following values:
765 * <ul>
766 * <li>{@code SwingConstants.RIGHT}
767 * <li>{@code SwingConstants.LEFT}
768 * <li>{@code SwingConstants.CENTER}
769 * <li>{@code SwingConstants.LEADING}
770 * <li>{@code SwingConstants.TRAILING}
772 */
773 public int getHorizontalAlignment() {
774 return horizontalAlignment;
775 }
776
777 /**
778 * Sets the horizontal alignment of the icon and text.
779 * {@code AbstractButton}'s default is {@code SwingConstants.CENTER},
780 * but subclasses such as {@code JCheckBox} may use a different default.
781 *
782 * @param alignment the alignment value, one of the following values:
783 * <ul>
784 * <li>{@code SwingConstants.RIGHT}
785 * <li>{@code SwingConstants.LEFT}
786 * <li>{@code SwingConstants.CENTER}
787 * <li>{@code SwingConstants.LEADING}
788 * <li>{@code SwingConstants.TRAILING}
789 * </ul>
790 * @throws IllegalArgumentException if the alignment is not one of the
791 * valid values
792 */
793 @BeanProperty(visualUpdate = true, enumerationValues = {
794 "SwingConstants.LEFT",
795 "SwingConstants.CENTER",
796 "SwingConstants.RIGHT",
797 "SwingConstants.LEADING",
798 "SwingConstants.TRAILING"}, description
799 = "The horizontal alignment of the icon and text.")
800 public void setHorizontalAlignment(int alignment) {
801 if (alignment == horizontalAlignment) return;
802 int oldValue = horizontalAlignment;
803 horizontalAlignment = checkHorizontalKey(alignment,
804 "horizontalAlignment");
805 firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY,
806 oldValue, horizontalAlignment);
807 repaint();
808 }
809
810
811 /**
812 * Returns the vertical position of the text relative to the icon.
813 * @return the <code>verticalTextPosition</code> property,
814 * one of the following values:
815 * <ul>
816 * <li>{@code SwingConstants.CENTER} (the default)
817 * <li>{@code SwingConstants.TOP}
818 * <li>{@code SwingConstants.BOTTOM}
819 * </ul>
820 */
821 public int getVerticalTextPosition() {
822 return verticalTextPosition;
823 }
824
825 /**
826 * Sets the vertical position of the text relative to the icon.
827 * @param textPosition one of the following values:
828 * <ul>
829 * <li>{@code SwingConstants.CENTER} (the default)
830 * <li>{@code SwingConstants.TOP}
831 * <li>{@code SwingConstants.BOTTOM}
832 * </ul>
833 */
834 @BeanProperty(visualUpdate = true, enumerationValues = {
835 "SwingConstants.TOP",
836 "SwingConstants.CENTER",
837 "SwingConstants.BOTTOM"}, description
838 = "The vertical position of the text relative to the icon.")
839 public void setVerticalTextPosition(int textPosition) {
840 if (textPosition == verticalTextPosition) return;
841 int oldValue = verticalTextPosition;
842 verticalTextPosition = checkVerticalKey(textPosition, "verticalTextPosition");
843 firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, oldValue, verticalTextPosition);
844 revalidate();
845 repaint();
846 }
847
848 /**
849 * Returns the horizontal position of the text relative to the icon.
850 * @return the <code>horizontalTextPosition</code> property,
851 * one of the following values:
852 * <ul>
853 * <li>{@code SwingConstants.RIGHT}
854 * <li>{@code SwingConstants.LEFT}
855 * <li>{@code SwingConstants.CENTER}
856 * <li>{@code SwingConstants.LEADING}
857 * <li>{@code SwingConstants.TRAILING} (the default)
858 * </ul>
859 */
860 public int getHorizontalTextPosition() {
861 return horizontalTextPosition;
862 }
863
864 /**
865 * Sets the horizontal position of the text relative to the icon.
866 * @param textPosition one of the following values:
867 * <ul>
868 * <li>{@code SwingConstants.RIGHT}
869 * <li>{@code SwingConstants.LEFT}
870 * <li>{@code SwingConstants.CENTER}
871 * <li>{@code SwingConstants.LEADING}
872 * <li>{@code SwingConstants.TRAILING} (the default)
873 * </ul>
874 * @exception IllegalArgumentException if <code>textPosition</code>
875 * is not one of the legal values listed above
876 */
877 @BeanProperty(visualUpdate = true, enumerationValues = {
878 "SwingConstants.LEFT",
879 "SwingConstants.CENTER",
880 "SwingConstants.RIGHT",
881 "SwingConstants.LEADING",
882 "SwingConstants.TRAILING"}, description
883 = "The horizontal position of the text relative to the icon.")
884 public void setHorizontalTextPosition(int textPosition) {
885 if (textPosition == horizontalTextPosition) return;
886 int oldValue = horizontalTextPosition;
887 horizontalTextPosition = checkHorizontalKey(textPosition,
888 "horizontalTextPosition");
889 firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY,
890 oldValue,
891 horizontalTextPosition);
892 revalidate();
893 repaint();
894 }
895
896 /**
897 * Returns the amount of space between the text and the icon
898 * displayed in this button.
899 *
900 * @return an int equal to the number of pixels between the text
901 * and the icon.
902 * @since 1.4
903 * @see #setIconTextGap
904 */
905 public int getIconTextGap() {
906 return iconTextGap;
907 }
908
909 /**
910 * If both the icon and text properties are set, this property
911 * defines the space between them.
912 * <p>
913 * The default value of this property is 4 pixels.
914 * <p>
915 * This is a JavaBeans bound property.
916 *
917 * @param iconTextGap the space between icon and text if these properties are set.
918 * @since 1.4
919 * @see #getIconTextGap
920 */
921 @BeanProperty(visualUpdate = true, description
922 = "If both the icon and text properties are set, this property defines the space between them.")
923 public void setIconTextGap(int iconTextGap) {
924 int oldValue = this.iconTextGap;
925 this.iconTextGap = iconTextGap;
926 iconTextGapSet = true;
927 firePropertyChange("iconTextGap", oldValue, iconTextGap);
928 if (iconTextGap != oldValue) {
929 revalidate();
930 repaint();
931 }
932 }
933
934 /**
935 * Verify that the {@code key} argument is a legal value for the
936 * {@code horizontalAlignment} and {@code horizontalTextPosition}
937 * properties. Valid values are:
938 * <ul>
939 * <li>{@code SwingConstants.RIGHT}
940 * <li>{@code SwingConstants.LEFT}
941 * <li>{@code SwingConstants.CENTER}
942 * <li>{@code SwingConstants.LEADING}
1041 * <p>
1042 * This method uses three other methods to set
1043 * and help track the <code>Action</code>'s property values.
1044 * It uses the <code>configurePropertiesFromAction</code> method
1045 * to immediately change the button's properties.
1046 * To track changes in the <code>Action</code>'s property values,
1047 * this method registers the <code>PropertyChangeListener</code>
1048 * returned by <code>createActionPropertyChangeListener</code>. The
1049 * default {@code PropertyChangeListener} invokes the
1050 * {@code actionPropertyChanged} method when a property in the
1051 * {@code Action} changes.
1052 *
1053 * @param a the <code>Action</code> for the <code>AbstractButton</code>,
1054 * or <code>null</code>
1055 * @since 1.3
1056 * @see Action
1057 * @see #getAction
1058 * @see #configurePropertiesFromAction
1059 * @see #createActionPropertyChangeListener
1060 * @see #actionPropertyChanged
1061 */
1062 @BeanProperty(visualUpdate = true, description
1063 = "the Action instance connected with this ActionEvent source")
1064 public void setAction(Action a) {
1065 Action oldValue = getAction();
1066 if (action==null || !action.equals(a)) {
1067 action = a;
1068 if (oldValue!=null) {
1069 removeActionListener(oldValue);
1070 oldValue.removePropertyChangeListener(actionPropertyChangeListener);
1071 actionPropertyChangeListener = null;
1072 }
1073 configurePropertiesFromAction(action);
1074 if (action!=null) {
1075 // Don't add if it is already a listener
1076 if (!isListener(ActionListener.class, action)) {
1077 addActionListener(action);
1078 }
1079 // Reverse linkage:
1080 actionPropertyChangeListener = createActionPropertyChangeListener(action);
1081 action.addPropertyChangeListener(actionPropertyChangeListener);
1082 }
1083 firePropertyChange("action", oldValue, action);
1337 * @return the value of the <code>borderPainted</code> property
1338 * @see #setBorderPainted
1339 */
1340 public boolean isBorderPainted() {
1341 return paintBorder;
1342 }
1343
1344 /**
1345 * Sets the <code>borderPainted</code> property.
1346 * If <code>true</code> and the button has a border,
1347 * the border is painted. The default value for the
1348 * <code>borderPainted</code> property is <code>true</code>.
1349 * <p>
1350 * Some look and feels might not support
1351 * the <code>borderPainted</code> property,
1352 * in which case they ignore this.
1353 *
1354 * @param b if true and border property is not <code>null</code>,
1355 * the border is painted
1356 * @see #isBorderPainted
1357 */
1358 @BeanProperty(visualUpdate = true, description
1359 = "Whether the border should be painted.")
1360 public void setBorderPainted(boolean b) {
1361 boolean oldValue = paintBorder;
1362 paintBorder = b;
1363 borderPaintedSet = true;
1364 firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, oldValue, paintBorder);
1365 if (b != oldValue) {
1366 revalidate();
1367 repaint();
1368 }
1369 }
1370
1371 /**
1372 * Paint the button's border if <code>BorderPainted</code>
1373 * property is true and the button has a border.
1374 * @param g the <code>Graphics</code> context in which to paint
1375 *
1376 * @see #paint
1377 * @see #setBorder
1378 */
1379 protected void paintBorder(Graphics g) {
1385 /**
1386 * Gets the <code>paintFocus</code> property.
1387 *
1388 * @return the <code>paintFocus</code> property
1389 * @see #setFocusPainted
1390 */
1391 public boolean isFocusPainted() {
1392 return paintFocus;
1393 }
1394
1395 /**
1396 * Sets the <code>paintFocus</code> property, which must
1397 * be <code>true</code> for the focus state to be painted.
1398 * The default value for the <code>paintFocus</code> property
1399 * is <code>true</code>.
1400 * Some look and feels might not paint focus state;
1401 * they will ignore this property.
1402 *
1403 * @param b if <code>true</code>, the focus state should be painted
1404 * @see #isFocusPainted
1405 */
1406 @BeanProperty(visualUpdate = true, description
1407 = "Whether focus should be painted")
1408 public void setFocusPainted(boolean b) {
1409 boolean oldValue = paintFocus;
1410 paintFocus = b;
1411 firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, oldValue, paintFocus);
1412 if (b != oldValue && isFocusOwner()) {
1413 revalidate();
1414 repaint();
1415 }
1416 }
1417
1418 /**
1419 * Gets the <code>contentAreaFilled</code> property.
1420 *
1421 * @return the <code>contentAreaFilled</code> property
1422 * @see #setContentAreaFilled
1423 */
1424 public boolean isContentAreaFilled() {
1425 return contentAreaFilled;
1426 }
1427
1428 /**
1429 * Sets the <code>contentAreaFilled</code> property.
1430 * If <code>true</code> the button will paint the content
1431 * area. If you wish to have a transparent button, such as
1432 * an icon only button, for example, then you should set
1433 * this to <code>false</code>. Do not call <code>setOpaque(false)</code>.
1434 * The default value for the the <code>contentAreaFilled</code>
1435 * property is <code>true</code>.
1436 * <p>
1437 * This function may cause the component's opaque property to change.
1438 * <p>
1439 * The exact behavior of calling this function varies on a
1440 * component-by-component and L&F-by-L&F basis.
1441 *
1442 * @param b if true, the content should be filled; if false
1443 * the content area is not filled
1444 * @see #isContentAreaFilled
1445 * @see #setOpaque
1446 */
1447 @BeanProperty(visualUpdate = true, description
1448 = "Whether the button should paint the content area or leave it transparent.")
1449 public void setContentAreaFilled(boolean b) {
1450 boolean oldValue = contentAreaFilled;
1451 contentAreaFilled = b;
1452 contentAreaFilledSet = true;
1453 firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, oldValue, contentAreaFilled);
1454 if (b != oldValue) {
1455 repaint();
1456 }
1457 }
1458
1459 /**
1460 * Gets the <code>rolloverEnabled</code> property.
1461 *
1462 * @return the value of the <code>rolloverEnabled</code> property
1463 * @see #setRolloverEnabled
1464 */
1465 public boolean isRolloverEnabled() {
1466 return rolloverEnabled;
1467 }
1468
1469 /**
1470 * Sets the <code>rolloverEnabled</code> property, which
1471 * must be <code>true</code> for rollover effects to occur.
1472 * The default value for the <code>rolloverEnabled</code>
1473 * property is <code>false</code>.
1474 * Some look and feels might not implement rollover effects;
1475 * they will ignore this property.
1476 *
1477 * @param b if <code>true</code>, rollover effects should be painted
1478 * @see #isRolloverEnabled
1479 */
1480 @BeanProperty(visualUpdate = true, description
1481 = "Whether rollover effects should be enabled.")
1482 public void setRolloverEnabled(boolean b) {
1483 boolean oldValue = rolloverEnabled;
1484 rolloverEnabled = b;
1485 rolloverEnabledSet = true;
1486 firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, oldValue, rolloverEnabled);
1487 if (b != oldValue) {
1488 repaint();
1489 }
1490 }
1491
1492 /**
1493 * Returns the keyboard mnemonic from the the current model.
1494 * @return the keyboard mnemonic from the model
1495 */
1496 public int getMnemonic() {
1497 return mnemonic;
1498 }
1499
1500 /**
1501 * Sets the keyboard mnemonic on the current model.
1504 * if focus is contained somewhere within this button's ancestor
1505 * window.
1506 * <p>
1507 * A mnemonic must correspond to a single key on the keyboard
1508 * and should be specified using one of the <code>VK_XXX</code>
1509 * keycodes defined in <code>java.awt.event.KeyEvent</code>.
1510 * These codes and the wider array of codes for international
1511 * keyboards may be obtained through
1512 * <code>java.awt.event.KeyEvent.getExtendedKeyCodeForChar</code>.
1513 * Mnemonics are case-insensitive, therefore a key event
1514 * with the corresponding keycode would cause the button to be
1515 * activated whether or not the Shift modifier was pressed.
1516 * <p>
1517 * If the character defined by the mnemonic is found within
1518 * the button's label string, the first occurrence of it
1519 * will be underlined to indicate the mnemonic to the user.
1520 *
1521 * @param mnemonic the key code which represents the mnemonic
1522 * @see java.awt.event.KeyEvent
1523 * @see #setDisplayedMnemonicIndex
1524 */
1525 @BeanProperty(visualUpdate = true, description
1526 = "the keyboard character mnemonic")
1527 public void setMnemonic(int mnemonic) {
1528 int oldValue = getMnemonic();
1529 model.setMnemonic(mnemonic);
1530 updateMnemonicProperties();
1531 }
1532
1533 /**
1534 * This method is now obsolete, please use <code>setMnemonic(int)</code>
1535 * to set the mnemonic for a button. This method is only designed
1536 * to handle character values which fall between 'a' and 'z' or
1537 * 'A' and 'Z'.
1538 *
1539 * @param mnemonic a char specifying the mnemonic value
1540 * @see #setMnemonic(int)
1541 */
1542 @BeanProperty(visualUpdate = true, description
1543 = "the keyboard character mnemonic")
1544 public void setMnemonic(char mnemonic) {
1545 int vk = (int) mnemonic;
1546 if(vk >= 'a' && vk <='z')
1547 vk -= ('a' - 'A');
1548 setMnemonic(vk);
1549 }
1550
1551 /**
1552 * Provides a hint to the look and feel as to which character in the
1553 * text should be decorated to represent the mnemonic. Not all look and
1554 * feels may support this. A value of -1 indicates either there is no
1555 * mnemonic, the mnemonic character is not contained in the string, or
1556 * the developer does not wish the mnemonic to be displayed.
1557 * <p>
1558 * The value of this is updated as the properties relating to the
1559 * mnemonic change (such as the mnemonic itself, the text...).
1560 * You should only ever have to call this if
1561 * you do not wish the default character to be underlined. For example, if
1562 * the text was 'Save As', with a mnemonic of 'a', and you wanted the 'A'
1563 * to be decorated, as 'Save <u>A</u>s', you would have to invoke
1564 * <code>setDisplayedMnemonicIndex(5)</code> after invoking
1565 * <code>setMnemonic(KeyEvent.VK_A)</code>.
1566 *
1567 * @since 1.4
1568 * @param index Index into the String to underline
1569 * @exception IllegalArgumentException will be thrown if <code>index</code>
1570 * is >= length of the text, or < -1
1571 * @see #getDisplayedMnemonicIndex
1572 */
1573 @BeanProperty(visualUpdate = true, description
1574 = "the index into the String to draw the keyboard character mnemonic at")
1575 public void setDisplayedMnemonicIndex(int index)
1576 throws IllegalArgumentException {
1577 int oldValue = mnemonicIndex;
1578 if (index == -1) {
1579 mnemonicIndex = -1;
1580 } else {
1581 String text = getText();
1582 int textLength = (text == null) ? 0 : text.length();
1583 if (index < -1 || index >= textLength) { // index out of range
1584 throw new IllegalArgumentException("index == " + index);
1585 }
1586 }
1587 mnemonicIndex = index;
1588 firePropertyChange("displayedMnemonicIndex", oldValue, index);
1589 if (index != oldValue) {
1590 revalidate();
1591 repaint();
1592 }
1593 }
1594
1669 * to generate corresponding action events
1670 * @since 1.4
1671 */
1672 public long getMultiClickThreshhold() {
1673 return multiClickThreshhold;
1674 }
1675
1676 /**
1677 * Returns the model that this button represents.
1678 * @return the <code>model</code> property
1679 * @see #setModel
1680 */
1681 public ButtonModel getModel() {
1682 return model;
1683 }
1684
1685 /**
1686 * Sets the model that this button represents.
1687 * @param newModel the new <code>ButtonModel</code>
1688 * @see #getModel
1689 */
1690 @BeanProperty(description
1691 = "Model that the Button uses.")
1692 public void setModel(ButtonModel newModel) {
1693
1694 ButtonModel oldModel = getModel();
1695
1696 if (oldModel != null) {
1697 oldModel.removeChangeListener(changeListener);
1698 oldModel.removeActionListener(actionListener);
1699 oldModel.removeItemListener(itemListener);
1700 changeListener = null;
1701 actionListener = null;
1702 itemListener = null;
1703 }
1704
1705 model = newModel;
1706
1707 if (newModel != null) {
1708 changeListener = createChangeListener();
1709 actionListener = createActionListener();
1710 itemListener = createItemListener();
1711 newModel.addChangeListener(changeListener);
1729 revalidate();
1730 repaint();
1731 }
1732 }
1733
1734
1735 /**
1736 * Returns the L&F object that renders this component.
1737 * @return the ButtonUI object
1738 * @see #setUI
1739 */
1740 public ButtonUI getUI() {
1741 return (ButtonUI) ui;
1742 }
1743
1744
1745 /**
1746 * Sets the L&F object that renders this component.
1747 * @param ui the <code>ButtonUI</code> L&F object
1748 * @see #getUI
1749 */
1750 @BeanProperty(hidden = true, visualUpdate = true, description
1751 = "The UI object that implements the LookAndFeel.")
1752 public void setUI(ButtonUI ui) {
1753 super.setUI(ui);
1754 // disabled icons are generated by the LF so they should be unset here
1755 if (disabledIcon instanceof UIResource) {
1756 setDisabledIcon(null);
1757 }
1758 if (disabledSelectedIcon instanceof UIResource) {
1759 setDisabledSelectedIcon(null);
1760 }
1761 }
1762
1763
1764 /**
1765 * Resets the UI property to a value from the current look
1766 * and feel. Subtypes of <code>AbstractButton</code>
1767 * should override this to update the UI. For
1768 * example, <code>JButton</code> might do the following:
1769 * <pre>
1770 * setUI((ButtonUI)UIManager.getUI(
1771 * "ButtonUI", "javax.swing.plaf.basic.BasicButtonUI", this));
1819 public void addChangeListener(ChangeListener l) {
1820 listenerList.add(ChangeListener.class, l);
1821 }
1822
1823 /**
1824 * Removes a ChangeListener from the button.
1825 * @param l the listener to be removed
1826 */
1827 public void removeChangeListener(ChangeListener l) {
1828 listenerList.remove(ChangeListener.class, l);
1829 }
1830
1831 /**
1832 * Returns an array of all the <code>ChangeListener</code>s added
1833 * to this AbstractButton with addChangeListener().
1834 *
1835 * @return all of the <code>ChangeListener</code>s added or an empty
1836 * array if no listeners have been added
1837 * @since 1.4
1838 */
1839 @BeanProperty(bound = false)
1840 public ChangeListener[] getChangeListeners() {
1841 return listenerList.getListeners(ChangeListener.class);
1842 }
1843
1844 /**
1845 * Notifies all listeners that have registered interest for
1846 * notification on this event type. The event instance
1847 * is lazily created.
1848 * @see EventListenerList
1849 */
1850 protected void fireStateChanged() {
1851 // Guaranteed to return a non-null array
1852 Object[] listeners = listenerList.getListenerList();
1853 // Process the listeners last to first, notifying
1854 // those that are interested in this event
1855 for (int i = listeners.length-2; i>=0; i-=2) {
1856 if (listeners[i]==ChangeListener.class) {
1857 // Lazily create the event:
1858 if (changeEvent == null)
1859 changeEvent = new ChangeEvent(this);
1877 * is set to <code>null</code>.
1878 *
1879 * @param l the listener to be removed
1880 */
1881 public void removeActionListener(ActionListener l) {
1882 if ((l != null) && (getAction() == l)) {
1883 setAction(null);
1884 } else {
1885 listenerList.remove(ActionListener.class, l);
1886 }
1887 }
1888
1889 /**
1890 * Returns an array of all the <code>ActionListener</code>s added
1891 * to this AbstractButton with addActionListener().
1892 *
1893 * @return all of the <code>ActionListener</code>s added or an empty
1894 * array if no listeners have been added
1895 * @since 1.4
1896 */
1897 @BeanProperty(bound = false)
1898 public ActionListener[] getActionListeners() {
1899 return listenerList.getListeners(ActionListener.class);
1900 }
1901
1902 /**
1903 * Subclasses that want to handle <code>ChangeEvents</code> differently
1904 * can override this to return another <code>ChangeListener</code>
1905 * implementation.
1906 *
1907 * @return the new <code>ChangeListener</code>
1908 */
1909 protected ChangeListener createChangeListener() {
1910 return getHandler();
1911 }
1912
1913 /**
1914 * Extends <code>ChangeListener</code> to be serializable.
1915 * <p>
1916 * <strong>Warning:</strong>
1917 * Serialized objects of this class will not be compatible with
2046 }
2047
2048 // *** Deprecated java.awt.Button APIs below *** //
2049
2050 /**
2051 * Returns the label text.
2052 *
2053 * @return a <code>String</code> containing the label
2054 * @deprecated - Replaced by <code>getText</code>
2055 */
2056 @Deprecated
2057 public String getLabel() {
2058 return getText();
2059 }
2060
2061 /**
2062 * Sets the label text.
2063 *
2064 * @param label a <code>String</code> containing the text
2065 * @deprecated - Replaced by <code>setText(text)</code>
2066 */
2067 @Deprecated
2068 @BeanProperty(description
2069 = "Replace by setText(text)")
2070 public void setLabel(String label) {
2071 setText(label);
2072 }
2073
2074 /**
2075 * Adds an <code>ItemListener</code> to the <code>checkbox</code>.
2076 * @param l the <code>ItemListener</code> to be added
2077 */
2078 public void addItemListener(ItemListener l) {
2079 listenerList.add(ItemListener.class, l);
2080 }
2081
2082 /**
2083 * Removes an <code>ItemListener</code> from the button.
2084 * @param l the <code>ItemListener</code> to be removed
2085 */
2086 public void removeItemListener(ItemListener l) {
2087 listenerList.remove(ItemListener.class, l);
2088 }
2089
2090 /**
2091 * Returns an array of all the <code>ItemListener</code>s added
2092 * to this AbstractButton with addItemListener().
2093 *
2094 * @return all of the <code>ItemListener</code>s added or an empty
2095 * array if no listeners have been added
2096 * @since 1.4
2097 */
2098 @BeanProperty(bound = false)
2099 public ItemListener[] getItemListeners() {
2100 return listenerList.getListeners(ItemListener.class);
2101 }
2102
2103 /**
2104 * Returns an array (length 1) containing the label or
2105 * <code>null</code> if the button is not selected.
2106 *
2107 * @return an array containing 1 Object: the text of the button,
2108 * if the item is selected; otherwise <code>null</code>
2109 */
2110 @BeanProperty(bound = false)
2111 public Object[] getSelectedObjects() {
2112 if (isSelected() == false) {
2113 return null;
2114 }
2115 Object[] selectedObjects = new Object[1];
2116 selectedObjects[0] = getText();
2117 return selectedObjects;
2118 }
2119
2120 /**
2121 * Initialization of the {@code AbstractButton}.
2122 *
2123 * @param text the text of the button
2124 * @param icon the Icon image to display on the button
2125 */
2126 protected void init(String text, Icon icon) {
2127 if(text != null) {
2128 setText(text);
2129 }
2130
|