| GNU Classpath (0.95) | |
| Frames | No Frames |
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: