Source for javax.swing.AbstractButton

   1: /* AbstractButton.java -- Provides basic button functionality.
   2:    Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package javax.swing;
  39: 
  40: import java.awt.Component;
  41: import java.awt.Graphics;
  42: import java.awt.Image;
  43: import java.awt.Insets;
  44: import java.awt.ItemSelectable;
  45: import java.awt.LayoutManager;
  46: import java.awt.Point;
  47: import java.awt.Rectangle;
  48: import java.awt.Shape;
  49: import java.awt.event.ActionEvent;
  50: import java.awt.event.ActionListener;
  51: import java.awt.event.ItemEvent;
  52: import java.awt.event.ItemListener;
  53: import java.awt.image.ImageObserver;
  54: import java.beans.PropertyChangeEvent;
  55: import java.beans.PropertyChangeListener;
  56: import java.io.Serializable;
  57: import java.util.Enumeration;
  58: 
  59: import javax.accessibility.Accessible;
  60: import javax.accessibility.AccessibleAction;
  61: import javax.accessibility.AccessibleContext;
  62: import javax.accessibility.AccessibleIcon;
  63: import javax.accessibility.AccessibleRelation;
  64: import javax.accessibility.AccessibleRelationSet;
  65: import javax.accessibility.AccessibleState;
  66: import javax.accessibility.AccessibleStateSet;
  67: import javax.accessibility.AccessibleText;
  68: import javax.accessibility.AccessibleValue;
  69: import javax.swing.event.ChangeEvent;
  70: import javax.swing.event.ChangeListener;
  71: import javax.swing.plaf.ButtonUI;
  72: import javax.swing.plaf.basic.BasicHTML;
  73: import javax.swing.text.AttributeSet;
  74: import javax.swing.text.BadLocationException;
  75: import javax.swing.text.Document;
  76: import javax.swing.text.Element;
  77: import javax.swing.text.Position;
  78: import javax.swing.text.StyledDocument;
  79: import javax.swing.text.View;
  80: 
  81: 
  82: /**
  83:  * Provides an abstract implementation of common button behaviour,
  84:  * data model and look & feel.
  85:  *
  86:  * <p>This class is supposed to serve as a base class for
  87:  * several kinds of buttons with similar but non-identical semantics:
  88:  * toggle buttons (radio buttons and checkboxes), simple push buttons,
  89:  * menu items, etc.</p>
  90:  *
  91:  * <p>Buttons have many properties, some of which are stored in this class
  92:  * while others are delegated to the button's model. The following properties
  93:  * are available:</p>
  94:  *
  95:  * <table>
  96:  * <tr><th>Property               </th><th>Stored in</th><th>Bound?</th></tr>
  97:  *
  98:  * <tr><td>action                 </td><td>button</td> <td>no</td></tr>
  99:  * <tr><td>actionCommand          </td><td>model</td>  <td>no</td></tr>
 100:  * <tr><td>borderPainted          </td><td>button</td> <td>yes</td></tr>
 101:  * <tr><td>contentAreaFilled      </td><td>button</td> <td>yes</td></tr>
 102:  * <tr><td>disabledIcon           </td><td>button</td> <td>yes</td></tr>
 103:  * <tr><td>disabledSelectedIcon   </td><td>button</td> <td>yes</td></tr>
 104:  * <tr><td>displayedMnemonicIndex </td><td>button</td> <td>no</td></tr>
 105:  * <tr><td>enabled                </td><td>model</td>  <td>no</td></tr>
 106:  * <tr><td>focusPainted           </td><td>button</td> <td>yes</td></tr>
 107:  * <tr><td>horizontalAlignment    </td><td>button</td> <td>yes</td></tr>
 108:  * <tr><td>horizontalTextPosition </td><td>button</td> <td>yes</td></tr>
 109:  * <tr><td>icon                   </td><td>button</td> <td>yes</td></tr>
 110:  * <tr><td>iconTextGap            </td><td>button</td> <td>no</td></tr>
 111:  * <tr><td>label (same as text)   </td><td>model</td>  <td>yes</td></tr>
 112:  * <tr><td>margin                 </td><td>button</td> <td>yes</td></tr>
 113:  * <tr><td>multiClickThreshold    </td><td>button</td> <td>no</td></tr>
 114:  * <tr><td>pressedIcon            </td><td>button</td> <td>yes</td></tr>
 115:  * <tr><td>rolloverEnabled        </td><td>button</td> <td>yes</td></tr>
 116:  * <tr><td>rolloverIcon           </td><td>button</td> <td>yes</td></tr>
 117:  * <tr><td>rolloverSelectedIcon   </td><td>button</td> <td>yes</td></tr>
 118:  * <tr><td>selected               </td><td>model</td>  <td>no</td></tr>
 119:  * <tr><td>selectedIcon           </td><td>button</td> <td>yes</td></tr>
 120:  * <tr><td>selectedObjects        </td><td>button</td> <td>no</td></tr>
 121:  * <tr><td>text                   </td><td>model</td>  <td>yes</td></tr>
 122:  * <tr><td>UI                     </td><td>button</td> <td>yes</td></tr>
 123:  * <tr><td>verticalAlignment      </td><td>button</td> <td>yes</td></tr>
 124:  * <tr><td>verticalTextPosition   </td><td>button</td> <td>yes</td></tr>
 125:  *
 126:  * </table>
 127:  *
 128:  * <p>The various behavioral aspects of these properties follows:</p>
 129:  *
 130:  * <ul> 
 131:  *
 132:  * <li>When non-bound properties stored in the button change, the button
 133:  * fires ChangeEvents to its ChangeListeners.</li>
 134:  * 
 135:  * <li>When bound properties stored in the button change, the button fires
 136:  * PropertyChangeEvents to its PropertyChangeListeners</li>
 137:  *
 138:  * <li>If any of the model's properties change, it fires a ChangeEvent to
 139:  * its ChangeListeners, which include the button.</li>
 140:  *
 141:  * <li>If the button receives a ChangeEvent from its model, it will
 142:  * propagate the ChangeEvent to its ChangeListeners, with the ChangeEvent's
 143:  * "source" property set to refer to the button, rather than the model. The
 144:  * the button will request a repaint, to paint its updated state.</li>
 145:  *
 146:  * <li>If the model's "selected" property changes, the model will fire an
 147:  * ItemEvent to its ItemListeners, which include the button, in addition to
 148:  * the ChangeEvent which models the property change. The button propagates
 149:  * ItemEvents directly to its ItemListeners.</li>
 150:  *
 151:  * <li>If the model's armed and pressed properties are simultaneously
 152:  * <code>true</code>, the model will fire an ActionEvent to its
 153:  * ActionListeners, which include the button. The button will propagate
 154:  * this ActionEvent to its ActionListeners, with the ActionEvent's "source"
 155:  * property set to refer to the button, rather than the model.</li>
 156:  *
 157:  * </ul>
 158:  *
 159:  * @author Ronald Veldema (rveldema@cs.vu.nl)
 160:  * @author Graydon Hoare (graydon@redhat.com)
 161:  */
 162: 
 163: public abstract class AbstractButton extends JComponent
 164:   implements ItemSelectable, SwingConstants
 165: {
 166:   private static final long serialVersionUID = -937921345538462020L;
 167: 
 168:   /**
 169:    * An extension of ChangeListener to be serializable.
 170:    */
 171:   protected class ButtonChangeListener
 172:     implements ChangeListener, Serializable
 173:   {
 174:     private static final long serialVersionUID = 1471056094226600578L;
 175: 
 176:     /**
 177:      * The spec has no public/protected constructor for this class, so do we.
 178:      */
 179:     ButtonChangeListener()
 180:     {
 181:       // Nothing to do here.
 182:     }
 183: 
 184:     /**
 185:      * Notified when the target of the listener changes its state.
 186:      *
 187:      * @param ev the ChangeEvent describing the change
 188:      */
 189:     public void stateChanged(ChangeEvent ev)
 190:     {
 191:       getEventHandler().stateChanged(ev);
 192:     }
 193:   }
 194: 
 195:   /**
 196:    * The combined event handler for ActionEvent, ChangeEvent and
 197:    * ItemEvent. This combines ButtonChangeListener, ActionListener
 198:    */
 199:   private class EventHandler
 200:     implements ActionListener, ChangeListener, ItemListener
 201:   {
 202:     public void actionPerformed(ActionEvent ev)
 203:     {
 204:       fireActionPerformed(ev);
 205:     }
 206: 
 207:     public void stateChanged(ChangeEvent ev)
 208:     {
 209:       fireStateChanged();
 210:       repaint();
 211:     }
 212: 
 213:     public void itemStateChanged(ItemEvent ev)
 214:     {
 215:       fireItemStateChanged(ev);
 216:     }
 217:   }
 218: 
 219:   /** The icon displayed by default. */
 220:   Icon default_icon;
 221: 
 222:   /** The icon displayed when the button is pressed. */
 223:   Icon pressed_icon;
 224: 
 225:   /** The icon displayed when the button is disabled. */
 226:   Icon disabledIcon;
 227: 
 228:   /** The icon displayed when the button is selected. */
 229:   Icon selectedIcon;
 230: 
 231:   /** The icon displayed when the button is selected but disabled. */
 232:   Icon disabledSelectedIcon;
 233: 
 234:   /** The icon displayed when the button is rolled over. */
 235:   Icon rolloverIcon;
 236: 
 237:   /** The icon displayed when the button is selected and rolled over. */
 238:   Icon rolloverSelectedIcon;
 239: 
 240:   /** The icon currently displayed. */
 241:   Icon current_icon;
 242: 
 243:   /** The text displayed in the button. */
 244:   String text;
 245: 
 246:   /**
 247:    * The gap between icon and text, if both icon and text are
 248:    * non-<code>null</code>.
 249:    */
 250:   int iconTextGap;
 251: 
 252:   /** The vertical alignment of the button's text and icon. */
 253:   int verticalAlignment;
 254: 
 255:   /** The horizontal alignment of the button's text and icon. */
 256:   int horizontalAlignment;
 257: 
 258:   /** The horizontal position of the button's text relative to its icon. */
 259:   int horizontalTextPosition;
 260: 
 261:   /** The vertical position of the button's text relative to its icon. */
 262:   int verticalTextPosition;
 263: 
 264:   /** Whether or not the button paints its border. */
 265:   boolean borderPainted;
 266: 
 267:   /** Whether or not the button paints its focus state. */
 268:   boolean focusPainted;
 269: 
 270:   /** Whether or not the button fills its content area. */
 271:   boolean contentAreaFilled;
 272:   
 273:   /** Whether rollover is enabled. */
 274:   boolean rollOverEnabled;
 275: 
 276:   /** The action taken when the button is clicked. */
 277:   Action action;
 278: 
 279:   /** The button's current state. */
 280:   protected ButtonModel model;
 281: 
 282:   /** The margin between the button's border and its label. */
 283:   Insets margin;
 284: 
 285:   /**
 286:    * A hint to the look and feel class, suggesting which character in the
 287:    * button's label should be underlined when drawing the label.
 288:    */
 289:   int mnemonicIndex;
 290: 
 291:   /**
 292:    * Listener the button uses to receive ActionEvents from its model.
 293:    */
 294:   protected ActionListener actionListener;
 295: 
 296:   /**
 297:    * Listener the button uses to receive ItemEvents from its model.
 298:    */
 299:   protected ItemListener itemListener;
 300: 
 301:   /**
 302:    * Listener the button uses to receive ChangeEvents from its model.
 303:    */  
 304:   protected ChangeListener changeListener;
 305: 
 306:   /**
 307:    * The event handler for ActionEvent, ItemEvent and ChangeEvent.
 308:    * This replaces the above three handlers and combines them
 309:    * into one for efficiency.
 310:    */
 311:   private EventHandler eventHandler;
 312: 
 313:   /**
 314:    * The time in milliseconds in which clicks get coalesced into a single
 315:    * <code>ActionEvent</code>.
 316:    */
 317:   long multiClickThreshhold;
 318:   
 319:   /**
 320:    * Listener the button uses to receive PropertyChangeEvents from its
 321:    * Action.
 322:    */
 323:   PropertyChangeListener actionPropertyChangeListener;
 324:   
 325:   /** ChangeEvent that is fired to button's ChangeEventListeners  */  
 326:   protected ChangeEvent changeEvent = new ChangeEvent(this);
 327:   
 328:   /**
 329:    * Indicates if the borderPainted property has been set by a client
 330:    * program or by the UI.
 331:    *
 332:    * @see #setUIProperty(String, Object)
 333:    * @see LookAndFeel#installProperty(JComponent, String, Object)
 334:    */
 335:   private boolean clientBorderPaintedSet = false;
 336: 
 337:   /**
 338:    * Indicates if the rolloverEnabled property has been set by a client
 339:    * program or by the UI.
 340:    *
 341:    * @see #setUIProperty(String, Object)
 342:    * @see LookAndFeel#installProperty(JComponent, String, Object)
 343:    */
 344:   private boolean clientRolloverEnabledSet = false;
 345: 
 346:   /**
 347:    * Indicates if the iconTextGap property has been set by a client
 348:    * program or by the UI.
 349:    *
 350:    * @see #setUIProperty(String, Object)
 351:    * @see LookAndFeel#installProperty(JComponent, String, Object)
 352:    */
 353:   private boolean clientIconTextGapSet = false;
 354: 
 355:   /**
 356:    * Indicates if the contentAreaFilled property has been set by a client
 357:    * program or by the UI.
 358:    *
 359:    * @see #setUIProperty(String, Object)
 360:    * @see LookAndFeel#installProperty(JComponent, String, Object)
 361:    */
 362:   private boolean clientContentAreaFilledSet = false;
 363: 
 364:   /**
 365:    * Fired in a PropertyChangeEvent when the "borderPainted" property changes.
 366:    */
 367:   public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";
 368:   
 369:   /**
 370:    * Fired in a PropertyChangeEvent when the "contentAreaFilled" property
 371:    * changes.
 372:    */
 373:   public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY =
 374:     "contentAreaFilled";
 375:   
 376:   /**
 377:    * Fired in a PropertyChangeEvent when the "disabledIcon" property changes.
 378:    */
 379:   public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";
 380:   
 381:   /**
 382:    * Fired in a PropertyChangeEvent when the "disabledSelectedIcon" property
 383:    * changes.
 384:    */
 385:   public static final String DISABLED_SELECTED_ICON_CHANGED_PROPERTY =
 386:     "disabledSelectedIcon";
 387:   
 388:   /**
 389:    * Fired in a PropertyChangeEvent when the "focusPainted" property changes.
 390:    */
 391:   public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
 392: 
 393:   /**
 394:    * Fired in a PropertyChangeEvent when the "horizontalAlignment" property
 395:    * changes.
 396:    */
 397:   public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY =
 398:     "horizontalAlignment";
 399: 
 400:   /**
 401:    * Fired in a PropertyChangeEvent when the "horizontalTextPosition" property
 402:    * changes.
 403:    */
 404:   public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY =
 405:     "horizontalTextPosition";
 406: 
 407:   /**
 408:    * Fired in a PropertyChangeEvent when the "icon" property changes. */
 409:   public static final String ICON_CHANGED_PROPERTY = "icon";
 410: 
 411:   /** Fired in a PropertyChangeEvent when the "margin" property changes. */
 412:   public static final String MARGIN_CHANGED_PROPERTY = "margin";
 413: 
 414:   /** Fired in a PropertyChangeEvent when the "mnemonic" property changes. */
 415:   public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic";
 416: 
 417:   /** Fired in a PropertyChangeEvent when the "model" property changes. */
 418:   public static final String MODEL_CHANGED_PROPERTY = "model";
 419: 
 420:   /** Fired in a PropertyChangeEvent when the "pressedIcon" property changes. */
 421:   public static final String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";
 422: 
 423:   /**
 424:    * Fired in a PropertyChangeEvent when the "rolloverEnabled" property
 425:    * changes.
 426:    */
 427:   public static final String ROLLOVER_ENABLED_CHANGED_PROPERTY =
 428:     "rolloverEnabled";
 429: 
 430:   /**
 431:    * Fired in a PropertyChangeEvent when the "rolloverIcon" property changes.
 432:    */
 433:   public static final String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";
 434:   
 435:   /**
 436:    * Fired in a PropertyChangeEvent when the "rolloverSelectedIcon" property
 437:    * changes.
 438:    */
 439:   public static final String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY =
 440:     "rolloverSelectedIcon";
 441:   
 442:   /**
 443:    * Fired in a PropertyChangeEvent when the "selectedIcon" property changes.
 444:    */
 445:   public static final String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";
 446: 
 447:   /** Fired in a PropertyChangeEvent when the "text" property changes. */
 448:   public static final String TEXT_CHANGED_PROPERTY = "text";
 449: 
 450:   /**
 451:    * Fired in a PropertyChangeEvent when the "verticalAlignment" property
 452:    * changes.
 453:    */
 454:   public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY =
 455:     "verticalAlignment";
 456: 
 457:   /**
 458:    * Fired in a PropertyChangeEvent when the "verticalTextPosition" property
 459:    * changes.
 460:    */
 461:   public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY =
 462:     "verticalTextPosition";
 463: 
 464:   /**
 465:    * A Java Accessibility extension of the AbstractButton.
 466:    */
 467:   protected abstract class AccessibleAbstractButton
 468:     extends AccessibleJComponent implements AccessibleAction, AccessibleValue,
 469:                                             AccessibleText
 470:   {
 471:     private static final long serialVersionUID = -5673062525319836790L;
 472:     
 473:     protected AccessibleAbstractButton()
 474:     {
 475:       // Nothing to do here yet.
 476:     }
 477: 
 478:     /**
 479:      * Returns the accessible state set of this object. In addition to the
 480:      * superclass's states, the <code>AccessibleAbstractButton</code>
 481:      * supports the following states: {@link AccessibleState#ARMED},
 482:      * {@link AccessibleState#FOCUSED}, {@link AccessibleState#PRESSED} and
 483:      * {@link AccessibleState#CHECKED}.
 484:      *
 485:      * @return the current state of this accessible object
 486:      */
 487:     public AccessibleStateSet getAccessibleStateSet()
 488:     {
 489:       AccessibleStateSet state = super.getAccessibleStateSet();
 490: 
 491:       if (getModel().isArmed())
 492:         state.add(AccessibleState.ARMED);
 493:       if (getModel().isPressed())
 494:         state.add(AccessibleState.PRESSED);
 495:       if (isSelected())
 496:         state.add(AccessibleState.CHECKED);
 497: 
 498:       return state;
 499:     }
 500: 
 501:     /**
 502:      * Returns the accessible name for the button.
 503:      */
 504:     public String getAccessibleName()
 505:     {
 506:       String result = super.getAccessibleName();
 507:       if (result == null)
 508:         result = text;
 509:       return result;
 510:     }
 511: 
 512:     /**
 513:      * Returns the accessible icons of this object. If the AbstractButton's
 514:      * icon is an Accessible, and it's AccessibleContext is an AccessibleIcon,
 515:      * then this AccessibleIcon is returned, otherwise <code>null</code>.
 516:      *
 517:      * @return the accessible icons of this object, or <code>null</code> if
 518:      *         there is no accessible icon
 519:      */
 520:     public AccessibleIcon[] getAccessibleIcon()
 521:     {
 522:       AccessibleIcon[] ret = null;
 523:       Icon icon = getIcon();
 524:       if (icon instanceof Accessible)
 525:         {
 526:           AccessibleContext ctx = ((Accessible) icon).getAccessibleContext();
 527:           if (ctx instanceof AccessibleIcon)
 528:             {
 529:               ret = new AccessibleIcon[]{ (AccessibleIcon) ctx };
 530:             }
 531:         }
 532:       return ret;
 533:     }
 534: 
 535:     /**
 536:      * Returns the accessible relations of this AccessibleAbstractButton.
 537:      * If the AbstractButton is part of a ButtonGroup, then all the buttons
 538:      * in this button group are added as targets in a MEMBER_OF relation,
 539:      * otherwise an empty relation set is returned (from super).
 540:      *
 541:      * @return the accessible relations of this AccessibleAbstractButton
 542:      */
 543:     public AccessibleRelationSet getAccessibleRelationSet()
 544:     {
 545:       AccessibleRelationSet relations = super.getAccessibleRelationSet();
 546:       ButtonModel model = getModel();
 547:       if (model instanceof DefaultButtonModel)
 548:         {
 549:           ButtonGroup group = ((DefaultButtonModel) model).getGroup();
 550:           if (group != null)
 551:             {
 552:               Object[] target = new Object[group.getButtonCount()];
 553:               Enumeration els = group.getElements();
 554:               
 555:               for (int index = 0; els.hasMoreElements(); ++index)
 556:                 {
 557:                   target[index] = els.nextElement();
 558:                 }
 559: 
 560:               AccessibleRelation rel =
 561:                 new AccessibleRelation(AccessibleRelation.MEMBER_OF);
 562:               rel.setTarget(target);
 563:               relations.add(rel);
 564:             }
 565:         }
 566:       return relations;
 567:     }
 568: 
 569:     /**
 570:      * Returns the accessible action associated with this object. For buttons,
 571:      * this will be <code>this</code>.
 572:      *
 573:      * @return <code>this</code>
 574:      */
 575:     public AccessibleAction getAccessibleAction()
 576:     {
 577:       return this;
 578:     }
 579: 
 580:     /**
 581:      * Returns the accessible value of this AccessibleAbstractButton, which
 582:      * is always <code>this</code>.
 583:      *
 584:      * @return the accessible value of this AccessibleAbstractButton, which
 585:      *         is always <code>this</code>
 586:      */
 587:     public AccessibleValue getAccessibleValue()
 588:     {
 589:       return this;
 590:     }
 591: 
 592:     /**
 593:      * Returns the number of accessible actions that are supported by this
 594:      * object. Buttons support one action by default ('press button'), so this
 595:      * method always returns <code>1</code>.
 596:      *
 597:      * @return <code>1</code>, the number of supported accessible actions
 598:      */
 599:     public int getAccessibleActionCount()
 600:     {
 601:       return 1;
 602:     }
 603: 
 604:     /**
 605:      * Returns a description for the action with the specified index or
 606:      * <code>null</code> if such action does not exist.
 607:      *
 608:      * @param actionIndex the zero based index to the actions
 609:      *
 610:      * @return a description for the action with the specified index or
 611:      *         <code>null</code> if such action does not exist
 612:      */
 613:     public String getAccessibleActionDescription(int actionIndex)
 614:     {
 615:       String descr = null;
 616:       if (actionIndex == 0)
 617:         {
 618:           // FIXME: Supply localized descriptions in the UIDefaults.
 619:           descr = UIManager.getString("AbstractButton.clickText");
 620:         }
 621:       return descr;
 622:     }
 623: 
 624:     /**
 625:      * Performs the acccessible action with the specified index on this object.
 626:      * Since buttons have only one action by default (which is to press the
 627:      * button), this method performs a 'press button' when the specified index
 628:      * is <code>0</code> and nothing otherwise.
 629:      *
 630:      * @param actionIndex a zero based index into the actions of this button
 631:      *
 632:      * @return <code>true</code> if the specified action has been performed
 633:      *         successfully, <code>false</code> otherwise
 634:      */
 635:     public boolean doAccessibleAction(int actionIndex)
 636:     {
 637:       boolean retVal = false;
 638:       if (actionIndex == 0)
 639:         {
 640:           doClick();
 641:           retVal = true;
 642:         }
 643:       return retVal;
 644:     }
 645: 
 646:     /**
 647:      * Returns the current value of this object as a number. This
 648:      * implementation returns an <code>Integer(1)</code> if the button is
 649:      * selected, <code>Integer(0)</code> if the button is not selected.
 650:      *
 651:      * @return the current value of this object as a number
 652:      */
 653:     public Number getCurrentAccessibleValue()
 654:     {
 655:       Integer retVal;
 656:       if (isSelected())
 657:         retVal = new Integer(1);
 658:       else
 659:         retVal = new Integer(0);
 660:       return retVal;
 661:     }
 662: 
 663:     /**
 664:      * Sets the current accessible value as object. If the specified number 
 665:      * is 0 the button will be deselected, otherwise the button will
 666:      * be selected.
 667:      *
 668:      * @param value 0 for deselected button, other for selected button
 669:      *
 670:      * @return <code>true</code> if the value has been set, <code>false</code>
 671:      *         otherwise
 672:      */
 673:     public boolean setCurrentAccessibleValue(Number value)
 674:     {
 675:       boolean retVal = false;
 676:       if (value != null)
 677:         {
 678:           if (value.intValue() == 0)
 679:             setSelected(false);
 680:           else
 681:             setSelected(true);
 682:           retVal = true;
 683:         }
 684:       return retVal;
 685:     }
 686: 
 687:     /**
 688:      * Returns the minimum accessible value for the AccessibleAbstractButton,
 689:      * which is <code>0</code>.
 690:      *
 691:      * @return the minimimum accessible value for the AccessibleAbstractButton,
 692:      *         which is <code>0</code>
 693:      */
 694:     public Number getMinimumAccessibleValue()
 695:     {
 696:       return new Integer(0);
 697:     }
 698: 
 699:     /**
 700:      * Returns the maximum accessible value for the AccessibleAbstractButton,
 701:      * which is <code>1</code>.
 702:      *
 703:      * @return the maximum accessible value for the AccessibleAbstractButton,
 704:      *         which is <code>1</code>
 705:      */
 706:     public Number getMaximumAccessibleValue()
 707:     {
 708:       return new Integer(1);
 709:     }
 710: 
 711:     /**
 712:      * Returns the accessible text for this AccessibleAbstractButton. This
 713:      * will be <code>null</code> if the button has a non-HTML label, otherwise
 714:      * <code>this</code>.
 715:      *
 716:      * @return the accessible text for this AccessibleAbstractButton
 717:      */
 718:     public AccessibleText getAccessibleText()
 719:     {
 720:       AccessibleText accessibleText = null;
 721:       if (getClientProperty(BasicHTML.propertyKey) != null)
 722:         accessibleText = this;
 723: 
 724:       return accessibleText;
 725:     }
 726: 
 727:     /**
 728:      * Returns the index of the label's character at the specified point,
 729:      * relative to the local bounds of the button. This only works for
 730:      * HTML labels.
 731:      *
 732:      * @param p the point, relative to the buttons local bounds
 733:      *
 734:      * @return the index of the label's character at the specified point
 735:      */
 736:     public int getIndexAtPoint(Point p)
 737:     {
 738:       int index = -1;
 739:       View view = (View) getClientProperty(BasicHTML.propertyKey);
 740:       if (view != null)
 741:         {
 742:           Rectangle shape = new Rectangle(0, 0, getWidth(), getHeight());
 743:           index = view.viewToModel(p.x, p.y, shape, new Position.Bias[1]);
 744:         }
 745:       return index;
 746:     }
 747: 
 748:     /**
 749:      * Returns the bounds of the character at the specified index of the
 750:      * button's label. This will only work for HTML labels.
 751:      *
 752:      * @param i the index of the character of the label
 753:      *
 754:      * @return the bounds of the character at the specified index of the
 755:      *         button's label
 756:      */
 757:     public Rectangle getCharacterBounds(int i)
 758:     {
 759:       Rectangle rect = null;
 760:       View view = (View) getClientProperty(BasicHTML.propertyKey);
 761:       if (view != null)
 762:         {
 763:           Rectangle shape = new Rectangle(0, 0, getWidth(), getHeight());
 764:           try
 765:             {
 766:               Shape s = view.modelToView(i, shape, Position.Bias.Forward);
 767:               rect = s.getBounds();
 768:             }
 769:           catch (BadLocationException ex)
 770:             {
 771:               rect = null;
 772:             }
 773:         }
 774:       return rect;
 775:     }
 776: 
 777:     /**
 778:      * Returns the number of characters in the button's label.
 779:      *
 780:      * @return the bounds of the character at the specified index of the
 781:      *         button's label
 782:      */
 783:     public int getCharCount()
 784:     {
 785:       int charCount;
 786:       View view = (View) getClientProperty(BasicHTML.propertyKey);
 787:       if (view != null)
 788:         {
 789:           charCount = view.getDocument().getLength();
 790:         }
 791:       else
 792:         {
 793:           charCount = getAccessibleName().length();
 794:         }
 795:       return charCount;
 796:     }
 797: 
 798:     /**
 799:      * This always returns <code>-1</code> since there is no caret in a button.
 800:      *
 801:      * @return <code>-1</code> since there is no caret in a button
 802:      */
 803:     public int getCaretPosition()
 804:     {
 805:       return -1;
 806:     }
 807: 
 808:     /**
 809:      * Returns the character, word or sentence at the specified index. The
 810:      * <code>part</code> parameter determines what is returned, the character,
 811:      * word or sentence after the index.
 812:      *
 813:      * @param part one of {@link AccessibleText#CHARACTER},
 814:      *             {@link AccessibleText#WORD} or
 815:      *             {@link AccessibleText#SENTENCE}, specifying what is returned
 816:      * @param index the index
 817:      *
 818:      * @return the character, word or sentence after <code>index</code>
 819:      */
 820:     public String getAtIndex(int part, int index)
 821:     {
 822:       String result = "";
 823:       int startIndex = -1;
 824:       int endIndex = -1;
 825:       switch(part)
 826:         {
 827:         case AccessibleText.CHARACTER:
 828:           result = String.valueOf(text.charAt(index));
 829:           break;
 830:         case AccessibleText.WORD:
 831:           startIndex = text.lastIndexOf(' ', index);
 832:           endIndex = text.indexOf(' ', startIndex + 1);
 833:           if (endIndex == -1)
 834:             endIndex = startIndex + 1;
 835:           result = text.substring(startIndex + 1, endIndex);
 836:           break;
 837:         case AccessibleText.SENTENCE:
 838:         default:
 839:           startIndex = text.lastIndexOf('.', index);
 840:           endIndex = text.indexOf('.', startIndex + 1);
 841:           if (endIndex == -1)
 842:             endIndex = startIndex + 1;
 843:           result = text.substring(startIndex + 1, endIndex);
 844:           break;
 845:         }
 846:       return result;
 847:     }
 848: 
 849:     /**
 850:      * Returns the character, word or sentence after the specified index. The
 851:      * <code>part</code> parameter determines what is returned, the character,
 852:      * word or sentence after the index.
 853:      *
 854:      * @param part one of {@link AccessibleText#CHARACTER},
 855:      *             {@link AccessibleText#WORD} or
 856:      *             {@link AccessibleText#SENTENCE}, specifying what is returned
 857:      * @param index the index
 858:      *
 859:      * @return the character, word or sentence after <code>index</code>
 860:      */
 861:     public String getAfterIndex(int part, int index)
 862:     {
 863:       String result = "";
 864:       int startIndex = -1;
 865:       int endIndex = -1;
 866:       switch(part)
 867:         {
 868:         case AccessibleText.CHARACTER:
 869:           result = String.valueOf(text.charAt(index + 1));
 870:           break;
 871:         case AccessibleText.WORD:
 872:           startIndex = text.indexOf(' ', index);
 873:           endIndex = text.indexOf(' ', startIndex + 1);
 874:           if (endIndex == -1)
 875:             endIndex = startIndex + 1;
 876:           result = text.substring(startIndex + 1, endIndex);
 877:           break;
 878:         case AccessibleText.SENTENCE:
 879:         default:
 880:           startIndex = text.indexOf('.', index);
 881:           endIndex = text.indexOf('.', startIndex + 1);
 882:           if (endIndex == -1)
 883:             endIndex = startIndex + 1;
 884:           result = text.substring(startIndex + 1, endIndex);
 885:           break;
 886:         }
 887:       return result;
 888:     }
 889: 
 890:     /**
 891:      * Returns the character, word or sentence before the specified index. The
 892:      * <code>part</code> parameter determines what is returned, the character,
 893:      * word or sentence before the index.
 894:      *
 895:      * @param part one of {@link AccessibleText#CHARACTER},
 896:      *             {@link AccessibleText#WORD} or
 897:      *             {@link AccessibleText#SENTENCE}, specifying what is returned
 898:      * @param index the index
 899:      *
 900:      * @return the character, word or sentence before <code>index</code>
 901:      */
 902:     public String getBeforeIndex(int part, int index)
 903:     {
 904:       String result = "";
 905: