OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [AbstractButton.java] - Blame information for rev 772

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* AbstractButton.java -- Provides basic button functionality.
2
   Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
package javax.swing;
39
 
40
import gnu.java.lang.CPStringBuilder;
41
 
42
import java.awt.Component;
43
import java.awt.Graphics;
44
import java.awt.Image;
45
import java.awt.Insets;
46
import java.awt.ItemSelectable;
47
import java.awt.LayoutManager;
48
import java.awt.Point;
49
import java.awt.Rectangle;
50
import java.awt.Shape;
51
import java.awt.event.ActionEvent;
52
import java.awt.event.ActionListener;
53
import java.awt.event.ItemEvent;
54
import java.awt.event.ItemListener;
55
import java.awt.image.ImageObserver;
56
import java.beans.PropertyChangeEvent;
57
import java.beans.PropertyChangeListener;
58
import java.io.Serializable;
59
import java.util.Enumeration;
60
 
61
import javax.accessibility.Accessible;
62
import javax.accessibility.AccessibleAction;
63
import javax.accessibility.AccessibleContext;
64
import javax.accessibility.AccessibleIcon;
65
import javax.accessibility.AccessibleRelation;
66
import javax.accessibility.AccessibleRelationSet;
67
import javax.accessibility.AccessibleState;
68
import javax.accessibility.AccessibleStateSet;
69
import javax.accessibility.AccessibleText;
70
import javax.accessibility.AccessibleValue;
71
import javax.swing.event.ChangeEvent;
72
import javax.swing.event.ChangeListener;
73
import javax.swing.plaf.ButtonUI;
74
import javax.swing.plaf.basic.BasicHTML;
75
import javax.swing.text.AttributeSet;
76
import javax.swing.text.BadLocationException;
77
import javax.swing.text.Document;
78
import javax.swing.text.Element;
79
import javax.swing.text.Position;
80
import javax.swing.text.StyledDocument;
81
import javax.swing.text.View;
82
 
83
 
84
/**
85
 * Provides an abstract implementation of common button behaviour,
86
 * data model and look & feel.
87
 *
88
 * <p>This class is supposed to serve as a base class for
89
 * several kinds of buttons with similar but non-identical semantics:
90
 * toggle buttons (radio buttons and checkboxes), simple push buttons,
91
 * menu items, etc.</p>
92
 *
93
 * <p>Buttons have many properties, some of which are stored in this class
94
 * while others are delegated to the button's model. The following properties
95
 * are available:</p>
96
 *
97
 * <table>
98
 * <tr><th>Property               </th><th>Stored in</th><th>Bound?</th></tr>
99
 *
100
 * <tr><td>action                 </td><td>button</td> <td>no</td></tr>
101
 * <tr><td>actionCommand          </td><td>model</td>  <td>no</td></tr>
102
 * <tr><td>borderPainted          </td><td>button</td> <td>yes</td></tr>
103
 * <tr><td>contentAreaFilled      </td><td>button</td> <td>yes</td></tr>
104
 * <tr><td>disabledIcon           </td><td>button</td> <td>yes</td></tr>
105
 * <tr><td>disabledSelectedIcon   </td><td>button</td> <td>yes</td></tr>
106
 * <tr><td>displayedMnemonicIndex </td><td>button</td> <td>no</td></tr>
107
 * <tr><td>enabled                </td><td>model</td>  <td>no</td></tr>
108
 * <tr><td>focusPainted           </td><td>button</td> <td>yes</td></tr>
109
 * <tr><td>horizontalAlignment    </td><td>button</td> <td>yes</td></tr>
110
 * <tr><td>horizontalTextPosition </td><td>button</td> <td>yes</td></tr>
111
 * <tr><td>icon                   </td><td>button</td> <td>yes</td></tr>
112
 * <tr><td>iconTextGap            </td><td>button</td> <td>no</td></tr>
113
 * <tr><td>label (same as text)   </td><td>model</td>  <td>yes</td></tr>
114
 * <tr><td>margin                 </td><td>button</td> <td>yes</td></tr>
115
 * <tr><td>multiClickThreshold    </td><td>button</td> <td>no</td></tr>
116
 * <tr><td>pressedIcon            </td><td>button</td> <td>yes</td></tr>
117
 * <tr><td>rolloverEnabled        </td><td>button</td> <td>yes</td></tr>
118
 * <tr><td>rolloverIcon           </td><td>button</td> <td>yes</td></tr>
119
 * <tr><td>rolloverSelectedIcon   </td><td>button</td> <td>yes</td></tr>
120
 * <tr><td>selected               </td><td>model</td>  <td>no</td></tr>
121
 * <tr><td>selectedIcon           </td><td>button</td> <td>yes</td></tr>
122
 * <tr><td>selectedObjects        </td><td>button</td> <td>no</td></tr>
123
 * <tr><td>text                   </td><td>model</td>  <td>yes</td></tr>
124
 * <tr><td>UI                     </td><td>button</td> <td>yes</td></tr>
125
 * <tr><td>verticalAlignment      </td><td>button</td> <td>yes</td></tr>
126
 * <tr><td>verticalTextPosition   </td><td>button</td> <td>yes</td></tr>
127
 *
128
 * </table>
129
 *
130
 * <p>The various behavioral aspects of these properties follows:</p>
131
 *
132
 * <ul>
133
 *
134
 * <li>When non-bound properties stored in the button change, the button
135
 * fires ChangeEvents to its ChangeListeners.</li>
136
 *
137
 * <li>When bound properties stored in the button change, the button fires
138
 * PropertyChangeEvents to its PropertyChangeListeners</li>
139
 *
140
 * <li>If any of the model's properties change, it fires a ChangeEvent to
141
 * its ChangeListeners, which include the button.</li>
142
 *
143
 * <li>If the button receives a ChangeEvent from its model, it will
144
 * propagate the ChangeEvent to its ChangeListeners, with the ChangeEvent's
145
 * "source" property set to refer to the button, rather than the model. The
146
 * the button will request a repaint, to paint its updated state.</li>
147
 *
148
 * <li>If the model's "selected" property changes, the model will fire an
149
 * ItemEvent to its ItemListeners, which include the button, in addition to
150
 * the ChangeEvent which models the property change. The button propagates
151
 * ItemEvents directly to its ItemListeners.</li>
152
 *
153
 * <li>If the model's armed and pressed properties are simultaneously
154
 * <code>true</code>, the model will fire an ActionEvent to its
155
 * ActionListeners, which include the button. The button will propagate
156
 * this ActionEvent to its ActionListeners, with the ActionEvent's "source"
157
 * property set to refer to the button, rather than the model.</li>
158
 *
159
 * </ul>
160
 *
161
 * @author Ronald Veldema (rveldema@cs.vu.nl)
162
 * @author Graydon Hoare (graydon@redhat.com)
163
 */
164
 
165
public abstract class AbstractButton extends JComponent
166
  implements ItemSelectable, SwingConstants
167
{
168
  private static final long serialVersionUID = -937921345538462020L;
169
 
170
  /**
171
   * An extension of ChangeListener to be serializable.
172
   */
173
  protected class ButtonChangeListener
174
    implements ChangeListener, Serializable
175
  {
176
    private static final long serialVersionUID = 1471056094226600578L;
177
 
178
    /**
179
     * The spec has no public/protected constructor for this class, so do we.
180
     */
181
    ButtonChangeListener()
182
    {
183
      // Nothing to do here.
184
    }
185
 
186
    /**
187
     * Notified when the target of the listener changes its state.
188
     *
189
     * @param ev the ChangeEvent describing the change
190
     */
191
    public void stateChanged(ChangeEvent ev)
192
    {
193
      getEventHandler().stateChanged(ev);
194
    }
195
  }
196
 
197
  /**
198
   * The combined event handler for ActionEvent, ChangeEvent and
199
   * ItemEvent. This combines ButtonChangeListener, ActionListener
200
   */
201
  private class EventHandler
202
    implements ActionListener, ChangeListener, ItemListener
203
  {
204
    public void actionPerformed(ActionEvent ev)
205
    {
206
      fireActionPerformed(ev);
207
    }
208
 
209
    public void stateChanged(ChangeEvent ev)
210
    {
211
      fireStateChanged();
212
      repaint();
213
    }
214
 
215
    public void itemStateChanged(ItemEvent ev)
216
    {
217
      fireItemStateChanged(ev);
218
    }
219
  }
220
 
221
  /** The icon displayed by default. */
222
  Icon default_icon;
223
 
224
  /** The icon displayed when the button is pressed. */
225
  Icon pressed_icon;
226
 
227
  /** The icon displayed when the button is disabled. */
228
  Icon disabledIcon;
229
 
230
  /** The icon displayed when the button is selected. */
231
  Icon selectedIcon;
232
 
233
  /** The icon displayed when the button is selected but disabled. */
234
  Icon disabledSelectedIcon;
235
 
236
  /** The icon displayed when the button is rolled over. */
237
  Icon rolloverIcon;
238
 
239
  /** The icon displayed when the button is selected and rolled over. */
240
  Icon rolloverSelectedIcon;
241
 
242
  /** The icon currently displayed. */
243
  Icon current_icon;
244
 
245
  /** The text displayed in the button. */
246
  String text;
247
 
248
  /**
249
   * The gap between icon and text, if both icon and text are
250
   * non-<code>null</code>.
251
   */
252
  int iconTextGap;
253
 
254
  /** The vertical alignment of the button's text and icon. */
255
  int verticalAlignment;
256
 
257
  /** The horizontal alignment of the button's text and icon. */
258
  int horizontalAlignment;
259
 
260
  /** The horizontal position of the button's text relative to its icon. */
261
  int horizontalTextPosition;
262
 
263
  /** The vertical position of the button's text relative to its icon. */
264
  int verticalTextPosition;
265
 
266
  /** Whether or not the button paints its border. */
267
  boolean borderPainted;
268
 
269
  /** Whether or not the button paints its focus state. */
270
  boolean focusPainted;
271
 
272
  /** Whether or not the button fills its content area. */
273
  boolean contentAreaFilled;
274
 
275
  /** Whether rollover is enabled. */
276
  boolean rollOverEnabled;
277
 
278
  /** The action taken when the button is clicked. */
279
  Action action;
280
 
281
  /** The button's current state. */
282
  protected ButtonModel model;
283
 
284
  /** The margin between the button's border and its label. */
285
  Insets margin;
286
 
287
  /**
288
   * A hint to the look and feel class, suggesting which character in the
289
   * button's label should be underlined when drawing the label.
290
   */
291
  int mnemonicIndex;
292
 
293
  /**
294
   * Listener the button uses to receive ActionEvents from its model.
295
   */
296
  protected ActionListener actionListener;
297
 
298
  /**
299
   * Listener the button uses to receive ItemEvents from its model.
300
   */
301
  protected ItemListener itemListener;
302
 
303
  /**
304
   * Listener the button uses to receive ChangeEvents from its model.
305
   */
306
  protected ChangeListener changeListener;
307
 
308
  /**
309
   * The event handler for ActionEvent, ItemEvent and ChangeEvent.
310
   * This replaces the above three handlers and combines them
311
   * into one for efficiency.
312
   */
313
  private EventHandler eventHandler;
314
 
315
  /**
316
   * The time in milliseconds in which clicks get coalesced into a single
317
   * <code>ActionEvent</code>.
318
   */
319
  long multiClickThreshhold;
320
 
321
  /**
322
   * Listener the button uses to receive PropertyChangeEvents from its
323
   * Action.
324
   */
325
  PropertyChangeListener actionPropertyChangeListener;
326
 
327
  /** ChangeEvent that is fired to button's ChangeEventListeners  */
328
  protected ChangeEvent changeEvent = new ChangeEvent(this);
329
 
330
  /**
331
   * Indicates if the borderPainted property has been set by a client
332
   * program or by the UI.
333
   *
334
   * @see #setUIProperty(String, Object)
335
   * @see LookAndFeel#installProperty(JComponent, String, Object)
336
   */
337
  private boolean clientBorderPaintedSet = false;
338
 
339
  /**
340
   * Indicates if the rolloverEnabled property has been set by a client
341
   * program or by the UI.
342
   *
343
   * @see #setUIProperty(String, Object)
344
   * @see LookAndFeel#installProperty(JComponent, String, Object)
345
   */
346
  private boolean clientRolloverEnabledSet = false;
347
 
348
  /**
349
   * Indicates if the iconTextGap property has been set by a client
350
   * program or by the UI.
351
   *
352
   * @see #setUIProperty(String, Object)
353
   * @see LookAndFeel#installProperty(JComponent, String, Object)
354
   */
355
  private boolean clientIconTextGapSet = false;
356
 
357
  /**
358
   * Indicates if the contentAreaFilled property has been set by a client
359
   * program or by the UI.
360
   *
361
   * @see #setUIProperty(String, Object)
362
   * @see LookAndFeel#installProperty(JComponent, String, Object)
363
   */
364
  private boolean clientContentAreaFilledSet = false;
365
 
366
  /**
367
   * Fired in a PropertyChangeEvent when the "borderPainted" property changes.
368
   */
369
  public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";
370
 
371
  /**
372
   * Fired in a PropertyChangeEvent when the "contentAreaFilled" property
373
   * changes.
374
   */
375
  public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY =
376
    "contentAreaFilled";
377
 
378
  /**
379
   * Fired in a PropertyChangeEvent when the "disabledIcon" property changes.
380
   */
381
  public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";
382
 
383
  /**
384
   * Fired in a PropertyChangeEvent when the "disabledSelectedIcon" property
385
   * changes.
386
   */
387
  public static final String DISABLED_SELECTED_ICON_CHANGED_PROPERTY =
388
    "disabledSelectedIcon";
389
 
390
  /**
391
   * Fired in a PropertyChangeEvent when the "focusPainted" property changes.
392
   */
393
  public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
394
 
395
  /**
396
   * Fired in a PropertyChangeEvent when the "horizontalAlignment" property
397
   * changes.
398
   */
399
  public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY =
400
    "horizontalAlignment";
401
 
402
  /**
403
   * Fired in a PropertyChangeEvent when the "horizontalTextPosition" property
404
   * changes.
405
   */
406
  public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY =
407
    "horizontalTextPosition";
408
 
409
  /**
410
   * Fired in a PropertyChangeEvent when the "icon" property changes. */
411
  public static final String ICON_CHANGED_PROPERTY = "icon";
412
 
413
  /** Fired in a PropertyChangeEvent when the "margin" property changes. */
414
  public static final String MARGIN_CHANGED_PROPERTY = "margin";
415
 
416
  /** Fired in a PropertyChangeEvent when the "mnemonic" property changes. */
417
  public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic";
418
 
419
  /** Fired in a PropertyChangeEvent when the "model" property changes. */
420
  public static final String MODEL_CHANGED_PROPERTY = "model";
421
 
422
  /** Fired in a PropertyChangeEvent when the "pressedIcon" property changes. */
423
  public static final String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";
424
 
425
  /**
426
   * Fired in a PropertyChangeEvent when the "rolloverEnabled" property
427
   * changes.
428
   */
429
  public static final String ROLLOVER_ENABLED_CHANGED_PROPERTY =
430
    "rolloverEnabled";
431
 
432
  /**
433
   * Fired in a PropertyChangeEvent when the "rolloverIcon" property changes.
434
   */
435
  public static final String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";
436
 
437
  /**
438
   * Fired in a PropertyChangeEvent when the "rolloverSelectedIcon" property
439
   * changes.
440
   */
441
  public static final String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY =
442
    "rolloverSelectedIcon";
443
 
444
  /**
445
   * Fired in a PropertyChangeEvent when the "selectedIcon" property changes.
446
   */
447
  public static final String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";
448
 
449
  /** Fired in a PropertyChangeEvent when the "text" property changes. */
450
  public static final String TEXT_CHANGED_PROPERTY = "text";
451
 
452
  /**
453
   * Fired in a PropertyChangeEvent when the "verticalAlignment" property
454
   * changes.
455
   */
456
  public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY =
457
    "verticalAlignment";
458
 
459
  /**
460
   * Fired in a PropertyChangeEvent when the "verticalTextPosition" property
461
   * changes.
462
   */
463
  public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY =
464
    "verticalTextPosition";
465
 
466
  /**
467
   * A Java Accessibility extension of the AbstractButton.
468
   */
469
  protected abstract class AccessibleAbstractButton
470
    extends AccessibleJComponent implements AccessibleAction, AccessibleValue,
471
                                            AccessibleText
472
  {
473
    private static final long serialVersionUID = -5673062525319836790L;
474
 
475
    protected AccessibleAbstractButton()
476
    {
477
      // Nothing to do here yet.
478
    }
479
 
480
    /**
481
     * Returns the accessible state set of this object. In addition to the
482
     * superclass's states, the <code>AccessibleAbstractButton</code>
483
     * supports the following states: {@link AccessibleState#ARMED},
484
     * {@link AccessibleState#FOCUSED}, {@link AccessibleState#PRESSED} and
485
     * {@link AccessibleState#CHECKED}.
486
     *
487
     * @return the current state of this accessible object
488
     */
489
    public AccessibleStateSet getAccessibleStateSet()
490
    {
491
      AccessibleStateSet state = super.getAccessibleStateSet();
492
 
493
      if (getModel().isArmed())
494
        state.add(AccessibleState.ARMED);
495
      if (getModel().isPressed())
496
        state.add(AccessibleState.PRESSED);
497
      if (isSelected())
498
        state.add(AccessibleState.CHECKED);
499
 
500
      return state;
501
    }
502
 
503
    /**
504
     * Returns the accessible name for the button.
505
     */
506
    public String getAccessibleName()
507
    {
508
      String result = super.getAccessibleName();
509
      if (result == null)
510
        result = text;
511
      return result;
512
    }
513
 
514
    /**
515
     * Returns the accessible icons of this object. If the AbstractButton's
516
     * icon is an Accessible, and it's AccessibleContext is an AccessibleIcon,
517
     * then this AccessibleIcon is returned, otherwise <code>null</code>.
518
     *
519
     * @return the accessible icons of this object, or <code>null</code> if
520
     *         there is no accessible icon
521
     */
522
    public AccessibleIcon[] getAccessibleIcon()
523
    {
524
      AccessibleIcon[] ret = null;
525
      Icon icon = getIcon();
526
      if (icon instanceof Accessible)
527
        {
528
          AccessibleContext ctx = ((Accessible) icon).getAccessibleContext();
529
          if (ctx instanceof AccessibleIcon)
530
            {
531
              ret = new AccessibleIcon[]{ (AccessibleIcon) ctx };
532
            }
533
        }
534
      return ret;
535
    }
536
 
537
    /**
538
     * Returns the accessible relations of this AccessibleAbstractButton.
539
     * If the AbstractButton is part of a ButtonGroup, then all the buttons
540
     * in this button group are added as targets in a MEMBER_OF relation,
541
     * otherwise an empty relation set is returned (from super).
542
     *
543
     * @return the accessible relations of this AccessibleAbstractButton
544
     */
545
    public AccessibleRelationSet getAccessibleRelationSet()
546
    {
547
      AccessibleRelationSet relations = super.getAccessibleRelationSet();
548
      ButtonModel model = getModel();
549
      if (model instanceof DefaultButtonModel)
550
        {
551
          ButtonGroup group = ((DefaultButtonModel) model).getGroup();
552
          if (group != null)
553
            {
554
              Object[] target = new Object[group.getButtonCount()];
555
              Enumeration els = group.getElements();
556
 
557
              for (int index = 0; els.hasMoreElements(); ++index)
558
                {
559
                  target[index] = els.nextElement();
560
                }
561
 
562
              AccessibleRelation rel =
563
                new AccessibleRelation(AccessibleRelation.MEMBER_OF);
564
              rel.setTarget(target);
565
              relations.add(rel);
566
            }
567
        }
568
      return relations;
569
    }
570
 
571
    /**
572
     * Returns the accessible action associated with this object. For buttons,
573
     * this will be <code>this</code>.
574
     *
575
     * @return <code>this</code>
576
     */
577
    public AccessibleAction getAccessibleAction()
578
    {
579
      return this;
580
    }
581
 
582
    /**
583
     * Returns the accessible value of this AccessibleAbstractButton, which
584
     * is always <code>this</code>.
585
     *
586
     * @return the accessible value of this AccessibleAbstractButton, which
587
     *         is always <code>this</code>
588
     */
589
    public AccessibleValue getAccessibleValue()
590
    {
591
      return this;
592
    }
593
 
594
    /**
595
     * Returns the number of accessible actions that are supported by this
596
     * object. Buttons support one action by default ('press button'), so this
597
     * method always returns <code>1</code>.
598
     *
599
     * @return <code>1</code>, the number of supported accessible actions
600
     */
601
    public int getAccessibleActionCount()
602
    {
603
      return 1;
604
    }
605
 
606
    /**
607
     * Returns a description for the action with the specified index or
608
     * <code>null</code> if such action does not exist.
609
     *
610
     * @param actionIndex the zero based index to the actions
611
     *
612
     * @return a description for the action with the specified index or
613
     *         <code>null</code> if such action does not exist
614
     */
615
    public String getAccessibleActionDescription(int actionIndex)
616
    {
617
      String descr = null;
618
      if (actionIndex == 0)
619
        {
620
          // FIXME: Supply localized descriptions in the UIDefaults.
621
          descr = UIManager.getString("AbstractButton.clickText");
622
        }
623
      return descr;
624
    }
625
 
626
    /**
627
     * Performs the acccessible action with the specified index on this object.
628
     * Since buttons have only one action by default (which is to press the
629
     * button), this method performs a 'press button' when the specified index
630
     * is <code>0</code> and nothing otherwise.
631
     *
632
     * @param actionIndex a zero based index into the actions of this button
633
     *
634
     * @return <code>true</code> if the specified action has been performed
635
     *         successfully, <code>false</code> otherwise
636
     */
637
    public boolean doAccessibleAction(int actionIndex)
638
    {
639
      boolean retVal = false;
640
      if (actionIndex == 0)
641
        {
642
          doClick();
643
          retVal = true;
644
        }
645
      return retVal;
646
    }
647
 
648
    /**
649
     * Returns the current value of this object as a number. This
650
     * implementation returns an <code>Integer(1)</code> if the button is
651
     * selected, <code>Integer(0)</code> if the button is not selected.
652
     *
653
     * @return the current value of this object as a number
654
     */
655
    public Number getCurrentAccessibleValue()
656
    {
657
      Integer retVal;
658
      if (isSelected())
659
        retVal = new Integer(1);
660
      else
661
        retVal = new Integer(0);
662
      return retVal;
663
    }
664
 
665
    /**
666
     * Sets the current accessible value as object. If the specified number
667
     * is 0 the button will be deselected, otherwise the button will
668
     * be selected.
669
     *
670
     * @param value 0 for deselected button, other for selected button
671
     *
672
     * @return <code>true</code> if the value has been set, <code>false</code>
673
     *         otherwise
674
     */
675
    public boolean setCurrentAccessibleValue(Number value)
676
    {
677
      boolean retVal = false;
678
      if (value != null)
679
        {
680
          if (value.intValue() == 0)
681
            setSelected(false);
682
          else
683
            setSelected(true);
684
          retVal = true;
685
        }
686
      return retVal;
687
    }
688
 
689
    /**
690
     * Returns the minimum accessible value for the AccessibleAbstractButton,
691
     * which is <code>0</code>.
692
     *
693
     * @return the minimimum accessible value for the AccessibleAbstractButton,
694
     *         which is <code>0</code>
695
     */
696
    public Number getMinimumAccessibleValue()
697
    {
698
      return new Integer(0);
699
    }
700
 
701
    /**
702
     * Returns the maximum accessible value for the AccessibleAbstractButton,
703
     * which is <code>1</code>.
704
     *
705
     * @return the maximum accessible value for the AccessibleAbstractButton,
706
     *         which is <code>1</code>
707
     */
708
    public Number getMaximumAccessibleValue()
709
    {
710
      return new Integer(1);
711
    }
712
 
713
    /**
714
     * Returns the accessible text for this AccessibleAbstractButton. This
715
     * will be <code>null</code> if the button has a non-HTML label, otherwise
716
     * <code>this</code>.
717
     *
718
     * @return the accessible text for this AccessibleAbstractButton
719
     */
720
    public AccessibleText getAccessibleText()
721
    {
722
      AccessibleText accessibleText = null;
723
      if (getClientProperty(BasicHTML.propertyKey) != null)
724
        accessibleText = this;
725
 
726
      return accessibleText;
727
    }
728
 
729
    /**
730
     * Returns the index of the label's character at the specified point,
731
     * relative to the local bounds of the button. This only works for
732
     * HTML labels.
733
     *
734
     * @param p the point, relative to the buttons local bounds
735
     *
736
     * @return the index of the label's character at the specified point
737
     */
738
    public int getIndexAtPoint(Point p)
739
    {
740
      int index = -1;
741
      View view = (View) getClientProperty(BasicHTML.propertyKey);
742
      if (view != null)
743
        {
744
          Rectangle shape = new Rectangle(0, 0, getWidth(), getHeight());
745
          index = view.viewToModel(p.x, p.y, shape, new Position.Bias[1]);
746
        }
747
      return index;
748
    }
749
 
750
    /**
751
     * Returns the bounds of the character at the specified index of the
752
     * button's label. This will only work for HTML labels.
753
     *
754
     * @param i the index of the character of the label
755
     *
756
     * @return the bounds of the character at the specified index of the
757
     *         button's label
758
     */
759
    public Rectangle getCharacterBounds(int i)
760
    {
761
      Rectangle rect = null;
762
      View view = (View) getClientProperty(BasicHTML.propertyKey);
763
      if (view != null)
764
        {
765
          Rectangle shape = new Rectangle(0, 0, getWidth(), getHeight());
766
          try
767
            {
768
              Shape s = view.modelToView(i, shape, Position.Bias.Forward);
769
              rect = s.getBounds();
770
            }
771
          catch (BadLocationException ex)
772
            {
773
              rect = null;
774
            }
775
        }
776
      return rect;
777
    }
778
 
779
    /**
780
     * Returns the number of characters in the button's label.
781
     *
782
     * @return the bounds of the character at the specified index of the
783
     *         button's label
784
     */
785
    public int getCharCount()
786
    {
787
      int charCount;
788
      View view = (View) getClientProperty(BasicHTML.propertyKey);
789
      if (view != null)
790
        {
791
          charCount = view.getDocument().getLength();
792
        }
793
      else
794
        {
795
          charCount = getAccessibleName().length();
796
        }
797
      return charCount;
798
    }
799
 
800
    /**
801
     * This always returns <code>-1</code> since there is no caret in a button.
802
     *
803
     * @return <code>-1</code> since there is no caret in a button
804
     */
805
    public int getCaretPosition()
806
    {
807
      return -1;
808
    }
809
 
810
    /**
811
     * Returns the character, word or sentence at the specified index. The
812
     * <code>part</code> parameter determines what is returned, the character,
813
     * word or sentence after the index.
814
     *
815
     * @param part one of {@link AccessibleText#CHARACTER},
816
     *             {@link AccessibleText#WORD} or
817
     *             {@link AccessibleText#SENTENCE}, specifying what is returned
818
     * @param index the index
819
     *
820
     * @return the character, word or sentence after <code>index</code>
821
     */
822
    public String getAtIndex(int part, int index)
823
    {
824
      String result = "";
825
      int startIndex = -1;
826
      int endIndex = -1;
827
      switch(part)
828
        {
829
        case AccessibleText.CHARACTER:
830
          result = String.valueOf(text.charAt(index));
831
          break;
832
        case AccessibleText.WORD:
833
          startIndex = text.lastIndexOf(' ', index);
834
          endIndex = text.indexOf(' ', startIndex + 1);
835
          if (endIndex == -1)
836
            endIndex = startIndex + 1;
837
          result = text.substring(startIndex + 1, endIndex);
838
          break;
839
        case AccessibleText.SENTENCE:
840
        default:
841
          startIndex = text.lastIndexOf('.', index);
842
          endIndex = text.indexOf('.', startIndex + 1);
843
          if (endIndex == -1)
844
            endIndex = startIndex + 1;
845
          result = text.substring(startIndex + 1, endIndex);
846
          break;
847
        }
848
      return result;
849
    }
850
 
851
    /**
852
     * Returns the character, word or sentence after the specified index. The
853
     * <code>part</code> parameter determines what is returned, the character,
854
     * word or sentence after the index.
855
     *
856
     * @param part one of {@link AccessibleText#CHARACTER},
857
     *             {@link AccessibleText#WORD} or
858
     *             {@link AccessibleText#SENTENCE}, specifying what is returned
859
     * @param index the index
860
     *
861
     * @return the character, word or sentence after <code>index</code>
862
     */
863
    public String getAfterIndex(int part, int index)
864
    {
865
      String result = "";
866
      int startIndex = -1;
867
      int endIndex = -1;
868
      switch(part)
869
        {
870
        case AccessibleText.CHARACTER:
871
          result = String.valueOf(text.charAt(index + 1));
872
          break;
873
        case AccessibleText.WORD:
874
          startIndex = text.indexOf(' ', index);
875
          endIndex = text.indexOf(' ', startIndex + 1);
876
          if (endIndex == -1)
877
            endIndex = startIndex + 1;
878
          result = text.substring(startIndex + 1, endIndex);
879
          break;
880
        case AccessibleText.SENTENCE:
881
        default:
882
          startIndex = text.indexOf('.', index);
883
          endIndex = text.indexOf('.', startIndex + 1);
884
          if (endIndex == -1)
885
            endIndex = startIndex + 1;
886
          result = text.substring(startIndex + 1, endIndex);
887
          break;
888
        }
889
      return result;
890
    }
891
 
892
    /**
893
     * Returns the character, word or sentence before the specified index. The
894
     * <code>part</code> parameter determines what is returned, the character,
895
     * word or sentence before the index.
896
     *
897
     * @param part one of {@link AccessibleText#CHARACTER},
898
     *             {@link AccessibleText#WORD} or
899
     *             {@link AccessibleText#SENTENCE}, specifying what is returned
900
     * @param index the index
901
     *
902
     * @return the character, word or sentence before <code>index</code>
903
     */
904
    public String getBeforeIndex(int part, int index)
905
    {
906
      String result = "";
907
      int startIndex = -1;
908
      int endIndex = -1;
909
      switch(part)
910
        {
911
        case AccessibleText.CHARACTER:
912
          result = String.valueOf(text.charAt(index - 1));
913
          break;
914
        case AccessibleText.WORD:
915
          endIndex = text.lastIndexOf(' ', index);
916
          if (endIndex == -1)
917
            endIndex = 0;
918
          startIndex = text.lastIndexOf(' ', endIndex - 1);
919
          result = text.substring(startIndex + 1, endIndex);
920
          break;
921
        case AccessibleText.SENTENCE:
922
        default:
923
          endIndex = text.lastIndexOf('.', index);
924
          if (endIndex == -1)
925
            endIndex = 0;
926
          startIndex = text.lastIndexOf('.', endIndex - 1);
927
          result = text.substring(startIndex + 1, endIndex);
928
          break;
929
        }
930
      return result;
931
    }
932
 
933
    /**
934
     * Returns the text attribute for the character at the specified character
935
     * index.
936
     *
937
     * @param i the character index
938
     *
939
     * @return the character attributes for the specified character or
940
     *         <code>null</code> if the character has no attributes
941
     */
942
    public AttributeSet getCharacterAttribute(int i)
943
    {
944
      AttributeSet atts = null;
945
      View view = (View) getClientProperty(BasicHTML.propertyKey);
946
      if (view != null)
947
        {
948
          Document doc = view.getDocument();
949
          if (doc instanceof StyledDocument)
950
            {
951
              StyledDocument sDoc = (StyledDocument) doc;
952
              Element charEl = sDoc.getCharacterElement(i);
953
              if (charEl != null)
954
                atts = charEl.getAttributes();
955
            }
956
        }
957
      return atts;
958
    }
959
 
960
    /**
961
     * This always returns <code>-1</code> since
962
     * button labels can't be selected.
963
     *
964
     * @return <code>-1</code>, button labels can't be selected
965
     */
966
    public int getSelectionStart()
967
    {
968
      return -1;
969
    }
970
 
971
    /**
972
     * This always returns <code>-1</code> since
973
     * button labels can't be selected.
974
     *
975
     * @return <code>-1</code>, button labels can't be selected
976
     */
977
    public int getSelectionEnd()
978
    {
979
      return -1;
980
    }
981
 
982
    /**
983
     * Returns the selected text. This always returns <code>null</code> since
984
     * button labels can't be selected.
985
     *
986
     * @return <code>null</code>, button labels can't be selected
987
     */
988
    public String getSelectedText()
989
    {
990
      return null;
991
    }
992
  }
993
 
994
  /**
995
   * Creates a new AbstractButton object. Subclasses should call the following
996
   * sequence in their constructor in order to initialize the button correctly:
997
   * <pre>
998
   * super();
999
   * init(text, icon);
1000
   * </pre>
1001
   *
1002
   * The {@link #init(String, Icon)} method is not called automatically by this
1003
   * constructor.
1004
   *
1005
   * @see #init(String, Icon)
1006
   */
1007
  public AbstractButton()
1008
  {
1009
    horizontalAlignment = CENTER;
1010
    horizontalTextPosition = TRAILING;
1011
    verticalAlignment = CENTER;
1012
    verticalTextPosition = CENTER;
1013
    borderPainted = true;
1014
    contentAreaFilled = true;
1015
    focusPainted = true;
1016
    setFocusable(true);
1017
    setAlignmentX(CENTER_ALIGNMENT);
1018
    setAlignmentY(CENTER_ALIGNMENT);
1019
    setDisplayedMnemonicIndex(-1);
1020
    setOpaque(true);
1021
    text = "";
1022
    // testing on JRE1.5 shows that the iconTextGap default value is
1023
    // hard-coded here and the 'Button.iconTextGap' setting in the
1024
    // UI defaults is ignored, at least by the MetalLookAndFeel
1025
    iconTextGap = 4;
1026
  }
1027
 
1028
  /**
1029
   * Get the model the button is currently using.
1030
   *
1031
   * @return The current model
1032
   */
1033
  public ButtonModel getModel()
1034
  {
1035
      return model;
1036
  }
1037
 
1038
  /**
1039
   * Set the model the button is currently using. This un-registers all
1040
   * listeners associated with the current model, and re-registers them
1041
   * with the new model.
1042
   *
1043
   * @param newModel The new model
1044
   */
1045
  public void setModel(ButtonModel newModel)
1046
  {
1047
    if (newModel == model)
1048
      return;
1049
 
1050
    if (model != null)
1051
      {
1052
        model.removeActionListener(actionListener);
1053
        actionListener = null;
1054
        model.removeChangeListener(changeListener);
1055
        changeListener = null;
1056
        model.removeItemListener(itemListener);
1057
        itemListener = null;
1058
      }
1059
    ButtonModel old = model;
1060
    model = newModel;
1061
    if (model != null)
1062
      {
1063
        actionListener = createActionListener();
1064
        model.addActionListener(actionListener);
1065
        changeListener = createChangeListener();
1066
        model.addChangeListener(changeListener);
1067
        itemListener = createItemListener();
1068
        model.addItemListener(itemListener);
1069
      }
1070
    firePropertyChange(MODEL_CHANGED_PROPERTY, old, model);
1071
    revalidate();
1072
    repaint();
1073
  }
1074
 
1075
 protected void init(String text, Icon icon)
1076
 {
1077
    // If text is null, we fall back to the empty
1078
    // string (which is set using AbstractButton's
1079
    // constructor).
1080
    // This way the behavior of the JDK is matched.
1081
    if(text != null)
1082
      setText(text);
1083
 
1084
    if (icon != null)
1085
      default_icon = icon;
1086
 
1087
    updateUI();
1088
 }
1089
 
1090
  /**
1091
   * <p>Returns the action command string for this button's model.</p>
1092
   *
1093
   * <p>If the action command was set to <code>null</code>, the button's
1094
   * text (label) is returned instead.</p>
1095
   *
1096
   * @return The current action command string from the button's model
1097
   */
1098
  public String getActionCommand()
1099
  {
1100
    String ac = model.getActionCommand();
1101
    if (ac != null)
1102
      return ac;
1103
    else
1104
      return text;
1105
  }
1106
 
1107
  /**
1108
   * Sets the action command string for this button's model.
1109
   *
1110
   * @param actionCommand The new action command string to set in the button's
1111
   * model.
1112
   */
1113
  public void setActionCommand(String actionCommand)
1114
  {
1115
    if (model != null)
1116
      model.setActionCommand(actionCommand);
1117
  }
1118
 
1119
  /**
1120
   * Adds an ActionListener to the button's listener list. When the
1121
   * button's model is clicked it fires an ActionEvent, and these
1122
   * listeners will be called.
1123
   *
1124
   * @param l The new listener to add
1125
   */
1126
  public void addActionListener(ActionListener l)
1127
  {
1128
    listenerList.add(ActionListener.class, l);
1129
  }
1130
 
1131
  /**
1132
   * Removes an ActionListener from the button's listener list.
1133
   *
1134
   * @param l The listener to remove
1135
   */
1136
  public void removeActionListener(ActionListener l)
1137
  {
1138
    listenerList.remove(ActionListener.class, l);
1139
  }
1140
 
1141
  /**
1142
   * Returns all added <code>ActionListener</code> objects.
1143
   *
1144
   * @return an array of listeners
1145
   *
1146
   * @since 1.4
1147
   */
1148
  public ActionListener[] getActionListeners()
1149
  {
1150
    return (ActionListener[]) listenerList.getListeners(ActionListener.class);
1151
  }
1152
 
1153
  /**
1154
   * Adds an ItemListener to the button's listener list. When the button's
1155
   * model changes state (between any of ARMED, ENABLED, PRESSED, ROLLOVER
1156
   * or SELECTED) it fires an ItemEvent, and these listeners will be
1157
   * called.
1158
   *
1159
   * @param l The new listener to add
1160
   */
1161
  public void addItemListener(ItemListener l)
1162
  {
1163
    listenerList.add(ItemListener.class, l);
1164
  }
1165
 
1166
  /**
1167
   * Removes an ItemListener from the button's listener list.
1168
   *
1169
   * @param l The listener to remove
1170
   */
1171
  public void removeItemListener(ItemListener l)
1172
  {
1173
    listenerList.remove(ItemListener.class, l);
1174
  }
1175
 
1176
  /**
1177
   * Returns all added <code>ItemListener</code> objects.
1178
   *
1179
   * @return an array of listeners
1180
   *
1181
   * @since 1.4
1182
   */
1183
  public ItemListener[] getItemListeners()
1184
  {
1185
    return (ItemListener[]) listenerList.getListeners(ItemListener.class);
1186
  }
1187
 
1188
  /**
1189
   * Adds a ChangeListener to the button's listener list. When the button's
1190
   * model changes any of its (non-bound) properties, these listeners will be
1191
   * called.
1192
   *
1193
   * @param l The new listener to add
1194
   */
1195
  public void addChangeListener(ChangeListener l)
1196
  {
1197
    listenerList.add(ChangeListener.class, l);
1198
  }
1199
 
1200
  /**
1201
   * Removes a ChangeListener from the button's listener list.
1202
   *
1203
   * @param l The listener to remove
1204
   */
1205
  public void removeChangeListener(ChangeListener l)
1206
  {
1207
    listenerList.remove(ChangeListener.class, l);
1208
  }
1209
 
1210
  /**
1211
   * Returns all added <code>ChangeListener</code> objects.
1212
   *
1213
   * @return an array of listeners
1214
   *
1215
   * @since 1.4
1216
   */
1217
  public ChangeListener[] getChangeListeners()
1218
  {
1219
    return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
1220
  }
1221
 
1222
  /**
1223
   * Calls {@link ItemListener#itemStateChanged} on each ItemListener in
1224
   * the button's listener list.
1225
   *
1226
   * @param e The event signifying that the button's model changed state
1227
   */
1228
  protected void fireItemStateChanged(ItemEvent e)
1229
  {
1230
    e.setSource(this);
1231
    ItemListener[] listeners = getItemListeners();
1232
 
1233
    for (int i = 0; i < listeners.length; i++)
1234
      listeners[i].itemStateChanged(e);
1235
  }
1236
 
1237
  /**
1238
   * Calls {@link ActionListener#actionPerformed} on each {@link
1239
   * ActionListener} in the button's listener list.
1240
   *
1241
   * @param e The event signifying that the button's model was clicked
1242
   */
1243
  protected void fireActionPerformed(ActionEvent e)
1244
  {
1245
        // Dispatch a copy of the given ActionEvent in order to
1246
        // set the source and action command correctly.
1247
    ActionEvent ae = new ActionEvent(
1248
        this,
1249
        e.getID(),
1250
        getActionCommand(),
1251
        e.getWhen(),
1252
        e.getModifiers());
1253
 
1254
    ActionListener[] listeners = getActionListeners();
1255
 
1256
    for (int i = 0; i < listeners.length; i++)
1257
      listeners[i].actionPerformed(ae);
1258
  }
1259
 
1260
  /**
1261
   * Calls {@link ChangeListener#stateChanged} on each {@link ChangeListener}
1262
   * in the button's listener list.
1263
   */
1264
  protected void fireStateChanged()
1265
  {
1266
    ChangeListener[] listeners = getChangeListeners();
1267
 
1268
    for (int i = 0; i < listeners.length; i++)
1269
      listeners[i].stateChanged(changeEvent);
1270
  }
1271
 
1272
  /**
1273
   * Get the current keyboard mnemonic value. This value corresponds to a
1274
   * single key code (one of the {@link java.awt.event.KeyEvent} VK_*
1275
   * codes) and is used to activate the button when pressed in conjunction
1276
   * with the "mouseless modifier" of the button's look and feel class, and
1277
   * when focus is in one of the button's ancestors.
1278
   *
1279
   * @return The button's current keyboard mnemonic
1280
   */
1281
  public int getMnemonic()
1282
  {
1283
    ButtonModel mod = getModel();
1284
    if (mod != null)
1285
      return mod.getMnemonic();
1286
    return -1;
1287
  }
1288
 
1289
  /**
1290
   * Set the current keyboard mnemonic value. This value corresponds to a
1291
   * single key code (one of the {@link java.awt.event.KeyEvent} VK_*
1292
   * codes) and is used to activate the button when pressed in conjunction
1293
   * with the "mouseless modifier" of the button's look and feel class, and
1294
   * when focus is in one of the button's ancestors.
1295
   *
1296
   * @param mne A new mnemonic to use for the button
1297
   */
1298
  public void setMnemonic(char mne)
1299
  {
1300
    setMnemonic((int) mne);
1301
  }
1302
 
1303
  /**
1304
   * Set the current keyboard mnemonic value. This value corresponds to a
1305
   * single key code (one of the {@link java.awt.event.KeyEvent} VK_*
1306
   * codes) and is used to activate the button when pressed in conjunction
1307
   * with the "mouseless modifier" of the button's look and feel class, and
1308
   * when focus is in one of the button's ancestors.
1309
   *
1310
   * @param mne A new mnemonic to use for the button
1311
   */
1312
  public void setMnemonic(int mne)
1313
  {
1314
    ButtonModel mod = getModel();
1315
    int old = -1;
1316
    if (mod != null)
1317
      old = mod.getMnemonic();
1318
 
1319
    if (old != mne)
1320
      {
1321
        if (mod != null)
1322
          mod.setMnemonic(mne);
1323
 
1324
        if (text != null && !text.equals(""))
1325
          {
1326
            // Since lower case char = upper case char for
1327
            // mnemonic, we will convert both text and mnemonic
1328
            // to upper case before checking if mnemonic character occurs
1329
            // in the menu item text.
1330
            int upperCaseMne = Character.toUpperCase((char) mne);
1331
            String upperCaseText = text.toUpperCase();
1332
            setDisplayedMnemonicIndex(upperCaseText.indexOf(upperCaseMne));
1333
          }
1334
 
1335
        firePropertyChange(MNEMONIC_CHANGED_PROPERTY, old, mne);
1336
        revalidate();
1337
        repaint();
1338
      }
1339
  }
1340
 
1341
  /**
1342
   * Sets the button's mnemonic index. The mnemonic index is a hint to the
1343
   * look and feel class, suggesting which character in the button's label
1344
   * should be underlined when drawing the label. If the mnemonic index is
1345
   * -1, no mnemonic will be displayed.
1346
   *
1347
   * If no mnemonic index is set, the button will choose a mnemonic index
1348
   * by default, which will be the first occurrence of the mnemonic
1349
   * character in the button's text.
1350
   *
1351
   * @param index An offset into the "text" property of the button
1352
   * @throws IllegalArgumentException If <code>index</code> is not within the
1353
   * range of legal offsets for the "text" property of the button.
1354
   * @since 1.4
1355
   */
1356
 
1357
  public void setDisplayedMnemonicIndex(int index)
1358
  {
1359
    if (index < -1 || (text != null && index >= text.length()))
1360
      throw new IllegalArgumentException();
1361
 
1362
    mnemonicIndex = index;
1363
  }
1364
 
1365
  /**
1366
   * Get the button's mnemonic index, which is an offset into the button's
1367
   * "text" property.  The character specified by this offset should be
1368
   * underlined when the look and feel class draws this button.
1369
   *
1370
   * @return An index into the button's "text" property
1371
   */
1372
  public int getDisplayedMnemonicIndex()
1373
  {
1374
    return mnemonicIndex;
1375
  }
1376
 
1377
 
1378
  /**
1379
   * Set the "rolloverEnabled" property. When rollover is enabled, and the
1380
   * look and feel supports it, the button will change its icon to
1381
   * rolloverIcon, when the mouse passes over it.
1382
   *
1383
   * @param r Whether or not to enable rollover icon changes
1384
   */
1385
  public void setRolloverEnabled(boolean r)
1386
  {
1387
    clientRolloverEnabledSet = true;
1388
    if (rollOverEnabled != r)
1389
      {
1390
        rollOverEnabled = r;
1391
        firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, !r, r);
1392
        revalidate();
1393
        repaint();
1394
      }
1395
  }
