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:     setFocusable(b);
 960:     ButtonModel mod = getModel();
 961:     if (mod != null)
 962:       mod.setEnabled(b);
 963:   }
 964: 
 965:   /** 
 966:    * Set the horizontal alignment of the button's text and icon. The
 967:    * alignment is a numeric constant from {@link SwingConstants}. It must
 968:    * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
 969:    * <code>LEADING</code> or <code>TRAILING</code>.  The default is
 970:    * <code>RIGHT</code>.
 971:    * 
 972:    * @return The current horizontal alignment
 973:    */
 974:   public int getHorizontalAlignment()
 975:   {
 976:     return horizontalAlignment;
 977:   }
 978: 
 979:   /**
 980:    * Set the horizontal alignment of the button's text and icon. The
 981:    * alignment is a numeric constant from {@link SwingConstants}. It must
 982:    * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
 983:    * <code>LEADING</code> or <code>TRAILING</code>.  The default is
 984:    * <code>RIGHT</code>.
 985:    *
 986:    * @param a The new horizontal alignment
 987:    * @throws IllegalArgumentException If alignment is not one of the legal
 988:    * constants.
 989:    */
 990:   public void setHorizontalAlignment(int a)
 991:   {
 992:     if (horizontalAlignment == a)
 993:       return;
 994: 
 995:     int old = horizontalAlignment;
 996:     horizontalAlignment = a;
 997:     firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY, old, a);
 998:     revalidate();
 999:     repaint();
