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