1396
 
1397
  /**
1398
   * Returns whether or not rollover icon changes are enabled on the
1399
   * button.
1400
   *
1401
   * @return The state of the "rolloverEnabled" property
1402
   */
1403
  public boolean isRolloverEnabled()
1404
  {
1405
    return rollOverEnabled;
1406
  }
1407
 
1408
  /**
1409
   * Set the value of the button's "selected" property. Selection is only
1410
   * meaningful for toggle-type buttons (check boxes, radio buttons).
1411
   *
1412
   * @param s New value for the property
1413
   */
1414
  public void setSelected(boolean s)
1415
  {
1416
    ButtonModel mod = getModel();
1417
    if (mod != null)
1418
      mod.setSelected(s);
1419
  }
1420
 
1421
  /**
1422
   * Get the value of the button's "selected" property. Selection is only
1423
   * meaningful for toggle-type buttons (check boxes, radio buttons).
1424
   *
1425
   * @return The value of the property
1426
   */
1427
  public boolean isSelected()
1428
  {
1429
    ButtonModel mod = getModel();
1430
    if (mod != null)
1431
      return mod.isSelected();
1432
    return false;
1433
  }
1434
 
1435
  /**
1436
   * Enables or disables the button. A button will neither be selectable
1437
   * nor preform any actions unless it is enabled.
1438
   *
1439
   * @param b Whether or not to enable the button
1440
   */
1441
  public void setEnabled(boolean b)
1442
  {
1443
    // Do nothing if state does not change.
1444
    if (b == isEnabled())
1445
      return;
1446
    super.setEnabled(b);
1447
    setFocusable(b);
1448
    ButtonModel mod = getModel();
1449
    if (mod != null)
1450
      mod.setEnabled(b);
1451
  }
1452
 
1453
  /**
1454
   * Set the horizontal alignment of the button's text and icon. The
1455
   * alignment is a numeric constant from {@link SwingConstants}. It must
1456
   * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
1457
   * <code>LEADING</code> or <code>TRAILING</code>.  The default is
1458
   * <code>CENTER</code>.
1459
   *
1460
   * @return The current horizontal alignment
1461
   *
1462
   * @see #setHorizontalAlignment(int)
1463
   */
1464
  public int getHorizontalAlignment()
1465
  {
1466
    return horizontalAlignment;
1467
  }
1468
 
1469
  /**
1470
   * Set the horizontal alignment of the button's text and icon. The
1471
   * alignment is a numeric constant from {@link SwingConstants}. It must
1472
   * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
1473
   * <code>LEADING</code> or <code>TRAILING</code>.  The default is
1474
   * <code>CENTER</code>.
1475
   *
1476
   * @param a The new horizontal alignment
1477
   * @throws IllegalArgumentException If alignment is not one of the legal
1478
   * constants.
1479
   *
1480
   * @see #getHorizontalAlignment()
1481
   */