1000:   }
1001: 
1002:   /**
1003:    * Get the horizontal position of the button's text relative to its
1004:    * icon. The position is a numeric constant from {@link
1005:    * SwingConstants}. It must be one of: <code>RIGHT</code>,
1006:    * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or
1007:    * <code>TRAILING</code>.  The default is <code>TRAILING</code>.
1008:    *
1009:    * @return The current horizontal text position
1010:    */
1011:   public int getHorizontalTextPosition()
1012:   {
1013:     return horizontalTextPosition;
1014:   }
1015: 
1016:   /**
1017:    * Set the horizontal position of the button's text relative to its
1018:    * icon. The position is a numeric constant from {@link
1019:    * SwingConstants}. It must be one of: <code>RIGHT</code>,
1020:    * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or
1021:    * <code>TRAILING</code>. The default is <code>TRAILING</code>.
1022:    *
1023:    * @param t The new horizontal text position
1024:    * @throws IllegalArgumentException If position is not one of the legal
1025:    * constants.
1026:    */
1027:   public void setHorizontalTextPosition(int t)
1028:   {
1029:     if (horizontalTextPosition == t)
1030:       return;
1031: 
1032:     int old = horizontalTextPosition;
1033:     horizontalTextPosition = t;
1034:     firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY, old, t);
1035:     revalidate();
1036:     repaint();
1037:   }
1038: 
1039:   /**
1040:    * Get the vertical alignment of the button's text and icon. The
1041:    * alignment is a numeric constant from {@link SwingConstants}. It must
1042:    * be one of: <code>CENTER</code>, <code>TOP</code>, or
1043:    * <code>BOTTOM</code>. The default is <code>CENTER</code>.
1044:    *
1045:    * @return The current vertical alignment
1046:    */
1047:   public int getVerticalAlignment()
1048:   {
1049:     return verticalAlignment;
1050:   }
1051: 
1052:   /**
1053:    * Set the vertical alignment of the button's text and icon. The
1054:    * alignment is a numeric constant from {@link SwingConstants}. It must
1055:    * be one of: <code>CENTER</code>, <code>TOP</code>, or
1056:    * <code>BOTTOM</code>. The default is <code>CENTER</code>.
1057:    *
1058:    * @param a The new vertical alignment
1059:    * @throws IllegalArgumentException If alignment is not one of the legal
1060:    * constants.
1061:    */
1062:   public void setVerticalAlignment(int a)
1063:   {
1064:     if (verticalAlignment == a)
1065:       return;
1066:     
1067:     int old = verticalAlignment;
1068:     verticalAlignment = a;
1069:     firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, old, a);
1070:     revalidate();
1071:     repaint();
1072:   }
1073: 
1074:   /**
1075:    * Get the vertical position of the button's text relative to its
1076:    * icon. The alignment is a numeric constant from {@link
1077:    * SwingConstants}. It must be one of: <code>CENTER</code>,
1078:    * <code>TOP</code>, or <code>BOTTOM</code>. The default is
1079:    * <code>CENTER</code>.
1080:    *
1081:    * @return The current vertical position
1082:    */
1083:   public int getVerticalTextPosition()
1084:   {
1085:     return verticalTextPosition;
1086:   }
1087: 
1088:   /**
1089:    * Set the vertical position of the button's text relative to its
1090:    * icon. The alignment is a numeric constant from {@link
1091:    * SwingConstants}. It must be one of: <code>CENTER</code>,
1092:    * <code>TOP</code>, or <code>BOTTOM</code>. The default is
1093:    * <code>CENTER</code>.
1094:    *
1095:    * @param t The new vertical position
1096:    * @throws IllegalArgumentException If position is not one of the legal
1097:    * constants.
1098:    */
1099:   public void setVerticalTextPosition(int t)
1100:   {
1101:     if (verticalTextPosition == t)
1102:       return;
1103:     
1104:     int old = verticalTextPosition;
1105:     verticalTextPosition = t;
1106:     firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, old, t);
1107:     revalidate();
1108:     repaint();
1109:   }
1110: 
1111:   /**
1112:    * Set the value of the "borderPainted" property. If set to
1113:    * <code>false</code>, the button's look and feel class should not paint
1114:    * a border for the button. The default is <code>true</code>.
1115:    *
1116:    * @return The current value of the property.
1117:    */
1118:   public boolean isBorderPainted()
1119:   {
1120:     return borderPainted;
1121:   }
1122: 
1123:   /**
1124:    * Set the value of the "borderPainted" property. If set to
1125:    * <code>false</code>, the button's look and feel class should not paint
1126:    * a border for the button. The default is <code>true</code>.
1127:    *
1128:    * @param b The new value of the property.
1129:    */
1130:   public void setBorderPainted(boolean b)
1131:   {
1132:     if (borderPainted == b)
1133:       return;
1134:     
1135:     boolean old = borderPainted;
1136:     borderPainted = b;
1137:     firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, old, b);
1138:     revalidate();
1139:     repaint();
1140:   }
1141: 
1142:   /**
1143:    * Get the value of the "action" property. 
1144:    *
1145:    * @return The current value of the "action" property
1146:    */
1147:   public Action getAction()
1148:   {
1149:     return action;
1150:   }
1151: 
1152:   /**
1153:    * <p>Set the button's "action" property, subscribing the new action to the
1154:    * button, as an ActionListener, if it is not already subscribed. The old
1155:    * Action, if it exists, is unsubscribed, and the button is unsubscribed
1156:    * from the old Action if it was previously subscribed as a
1157:    * PropertyChangeListener.</p>
1158:    *
1159:    * <p>This method also configures several of the button's properties from
1160:    * the Action, by calling {@link #configurePropertiesFromAction}, and
1161:    * subscribes the button to the Action as a PropertyChangeListener.
1162:    * Subsequent changes to the Action will thus reconfigure the button 
1163:    * automatically.</p>
1164:    *
1165:    * @param a The new value of the "action" property
1166:    */
1167:   public void setAction(Action a)
1168:   {
1169:     if (action != null)
1170:       {
1171:         action.removePropertyChangeListener(actionPropertyChangeListener);
1172:         removeActionListener(action);
1173:         if (actionPropertyChangeListener != null)
1174:           {
1175:             action.removePropertyChangeListener(actionPropertyChangeListener);
1176:             actionPropertyChangeListener = null;
1177:           }
1178:       }
1179: 
1180:     Action old = action;
1181:     action = a;
1182:     configurePropertiesFromAction(action);
1183:     if (action != null)
1184:       {
1185:         actionPropertyChangeListener = createActionPropertyChangeListener(a);      
1186:         action.addPropertyChangeListener(actionPropertyChangeListener);
1187:         addActionListener(action);
1188:       }
1189:   }
1190: 
1191:   /**
1192:    * Return the button's default "icon" property.
1193:    *
1194:    * @return The current default icon
1195:    */
1196:   public Icon getIcon()
1197:   {
1198:     return default_icon;
1199:   }
1200: 
1201:   /**
1202:    * Set the button's default "icon" property. This icon is used as a basis
1203:    * for the pressed and disabled icons, if none are explicitly set.
1204:    *
1205:    * @param i The new default icon
1206:    */
1207:   public void setIcon(Icon i)
1208:   {
1209:     if (default_icon == i)
1210:       return;
1211:     
1212:     Icon old = default_icon;      
1213:     default_icon = i;      
1214:     firePropertyChange(ICON_CHANGED_PROPERTY, old, i);
1215:     revalidate();
1216:     repaint();
1217:   }
1218: 
1219:   /**
1220:    * Return the button's "text" property. This property is synonymous with
1221:    * the "label" property.
1222:    *
1223:    * @return The current "text" property
1224:    */
1225:   public String getText()
1226:   {
1227:     return text;
1228:   }
1229: 
1230:   /**
1231:    * Set the button's "label" property. This property is synonymous with the
1232:    * "text" property.
1233:    *
1234:    * @param label The new "label" property
1235:    *
1236:    * @deprecated use <code>setText(text)</code>
1237:    */
1238:   public void setLabel(String label)
1239:   {
1240:     setText(label);
1241:   }
1242: 
1243:   /**
1244:    * Return the button's "label" property. This property is synonymous with
1245:    * the "text" property.
1246:    *
1247:    * @return The current "label" property
1248:    *
1249:    * @deprecated use <code>getText()</code>
1250:    */
1251:   public String getLabel()
1252:   {
1253:     return getText();
1254:   }
1255: 
1256:   /**
1257:    * Set the button's "text" property. This property is synonymous with the
1258:    * "label" property.
1259:    *
1260:    * @param t The new "text" property
1261:    */
1262:   public void setText(String t)
1263:   {
1264:     if (text == t)
1265:       return;
1266:     
1267:     String old = text;
1268:     text = t;
1269:     firePropertyChange(TEXT_CHANGED_PROPERTY, old, t);
1270:     revalidate();
1271:     repaint();
1272:   }
1273: 
1274:   /**
1275:    * Set the value of the {@link #iconTextGap} property.
1276:    * 
1277:    * @param i The new value of the property
1278:    */
1279:   public void setIconTextGap(int i)
1280:   {
1281:     if (iconTextGap == i)
1282:       return;
1283:     
1284:     int old = iconTextGap;
1285:     iconTextGap = i;
1286:     fireStateChanged();
1287:     revalidate();
1288:     repaint();
1289:   }
1290: 
1291:   /**
1292:    * Get the value of the {@link #iconTextGap} property.
1293:    *
1294:    * @return The current value of the property
1295:    */
1296:   public int getIconTextGap()
1297:   {
1298:     return iconTextGap;
1299:   }
1300: 
1301:   /**
1302:    * Return the button's "margin" property, which is an {@link Insets} object
1303:    * describing the distance between the button's border and its text and
1304:    * icon.
1305:    *
1306:    * @return The current "margin" property
1307:    */
1308:   public Insets getMargin()
1309:   {
1310:     return margin;
1311:   }
1312: 
1313:   /**
1314:    * Set the button's "margin" property, which is an {@link Insets} object
1315:    * describing the distance between the button's border and its text and
1316:    * icon.
1317:    *
1318:    * @param m The new "margin" property
1319:    */
1320:   public void setMargin(Insets m)
1321:   {
1322:     if (margin == m)
1323:       return;
1324:     
1325:     Insets old = margin;
1326:     margin = m;
1327:     firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);
1328:     revalidate();
1329:     repaint();
1330:   }
1331: 
1332:   /**
1333:    * Return the button's "pressedIcon" property. The look and feel class
1334:    * should paint this icon when the "pressed" property of the button's
1335:    * {@link ButtonModel} is <code>true</code>. This property may be
1336:    * <code>null</code>, in which case the default icon is used.
1337:    *
1338:    * @return The current "pressedIcon" property
1339:    */
1340:   public Icon getPressedIcon()
1341:   {
1342:     return pressed_icon;
1343:   }
1344: 
1345:   /**
1346:    * Set the button's "pressedIcon" property. The look and feel class
1347:    * should paint this icon when the "pressed" property of the button's
1348:    * {@link ButtonModel} is <code>true</code>. This property may be
1349:    * <code>null</code>, in which case the default icon is used.
1350:    *
1351:    * @param pressedIcon The new "pressedIcon" property
1352:    */
1353:   public void setPressedIcon(Icon pressedIcon)
1354:   {
1355:     if (pressed_icon == pressedIcon)
1356:       return;
1357:     
1358:     Icon old = pressed_icon;
1359:     pressed_icon = pressedIcon;
1360:     firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, old, pressed_icon);
1361:     revalidate();
1362:     repaint();
1363:   }
1364: 
1365:   /**
1366:    * Return the button's "disabledIcon" property. The look and feel class
1367:    * should paint this icon when the "enabled" property of the button's
1368:    * {@link ButtonModel} is <code>false</code>. This property may be
1369:    * <code>null</code>, in which case an icon is constructed, based on the
1370:    * default icon.
1371:    *
1372:    * @return The current "disabledIcon" property
1373:    */
1374:   public Icon getDisabledIcon()
1375:   {
1376:     if (disabeldIcon == null && default_icon instanceof ImageIcon)
1377:       {
1378:         Image iconImage = ((ImageIcon) default_icon).getImage();
1379:         Image grayImage = GrayFilter.createDisabledImage(iconImage);
1380:         disabeldIcon = new ImageIcon(grayImage);
1381:       }
1382:       
1383:     return disabeldIcon;
1384:   }
1385: 
1386:   /**
1387:    * Set the button's "disabledIcon" property. The look and feel class should
1388:    * paint this icon when the "enabled" property of the button's {@link
1389:    * ButtonModel} is <code>false</code>. This property may be
1390:    * <code>null</code>, in which case an icon is constructed, based on the
1391:    * default icon.
1392:    *
1393:    * @param d The new "disabledIcon" property
1394:    */
1395:   public void setDisabledIcon(Icon d)
1396:   {
1397:     disabeldIcon = d;
1398:     revalidate();
1399:     repaint();
1400:   }
1401: 
1402:   /**
1403:    * Return the button's "paintFocus" property. This property controls
1404:    * whether or not the look and feel class will paint a special indicator
1405:    * of focus state for the button. If it is false, the button still paints
1406:    * when focused, but no special decoration is painted to indicate the
1407:    * presence of focus.
1408:    *
1409:    * @return The current "paintFocus" property
1410:    */
1411:   public boolean isFocusPainted()
1412:   {
1413:     return focusPainted;
1414:   }
1415: 
1416:   /**
1417:    * Set the button's "paintFocus" property. This property controls whether
1418:    * or not the look and feel class will paint a special indicator of focus
1419:    * state for the button. If it is false, the button still paints when
1420:    * focused, but no special decoration is painted to indicate the presence
1421:    * of focus.
1422:    *
1423:    * @param p The new "paintFocus" property
1424:    */
1425:   public void setFocusPainted(boolean p)
1426:   {
1427:     if (focusPainted == p)
1428:       return;
1429:     
1430:     boolean old = focusPainted;
1431:     focusPainted = p;
1432:     firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, old, p);
1433:     revalidate();
1434:     repaint();
1435:   }
1436: 
1437:   /**
1438:    * Verifies that a particular key is one of the valid constants used for
1439:    * describing horizontal alignment and positioning. The valid constants
1440:    * are the following members of {@link SwingConstants}:
1441:    * <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
1442:    * <code>LEADING</code> or <code>TRAILING</code>.
1443:    *
1444:    * @param key The key to check
1445:    * @param exception A message to include in an IllegalArgumentException
1446:    *
1447:    * @return the value of key
1448:    *
1449:    * @throws IllegalArgumentException If key is not one of the valid constants
1450:    *
1451:    * @see #setHorizontalTextPosition(int)
1452:    * @see #setHorizontalAlignment(int)
1453:    */
1454:   protected  int checkHorizontalKey(int key, String exception)
1455:   {
1456:     switch (key)
1457:       {
1458:       case SwingConstants.RIGHT:
1459:       case SwingConstants.LEFT:
1460:       case SwingConstants.CENTER:
1461:       case SwingConstants.LEADING:
1462:       case SwingConstants.TRAILING:
1463:         break;
1464:       default:
1465:         throw new IllegalArgumentException(exception);
1466:       }
1467:     return key;
1468:   }
1469: 
1470:   /**
1471:    * Verifies that a particular key is one of the valid constants used for
1472:    * describing vertical alignment and positioning. The valid constants are
1473:    * the following members of {@link SwingConstants}: <code>TOP</code>,
1474:    * <code>BOTTOM</code> or <code>CENTER</code>.
1475:    *
1476:    * @param key The key to check
1477:    * @param exception A message to include in an IllegalArgumentException
1478:    *
1479:    * @return the value of key
1480:    *
1481:    * @throws IllegalArgumentException If key is not one of the valid constants
1482:    *
1483:    * @see #setVerticalTextPosition(int)
1484:    * @see #setVerticalAlignment(int)
1485:    */
1486:   protected  int checkVerticalKey(int key, String exception)
1487:   {
1488:     switch (key)
1489:       {
1490:       case SwingConstants.TOP:
1491:       case SwingConstants.BOTTOM:
1492:       case SwingConstants.CENTER:
1493:         break;
1494:       default:
1495:         throw new IllegalArgumentException(exception);
1496:       }
1497:     return key;
1498:   }
1499: 
1500:   /**
1501:    * Configure various properties of the button by reading properties
1502:    * of an {@link Action}. The mapping of properties is as follows:
1503:    *
1504:    * <table>
1505:    *
1506:    * <tr><th>Action keyed property</th> <th>AbstractButton property</th></tr>
1507:    *
1508:    * <tr><td>NAME                 </td> <td>text                   </td></tr>
1509:    * <tr><td>SMALL_ICON           </td> <td>icon                   </td></tr>
1510:    * <tr><td>SHORT_DESCRIPTION    </td> <td>toolTipText            </td></tr>
1511:    * <tr><td>MNEMONIC_KEY         </td> <td>mnemonic               </td></tr>
1512:    * <tr><td>ACTION_COMMAND_KEY   </td> <td>actionCommand          </td></tr>
1513:    *
1514:    * </table>
1515:    *
1516:    * <p>In addition, this method always sets the button's "enabled" property to
1517:    * the value of the Action's "enabled" property.</p>
1518:    *
1519:    * <p>If the provided Action is <code>null</code>, the text, icon, and
1520:    * toolTipText properties of the button are set to <code>null</code>, and
1521:    * the "enabled" property is set to <code>true</code>; the mnemonic and
1522:    * actionCommand properties are unchanged.</p>
1523:    *
1524:    * @param a An Action to configure the button from
1525:    */
1526:   protected void configurePropertiesFromAction(Action a)
1527:   {
1528:     if (a == null)
1529:       {
1530:         setText(null);
1531:         setIcon(null);
1532:         setEnabled(true);
1533:         setToolTipText(null);
1534:       }
1535:     else
1536:       {
1537:         setText((String) (a.getValue(Action.NAME)));
1538:         setIcon((Icon) (a.getValue(Action.SMALL_ICON)));
1539:         setEnabled(a.isEnabled());
1540:         setToolTipText((String) (a.getValue(Action.SHORT_DESCRIPTION)));
1541:         if (a.getValue(Action.MNEMONIC_KEY) != null)
1542:           setMnemonic(((Integer) (a.getValue(Action.MNEMONIC_KEY))).intValue());
1543:         String actionCommand = (String) (a.getValue(Action.ACTION_COMMAND_KEY));
1544: 
1545:         // Set actionCommand to button's text by default if it is not specified
1546:         if (actionCommand != null)
1547:           setActionCommand((String) (a.getValue(Action.ACTION_COMMAND_KEY)));
1548:         else
1549:           setActionCommand(getText());
1550:       }
1551:   }
1552: 
1553:   /**
1554:    * <p>A factory method which should return an {@link ActionListener} that
1555:    * propagates events from the button's {@link ButtonModel} to any of the
1556:    * button's ActionListeners. By default, this is an inner class which
1557:    * calls {@link AbstractButton#fireActionPerformed} with a modified copy
1558:    * of the incoming model {@link ActionEvent}.</p>
1559:    *
1560:    * <p>The button calls this method during construction, stores the
1561:    * resulting ActionListener in its <code>actionListener</code> member
1562:    * field, and subscribes it to the button's model. If the button's model
1563:    * is changed, this listener is unsubscribed from the old model and
1564:    * subscribed to the new one.</p>
1565:    *
1566:    * @return A new ActionListener 
1567:    */
1568:   protected  ActionListener createActionListener()
1569:   {
1570:     return new ActionListener()
1571:       {
1572:         public void actionPerformed(ActionEvent e)
1573:         {
1574:           AbstractButton.this.fireActionPerformed(e);
1575:         }
1576:       };
1577:   }
1578: 
1579:   /**
1580:    * <p>A factory method which should return a {@link PropertyChangeListener}
1581:    * that accepts changes to the specified {@link Action} and reconfigure
1582:    * the {@link AbstractButton}, by default using the {@link
1583:    * #configurePropertiesFromAction} method.</p>
1584:    *
1585:    * <p>The button calls this method whenever a new Action is assigned to
1586:    * the button's "action" property, via {@link #setAction}, and stores the
1587:    * resulting PropertyChangeListener in its
1588:    * <code>actionPropertyChangeListener</code> member field. The button
1589:    * then subscribes the listener to the button's new action. If the
1590:    * button's action is changed subsequently, the listener is unsubscribed
1591:    * from the old action and subscribed to the new one.</p>
1592:    *
1593:    * @param a The Action which will be listened to, and which should be 
1594:    * the same as the source of any PropertyChangeEvents received by the
1595:    * new listener returned from this method.
1596:    *
1597:    * @return A new PropertyChangeListener
1598:    */
1599:   protected  PropertyChangeListener createActionPropertyChangeListener(Action a)
1600:   {
1601:     return new PropertyChangeListener()
1602:       {
1603:         public void propertyChange(PropertyChangeEvent e)
1604:         {
1605:           Action act = (Action) (e.getSource());
1606:           if (e.getPropertyName().equals("enabled"))
1607:             setEnabled(act.isEnabled());
1608:           else if (e.getPropertyName().equals(Action.NAME))
1609:             setText((String) (act.getValue(Action.NAME)));
1610:           else if (e.getPropertyName().equals(Action.SMALL_ICON))
1611:             setIcon((Icon) (act.getValue(Action.SMALL_ICON)));
1612:           else if (e.getPropertyName().equals(Action.SHORT_DESCRIPTION))
1613:             setToolTipText((String) (act.getValue(Action.SHORT_DESCRIPTION)));
1614:           else if (e.getPropertyName().equals(Action.MNEMONIC_KEY))
1615:             if (act.getValue(Action.MNEMONIC_KEY) != null)
1616:               setMnemonic(((Integer) (act.getValue(Action.MNEMONIC_KEY)))
1617:                           .intValue());
1618:           else if (e.getPropertyName().equals(Action.ACTION_COMMAND_KEY))
1619:             setActionCommand((String) (act.getValue(Action.ACTION_COMMAND_KEY)));
1620:         }
1621:       };
1622:   }
1623: 
1624:   /**
1625:    * <p>Factory method which creates a {@link ChangeListener}, used to
1626:    * subscribe to ChangeEvents from the button's model. Subclasses of
1627:    * AbstractButton may wish to override the listener used to subscribe to
1628:    * such ChangeEvents. By default, the listener just propagates the
1629:    * {@link ChangeEvent} to the button's ChangeListeners, via the {@link
1630:    * AbstractButton#fireStateChanged} method.</p>
1631:    *
1632:    * <p>The button calls this method during construction, stores the
1633:    * resulting ChangeListener in its <code>changeListener</code> member
1634:    * field, and subscribes it to the button's model. If the button's model
1635:    * is changed, this listener is unsubscribed from the old model and
1636:    * subscribed to the new one.</p>
1637:    *
1638:    * @return The new ChangeListener
1639:    */
1640:   protected ChangeListener createChangeListener()
1641:   {
1642:     return new ButtonChangeListener();
1643:   }
1644: 
1645:   /**
1646:    * <p>Factory method which creates a {@link ItemListener}, used to
1647:    * subscribe to ItemEvents from the button's model. Subclasses of
1648:    * AbstractButton may wish to override the listener used to subscribe to
1649:    * such ItemEvents. By default, the listener just propagates the
1650:    * {@link ItemEvent} to the button's ItemListeners, via the {@link
1651:    * AbstractButton#fireItemStateChanged} method.</p>
1652:    *
1653:    * <p>The button calls this method during construction, stores the
1654:    * resulting ItemListener in its <code>changeListener</code> member
1655:    * field, and subscribes it to the button's model. If the button's model
1656:    * is changed, this listener is unsubscribed from the old model and
1657:    * subscribed to the new one.</p>
1658:    *
1659:    * <p>Note that ItemEvents are only generated from the button's model
1660:    * when the model's <em>selected</em> property changes. If you want to
1661:    * subscribe to other properties of the model, you must subscribe to
1662:    * ChangeEvents.
1663:    *
1664:    * @return The new ItemListener
1665:    */
1666:   protected  ItemListener createItemListener()
1667:   {
1668:     return new ItemListener()
1669:       {
1670:         public void itemStateChanged(ItemEvent e)
1671:         {
1672:           AbstractButton.this.fireItemStateChanged(e);
1673:         }
1674:       };
1675:   }
1676: 
1677:   /**
1678:    * Programmatically perform a "click" on the button: arming, pressing,
1679:    * waiting, un-pressing, and disarming the model.
1680:    */
1681:   public void doClick()
1682:   {
1683:     doClick(100);
1684:   }
1685: 
1686:   /**
1687:    * Programmatically perform a "click" on the button: arming, pressing,
1688:    * waiting, un-pressing, and disarming the model.
1689:    *
1690:    * @param pressTime The number of milliseconds to wait in the pressed state
1691:    */
1692:   public void doClick(int pressTime)
1693:   {
1694:     ButtonModel mod = getModel();
1695:     if (mod != null)
1696:       {
1697:         mod.setArmed(true);
1698:         mod.setPressed(true);
1699:         try
1700:           {
1701:             java.lang.Thread.sleep(pressTime);
1702:           }
1703:         catch (java.lang.InterruptedException e)
1704:           {
1705:             // probably harmless
1706:           }
1707:         mod.setPressed(false);
1708:         mod.setArmed(false);
1709:       }
1710:   }
1711: 
1712:   /**
1713:    * Return the button's disabled selected icon. The look and feel class
1714:    * should paint this icon when the "enabled" property of the button's model
1715:    * is <code>false</code> and its "selected" property is
1716:    * <code>true</code>. This icon can be <code>null</code>, in which case
1717:    * it is synthesized from the button's selected icon.
1718:    *
1719:    * @return The current disabled selected icon
1720:    */
1721:   public Icon getDisabledSelectedIcon()
1722:   {
1723:     return disabledSelectedIcon;
1724:   }
1725: 
1726:   /**
1727:    * Set the button's disabled selected icon. The look and feel class
1728:    * should paint this icon when the "enabled" property of the button's model
1729:    * is <code>false</code> and its "selected" property is
1730:    * <code>true</code>. This icon can be <code>null</code>, in which case
1731:    * it is synthesized from the button's selected icon.
1732:    *
1733:    * @param icon The new disabled selected icon
1734:    */
1735:   public void setDisabledSelectedIcon(Icon icon)
1736:   {
1737:     if (disabledSelectedIcon == icon)
1738:       return;
1739:     
1740:     Icon old = disabledSelectedIcon;
1741:     disabledSelectedIcon = icon;
1742:     firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, old, icon);
1743:     revalidate();
1744:     repaint();        
1745:   }
1746: 
1747:   /**
1748:    * Return the button's rollover icon. The look and feel class should
1749:    * paint this icon when the "rolloverEnabled" property of the button is
1750:    * <code>true</code> and the mouse rolls over the button.
1751:    *
1752:    * @return The current rollover icon
1753:    */
1754:   public Icon getRolloverIcon()
1755:   {
1756:     return rolloverIcon;
1757:   }
1758: 
1759:   /**
1760:    * Set the button's rollover icon. The look and feel class should
1761:    * paint this icon when the "rolloverEnabled" property of the button is
1762:    * <code>true</code> and the mouse rolls over the button.
1763:    *
1764:    * @param r The new rollover icon
1765:    */
1766:   public void setRolloverIcon(Icon r)
1767:   {
1768:     if (rolloverIcon == r)
1769:       return;
1770:     
1771:     Icon old = rolloverIcon;
1772:     rolloverIcon = r;
1773:     firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, old, rolloverIcon);
1774:     revalidate();
1775:     repaint();
1776:   }
1777: 
1778:   /**
1779:    * Return the button's rollover selected icon. The look and feel class
1780:    * should paint this icon when the "rolloverEnabled" property of the button
1781:    * is <code>true</code>, the "selected" property of the button's model is
1782:    * <code>true</code>, and the mouse rolls over the button.
1783:    *
1784:    * @return The current rollover selected icon
1785:    */
1786:   public Icon getRolloverSelectedIcon()
1787:   {
1788:     return rolloverSelectedIcon;
1789:   }
1790: 
1791:   /**
1792:    * Set the button's rollover selected icon. The look and feel class
1793:    * should paint this icon when the "rolloverEnabled" property of the button
1794:    * is <code>true</code>, the "selected" property of the button's model is
1795:    * <code>true</code>, and the mouse rolls over the button.
1796:    *
1797:    * @param r The new rollover selected icon
1798:    */
1799:   public void setRolloverSelectedIcon(Icon r)
1800:   {
1801:     if (rolloverSelectedIcon == r)
1802:       return;
1803:     
1804:     Icon old = rolloverSelectedIcon;
1805:     rolloverSelectedIcon = r;
1806:     firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, old, r);
1807:     revalidate();
1808:     repaint();
1809:   }
1810: 
1811:   /**
1812:    * Return the button's selected icon. The look and feel class should
1813:    * paint this icon when the "selected" property of the button's model is
1814:    * <code>true</code>, and either the "rolloverEnabled" property of the
1815:    * button is <code>false</code> or the mouse is not currently rolled
1816:    * over the button.
1817:    *
1818:    * @return The current selected icon
1819:    */
1820:   public Icon getSelectedIcon()
1821:   {
1822:     return selectedIcon;
1823:   }
1824: 
1825:   /**
1826:    * Set the button's selected icon. The look and feel class should
1827:    * paint this icon when the "selected" property of the button's model is
1828:    * <code>true</code>, and either the "rolloverEnabled" property of the
1829:    * button is <code>false</code> or the mouse is not currently rolled
1830:    * over the button.
1831:    *
1832:    * @param s The new selected icon
1833:    */
1834:   public void setSelectedIcon(Icon s)
1835:   {
1836:     if (selectedIcon == s)
1837:       return;
1838:     
1839:     Icon old = selectedIcon;
1840:     selectedIcon = s;
1841:     firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, old, s);
1842:     revalidate();
1843:     repaint();
1844:   }
1845: 
1846:   /**
1847:    * Returns an single-element array containing the "text" property of the
1848:    * button if the "selected" property of the button's model is
1849:    * <code>true</code>, otherwise returns <code>null</code>.
1850:    *
1851:    * @return The button's "selected object" array
1852:    */
1853:   public Object[] getSelectedObjects()
1854:   {
1855:     if (isSelected())
1856:       {
1857:         Object[] objs = new Object[1];
1858:         objs[0] = getText();
1859:         return objs;
1860:       }
1861:     else
1862:       {
1863:         return null;
1864:       }
1865:   }
1866: 
1867:   /**
1868:    * Called when image data becomes available for one of the button's icons.
1869:    *
1870:    * @param img The image being updated
1871:    * @param infoflags One of the constant codes in {@link ImageObserver} used
1872:    *     to describe updated portions of an image.
1873:    * @param x X coordinate of the region being updated
1874:    * @param y Y coordinate of the region being updated
1875:    * @param w Width of the region beign updated
1876:    * @param h Height of the region being updated
1877:    *
1878:    * @return <code>true</code> if img is equal to the button's current icon,
1879:    *     otherwise <code>false</code>
1880:    */
1881:   public boolean imageUpdate(Image img, int infoflags, int x, int y, int w,
1882:                              int h)
1883:   {
1884:     return current_icon == img;
1885:   }
1886: 
1887:   /**
1888:    * Returns the value of the button's "contentAreaFilled" property. This
1889:    * property indicates whether the area surrounding the text and icon of
1890:    * the button should be filled by the look and feel class.  If this
1891:    * property is <code>false</code>, the look and feel class should leave
1892:    * the content area transparent.
1893:    *
1894:    * @return The current value of the "contentAreaFilled" property
1895:    */
1896:   public boolean isContentAreaFilled()
1897:   {
1898:     return contentAreaFilled;
1899:   }
1900: 
1901:   /**
1902:    * Sets the value of the button's "contentAreaFilled" property. This
1903:    * property indicates whether the area surrounding the text and icon of
1904:    * the button should be filled by the look and feel class.  If this
1905:    * property is <code>false</code>, the look and feel class should leave
1906:    * the content area transparent.
1907:    *
1908:    * @param b The new value of the "contentAreaFilled" property
1909:    */
1910:   public void setContentAreaFilled(boolean b)
1911:   {
1912:     if (contentAreaFilled == b)
1913:       return;
1914:     
1915:     boolean old = contentAreaFilled;
1916:     contentAreaFilled = b;
1917:     firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, old, b);
1918:     // The JDK sets the opaque property to the value of the contentAreaFilled
1919:     // property, so should we do.
1920:     setOpaque(b);
1921:    }
1922: 
1923:   /**
1924:    * Paints the button's border, if the button's "borderPainted" property is
1925:    * <code>true</code>, by out calling to the button's look and feel class.
1926:    *
1927:    * @param g The graphics context used to paint the border
1928:    */
1929:   protected void paintBorder(Graphics g)
1930:   {
1931:     if (isBorderPainted())
1932:       super.paintBorder(g);
1933:   }
1934: 
1935:   /**
1936:    * Returns a string, used only for debugging, which identifies or somehow
1937:    * represents this button. The exact value is implementation-defined.
1938:    *
1939:    * @return A string representation of the button
1940:    */
1941:   protected String paramString()
1942:   {
1943:     StringBuffer sb = new StringBuffer();
1944:     sb.append(super.paramString());
1945:     sb.append(",defaultIcon=");
1946:     if (getIcon() != null)
1947:       sb.append(getIcon());
1948:     sb.append(",disabledIcon=");
1949:     if (getDisabledIcon() != null)
1950:       sb.append(getDisabledIcon());
1951:     sb.append(",disabledSelectedIcon=");
1952:     if (getDisabledSelectedIcon() != null)
1953:       sb.append(getDisabledSelectedIcon());
1954:     sb.append(",margin=");
1955:     if (getMargin() != null)
1956:       sb.append(getMargin());
1957:     sb.append(",paintBorder=").append(isBorderPainted());
1958:     sb.append(",paintFocus=").append(isFocusPainted());
1959:     sb.append(",pressedIcon=");
1960:     if (getPressedIcon() != null)
1961:       sb.append(getPressedIcon());
1962:     sb.append(",rolloverEnabled=").append(isRolloverEnabled());
1963:     sb.append(",rolloverIcon=");
1964:     if (getRolloverIcon() != null)
1965:       sb.append(getRolloverIcon());
1966:     sb.append(",rolloverSelected=");
1967:     if (getRolloverSelectedIcon() != null)
1968:       sb.append(getRolloverSelectedIcon());
1969:     sb.append(",selectedIcon=");
1970:     if (getSelectedIcon() != null)
1971:       sb.append(getSelectedIcon());
1972:     sb.append(",text=");
1973:     if (getText() != null)
1974:       sb.append(getText());
1975:     return sb.toString();
1976:   }
1977: 
1978:   /**
1979:    * Set the "UI" property of the button, which is a look and feel class
1980:    * responsible for handling the button's input events and painting it.
1981:    *
1982:    * @param ui The new "UI" property
1983:    */
1984:   public void setUI(ButtonUI ui)
1985:   {
1986:     super.setUI(ui);
1987:   }
1988:   
1989:   /**
1990:    * Set the "UI" property of the button, which is a look and feel class
1991:    * responsible for handling the button's input events and painting it.
1992:    *
1993:    * @return The current "UI" property
1994:    */
1995:   public ButtonUI getUI()
1996:   {
1997:     return (ButtonUI) ui;
1998:   }
1999:   
2000:   /**
2001:    * Set the "UI" property to a class constructed, via the {@link
2002:    * UIManager}, from the current look and feel. This should be overridden
2003:    * for each subclass of AbstractButton, to retrieve a suitable {@link
2004:    * ButtonUI} look and feel class.
2005:    */
2006:   public void updateUI()
2007:   {
2008:     // TODO: What to do here?
2009:   }
2010: 
2011:   /**
2012:    * Returns the current time in milliseconds in which clicks gets coalesced
2013:    * into a single <code>ActionEvent</code>.
2014:    *
2015:    * @return the time in milliseconds
2016:    * 
2017:    * @since 1.4
2018:    */
2019:   public long getMultiClickThreshhold()
2020:   {
2021:     return multiClickThreshhold;
2022:   }
2023: 
2024:   /**
2025:    * Sets the time in milliseconds in which clicks gets coalesced into a single
2026:    * <code>ActionEvent</code>.
2027:    *
2028:    * @param threshhold the time in milliseconds
2029:    * 
2030:    * @since 1.4
2031:    */
2032:   public void setMultiClickThreshhold(long threshhold)
2033:   {
2034:     if (threshhold < 0)
2035:       throw new IllegalArgumentException();
2036: 
2037:     multiClickThreshhold = threshhold;
2038:   }
2039: }