Source for javax.swing.AbstractButton

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