1482
  public void setHorizontalAlignment(int a)
1483
  {
1484
    if (horizontalAlignment == a)
1485
      return;
1486
    if (a != LEFT && a != CENTER && a != RIGHT && a != LEADING
1487
        && a != TRAILING)
1488
      throw new IllegalArgumentException("Invalid alignment.");
1489
    int old = horizontalAlignment;
1490
    horizontalAlignment = a;
1491
    firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY, old, a);
1492
    revalidate();
1493
    repaint();
1494
  }
1495
 
1496
  /**
1497
   * Get the horizontal position of the button's text relative to its
1498
   * icon. The position is a numeric constant from {@link
1499
   * SwingConstants}. It must be one of: <code>RIGHT</code>,
1500
   * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or
1501
   * <code>TRAILING</code>.  The default is <code>TRAILING</code>.
1502
   *
1503
   * @return The current horizontal text position
1504
   */
1505
  public int getHorizontalTextPosition()
1506
  {
1507
    return horizontalTextPosition;
1508
  }
1509
 
1510
  /**
1511
   * Set the horizontal position of the button's text relative to its
1512
   * icon. The position is a numeric constant from {@link
1513
   * SwingConstants}. It must be one of: <code>RIGHT</code>,
1514
   * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or
1515
   * <code>TRAILING</code>. The default is <code>TRAILING</code>.
1516
   *
1517
   * @param t The new horizontal text position
1518
   * @throws IllegalArgumentException If position is not one of the legal
1519
   * constants.
1520
   */
1521
  public void setHorizontalTextPosition(int t)
1522
  {
1523
    if (horizontalTextPosition == t)
1524
      return;
1525
    if (t != LEFT && t != CENTER && t != RIGHT && t != LEADING
1526
        && t != TRAILING)
1527
      throw new IllegalArgumentException("Invalid alignment.");
1528
 
1529
    int old = horizontalTextPosition;
1530
    horizontalTextPosition = t;
1531
    firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY, old, t);
1532
    revalidate();
1533
    repaint();
1534
  }
1535
 
1536
  /**
1537
   * Get the vertical alignment of the button's text and icon. The
1538
   * alignment is a numeric constant from {@link SwingConstants}. It must
1539
   * be one of: <code>CENTER</code>, <code>TOP</code>, or
1540
   * <code>BOTTOM</code>. The default is <code>CENTER</code>.
1541
   *
1542
   * @return The current vertical alignment
1543
   *
1544
   * @see #setVerticalAlignment(int)
1545
   */
1546
  public int getVerticalAlignment()
1547
  {
1548
    return verticalAlignment;
1549
  }
1550
 
1551
  /**
1552
   * Set the vertical alignment of the button's text and icon. The
1553
   * alignment is a numeric constant from {@link SwingConstants}. It must
1554
   * be one of: <code>CENTER</code>, <code>TOP</code>, or
1555
   * <code>BOTTOM</code>. The default is <code>CENTER</code>.
1556
   *
1557
   * @param a The new vertical alignment
1558
   * @throws IllegalArgumentException If alignment is not one of the legal
1559
   * constants.
1560
   *
1561
   * @see #getVerticalAlignment()
1562
   */
1563
  public void setVerticalAlignment(int a)
1564
  {
1565
    if (verticalAlignment == a)
1566
      return;
1567
    if (a != TOP && a != CENTER && a != BOTTOM)
1568
      throw new IllegalArgumentException("Invalid alignment.");
1569
 
1570
    int old = verticalAlignment;
1571
    verticalAlignment = a;
1572
    firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, old, a);
1573
    revalidate();
1574
    repaint();
1575
  }
1576
 
1577
  /**
1578
   * Get the vertical position of the button's text relative to its
1579
   * icon. The alignment is a numeric constant from {@link
1580
   * SwingConstants}. It must be one of: <code>CENTER</code>,
1581
   * <code>TOP</code>, or <code>BOTTOM</code>. The default is
1582
   * <code>CENTER</code>.
1583
   *
1584
   * @return The current vertical position
1585
   */
1586
  public int getVerticalTextPosition()
1587
  {
1588
    return verticalTextPosition;
1589
  }
1590
 
1591
  /**
1592
   * Set the vertical position of the button's text relative to its
1593
   * icon. The alignment is a numeric constant from {@link
1594
   * SwingConstants}. It must be one of: <code>CENTER</code>,
1595
   * <code>TOP</code>, or <code>BOTTOM</code>. The default is
1596
   * <code>CENTER</code>.
1597
   *
1598
   * @param t The new vertical position
1599
   * @throws IllegalArgumentException If position is not one of the legal
1600
   * constants.
1601
   */
1602
  public void setVerticalTextPosition(int t)
1603
  {
1604
    if (verticalTextPosition == t)
1605
      return;
1606
    if (t != TOP && t != CENTER && t != BOTTOM)
1607
      throw new IllegalArgumentException("Invalid alignment.");
1608
 
1609
    int old = verticalTextPosition;
1610
    verticalTextPosition = t;
1611
    firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, old, t);
1612
    revalidate();
1613
    repaint();
1614
  }
1615
 
1616
  /**
1617
   * Set the value of the "borderPainted" property. If set to
1618
   * <code>false</code>, the button's look and feel class should not paint
1619
   * a border for the button. The default is <code>true</code>.
1620
   *
1621
   * @return The current value of the property.
1622
   */
1623
  public boolean isBorderPainted()
1624
  {
1625
    return borderPainted;
1626
  }
1627
 
1628
  /**
1629
   * Set the value of the "borderPainted" property. If set to
1630
   * <code>false</code>, the button's look and feel class should not paint
1631
   * a border for the button. The default is <code>true</code>.
1632
   *
1633
   * @param b The new value of the property.
1634
   */
1635
  public void setBorderPainted(boolean b)
1636
  {
1637
    clientBorderPaintedSet = true;
1638
    if (borderPainted == b)
1639
      return;
1640
    boolean old = borderPainted;
1641
    borderPainted = b;
1642
    firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, old, b);
1643
    revalidate();
1644
    repaint();
1645
  }
1646
 
1647
  /**
1648
   * Get the value of the "action" property.
1649
   *
1650
   * @return The current value of the "action" property
1651
   */
1652
  public Action getAction()
1653
  {
1654
    return action;
1655
  }
1656
 
1657
  /**
1658
   * <p>Set the button's "action" property, subscribing the new action to the
1659
   * button, as an ActionListener, if it is not already subscribed. The old
1660
   * Action, if it exists, is unsubscribed, and the button is unsubscribed
1661
   * from the old Action if it was previously subscribed as a
1662
   * PropertyChangeListener.</p>
1663
   *
1664
   * <p>This method also configures several of the button's properties from
1665
   * the Action, by calling {@link #configurePropertiesFromAction}, and
1666
   * subscribes the button to the Action as a PropertyChangeListener.
1667
   * Subsequent changes to the Action will thus reconfigure the button
1668
   * automatically.</p>
1669
   *
1670
   * @param a The new value of the "action" property
1671
   */
1672
  public void setAction(Action a)
1673
  {
1674
    if (action != null)
1675
      {
1676
        action.removePropertyChangeListener(actionPropertyChangeListener);
1677
        removeActionListener(action);
1678
        if (actionPropertyChangeListener != null)
1679
          {
1680
            action.removePropertyChangeListener(actionPropertyChangeListener);
1681
            actionPropertyChangeListener = null;
1682
          }
1683
      }
1684
 
1685
    Action old = action;
1686
    action = a;
1687
    configurePropertiesFromAction(action);
1688
    if (action != null)
1689
      {
1690
        actionPropertyChangeListener = createActionPropertyChangeListener(a);
1691
        action.addPropertyChangeListener(actionPropertyChangeListener);
1692
        addActionListener(action);
1693
      }
1694
  }
1695
 
