History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/AbstractButton.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/AbstractButton.java+3101−0
@@ -0,0 +1,3101 @@
1/*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package javax.swing;
26
27import java.awt.*;
28import java.awt.event.*;
29import java.awt.image.*;
30import java.text.*;
31import java.awt.geom.*;
32import java.beans.PropertyChangeEvent;
33import java.beans.PropertyChangeListener;
34import java.beans.Transient;
35import java.util.Enumeration;
36import java.util.Vector;
37import java.io.Serializable;
38import javax.swing.event.*;
39import javax.swing.border.*;
40import javax.swing.plaf.*;
41import javax.accessibility.*;
42import javax.swing.text.*;
43import javax.swing.text.html.*;
44import javax.swing.plaf.basic.*;
45import java.util.*;
46
47/**
48 * Defines common behaviors for buttons and menu items.
49 * <p>
50 * Buttons can be configured, and to some degree controlled, by
51 * <code><a href="Action.html">Action</a></code>s. Using an
52 * <code>Action</code> with a button has many benefits beyond directly
53 * configuring a button. Refer to <a href="Action.html#buttonActions">
54 * Swing Components Supporting <code>Action</code></a> for more
55 * details, and you can find more information in <a
56 * href="http://java.sun.com/docs/books/tutorial/uiswing/misc/action.html">How
57 * to Use Actions</a>, a section in <em>The Java Tutorial</em>.
58 * <p>
59 * For further information see
60 * <a
61 href="http://java.sun.com/docs/books/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons</a>,
62 * a section in <em>The Java Tutorial</em>.
63 * <p>
64 * <strong>Warning:</strong>
65 * Serialized objects of this class will not be compatible with
66 * future Swing releases. The current serialization support is
67 * appropriate for short term storage or RMI between applications running
68 * the same version of Swing. As of 1.4, support for long term storage
69 * of all JavaBeans<sup><font size="-2">TM</font></sup>
70 * has been added to the <code>java.beans</code> package.
71 * Please see {@link java.beans.XMLEncoder}.
72 *
73 * @author Jeff Dinkins
74 */
75public abstract class AbstractButton extends JComponent implements ItemSelectable, SwingConstants {
76
77 // *********************************
78 // ******* Button properties *******
79 // *********************************
80
81 /** Identifies a change in the button model. */
82 public static final String MODEL_CHANGED_PROPERTY = "model";
83 /** Identifies a change in the button's text. */
84 public static final String TEXT_CHANGED_PROPERTY = "text";
85 /** Identifies a change to the button's mnemonic. */
86 public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic";
87
88 // Text positioning and alignment
89 /** Identifies a change in the button's margins. */
90 public static final String MARGIN_CHANGED_PROPERTY = "margin";
91 /** Identifies a change in the button's vertical alignment. */
92 public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";
93 /** Identifies a change in the button's horizontal alignment. */
94 public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = "horizontalAlignment";
95
96 /** Identifies a change in the button's vertical text position. */
97 public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = "verticalTextPosition";
98 /** Identifies a change in the button's horizontal text position. */
99 public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = "horizontalTextPosition";
100
101 // Paint options
102 /**
103 * Identifies a change to having the border drawn,
104 * or having it not drawn.
105 */
106 public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";
107 /**
108 * Identifies a change to having the border highlighted when focused,
109 * or not.
110 */
111 public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
112 /**
113 * Identifies a change from rollover enabled to disabled or back
114 * to enabled.
115 */
116 public static final String ROLLOVER_ENABLED_CHANGED_PROPERTY = "rolloverEnabled";
117 /**
118 * Identifies a change to having the button paint the content area.
119 */
120 public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled";
121
122 // Icons
123 /** Identifies a change to the icon that represents the button. */
124 public static final String ICON_CHANGED_PROPERTY = "icon";
125
126 /**
127 * Identifies a change to the icon used when the button has been
128 * pressed.
129 */
130 public static final String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";
131 /**
132 * Identifies a change to the icon used when the button has
133 * been selected.
134 */
135 public static final String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";
136
137 /**
138 * Identifies a change to the icon used when the cursor is over
139 * the button.
140 */
141 public static final String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";
142 /**
143 * Identifies a change to the icon used when the cursor is
144 * over the button and it has been selected.
145 */
146 public static final String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = "rolloverSelectedIcon";
147
148 /**
149 * Identifies a change to the icon used when the button has
150 * been disabled.
151 */
152 public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";
153 /**
154 * Identifies a change to the icon used when the button has been
155 * disabled and selected.
156 */
157 public static final String DISABLED_SELECTED_ICON_CHANGED_PROPERTY = "disabledSelectedIcon";
158
159
160 /** The data model that determines the button's state. */
161 protected ButtonModel model = null;
162
163 private String text = ""; // for BeanBox
164 private Insets margin = null;
165 private Insets defaultMargin = null;
166
167 // Button icons
168 // PENDING(jeff) - hold icons in an array
169 private Icon defaultIcon = null;
170 private Icon pressedIcon = null;
171 private Icon disabledIcon = null;
172
173 private Icon selectedIcon = null;
174 private Icon disabledSelectedIcon = null;
175
176 private Icon rolloverIcon = null;
177 private Icon rolloverSelectedIcon = null;
178
179 // Display properties
180 private boolean paintBorder = true;
181 private boolean paintFocus = true;
182 private boolean rolloverEnabled = false;
183 private boolean contentAreaFilled = true;
184
185 // Icon/Label Alignment
186 private int verticalAlignment = CENTER;
187 private int horizontalAlignment = CENTER;
188
189 private int verticalTextPosition = CENTER;
190 private int horizontalTextPosition = TRAILING;
191
192 private int iconTextGap = 4;
193
194 private int mnemonic;
195 private int mnemonicIndex = -1;
196
197 private long multiClickThreshhold = 0;
198
199 private boolean borderPaintedSet = false;
200 private boolean rolloverEnabledSet = false;
201 private boolean iconTextGapSet = false;
202 private boolean contentAreaFilledSet = false;
203
204 // Whether or not we've set the LayoutManager.
205 private boolean setLayout = false;
206
207 // This is only used by JButton, promoted to avoid an extra
208 // boolean field in JButton
209 boolean defaultCapable = true;
210
211 /**
212 * Combined listeners: ActionListener, ChangeListener, ItemListener.
213 */
214 private Handler handler;
215
216 /**
217 * The button model's <code>changeListener</code>.
218 */
219 protected ChangeListener changeListener = null;
220 /**
221 * The button model's <code>ActionListener</code>.
222 */
223 protected ActionListener actionListener = null;
224 /**
225 * The button model's <code>ItemListener</code>.
226 */
227 protected ItemListener itemListener = null;
228
229 /**
230 * Only one <code>ChangeEvent</code> is needed per button
231 * instance since the
232 * event's only state is the source property. The source of events
233 * generated is always "this".
234 */
235 protected transient ChangeEvent changeEvent;
236
237 private boolean hideActionText = false;
238
239 /**
240 * Sets the <code>hideActionText</code> property, which determines
241 * whether the button displays text from the <code>Action</code>.
242 * This is useful only if an <code>Action</code> has been
243 * installed on the button.
244 *
245 * @param hideActionText <code>true</code> if the button's
246 * <code>text</code> property should not reflect
247 * that of the <code>Action</code>; the default is
248 * <code>false</code>
249 * @see <a href="Action.html#buttonActions">Swing Components Supporting
250 * <code>Action</code></a>
251 * @since 1.6
252 * @beaninfo
253 * bound: true
254 * expert: true
255 * description: Whether the text of the button should come from
256 * the <code>Action</code>.
257 */
258 public void setHideActionText(boolean hideActionText) {
259 if (hideActionText != this.hideActionText) {
260 this.hideActionText = hideActionText;
261 if (getAction() != null) {
262 setTextFromAction(getAction(), false);
263 }
264 firePropertyChange("hideActionText", !hideActionText,
265 hideActionText);
266 }
267 }
268
269 /**
270 * Returns the value of the <code>hideActionText</code> property, which
271 * determines whether the button displays text from the
272 * <code>Action</code>. This is useful only if an <code>Action</code>
273 * has been installed on the button.
274 *
275 * @return <code>true</code> if the button's <code>text</code>
276 * property should not reflect that of the
277 * <code>Action</code>; the default is <code>false</code>
278 * @since 1.6
279 */
280 public boolean getHideActionText() {
281 return hideActionText;
282 }
283
284 /**
285 * Returns the button's text.
286 * @return the buttons text
287 * @see #setText
288 */
289 public String getText() {
290 return text;
291 }
292
293 /**
294 * Sets the button's text.
295 * @param text the string used to set the text
296 * @see #getText
297 * @beaninfo
298 * bound: true
299 * preferred: true
300 * attribute: visualUpdate true
301 * description: The button's text.
302 */
303 public void setText(String text) {
304 String oldValue = this.text;
305 this.text = text;
306 firePropertyChange(TEXT_CHANGED_PROPERTY, oldValue, text);
307 updateDisplayedMnemonicIndex(text, getMnemonic());
308
309 if (accessibleContext != null) {
310 accessibleContext.firePropertyChange(
311 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
312 oldValue, text);
313 }
314 if (text == null || oldValue == null || !text.equals(oldValue)) {
315 revalidate();
316 repaint();
317 }
318 }
319
320
321 /**
322 * Returns the state of the button. True if the
323 * toggle button is selected, false if it's not.
324 * @return true if the toggle button is selected, otherwise false
325 */
326 public boolean isSelected() {
327 return model.isSelected();
328 }
329
330 /**
331 * Sets the state of the button. Note that this method does not
332 * trigger an <code>actionEvent</code>.
333 * Call <code>doClick</code> to perform a programatic action change.
334 *
335 * @param b true if the button is selected, otherwise false
336 */
337 public void setSelected(boolean b) {
338 boolean oldValue = isSelected();
339
340 // TIGER - 4840653
341 // Removed code which fired an AccessibleState.SELECTED
342 // PropertyChangeEvent since this resulted in two
343 // identical events being fired since
344 // AbstractButton.fireItemStateChanged also fires the
345 // same event. This caused screen readers to speak the
346 // name of the item twice.
347
348 model.setSelected(b);
349 }
350
351 /**
352 * Programmatically perform a "click". This does the same
353 * thing as if the user had pressed and released the button.
354 */
355 public void doClick() {
356 doClick(68);
357 }
358
359 /**
360 * Programmatically perform a "click". This does the same
361 * thing as if the user had pressed and released the button.
362 * The button stays visually "pressed" for <code>pressTime</code>
363 * milliseconds.
364 *
365 * @param pressTime the time to "hold down" the button, in milliseconds
366 */
367 public void doClick(int pressTime) {
368 Dimension size = getSize();
369 model.setArmed(true);
370 model.setPressed(true);
371 paintImmediately(new Rectangle(0,0, size.width, size.height));
372 try {
373 Thread.currentThread().sleep(pressTime);
374 } catch(InterruptedException ie) {
375 }
376 model.setPressed(false);
377 model.setArmed(false);
378 }
379
380 /**
381 * Sets space for margin between the button's border and
382 * the label. Setting to <code>null</code> will cause the button to
383 * use the default margin. The button's default <code>Border</code>
384 * object will use this value to create the proper margin.
385 * However, if a non-default border is set on the button,
386 * it is that <code>Border</code> object's responsibility to create the
387 * appropriate margin space (else this property will
388 * effectively be ignored).
389 *
390 * @param m the space between the border and the label
391 *
392 * @beaninfo
393 * bound: true
394 * attribute: visualUpdate true
395 * description: The space between the button's border and the label.
396 */
397 public void setMargin(Insets m) {
398 // Cache the old margin if it comes from the UI
399 if(m instanceof UIResource) {
400 defaultMargin = m;
401 } else if(margin instanceof UIResource) {
402 defaultMargin = margin;
403 }
404
405 // If the client passes in a null insets, restore the margin
406 // from the UI if possible
407 if(m == null && defaultMargin != null) {
408 m = defaultMargin;
409 }
410
411 Insets old = margin;
412 margin = m;
413 firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);
414 if (old == null || !old.equals(m)) {
415 revalidate();
416 repaint();
417 }
418 }
419
420 /**
421 * Returns the margin between the button's border and
422 * the label.
423 *
424 * @return an <code>Insets</code> object specifying the margin
425 * between the botton's border and the label
426 * @see #setMargin
427 */
428 public Insets getMargin() {
429 return (margin == null) ? null : (Insets) margin.clone();
430 }
431
432 /**
433 * Returns the default icon.
434 * @return the default <code>Icon</code>
435 * @see #setIcon
436 */
437 public Icon getIcon() {
438 return defaultIcon;
439 }
440
441 /**
442 * Sets the button's default icon. This icon is
443 * also used as the "pressed" and "disabled" icon if
444 * there is no explicitly set pressed icon.
445 *
446 * @param defaultIcon the icon used as the default image
447 * @see #getIcon
448 * @see #setPressedIcon
449 * @beaninfo
450 * bound: true
451 * attribute: visualUpdate true
452 * description: The button's default icon
453 */
454 public void setIcon(Icon defaultIcon) {
455 Icon oldValue = this.defaultIcon;
456 this.defaultIcon = defaultIcon;
457
458 /* If the default icon has really changed and we had
459 * generated the disabled icon for this component,
460 * (i.e. setDisabledIcon() was never called) then
461 * clear the disabledIcon field.
462 */
463 if (defaultIcon != oldValue && (disabledIcon instanceof UIResource)) {
464 disabledIcon = null;
465 }
466
467 firePropertyChange(ICON_CHANGED_PROPERTY, oldValue, defaultIcon);
468 if (accessibleContext != null) {
469 accessibleContext.firePropertyChange(
470 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
471 oldValue, defaultIcon);
472 }
473 if (defaultIcon != oldValue) {
474 if (defaultIcon == null || oldValue == null ||
475 defaultIcon.getIconWidth() != oldValue.getIconWidth() ||
476 defaultIcon.getIconHeight() != oldValue.getIconHeight()) {
477 revalidate();
478 }
479 repaint();
480 }
481 }
482
483 /**
484 * Returns the pressed icon for the button.
485 * @return the <code>pressedIcon</code> property
486 * @see #setPressedIcon
487 */
488 public Icon getPressedIcon() {
489 return pressedIcon;
490 }
491
492 /**
493 * Sets the pressed icon for the button.
494 * @param pressedIcon the icon used as the "pressed" image
495 * @see #getPressedIcon
496 * @beaninfo
497 * bound: true
498 * attribute: visualUpdate true
499 * description: The pressed icon for the button.
500 */
501 public void setPressedIcon(Icon pressedIcon) {
502 Icon oldValue = this.pressedIcon;
503 this.pressedIcon = pressedIcon;
504 firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, oldValue, pressedIcon);
505 if (accessibleContext != null) {
506 accessibleContext.firePropertyChange(
507 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
508 oldValue, pressedIcon);
509 }
510 if (pressedIcon != oldValue) {
511 if (getModel().isPressed()) {
512 repaint();
513 }
514 }
515 }
516
517 /**
518 * Returns the selected icon for the button.
519 * @return the <code>selectedIcon</code> property
520 * @see #setSelectedIcon
521 */
522 public Icon getSelectedIcon() {
523 return selectedIcon;
524 }
525
526 /**
527 * Sets the selected icon for the button.
528 * @param selectedIcon the icon used as the "selected" image
529 * @see #getSelectedIcon
530 * @beaninfo
531 * bound: true
532 * attribute: visualUpdate true
533 * description: The selected icon for the button.
534 */
535 public void setSelectedIcon(Icon selectedIcon) {
536 Icon oldValue = this.selectedIcon;
537 this.selectedIcon = selectedIcon;
538
539 /* If the default selected icon has really changed and we had
540 * generated the disabled selected icon for this component,
541 * (i.e. setDisabledSelectedIcon() was never called) then
542 * clear the disabledSelectedIcon field.
543 */
544 if (selectedIcon != oldValue &&
545 disabledSelectedIcon instanceof UIResource) {
546
547 disabledSelectedIcon = null;
548 }
549
550 firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, oldValue, selectedIcon);
551 if (accessibleContext != null) {
552 accessibleContext.firePropertyChange(
553 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
554 oldValue, selectedIcon);
555 }
556 if (selectedIcon != oldValue) {
557 if (isSelected()) {
558 repaint();
559 }
560 }
561 }
562
563 /**
564 * Returns the rollover icon for the button.
565 * @return the <code>rolloverIcon</code> property
566 * @see #setRolloverIcon
567 */
568 public Icon getRolloverIcon() {
569 return rolloverIcon;
570 }
571
572 /**
573 * Sets the rollover icon for the button.
574 * @param rolloverIcon the icon used as the "rollover" image
575 * @see #getRolloverIcon
576 * @beaninfo
577 * bound: true
578 * attribute: visualUpdate true
579 * description: The rollover icon for the button.
580 */
581 public void setRolloverIcon(Icon rolloverIcon) {
582 Icon oldValue = this.rolloverIcon;
583 this.rolloverIcon = rolloverIcon;
584 firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, oldValue, rolloverIcon);
585 if (accessibleContext != null) {
586 accessibleContext.firePropertyChange(
587 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
588 oldValue, rolloverIcon);
589 }
590 setRolloverEnabled(true);
591 if (rolloverIcon != oldValue) {
592 // No way to determine whether we are currently in
593 // a rollover state, so repaint regardless
594 repaint();
595 }
596
597 }
598
599 /**
600 * Returns the rollover selection icon for the button.
601 * @return the <code>rolloverSelectedIcon</code> property
602 * @see #setRolloverSelectedIcon
603 */
604 public Icon getRolloverSelectedIcon() {
605 return rolloverSelectedIcon;
606 }
607
608 /**
609 * Sets the rollover selected icon for the button.
610 * @param rolloverSelectedIcon the icon used as the
611 * "selected rollover" image
612 * @see #getRolloverSelectedIcon
613 * @beaninfo
614 * bound: true
615 * attribute: visualUpdate true
616 * description: The rollover selected icon for the button.
617 */
618 public void setRolloverSelectedIcon(Icon rolloverSelectedIcon) {
619 Icon oldValue = this.rolloverSelectedIcon;
620 this.rolloverSelectedIcon = rolloverSelectedIcon;
621 firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, oldValue, rolloverSelectedIcon);
622 if (accessibleContext != null) {
623 accessibleContext.firePropertyChange(
624 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
625 oldValue, rolloverSelectedIcon);
626 }
627 setRolloverEnabled(true);
628 if (rolloverSelectedIcon != oldValue) {
629 // No way to determine whether we are currently in
630 // a rollover state, so repaint regardless
631 if (isSelected()) {
632 repaint();
633 }
634 }
635 }
636
637 /**
638 * Returns the icon used by the button when it's disabled.
639 * If no disabled icon has been set this will forward the call to
640 * the look and feel to construct an appropriate disabled Icon.
641 * <p>
642 * Some look and feels might not render the disabled Icon, in which
643 * case they will ignore this.
644 *
645 * @return the <code>disabledIcon</code> property
646 * @see #getPressedIcon
647 * @see #setDisabledIcon
648 * @see javax.swing.LookAndFeel#getDisabledIcon
649 */
650 @Transient
651 public Icon getDisabledIcon() {
652 if (disabledIcon == null) {
653 disabledIcon = UIManager.getLookAndFeel().getDisabledIcon(this, getIcon());
654 if (disabledIcon != null) {
655 firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, null, disabledIcon);
656 }
657 }
658 return disabledIcon;
659 }
660
661 /**
662 * Sets the disabled icon for the button.
663 * @param disabledIcon the icon used as the disabled image
664 * @see #getDisabledIcon
665 * @beaninfo
666 * bound: true
667 * attribute: visualUpdate true
668 * description: The disabled icon for the button.
669 */
670 public void setDisabledIcon(Icon disabledIcon) {
671 Icon oldValue = this.disabledIcon;
672 this.disabledIcon = disabledIcon;
673 firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, oldValue, disabledIcon);
674 if (accessibleContext != null) {
675 accessibleContext.firePropertyChange(
676 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
677 oldValue, disabledIcon);
678 }
679 if (disabledIcon != oldValue) {
680 if (!isEnabled()) {
681 repaint();
682 }
683 }
684 }
685
686 /**
687 * Returns the icon used by the button when it's disabled and selected.
688 * If no disabled selection icon has been set, this will forward
689 * the call to the LookAndFeel to construct an appropriate disabled
690 * Icon from the selection icon if it has been set and to
691 * <code>getDisabledIcon()</code> otherwise.
692 * <p>
693 * Some look and feels might not render the disabled selected Icon, in
694 * which case they will ignore this.
695 *
696 * @return the <code>disabledSelectedIcon</code> property
697 * @see #getDisabledIcon
698 * @see #setDisabledSelectedIcon
699 * @see javax.swing.LookAndFeel#getDisabledSelectedIcon
700 */
701 public Icon getDisabledSelectedIcon() {
702 if (disabledSelectedIcon == null) {
703 if (selectedIcon != null) {
704 disabledSelectedIcon = UIManager.getLookAndFeel().
705 getDisabledSelectedIcon(this, getSelectedIcon());
706 } else {
707 return getDisabledIcon();
708 }
709 }
710 return disabledSelectedIcon;
711 }
712
713 /**
714 * Sets the disabled selection icon for the button.
715 * @param disabledSelectedIcon the icon used as the disabled
716 * selection image
717 * @see #getDisabledSelectedIcon
718 * @beaninfo
719 * bound: true
720 * attribute: visualUpdate true
721 * description: The disabled selection icon for the button.
722 */
723 public void setDisabledSelectedIcon(Icon disabledSelectedIcon) {
724 Icon oldValue = this.disabledSelectedIcon;
725 this.disabledSelectedIcon = disabledSelectedIcon;
726 firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, oldValue, disabledSelectedIcon);
727 if (accessibleContext != null) {
728 accessibleContext.firePropertyChange(
729 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
730 oldValue, disabledSelectedIcon);
731 }
732 if (disabledSelectedIcon != oldValue) {
733 if (disabledSelectedIcon == null || oldValue == null ||
734 disabledSelectedIcon.getIconWidth() != oldValue.getIconWidth() ||
735 disabledSelectedIcon.getIconHeight() != oldValue.getIconHeight()) {
736 revalidate();
737 }
738 if (!isEnabled() && isSelected()) {
739 repaint();
740 }
741 }
742 }
743
744 /**
745 * Returns the vertical alignment of the text and icon.
746 *
747 * @return the <code>verticalAlignment</code> property, one of the
748 * following values:
749 * <ul>
750 * <li>{@code SwingConstants.CENTER} (the default)
751 * <li>{@code SwingConstants.TOP}
752 * <li>{@code SwingConstants.BOTTOM}
753 * </ul>
754 */
755 public int getVerticalAlignment() {
756 return verticalAlignment;
757 }
758
759 /**
760 * Sets the vertical alignment of the icon and text.
761 * @param alignment one of the following values:
762 * <ul>
763 * <li>{@code SwingConstants.CENTER} (the default)
764 * <li>{@code SwingConstants.TOP}
765 * <li>{@code SwingConstants.BOTTOM}
766 * </ul>
767 * @throws IllegalArgumentException if the alignment is not one of the legal
768 * values listed above
769 * @beaninfo
770 * bound: true
771 * enum: TOP SwingConstants.TOP
772 * CENTER SwingConstants.CENTER
773 * BOTTOM SwingConstants.BOTTOM
774 * attribute: visualUpdate true
775 * description: The vertical alignment of the icon and text.
776 */
777 public void setVerticalAlignment(int alignment) {
778 if (alignment == verticalAlignment) return;
779 int oldValue = verticalAlignment;
780 verticalAlignment = checkVerticalKey(alignment, "verticalAlignment");
781 firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, oldValue, verticalAlignment); repaint();
782 }
783
784 /**
785 * Returns the horizontal alignment of the icon and text.
786 * {@code AbstractButton}'s default is {@code SwingConstants.CENTER},
787 * but subclasses such as {@code JCheckBox} may use a different default.
788 *
789 * @return the <code>horizontalAlignment</code> property,
790 * one of the following values:
791 * <ul>
792 * <li>{@code SwingConstants.RIGHT}
793 * <li>{@code SwingConstants.LEFT}
794 * <li>{@code SwingConstants.CENTER}
795 * <li>{@code SwingConstants.LEADING}
796 * <li>{@code SwingConstants.TRAILING}
797 * </ul>
798 */
799 public int getHorizontalAlignment() {
800 return horizontalAlignment;
801 }
802
803 /**
804 * Sets the horizontal alignment of the icon and text.
805 * {@code AbstractButton}'s default is {@code SwingConstants.CENTER},
806 * but subclasses such as {@code JCheckBox} may use a different default.
807 *
808 * @param alignment the alignment value, one of the following values:
809 * <ul>
810 * <li>{@code SwingConstants.RIGHT}
811 * <li>{@code SwingConstants.LEFT}
812 * <li>{@code SwingConstants.CENTER}
813 * <li>{@code SwingConstants.LEADING}
814 * <li>{@code SwingConstants.TRAILING}
815 * </ul>
816 * @throws IllegalArgumentException if the alignment is not one of the
817 * valid values
818 * @beaninfo
819 * bound: true
820 * enum: LEFT SwingConstants.LEFT
821 * CENTER SwingConstants.CENTER
822 * RIGHT SwingConstants.RIGHT
823 * LEADING SwingConstants.LEADING
824 * TRAILING SwingConstants.TRAILING
825 * attribute: visualUpdate true
826 * description: The horizontal alignment of the icon and text.
827 */
828 public void setHorizontalAlignment(int alignment) {
829 if (alignment == horizontalAlignment) return;
830 int oldValue = horizontalAlignment;
831 horizontalAlignment = checkHorizontalKey(alignment,
832 "horizontalAlignment");
833 firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY,
834 oldValue, horizontalAlignment);
835 repaint();
836 }
837
838
839 /**
840 * Returns the vertical position of the text relative to the icon.
841 * @return the <code>verticalTextPosition</code> property,
842 * one of the following values:
843 * <ul>
844 * <li>{@code SwingConstants.CENTER} (the default)
845 * <li>{@code SwingConstants.TOP}
846 * <li>{@code SwingConstants.BOTTOM}
847 * </ul>
848 */
849 public int getVerticalTextPosition() {
850 return verticalTextPosition;
851 }
852
853 /**
854 * Sets the vertical position of the text relative to the icon.
855 * @param textPosition one of the following values:
856 * <ul>
857 * <li>{@code SwingConstants.CENTER} (the default)
858 * <li>{@code SwingConstants.TOP}
859 * <li>{@code SwingConstants.BOTTOM}
860 * </ul>
861 * @beaninfo
862 * bound: true
863 * enum: TOP SwingConstants.TOP
864 * CENTER SwingConstants.CENTER
865 * BOTTOM SwingConstants.BOTTOM
866 * attribute: visualUpdate true
867 * description: The vertical position of the text relative to the icon.
868 */
869 public void setVerticalTextPosition(int textPosition) {
870 if (textPosition == verticalTextPosition) return;
871 int oldValue = verticalTextPosition;
872 verticalTextPosition = checkVerticalKey(textPosition, "verticalTextPosition");
873 firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, oldValue, verticalTextPosition);
874 revalidate();
875 repaint();
876 }
877
878 /**
879 * Returns the horizontal position of the text relative to the icon.
880 * @return the <code>horizontalTextPosition</code> property,
881 * one of the following values:
882 * <ul>
883 * <li>{@code SwingConstants.RIGHT}
884 * <li>{@code SwingConstants.LEFT}
885 * <li>{@code SwingConstants.CENTER}
886 * <li>{@code SwingConstants.LEADING}
887 * <li>{@code SwingConstants.TRAILING} (the default)
888 * </ul>
889 */
890 public int getHorizontalTextPosition() {
891 return horizontalTextPosition;
892 }
893
894 /**
895 * Sets the horizontal position of the text relative to the icon.
896 * @param textPosition one of the following values:
897 * <ul>
898 * <li>{@code SwingConstants.RIGHT}
899 * <li>{@code SwingConstants.LEFT}
900 * <li>{@code SwingConstants.CENTER}
901 * <li>{@code SwingConstants.LEADING}
902 * <li>{@code SwingConstants.TRAILING} (the default)
903 * </ul>
904 * @exception IllegalArgumentException if <code>textPosition</code>
905 * is not one of the legal values listed above
906 * @beaninfo
907 * bound: true
908 * enum: LEFT SwingConstants.LEFT
909 * CENTER SwingConstants.CENTER
910 * RIGHT SwingConstants.RIGHT
911 * LEADING SwingConstants.LEADING
912 * TRAILING SwingConstants.TRAILING
913 * attribute: visualUpdate true
914 * description: The horizontal position of the text relative to the icon.
915 */
916 public void setHorizontalTextPosition(int textPosition) {
917 if (textPosition == horizontalTextPosition) return;
918 int oldValue = horizontalTextPosition;
919 horizontalTextPosition = checkHorizontalKey(textPosition,
920 "horizontalTextPosition");
921 firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY,
922 oldValue,
923 horizontalTextPosition);
924 revalidate();
925 repaint();
926 }
927
928 /**
929 * Returns the amount of space between the text and the icon
930 * displayed in this button.
931 *
932 * @return an int equal to the number of pixels between the text
933 * and the icon.
934 * @since 1.4
935 * @see #setIconTextGap
936 */
937 public int getIconTextGap() {
938 return iconTextGap;
939 }
940
941 /**
942 * If both the icon and text properties are set, this property
943 * defines the space between them.
944 * <p>
945 * The default value of this property is 4 pixels.
946 * <p>
947 * This is a JavaBeans bound property.
948 *
949 * @since 1.4
950 * @see #getIconTextGap
951 * @beaninfo
952 * bound: true
953 * attribute: visualUpdate true
954 * description: If both the icon and text properties are set, this
955 * property defines the space between them.
956 */
957 public void setIconTextGap(int iconTextGap) {
958 int oldValue = this.iconTextGap;
959 this.iconTextGap = iconTextGap;
960 iconTextGapSet = true;
961 firePropertyChange("iconTextGap", oldValue, iconTextGap);
962 if (iconTextGap != oldValue) {
963 revalidate();
964 repaint();
965 }
966 }
967
968 /**
969 * Verify that the {@code key} argument is a legal value for the
970 * {@code horizontalAlignment} and {@code horizontalTextPosition}
971 * properties. Valid values are:
972 * <ul>
973 * <li>{@code SwingConstants.RIGHT}
974 * <li>{@code SwingConstants.LEFT}
975 * <li>{@code SwingConstants.CENTER}
976 * <li>{@code SwingConstants.LEADING}
977 * <li>{@code SwingConstants.TRAILING}
978 * </ul>
979 *
980 * @param key the property value to check
981 * @param exception the message to use in the
982 * {@code IllegalArgumentException} that is thrown for an invalid
983 * value
984 * @exception IllegalArgumentException if key is not one of the legal
985 * values listed above
986 * @see #setHorizontalTextPosition
987 * @see #setHorizontalAlignment
988 */
989 protected int checkHorizontalKey(int key, String exception) {
990 if ((key == LEFT) ||
991 (key == CENTER) ||
992 (key == RIGHT) ||
993 (key == LEADING) ||
994 (key == TRAILING)) {
995 return key;
996 } else {
997 throw new IllegalArgumentException(exception);
998 }
999 }
1000
1001 /**
1002 * Verify that the {@code key} argument is a legal value for the
1003 * vertical properties. Valid values are:
1004 * <ul>
1005 * <li>{@code SwingConstants.CENTER}
1006 * <li>{@code SwingConstants.TOP}
1007 * <li>{@code SwingConstants.BOTTOM}
1008 * </ul>
1009 *
1010 * @param key the property value to check
1011 * @param exception the message to use in the
1012 * {@code IllegalArgumentException} that is thrown for an invalid
1013 * value
1014 * @exception IllegalArgumentException if key is not one of the legal
1015 * values listed above
1016 */
1017 protected int checkVerticalKey(int key, String exception) {
1018 if ((key == TOP) || (key == CENTER) || (key == BOTTOM)) {
1019 return key;
1020 } else {
1021 throw new IllegalArgumentException(exception);
1022 }
1023 }
1024
1025 /**
1026 *{@inheritDoc}
1027 *
1028 * @since 1.6
1029 */
1030 public void removeNotify() {
1031 super.removeNotify();
1032 if(isRolloverEnabled()) {
1033 getModel().setRollover(false);
1034 }
1035 }
1036
1037 /**
1038 * Sets the action command for this button.
1039 * @param actionCommand the action command for this button
1040 */
1041 public void setActionCommand(String actionCommand) {
1042 getModel().setActionCommand(actionCommand);
1043 }
1044
1045 /**
1046 * Returns the action command for this button.
1047 * @return the action command for this button
1048 */
1049 public String getActionCommand() {
1050 String ac = getModel().getActionCommand();
1051 if(ac == null) {
1052 ac = getText();
1053 }
1054 return ac;
1055 }
1056
1057 private Action action;
1058 private PropertyChangeListener actionPropertyChangeListener;
1059
1060 /**
1061 * Sets the <code>Action</code>.
1062 * The new <code>Action</code> replaces any previously set
1063 * <code>Action</code> but does not affect <code>ActionListeners</code>
1064 * independently added with <code>addActionListener</code>.
1065 * If the <code>Action</code> is already a registered
1066 * <code>ActionListener</code> for the button, it is not re-registered.
1067 * <p>
1068 * Setting the <code>Action</code> results in immediately changing
1069 * all the properties described in <a href="Action.html#buttonActions">
1070 * Swing Components Supporting <code>Action</code></a>.
1071 * Subsequently, the button's properties are automatically updated
1072 * as the <code>Action</code>'s properties change.
1073 * <p>
1074 * This method uses three other methods to set
1075 * and help track the <code>Action</code>'s property values.
1076 * It uses the <code>configurePropertiesFromAction</code> method
1077 * to immediately change the button's properties.
1078 * To track changes in the <code>Action</code>'s property values,
1079 * this method registers the <code>PropertyChangeListener</code>
1080 * returned by <code>createActionPropertyChangeListener</code>. The
1081 * default {@code PropertyChangeListener} invokes the
1082 * {@code actionPropertyChanged} method when a property in the
1083 * {@code Action} changes.
1084 *
1085 * @param a the <code>Action</code> for the <code>AbstractButton</code>,
1086 * or <code>null</code>
1087 * @since 1.3
1088 * @see Action
1089 * @see #getAction
1090 * @see #configurePropertiesFromAction
1091 * @see #createActionPropertyChangeListener
1092 * @see #actionPropertyChanged
1093 * @beaninfo
1094 * bound: true
1095 * attribute: visualUpdate true
1096 * description: the Action instance connected with this ActionEvent source
1097 */
1098 public void setAction(Action a) {
1099 Action oldValue = getAction();
1100 if (action==null || !action.equals(a)) {
1101 action = a;
1102 if (oldValue!=null) {
1103 removeActionListener(oldValue);
1104 oldValue.removePropertyChangeListener(actionPropertyChangeListener);
1105 actionPropertyChangeListener = null;
1106 }
1107 configurePropertiesFromAction(action);
1108 if (action!=null) {
1109 // Don't add if it is already a listener
1110 if (!isListener(ActionListener.class, action)) {
1111 addActionListener(action);
1112 }
1113 // Reverse linkage:
1114 actionPropertyChangeListener = createActionPropertyChangeListener(action);
1115 action.addPropertyChangeListener(actionPropertyChangeListener);
1116 }
1117 firePropertyChange("action", oldValue, action);
1118 }
1119 }
1120
1121 private boolean isListener(Class c, ActionListener a) {
1122 boolean isListener = false;
1123 Object[] listeners = listenerList.getListenerList();
1124 for (int i = listeners.length-2; i>=0; i-=2) {
1125 if (listeners[i]==c && listeners[i+1]==a) {
1126 isListener=true;
1127 }
1128 }
1129 return isListener;
1130 }
1131
1132 /**
1133 * Returns the currently set <code>Action</code> for this
1134 * <code>ActionEvent</code> source, or <code>null</code>
1135 * if no <code>Action</code> is set.
1136 *
1137 * @return the <code>Action</code> for this <code>ActionEvent</code>
1138 * source, or <code>null</code>
1139 * @since 1.3
1140 * @see Action
1141 * @see #setAction
1142 */
1143 public Action getAction() {
1144 return action;
1145 }
1146
1147 /**
1148 * Sets the properties on this button to match those in the specified
1149 * <code>Action</code>. Refer to <a href="Action.html#buttonActions">
1150 * Swing Components Supporting <code>Action</code></a> for more
1151 * details as to which properties this sets.
1152 *
1153 * @param a the <code>Action</code> from which to get the properties,
1154 * or <code>null</code>
1155 * @since 1.3
1156 * @see Action
1157 * @see #setAction
1158 */
1159 protected void configurePropertiesFromAction(Action a) {
1160 setMnemonicFromAction(a);
1161 setTextFromAction(a, false);
1162 AbstractAction.setToolTipTextFromAction(this, a);
1163 setIconFromAction(a);
1164 setActionCommandFromAction(a);
1165 AbstractAction.setEnabledFromAction(this, a);
1166 if (AbstractAction.hasSelectedKey(a) &&
1167 shouldUpdateSelectedStateFromAction()) {
1168 setSelectedFromAction(a);
1169 }
1170 setDisplayedMnemonicIndexFromAction(a, false);
1171 }
1172
1173 void clientPropertyChanged(Object key, Object oldValue,
1174 Object newValue) {
1175 if (key == "hideActionText") {
1176 boolean current = (newValue instanceof Boolean) ?
1177 (Boolean)newValue : false;
1178 if (getHideActionText() != current) {
1179 setHideActionText(current);
1180 }
1181 }
1182 }
1183
1184 /**
1185 * Button subclasses that support mirroring the selected state from
1186 * the action should override this to return true. AbstractButton's
1187 * implementation returns false.
1188 */
1189 boolean shouldUpdateSelectedStateFromAction() {
1190 return false;
1191 }
1192
1193 /**
1194 * Updates the button's state in response to property changes in the
1195 * associated action. This method is invoked from the
1196 * {@code PropertyChangeListener} returned from
1197 * {@code createActionPropertyChangeListener}. Subclasses do not normally
1198 * need to invoke this. Subclasses that support additional {@code Action}
1199 * properties should override this and
1200 * {@code configurePropertiesFromAction}.
1201 * <p>
1202 * Refer to the table at <a href="Action.html#buttonActions">
1203 * Swing Components Supporting <code>Action</code></a> for a list of
1204 * the properties this method sets.
1205 *
1206 * @param action the <code>Action</code> associated with this button
1207 * @param propertyName the name of the property that changed
1208 * @since 1.6
1209 * @see Action
1210 * @see #configurePropertiesFromAction
1211 */
1212 protected void actionPropertyChanged(Action action, String propertyName) {
1213 if (propertyName == Action.NAME) {
1214 setTextFromAction(action, true);
1215 } else if (propertyName == "enabled") {
1216 AbstractAction.setEnabledFromAction(this, action);
1217 } else if (propertyName == Action.SHORT_DESCRIPTION) {
1218 AbstractAction.setToolTipTextFromAction(this, action);
1219 } else if (propertyName == Action.SMALL_ICON) {
1220 smallIconChanged(action);
1221 } else if (propertyName == Action.MNEMONIC_KEY) {
1222 setMnemonicFromAction(action);
1223 } else if (propertyName == Action.ACTION_COMMAND_KEY) {
1224 setActionCommandFromAction(action);
1225 } else if (propertyName == Action.SELECTED_KEY &&
1226 AbstractAction.hasSelectedKey(action) &&
1227 shouldUpdateSelectedStateFromAction()) {
1228 setSelectedFromAction(action);
1229 } else if (propertyName == Action.DISPLAYED_MNEMONIC_INDEX_KEY) {
1230 setDisplayedMnemonicIndexFromAction(action, true);
1231 } else if (propertyName == Action.LARGE_ICON_KEY) {
1232 largeIconChanged(action);
1233 }
1234 }
1235
1236 private void setDisplayedMnemonicIndexFromAction(
1237 Action a, boolean fromPropertyChange) {
1238 Integer iValue = (a == null) ? null :
1239 (Integer)a.getValue(Action.DISPLAYED_MNEMONIC_INDEX_KEY);
1240 if (fromPropertyChange || iValue != null) {
1241 int value;
1242 if (iValue == null) {
1243 value = -1;
1244 } else {
1245 value = iValue;
1246 String text = getText();
1247 if (text == null || value >= text.length()) {
1248 value = -1;
1249 }
1250 }
1251 setDisplayedMnemonicIndex(value);
1252 }
1253 }
1254
1255 private void setMnemonicFromAction(Action a) {
1256 Integer n = (a == null) ? null :
1257 (Integer)a.getValue(Action.MNEMONIC_KEY);
1258 setMnemonic((n == null) ? '\0' : n);
1259 }
1260
1261 private void setTextFromAction(Action a, boolean propertyChange) {
1262 boolean hideText = getHideActionText();
1263 if (!propertyChange) {
1264 setText((a != null && !hideText) ?
1265 (String)a.getValue(Action.NAME) : null);
1266 }
1267 else if (!hideText) {
1268 setText((String)a.getValue(Action.NAME));
1269 }
1270 }
1271
1272 void setIconFromAction(Action a) {
1273 Icon icon = null;
1274 if (a != null) {
1275 icon = (Icon)a.getValue(Action.LARGE_ICON_KEY);
1276 if (icon == null) {
1277 icon = (Icon)a.getValue(Action.SMALL_ICON);
1278 }
1279 }
1280 setIcon(icon);
1281 }
1282
1283 void smallIconChanged(Action a) {
1284 if (a.getValue(Action.LARGE_ICON_KEY) == null) {
1285 setIconFromAction(a);
1286 }
1287 }
1288
1289 void largeIconChanged(Action a) {
1290 setIconFromAction(a);
1291 }
1292
1293 private void setActionCommandFromAction(Action a) {
1294 setActionCommand((a != null) ?
1295 (String)a.getValue(Action.ACTION_COMMAND_KEY) :
1296 null);
1297 }
1298
1299 /**
1300 * Sets the seleted state of the button from the action. This is defined
1301 * here, but not wired up. Subclasses like JToggleButton and
1302 * JCheckBoxMenuItem make use of it.
1303 *
1304 * @param a the Action
1305 */
1306 private void setSelectedFromAction(Action a) {
1307 boolean selected = false;
1308 if (a != null) {
1309 selected = AbstractAction.isSelected(a);
1310 }
1311 if (selected != isSelected()) {
1312 // This won't notify ActionListeners, but that should be
1313 // ok as the change is coming from the Action.
1314 setSelected(selected);
1315 // Make sure the change actually took effect
1316 if (!selected && isSelected()) {
1317 if (getModel() instanceof DefaultButtonModel) {
1318 ButtonGroup group = ((DefaultButtonModel)getModel()).getGroup();
1319 if (group != null) {
1320 group.clearSelection();
1321 }
1322 }
1323 }
1324 }
1325 }
1326
1327 /**
1328 * Creates and returns a <code>PropertyChangeListener</code> that is
1329 * responsible for listening for changes from the specified
1330 * <code>Action</code> and updating the appropriate properties.
1331 * <p>
1332 * <b>Warning:</b> If you subclass this do not create an anonymous
1333 * inner class. If you do the lifetime of the button will be tied to
1334 * that of the <code>Action</code>.
1335 *
1336 * @param a the button's action
1337 * @since 1.3
1338 * @see Action
1339 * @see #setAction
1340 */
1341 protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
1342 return createActionPropertyChangeListener0(a);
1343 }
1344
1345
1346 PropertyChangeListener createActionPropertyChangeListener0(Action a) {
1347 return new ButtonActionPropertyChangeListener(this, a);
1348 }
1349
1350 private static class ButtonActionPropertyChangeListener
1351 extends ActionPropertyChangeListener<AbstractButton> {
1352 ButtonActionPropertyChangeListener(AbstractButton b, Action a) {
1353 super(b, a);
1354 }
1355 protected void actionPropertyChanged(AbstractButton button,
1356 Action action,
1357 PropertyChangeEvent e) {
1358 if (AbstractAction.shouldReconfigure(e)) {
1359 button.configurePropertiesFromAction(action);
1360 } else {
1361 button.actionPropertyChanged(action, e.getPropertyName());
1362 }
1363 }
1364 }
1365
1366 /**
1367 * Gets the <code>borderPainted</code> property.
1368 *
1369 * @return the value of the <code>borderPainted</code> property
1370 * @see #setBorderPainted
1371 */
1372 public boolean isBorderPainted() {
1373 return paintBorder;
1374 }
1375
1376 /**
1377 * Sets the <code>borderPainted</code> property.
1378 * If <code>true</code> and the button has a border,
1379 * the border is painted. The default value for the
1380 * <code>borderPainted</code> property is <code>true</code>.
1381 * <p/>
1382 * Some look and feels might not support
1383 * the <code>borderPainted</code> property,
1384 * in which case they ignore this.
1385 *
1386 * @param b if true and border property is not <code>null</code>,
1387 * the border is painted
1388 * @see #isBorderPainted
1389 * @beaninfo
1390 * bound: true
1391 * attribute: visualUpdate true
1392 * description: Whether the border should be painted.
1393 */
1394 public void setBorderPainted(boolean b) {
1395 boolean oldValue = paintBorder;
1396 paintBorder = b;
1397 borderPaintedSet = true;
1398 firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, oldValue, paintBorder);
1399 if (b != oldValue) {
1400 revalidate();
1401 repaint();
1402 }
1403 }
1404
1405 /**
1406 * Paint the button's border if <code>BorderPainted</code>
1407 * property is true and the button has a border.
1408 * @param g the <code>Graphics</code> context in which to paint
1409 *
1410 * @see #paint
1411 * @see #setBorder
1412 */
1413 protected void paintBorder(Graphics g) {
1414 if (isBorderPainted()) {
1415 super.paintBorder(g);
1416 }
1417 }
1418
1419 /**
1420 * Gets the <code>paintFocus</code> property.
1421 *
1422 * @return the <code>paintFocus</code> property
1423 * @see #setFocusPainted
1424 */
1425 public boolean isFocusPainted() {
1426 return paintFocus;
1427 }
1428
1429 /**
1430 * Sets the <code>paintFocus</code> property, which must
1431 * be <code>true</code> for the focus state to be painted.
1432 * The default value for the <code>paintFocus</code> property
1433 * is <code>true</code>.
1434 * Some look and feels might not paint focus state;
1435 * they will ignore this property.
1436 *
1437 * @param b if <code>true</code>, the focus state should be painted
1438 * @see #isFocusPainted
1439 * @beaninfo
1440 * bound: true
1441 * attribute: visualUpdate true
1442 * description: Whether focus should be painted
1443 */
1444 public void setFocusPainted(boolean b) {
1445 boolean oldValue = paintFocus;
1446 paintFocus = b;
1447 firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, oldValue, paintFocus);
1448 if (b != oldValue && isFocusOwner()) {
1449 revalidate();
1450 repaint();
1451 }
1452 }
1453
1454 /**
1455 * Gets the <code>contentAreaFilled</code> property.
1456 *
1457 * @return the <code>contentAreaFilled</code> property
1458 * @see #setContentAreaFilled
1459 */
1460 public boolean isContentAreaFilled() {
1461 return contentAreaFilled;
1462 }
1463
1464 /**
1465 * Sets the <code>contentAreaFilled</code> property.
1466 * If <code>true</code> the button will paint the content
1467 * area. If you wish to have a transparent button, such as
1468 * an icon only button, for example, then you should set
1469 * this to <code>false</code>. Do not call <code>setOpaque(false)</code>.
1470 * The default value for the the <code>contentAreaFilled</code>
1471 * property is <code>true</code>.
1472 * <p>
1473 * This function may cause the component's opaque property to change.
1474 * <p>
1475 * The exact behavior of calling this function varies on a
1476 * component-by-component and L&F-by-L&F basis.
1477 *
1478 * @param b if true, the content should be filled; if false
1479 * the content area is not filled
1480 * @see #isContentAreaFilled
1481 * @see #setOpaque
1482 * @beaninfo
1483 * bound: true
1484 * attribute: visualUpdate true
1485 * description: Whether the button should paint the content area
1486 * or leave it transparent.
1487 */
1488 public void setContentAreaFilled(boolean b) {
1489 boolean oldValue = contentAreaFilled;
1490 contentAreaFilled = b;
1491 contentAreaFilledSet = true;
1492 firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, oldValue, contentAreaFilled);
1493 if (b != oldValue) {
1494 repaint();
1495 }
1496 }
1497
1498 /**
1499 * Gets the <code>rolloverEnabled</code> property.
1500 *
1501 * @return the value of the <code>rolloverEnabled</code> property
1502 * @see #setRolloverEnabled
1503 */
1504 public boolean isRolloverEnabled() {
1505 return rolloverEnabled;
1506 }
1507
1508 /**
1509 * Sets the <code>rolloverEnabled</code> property, which
1510 * must be <code>true</code> for rollover effects to occur.
1511 * The default value for the <code>rolloverEnabled</code>
1512 * property is <code>false</code>.
1513 * Some look and feels might not implement rollover effects;
1514 * they will ignore this property.
1515 *
1516 * @param b if <code>true</code>, rollover effects should be painted
1517 * @see #isRolloverEnabled
1518 * @beaninfo
1519 * bound: true
1520 * attribute: visualUpdate true
1521 * description: Whether rollover effects should be enabled.
1522 */
1523 public void setRolloverEnabled(boolean b) {
1524 boolean oldValue = rolloverEnabled;
1525 rolloverEnabled = b;
1526 rolloverEnabledSet = true;
1527 firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, oldValue, rolloverEnabled);
1528 if (b != oldValue) {
1529 repaint();
1530 }
1531 }
1532
1533 /**
1534 * Returns the keyboard mnemonic from the the current model.
1535 * @return the keyboard mnemonic from the model
1536 */
1537 public int getMnemonic() {
1538 return mnemonic;
1539 }
1540
1541 /**
1542 * Sets the keyboard mnemonic on the current model.
1543 * The mnemonic is the key which when combined with the look and feel's
1544 * mouseless modifier (usually Alt) will activate this button
1545 * if focus is contained somewhere within this button's ancestor
1546 * window.
1547 * <p>
1548 * A mnemonic must correspond to a single key on the keyboard
1549 * and should be specified using one of the <code>VK_XXX</code>
1550 * keycodes defined in <code>java.awt.event.KeyEvent</code>.
1551 * These codes and the wider array of codes for international
1552 * keyboards may be obtained through
1553 * <code>java.awt.event.KeyEvent.getExtendedKeyCodeForChar</code>.
1554 * Mnemonics are case-insensitive, therefore a key event
1555 * with the corresponding keycode would cause the button to be
1556 * activated whether or not the Shift modifier was pressed.
1557 * <p>
1558 * If the character defined by the mnemonic is found within
1559 * the button's label string, the first occurrence of it
1560 * will be underlined to indicate the mnemonic to the user.
1561 *
1562 * @param mnemonic the key code which represents the mnemonic
1563 * @see java.awt.event.KeyEvent
1564 * @see #setDisplayedMnemonicIndex
1565 *
1566 * @beaninfo
1567 * bound: true
1568 * attribute: visualUpdate true
1569 * description: the keyboard character mnemonic
1570 */
1571 public void setMnemonic(int mnemonic) {
1572 int oldValue = getMnemonic();
1573 model.setMnemonic(mnemonic);
1574 updateMnemonicProperties();
1575 }
1576
1577 /**
1578 * This method is now obsolete, please use <code>setMnemonic(int)</code>
1579 * to set the mnemonic for a button. This method is only designed
1580 * to handle character values which fall between 'a' and 'z' or
1581 * 'A' and 'Z'.
1582 *
1583 * @param mnemonic a char specifying the mnemonic value
1584 * @see #setMnemonic(int)
1585 * @beaninfo
1586 * bound: true
1587 * attribute: visualUpdate true
1588 * description: the keyboard character mnemonic
1589 */
1590 public void setMnemonic(char mnemonic) {
1591 int vk = (int) mnemonic;
1592 if(vk >= 'a' && vk <='z')
1593 vk -= ('a' - 'A');
1594 setMnemonic(vk);
1595 }
1596
1597 /**
1598 * Provides a hint to the look and feel as to which character in the
1599 * text should be decorated to represent the mnemonic. Not all look and
1600 * feels may support this. A value of -1 indicates either there is no
1601 * mnemonic, the mnemonic character is not contained in the string, or
1602 * the developer does not wish the mnemonic to be displayed.
1603 * <p>
1604 * The value of this is updated as the properties relating to the
1605 * mnemonic change (such as the mnemonic itself, the text...).
1606 * You should only ever have to call this if
1607 * you do not wish the default character to be underlined. For example, if
1608 * the text was 'Save As', with a mnemonic of 'a', and you wanted the 'A'
1609 * to be decorated, as 'Save <u>A</u>s', you would have to invoke
1610 * <code>setDisplayedMnemonicIndex(5)</code> after invoking
1611 * <code>setMnemonic(KeyEvent.VK_A)</code>.
1612 *
1613 * @since 1.4
1614 * @param index Index into the String to underline
1615 * @exception IllegalArgumentException will be thrown if <code>index</code>
1616 * is &gt;= length of the text, or &lt; -1
1617 * @see #getDisplayedMnemonicIndex
1618 *
1619 * @beaninfo
1620 * bound: true
1621 * attribute: visualUpdate true
1622 * description: the index into the String to draw the keyboard character
1623 * mnemonic at
1624 */
1625 public void setDisplayedMnemonicIndex(int index)
1626 throws IllegalArgumentException {
1627 int oldValue = mnemonicIndex;
1628 if (index == -1) {
1629 mnemonicIndex = -1;
1630 } else {
1631 String text = getText();
1632 int textLength = (text == null) ? 0 : text.length();
1633 if (index < -1 || index >= textLength) { // index out of range
1634 throw new IllegalArgumentException("index == " + index);
1635 }
1636 }
1637 mnemonicIndex = index;
1638 firePropertyChange("displayedMnemonicIndex", oldValue, index);
1639 if (index != oldValue) {
1640 revalidate();
1641 repaint();
1642 }
1643 }
1644
1645 /**
1646 * Returns the character, as an index, that the look and feel should
1647 * provide decoration for as representing the mnemonic character.
1648 *
1649 * @since 1.4
1650 * @return index representing mnemonic character
1651 * @see #setDisplayedMnemonicIndex
1652 */
1653 public int getDisplayedMnemonicIndex() {
1654 return mnemonicIndex;
1655 }
1656
1657 /**
1658 * Update the displayedMnemonicIndex property. This method
1659 * is called when either text or mnemonic changes. The new
1660 * value of the displayedMnemonicIndex property is the index
1661 * of the first occurrence of mnemonic in text.
1662 */
1663 private void updateDisplayedMnemonicIndex(String text, int mnemonic) {
1664 setDisplayedMnemonicIndex(
1665 SwingUtilities.findDisplayedMnemonicIndex(text, mnemonic));
1666 }
1667
1668 /**
1669 * Brings the mnemonic property in accordance with model's mnemonic.
1670 * This is called when model's mnemonic changes. Also updates the
1671 * displayedMnemonicIndex property.
1672 */
1673 private void updateMnemonicProperties() {
1674 int newMnemonic = model.getMnemonic();
1675 if (mnemonic != newMnemonic) {
1676 int oldValue = mnemonic;
1677 mnemonic = newMnemonic;
1678 firePropertyChange(MNEMONIC_CHANGED_PROPERTY,
1679 oldValue, mnemonic);
1680 updateDisplayedMnemonicIndex(getText(), mnemonic);
1681 revalidate();
1682 repaint();
1683 }
1684 }
1685
1686 /**
1687 * Sets the amount of time (in milliseconds) required between
1688 * mouse press events for the button to generate the corresponding
1689 * action events. After the initial mouse press occurs (and action
1690 * event generated) any subsequent mouse press events which occur
1691 * on intervals less than the threshhold will be ignored and no
1692 * corresponding action event generated. By default the threshhold is 0,
1693 * which means that for each mouse press, an action event will be
1694 * fired, no matter how quickly the mouse clicks occur. In buttons
1695 * where this behavior is not desirable (for example, the "OK" button
1696 * in a dialog), this threshhold should be set to an appropriate
1697 * positive value.
1698 *
1699 * @see #getMultiClickThreshhold
1700 * @param threshhold the amount of time required between mouse
1701 * press events to generate corresponding action events
1702 * @exception IllegalArgumentException if threshhold < 0
1703 * @since 1.4
1704 */
1705 public void setMultiClickThreshhold(long threshhold) {
1706 if (threshhold < 0) {
1707 throw new IllegalArgumentException("threshhold must be >= 0");
1708 }
1709 this.multiClickThreshhold = threshhold;
1710 }
1711
1712 /**
1713 * Gets the amount of time (in milliseconds) required between
1714 * mouse press events for the button to generate the corresponding
1715 * action events.
1716 *
1717 * @see #setMultiClickThreshhold
1718 * @return the amount of time required between mouse press events
1719 * to generate corresponding action events
1720 * @since 1.4
1721 */
1722 public long getMultiClickThreshhold() {
1723 return multiClickThreshhold;
1724 }
1725
1726 /**
1727 * Returns the model that this button represents.
1728 * @return the <code>model</code> property
1729 * @see #setModel
1730 */
1731 public ButtonModel getModel() {
1732 return model;
1733 }
1734
1735 /**
1736 * Sets the model that this button represents.
1737 * @param newModel the new <code>ButtonModel</code>
1738 * @see #getModel
1739 * @beaninfo
1740 * bound: true
1741 * description: Model that the Button uses.
1742 */
1743 public void setModel(ButtonModel newModel) {
1744
1745 ButtonModel oldModel = getModel();
1746
1747 if (oldModel != null) {
1748 oldModel.removeChangeListener(changeListener);
1749 oldModel.removeActionListener(actionListener);
1750 oldModel.removeItemListener(itemListener);
1751 changeListener = null;
1752 actionListener = null;
1753 itemListener = null;
1754 }
1755
1756 model = newModel;
1757
1758 if (newModel != null) {
1759 changeListener = createChangeListener();
1760 actionListener = createActionListener();
1761 itemListener = createItemListener();
1762 newModel.addChangeListener(changeListener);
1763 newModel.addActionListener(actionListener);
1764 newModel.addItemListener(itemListener);
1765
1766 updateMnemonicProperties();
1767 //We invoke setEnabled() from JComponent
1768 //because setModel() can be called from a constructor
1769 //when the button is not fully initialized
1770 super.setEnabled(newModel.isEnabled());
1771
1772 } else {
1773 mnemonic = '\0';
1774 }
1775
1776 updateDisplayedMnemonicIndex(getText(), mnemonic);
1777
1778 firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel);
1779 if (newModel != oldModel) {
1780 revalidate();
1781 repaint();
1782 }
1783 }
1784
1785
1786 /**
1787 * Returns the L&F object that renders this component.
1788 * @return the ButtonUI object
1789 * @see #setUI
1790 */
1791 public ButtonUI getUI() {
1792 return (ButtonUI) ui;
1793 }
1794
1795
1796 /**
1797 * Sets the L&F object that renders this component.
1798 * @param ui the <code>ButtonUI</code> L&F object
1799 * @see #getUI
1800 * @beaninfo
1801 * bound: true
1802 * hidden: true
1803 * attribute: visualUpdate true
1804 * description: The UI object that implements the LookAndFeel.
1805 */
1806 public void setUI(ButtonUI ui) {
1807 super.setUI(ui);
1808 // disabled icons are generated by the LF so they should be unset here
1809 if (disabledIcon instanceof UIResource) {
1810 setDisabledIcon(null);
1811 }
1812 if (disabledSelectedIcon instanceof UIResource) {
1813 setDisabledSelectedIcon(null);
1814 }
1815 }
1816
1817
1818 /**
1819 * Resets the UI property to a value from the current look
1820 * and feel. Subtypes of <code>AbstractButton</code>
1821 * should override this to update the UI. For
1822 * example, <code>JButton</code> might do the following:
1823 * <pre>
1824 * setUI((ButtonUI)UIManager.getUI(
1825 * "ButtonUI", "javax.swing.plaf.basic.BasicButtonUI", this));
1826 * </pre>
1827 */
1828 public void updateUI() {
1829 }
1830
1831 /**
1832 * Adds the specified component to this container at the specified
1833 * index, refer to
1834 * {@link java.awt.Container#addImpl(Component, Object, int)}
1835 * for a complete description of this method.
1836 *
1837 * @param comp the component to be added
1838 * @param constraints an object expressing layout constraints
1839 * for this component
1840 * @param index the position in the container's list at which to
1841 * insert the component, where <code>-1</code>
1842 * means append to the end
1843 * @exception IllegalArgumentException if <code>index</code> is invalid
1844 * @exception IllegalArgumentException if adding the container's parent
1845 * to itself
1846 * @exception IllegalArgumentException if adding a window to a container
1847 * @since 1.5
1848 */
1849 protected void addImpl(Component comp, Object constraints, int index) {
1850 if (!setLayout) {
1851 setLayout(new OverlayLayout(this));
1852 }
1853 super.addImpl(comp, constraints, index);
1854 }
1855
1856 /**
1857 * Sets the layout manager for this container, refer to
1858 * {@link java.awt.Container#setLayout(LayoutManager)}
1859 * for a complete description of this method.
1860 *
1861 * @param mgr the specified layout manager
1862 * @since 1.5
1863 */
1864 public void setLayout(LayoutManager mgr) {
1865 setLayout = true;
1866 super.setLayout(mgr);
1867 }
1868
1869 /**
1870 * Adds a <code>ChangeListener</code> to the button.
1871 * @param l the listener to be added
1872 */
1873 public void addChangeListener(ChangeListener l) {
1874 listenerList.add(ChangeListener.class, l);
1875 }
1876
1877 /**
1878 * Removes a ChangeListener from the button.
1879 * @param l the listener to be removed
1880 */
1881 public void removeChangeListener(ChangeListener l) {
1882 listenerList.remove(ChangeListener.class, l);
1883 }
1884
1885 /**
1886 * Returns an array of all the <code>ChangeListener</code>s added
1887 * to this AbstractButton with addChangeListener().
1888 *
1889 * @return all of the <code>ChangeListener</code>s added or an empty
1890 * array if no listeners have been added
1891 * @since 1.4
1892 */
1893 public ChangeListener[] getChangeListeners() {
1894 return listenerList.getListeners(ChangeListener.class);
1895 }
1896
1897 /**
1898 * Notifies all listeners that have registered interest for
1899 * notification on this event type. The event instance
1900 * is lazily created.
1901 * @see EventListenerList
1902 */
1903 protected void fireStateChanged() {
1904 // Guaranteed to return a non-null array
1905 Object[] listeners = listenerList.getListenerList();
1906 // Process the listeners last to first, notifying
1907 // those that are interested in this event
1908 for (int i = listeners.length-2; i>=0; i-=2) {
1909 if (listeners[i]==ChangeListener.class) {
1910 // Lazily create the event:
1911 if (changeEvent == null)
1912 changeEvent = new ChangeEvent(this);
1913 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
1914 }
1915 }
1916 }
1917
1918 /**
1919 * Adds an <code>ActionListener</code> to the button.
1920 * @param l the <code>ActionListener</code> to be added
1921 */
1922 public void addActionListener(ActionListener l) {
1923 listenerList.add(ActionListener.class, l);
1924 }
1925
1926 /**
1927 * Removes an <code>ActionListener</code> from the button.
1928 * If the listener is the currently set <code>Action</code>
1929 * for the button, then the <code>Action</code>
1930 * is set to <code>null</code>.
1931 *
1932 * @param l the listener to be removed
1933 */
1934 public void removeActionListener(ActionListener l) {
1935 if ((l != null) && (getAction() == l)) {
1936 setAction(null);
1937 } else {
1938 listenerList.remove(ActionListener.class, l);
1939 }
1940 }
1941
1942 /**
1943 * Returns an array of all the <code>ActionListener</code>s added
1944 * to this AbstractButton with addActionListener().
1945 *
1946 * @return all of the <code>ActionListener</code>s added or an empty
1947 * array if no listeners have been added
1948 * @since 1.4
1949 */
1950 public ActionListener[] getActionListeners() {
1951 return listenerList.getListeners(ActionListener.class);
1952 }
1953
1954 /**
1955 * Subclasses that want to handle <code>ChangeEvents</code> differently
1956 * can override this to return another <code>ChangeListener</code>
1957 * implementation.
1958 *
1959 * @return the new <code>ChangeListener</code>
1960 */
1961 protected ChangeListener createChangeListener() {
1962 return getHandler();
1963 }
1964
1965 /**
1966 * Extends <code>ChangeListener</code> to be serializable.
1967 * <p>
1968 * <strong>Warning:</strong>
1969 * Serialized objects of this class will not be compatible with
1970 * future Swing releases. The current serialization support is
1971 * appropriate for short term storage or RMI between applications running
1972 * the same version of Swing. As of 1.4, support for long term storage
1973 * of all JavaBeans<sup><font size="-2">TM</font></sup>
1974 * has been added to the <code>java.beans</code> package.
1975 * Please see {@link java.beans.XMLEncoder}.
1976 */
1977 protected class ButtonChangeListener implements ChangeListener, Serializable {
1978 // NOTE: This class is NOT used, instead the functionality has
1979 // been moved to Handler.
1980 ButtonChangeListener() {
1981 }
1982
1983 public void stateChanged(ChangeEvent e) {
1984 getHandler().stateChanged(e);
1985 }
1986 }
1987
1988
1989 /**
1990 * Notifies all listeners that have registered interest for
1991 * notification on this event type. The event instance
1992 * is lazily created using the <code>event</code>
1993 * parameter.
1994 *
1995 * @param event the <code>ActionEvent</code> object
1996 * @see EventListenerList
1997 */
1998 protected void fireActionPerformed(ActionEvent event) {
1999 // Guaranteed to return a non-null array
2000 Object[] listeners = listenerList.getListenerList();
2001 ActionEvent e = null;
2002 // Process the listeners last to first, notifying
2003 // those that are interested in this event
2004 for (int i = listeners.length-2; i>=0; i-=2) {
2005 if (listeners[i]==ActionListener.class) {
2006 // Lazily create the event:
2007 if (e == null) {
2008 String actionCommand = event.getActionCommand();
2009 if(actionCommand == null) {
2010 actionCommand = getActionCommand();
2011 }
2012 e = new ActionEvent(AbstractButton.this,
2013 ActionEvent.ACTION_PERFORMED,
2014 actionCommand,
2015 event.getWhen(),
2016 event.getModifiers());
2017 }
2018 ((ActionListener)listeners[i+1]).actionPerformed(e);
2019 }
2020 }
2021 }
2022
2023 /**
2024 * Notifies all listeners that have registered interest for
2025 * notification on this event type. The event instance
2026 * is lazily created using the <code>event</code> parameter.
2027 *
2028 * @param event the <code>ItemEvent</code> object
2029 * @see EventListenerList
2030 */
2031 protected void fireItemStateChanged(ItemEvent event) {
2032 // Guaranteed to return a non-null array
2033 Object[] listeners = listenerList.getListenerList();
2034 ItemEvent e = null;
2035 // Process the listeners last to first, notifying
2036 // those that are interested in this event
2037 for (int i = listeners.length-2; i>=0; i-=2) {
2038 if (listeners[i]==ItemListener.class) {
2039 // Lazily create the event:
2040 if (e == null) {
2041 e = new ItemEvent(AbstractButton.this,
2042 ItemEvent.ITEM_STATE_CHANGED,
2043 AbstractButton.this,
2044 event.getStateChange());
2045 }
2046 ((ItemListener)listeners[i+1]).itemStateChanged(e);
2047 }
2048 }
2049 if (accessibleContext != null) {
2050 if (event.getStateChange() == ItemEvent.SELECTED) {
2051 accessibleContext.firePropertyChange(
2052 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
2053 null, AccessibleState.SELECTED);
2054 accessibleContext.firePropertyChange(
2055 AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
2056 Integer.valueOf(0), Integer.valueOf(1));
2057 } else {
2058 accessibleContext.firePropertyChange(
2059 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
2060 AccessibleState.SELECTED, null);
2061 accessibleContext.firePropertyChange(
2062 AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
2063 Integer.valueOf(1), Integer.valueOf(0));
2064 }
2065 }
2066 }
2067
2068
2069 protected ActionListener createActionListener() {
2070 return getHandler();
2071 }
2072
2073
2074 protected ItemListener createItemListener() {
2075 return getHandler();
2076 }
2077
2078
2079 /**
2080 * Enables (or disables) the button.
2081 * @param b true to enable the button, otherwise false
2082 */
2083 public void setEnabled(boolean b) {
2084 if (!b && model.isRollover()) {
2085 model.setRollover(false);
2086 }
2087 super.setEnabled(b);
2088 model.setEnabled(b);
2089 }
2090
2091 // *** Deprecated java.awt.Button APIs below *** //
2092
2093 /**
2094 * Returns the label text.
2095 *
2096 * @return a <code>String</code> containing the label
2097 * @deprecated - Replaced by <code>getText</code>
2098 */
2099 @Deprecated
2100 public String getLabel() {
2101 return getText();
2102 }
2103
2104 /**
2105 * Sets the label text.
2106 *
2107 * @param label a <code>String</code> containing the text
2108 * @deprecated - Replaced by <code>setText(text)</code>
2109 * @beaninfo
2110 * bound: true
2111 * description: Replace by setText(text)
2112 */
2113 @Deprecated
2114 public void setLabel(String label) {
2115 setText(label);
2116 }
2117
2118 /**
2119 * Adds an <code>ItemListener</code> to the <code>checkbox</code>.
2120 * @param l the <code>ItemListener</code> to be added
2121 */
2122 public void addItemListener(ItemListener l) {
2123 listenerList.add(ItemListener.class, l);
2124 }
2125
2126 /**
2127 * Removes an <code>ItemListener</code> from the button.
2128 * @param l the <code>ItemListener</code> to be removed
2129 */
2130 public void removeItemListener(ItemListener l) {
2131 listenerList.remove(ItemListener.class, l);
2132 }
2133
2134 /**
2135 * Returns an array of all the <code>ItemListener</code>s added
2136 * to this AbstractButton with addItemListener().
2137 *
2138 * @return all of the <code>ItemListener</code>s added or an empty
2139 * array if no listeners have been added
2140 * @since 1.4
2141 */
2142 public ItemListener[] getItemListeners() {
2143 return listenerList.getListeners(ItemListener.class);
2144 }
2145
2146 /**
2147 * Returns an array (length 1) containing the label or
2148 * <code>null</code> if the button is not selected.
2149 *
2150 * @return an array containing 1 Object: the text of the button,
2151 * if the item is selected; otherwise <code>null</code>
2152 */
2153 public Object[] getSelectedObjects() {
2154 if (isSelected() == false) {
2155 return null;
2156 }
2157 Object[] selectedObjects = new Object[1];
2158 selectedObjects[0] = getText();
2159 return selectedObjects;
2160 }
2161
2162 protected void init(String text, Icon icon) {
2163 if(text != null) {
2164 setText(text);
2165 }
2166
2167 if(icon != null) {
2168 setIcon(icon);
2169 }
2170
2171 // Set the UI
2172 updateUI();
2173
2174 setAlignmentX(LEFT_ALIGNMENT);
2175 setAlignmentY(CENTER_ALIGNMENT);
2176 }
2177
2178
2179 /**
2180 * This is overridden to return false if the current <code>Icon</code>'s
2181 * <code>Image</code> is not equal to the
2182 * passed in <code>Image</code> <code>img</code>.
2183 *
2184 * @param img the <code>Image</code> to be compared
2185 * @param infoflags flags used to repaint the button when the image
2186 * is updated and which determine how much is to be painted
2187 * @param x the x coordinate
2188 * @param y the y coordinate
2189 * @param w the width
2190 * @param h the height
2191 * @see java.awt.image.ImageObserver
2192 * @see java.awt.Component#imageUpdate(java.awt.Image, int, int, int, int, int)
2193 */
2194 public boolean imageUpdate(Image img, int infoflags,
2195 int x, int y, int w, int h) {
2196 Icon iconDisplayed = getIcon();
2197 if (iconDisplayed == null) {
2198 return false;
2199 }
2200
2201 if (!model.isEnabled()) {
2202 if (model.isSelected()) {
2203 iconDisplayed = getDisabledSelectedIcon();
2204 } else {
2205 iconDisplayed = getDisabledIcon();
2206 }
2207 } else if (model.isPressed() && model.isArmed()) {
2208 iconDisplayed = getPressedIcon();
2209 } else if (isRolloverEnabled() && model.isRollover()) {
2210 if (model.isSelected()) {
2211 iconDisplayed = getRolloverSelectedIcon();
2212 } else {
2213 iconDisplayed = getRolloverIcon();
2214 }
2215 } else if (model.isSelected()) {
2216 iconDisplayed = getSelectedIcon();
2217 }
2218
2219 if (!SwingUtilities.doesIconReferenceImage(iconDisplayed, img)) {
2220 // We don't know about this image, disable the notification so
2221 // we don't keep repainting.
2222 return false;
2223 }
2224 return super.imageUpdate(img, infoflags, x, y, w, h);
2225 }
2226
2227 void setUIProperty(String propertyName, Object value) {
2228 if (propertyName == "borderPainted") {
2229 if (!borderPaintedSet) {
2230 setBorderPainted(((Boolean)value).booleanValue());
2231 borderPaintedSet = false;
2232 }
2233 } else if (propertyName == "rolloverEnabled") {
2234 if (!rolloverEnabledSet) {
2235 setRolloverEnabled(((Boolean)value).booleanValue());
2236 rolloverEnabledSet = false;
2237 }
2238 } else if (propertyName == "iconTextGap") {
2239 if (!iconTextGapSet) {
2240 setIconTextGap(((Number)value).intValue());
2241 iconTextGapSet = false;
2242 }
2243 } else if (propertyName == "contentAreaFilled") {
2244 if (!contentAreaFilledSet) {
2245 setContentAreaFilled(((Boolean)value).booleanValue());
2246 contentAreaFilledSet = false;
2247 }
2248 } else {
2249 super.setUIProperty(propertyName, value);
2250 }
2251 }
2252
2253 /**
2254 * Returns a string representation of this <code>AbstractButton</code>.
2255 * This method
2256 * is intended to be used only for debugging purposes, and the
2257 * content and format of the returned string may vary between
2258 * implementations. The returned string may be empty but may not
2259 * be <code>null</code>.
2260 * <P>
2261 * Overriding <code>paramString</code> to provide information about the
2262 * specific new aspects of the JFC components.
2263 *
2264 * @return a string representation of this <code>AbstractButton</code>
2265 */
2266 protected String paramString() {
2267 String defaultIconString = ((defaultIcon != null)
2268 && (defaultIcon != this) ?
2269 defaultIcon.toString() : "");
2270 String pressedIconString = ((pressedIcon != null)
2271 && (pressedIcon != this) ?
2272 pressedIcon.toString() : "");
2273 String disabledIconString = ((disabledIcon != null)
2274 && (disabledIcon != this) ?
2275 disabledIcon.toString() : "");
2276 String selectedIconString = ((selectedIcon != null)
2277 && (selectedIcon != this) ?
2278 selectedIcon.toString() : "");
2279 String disabledSelectedIconString = ((disabledSelectedIcon != null) &&
2280 (disabledSelectedIcon != this) ?
2281 disabledSelectedIcon.toString()
2282 : "");
2283 String rolloverIconString = ((rolloverIcon != null)
2284 && (rolloverIcon != this) ?
2285 rolloverIcon.toString() : "");
2286 String rolloverSelectedIconString = ((rolloverSelectedIcon != null) &&
2287 (rolloverSelectedIcon != this) ?
2288 rolloverSelectedIcon.toString()
2289 : "");
2290 String paintBorderString = (paintBorder ? "true" : "false");
2291 String paintFocusString = (paintFocus ? "true" : "false");
2292 String rolloverEnabledString = (rolloverEnabled ? "true" : "false");
2293
2294 return super.paramString() +
2295 ",defaultIcon=" + defaultIconString +
2296 ",disabledIcon=" + disabledIconString +
2297 ",disabledSelectedIcon=" + disabledSelectedIconString +
2298 ",margin=" + margin +
2299 ",paintBorder=" + paintBorderString +
2300 ",paintFocus=" + paintFocusString +
2301 ",pressedIcon=" + pressedIconString +
2302 ",rolloverEnabled=" + rolloverEnabledString +
2303 ",rolloverIcon=" + rolloverIconString +
2304 ",rolloverSelectedIcon=" + rolloverSelectedIconString +
2305 ",selectedIcon=" + selectedIconString +
2306 ",text=" + text;
2307 }
2308
2309
2310 private Handler getHandler() {
2311 if (handler == null) {
2312 handler = new Handler();
2313 }
2314 return handler;
2315 }
2316
2317
2318 //
2319 // Listeners that are added to model
2320 //
2321 class Handler implements ActionListener, ChangeListener, ItemListener,
2322 Serializable {
2323 //
2324 // ChangeListener
2325 //
2326 public void stateChanged(ChangeEvent e) {
2327 Object source = e.getSource();
2328
2329 updateMnemonicProperties();
2330 if (isEnabled() != model.isEnabled()) {
2331 setEnabled(model.isEnabled());
2332 }
2333 fireStateChanged();
2334 repaint();
2335 }
2336
2337 //
2338 // ActionListener
2339 //
2340 public void actionPerformed(ActionEvent event) {
2341 fireActionPerformed(event);
2342 }
2343
2344 //
2345 // ItemListener
2346 //
2347 public void itemStateChanged(ItemEvent event) {
2348 fireItemStateChanged(event);
2349 if (shouldUpdateSelectedStateFromAction()) {
2350 Action action = getAction();
2351 if (action != null && AbstractAction.hasSelectedKey(action)) {
2352 boolean selected = isSelected();
2353 boolean isActionSelected = AbstractAction.isSelected(
2354 action);
2355 if (isActionSelected != selected) {
2356 action.putValue(Action.SELECTED_KEY, selected);
2357 }
2358 }
2359 }
2360 }
2361 }
2362
2363///////////////////
2364// Accessibility support
2365///////////////////
2366 /**
2367 * This class implements accessibility support for the
2368 * <code>AbstractButton</code> class. It provides an implementation of the
2369 * Java Accessibility API appropriate to button and menu item
2370 * user-interface elements.
2371 * <p>
2372 * <strong>Warning:</strong>
2373 * Serialized objects of this class will not be compatible with
2374 * future Swing releases. The current serialization support is
2375 * appropriate for short term storage or RMI between applications running
2376 * the same version of Swing. As of 1.4, support for long term storage
2377 * of all JavaBeans<sup><font size="-2">TM</font></sup>
2378 * has been added to the <code>java.beans</code> package.
2379 * Please see {@link java.beans.XMLEncoder}.
2380 * @since 1.4
2381 */
2382 protected abstract class AccessibleAbstractButton
2383 extends AccessibleJComponent implements AccessibleAction,
2384 AccessibleValue, AccessibleText, AccessibleExtendedComponent {
2385
2386 /**
2387 * Returns the accessible name of this object.
2388 *
2389 * @return the localized name of the object -- can be
2390 * <code>null</code> if this
2391 * object does not have a name
2392 */
2393 public String getAccessibleName() {
2394 String name = accessibleName;
2395
2396 if (name == null) {
2397 name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
2398 }
2399 if (name == null) {
2400 name = AbstractButton.this.getText();
2401 }
2402 if (name == null) {
2403 name = super.getAccessibleName();
2404 }
2405 return name;
2406 }
2407
2408 /**
2409 * Get the AccessibleIcons associated with this object if one
2410 * or more exist. Otherwise return null.
2411 * @since 1.3
2412 */
2413 public AccessibleIcon [] getAccessibleIcon() {
2414 Icon defaultIcon = getIcon();
2415
2416 if (defaultIcon instanceof Accessible) {
2417 AccessibleContext ac =
2418 ((Accessible)defaultIcon).getAccessibleContext();
2419 if (ac != null && ac instanceof AccessibleIcon) {
2420 return new AccessibleIcon[] { (AccessibleIcon)ac };
2421 }
2422 }
2423 return null;
2424 }
2425
2426 /**
2427 * Get the state set of this object.
2428 *
2429 * @return an instance of AccessibleState containing the current state
2430 * of the object
2431 * @see AccessibleState
2432 */
2433 public AccessibleStateSet getAccessibleStateSet() {
2434 AccessibleStateSet states = super.getAccessibleStateSet();
2435 if (getModel().isArmed()) {
2436 states.add(AccessibleState.ARMED);
2437 }
2438 if (isFocusOwner()) {
2439 states.add(AccessibleState.FOCUSED);
2440 }
2441 if (getModel().isPressed()) {
2442 states.add(AccessibleState.PRESSED);
2443 }
2444 if (isSelected()) {
2445 states.add(AccessibleState.CHECKED);
2446 }
2447 return states;
2448 }
2449
2450 /**
2451 * Get the AccessibleRelationSet associated with this object if one
2452 * exists. Otherwise return null.
2453 * @see AccessibleRelation
2454 * @since 1.3
2455 */
2456 public AccessibleRelationSet getAccessibleRelationSet() {
2457
2458 // Check where the AccessibleContext's relation
2459 // set already contains a MEMBER_OF relation.
2460 AccessibleRelationSet relationSet
2461 = super.getAccessibleRelationSet();
2462
2463 if (!relationSet.contains(AccessibleRelation.MEMBER_OF)) {
2464 // get the members of the button group if one exists
2465 ButtonModel model = getModel();
2466 if (model != null && model instanceof DefaultButtonModel) {
2467 ButtonGroup group = ((DefaultButtonModel)model).getGroup();
2468 if (group != null) {
2469 // set the target of the MEMBER_OF relation to be
2470 // the members of the button group.
2471 int len = group.getButtonCount();
2472 Object [] target = new Object[len];
2473 Enumeration elem = group.getElements();
2474 for (int i = 0; i < len; i++) {
2475 if (elem.hasMoreElements()) {
2476 target[i] = elem.nextElement();
2477 }
2478 }
2479 AccessibleRelation relation =
2480 new AccessibleRelation(AccessibleRelation.MEMBER_OF);
2481 relation.setTarget(target);
2482 relationSet.add(relation);
2483 }
2484 }
2485 }
2486 return relationSet;
2487 }
2488
2489 /**
2490 * Get the AccessibleAction associated with this object. In the
2491 * implementation of the Java Accessibility API for this class,
2492 * return this object, which is responsible for implementing the
2493 * AccessibleAction interface on behalf of itself.
2494 *
2495 * @return this object
2496 */
2497 public AccessibleAction getAccessibleAction() {
2498 return this;
2499 }
2500
2501 /**
2502 * Get the AccessibleValue associated with this object. In the
2503 * implementation of the Java Accessibility API for this class,
2504 * return this object, which is responsible for implementing the
2505 * AccessibleValue interface on behalf of itself.
2506 *
2507 * @return this object
2508 */
2509 public AccessibleValue getAccessibleValue() {
2510 return this;
2511 }
2512
2513 /**
2514 * Returns the number of Actions available in this object. The
2515 * default behavior of a button is to have one action - toggle
2516 * the button.
2517 *
2518 * @return 1, the number of Actions in this object
2519 */
2520 public int getAccessibleActionCount() {
2521 return 1;
2522 }
2523
2524 /**
2525 * Return a description of the specified action of the object.
2526 *
2527 * @param i zero-based index of the actions
2528 */
2529 public String getAccessibleActionDescription(int i) {
2530 if (i == 0) {
2531 return UIManager.getString("AbstractButton.clickText");
2532 } else {
2533 return null;
2534 }
2535 }
2536
2537 /**
2538 * Perform the specified Action on the object
2539 *
2540 * @param i zero-based index of actions
2541 * @return true if the the action was performed; else false.
2542 */
2543 public boolean doAccessibleAction(int i) {
2544 if (i == 0) {
2545 doClick();
2546 return true;
2547 } else {
2548 return false;
2549 }
2550 }
2551
2552 /**
2553 * Get the value of this object as a Number.
2554 *
2555 * @return An Integer of 0 if this isn't selected or an Integer of 1 if
2556 * this is selected.
2557 * @see AbstractButton#isSelected
2558 */
2559 public Number getCurrentAccessibleValue() {
2560 if (isSelected()) {
2561 return Integer.valueOf(1);
2562 } else {
2563 return Integer.valueOf(0);
2564 }
2565 }
2566
2567 /**
2568 * Set the value of this object as a Number.
2569 *
2570 * @return True if the value was set.
2571 */
2572 public boolean setCurrentAccessibleValue(Number n) {
2573 // TIGER - 4422535
2574 if (n == null) {
2575 return false;
2576 }
2577 int i = n.intValue();
2578 if (i == 0) {
2579 setSelected(false);
2580 } else {
2581 setSelected(true);
2582 }
2583 return true;
2584 }
2585
2586 /**
2587 * Get the minimum value of this object as a Number.
2588 *
2589 * @return an Integer of 0.
2590 */
2591 public Number getMinimumAccessibleValue() {
2592 return Integer.valueOf(0);
2593 }
2594
2595 /**
2596 * Get the maximum value of this object as a Number.
2597 *
2598 * @return An Integer of 1.
2599 */
2600 public Number getMaximumAccessibleValue() {
2601 return Integer.valueOf(1);
2602 }
2603
2604
2605 /* AccessibleText ---------- */
2606
2607 public AccessibleText getAccessibleText() {
2608 View view = (View)AbstractButton.this.getClientProperty("html");
2609 if (view != null) {
2610 return this;
2611 } else {
2612 return null;
2613 }
2614 }
2615
2616 /**
2617 * Given a point in local coordinates, return the zero-based index
2618 * of the character under that Point. If the point is invalid,
2619 * this method returns -1.
2620 *
2621 * Note: the AbstractButton must have a valid size (e.g. have
2622 * been added to a parent container whose ancestor container
2623 * is a valid top-level window) for this method to be able
2624 * to return a meaningful value.
2625 *
2626 * @param p the Point in local coordinates
2627 * @return the zero-based index of the character under Point p; if
2628 * Point is invalid returns -1.
2629 * @since 1.3
2630 */
2631 public int getIndexAtPoint(Point p) {
2632 View view = (View) AbstractButton.this.getClientProperty("html");
2633 if (view != null) {
2634 Rectangle r = getTextRectangle();
2635 if (r == null) {
2636 return -1;
2637 }
2638 Rectangle2D.Float shape =
2639 new Rectangle2D.Float(r.x, r.y, r.width, r.height);
2640 Position.Bias bias[] = new Position.Bias[1];
2641 return view.viewToModel(p.x, p.y, shape, bias);
2642 } else {
2643 return -1;
2644 }
2645 }
2646
2647 /**
2648 * Determine the bounding box of the character at the given
2649 * index into the string. The bounds are returned in local
2650 * coordinates. If the index is invalid an empty rectangle is
2651 * returned.
2652 *
2653 * Note: the AbstractButton must have a valid size (e.g. have
2654 * been added to a parent container whose ancestor container
2655 * is a valid top-level window) for this method to be able
2656 * to return a meaningful value.
2657 *
2658 * @param i the index into the String
2659 * @return the screen coordinates of the character's the bounding box,
2660 * if index is invalid returns an empty rectangle.
2661 * @since 1.3
2662 */
2663 public Rectangle getCharacterBounds(int i) {
2664 View view = (View) AbstractButton.this.getClientProperty("html");
2665 if (view != null) {
2666 Rectangle r = getTextRectangle();
2667 if (r == null) {
2668 return null;
2669 }
2670 Rectangle2D.Float shape =
2671 new Rectangle2D.Float(r.x, r.y, r.width, r.height);
2672 try {
2673 Shape charShape =
2674 view.modelToView(i, shape, Position.Bias.Forward);
2675 return charShape.getBounds();
2676 } catch (BadLocationException e) {
2677 return null;
2678 }
2679 } else {
2680 return null;
2681 }
2682 }
2683
2684 /**
2685 * Return the number of characters (valid indicies)
2686 *
2687 * @return the number of characters
2688 * @since 1.3
2689 */
2690 public int getCharCount() {
2691 View view = (View) AbstractButton.this.getClientProperty("html");
2692 if (view != null) {
2693 Document d = view.getDocument();
2694 if (d instanceof StyledDocument) {
2695 StyledDocument doc = (StyledDocument)d;
2696 return doc.getLength();
2697 }
2698 }
2699 return accessibleContext.getAccessibleName().length();
2700 }
2701
2702 /**
2703 * Return the zero-based offset of the caret.
2704 *
2705 * Note: That to the right of the caret will have the same index
2706 * value as the offset (the caret is between two characters).
2707 * @return the zero-based offset of the caret.
2708 * @since 1.3
2709 */
2710 public int getCaretPosition() {
2711 // There is no caret.
2712 return -1;
2713 }
2714
2715 /**
2716 * Returns the String at a given index.
2717 *
2718 * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
2719 * or AccessibleText.SENTENCE to retrieve
2720 * @param index an index within the text >= 0
2721 * @return the letter, word, or sentence,
2722 * null for an invalid index or part
2723 * @since 1.3
2724 */
2725 public String getAtIndex(int part, int index) {
2726 if (index < 0 || index >= getCharCount()) {
2727 return null;
2728 }
2729 switch (part) {
2730 case AccessibleText.CHARACTER:
2731 try {
2732 return getText(index, 1);
2733 } catch (BadLocationException e) {
2734 return null;
2735 }
2736 case AccessibleText.WORD:
2737 try {
2738 String s = getText(0, getCharCount());
2739 BreakIterator words = BreakIterator.getWordInstance(getLocale());
2740 words.setText(s);
2741 int end = words.following(index);
2742 return s.substring(words.previous(), end);
2743 } catch (BadLocationException e) {
2744 return null;
2745 }
2746 case AccessibleText.SENTENCE:
2747 try {
2748 String s = getText(0, getCharCount());
2749 BreakIterator sentence =
2750 BreakIterator.getSentenceInstance(getLocale());
2751 sentence.setText(s);
2752 int end = sentence.following(index);
2753 return s.substring(sentence.previous(), end);
2754 } catch (BadLocationException e) {
2755 return null;
2756 }
2757 default:
2758 return null;
2759 }
2760 }
2761
2762 /**
2763 * Returns the String after a given index.
2764 *
2765 * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
2766 * or AccessibleText.SENTENCE to retrieve
2767 * @param index an index within the text >= 0
2768 * @return the letter, word, or sentence, null for an invalid
2769 * index or part
2770 * @since 1.3
2771 */
2772 public String getAfterIndex(int part, int index) {
2773 if (index < 0 || index >= getCharCount()) {
2774 return null;
2775 }
2776 switch (part) {
2777 case AccessibleText.CHARACTER:
2778 if (index+1 >= getCharCount()) {
2779 return null;
2780 }
2781 try {
2782 return getText(index+1, 1);
2783 } catch (BadLocationException e) {
2784 return null;
2785 }
2786 case AccessibleText.WORD:
2787 try {
2788 String s = getText(0, getCharCount());
2789 BreakIterator words = BreakIterator.getWordInstance(getLocale());
2790 words.setText(s);
2791 int start = words.following(index);
2792 if (start == BreakIterator.DONE || start >= s.length()) {
2793 return null;
2794 }
2795 int end = words.following(start);
2796 if (end == BreakIterator.DONE || end >= s.length()) {
2797 return null;
2798 }
2799 return s.substring(start, end);
2800 } catch (BadLocationException e) {
2801 return null;
2802 }
2803 case AccessibleText.SENTENCE:
2804 try {
2805 String s = getText(0, getCharCount());
2806 BreakIterator sentence =
2807 BreakIterator.getSentenceInstance(getLocale());
2808 sentence.setText(s);
2809 int start = sentence.following(index);
2810 if (start == BreakIterator.DONE || start > s.length()) {
2811 return null;
2812 }
2813 int end = sentence.following(start);
2814 if (end == BreakIterator.DONE || end > s.length()) {
2815 return null;
2816 }
2817 return s.substring(start, end);
2818 } catch (BadLocationException e) {
2819 return null;
2820 }
2821 default:
2822 return null;
2823 }
2824 }
2825
2826 /**
2827 * Returns the String before a given index.
2828 *
2829 * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
2830 * or AccessibleText.SENTENCE to retrieve
2831 * @param index an index within the text >= 0
2832 * @return the letter, word, or sentence, null for an invalid index
2833 * or part
2834 * @since 1.3
2835 */
2836 public String getBeforeIndex(int part, int index) {
2837 if (index < 0 || index > getCharCount()-1) {
2838 return null;
2839 }
2840 switch (part) {
2841 case AccessibleText.CHARACTER:
2842 if (index == 0) {
2843 return null;
2844 }
2845 try {
2846 return getText(index-1, 1);
2847 } catch (BadLocationException e) {
2848 return null;
2849 }
2850 case AccessibleText.WORD:
2851 try {
2852 String s = getText(0, getCharCount());
2853 BreakIterator words = BreakIterator.getWordInstance(getLocale());
2854 words.setText(s);
2855 int end = words.following(index);
2856 end = words.previous();
2857 int start = words.previous();
2858 if (start == BreakIterator.DONE) {
2859 return null;
2860 }
2861 return s.substring(start, end);
2862 } catch (BadLocationException e) {
2863 return null;
2864 }
2865 case AccessibleText.SENTENCE:
2866 try {
2867 String s = getText(0, getCharCount());
2868 BreakIterator sentence =
2869 BreakIterator.getSentenceInstance(getLocale());
2870 sentence.setText(s);
2871 int end = sentence.following(index);
2872 end = sentence.previous();
2873 int start = sentence.previous();
2874 if (start == BreakIterator.DONE) {
2875 return null;
2876 }
2877 return s.substring(start, end);
2878 } catch (BadLocationException e) {
2879 return null;
2880 }
2881 default:
2882 return null;
2883 }
2884 }
2885
2886 /**
2887 * Return the AttributeSet for a given character at a given index
2888 *
2889 * @param i the zero-based index into the text
2890 * @return the AttributeSet of the character
2891 * @since 1.3
2892 */
2893 public AttributeSet getCharacterAttribute(int i) {
2894 View view = (View) AbstractButton.this.getClientProperty("html");
2895 if (view != null) {
2896 Document d = view.getDocument();
2897 if (d instanceof StyledDocument) {
2898 StyledDocument doc = (StyledDocument)d;
2899 Element elem = doc.getCharacterElement(i);
2900 if (elem != null) {
2901 return elem.getAttributes();
2902 }
2903 }
2904 }
2905 return null;
2906 }
2907
2908 /**
2909 * Returns the start offset within the selected text.
2910 * If there is no selection, but there is
2911 * a caret, the start and end offsets will be the same.
2912 *
2913 * @return the index into the text of the start of the selection
2914 * @since 1.3
2915 */
2916 public int getSelectionStart() {
2917 // Text cannot be selected.
2918 return -1;
2919 }
2920
2921 /**
2922 * Returns the end offset within the selected text.
2923 * If there is no selection, but there is
2924 * a caret, the start and end offsets will be the same.
2925 *
2926 * @return the index into teh text of the end of the selection
2927 * @since 1.3
2928 */
2929 public int getSelectionEnd() {
2930 // Text cannot be selected.
2931 return -1;
2932 }
2933
2934 /**
2935 * Returns the portion of the text that is selected.
2936 *
2937 * @return the String portion of the text that is selected
2938 * @since 1.3
2939 */
2940 public String getSelectedText() {
2941 // Text cannot be selected.
2942 return null;
2943 }
2944
2945 /*
2946 * Returns the text substring starting at the specified
2947 * offset with the specified length.
2948 */
2949 private String getText(int offset, int length)
2950 throws BadLocationException {
2951
2952 View view = (View) AbstractButton.this.getClientProperty("html");
2953 if (view != null) {
2954 Document d = view.getDocument();
2955 if (d instanceof StyledDocument) {
2956 StyledDocument doc = (StyledDocument)d;
2957 return doc.getText(offset, length);
2958 }
2959 }
2960 return null;
2961 }
2962
2963 /*
2964 * Returns the bounding rectangle for the component text.
2965 */
2966 private Rectangle getTextRectangle() {
2967
2968 String text = AbstractButton.this.getText();
2969 Icon icon = (AbstractButton.this.isEnabled()) ? AbstractButton.this.getIcon() : AbstractButton.this.getDisabledIcon();
2970
2971 if ((icon == null) && (text == null)) {
2972 return null;
2973 }
2974
2975 Rectangle paintIconR = new Rectangle();
2976 Rectangle paintTextR = new Rectangle();
2977 Rectangle paintViewR = new Rectangle();
2978 Insets paintViewInsets = new Insets(0, 0, 0, 0);
2979
2980 paintViewInsets = AbstractButton.this.getInsets(paintViewInsets);
2981 paintViewR.x = paintViewInsets.left;
2982 paintViewR.y = paintViewInsets.top;
2983 paintViewR.width = AbstractButton.this.getWidth() - (paintViewInsets.left + paintViewInsets.right);
2984 paintViewR.height = AbstractButton.this.getHeight() - (paintViewInsets.top + paintViewInsets.bottom);
2985
2986 String clippedText = SwingUtilities.layoutCompoundLabel(
2987 AbstractButton.this,
2988 getFontMetrics(getFont()),
2989 text,
2990 icon,
2991 AbstractButton.this.getVerticalAlignment(),
2992 AbstractButton.this.getHorizontalAlignment(),
2993 AbstractButton.this.getVerticalTextPosition(),
2994 AbstractButton.this.getHorizontalTextPosition(),
2995 paintViewR,
2996 paintIconR,
2997 paintTextR,
2998 0);
2999
3000 return paintTextR;
3001 }
3002
3003 // ----- AccessibleExtendedComponent
3004
3005 /**
3006 * Returns the AccessibleExtendedComponent
3007 *
3008 * @return the AccessibleExtendedComponent
3009 */
3010 AccessibleExtendedComponent getAccessibleExtendedComponent() {
3011 return this;
3012 }
3013
3014 /**
3015 * Returns the tool tip text
3016 *
3017 * @return the tool tip text, if supported, of the object;
3018 * otherwise, null
3019 * @since 1.4
3020 */
3021 public String getToolTipText() {
3022 return AbstractButton.this.getToolTipText();
3023 }
3024
3025 /**
3026 * Returns the titled border text
3027 *
3028 * @return the titled border text, if supported, of the object;
3029 * otherwise, null
3030 * @since 1.4
3031 */
3032 public String getTitledBorderText() {
3033 return super.getTitledBorderText();
3034 }
3035
3036 /**
3037 * Returns key bindings associated with this object
3038 *
3039 * @return the key bindings, if supported, of the object;
3040 * otherwise, null
3041 * @see AccessibleKeyBinding
3042 * @since 1.4
3043 */
3044 public AccessibleKeyBinding getAccessibleKeyBinding() {
3045 int mnemonic = AbstractButton.this.getMnemonic();
3046 if (mnemonic == 0) {
3047 return null;
3048 }
3049 return new ButtonKeyBinding(mnemonic);
3050 }
3051
3052 class ButtonKeyBinding implements AccessibleKeyBinding {
3053 int mnemonic;
3054
3055 ButtonKeyBinding(int mnemonic) {
3056 this.mnemonic = mnemonic;
3057 }
3058
3059 /**
3060 * Returns the number of key bindings for this object
3061 *
3062 * @return the zero-based number of key bindings for this object
3063 */
3064 public int getAccessibleKeyBindingCount() {
3065 return 1;
3066 }
3067
3068 /**
3069 * Returns a key binding for this object. The value returned is an
3070 * java.lang.Object which must be cast to appropriate type depending
3071 * on the underlying implementation of the key. For example, if the
3072 * Object returned is a javax.swing.KeyStroke, the user of this
3073 * method should do the following:
3074 * <nf><code>
3075 * Component c = <get the component that has the key bindings>
3076 * AccessibleContext ac = c.getAccessibleContext();
3077 * AccessibleKeyBinding akb = ac.getAccessibleKeyBinding();
3078 * for (int i = 0; i < akb.getAccessibleKeyBindingCount(); i++) {
3079 * Object o = akb.getAccessibleKeyBinding(i);
3080 * if (o instanceof javax.swing.KeyStroke) {
3081 * javax.swing.KeyStroke keyStroke = (javax.swing.KeyStroke)o;
3082 * <do something with the key binding>
3083 * }
3084 * }
3085 * </code></nf>
3086 *
3087 * @param i zero-based index of the key bindings
3088 * @return a javax.lang.Object which specifies the key binding
3089 * @exception IllegalArgumentException if the index is
3090 * out of bounds
3091 * @see #getAccessibleKeyBindingCount
3092 */
3093 public java.lang.Object getAccessibleKeyBinding(int i) {
3094 if (i != 0) {
3095 throw new IllegalArgumentException();
3096 }
3097 return KeyStroke.getKeyStroke(mnemonic, 0);
3098 }
3099 }
3100 }
3101}