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