1696
  /**
1697
   * Return the button's default "icon" property.
1698
   *
1699
   * @return The current default icon
1700
   */
1701
  public Icon getIcon()
1702
  {
1703
    return default_icon;
1704
  }
1705
 
1706
  /**
1707
   * Set the button's default "icon" property. This icon is used as a basis
1708
   * for the pressed and disabled icons, if none are explicitly set.
1709
   *
1710
   * @param i The new default icon
1711
   */
1712
  public void setIcon(Icon i)
1713
  {
1714
    if (default_icon == i)
1715
      return;
1716
 
1717
    Icon old = default_icon;
1718
    default_icon = i;
1719
    firePropertyChange(ICON_CHANGED_PROPERTY, old, i);
1720
    revalidate();
1721
    repaint();
1722
  }
1723
 
1724
  /**
1725
   * Return the button's "text" property. This property is synonymous with
1726
   * the "label" property.
1727
   *
1728
   * @return The current "text" property
1729
   */
1730
  public String getText()
1731
  {
1732
    return text;
1733
  }
1734
 
1735
  /**
1736
   * Set the button's "label" property. This property is synonymous with the
1737
   * "text" property.
1738
   *
1739
   * @param label The new "label" property
1740
   *
1741
   * @deprecated use <code>setText(text)</code>
1742
   */
1743
  public void setLabel(String label)
1744
  {
1745
    setText(label);
1746
  }
1747
 
1748
  /**
1749
   * Return the button's "label" property. This property is synonymous with
1750
   * the "text" property.
1751
   *
1752
   * @return The current "label" property
1753
   *
1754
   * @deprecated use <code>getText()</code>
1755
   */
1756
  public String getLabel()
1757
  {
1758
    return getText();
1759
  }
1760
 
1761
  /**
1762
   * Set the button's "text" property. This property is synonymous with the
1763
   * "label" property.
1764
   *
1765
   * @param t The new "text" property
1766
   */
1767
  public void setText(String t)
1768
  {
1769
    if (text == t)
1770
      return;
1771
 
1772
    String old = text;
1773
    text = t;
1774
    firePropertyChange(TEXT_CHANGED_PROPERTY, old, t);
1775
    revalidate();
1776
    repaint();
1777
  }
1778
 
1779
  /**
1780
   * Set the value of the {@link #iconTextGap} property.
1781
   *
1782
   * @param i The new value of the property
1783
   *
1784
   * @since 1.4
1785
   */
1786
  public void setIconTextGap(int i)
1787
  {
1788
    clientIconTextGapSet = true;
1789
    if (iconTextGap == i)
1790
      return;
1791
 
1792
    int old = iconTextGap;
1793
    iconTextGap = i;
1794
    firePropertyChange("iconTextGap", new Integer(old), new Integer(i));
1795
    revalidate();
1796
    repaint();
1797
  }
1798
 
1799
  /**
1800
   * Get the value of the {@link #iconTextGap} property.
1801
   *
1802
   * @return The current value of the property
1803
   *
1804
   * @since 1.4
1805
   */
1806
  public int getIconTextGap()
1807
  {
1808
    return iconTextGap;
1809
  }
1810
 
1811
  /**
1812
   * Return the button's "margin" property, which is an {@link Insets} object
1813
   * describing the distance between the button's border and its text and
1814
   * icon.
1815
   *
1816
   * @return The current "margin" property
1817
   */
1818
  public Insets getMargin()
1819
  {
1820
    return margin;
1821
  }
1822
 
1823
  /**
1824
   * Set the button's "margin" property, which is an {@link Insets} object
1825
   * describing the distance between the button's border and its text and
1826
   * icon.
1827
   *
1828
   * @param m The new "margin" property
1829
   */
1830
  public void setMargin(Insets m)
1831
  {
1832
    if (margin == m)
1833
      return;
1834
 
1835
    Insets old = margin;
1836
    margin = m;
1837
    firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);
1838
    revalidate();
1839
    repaint();
1840
  }
1841
 
1842
  /**
1843
   * Return the button's "pressedIcon" property. The look and feel class
1844
   * should paint this icon when the "pressed" property of the button's
1845
   * {@link ButtonModel} is <code>true</code>. This property may be
1846
   * <code>null</code>, in which case the default icon is used.
1847
   *
1848
   * @return The current "pressedIcon" property
1849
   */
1850
  public Icon getPressedIcon()
1851
  {
1852
    return pressed_icon;
1853
  }
1854
 
1855
  /**
1856
   * Set the button's "pressedIcon" property. The look and feel class
1857
   * should paint this icon when the "pressed" property of the button's
1858
   * {@link ButtonModel} is <code>true</code>. This property may be
1859
   * <code>null</code>, in which case the default icon is used.
1860
   *
1861
   * @param pressedIcon The new "pressedIcon" property
1862
   */
1863
  public void setPressedIcon(Icon pressedIcon)
1864
  {
1865
    if (pressed_icon == pressedIcon)
1866
      return;
1867
 
1868
    Icon old = pressed_icon;
1869
    pressed_icon = pressedIcon;
1870
    firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, old, pressed_icon);
1871
    revalidate();
1872
    repaint();
1873
  }
1874
 
1875
  /**
1876
   * Return the button's "disabledIcon" property. The look and feel class
1877
   * should paint this icon when the "enabled" property of the button's
1878
   * {@link ButtonModel} is <code>false</code>. This property may be
1879
   * <code>null</code>, in which case an icon is constructed, based on the
1880
   * default icon.
1881
   *
1882
   * @return The current "disabledIcon" property
1883
   */
1884
  public Icon getDisabledIcon()
1885
  {
1886
    if (disabledIcon == null && default_icon instanceof ImageIcon)
1887
      {
1888
        Image iconImage = ((ImageIcon) default_icon).getImage();
1889
        Image grayImage = GrayFilter.createDisabledImage(iconImage);
1890
        disabledIcon = new ImageIcon(grayImage);
1891
      }
1892
 
1893
    return disabledIcon;
1894
  }
1895
 
1896
  /**
1897
   * Set the button's "disabledIcon" property. The look and feel class should
1898
   * paint this icon when the "enabled" property of the button's {@link
1899
   * ButtonModel} is <code>false</code>. This property may be
1900
   * <code>null</code>, in which case an icon is constructed, based on the
1901
   * default icon.
1902
   *
1903
   * @param d The new "disabledIcon" property
1904
   */
1905
  public void setDisabledIcon(Icon d)
1906
  {
1907
    if (disabledIcon == d)
1908
      return;
1909
    Icon old = disabledIcon;
1910
    disabledIcon = d;
1911
    firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, old, d);
1912
    revalidate();
1913
    repaint();
1914
  }
1915
 
1916
  /**
1917
   * Return the button's "paintFocus" property. This property controls
1918
   * whether or not the look and feel class will paint a special indicator
1919
   * of focus state for the button. If it is false, the button still paints
1920
   * when focused, but no special decoration is painted to indicate the
1921
   * presence of focus.
1922
   *
1923
   * @return The current "paintFocus" property
1924
   */
1925
  public boolean isFocusPainted()
1926
  {
1927
    return focusPainted;
1928
  }
1929
 
1930
  /**
1931
   * Set the button's "paintFocus" property. This property controls whether
1932
   * or not the look and feel class will paint a special indicator of focus
1933
   * state for the button. If it is false, the button still paints when
1934
   * focused, but no special decoration is painted to indicate the presence
1935
   * of focus.
1936
   *
1937
   * @param p The new "paintFocus" property
1938
   */
1939
  public void setFocusPainted(boolean p)
1940
  {
1941
    if (focusPainted == p)
1942
      return;
1943
 
1944
    boolean old = focusPainted;
1945
    focusPainted = p;
1946
    firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, old, p);
1947
    revalidate();
1948
    repaint();
1949
  }
1950
 
1951
  /**
1952
   * Verifies that a particular key is one of the valid constants used for
1953
   * describing horizontal alignment and positioning. The valid constants
1954
   * are the following members of {@link SwingConstants}:
1955
   * <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
1956
   * <code>LEADING</code> or <code>TRAILING</code>.
1957
   *
1958
   * @param key The key to check
1959
   * @param exception A message to include in an IllegalArgumentException
1960
   *
1961
   * @return the value of key
1962
   *
1963
   * @throws IllegalArgumentException If key is not one of the valid constants
1964
   *
1965
   * @see #setHorizontalTextPosition(int)
1966
   * @see #setHorizontalAlignment(int)
1967
   */
1968
  protected  int checkHorizontalKey(int key, String exception)
1969
  {
1970
    switch (key)
1971
      {
1972
      case SwingConstants.RIGHT:
1973
      case SwingConstants.LEFT:
1974
      case SwingConstants.CENTER:
1975
      case SwingConstants.LEADING:
1976
      case SwingConstants.TRAILING:
1977
        break;
1978
      default:
1979
        throw new IllegalArgumentException(exception);
1980
      }
1981
    return key;
1982
  }
1983
 
1984
  /**
1985
   * Verifies that a particular key is one of the valid constants used for
1986
   * describing vertical alignment and positioning. The valid constants are
1987
   * the following members of {@link SwingConstants}: <code>TOP</code>,
1988
   * <code>BOTTOM</code> or <code>CENTER</code>.
1989
   *
1990
   * @param key The key to check
1991
   * @param exception A message to include in an IllegalArgumentException
1992
   *
1993
   * @return the value of key
1994
   *
1995
   * @throws IllegalArgumentException If key is not one of the valid constants
1996
   *
1997
   * @see #setVerticalTextPosition(int)
1998
   * @see #setVerticalAlignment(int)
1999
   */
2000
  protected  int checkVerticalKey(int key, String exception)
2001
  {
2002
    switch (key)
2003
      {
2004
      case SwingConstants.TOP:
2005
      case SwingConstants.BOTTOM:
2006
      case SwingConstants.CENTER:
2007
        break;
2008
      default:
2009
        throw new IllegalArgumentException(exception);
2010
      }
2011
    return key;
2012
  }
2013
 
2014
  /**
2015
   * Configure various properties of the button by reading properties
2016
   * of an {@link Action}. The mapping of properties is as follows:
2017
   *
2018
   * <table>
2019
   *
2020
   * <tr><th>Action keyed property</th> <th>AbstractButton property</th></tr>
2021
   *
2022
   * <tr><td>NAME                 </td> <td>text                   </td></tr>
2023
   * <tr><td>SMALL_ICON           </td> <td>icon                   </td></tr>
2024
   * <tr><td>SHORT_DESCRIPTION    </td> <td>toolTipText            </td></tr>
2025
   * <tr><td>MNEMONIC_KEY         </td> <td>mnemonic               </td></tr>
2026
   * <tr><td>ACTION_COMMAND_KEY   </td> <td>actionCommand          </td></tr>
2027
   *
2028
   * </table>
2029
   *
2030
   * <p>In addition, this method always sets the button's "enabled" property to
2031
   * the value of the Action's "enabled" property.</p>
2032
   *
2033
   * <p>If the provided Action is <code>null</code>, the text, icon, and
2034
   * toolTipText properties of the button are set to <code>null</code>, and
2035
   * the "enabled" property is set to <code>true</code>; the mnemonic and
2036
   * actionCommand properties are unchanged.</p>
2037
   *
2038
   * @param a An Action to configure the button from
2039
   */
2040
  protected void configurePropertiesFromAction(Action a)
