OSDN Git Service

2005-04-19 Roman Kennke <roman@kennke.org>
[pf3gnuchains/gcc-fork.git] / libjava / javax / swing / AbstractButton.java
1 /* AbstractButton.java -- Provides basic button functionality.
2    Copyright (C) 2002, 2004 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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 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 java.awt.Graphics;
41 import java.awt.Image;
42 import java.awt.Insets;
43 import java.awt.ItemSelectable;
44 import java.awt.Point;
45 import java.awt.Rectangle;
46 import java.awt.event.ActionEvent;
47 import java.awt.event.ActionListener;
48 import java.awt.event.ItemEvent;
49 import java.awt.event.ItemListener;
50 import java.beans.PropertyChangeEvent;
51 import java.beans.PropertyChangeListener;
52
53 import javax.accessibility.AccessibleAction;
54 import javax.accessibility.AccessibleIcon;
55 import javax.accessibility.AccessibleRelationSet;
56 import javax.accessibility.AccessibleStateSet;
57 import javax.accessibility.AccessibleText;
58 import javax.accessibility.AccessibleValue;
59 import javax.swing.event.ChangeEvent;
60 import javax.swing.event.ChangeListener;
61 import javax.swing.plaf.ButtonUI;
62 import javax.swing.text.AttributeSet;
63
64
65 /**
66  * <p>The purpose of this class is to serve as a facade over a number of
67  * classes which collectively represent the semantics of a button: the
68  * button's model, its listeners, its action, and its look and feel. Some
69  * parts of a button's state are stored explicitly in this class, other
70  * parts are delegates to the model. Some methods related to buttons are
71  * implemented in this class, other methods pass through to the current 
72  * model or look and feel.</p>
73  *
74  * <p>Furthermore this class is supposed to serve as a base class for
75  * several kinds of buttons with similar but non-identical semantics:
76  * toggle buttons (radio buttons and checkboxes), simple "push" buttons,
77  * menu items.</p>
78  *
79  * <p>Buttons have many properties, some of which are stored in this class
80  * while others are delegated to the button's model. The following properties
81  * are available:</p>
82  *
83  * <table>
84  * <tr><th>Property               </th><th>Stored in</th><th>Bound?</th></tr>
85  *
86  * <tr><td>action                 </td><td>button</td> <td>no</td></tr>
87  * <tr><td>actionCommand          </td><td>model</td>  <td>no</td></tr>
88  * <tr><td>borderPainted          </td><td>button</td> <td>yes</td></tr>
89  * <tr><td>contentAreaFilled      </td><td>button</td> <td>yes</td></tr>
90  * <tr><td>disabledIcon           </td><td>button</td> <td>yes</td></tr>
91  * <tr><td>disabledSelectedIcon   </td><td>button</td> <td>yes</td></tr>
92  * <tr><td>displayedMnemonicIndex </td><td>button</td> <td>no</td></tr>
93  * <tr><td>enabled                </td><td>model</td>  <td>no</td></tr>
94  * <tr><td>focusPainted           </td><td>button</td> <td>yes</td></tr>
95  * <tr><td>horizontalAlignment    </td><td>button</td> <td>yes</td></tr>
96  * <tr><td>horizontalTextPosition </td><td>button</td> <td>yes</td></tr>
97  * <tr><td>icon                   </td><td>button</td> <td>yes</td></tr>
98  * <tr><td>iconTextGap            </td><td>button</td> <td>no</td></tr>
99  * <tr><td>label (same as text)   </td><td>model</td>  <td>yes</td></tr>
100  * <tr><td>margin                 </td><td>button</td> <td>yes</td></tr>
101  * <tr><td>multiClickThreshold    </td><td>button</td> <td>no</td></tr>
102  * <tr><td>pressedIcon            </td><td>button</td> <td>yes</td></tr>
103  * <tr><td>rolloverEnabled        </td><td>button</td> <td>yes</td></tr>
104  * <tr><td>rolloverIcon           </td><td>button</td> <td>yes</td></tr>
105  * <tr><td>rolloverSelectedIcon   </td><td>button</td> <td>yes</td></tr>
106  * <tr><td>selected               </td><td>model</td>  <td>no</td></tr>
107  * <tr><td>selectedIcon           </td><td>button</td> <td>yes</td></tr>
108  * <tr><td>selectedObjects        </td><td>button</td> <td>no</td></tr>
109  * <tr><td>text                   </td><td>model</td>  <td>yes</td></tr>
110  * <tr><td>UI                     </td><td>button</td> <td>yes</td></tr>
111  * <tr><td>verticalAlignment      </td><td>button</td> <td>yes</td></tr>
112  * <tr><td>verticalTextPosition   </td><td>button</td> <td>yes</td></tr>
113  *
114  * </table>
115  *
116  * <p>The various behavioral aspects of these properties follows:</p>
117  *
118  * <ul> 
119  *
120  * <li>When non-bound properties stored in the button change, the button
121  * fires ChangeEvents to its ChangeListeners.</li>
122  * 
123  * <li>When bound properties stored in the button change, the button fires
124  * PropertyChangeEvents to its PropertyChangeListeners</li>
125  *
126  * <li>If any of the model's properties change, it fires a ChangeEvent to
127  * its ChangeListeners, which include the button.</li>
128  *
129  * <li>If the button receives a ChangeEvent from its model, it will
130  * propagate the ChangeEvent to its ChangeListeners, with the ChangeEvent's
131  * "source" property set to refer to the button, rather than the model. The
132  * the button will request a repaint, to paint its updated state.</li>
133  *
134  * <li>If the model's "selected" property changes, the model will fire an
135  * ItemEvent to its ItemListeners, which include the button, in addition to
136  * the ChangeEvent which models the property change. The button propagates
137  * ItemEvents directly to its ItemListeners.</li>
138  *
139  * <li>If the model's armed and pressed properties are simultaneously
140  * <code>true</code>, the model will fire an ActionEvent to its
141  * ActionListeners, which include the button. The button will propagate
142  * this ActionEvent to its ActionListeners, with the ActionEvent's "source"
143  * property set to refer to the button, rather than the model.</li>
144  *
145  * </ul>
146  *
147  * @author Ronald Veldema (rveldema@cs.vu.nl)
148  * @author Graydon Hoare (graydon@redhat.com)
149  */
150
151 public abstract class AbstractButton extends JComponent
152   implements ItemSelectable, SwingConstants
153 {
154   private static final long serialVersionUID = -937921345538462020L;
155   
156   /** The icon displayed by default. */
157   Icon default_icon;
158
159   /** The icon displayed when the button is pressed. */
160   Icon pressed_icon;
161
162   /** The icon displayed when the button is disabled. */
163   Icon disabeldIcon;
164
165   /** The icon displayed when the button is selected. */
166   Icon selectedIcon;
167
168   /** The icon displayed when the button is selected but disabled. */
169   Icon disabledSelectedIcon;
170
171   /** The icon displayed when the button is rolled over. */
172   Icon rolloverIcon;
173
174   /** The icon displayed when the button is selected and rolled over. */
175   Icon rolloverSelectedIcon;
176
177   /** The icon currently displayed. */
178   Icon current_icon;
179
180   /** The text displayed in the button. */
181   String text;
182
183   /** The gap between icon and text, if both icon and text are non-<code>null</code>. */
184   int iconTextGap;
185
186   /** The vertical alignment of the button's text and icon. */
187   int verticalAlignment;
188
189   /** The horizontal alignment of the button's text and icon. */
190   int horizontalAlignment;
191
192   /** The horizontal position of the button's text relative to its icon. */
193   int horizontalTextPosition;
194
195   /** The vertical position of the button's text relative to its icon. */
196   int verticalTextPosition;
197
198   /** Whether or not the button paints its border. */
199   boolean borderPainted;
200
201   /** Whether or not the button paints its focus state. */
202   boolean focusPainted;
203
204   /** Whether or not the button fills its content area. */
205   boolean contentAreaFilled;
206   
207   /** Whether rollover is enabled. */
208   boolean rollOverEnabled;
209
210   /** The action taken when the button is clicked. */
211   Action action;
212
213   /** The button's current state. */
214   protected ButtonModel model;
215
216   /** The margin between the button's border and its label. */
217   Insets margin;
218
219   /** A hint to the look and feel class, suggesting which character in the
220    * button's label should be underlined when drawing the label. */
221   int mnemonicIndex;
222
223   /** Listener the button uses to receive ActionEvents from its model.  */
224   protected ActionListener actionListener;
225
226   /** Listener the button uses to receive ItemEvents from its model.  */
227   protected ItemListener itemListener;
228
229   /** Listener the button uses to receive ChangeEvents from its model.  */  
230   protected ChangeListener changeListener;
231
232   /** The time in miliseconds in which clicks get coalesced into a single
233    * <code>ActionEvent</code>. */
234   long multiClickThreshhold;
235   
236   /** Listener the button uses to receive PropertyChangeEvents from its
237       Action. */
238   PropertyChangeListener actionPropertyChangeListener;
239   
240   /** ChangeEvent that is fired to button's ChangeEventListeners  */  
241   protected ChangeEvent changeEvent = new ChangeEvent(this);
242   
243   /** Fired in a PropertyChangeEvent when the "borderPainted" property changes. */
244   public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";
245   
246   /** Fired in a PropertyChangeEvent when the "contentAreaFilled" property changes. */
247   public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled";
248   
249   /** Fired in a PropertyChangeEvent when the "disabledIcon" property changes. */
250   public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";
251   
252   /** Fired in a PropertyChangeEvent when the "disabledSelectedIcon" property changes. */
253   public static final String DISABLED_SELECTED_ICON_CHANGED_PROPERTY = "disabledSelectedIcon";
254   
255   /** Fired in a PropertyChangeEvent when the "focusPainted" property changes. */
256   public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
257
258   /** Fired in a PropertyChangeEvent when the "horizontalAlignment" property changes. */
259   public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = "horizontalAlignment";
260
261   /** Fired in a PropertyChangeEvent when the "horizontalTextPosition" property changes. */
262   public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = "horizontalTextPosition";
263
264   /** Fired in a PropertyChangeEvent when the "icon" property changes. */
265   public static final String ICON_CHANGED_PROPERTY = "icon";
266
267   /** Fired in a PropertyChangeEvent when the "margin" property changes. */
268   public static final String MARGIN_CHANGED_PROPERTY = "margin";
269
270   /** Fired in a PropertyChangeEvent when the "mnemonic" property changes. */
271   public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic";
272
273   /** Fired in a PropertyChangeEvent when the "model" property changes. */
274   public static final String MODEL_CHANGED_PROPERTY = "model";
275
276   /** Fired in a PropertyChangeEvent when the "pressedIcon" property changes. */
277   public static final String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";
278
279   /** Fired in a PropertyChangeEvent when the "rolloverEnabled" property changes. */
280   public static final String ROLLOVER_ENABLED_CHANGED_PROPERTY = "rolloverEnabled";
281
282   /** Fired in a PropertyChangeEvent when the "rolloverIcon" property changes. */
283   public static final String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";
284   
285   /** Fired in a PropertyChangeEvent when the "rolloverSelectedIcon" property changes. */
286   public static final String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = "rolloverSelectedIcon";
287   
288   /** Fired in a PropertyChangeEvent when the "selectedIcon" property changes. */
289   public static final String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";
290
291   /** Fired in a PropertyChangeEvent when the "text" property changes. */
292   public static final String TEXT_CHANGED_PROPERTY = "text";
293
294   /** Fired in a PropertyChangeEvent when the "verticalAlignment" property changes. */
295   public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";
296
297   /** Fired in a PropertyChangeEvent when the "verticalTextPosition" property changes. */
298   public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = "verticalTextPosition";
299
300   /**
301    * A Java Accessibility extension of the AbstractButton.
302    */
303   protected abstract class AccessibleAbstractButton
304     extends AccessibleJComponent implements AccessibleAction, AccessibleValue,
305                                             AccessibleText
306   {
307     private static final long serialVersionUID = -5673062525319836790L;
308     
309     protected AccessibleAbstractButton()
310     {
311     }
312
313     public AccessibleStateSet getAccessibleStateSet()
314     {
315       return null; // TODO
316     }
317
318     public String getAccessibleName()
319     {
320       return null; // TODO
321     }
322
323     public AccessibleIcon[] getAccessibleIcon()
324     {
325       return null; // TODO
326     }
327
328     public AccessibleRelationSet getAccessibleRelationSet()
329     {
330       return null; // TODO
331     }
332
333     public AccessibleAction getAccessibleAction()
334     {
335       return null; // TODO
336     }
337
338     public AccessibleValue getAccessibleValue()
339     {
340       return null; // TODO
341     }
342
343     public int getAccessibleActionCount()
344     {
345       return 0; // TODO
346     }
347
348     public String getAccessibleActionDescription(int value0)
349     {
350       return null; // TODO
351     }
352
353     public boolean doAccessibleAction(int value0)
354     {
355       return false; // TODO
356     }
357
358     public Number getCurrentAccessibleValue()
359     {
360       return null; // TODO
361     }
362
363     public boolean setCurrentAccessibleValue(Number value0)
364     {
365       return false; // TODO
366     }
367
368     public Number getMinimumAccessibleValue()
369     {
370       return null; // TODO
371     }
372
373     public Number getMaximumAccessibleValue()
374     {
375       return null; // TODO
376     }
377
378     public AccessibleText getAccessibleText()
379     {
380       return null; // TODO
381     }
382
383     public int getIndexAtPoint(Point value0)
384     {
385       return 0; // TODO
386     }
387
388     public Rectangle getCharacterBounds(int value0)
389     {
390       return null; // TODO
391     }
392
393     public int getCharCount()
394     {
395       return 0; // TODO
396     }
397
398     public int getCaretPosition()
399     {
400       return 0; // TODO
401     }
402
403     public String getAtIndex(int value0, int value1)
404     {
405       return null; // TODO
406     }
407
408     public String getAfterIndex(int value0, int value1)
409     {
410       return null; // TODO
411     }
412
413     public String getBeforeIndex(int value0, int value1)
414     {
415       return null; // TODO
416     }
417
418     public AttributeSet getCharacterAttribute(int value0)
419     {
420       return null; // TODO
421     }
422
423     public int getSelectionStart()
424     {
425       return 0; // TODO
426     }
427
428     public int getSelectionEnd()
429     {
430       return 0; // TODO
431     }
432
433     public String getSelectedText()
434     {
435       return null; // TODO
436     }
437
438     private Rectangle getTextRectangle()
439     {
440       return null; // TODO
441     }
442   }
443
444   /**
445    * Creates a new AbstractButton object.
446    */
447   public AbstractButton()
448   {
449     this("",null);
450   }
451
452   /**
453    * Creates a new AbstractButton object.
454    *
455    * @param txt Value to use for the button's "text" property
456    * @param icon Value to use for the button's "defaultIcon" property
457    */
458   AbstractButton(String txt, Icon icon)
459   {
460     init (txt, icon);
461     updateUI();
462   }
463
464   /**
465    * Get the model the button is currently using.
466    *
467    * @return The current model
468    */
469   public ButtonModel getModel()
470   {
471     return model;
472   }
473
474   /**
475    * Set the model the button is currently using. This un-registers all 
476    * listeners associated with the current model, and re-registers them
477    * with the new model.
478    *
479    * @param newModel The new model
480    */
481   public void setModel(ButtonModel newModel)
482   {
483     if (newModel == model)
484       return;
485
486     if (model != null)
487       {
488         model.removeActionListener(actionListener);
489         model.removeChangeListener(changeListener);
490         model.removeItemListener(itemListener);
491       }
492     ButtonModel old = model;
493     model = newModel;
494     if (model != null)
495       {
496         model.addActionListener(actionListener);
497         model.addChangeListener(changeListener);
498         model.addItemListener(itemListener);
499       }
500     firePropertyChange(MODEL_CHANGED_PROPERTY, old, model);
501     revalidate();
502     repaint();
503   }
504
505  protected void init(String text, Icon icon) 
506  {
507     this.text = text;
508     default_icon = icon;
509     model = new DefaultButtonModel();
510     actionListener = createActionListener();
511     changeListener = createChangeListener();
512     itemListener = createItemListener();
513
514     model.addActionListener(actionListener);
515     model.addChangeListener(changeListener);
516     model.addItemListener(itemListener);
517
518     horizontalAlignment = CENTER;
519     horizontalTextPosition = TRAILING;
520     verticalAlignment = CENTER;
521     verticalTextPosition = CENTER;
522     borderPainted = true;
523     contentAreaFilled = true;
524
525     focusPainted = true;
526     setFocusable(true);
527
528     setAlignmentX(LEFT_ALIGNMENT);
529     setAlignmentY(CENTER_ALIGNMENT);
530
531     setDisplayedMnemonicIndex(-1);    
532  }
533  
534   /**
535    * Get the action command string for this button's model.
536    *
537    * @return The current action command string from the button's model
538    */
539   public String getActionCommand()
540   {
541     return getModel().getActionCommand();
542   }
543
544   /**
545    * Set the action command string for this button's model.
546    *
547    * @param aCommand The new action command string to set in the button's
548    * model.
549    */
550   public void setActionCommand(String aCommand)
551   {
552     getModel().setActionCommand(aCommand);
553   }
554
555   /**
556    * Adds an ActionListener to the button's listener list. When the
557    * button's model is clicked it fires an ActionEvent, and these
558    * listeners will be called.
559    *
560    * @param l The new listener to add
561    */
562   public void addActionListener(ActionListener l)
563   {
564     listenerList.add(ActionListener.class, l);
565   }
566
567   /**
568    * Removes an ActionListener from the button's listener list.
569    *
570    * @param l The listener to remove
571    */
572   public void removeActionListener(ActionListener l)
573   {
574     listenerList.remove(ActionListener.class, l);
575   }
576
577   /**
578    * Returns all added <code>ActionListener</code> objects.
579    * 
580    * @return an array of listeners
581    * 
582    * @since 1.4
583    */
584   public ActionListener[] getActionListeners()
585   {
586     return (ActionListener[]) listenerList.getListeners(ActionListener.class);
587   }
588
589   /**
590    * Adds an ItemListener to the button's listener list. When the button's
591    * model changes state (between any of ARMED, ENABLED, PRESSED, ROLLOVER
592    * or SELECTED) it fires an ItemEvent, and these listeners will be
593    * called.
594    *
595    * @param l The new listener to add
596    */
597   public void addItemListener(ItemListener l)
598   {
599     listenerList.add(ItemListener.class, l);
600   }
601
602   /**
603    * Removes an ItemListener from the button's listener list.
604    *
605    * @param l The listener to remove
606    */
607   public void removeItemListener(ItemListener l)
608   {
609     listenerList.remove(ItemListener.class, l);
610   }
611
612   /**
613    * Returns all added <code>ItemListener</code> objects.
614    * 
615    * @return an array of listeners
616    * 
617    * @since 1.4
618    */
619   public ItemListener[] getItemListeners()
620   {
621     return (ItemListener[]) listenerList.getListeners(ItemListener.class);
622   }
623
624   /**
625    * Adds a ChangeListener to the button's listener list. When the button's
626    * model changes any of its (non-bound) properties, these listeners will be
627    * called. 
628    *
629    * @param l The new listener to add
630    */
631   public void addChangeListener(ChangeListener l)
632   {
633     listenerList.add(ChangeListener.class, l);
634   }
635
636   /**
637    * Removes a ChangeListener from the button's listener list.
638    *
639    * @param l The listener to remove
640    */
641   public void removeChangeListener(ChangeListener l)
642   {
643     listenerList.remove(ChangeListener.class, l);
644   }
645
646   /**
647    * Returns all added <code>ChangeListener</code> objects.
648    * 
649    * @return an array of listeners
650    * 
651    * @since 1.4
652    */
653   public ChangeListener[] getChangeListeners()
654   {
655     return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
656   }
657
658   /**
659    * Calls {@link ItemListener.itemStateChanged} on each ItemListener in
660    * the button's listener list.
661    *
662    * @param e The event signifying that the button's model changed state
663    */
664   protected void fireItemStateChanged(ItemEvent e)
665   {
666     e.setSource(this);
667     ItemListener[] listeners = getItemListeners();
668  
669     for (int i = 0; i < listeners.length; i++)
670       listeners[i].itemStateChanged(e);
671   }
672
673   /**
674    * Calls {@link ActionListener.actionPerformed} on each {@link
675    * ActionListener} in the button's listener list.
676    *
677    * @param e The event signifying that the button's model was clicked
678    */
679   protected void fireActionPerformed(ActionEvent e)
680   {
681     e.setSource(this);
682     ActionListener[] listeners = getActionListeners();
683     
684     for (int i = 0; i < listeners.length; i++)
685       listeners[i].actionPerformed(e);
686   }
687
688   /**
689    * Calls {@link ChangeEvent.stateChanged} on each {@link ChangeListener}
690    * in the button's listener list.
691    */
692   protected void fireStateChanged()
693   {
694     ChangeListener[] listeners = getChangeListeners();
695
696     for (int i = 0; i < listeners.length; i++)
697       listeners[i].stateChanged(changeEvent);
698   }
699
700   /**
701    * Get the current keyboard mnemonic value. This value corresponds to a
702    * single key code (one of the {@link java.awt.event.KeyEvent} VK_*
703    * codes) and is used to activate the button when pressed in conjunction
704    * with the "mouseless modifier" of the button's look and feel class, and
705    * when focus is in one of the button's ancestors.
706    *
707    * @return The button's current keyboard mnemonic
708    */
709   public int getMnemonic()
710   {
711     return getModel().getMnemonic();
712   }
713
714   /**
715    * Set the current keyboard mnemonic value. This value corresponds to a
716    * single key code (one of the {@link java.awt.event.KeyEvent} VK_*
717    * codes) and is used to activate the button when pressed in conjunction
718    * with the "mouseless modifier" of the button's look and feel class, and
719    * when focus is in one of the button's ancestors.
720    *
721    * @param mne A new mnemonic to use for the button
722    */
723   public void setMnemonic(char mne)
724   {
725     setMnemonic((int) mne);
726   }
727
728   /**
729    * Set the current keyboard mnemonic value. This value corresponds to a
730    * single key code (one of the {@link java.awt.event.KeyEvent} VK_*
731    * codes) and is used to activate the button when pressed in conjunction
732    * with the "mouseless modifier" of the button's look and feel class, and
733    * when focus is in one of the button's ancestors.
734    *
735    * @param mne A new mnemonic to use for the button
736    */
737   public void setMnemonic(int mne)
738   {
739     int old = getModel().getMnemonic();
740
741     if (old != mne)
742       {
743         getModel().setMnemonic(mne);
744
745         if (text != null && ! text.equals(""))
746           {
747             // Since lower case char = upper case char for 
748             // mnemonic, we will convert both text and mnemonic 
749             // to upper case before checking if mnemonic character occurs
750             // in the menu item text. 
751             int upperCaseMne = Character.toUpperCase((char) mne);
752             String upperCaseText = text.toUpperCase();
753             setDisplayedMnemonicIndex(upperCaseText.indexOf(upperCaseMne));
754           }
755
756         firePropertyChange(MNEMONIC_CHANGED_PROPERTY, old, mne);
757         revalidate();
758         repaint();
759       }
760   }
761
762   /** 
763    * Sets the button's mnemonic index. The mnemonic index is a hint to the
764    * look and feel class, suggesting which character in the button's label
765    * should be underlined when drawing the label. If the mnemonic index is
766    * -1, no mnemonic will be displayed. 
767    * 
768    * If no mnemonic index is set, the button will choose a mnemonic index
769    * by default, which will be the first occurrence of the mnemonic
770    * character in the button's text.
771    *
772    * @param index An offset into the "text" property of the button
773    * @throws IllegalArgumentException If <code>index</code> is not within the
774    * range of legal offsets for the "text" property of the button.
775    * @since 1.4
776    */
777
778   public void setDisplayedMnemonicIndex(int index)
779   {
780     if (index < -1 || (text != null && index >= text.length()))
781       throw new IllegalArgumentException();
782   
783     mnemonicIndex = index;
784   }
785   
786   /** 
787    * Get the button's mnemonic index, which is an offset into the button's
788    * "text" property.  The character specified by this offset should be
789    * underlined when the look and feel class draws this button.
790    *
791    * @return An index into the button's "text" property
792    */
793   public int getDisplayedMnemonicIndex()
794   {
795     return mnemonicIndex;
796   }
797   
798
799   /**
800    * Set the "rolloverEnabled" property. When rollover is enabled, and the
801    * look and feel supports it, the button will change its icon to
802    * rolloverIcon, when the mouse passes over it.
803    *
804    * @param r Whether or not to enable rollover icon changes
805    */
806   public void setRolloverEnabled(boolean r)
807   {
808     if (rollOverEnabled != r)
809       {
810         rollOverEnabled = r;
811         firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, !r, r);
812         revalidate();
813         repaint();
814       }
815   }
816
817   /**
818    * Returns whether or not rollover icon changes are enabled on the
819    * button.
820    *
821    * @return The state of the "rolloverEnabled" property
822    */
823   public boolean isRolloverEnabled()
824   {
825     return rollOverEnabled;
826   }
827
828   /**
829    * Set the value of the button's "selected" property. Selection is only
830    * meaningful for toggle-type buttons (check boxes, radio buttons).
831    *
832    * @param s New value for the property
833    */
834   public void setSelected(boolean s)
835   {
836     getModel().setSelected(s);
837   }
838
839   /**
840    * Get the value of the button's "selected" property. Selection is only
841    * meaningful for toggle-type buttons (check boxes, radio buttons).
842    *
843    * @return The value of the property
844    */
845   public boolean isSelected()
846   {
847     return getModel().isSelected();
848   }
849
850   /**
851    * Enables or disables the button. A button will neither be selectable
852    * nor preform any actions unless it is enabled.
853    *
854    * @param b Whether or not to enable the button
855    */
856   public void setEnabled(boolean b)
857   {
858     super.setEnabled(b);
859     getModel().setEnabled(b);
860   }
861
862   /** 
863    * Set the horizontal alignment of the button's text and icon. The
864    * alignment is a numeric constant from {@link SwingConstants}. It must
865    * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
866    * <code>LEADING</code> or <code>TRAILING</code>.  The default is
867    * <code>RIGHT</code>.
868    * 
869    * @return The current horizontal alignment
870    */
871   public int getHorizontalAlignment()
872   {
873     return horizontalAlignment;
874   }
875
876   /**
877    * Set the horizontal alignment of the button's text and icon. The
878    * alignment is a numeric constant from {@link SwingConstants}. It must
879    * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
880    * <code>LEADING</code> or <code>TRAILING</code>.  The default is
881    * <code>RIGHT</code>.
882    *
883    * @param a The new horizontal alignment
884    * @throws IllegalArgumentException If alignment is not one of the legal
885    * constants.
886    */
887   public void setHorizontalAlignment(int a)
888   {
889     if (horizontalAlignment == a)
890       return;
891
892     int old = horizontalAlignment;
893     horizontalAlignment = a;
894     firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY, old, a);
895     revalidate();
896     repaint();
897   }
898
899   /**
900    * Get the horizontal position of the button's text relative to its
901    * icon. The position is a numeric constant from {@link
902    * SwingConstants}. It must be one of: <code>RIGHT</code>,
903    * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or
904    * <code>TRAILING</code>.  The default is <code>TRAILING</code>.
905    *
906    * @return The current horizontal text position
907    */
908   public int getHorizontalTextPosition()
909   {
910     return horizontalTextPosition;
911   }
912
913   /**
914    * Set the horizontal position of the button's text relative to its
915    * icon. The position is a numeric constant from {@link
916    * SwingConstants}. It must be one of: <code>RIGHT</code>,
917    * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or
918    * <code>TRAILING</code>. The default is <code>TRAILING</code>.
919    *
920    * @param t The new horizontal text position
921    * @throws IllegalArgumentException If position is not one of the legal
922    * constants.
923    */
924   public void setHorizontalTextPosition(int t)
925   {
926     if (horizontalTextPosition == t)
927       return;
928
929     int old = horizontalTextPosition;
930     horizontalTextPosition = t;
931     firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY, old, t);
932     revalidate();
933     repaint();
934   }
935
936   /**
937    * Get the vertical alignment of the button's text and icon. The
938    * alignment is a numeric constant from {@link SwingConstants}. It must
939    * be one of: <code>CENTER</code>, <code>TOP</code>, or
940    * <code>BOTTOM</code>. The default is <code>CENTER</code>.
941    *
942    * @return The current vertical alignment
943    */
944   public int getVerticalAlignment()
945   {
946     return verticalAlignment;
947   }
948
949   /**
950    * Set the vertical alignment of the button's text and icon. The
951    * alignment is a numeric constant from {@link SwingConstants}. It must
952    * be one of: <code>CENTER</code>, <code>TOP</code>, or
953    * <code>BOTTOM</code>. The default is <code>CENTER</code>.
954    *
955    * @param a The new vertical alignment
956    * @throws IllegalArgumentException If alignment is not one of the legal
957    * constants.
958    */
959   public void setVerticalAlignment(int a)
960   {
961     if (verticalAlignment == a)
962       return;
963     
964     int old = verticalAlignment;
965     verticalAlignment = a;
966     firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, old, a);
967     revalidate();
968     repaint();
969   }
970
971   /**
972    * Get the vertical position of the button's text relative to its
973    * icon. The alignment is a numeric constant from {@link
974    * SwingConstants}. It must be one of: <code>CENTER</code>,
975    * <code>TOP</code>, or <code>BOTTOM</code>. The default is
976    * <code>CENTER</code>.
977    *
978    * @return The current vertical position
979    */
980   public int getVerticalTextPosition()
981   {
982     return verticalTextPosition;
983   }
984
985   /**
986    * Set the vertical position of the button's text relative to its
987    * icon. The alignment is a numeric constant from {@link
988    * SwingConstants}. It must be one of: <code>CENTER</code>,
989    * <code>TOP</code>, or <code>BOTTOM</code>. The default is
990    * <code>CENTER</code>.
991    *
992    * @param t The new vertical position
993    * @throws IllegalArgumentException If position is not one of the legal
994    * constants.
995    */
996   public void setVerticalTextPosition(int t)
997   {
998     if (verticalTextPosition == t)
999       return;
1000     
1001     int old = verticalTextPosition;
1002     verticalTextPosition = t;
1003     firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, old, t);
1004     revalidate();
1005     repaint();
1006   }
1007
1008   /**
1009    * Set the value of the "borderPainted" property. If set to
1010    * <code>false</code>, the button's look and feel class should not paint
1011    * a border for the button. The default is <code>true</code>.
1012    *
1013    * @return The current value of the property.
1014    */
1015   public boolean isBorderPainted()
1016   {
1017     return borderPainted;
1018   }
1019
1020   /**
1021    * Set the value of the "borderPainted" property. If set to
1022    * <code>false</code>, the button's look and feel class should not paint
1023    * a border for the button. The default is <code>true</code>.
1024    *
1025    * @param b The new value of the property.
1026    */
1027   public void setBorderPainted(boolean b)
1028   {
1029     if (borderPainted == b)
1030       return;
1031     
1032     boolean old = borderPainted;
1033     borderPainted = b;
1034     firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, old, b);
1035     revalidate();
1036     repaint();
1037   }
1038
1039   /**
1040    * Get the value of the "action" property. 
1041    *
1042    * @return The current value of the "action" property
1043    */
1044   public Action getAction()
1045   {
1046     return action;
1047   }
1048
1049   /**
1050    * <p>Set the button's "action" property, subscribing the new action to the
1051    * button, as an ActionListener, if it is not already subscribed. The old
1052    * Action, if it exists, is unsubscribed, and the button is unsubscribed
1053    * from the old Action if it was previously subscribed as a
1054    * PropertyChangeListener.</p>
1055    *
1056    * <p>This method also configures several of the button's properties from
1057    * the Action, by calling {@link configurePropertiesFromAction}, and
1058    * subscribes the button to the Action as a PropertyChangeListener.
1059    * Subsequent changes to the Action will thus reconfigure the button 
1060    * automatically.</p>
1061    *
1062    * @param a The new value of the "action" property
1063    */
1064   public void setAction(Action a)
1065   {
1066     if (action != null)
1067       {
1068         action.removePropertyChangeListener(actionPropertyChangeListener);
1069         removeActionListener(action);
1070         if (actionPropertyChangeListener != null)
1071           {
1072             action.removePropertyChangeListener(actionPropertyChangeListener);
1073             actionPropertyChangeListener = null;
1074           }
1075       }
1076
1077     Action old = action;
1078     action = a;
1079     configurePropertiesFromAction(action);
1080     if (action != null)
1081       {
1082         actionPropertyChangeListener = createActionPropertyChangeListener(a);      
1083         action.addPropertyChangeListener(actionPropertyChangeListener);
1084         addActionListener(action);
1085       }
1086   }
1087
1088   /**
1089    * Return the button's default "icon" property.
1090    *
1091    * @return The current default icon
1092    */
1093   public Icon getIcon()
1094   {
1095     return default_icon;
1096   }
1097
1098   /**
1099    * Set the button's default "icon" property. This icon is used as a basis
1100    * for the pressed and disabled icons, if none are explicitly set.
1101    *
1102    * @param i The new default icon
1103    */
1104   public void setIcon(Icon i)
1105   {
1106     if (default_icon == i)
1107       return;
1108     
1109     Icon old = default_icon;      
1110     default_icon = i;      
1111     firePropertyChange(ICON_CHANGED_PROPERTY, old, i);
1112     revalidate();
1113     repaint();
1114   }
1115
1116   /**
1117    * Return the button's "text" property. This property is synonymous with
1118    * the "label" property.
1119    *
1120    * @return The current "text" property
1121    */
1122   public String getText()
1123   {
1124     return text;
1125   }
1126
1127   /**
1128    * Set the button's "label" property. This property is synonymous with the
1129    * "text" property.
1130    *
1131    * @param label The new "label" property
1132    *
1133    * @deprecated use <code>setText(text)</code>
1134    */
1135   public void setLabel(String label)
1136   {
1137     setText(label);
1138   }
1139
1140   /**
1141    * Return the button's "label" property. This property is synonymous with
1142    * the "text" property.
1143    *
1144    * @return The current "label" property
1145    *
1146    * @deprecated use <code>getText()</code>
1147    */
1148   public String getLabel()
1149   {
1150     return getText();
1151   }
1152
1153   /**
1154    * Set the button's "text" property. This property is synonymous with the
1155    * "label" property.
1156    *
1157    * @param t The new "text" property
1158    */
1159   public void setText(String t)
1160   {
1161     if (text == t)
1162       return;
1163     
1164     String old = text;
1165     text = t;
1166     firePropertyChange(TEXT_CHANGED_PROPERTY, old, t);
1167     revalidate();
1168     repaint();
1169   }
1170
1171   /**
1172    * Set the value of the {@link #iconTextGap} property.
1173    * 
1174    * @param i The new value of the property
1175    */
1176   public void setIconTextGap(int i)
1177   {
1178     if (iconTextGap == i)
1179       return;
1180     
1181     int old = iconTextGap;
1182     iconTextGap = i;
1183     fireStateChanged();
1184     revalidate();
1185     repaint();
1186   }
1187
1188   /**
1189    * Get the value of the {@link #iconTextGap} property.
1190    *
1191    * @return The current value of the property
1192    */
1193   public int getIconTextGap()
1194   {
1195     return iconTextGap;
1196   }
1197
1198   /**
1199    * Return the button's "margin" property, which is an {@link Insets} object
1200    * describing the distance between the button's border and its text and
1201    * icon.
1202    *
1203    * @return The current "margin" property
1204    */
1205   public Insets getMargin()
1206   {
1207     return margin;
1208   }
1209
1210   /**
1211    * Set the button's "margin" property, which is an {@link Insets} object
1212    * describing the distance between the button's border and its text and
1213    * icon.
1214    *
1215    * @param m The new "margin" property
1216    */
1217   public void setMargin(Insets m)
1218   {
1219     if (margin == m)
1220       return;
1221     
1222     Insets old = margin;
1223     margin = m;
1224     firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);
1225     revalidate();
1226     repaint();
1227   }
1228
1229   /**
1230    * Return the button's "pressedIcon" property. The look and feel class
1231    * should paint this icon when the "pressed" property of the button's
1232    * {@link ButtonModel} is <code>true</code>. This property may be
1233    * <code>null</code>, in which case the default icon is used.
1234    *
1235    * @return The current "pressedIcon" property
1236    */
1237   public Icon getPressedIcon()
1238   {
1239     return pressed_icon;
1240   }
1241
1242   /**
1243    * Set the button's "pressedIcon" property. The look and feel class
1244    * should paint this icon when the "pressed" property of the button's
1245    * {@link ButtonModel} is <code>true</code>. This property may be
1246    * <code>null</code>, in which case the default icon is used.
1247    *
1248    * @param pressedIcon The new "pressedIcon" property
1249    */
1250   public void setPressedIcon(Icon pressedIcon)
1251   {
1252     if (pressed_icon == pressedIcon)
1253       return;
1254     
1255     Icon old = pressed_icon;
1256     pressed_icon = pressedIcon;
1257     firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, old, pressed_icon);
1258     revalidate();
1259     repaint();
1260   }
1261
1262   /**
1263    * Return the button's "disabledIcon" property. The look and feel class
1264    * should paint this icon when the "enabled" property of the button's
1265    * {@link ButtonModel} is <code>false</code>. This property may be
1266    * <code>null</code>, in which case an icon is constructed, based on the
1267    * default icon.
1268    *
1269    * @return The current "disabledIcon" property
1270    */
1271   public Icon getDisabledIcon()
1272   {
1273     if (disabeldIcon == null
1274         && default_icon instanceof ImageIcon)
1275       disabeldIcon = new ImageIcon(GrayFilter.createDisabledImage(((ImageIcon) default_icon).getImage()));
1276       
1277     return disabeldIcon;
1278   }
1279
1280   /**
1281    * Set the button's "disabledIcon" property. The look and feel class should
1282    * paint this icon when the "enabled" property of the button's {@link
1283    * ButtonModel} is <code>false</code>. This property may be
1284    * <code>null</code>, in which case an icon is constructed, based on the
1285    * default icon.
1286    *
1287    * @param disabledIcon The new "disabledIcon" property
1288    */
1289   public void setDisabledIcon(Icon d)
1290   {
1291     disabeldIcon = d;
1292     revalidate();
1293     repaint();
1294   }
1295
1296   /**
1297    * Return the button's "paintFocus" property. This property controls
1298    * whether or not the look and feel class will paint a special indicator
1299    * of focus state for the button. If it is false, the button still paints
1300    * when focused, but no special decoration is painted to indicate the
1301    * presence of focus.
1302    *
1303    * @return The current "paintFocus" property
1304    */
1305   public boolean isFocusPainted()
1306   {
1307     return focusPainted;
1308   }
1309
1310   /**
1311    * Set the button's "paintFocus" property. This property controls whether
1312    * or not the look and feel class will paint a special indicator of focus
1313    * state for the button. If it is false, the button still paints when
1314    * focused, but no special decoration is painted to indicate the presence
1315    * of focus.
1316    *
1317    * @param b The new "paintFocus" property
1318    */
1319   public void setFocusPainted(boolean p)
1320   {
1321     if (focusPainted == p)
1322       return;
1323     
1324     boolean old = focusPainted;
1325     focusPainted = p;
1326     firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, old, p);
1327     revalidate();
1328     repaint();
1329   }
1330
1331   /**
1332    * Return the button's "focusTraversable" property. This property controls
1333    * whether or not the button can receive focus when the user attempts to
1334    * traverse the focus hierarchy.
1335    *
1336    * @return The current "focusTraversable" property
1337    */
1338   public boolean isFocusTraversable()
1339   {
1340     return true;
1341   }
1342
1343   /**
1344    * Verifies that a particular key is one of the valid constants used for
1345    * describing horizontal alignment and positioning. The valid constants
1346    * are the following members of {@link SwingConstants}:
1347    * <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
1348    * <code>LEADING</code> or <code>TRAILING</code>.
1349    *
1350    * @param key The key to check
1351    * @param exception A message to include in an IllegalArgumentException
1352    *
1353    * @return the value of key
1354    *
1355    * @throws IllegalArgumentException If key is not one of the valid constants
1356    *
1357    * @see setHorizontalTextPosition()
1358    * @see setHorizontalAlignment()
1359    */
1360   protected  int checkHorizontalKey(int key, String exception)
1361   {
1362     switch (key)
1363       {
1364       case SwingConstants.RIGHT:
1365       case SwingConstants.LEFT:
1366       case SwingConstants.CENTER:
1367       case SwingConstants.LEADING:
1368       case SwingConstants.TRAILING:
1369         break;
1370       default:
1371         throw new IllegalArgumentException(exception);
1372       }
1373     return key;
1374   }
1375
1376   /**
1377    * Verifies that a particular key is one of the valid constants used for
1378    * describing vertical alignment and positioning. The valid constants are
1379    * the following members of {@link SwingConstants}: <code>TOP</code>,
1380    * <code>BOTTOM</code> or <code>CENTER</code>.
1381    *
1382    * @param key The key to check
1383    * @param exception A message to include in an IllegalArgumentException
1384    *
1385    * @return the value of key
1386    *
1387    * @throws IllegalArgumentException If key is not one of the valid constants
1388    *
1389    * @see setVerticalTextPosition()
1390    * @see setVerticalAlignment()
1391    */
1392   protected  int checkVerticalKey(int key, String exception)
1393   {
1394     switch (key)
1395       {
1396       case SwingConstants.TOP:
1397       case SwingConstants.BOTTOM:
1398       case SwingConstants.CENTER:
1399         break;
1400       default:
1401         throw new IllegalArgumentException(exception);
1402       }
1403     return key;
1404   }
1405
1406   /**
1407    * Configure various properties of the button by reading properties
1408    * of an {@link Action}. The mapping of properties is as follows:
1409    *
1410    * <table>
1411    *
1412    * <tr><th>Action keyed property</th> <th>AbstractButton property</th></tr>
1413    *
1414    * <tr><td>NAME                 </td> <td>text                   </td></tr>
1415    * <tr><td>SMALL_ICON           </td> <td>icon                   </td></tr>
1416    * <tr><td>SHORT_DESCRIPTION    </td> <td>toolTipText            </td></tr>
1417    * <tr><td>MNEMONIC_KEY         </td> <td>mnemonic               </td></tr>
1418    * <tr><td>ACTION_COMMAND_KEY   </td> <td>actionCommand          </td></tr>
1419    *
1420    * </table>
1421    *
1422    * <p>In addition, this method always sets the button's "enabled" property to
1423    * the value of the Action's "enabled" property.</p>
1424    *
1425    * <p>If the provided Action is <code>null</code>, the text, icon, and
1426    * toolTipText properties of the button are set to <code>null</code>, and
1427    * the "enabled" property is set to <code>true</code>; the mnemonic and
1428    * actionCommand properties are unchanged.</p>
1429    *
1430    * @param a An Action to configure the button from
1431    */
1432   protected  void configurePropertiesFromAction(Action a)
1433   {
1434     if (a == null)
1435       {
1436         setText(null);
1437         setIcon(null);
1438         setEnabled(true);
1439         setToolTipText(null);
1440       }
1441     else
1442       {
1443         setText((String)(a.getValue(Action.NAME)));
1444         setIcon((Icon)(a.getValue(Action.SMALL_ICON)));
1445         setEnabled(a.isEnabled());
1446         setToolTipText((String)(a.getValue(Action.SHORT_DESCRIPTION)));
1447         if (a.getValue(Action.MNEMONIC_KEY) != null)
1448           setMnemonic(((Integer)(a.getValue(Action.MNEMONIC_KEY))).intValue());
1449         String actionCommand = (String)(a.getValue(Action.ACTION_COMMAND_KEY));
1450
1451         // Set actionCommand to button's text by default if it is not specified
1452         if (actionCommand != null)
1453            setActionCommand((String)(a.getValue(Action.ACTION_COMMAND_KEY)));
1454          else
1455            setActionCommand(getText());
1456       }
1457   }
1458
1459   /**
1460    * <p>A factory method which should return an {@link ActionListener} that
1461    * propagates events from the button's {@link ButtonModel} to any of the
1462    * button's ActionListeners. By default, this is an inner class which
1463    * calls {@link AbstractButton.fireActionPerformed} with a modified copy
1464    * of the incoming model {@link ActionEvent}.</p>
1465    *
1466    * <p>The button calls this method during construction, stores the
1467    * resulting ActionListener in its <code>actionListener</code> member
1468    * field, and subscribes it to the button's model. If the button's model
1469    * is changed, this listener is unsubscribed from the old model and
1470    * subscribed to the new one.</p>
1471    *
1472    * @return A new ActionListener 
1473    */
1474   protected  ActionListener createActionListener()
1475   {
1476     return new ActionListener()
1477       {
1478         public void actionPerformed(ActionEvent e)
1479         {
1480           AbstractButton.this.fireActionPerformed(e);
1481         }
1482       };
1483   }
1484
1485   /**
1486    * <p>A factory method which should return a {@link PropertyChangeListener}
1487    * that accepts changes to the specified {@link Action} and reconfigure
1488    * the {@link AbstractButton}, by default using the {@link
1489    * configurePropertiesFromAction} method.</p>
1490    *
1491    * <p>The button calls this method whenever a new Action is assigned to
1492    * the button's "action" property, via {@link setAction}, and stores the
1493    * resulting PropertyChangeListener in its
1494    * <code>actionPropertyChangeListener</code> member field. The button
1495    * then subscribes the listener to the button's new action. If the
1496    * button's action is changed subsequently, the listener is unsubscribed
1497    * from the old action and subscribed to the new one.</p>
1498    *
1499    * @param a The Action which will be listened to, and which should be 
1500    * the same as the source of any PropertyChangeEvents received by the
1501    * new listener returned from this method.
1502    *
1503    * @return A new PropertyChangeListener
1504    */
1505   protected  PropertyChangeListener createActionPropertyChangeListener(Action a)
1506   {
1507     return new PropertyChangeListener()
1508       {
1509         public void propertyChange(PropertyChangeEvent e)
1510         {
1511           Action act = (Action) (e.getSource());        
1512           if (e.getPropertyName().equals("enabled"))
1513             setEnabled(act.isEnabled());
1514           else if (e.getPropertyName().equals(Action.NAME))
1515             setText((String)(act.getValue(Action.NAME)));
1516           else if (e.getPropertyName().equals(Action.SMALL_ICON))
1517             setIcon((Icon)(act.getValue(Action.SMALL_ICON)));
1518           else if (e.getPropertyName().equals(Action.SHORT_DESCRIPTION))
1519             setToolTipText((String)(act.getValue(Action.SHORT_DESCRIPTION)));
1520           else if (e.getPropertyName().equals(Action.MNEMONIC_KEY))
1521             if (act.getValue(Action.MNEMONIC_KEY) != null)
1522               setMnemonic(((Integer)(act.getValue(Action.MNEMONIC_KEY))).intValue());
1523           else if (e.getPropertyName().equals(Action.ACTION_COMMAND_KEY))
1524             setActionCommand((String)(act.getValue(Action.ACTION_COMMAND_KEY)));
1525         }
1526       };
1527   }
1528
1529   /**
1530    * <p>Factory method which creates a {@link ChangeListener}, used to
1531    * subscribe to ChangeEvents from the button's model. Subclasses of
1532    * AbstractButton may wish to override the listener used to subscribe to
1533    * such ChangeEvents. By default, the listener just propagates the
1534    * {@link ChangeEvent} to the button's ChangeListeners, via the {@link
1535    * AbstractButton.fireStateChanged} method.</p>
1536    *
1537    * <p>The button calls this method during construction, stores the
1538    * resulting ChangeListener in its <code>changeListener</code> member
1539    * field, and subscribes it to the button's model. If the button's model
1540    * is changed, this listener is unsubscribed from the old model and
1541    * subscribed to the new one.</p>
1542    *
1543    * @return The new ChangeListener
1544    */
1545   protected  ChangeListener createChangeListener()
1546   {
1547     return new ChangeListener()
1548       {
1549         public void stateChanged(ChangeEvent e)
1550         {
1551           AbstractButton.this.fireStateChanged();
1552           AbstractButton.this.repaint();          
1553         }
1554       };
1555   }
1556
1557   /**
1558    * <p>Factory method which creates a {@link ItemListener}, used to
1559    * subscribe to ItemEvents from the button's model. Subclasses of
1560    * AbstractButton may wish to override the listener used to subscribe to
1561    * such ItemEvents. By default, the listener just propagates the
1562    * {@link ItemEvent} to the button's ItemListeners, via the {@link
1563    * AbstractButton.fireItemStateChanged} method.</p>
1564    *
1565    * <p>The button calls this method during construction, stores the
1566    * resulting ItemListener in its <code>changeListener</code> member
1567    * field, and subscribes it to the button's model. If the button's model
1568    * is changed, this listener is unsubscribed from the old model and
1569    * subscribed to the new one.</p>
1570    *
1571    * <p>Note that ItemEvents are only generated from the button's model
1572    * when the model's <em>selected</em> property changes. If you want to
1573    * subscribe to other properties of the model, you must subscribe to
1574    * ChangeEvents.
1575    *
1576    * @return The new ItemListener
1577    */
1578   protected  ItemListener createItemListener()
1579   {
1580     return new ItemListener()
1581       {
1582         public void itemStateChanged(ItemEvent e)
1583         {
1584           AbstractButton.this.fireItemStateChanged(e);
1585         }
1586       };
1587   }
1588
1589   /**
1590    * Programmatically perform a "click" on the button: arming, pressing,
1591    * waiting, un-pressing, and disarming the model.
1592    */
1593   public void doClick()
1594   {
1595     doClick(100);
1596   }
1597
1598   /**
1599    * Programmatically perform a "click" on the button: arming, pressing,
1600    * waiting, un-pressing, and disarming the model.
1601    *
1602    * @param pressTime The number of milliseconds to wait in the pressed state
1603    */
1604   public void doClick(int pressTime)
1605   {
1606     getModel().setArmed(true);
1607     getModel().setPressed(true);
1608     try
1609       {
1610         java.lang.Thread.sleep(pressTime);
1611       }
1612     catch (java.lang.InterruptedException e)
1613       {
1614         // probably harmless
1615       }
1616     getModel().setPressed(false);
1617     getModel().setArmed(false);
1618   }
1619
1620   /**
1621    * Return the button's disabled selected icon. The look and feel class
1622    * should paint this icon when the "enabled" property of the button's model
1623    * is <code>false</code> and its "selected" property is
1624    * <code>true</code>. This icon can be <code>null</code>, in which case
1625    * it is synthesized from the button's selected icon.
1626    *
1627    * @return The current disabled selected icon
1628    */
1629   public Icon getDisabledSelectedIcon()
1630   {
1631     return disabledSelectedIcon;
1632   }
1633
1634   /**
1635    * Set the button's disabled selected icon. The look and feel class
1636    * should paint this icon when the "enabled" property of the button's model
1637    * is <code>false</code> and its "selected" property is
1638    * <code>true</code>. This icon can be <code>null</code>, in which case
1639    * it is synthesized from the button's selected icon.
1640    *
1641    * @param icon The new disabled selected icon
1642    */
1643   public void setDisabledSelectedIcon(Icon icon)
1644   {
1645     if (disabledSelectedIcon == icon)
1646       return;
1647     
1648     Icon old = disabledSelectedIcon;
1649     disabledSelectedIcon = icon;
1650     firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, old, icon);
1651     revalidate();
1652     repaint();        
1653   }
1654
1655   /**
1656    * Return the button's rollover icon. The look and feel class should
1657    * paint this icon when the "rolloverEnabled" property of the button is
1658    * <code>true</code> and the mouse rolls over the button.
1659    *
1660    * @return The current rollover icon
1661    */
1662   public Icon getRolloverIcon()
1663   {
1664     return rolloverIcon;
1665   }
1666
1667   /**
1668    * Set the button's rollover icon. The look and feel class should
1669    * paint this icon when the "rolloverEnabled" property of the button is
1670    * <code>true</code> and the mouse rolls over the button.
1671    *
1672    * @param rolloverIcon The new rollover icon
1673    */
1674   public void setRolloverIcon(Icon r)
1675   {
1676     if (rolloverIcon == r)
1677       return;
1678     
1679     Icon old = rolloverIcon;
1680     rolloverIcon = r;
1681     firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, old, rolloverIcon);
1682     revalidate();
1683     repaint();
1684   }
1685
1686   /**
1687    * Return the button's rollover selected icon. The look and feel class
1688    * should paint this icon when the "rolloverEnabled" property of the button
1689    * is <code>true</code>, the "selected" property of the button's model is
1690    * <code>true</code>, and the mouse rolls over the button.
1691    *
1692    * @return The current rollover selected icon
1693    */
1694   public Icon getRolloverSelectedIcon()
1695   {
1696     return rolloverSelectedIcon;
1697   }
1698
1699   /**
1700    * Set the button's rollover selected icon. The look and feel class
1701    * should paint this icon when the "rolloverEnabled" property of the button
1702    * is <code>true</code>, the "selected" property of the button's model is
1703    * <code>true</code>, and the mouse rolls over the button.
1704    *
1705    * @param rolloverSelectedIcon The new rollover selected icon
1706    */
1707   public void setRolloverSelectedIcon(Icon r)
1708   {
1709     if (rolloverSelectedIcon == r)
1710       return;
1711     
1712     Icon old = rolloverSelectedIcon;
1713     rolloverSelectedIcon = r;
1714     firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, old, r);
1715     revalidate();
1716     repaint();
1717   }
1718
1719   /**
1720    * Return the button's selected icon. The look and feel class should
1721    * paint this icon when the "selected" property of the button's model is
1722    * <code>true</code>, and either the "rolloverEnabled" property of the
1723    * button is <code>false</code> or the mouse is not currently rolled
1724    * over the button.
1725    *
1726    * @return The current selected icon
1727    */
1728   public Icon getSelectedIcon()
1729   {
1730     return selectedIcon;
1731   }
1732
1733   /**
1734    * Set the button's selected icon. The look and feel class should
1735    * paint this icon when the "selected" property of the button's model is
1736    * <code>true</code>, and either the "rolloverEnabled" property of the
1737    * button is <code>false</code> or the mouse is not currently rolled
1738    * over the button.
1739    *
1740    * @param selectedIcon The new selected icon
1741    */
1742   public void setSelectedIcon(Icon s)
1743   {
1744     if (selectedIcon == s)
1745       return;
1746     
1747     Icon old = selectedIcon;
1748     selectedIcon = s;
1749     firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, old, s);
1750     revalidate();
1751     repaint();
1752   }
1753
1754   /**
1755    * Returns an single-element array containing the "text" property of the
1756    * button if the "selected" property of the button's model is
1757    * <code>true</code>, otherwise returns <code>null</code>.
1758    *
1759    * @return The button's "selected object" array
1760    */
1761   public Object[] getSelectedObjects()
1762   {
1763     if (isSelected())
1764       {
1765         Object[] objs = new Object[1];
1766         objs[0] = getText();
1767         return objs;
1768       }
1769     else
1770      {
1771         return null;
1772       }
1773   }
1774
1775   /**
1776    * Called when image data becomes available for one of the button's icons.
1777    *
1778    * @param img The image being updated
1779    * @param infoflags One of the constant codes in {@link ImageObserver} used to describe
1780    * updated portions of an image.
1781    * @param x X coordinate of the region being updated
1782    * @param y Y coordinate of the region being updated
1783    * @param w Width of the region beign updated
1784    * @param h Height of the region being updated
1785    *
1786    * @return <code>true</code> if img is equal to the button's current
1787    * icon, otherwise <code>false</code>
1788    */
1789   public boolean imageUpdate(Image img, int infoflags, int x, int y, int w,
1790                              int h)
1791   {
1792     return current_icon == img;
1793   }
1794
1795   /**
1796    * Returns the value of the button's "contentAreaFilled" property. This
1797    * property indicates whether the area surrounding the text and icon of
1798    * the button should be filled by the look and feel class.  If this
1799    * property is <code>false</code>, the look and feel class should leave
1800    * the content area transparent.
1801    *
1802    * @return The current value of the "contentAreaFilled" property
1803    */
1804   public boolean isContentAreaFilled()
1805   {
1806     return contentAreaFilled;
1807   }
1808
1809   /**
1810    * Sets the value of the button's "contentAreaFilled" property. This
1811    * property indicates whether the area surrounding the text and icon of
1812    * the button should be filled by the look and feel class.  If this
1813    * property is <code>false</code>, the look and feel class should leave
1814    * the content area transparent.
1815    *
1816    * @param b The new value of the "contentAreaFilled" property
1817    */
1818   public void setContentAreaFilled(boolean b)
1819   {
1820     if (contentAreaFilled == b)
1821       return;
1822     
1823     boolean old = contentAreaFilled;
1824     contentAreaFilled = b;
1825     firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, old, b);
1826     revalidate();
1827     repaint();
1828    }
1829
1830   /**
1831    * Paints the button's border, if the button's "borderPainted" property is
1832    * <code>true</code>, by out calling to the button's look and feel class.
1833    *
1834    * @param g The graphics context used to paint the border
1835    */
1836   protected void paintBorder(Graphics g)
1837   {
1838     if (isBorderPainted())
1839       super.paintBorder(g);
1840   }
1841
1842   /**
1843    * Returns a string, used only for debugging, which identifies or somehow
1844    * represents this button. The exact value is implementation-defined.
1845    *
1846    * @return A string representation of the button
1847    */
1848   protected String paramString()
1849   {
1850     StringBuffer sb = new StringBuffer();
1851     sb.append(super.paramString());
1852     sb.append(",defaultIcon=");
1853     if (getIcon() != null)
1854       sb.append(getIcon());
1855     sb.append(",disabledIcon=");
1856     if (getDisabledIcon() != null)
1857       sb.append(getDisabledIcon());
1858     sb.append(",disabledSelectedIcon=");
1859     if (getDisabledSelectedIcon() != null)
1860       sb.append(getDisabledSelectedIcon());
1861     sb.append(",margin=");
1862     if (getMargin() != null)
1863       sb.append(getMargin());
1864     sb.append(",paintBorder=").append(isBorderPainted());
1865     sb.append(",paintFocus=").append(isFocusPainted());
1866     sb.append(",pressedIcon=");
1867     if (getPressedIcon() != null)
1868       sb.append(getPressedIcon());
1869     sb.append(",rolloverEnabled=").append(isRolloverEnabled());
1870     sb.append(",rolloverIcon=");
1871     if (getRolloverIcon() != null)
1872       sb.append(getRolloverIcon());
1873     sb.append(",rolloverSelected=");
1874     if (getRolloverSelectedIcon() != null)
1875       sb.append(getRolloverSelectedIcon());
1876     sb.append(",selectedIcon=");
1877     if (getSelectedIcon() != null)
1878       sb.append(getSelectedIcon());
1879     sb.append(",text=");
1880     if (getText() != null)
1881       sb.append(getText());
1882     return sb.toString();
1883   }
1884
1885   /**
1886    * Set the "UI" property of the button, which is a look and feel class
1887    * responsible for handling the button's input events and painting it.
1888    *
1889    * @param ui The new "UI" property
1890    */
1891   public void setUI(ButtonUI ui)
1892   {
1893     super.setUI(ui);
1894   }
1895   
1896   /**
1897    * Set the "UI" property of the button, which is a look and feel class
1898    * responsible for handling the button's input events and painting it.
1899    *
1900    * @return The current "UI" property
1901    */
1902   public ButtonUI getUI()
1903   {
1904     return (ButtonUI) ui;
1905   }
1906   
1907   /**
1908    * Set the "UI" property to a class constructed, via the {@link
1909    * UIManager}, from the current look and feel. This should be overridden
1910    * for each subclass of AbstractButton, to retrieve a suitable {@link
1911    * ButtonUI} look and feel class.
1912    */
1913   public void updateUI()
1914   {
1915   }
1916
1917   /**
1918    * Returns the current time in milliseconds in which clicks gets coalesced
1919    * into a single <code>ActionEvent</code>.
1920    *
1921    * @return the time in milliseconds
1922    * 
1923    * @since 1.4
1924    */
1925   public long getMultiClickThreshhold()
1926   {
1927     return multiClickThreshhold;
1928   }
1929
1930   /**
1931    * Sets the time in milliseconds in which clicks gets coalesced into a single
1932    * <code>ActionEvent</code>.
1933    *
1934    * @param threshhold the time in milliseconds
1935    * 
1936    * @since 1.4
1937    */
1938   public void setMultiClickThreshhold(long threshhold)
1939   {
1940     if (threshhold < 0)
1941       throw new IllegalArgumentException();
1942
1943     multiClickThreshhold = threshhold;
1944   }
1945 }