2041
  {
2042
    if (a == null)
2043
      {
2044
        setText(null);
2045
        setIcon(null);
2046
        setEnabled(true);
2047
        setToolTipText(null);
2048
      }
2049
    else
2050
      {
2051
        setText((String) (a.getValue(Action.NAME)));
2052
        setIcon((Icon) (a.getValue(Action.SMALL_ICON)));
2053
        setEnabled(a.isEnabled());
2054
        setToolTipText((String) (a.getValue(Action.SHORT_DESCRIPTION)));
2055
        if (a.getValue(Action.MNEMONIC_KEY) != null)
2056
          setMnemonic(((Integer) (a.getValue(Action.MNEMONIC_KEY))).intValue());
2057
        String actionCommand = (String) (a.getValue(Action.ACTION_COMMAND_KEY));
2058
 
2059
        // Set actionCommand to button's text by default if it is not specified
2060
        if (actionCommand != null)
2061
          setActionCommand((String) (a.getValue(Action.ACTION_COMMAND_KEY)));
2062
        else
2063
          setActionCommand(getText());
2064
      }
2065
  }
2066
 
2067
  /**
2068
   * <p>A factory method which should return an {@link ActionListener} that
2069
   * propagates events from the button's {@link ButtonModel} to any of the
2070
   * button's ActionListeners. By default, this is an inner class which
2071
   * calls {@link AbstractButton#fireActionPerformed} with a modified copy
2072
   * of the incoming model {@link ActionEvent}.</p>
2073
   *
2074
   * <p>The button calls this method during construction, stores the
2075
   * resulting ActionListener in its <code>actionListener</code> member
2076
   * field, and subscribes it to the button's model. If the button's model
2077
   * is changed, this listener is unsubscribed from the old model and
2078
   * subscribed to the new one.</p>
2079
   *
2080
   * @return A new ActionListener
2081
   */
2082
  protected  ActionListener createActionListener()
2083
  {
2084
    return getEventHandler();
2085
  }
2086
 
2087
  /**
2088
   * <p>A factory method which should return a {@link PropertyChangeListener}
2089
   * that accepts changes to the specified {@link Action} and reconfigure
2090
   * the {@link AbstractButton}, by default using the {@link
2091
   * #configurePropertiesFromAction} method.</p>
2092
   *
2093
   * <p>The button calls this method whenever a new Action is assigned to
2094
   * the button's "action" property, via {@link #setAction}, and stores the
2095
   * resulting PropertyChangeListener in its
2096
   * <code>actionPropertyChangeListener</code> member field. The button
2097
   * then subscribes the listener to the button's new action. If the
2098
   * button's action is changed subsequently, the listener is unsubscribed
2099
   * from the old action and subscribed to the new one.</p>
2100
   *
2101
   * @param a The Action which will be listened to, and which should be
2102
   * the same as the source of any PropertyChangeEvents received by the
2103
   * new listener returned from this method.
2104
   *
2105
   * @return A new PropertyChangeListener
2106
   */
2107
  protected  PropertyChangeListener createActionPropertyChangeListener(Action a)
2108
  {
2109
    return new PropertyChangeListener()
2110
      {
2111
        public void propertyChange(PropertyChangeEvent e)
2112
        {
2113
          Action act = (Action) (e.getSource());
2114
          if (e.getPropertyName().equals("enabled"))
2115
            setEnabled(act.isEnabled());
2116
          else if (e.getPropertyName().equals(Action.NAME))
2117
            setText((String) (act.getValue(Action.NAME)));
2118
          else if (e.getPropertyName().equals(Action.SMALL_ICON))
2119
            setIcon((Icon) (act.getValue(Action.SMALL_ICON)));
2120
          else if (e.getPropertyName().equals(Action.SHORT_DESCRIPTION))
2121
            setToolTipText((String) (act.getValue(Action.SHORT_DESCRIPTION)));
2122
          else if (e.getPropertyName().equals(Action.MNEMONIC_KEY))
2123
            if (act.getValue(Action.MNEMONIC_KEY) != null)
2124
              setMnemonic(((Integer) (act.getValue(Action.MNEMONIC_KEY)))
2125
                          .intValue());
2126
          else if (e.getPropertyName().equals(Action.ACTION_COMMAND_KEY))
2127
            setActionCommand((String) (act.getValue(Action.ACTION_COMMAND_KEY)));
2128
        }
2129
      };
2130
  }
2131
 
2132
  /**
2133
   * <p>Factory method which creates a {@link ChangeListener}, used to
2134
   * subscribe to ChangeEvents from the button's model. Subclasses of
2135
   * AbstractButton may wish to override the listener used to subscribe to
2136
   * such ChangeEvents. By default, the listener just propagates the
2137
   * {@link ChangeEvent} to the button's ChangeListeners, via the {@link
2138
   * AbstractButton#fireStateChanged} method.</p>
2139
   *
2140
   * <p>The button calls this method during construction, stores the
2141
   * resulting ChangeListener in its <code>changeListener</code> member
2142
   * field, and subscribes it to the button's model. If the button's model
2143
   * is changed, this listener is unsubscribed from the old model and
2144
   * subscribed to the new one.</p>
2145
   *
2146
   * @return The new ChangeListener
2147
   */
2148
  protected ChangeListener createChangeListener()
2149
  {
2150
    return getEventHandler();
2151
  }
2152
 
2153
  /**
2154
   * <p>Factory method which creates a {@link ItemListener}, used to
2155
   * subscribe to ItemEvents from the button's model. Subclasses of
2156
   * AbstractButton may wish to override the listener used to subscribe to
2157
   * such ItemEvents. By default, the listener just propagates the
2158
   * {@link ItemEvent} to the button's ItemListeners, via the {@link
2159
   * AbstractButton#fireItemStateChanged} method.</p>
2160
   *
2161
   * <p>The button calls this method during construction, stores the
2162
   * resulting ItemListener in its <code>changeListener</code> member
2163
   * field, and subscribes it to the button's model. If the button's model
2164
   * is changed, this listener is unsubscribed from the old model and
2165
   * subscribed to the new one.</p>
2166
   *
2167
   * <p>Note that ItemEvents are only generated from the button's model
2168
   * when the model's <em>selected</em> property changes. If you want to
2169
   * subscribe to other properties of the model, you must subscribe to
2170
   * ChangeEvents.
2171
   *
2172
   * @return The new ItemListener
2173
   */
2174
  protected  ItemListener createItemListener()
2175
  {
2176
    return getEventHandler();
2177
  }
2178
 
2179
  /**
2180
   * Programmatically perform a "click" on the button: arming, pressing,
2181
   * waiting, un-pressing, and disarming the model.
2182
   */
2183
  public void doClick()
2184
  {
2185
    doClick(100);
2186
  }
2187
 
2188
  /**
2189
   * Programmatically perform a "click" on the button: arming, pressing,
2190
   * waiting, un-pressing, and disarming the model.
2191
   *
2192
   * @param pressTime The number of milliseconds to wait in the pressed state
2193
   */
2194
  public void doClick(int pressTime)
2195
  {
2196
    ButtonModel mod = getModel();
2197
    if (mod != null)
2198
      {
2199
        mod.setArmed(true);
2200
        mod.setPressed(true);
2201
        try
2202
          {
2203
            java.lang.Thread.sleep(pressTime);
2204
          }
2205
        catch (java.lang.InterruptedException e)
2206
          {
2207
            // probably harmless
2208
          }
2209
        mod.setPressed(false);
2210
        mod.setArmed(false);
2211
      }
2212
  }
2213
 
2214
  /**
2215
   * Return the button's disabled selected icon. The look and feel class
2216
   * should paint this icon when the "enabled" property of the button's model
2217
   * is <code>false</code> and its "selected" property is
2218
   * <code>true</code>. This icon can be <code>null</code>, in which case
2219
   * it is synthesized from the button's selected icon.
2220
   *
2221
   * @return The current disabled selected icon
2222
   */
2223
  public Icon getDisabledSelectedIcon()
2224
  {
2225
    return disabledSelectedIcon;
2226
  }
2227
 
2228
  /**
2229
   * Set the button's disabled selected icon. The look and feel class
2230
   * should paint this icon when the "enabled" property of the button's model
2231
   * is <code>false</code> and its "selected" property is
2232
   * <code>true</code>. This icon can be <code>null</code>, in which case
2233
   * it is synthesized from the button's selected icon.
2234
   *
2235
   * @param icon The new disabled selected icon
2236
   */
2237
  public void setDisabledSelectedIcon(Icon icon)
2238
  {
2239
    if (disabledSelectedIcon == icon)
2240
      return;
2241
 
2242
    Icon old = disabledSelectedIcon;
2243
    disabledSelectedIcon = icon;
2244
    firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, old, icon);
2245
    revalidate();
2246
    repaint();
2247
  }
2248
 
2249
  /**
2250
   * Return the button's rollover icon. The look and feel class should
2251
   * paint this icon when the "rolloverEnabled" property of the button is
2252
   * <code>true</code> and the mouse rolls over the button.
2253
   *
2254
   * @return The current rollover icon
2255
   */
2256
  public Icon getRolloverIcon()
2257
  {
2258
    return rolloverIcon;
2259
  }
2260
 
2261
  /**
2262
   * Set the button's rollover icon and sets the <code>rolloverEnabled</code>
2263
   * property to <code>true</code>. The look and feel class should
2264
   * paint this icon when the "rolloverEnabled" property of the button is
2265
   * <code>true</code> and the mouse rolls over the button.
2266
   *
2267
   * @param r The new rollover icon
2268
   */
2269
  public void setRolloverIcon(Icon r)
2270
  {
2271
    if (rolloverIcon == r)
2272
      return;
2273
 
2274
    Icon old = rolloverIcon;
2275
    rolloverIcon = r;
2276
    firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, old, rolloverIcon);
2277
    setRolloverEnabled(true);
2278
    revalidate();
2279
    repaint();
2280
  }
2281
 
2282
  /**
2283
   * Return the button's rollover selected icon. The look and feel class
2284
   * should paint this icon when the "rolloverEnabled" property of the button
2285
   * is <code>true</code>, the "selected" property of the button's model is
2286
   * <code>true</code>, and the mouse rolls over the button.
2287
   *
2288
   * @return The current rollover selected icon
2289
   */
2290
  public Icon getRolloverSelectedIcon()
2291
  {
2292
    return rolloverSelectedIcon;
2293
  }
2294
 
2295
  /**
2296
   * Set the button's rollover selected icon and sets the
2297
   * <code>rolloverEnabled</code> property to <code>true</code>. The look and
2298
   * feel class should paint this icon when the "rolloverEnabled" property of
2299
   * the button is <code>true</code>, the "selected" property of the button's
2300
   * model is <code>true</code>, and the mouse rolls over the button.
2301
   *
2302
   * @param r The new rollover selected icon.
2303
   */
2304
  public void setRolloverSelectedIcon(Icon r)
2305
  {
2306
    if (rolloverSelectedIcon == r)
2307
      return;
2308
 
2309
    Icon old = rolloverSelectedIcon;
2310
    rolloverSelectedIcon = r;
2311
    firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, old, r);
2312
    setRolloverEnabled(true);
2313
    revalidate();
2314
    repaint();
2315
  }
2316
 
2317
  /**
2318
   * Return the button's selected icon. The look and feel class should
2319
   * paint this icon when the "selected" property of the button's model is
2320
   * <code>true</code>, and either the "rolloverEnabled" property of the
2321
   * button is <code>false</code> or the mouse is not currently rolled
2322
   * over the button.
2323
   *
2324
   * @return The current selected icon
2325
   */
2326
  public Icon getSelectedIcon()
2327
  {
2328
    return selectedIcon;
2329
  }
2330
 
2331
  /**
2332
   * Set the button's selected icon. The look and feel class should
2333
   * paint this icon when the "selected" property of the button's model is
2334
   * <code>true</code>, and either the "rolloverEnabled" property of the
2335
   * button is <code>false</code> or the mouse is not currently rolled
2336
   * over the button.
2337
   *
2338
   * @param s The new selected icon
2339
   */
2340
  public void setSelectedIcon(Icon s)
2341
  {
2342
    if (selectedIcon == s)
2343
      return;
2344
 
2345
    Icon old = selectedIcon;
2346
    selectedIcon = s;
2347
    firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, old, s);
2348
    revalidate();
2349
    repaint();
2350
  }
2351
 
2352
  /**
2353
   * Returns an single-element array containing the "text" property of the
2354
   * button if the "selected" property of the button's model is
2355
   * <code>true</code>, otherwise returns <code>null</code>.
2356
   *
2357
   * @return The button's "selected object" array
2358
   */
2359
  public Object[] getSelectedObjects()
2360
  {
2361
    if (isSelected())
2362
      {
2363
        Object[] objs = new Object[1];
2364
        objs[0] = getText();
2365
        return objs;
2366
      }
2367
    else
2368
      {
2369
        return null;
2370
      }
2371
  }
2372
 
2373
  /**
2374
   * Called when image data becomes available for one of the button's icons.
2375
   *
2376
   * @param img The image being updated
2377
   * @param infoflags One of the constant codes in {@link ImageObserver} used
2378
   *     to describe updated portions of an image.
2379
   * @param x X coordinate of the region being updated
2380
   * @param y Y coordinate of the region being updated
2381
   * @param w Width of the region beign updated
2382
   * @param h Height of the region being updated
2383
   *
2384
   * @return <code>true</code> if img is equal to the button's current icon,
2385
   *     otherwise <code>false</code>
2386
   */
2387
  public boolean imageUpdate(Image img, int infoflags, int x, int y, int w,
2388
                             int h)
2389
  {
2390
    return current_icon == img;
2391
  }
2392
 
2393
  /**
2394
   * Returns the value of the button's "contentAreaFilled" property. This
2395
   * property indicates whether the area surrounding the text and icon of
2396
   * the button should be filled by the look and feel class.  If this
2397
   * property is <code>false</code>, the look and feel class should leave
2398
   * the content area transparent.
2399
   *
2400
   * @return The current value of the "contentAreaFilled" property
2401
   */
2402
  public boolean isContentAreaFilled()
2403
  {
2404
    return contentAreaFilled;
2405
  }
2406
 
2407
  /**
2408
   * Sets the value of the button's "contentAreaFilled" property. This
2409
   * property indicates whether the area surrounding the text and icon of
2410
   * the button should be filled by the look and feel class.  If this
2411
   * property is <code>false</code>, the look and feel class should leave
2412
   * the content area transparent.
2413
   *
2414
   * @param b The new value of the "contentAreaFilled" property
2415
   */
2416
  public void setContentAreaFilled(boolean b)
2417
  {
2418
    clientContentAreaFilledSet = true;
2419
    if (contentAreaFilled == b)
2420
      return;
2421
 
2422
    // The JDK sets the opaque property to the value of the contentAreaFilled
2423
    // property, so should we do.
2424
    setOpaque(b);
2425
    boolean old = contentAreaFilled;
2426
    contentAreaFilled = b;
2427
    firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, old, b);
2428
   }
2429
 
2430
  /**
2431
   * Paints the button's border, if the button's "borderPainted" property is
2432
   * <code>true</code>, by out calling to the button's look and feel class.
2433
   *
2434
   * @param g The graphics context used to paint the border
2435
   */
2436
  protected void paintBorder(Graphics g)
2437
  {
2438
    if (isBorderPainted())
2439
      super.paintBorder(g);
2440
  }
2441
 
2442
  /**
2443
   * Returns a string, used only for debugging, which identifies or somehow
2444
   * represents this button. The exact value is implementation-defined.
2445
   *
2446
   * @return A string representation of the button
2447
   */
2448
  protected String paramString()
2449
  {
2450
    CPStringBuilder sb = new CPStringBuilder();
2451
    sb.append(super.paramString());
2452
    sb.append(",defaultIcon=");
2453
    if (getIcon() != null)
2454
      sb.append(getIcon());
2455
    sb.append(",disabledIcon=");
2456
    if (getDisabledIcon() != null)
2457
      sb.append(getDisabledIcon());
2458
    sb.append(",disabledSelectedIcon=");
2459
    if (getDisabledSelectedIcon() != null)
2460
      sb.append(getDisabledSelectedIcon());
2461
    sb.append(",margin=");
2462
    if (getMargin() != null)
2463
      sb.append(getMargin());
2464
    sb.append(",paintBorder=").append(isBorderPainted());
2465
    sb.append(",paintFocus=").append(isFocusPainted());
2466
    sb.append(",pressedIcon=");
2467
    if (getPressedIcon() != null)
2468
      sb.append(getPressedIcon());
2469
    sb.append(",rolloverEnabled=").append(isRolloverEnabled());
2470
    sb.append(",rolloverIcon=");
2471
    if (getRolloverIcon() != null)
2472
      sb.append(getRolloverIcon());
2473
    sb.append(",rolloverSelected=");
2474
    if (getRolloverSelectedIcon() != null)
2475
      sb.append(getRolloverSelectedIcon());
2476
    sb.append(",selectedIcon=");
2477
    if (getSelectedIcon() != null)
2478
      sb.append(getSelectedIcon());
2479
    sb.append(",text=");
2480
    if (getText() != null)
2481
      sb.append(getText());
2482
    return sb.toString();
2483
  }
2484
 
2485
  /**
2486
   * Set the "UI" property of the button, which is a look and feel class
2487
   * responsible for handling the button's input events and painting it.
2488
   *
2489
   * @param ui The new "UI" property
2490
   */
2491
  public void setUI(ButtonUI ui)
2492
  {
2493
    super.setUI(ui);
2494
  }
2495
 
2496
  /**
2497
   * Set the "UI" property of the button, which is a look and feel class
2498
   * responsible for handling the button's input events and painting it.
2499
   *
2500
   * @return The current "UI" property
2501
   */
2502
  public ButtonUI getUI()
2503
  {
2504
    return (ButtonUI) ui;
2505
  }
2506
 
2507
  /**
2508
   * Set the "UI" property to a class constructed, via the {@link
2509
   * UIManager}, from the current look and feel. This should be overridden
2510
   * for each subclass of AbstractButton, to retrieve a suitable {@link
2511
   * ButtonUI} look and feel class.
2512
   */
2513
  public void updateUI()
2514
  {
2515
    // TODO: What to do here?
2516
  }
2517
 
2518
  /**
2519
   * Returns the current time in milliseconds in which clicks gets coalesced
2520
   * into a single <code>ActionEvent</code>.
2521
   *
2522
   * @return the time in milliseconds
2523
   *
2524
   * @since 1.4
2525
   */
2526
  public long getMultiClickThreshhold()
2527
  {
2528
    return multiClickThreshhold;
2529
  }
2530
 
2531
  /**
2532
   * Sets the time in milliseconds in which clicks gets coalesced into a single
2533
   * <code>ActionEvent</code>.
2534
   *
2535
   * @param threshhold the time in milliseconds
2536
   *
2537
   * @since 1.4
2538
   */
2539
  public void setMultiClickThreshhold(long threshhold)
2540
  {
2541
    if (threshhold < 0)
2542
      throw new IllegalArgumentException();
2543
 
2544
    multiClickThreshhold = threshhold;
2545
  }
2546
 
2547
  /**
2548
   * Adds the specified component to this AbstractButton. This overrides the
2549
   * default in order to install an {@link OverlayLayout} layout manager
2550
   * before adding the component. The layout manager is only installed if
2551
   * no other layout manager has been installed before.
2552
   *
2553
   * @param comp the component to be added
2554
   * @param constraints constraints for the layout manager
2555
   * @param index the index at which the component is added
2556
   *
2557
   * @since 1.5
2558
   */
2559
  protected void addImpl(Component comp, Object constraints, int index)
2560
  {
2561
    // We use a client property here, so that no extra memory is used in
2562
    // the common case with no layout manager.
2563
    if (getClientProperty("AbstractButton.customLayoutSet") == null)
2564
      setLayout(new OverlayLayout(this));
2565
    super.addImpl(comp, constraints, index);
2566
  }
2567
 
2568
  /**
2569
   * Sets a layout manager on this AbstractButton. This is overridden in order
2570
   * to detect if the application sets a custom layout manager. If no custom
2571
   * layout manager is set, {@link #addImpl(Component, Object, int)} installs
2572
   * an OverlayLayout before adding a component.
2573
   *
2574
   * @param layout the layout manager to install
2575
   *
2576
   * @since 1.5
2577
   */
2578
  public void setLayout(LayoutManager layout)
2579
  {
2580
    // We use a client property here, so that no extra memory is used in
2581
    // the common case with no layout manager.
2582
    putClientProperty("AbstractButton.customLayoutSet", Boolean.TRUE);
2583
    super.setLayout(layout);
2584
  }
2585
 
2586
  /**
2587
   * Helper method for
2588
   * {@link LookAndFeel#installProperty(JComponent, String, Object)}.
2589
   *
2590
   * @param propertyName the name of the property
2591
   * @param value the value of the property
2592
   *
2593
   * @throws IllegalArgumentException if the specified property cannot be set
2594
   *         by this method
2595
   * @throws ClassCastException if the property value does not match the
2596
   *         property type
2597
   * @throws NullPointerException if <code>c</code> or
2598
   *         <code>propertyValue</code> is <code>null</code>
2599
   */
2600
  void setUIProperty(String propertyName, Object value)
2601
  {
2602
    if (propertyName.equals("borderPainted"))
2603
      {
2604
        if (! clientBorderPaintedSet)
2605
          {
2606
            setBorderPainted(((Boolean) value).booleanValue());
2607
            clientBorderPaintedSet = false;
2608
          }
2609
      }
2610
    else if (propertyName.equals("rolloverEnabled"))
2611
      {
2612
        if (! clientRolloverEnabledSet)
2613
          {
2614
            setRolloverEnabled(((Boolean) value).booleanValue());
2615
            clientRolloverEnabledSet = false;
2616
          }
2617
      }
2618
    else if (propertyName.equals("iconTextGap"))
2619
      {
2620
        if (! clientIconTextGapSet)
2621
          {
2622
            setIconTextGap(((Integer) value).intValue());
2623
            clientIconTextGapSet = false;
2624
          }
2625
      }
2626
    else if (propertyName.equals("contentAreaFilled"))
2627
      {
2628
        if (! clientContentAreaFilledSet)
2629
          {
2630
            setContentAreaFilled(((Boolean) value).booleanValue());
2631
            clientContentAreaFilledSet = false;
2632
          }
2633
      }
2634
    else
2635
      {
2636
        super.setUIProperty(propertyName, value);
2637
      }
2638
  }
2639
 
2640
  /**
2641
   * Returns the combined event handler. The instance is created if
2642
   * necessary.
2643
   *
2644
   * @return the combined event handler
2645
   */
2646
  EventHandler getEventHandler()
2647
  {
2648
    if (eventHandler == null)
2649
      eventHandler = new EventHandler();
2650
    return eventHandler;
2651
  }
2652
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.