1. /*
  2. * @(#)AbstractButton.java 1.161 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.*;
  9. import java.awt.event.*;
  10. import java.awt.image.*;
  11. import java.text.*;
  12. import java.awt.geom.*;
  13. import java.beans.*;
  14. import java.util.Enumeration;
  15. import java.util.Vector;
  16. import java.io.Serializable;
  17. import javax.swing.event.*;
  18. import javax.swing.border.*;
  19. import javax.swing.plaf.*;
  20. import javax.accessibility.*;
  21. import javax.swing.text.*;
  22. import javax.swing.text.html.*;
  23. import javax.swing.plaf.basic.*;
  24. import java.util.*;
  25. /**
  26. * Defines common behaviors for buttons and menu items.
  27. * For further information see
  28. * <a
  29. href="http://java.sun.com/docs/books/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons</a>,
  30. * a section in <em>The Java Tutorial</em>.
  31. *
  32. * <p>
  33. *
  34. * <strong>Warning:</strong>
  35. * Serialized objects of this class will not be compatible with
  36. * future Swing releases. The current serialization support is
  37. * appropriate for short term storage or RMI between applications running
  38. * the same version of Swing. As of 1.4, support for long term storage
  39. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  40. * has been added to the <code>java.beans</code> package.
  41. * Please see {@link java.beans.XMLEncoder}.
  42. *
  43. * @version 1.161 01/23/03
  44. * @author Jeff Dinkins
  45. */
  46. public abstract class AbstractButton extends JComponent implements ItemSelectable, SwingConstants {
  47. // *********************************
  48. // ******* Button properties *******
  49. // *********************************
  50. /** Identifies a change in the button model. */
  51. public static final String MODEL_CHANGED_PROPERTY = "model";
  52. /** Identifies a change in the button's text. */
  53. public static final String TEXT_CHANGED_PROPERTY = "text";
  54. /** Identifies a change to the button's mnemonic. */
  55. public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic";
  56. // Text positioning and alignment
  57. /** Identifies a change in the button's margins. */
  58. public static final String MARGIN_CHANGED_PROPERTY = "margin";
  59. /** Identifies a change in the button's vertical alignment. */
  60. public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";
  61. /** Identifies a change in the button's horizontal alignment. */
  62. public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = "horizontalAlignment";
  63. /** Identifies a change in the button's vertical text position. */
  64. public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = "verticalTextPosition";
  65. /** Identifies a change in the button's horizontal text position. */
  66. public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = "horizontalTextPosition";
  67. // Paint options
  68. /**
  69. * Identifies a change to having the border drawn,
  70. * or having it not drawn.
  71. */
  72. public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";
  73. /**
  74. * Identifies a change to having the border highlighted when focused,
  75. * or not.
  76. */
  77. public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
  78. /**
  79. * Identifies a change from rollover enabled to disabled or back
  80. * to enabled.
  81. */
  82. public static final String ROLLOVER_ENABLED_CHANGED_PROPERTY = "rolloverEnabled";
  83. /**
  84. * Identifies a change to having the button paint the content area.
  85. */
  86. public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled";
  87. // Icons
  88. /** Identifies a change to the icon that represents the button. */
  89. public static final String ICON_CHANGED_PROPERTY = "icon";
  90. /**
  91. * Identifies a change to the icon used when the button has been
  92. * pressed.
  93. */
  94. public static final String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";
  95. /**
  96. * Identifies a change to the icon used when the button has
  97. * been selected.
  98. */
  99. public static final String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";
  100. /**
  101. * Identifies a change to the icon used when the cursor is over
  102. * the button.
  103. */
  104. public static final String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";
  105. /**
  106. * Identifies a change to the icon used when the cursor is
  107. * over the button and it has been selected.
  108. */
  109. public static final String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = "rolloverSelectedIcon";
  110. /**
  111. * Identifies a change to the icon used when the button has
  112. * been disabled.
  113. */
  114. public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";
  115. /**
  116. * Identifies a change to the icon used when the button has been
  117. * disabled and selected.
  118. */
  119. public static final String DISABLED_SELECTED_ICON_CHANGED_PROPERTY = "disabledSelectedIcon";
  120. /** The data model that determines the button's state. */
  121. protected ButtonModel model = null;
  122. private String text = ""; // for BeanBox
  123. private Insets margin = null;
  124. private Insets defaultMargin = null;
  125. // Button icons
  126. // PENDING(jeff) - hold icons in an array
  127. private Icon defaultIcon = null;
  128. private Icon pressedIcon = null;
  129. private Icon disabledIcon = null;
  130. private Icon selectedIcon = null;
  131. private Icon disabledSelectedIcon = null;
  132. private Icon rolloverIcon = null;
  133. private Icon rolloverSelectedIcon = null;
  134. // Display properties
  135. private boolean paintBorder = true;
  136. private boolean paintFocus = true;
  137. private boolean rolloverEnabled = false;
  138. private boolean contentAreaFilled = true;
  139. // Icon/Label Alignment
  140. private int verticalAlignment = CENTER;
  141. private int horizontalAlignment = CENTER;
  142. private int verticalTextPosition = CENTER;
  143. private int horizontalTextPosition = TRAILING;
  144. private int iconTextGap = 4;
  145. private int mnemonic;
  146. private int mnemonicIndex = -1;
  147. private long multiClickThreshhold = 0;
  148. private AccessibleIcon accessibleIcon = null;
  149. /**
  150. * The button model's <code>changeListener</code>.
  151. */
  152. protected ChangeListener changeListener = null;
  153. /**
  154. * The button model's <code>ActionListener</code>.
  155. */
  156. protected ActionListener actionListener = null;
  157. /**
  158. * The button model's <code>ItemListener</code>.
  159. */
  160. protected ItemListener itemListener = null;
  161. /**
  162. * Only one <code>ChangeEvent</code> is needed per button
  163. * instance since the
  164. * event's only state is the source property. The source of events
  165. * generated is always "this".
  166. */
  167. protected transient ChangeEvent changeEvent;
  168. /**
  169. * Returns the button's text.
  170. * @return the buttons text
  171. * @see #setText
  172. */
  173. public String getText() {
  174. return text;
  175. }
  176. /**
  177. * Sets the button's text.
  178. * @param text the string used to set the text
  179. * @see #getText
  180. * @beaninfo
  181. * bound: true
  182. * preferred: true
  183. * attribute: visualUpdate true
  184. * description: The button's text.
  185. */
  186. public void setText(String text) {
  187. String oldValue = this.text;
  188. this.text = text;
  189. firePropertyChange(TEXT_CHANGED_PROPERTY, oldValue, text);
  190. updateDisplayedMnemonicIndex(text, getMnemonic());
  191. if (accessibleContext != null) {
  192. accessibleContext.firePropertyChange(
  193. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  194. oldValue, text);
  195. }
  196. if (text == null || oldValue == null || !text.equals(oldValue)) {
  197. revalidate();
  198. repaint();
  199. }
  200. }
  201. /**
  202. * Returns the state of the button. True if the
  203. * toggle button is selected, false if it's not.
  204. * @return true if the toggle button is selected, otherwise false
  205. */
  206. public boolean isSelected() {
  207. return model.isSelected();
  208. }
  209. /**
  210. * Sets the state of the button. Note that this method does not
  211. * trigger an <code>actionEvent</code>.
  212. * Call <code>doClick</code> to perform a programatic action change.
  213. *
  214. * @param b true if the button is selected, otherwise false
  215. */
  216. public void setSelected(boolean b) {
  217. boolean oldValue = isSelected();
  218. if (accessibleContext != null && oldValue != b) {
  219. if (b) {
  220. accessibleContext.firePropertyChange(
  221. AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  222. null, AccessibleState.SELECTED);
  223. } else {
  224. accessibleContext.firePropertyChange(
  225. AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  226. AccessibleState.SELECTED, null);
  227. }
  228. }
  229. model.setSelected(b);
  230. }
  231. /**
  232. * Programmatically perform a "click". This does the same
  233. * thing as if the user had pressed and released the button.
  234. */
  235. public void doClick() {
  236. doClick(68);
  237. }
  238. /**
  239. * Programmatically perform a "click". This does the same
  240. * thing as if the user had pressed and released the button.
  241. * The button stays visually "pressed" for <code>pressTime</code>
  242. * milliseconds.
  243. *
  244. * @param pressTime the time to "hold down" the button, in milliseconds
  245. */
  246. public void doClick(int pressTime) {
  247. Dimension size = getSize();
  248. model.setArmed(true);
  249. model.setPressed(true);
  250. paintImmediately(new Rectangle(0,0, size.width, size.height));
  251. try {
  252. Thread.currentThread().sleep(pressTime);
  253. } catch(InterruptedException ie) {
  254. }
  255. model.setPressed(false);
  256. model.setArmed(false);
  257. }
  258. /**
  259. * Sets space for margin between the button's border and
  260. * the label. Setting to <code>null</code> will cause the button to
  261. * use the default margin. The button's default <code>Border</code>
  262. * object will use this value to create the proper margin.
  263. * However, if a non-default border is set on the button,
  264. * it is that <code>Border</code> object's responsibility to create the
  265. * appropriate margin space (else this property will
  266. * effectively be ignored).
  267. *
  268. * @param m the space between the border and the label
  269. *
  270. * @beaninfo
  271. * bound: true
  272. * attribute: visualUpdate true
  273. * description: The space between the button's border and the label.
  274. */
  275. public void setMargin(Insets m) {
  276. // Cache the old margin if it comes from the UI
  277. if(m instanceof UIResource) {
  278. defaultMargin = m;
  279. } else if(margin instanceof UIResource) {
  280. defaultMargin = margin;
  281. }
  282. // If the client passes in a null insets, restore the margin
  283. // from the UI if possible
  284. if(m == null && defaultMargin != null) {
  285. m = defaultMargin;
  286. }
  287. Insets old = margin;
  288. margin = m;
  289. firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);
  290. if (old == null || !old.equals(m)) {
  291. revalidate();
  292. repaint();
  293. }
  294. }
  295. /**
  296. * Returns the margin between the button's border and
  297. * the label.
  298. *
  299. * @return an <code>Insets</code> object specifying the margin
  300. * between the botton's border and the label
  301. * @see #setMargin
  302. */
  303. public Insets getMargin() {
  304. return (margin == null) ? null : (Insets) margin.clone();
  305. }
  306. /**
  307. * Returns the default icon.
  308. * @return the default <code>Icon</code>
  309. * @see #setIcon
  310. */
  311. public Icon getIcon() {
  312. return defaultIcon;
  313. }
  314. /**
  315. * Sets the button's default icon. This icon is
  316. * also used as the "pressed" and "disabled" icon if
  317. * there is no explicitly set pressed icon.
  318. *
  319. * @param defaultIcon the icon used as the default image
  320. * @see #getIcon
  321. * @see #setPressedIcon
  322. * @beaninfo
  323. * bound: true
  324. * attribute: visualUpdate true
  325. * description: The button's default icon
  326. */
  327. public void setIcon(Icon defaultIcon) {
  328. Icon oldValue = this.defaultIcon;
  329. this.defaultIcon = defaultIcon;
  330. /* If the default icon has really changed and we had
  331. * generated the disabled icon for this component,
  332. * (i.e. setDisabledIcon() was never called) then
  333. * clear the disabledIcon field.
  334. */
  335. if (defaultIcon != oldValue && disabledIcon instanceof UIResource) {
  336. disabledIcon = null;
  337. }
  338. firePropertyChange(ICON_CHANGED_PROPERTY, oldValue, defaultIcon);
  339. if (accessibleContext != null) {
  340. accessibleContext.firePropertyChange(
  341. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  342. oldValue, defaultIcon);
  343. }
  344. if (defaultIcon != oldValue) {
  345. if (defaultIcon == null || oldValue == null ||
  346. defaultIcon.getIconWidth() != oldValue.getIconWidth() ||
  347. defaultIcon.getIconHeight() != oldValue.getIconHeight()) {
  348. revalidate();
  349. }
  350. repaint();
  351. }
  352. // set the accessible icon
  353. accessibleIcon = null;
  354. if (defaultIcon instanceof Accessible) {
  355. AccessibleContext ac =
  356. ((Accessible)defaultIcon).getAccessibleContext();
  357. if (ac != null && ac instanceof AccessibleIcon) {
  358. accessibleIcon = (AccessibleIcon)ac;
  359. }
  360. }
  361. }
  362. /**
  363. * Returns the pressed icon for the button.
  364. * @return the <code>pressedIcon</code> property
  365. * @see #setPressedIcon
  366. */
  367. public Icon getPressedIcon() {
  368. return pressedIcon;
  369. }
  370. /**
  371. * Sets the pressed icon for the button.
  372. * @param pressedIcon the icon used as the "pressed" image
  373. * @see #getPressedIcon
  374. * @beaninfo
  375. * bound: true
  376. * attribute: visualUpdate true
  377. * description: The pressed icon for the button.
  378. */
  379. public void setPressedIcon(Icon pressedIcon) {
  380. Icon oldValue = this.pressedIcon;
  381. this.pressedIcon = pressedIcon;
  382. firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, oldValue, pressedIcon);
  383. if (accessibleContext != null) {
  384. accessibleContext.firePropertyChange(
  385. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  386. oldValue, pressedIcon);
  387. }
  388. if (pressedIcon != oldValue) {
  389. if (getModel().isPressed()) {
  390. repaint();
  391. }
  392. }
  393. }
  394. /**
  395. * Returns the selected icon for the button.
  396. * @return the <code>selectedIcon</code> property
  397. * @see #setSelectedIcon
  398. */
  399. public Icon getSelectedIcon() {
  400. return selectedIcon;
  401. }
  402. /**
  403. * Sets the selected icon for the button.
  404. * @param selectedIcon the icon used as the "selected" image
  405. * @see #getSelectedIcon
  406. * @beaninfo
  407. * bound: true
  408. * attribute: visualUpdate true
  409. * description: The selected icon for the button.
  410. */
  411. public void setSelectedIcon(Icon selectedIcon) {
  412. Icon oldValue = this.selectedIcon;
  413. this.selectedIcon = selectedIcon;
  414. /* If the default selected icon has really changed and we had
  415. * generated the disabled selected icon for this component,
  416. * (i.e. setDisabledSelectedIcon() was never called) then
  417. * clear the disabledSelectedIcon field.
  418. */
  419. if (selectedIcon != oldValue &&
  420. disabledSelectedIcon instanceof UIResource) {
  421. disabledSelectedIcon = null;
  422. }
  423. firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, oldValue, selectedIcon);
  424. if (accessibleContext != null) {
  425. accessibleContext.firePropertyChange(
  426. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  427. oldValue, selectedIcon);
  428. }
  429. if (selectedIcon != oldValue) {
  430. if (isSelected()) {
  431. repaint();
  432. }
  433. }
  434. }
  435. /**
  436. * Returns the rollover icon for the button.
  437. * @return the <code>rolloverIcon</code> property
  438. * @see #setRolloverIcon
  439. */
  440. public Icon getRolloverIcon() {
  441. return rolloverIcon;
  442. }
  443. /**
  444. * Sets the rollover icon for the button.
  445. * @param rolloverIcon the icon used as the "rollover" image
  446. * @see #getRolloverIcon
  447. * @beaninfo
  448. * bound: true
  449. * attribute: visualUpdate true
  450. * description: The rollover icon for the button.
  451. */
  452. public void setRolloverIcon(Icon rolloverIcon) {
  453. Icon oldValue = this.rolloverIcon;
  454. this.rolloverIcon = rolloverIcon;
  455. firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, oldValue, rolloverIcon);
  456. if (accessibleContext != null) {
  457. accessibleContext.firePropertyChange(
  458. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  459. oldValue, rolloverIcon);
  460. }
  461. setRolloverEnabled(true);
  462. if (rolloverIcon != oldValue) {
  463. // No way to determine whether we are currently in
  464. // a rollover state, so repaint regardless
  465. repaint();
  466. }
  467. }
  468. /**
  469. * Returns the rollover selection icon for the button.
  470. * @return the <code>rolloverSelectedIcon</code> property
  471. * @see #setRolloverSelectedIcon
  472. */
  473. public Icon getRolloverSelectedIcon() {
  474. return rolloverSelectedIcon;
  475. }
  476. /**
  477. * Sets the rollover selected icon for the button.
  478. * @param rolloverSelectedIcon the icon used as the
  479. * "selected rollover" image
  480. * @see #getRolloverSelectedIcon
  481. * @beaninfo
  482. * bound: true
  483. * attribute: visualUpdate true
  484. * description: The rollover selected icon for the button.
  485. */
  486. public void setRolloverSelectedIcon(Icon rolloverSelectedIcon) {
  487. Icon oldValue = this.rolloverSelectedIcon;
  488. this.rolloverSelectedIcon = rolloverSelectedIcon;
  489. firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, oldValue, rolloverSelectedIcon);
  490. if (accessibleContext != null) {
  491. accessibleContext.firePropertyChange(
  492. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  493. oldValue, rolloverSelectedIcon);
  494. }
  495. setRolloverEnabled(true);
  496. if (rolloverSelectedIcon != oldValue) {
  497. // No way to determine whether we are currently in
  498. // a rollover state, so repaint regardless
  499. if (isSelected()) {
  500. repaint();
  501. }
  502. }
  503. }
  504. /**
  505. * Returns the icon used by the button when it's disabled.
  506. * If no disabled icon has been set, the button constructs
  507. * one from the default icon.
  508. * <!-- PENDING(jeff): the disabled icon really should be created
  509. * (if necessary) by the L&F.-->
  510. *
  511. * @return the <code>disabledIcon</code> property
  512. * @see #getPressedIcon
  513. * @see #setDisabledIcon
  514. */
  515. public Icon getDisabledIcon() {
  516. if (disabledIcon == null) {
  517. if (defaultIcon != null && defaultIcon instanceof ImageIcon) {
  518. disabledIcon = new IconUIResource(new ImageIcon(
  519. GrayFilter.createDisabledImage(
  520. ((ImageIcon)defaultIcon).getImage())));
  521. }
  522. }
  523. return disabledIcon;
  524. }
  525. /**
  526. * Sets the disabled icon for the button.
  527. * @param disabledIcon the icon used as the disabled image
  528. * @see #getDisabledIcon
  529. * @beaninfo
  530. * bound: true
  531. * attribute: visualUpdate true
  532. * description: The disabled icon for the button.
  533. */
  534. public void setDisabledIcon(Icon disabledIcon) {
  535. Icon oldValue = this.disabledIcon;
  536. this.disabledIcon = disabledIcon;
  537. firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, oldValue, disabledIcon);
  538. if (accessibleContext != null) {
  539. accessibleContext.firePropertyChange(
  540. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  541. oldValue, disabledIcon);
  542. }
  543. if (disabledIcon != oldValue) {
  544. if (!isEnabled()) {
  545. repaint();
  546. }
  547. }
  548. }
  549. /**
  550. * Returns the icon used by the button when it's disabled and selected.
  551. * If not no disabled selection icon has been set, the button constructs
  552. * one from the selection icon.
  553. * <!-- PENDING(jeff): the disabled selection icon really should be
  554. * created (if necessary) by the L&F. -->
  555. *
  556. * @return the <code>disabledSelectedIcon</code> property
  557. * @see #getPressedIcon
  558. * @see #setDisabledIcon
  559. */
  560. public Icon getDisabledSelectedIcon() {
  561. if(disabledSelectedIcon == null) {
  562. if(selectedIcon != null && selectedIcon instanceof ImageIcon) {
  563. disabledSelectedIcon = new IconUIResource(new ImageIcon(
  564. GrayFilter.createDisabledImage(
  565. ((ImageIcon)selectedIcon).getImage())));
  566. } else {
  567. return getDisabledIcon();
  568. }
  569. }
  570. return disabledSelectedIcon;
  571. }
  572. /**
  573. * Sets the disabled selection icon for the button.
  574. * @param disabledSelectedIcon the icon used as the disabled
  575. * selection image
  576. * @see #getDisabledSelectedIcon
  577. * @beaninfo
  578. * bound: true
  579. * attribute: visualUpdate true
  580. * description: The disabled selection icon for the button.
  581. */
  582. public void setDisabledSelectedIcon(Icon disabledSelectedIcon) {
  583. Icon oldValue = this.disabledSelectedIcon;
  584. this.disabledSelectedIcon = disabledSelectedIcon;
  585. firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, oldValue, disabledSelectedIcon);
  586. if (accessibleContext != null) {
  587. accessibleContext.firePropertyChange(
  588. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  589. oldValue, disabledSelectedIcon);
  590. }
  591. if (disabledSelectedIcon != oldValue) {
  592. if (disabledSelectedIcon == null || oldValue == null ||
  593. disabledSelectedIcon.getIconWidth() != oldValue.getIconWidth() ||
  594. disabledSelectedIcon.getIconHeight() != oldValue.getIconHeight()) {
  595. revalidate();
  596. }
  597. if (!isEnabled() && isSelected()) {
  598. repaint();
  599. }
  600. }
  601. }
  602. /**
  603. * Returns the vertical alignment of the text and icon.
  604. *
  605. * @return the <code>verticalAlignment</code> property, one of the
  606. * following values:
  607. * <ul>
  608. * <li>SwingConstants.CENTER (the default)
  609. * <li>SwingConstants.TOP
  610. * <li>SwingConstants.BOTTOM
  611. * </ul>
  612. */
  613. public int getVerticalAlignment() {
  614. return verticalAlignment;
  615. }
  616. /**
  617. * Sets the vertical alignment of the icon and text.
  618. * @param alignment one of the following values:
  619. * <ul>
  620. * <li>SwingConstants.CENTER (the default)
  621. * <li>SwingConstants.TOP
  622. * <li>SwingConstants.BOTTOM
  623. * </ul>
  624. * @beaninfo
  625. * bound: true
  626. * enum: TOP SwingConstants.TOP
  627. * CENTER SwingConstants.CENTER
  628. * BOTTOM SwingConstants.BOTTOM
  629. * attribute: visualUpdate true
  630. * description: The vertical alignment of the icon and text.
  631. */
  632. public void setVerticalAlignment(int alignment) {
  633. if (alignment == verticalAlignment) return;
  634. int oldValue = verticalAlignment;
  635. verticalAlignment = checkVerticalKey(alignment, "verticalAlignment");
  636. firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, oldValue, verticalAlignment); repaint();
  637. }
  638. /**
  639. * Returns the horizontal alignment of the icon and text.
  640. * @return the <code>horizontalAlignment</code> property,
  641. * one of the following values:
  642. * <ul>
  643. * <li>SwingConstants.RIGHT (the default)
  644. * <li>SwingConstants.LEFT
  645. * <li>SwingConstants.CENTER
  646. * <li>SwingConstants.LEADING
  647. * <li>SwingConstants.TRAILING
  648. * </ul>
  649. */
  650. public int getHorizontalAlignment() {
  651. return horizontalAlignment;
  652. }
  653. /**
  654. * Sets the horizontal alignment of the icon and text.
  655. * @param alignment one of the following values:
  656. * <ul>
  657. * <li>SwingConstants.RIGHT (the default)
  658. * <li>SwingConstants.LEFT
  659. * <li>SwingConstants.CENTER
  660. * <li>SwingConstants.LEADING
  661. * <li>SwingConstants.TRAILING
  662. * </ul>
  663. * @beaninfo
  664. * bound: true
  665. * enum: LEFT SwingConstants.LEFT
  666. * CENTER SwingConstants.CENTER
  667. * RIGHT SwingConstants.RIGHT
  668. * LEADING SwingConstants.LEADING
  669. * TRAILING SwingConstants.TRAILING
  670. * attribute: visualUpdate true
  671. * description: The horizontal alignment of the icon and text.
  672. */
  673. public void setHorizontalAlignment(int alignment) {
  674. if (alignment == horizontalAlignment) return;
  675. int oldValue = horizontalAlignment;
  676. horizontalAlignment = checkHorizontalKey(alignment,
  677. "horizontalAlignment");
  678. firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY,
  679. oldValue, horizontalAlignment);
  680. repaint();
  681. }
  682. /**
  683. * Returns the vertical position of the text relative to the icon.
  684. * @return the <code>verticalTextPosition</code> property,
  685. * one of the following values:
  686. * <ul>
  687. * <li>SwingConstants.CENTER (the default)
  688. * <li>SwingConstants.TOP
  689. * <li>SwingConstants.BOTTOM
  690. * </ul>
  691. */
  692. public int getVerticalTextPosition() {
  693. return verticalTextPosition;
  694. }
  695. /**
  696. * Sets the vertical position of the text relative to the icon.
  697. * @param textPosition one of the following values:
  698. * <ul>
  699. * <li>SwingConstants.CENTER (the default)
  700. * <li>SwingConstants.TOP
  701. * <li>SwingConstants.BOTTOM
  702. * </ul>
  703. * @beaninfo
  704. * bound: true
  705. * enum: TOP SwingConstants.TOP
  706. * CENTER SwingConstants.CENTER
  707. * BOTTOM SwingConstants.BOTTOM
  708. * attribute: visualUpdate true
  709. * description: The vertical position of the text relative to the icon.
  710. */
  711. public void setVerticalTextPosition(int textPosition) {
  712. if (textPosition == verticalTextPosition) return;
  713. int oldValue = verticalTextPosition;
  714. verticalTextPosition = checkVerticalKey(textPosition, "verticalTextPosition");
  715. firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, oldValue, verticalTextPosition);
  716. repaint();
  717. }
  718. /**
  719. * Returns the horizontal position of the text relative to the icon.
  720. * @return the <code>horizontalTextPosition</code> property,
  721. * one of the following values:
  722. * <ul>
  723. * <li>SwingConstants.RIGHT
  724. * <li>SwingConstants.LEFT
  725. * <li>SwingConstants.CENTER
  726. * <li>SwingConstants.LEADING
  727. * <li>SwingConstants.TRAILING (the default)
  728. * </ul>
  729. */
  730. public int getHorizontalTextPosition() {
  731. return horizontalTextPosition;
  732. }
  733. /**
  734. * Sets the horizontal position of the text relative to the icon.
  735. * @param textPosition one of the following values:
  736. * <ul>
  737. * <li>SwingConstants.RIGHT
  738. * <li>SwingConstants.LEFT
  739. * <li>SwingConstants.CENTER
  740. * <li>SwingConstants.LEADING
  741. * <li>SwingConstants.TRAILING (the default)
  742. * </ul>
  743. * @exception IllegalArgumentException if <code>textPosition</code>
  744. * is not one of the legal values listed above
  745. * @beaninfo
  746. * bound: true
  747. * enum: LEFT SwingConstants.LEFT
  748. * CENTER SwingConstants.CENTER
  749. * RIGHT SwingConstants.RIGHT
  750. * LEADING SwingConstants.LEADING
  751. * TRAILING SwingConstants.TRAILING
  752. * attribute: visualUpdate true
  753. * description: The horizontal position of the text relative to the icon.
  754. */
  755. public void setHorizontalTextPosition(int textPosition) {
  756. if (textPosition == horizontalTextPosition) return;
  757. int oldValue = horizontalTextPosition;
  758. horizontalTextPosition = checkHorizontalKey(textPosition,
  759. "horizontalTextPosition");
  760. firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY,
  761. oldValue,
  762. horizontalTextPosition);
  763. repaint();
  764. }
  765. /**
  766. * Returns the amount of space between the text and the icon
  767. * displayed in this button.
  768. *
  769. * @return an int equal to the number of pixels between the text
  770. * and the icon.
  771. * @since 1.4
  772. * @see #setIconTextGap
  773. */
  774. public int getIconTextGap() {
  775. return iconTextGap;
  776. }
  777. /**
  778. * If both the icon and text properties are set, this property
  779. * defines the space between them.
  780. * <p>
  781. * The default value of this property is 4 pixels.
  782. * <p>
  783. * This is a JavaBeans bound property.
  784. *
  785. * @since 1.4
  786. * @see #getIconTextGap
  787. * @beaninfo
  788. * bound: true
  789. * attribute: visualUpdate true
  790. * description: If both the icon and text properties are set, this
  791. * property defines the space between them.
  792. */
  793. public void setIconTextGap(int iconTextGap) {
  794. int oldValue = this.iconTextGap;
  795. this.iconTextGap = iconTextGap;
  796. firePropertyChange("iconTextGap", oldValue, iconTextGap);
  797. if (iconTextGap != oldValue) {
  798. revalidate();
  799. repaint();
  800. }
  801. }
  802. /**
  803. * Verify that key is a legal value for the
  804. * <code>horizontalAlignment</code> properties.
  805. *
  806. * @param key the property value to check, one of the following values:
  807. * <ul>
  808. * <li>SwingConstants.RIGHT (the default)
  809. * <li>SwingConstants.LEFT
  810. * <li>SwingConstants.CENTER
  811. * <li>SwingConstants.LEADING
  812. * <li>SwingConstants.TRAILING
  813. * </ul>
  814. * @param exception the <code>IllegalArgumentException</code>
  815. * detail message
  816. * @exception IllegalArgumentException if key is not one of the legal
  817. * values listed above
  818. * @see #setHorizontalTextPosition
  819. * @see #setHorizontalAlignment
  820. */
  821. protected int checkHorizontalKey(int key, String exception) {
  822. if ((key == LEFT) ||
  823. (key == CENTER) ||
  824. (key == RIGHT) ||
  825. (key == LEADING) ||
  826. (key == TRAILING)) {
  827. return key;
  828. } else {
  829. throw new IllegalArgumentException(exception);
  830. }
  831. }
  832. /**
  833. * Ensures that the key is a valid. Throws an
  834. * <code>IllegalArgumentException</code>
  835. * exception otherwise.
  836. *
  837. * @param key the value to check, one of the following values:
  838. * <ul>
  839. * <li>SwingConstants.CENTER (the default)
  840. * <li>SwingConstants.TOP
  841. * <li>SwingConstants.BOTTOM
  842. * </ul>
  843. * @param exception a string to be passed to the
  844. * <code>IllegalArgumentException</code> call if key
  845. * is not one of the valid values listed above
  846. * @exception IllegalArgumentException if key is not one of the legal
  847. * values listed above
  848. */
  849. protected int checkVerticalKey(int key, String exception) {
  850. if ((key == TOP) || (key == CENTER) || (key == BOTTOM)) {
  851. return key;
  852. } else {
  853. throw new IllegalArgumentException(exception);
  854. }
  855. }
  856. /**
  857. * Sets the action command for this button.
  858. * @param actionCommand the action command for this button
  859. */
  860. public void setActionCommand(String actionCommand) {
  861. getModel().setActionCommand(actionCommand);
  862. }
  863. /**
  864. * Returns the action command for this button.
  865. * @return the action command for this button
  866. */
  867. public String getActionCommand() {
  868. String ac = getModel().getActionCommand();
  869. if(ac == null) {
  870. ac = getText();
  871. }
  872. return ac;
  873. }
  874. private Action action;
  875. private PropertyChangeListener actionPropertyChangeListener;
  876. /**
  877. * Sets the <code>Action</code> for the <code>ActionEvent</code> source.
  878. * The new <code>Action</code> replaces any previously set
  879. * <code>Action</code> but does not affect <code>ActionListeners</code>
  880. * independently added with <code>addActionListener</code>.
  881. * If the <code>Action</code> is already a registered
  882. * <code>ActionListener</code> for the button, it is not re-registered.
  883. * <p>
  884. * A side-effect of setting the <code>Action</code> is that the
  885. * <code>ActionEvent</code> source's properties are immediately
  886. * set from the values in the <code>Action</code> (performed by the
  887. * method <code>configurePropertiesFromAction</code>) and
  888. * subsequently updated as the <code>Action</code>'s properties change
  889. * (via a <code>PropertyChangeListener</code> created by the method
  890. * <code>createActionPropertyChangeListener</code>.
  891. *
  892. * @param a the <code>Action</code> for the <code>AbstractButton</code>,
  893. * or <code>null</code>
  894. * @since 1.3
  895. * @see Action
  896. * @see #getAction
  897. * @see #configurePropertiesFromAction
  898. * @see #createActionPropertyChangeListener
  899. * @beaninfo
  900. * bound: true
  901. * attribute: visualUpdate true
  902. * description: the Action instance connected with this ActionEvent source
  903. */
  904. public void setAction(Action a) {
  905. Action oldValue = getAction();
  906. if (action==null || !action.equals(a)) {
  907. action = a;
  908. if (oldValue!=null) {
  909. removeActionListener(oldValue);
  910. oldValue.removePropertyChangeListener(actionPropertyChangeListener);
  911. actionPropertyChangeListener = null;
  912. }
  913. configurePropertiesFromAction(action);
  914. if (action!=null) {
  915. // Don't add if it is already a listener
  916. if (!isListener(ActionListener.class, action)) {
  917. addActionListener(action);
  918. }
  919. // Reverse linkage:
  920. actionPropertyChangeListener = createActionPropertyChangeListener(action);
  921. action.addPropertyChangeListener(actionPropertyChangeListener);
  922. }
  923. firePropertyChange("action", oldValue, action);
  924. revalidate();
  925. repaint();
  926. }
  927. }
  928. private boolean isListener(Class c, ActionListener a) {
  929. boolean isListener = false;
  930. Object[] listeners = listenerList.getListenerList();
  931. for (int i = listeners.length-2; i>=0; i-=2) {
  932. if (listeners[i]==c && listeners[i+1]==a) {
  933. isListener=true;
  934. }
  935. }
  936. return isListener;
  937. }
  938. /**
  939. * Returns the currently set <code>Action</code> for this
  940. * <code>ActionEvent</code> source, or <code>null</code>
  941. * if no <code>Action</code> is set.
  942. *
  943. * @return the <code>Action</code> for this <code>ActionEvent</code>
  944. * source, or <code>null</code>
  945. * @since 1.3
  946. * @see Action
  947. * @see #setAction
  948. */
  949. public Action getAction() {
  950. return action;
  951. }
  952. /**
  953. * Factory method which sets the <code>ActionEvent</code>
  954. * source's properties according to values from the
  955. * <code>Action</code> instance. The properties
  956. * which are set may differ for subclasses. By default,
  957. * the properties which get set are <code>Text, Icon,
  958. * Enabled, ToolTipText, ActionCommand</code>, and <code>Mnemonic</code>.
  959. * <p>
  960. * If the <code>Action</code> passed in is <code>null</code>,
  961. * the following things will occur:
  962. * <ul>
  963. * <li>the text is set to <code>null</code>,
  964. * <li>the icon is set to <code>null</code>,
  965. * <li>enabled is set to true,
  966. * <li>the tooltip text is set to <code>null</code>
  967. * </ul>
  968. *
  969. * @param a the <code>Action</code> from which to get the properties,
  970. * or <code>null</code>
  971. * @since 1.3
  972. * @see Action
  973. * @see #setAction
  974. */
  975. protected void configurePropertiesFromAction(Action a) {
  976. configurePropertiesFromAction(a, null);
  977. }
  978. /**
  979. * Configures the AbstractButton's properties according to values
  980. * from the <code>Action</code> instance. Which properties to set
  981. * is determined by the <code>types</code> parameter.
  982. * <code>types</code> may hold the following keys:
  983. * <ul>
  984. * <li><code>Action.NAME</code> - set the <code>Text</code> property
  985. * from the <code>Action</code>,
  986. * <li><code>Action.SHORT_DESCRIPTION</code> - set the
  987. * <code>ToolTipText</code> property from the <code>Action</code>,
  988. * <li><code>Action.SMALL_ICON</code> - set the <code>Icon</code> property
  989. * from the <code>Action</code>,
  990. * <li><code>Action.MNEMONIC</code> - set the <code>Mnemonic</code>
  991. * property from the <code>Action</code>,
  992. * <li><code>Action.ACTION_COMMAND_KEY</code> - set the
  993. * <code>ActionCommand</code> property from the <code>Action</code>,
  994. * <li><code>"enabled"</code> - set <code>Enabled</code> property
  995. * from the <code>Action</code>
  996. * </ul>
  997. * <p>
  998. * If the <code>Action</code> passed in is <code>null</code>,
  999. * the following things will occur:
  1000. * <ul>
  1001. * <li>the text is set to <code>null</code>,
  1002. * <li>the icon is set to <code>null</code>,
  1003. * <li>enabled is set to true,
  1004. * <li>the tooltip text is set to <code>null</code>
  1005. * <li>the mnemonic is set to <code>'\0'</code>
  1006. * </ul>
  1007. *
  1008. * @param a the <code>Action</code> from which to get the properties,
  1009. * or <code>null</code>
  1010. * @param types determines which properties to set from the
  1011. * <code>Action</code>
  1012. * @since 1.4
  1013. * @see Action
  1014. * @see #setAction
  1015. * @see #configurePropertiesFromAction(javax.swing.Action)
  1016. */
  1017. void configurePropertiesFromAction(Action a, String[] types) {
  1018. if (types == null) {
  1019. String[] alltypes = { Action.MNEMONIC_KEY, Action.NAME,
  1020. Action.SHORT_DESCRIPTION, Action.SMALL_ICON,
  1021. Action.ACTION_COMMAND_KEY, "enabled" };
  1022. types = alltypes;
  1023. }
  1024. for (int i=0; i<types.length; i++) {
  1025. String type = types[i];
  1026. if (type == null) continue;
  1027. if (type.equals(Action.MNEMONIC_KEY)) {
  1028. Integer n = (a==null) ? null : (Integer)a.getValue(type);
  1029. setMnemonic(n==null ? '\0' : n.intValue());
  1030. } else if (type.equals(Action.NAME)) {
  1031. setText(a!=null ? (String)a.getValue(type) : null);
  1032. } else if (type.equals(Action.SHORT_DESCRIPTION)) {
  1033. setToolTipText(a!=null ? (String)a.getValue(type) : null);
  1034. } else if (type.equals(Action.SMALL_ICON)) {
  1035. setIcon(a!=null ? (Icon)a.getValue(type) : null);
  1036. } else if (type.equals(Action.ACTION_COMMAND_KEY)) {
  1037. setActionCommand(a!=null? (String)a.getValue(type) : null);
  1038. } else if (type.equals("enabled")) {
  1039. setEnabled(a!=null ? a.isEnabled() : true);
  1040. }
  1041. }
  1042. }
  1043. /**
  1044. * Factory method which creates the <code>PropertyChangeListener</code>
  1045. * used to update the <code>ActionEvent</code> source as properties
  1046. * change on its <code>Action</code> instance. Subclasses may
  1047. * override this in order to provide their own
  1048. * <code>PropertyChangeListener</code> if the set of
  1049. * properties which should be kept up to date differs from the
  1050. * default properties (<code>Text, Icon, Enabled, ToolTipText,
  1051. * Mnemonic</code>).
  1052. * <p>
  1053. * Note that <code>PropertyChangeListeners</code> should avoid holding
  1054. * strong references to the <code>ActionEvent</code> source,
  1055. * as this may hinder garbage collection of the
  1056. * <code>ActionEvent</code> source and all components
  1057. * in its containment hierarchy.
  1058. *
  1059. * @param a the new action for the button
  1060. * @since 1.3
  1061. * @see Action
  1062. * @see #setAction
  1063. */
  1064. protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
  1065. return new ButtonActionPropertyChangeListener(this, a);
  1066. }
  1067. private static class ButtonActionPropertyChangeListener extends AbstractActionPropertyChangeListener {
  1068. ButtonActionPropertyChangeListener(AbstractButton b, Action a) {
  1069. super(b, a);
  1070. }
  1071. public void propertyChange(PropertyChangeEvent e) {
  1072. String propertyName = e.getPropertyName();
  1073. AbstractButton button = (AbstractButton)getTarget();
  1074. if (button == null) { //WeakRef GC'ed in 1.2
  1075. Action action = (Action)e.getSource();
  1076. action.removePropertyChangeListener(this);
  1077. } else {
  1078. if (e.getPropertyName().equals(Action.NAME)) {
  1079. Boolean hide = (Boolean)button.getClientProperty("hideActionText");
  1080. if (hide == null || hide == Boolean.FALSE) {
  1081. String text = (String) e.getNewValue();
  1082. button.setText(text);
  1083. button.repaint();
  1084. }
  1085. } else if (e.getPropertyName().equals(Action.SHORT_DESCRIPTION)) {
  1086. String text = (String) e.getNewValue();
  1087. button.setToolTipText(text);
  1088. } else if (propertyName.equals("enabled")) {
  1089. Boolean enabledState = (Boolean) e.getNewValue();
  1090. button.setEnabled(enabledState.booleanValue());
  1091. button.repaint();
  1092. } else if (e.getPropertyName().equals(Action.SMALL_ICON)) {
  1093. Icon icon = (Icon) e.getNewValue();
  1094. button.setIcon(icon);
  1095. button.invalidate();
  1096. button.repaint();
  1097. } else if (e.getPropertyName().equals(Action.MNEMONIC_KEY)) {
  1098. Integer mn = (Integer) e.getNewValue();
  1099. button.setMnemonic(mn.intValue());
  1100. button.invalidate();
  1101. button.repaint();
  1102. } else if (e.getPropertyName().equals(Action.ACTION_COMMAND_KEY)) {
  1103. button.setActionCommand((String)e.getNewValue());
  1104. }
  1105. }
  1106. }
  1107. }
  1108. /**
  1109. * Gets the <code>borderPainted</code> property.
  1110. *
  1111. * @return the value of the <code>borderPainted</code> property
  1112. * @see #setBorderPainted
  1113. */
  1114. public boolean isBorderPainted() {
  1115. return paintBorder;
  1116. }
  1117. /**
  1118. * Sets the <code>borderPainted</code> property.
  1119. * If <code>true</code> and the button has a border,
  1120. * the border is painted. The default value for the
  1121. * <code>borderPainted</code> property is <code>true</code>.
  1122. *
  1123. * @param b if true and border property is not <code>null</code>,
  1124. * the border is painted
  1125. * @see #isBorderPainted
  1126. * @beaninfo
  1127. * bound: true
  1128. * attribute: visualUpdate true
  1129. * description: Whether the border should be painted.
  1130. */
  1131. public void setBorderPainted(boolean b) {
  1132. boolean oldValue = paintBorder;
  1133. paintBorder = b;
  1134. firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, oldValue, paintBorder);
  1135. if (b != oldValue) {
  1136. revalidate();
  1137. repaint();
  1138. }
  1139. }
  1140. /**
  1141. * Paint the button's border if <code>BorderPainted</code>
  1142. * property is true and the button has a border.
  1143. * @param g the <code>Graphics</code> context in which to paint
  1144. *
  1145. * @see #paint
  1146. * @see #setBorder
  1147. */
  1148. protected void paintBorder(Graphics g) {
  1149. if (isBorderPainted()) {
  1150. super.paintBorder(g);
  1151. }
  1152. }
  1153. /**
  1154. * Gets the <code>paintFocus</code> property.
  1155. *
  1156. * @return the <code>paintFocus</code> property
  1157. * @see #setFocusPainted
  1158. */
  1159. public boolean isFocusPainted() {
  1160. return paintFocus;
  1161. }
  1162. /**
  1163. * Sets the <code>paintFocus</code> property, which must
  1164. * be <code>true</code> for the focus state to be painted.
  1165. * The default value for the <code>paintFocus</code> property
  1166. * is <code>true</code>.
  1167. * Some look and feels might not paint focus state;
  1168. * they will ignore this property.
  1169. *
  1170. * @param b if <code>true</code>, the focus state should be painted
  1171. * @see #isFocusPainted
  1172. * @beaninfo
  1173. * bound: true
  1174. * attribute: visualUpdate true
  1175. * description: Whether focus should be painted
  1176. */
  1177. public void setFocusPainted(boolean b) {
  1178. boolean oldValue = paintFocus;
  1179. paintFocus = b;
  1180. firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, oldValue, paintFocus);
  1181. if (b != oldValue && isFocusOwner()) {
  1182. revalidate();
  1183. repaint();
  1184. }
  1185. }
  1186. /**
  1187. * Gets the <code>contentAreaFilled</code> property.
  1188. *
  1189. * @return the <code>contentAreaFilled</code> property
  1190. * @see #setContentAreaFilled
  1191. */
  1192. public boolean isContentAreaFilled() {
  1193. return contentAreaFilled;
  1194. }
  1195. /**
  1196. * Sets the <code>contentAreaFilled</code> property.
  1197. * If <code>true</code> the button will paint the content
  1198. * area. If you wish to have a transparent button, such as
  1199. * an icon only button, for example, then you should set
  1200. * this to <code>false</code>. Do not call <code>setOpaque(false)</code>.
  1201. * The default value for the the <code>contentAreaFilled</code>
  1202. * property is <code>true</code>.
  1203. * <p>
  1204. * This function may cause the component's opaque property to change.
  1205. * <p>
  1206. * The exact behavior of calling this function varies on a
  1207. * component-by-component and L&F-by-L&F basis.
  1208. *
  1209. * @param b if true, the content should be filled; if false
  1210. * the content area is not filled
  1211. * @see #isContentAreaFilled
  1212. * @see #setOpaque
  1213. * @beaninfo
  1214. * bound: true
  1215. * attribute: visualUpdate true
  1216. * description: Whether the button should paint the content area
  1217. * or leave it transparent.
  1218. */
  1219. public void setContentAreaFilled(boolean b) {
  1220. boolean oldValue = contentAreaFilled;
  1221. contentAreaFilled = b;
  1222. firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, oldValue, contentAreaFilled);
  1223. if (b != oldValue) {
  1224. repaint();
  1225. }
  1226. }
  1227. /**
  1228. * Gets the <code>rolloverEnabled</code> property.
  1229. *
  1230. * @return the value of the <code>rolloverEnabled</code> property
  1231. * @see #setRolloverEnabled
  1232. */
  1233. public boolean isRolloverEnabled() {
  1234. return rolloverEnabled;
  1235. }
  1236. /**
  1237. * Sets the <code>rolloverEnabled</code> property, which
  1238. * must be <code>true</code> for rollover effects to occur.
  1239. * The default value for the <code>rolloverEnabled</code>
  1240. * property is <code>false</code>.
  1241. * Some look and feels might not implement rollover effects;
  1242. * they will ignore this property.
  1243. *
  1244. * @param b if <code>true</code>, rollover effects should be painted
  1245. * @see #isRolloverEnabled
  1246. * @beaninfo
  1247. * bound: true
  1248. * attribute: visualUpdate true
  1249. * description: Whether rollover effects should be enabled.
  1250. */
  1251. public void setRolloverEnabled(boolean b) {
  1252. boolean oldValue = rolloverEnabled;
  1253. rolloverEnabled = b;
  1254. firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, oldValue, rolloverEnabled);
  1255. if (b != oldValue) {
  1256. repaint();
  1257. }
  1258. }
  1259. /**
  1260. * Returns the keyboard mnemonic from the the current model.
  1261. * @return the keyboard mnemonic from the model
  1262. */
  1263. public int getMnemonic() {
  1264. return mnemonic;
  1265. }
  1266. /**
  1267. * Sets the keyboard mnemonic on the current model.
  1268. * The mnemonic is the key which when combined with the look and feel's
  1269. * mouseless modifier (usually Alt) will activate this button
  1270. * if focus is contained somewhere within this button's ancestor
  1271. * window.
  1272. * <p>
  1273. * A mnemonic must correspond to a single key on the keyboard
  1274. * and should be specified using one of the <code>VK_XXX</code>
  1275. * keycodes defined in <code>java.awt.event.KeyEvent</code>.
  1276. * Mnemonics are case-insensitive, therefore a key event
  1277. * with the corresponding keycode would cause the button to be
  1278. * activated whether or not the Shift modifier was pressed.
  1279. * <p>
  1280. * If the character defined by the mnemonic is found within
  1281. * the button's label string, the first occurrence of it
  1282. * will be underlined to indicate the mnemonic to the user.
  1283. *
  1284. * @param mnemonic the key code which represents the mnemonic
  1285. * @see java.awt.event.KeyEvent
  1286. * @see #setDisplayedMnemonicIndex
  1287. *
  1288. * @beaninfo
  1289. * bound: true
  1290. * attribute: visualUpdate true
  1291. * description: the keyboard character mnemonic
  1292. */
  1293. public void setMnemonic(int mnemonic) {
  1294. int oldValue = getMnemonic();
  1295. model.setMnemonic(mnemonic);
  1296. updateMnemonicProperties();
  1297. }
  1298. /**
  1299. * This method is now obsolete, please use <code>setMnemonic(int)</code>
  1300. * to set the mnemonic for a button. This method is only designed
  1301. * to handle character values which fall between 'a' and 'z' or
  1302. * 'A' and 'Z'.
  1303. *
  1304. * @param mnemonic a char specifying the mnemonic value
  1305. * @see #setMnemonic(int)
  1306. * @beaninfo
  1307. * bound: true
  1308. * attribute: visualUpdate true
  1309. * description: the keyboard character mnemonic
  1310. */
  1311. public void setMnemonic(char mnemonic) {
  1312. int vk = (int) mnemonic;
  1313. if(vk >= 'a' && vk <='z')
  1314. vk -= ('a' - 'A');
  1315. setMnemonic(vk);
  1316. }
  1317. /**
  1318. * Provides a hint to the look and feel as to which character in the
  1319. * text should be decorated to represent the mnemonic. Not all look and
  1320. * feels may support this. A value of -1 indicates either there is no
  1321. * mnemonic, the mnemonic character is not contained in the string, or
  1322. * the developer does not wish the mnemonic to be displayed.
  1323. * <p>
  1324. * The value of this is updated as the properties relating to the
  1325. * mnemonic change (such as the mnemonic itself, the text...).
  1326. * You should only ever have to call this if
  1327. * you do not wish the default character to be underlined. For example, if
  1328. * the text was 'Save As', with a mnemonic of 'a', and you wanted the 'A'
  1329. * to be decorated, as 'Save <u>A</u>s', you would have to invoke
  1330. * <code>setDisplayedMnemonicIndex(5)</code> after invoking
  1331. * <code>setMnemonic(KeyEvent.VK_A)</code>.
  1332. *
  1333. * @since 1.4
  1334. * @param index Index into the String to underline
  1335. * @exception IllegalArgumentException will be thrown if <code>index</code>
  1336. * is >= length of the text, or < -1
  1337. * @see #getDisplayedMnemonicIndex
  1338. *
  1339. * @beaninfo
  1340. * bound: true
  1341. * attribute: visualUpdate true
  1342. * description: the index into the String to draw the keyboard character
  1343. * mnemonic at
  1344. */
  1345. public void setDisplayedMnemonicIndex(int index)
  1346. throws IllegalArgumentException {
  1347. int oldValue = mnemonicIndex;
  1348. if (index == -1) {
  1349. mnemonicIndex = -1;
  1350. } else {
  1351. String text = getText();
  1352. int textLength = (text == null) ? 0 : text.length();
  1353. if (index < -1 || index >= textLength) { // index out of range
  1354. throw new IllegalArgumentException("index == " + index);
  1355. }
  1356. }
  1357. mnemonicIndex = index;
  1358. firePropertyChange("displayedMnemonicIndex", oldValue, index);
  1359. if (index != oldValue) {
  1360. revalidate();
  1361. repaint();
  1362. }
  1363. }
  1364. /**
  1365. * Returns the character, as an index, that the look and feel should
  1366. * provide decoration for as representing the mnemonic character.
  1367. *
  1368. * @since 1.4
  1369. * @return index representing mnemonic character
  1370. * @see #setDisplayedMnemonicIndex
  1371. */
  1372. public int getDisplayedMnemonicIndex() {
  1373. return mnemonicIndex;
  1374. }
  1375. /**
  1376. * Update the displayedMnemonicIndex property. This method
  1377. * is called when either text or mnemonic changes. The new
  1378. * value of the displayedMnemonicIndex property is the index
  1379. * of the first occurrence of mnemonic in text.
  1380. */
  1381. private void updateDisplayedMnemonicIndex(String text, int mnemonic) {
  1382. setDisplayedMnemonicIndex(
  1383. SwingUtilities.findDisplayedMnemonicIndex(text, mnemonic));
  1384. }
  1385. /**
  1386. * Brings the mnemonic property in accordance with model's mnemonic.
  1387. * This is called when model's mnemonic changes. Also updates the
  1388. * displayedMnemonicIndex property.
  1389. */
  1390. private void updateMnemonicProperties() {
  1391. int newMnemonic = model.getMnemonic();
  1392. if (mnemonic != newMnemonic) {
  1393. int oldValue = mnemonic;
  1394. mnemonic = newMnemonic;
  1395. firePropertyChange(MNEMONIC_CHANGED_PROPERTY,
  1396. oldValue, mnemonic);
  1397. updateDisplayedMnemonicIndex(getText(), mnemonic);
  1398. revalidate();
  1399. repaint();
  1400. }
  1401. }
  1402. /**
  1403. * Sets the amount of time (in milliseconds) required between
  1404. * mouse press events for the button to generate the corresponding
  1405. * action events. After the initial mouse press occurs (and action
  1406. * event generated) any subsequent mouse press events which occur
  1407. * on intervals less than the threshhold will be ignored and no
  1408. * corresponding action event generated. By default the threshhold is 0,
  1409. * which means that for each mouse press, an action event will be
  1410. * fired, no matter how quickly the mouse clicks occur. In buttons
  1411. * where this behavior is not desirable (for example, the "OK" button
  1412. * in a dialog), this threshhold should be set to an appropriate
  1413. * positive value.
  1414. *
  1415. * @see #getMultiClickThreshhold
  1416. * @param threshhold the amount of time required between mouse
  1417. * press events to generate corresponding action events
  1418. * @exception IllegalArgumentException if threshhold < 0
  1419. * @since 1.4
  1420. */
  1421. public void setMultiClickThreshhold(long threshhold) {
  1422. if (threshhold < 0) {
  1423. throw new IllegalArgumentException("threshhold must be >= 0");
  1424. }
  1425. this.multiClickThreshhold = threshhold;
  1426. }
  1427. /**
  1428. * Gets the amount of time (in milliseconds) required between
  1429. * mouse press events for the button to generate the corresponding
  1430. * action events.
  1431. *
  1432. * @see #setMultiClickThreshhold
  1433. * @return the amount of time required between mouse press events
  1434. * to generate corresponding action events
  1435. * @since 1.4
  1436. */
  1437. public long getMultiClickThreshhold() {
  1438. return multiClickThreshhold;
  1439. }
  1440. /**
  1441. * Returns the model that this button represents.
  1442. * @return the <code>model</code> property
  1443. * @see #setModel
  1444. */
  1445. public ButtonModel getModel() {
  1446. return model;
  1447. }
  1448. /**
  1449. * Sets the model that this button represents.
  1450. * @param newModel the new <code>ButtonModel</code>
  1451. * @see #getModel
  1452. * @beaninfo
  1453. * bound: true
  1454. * description: Model that the Button uses.
  1455. */
  1456. public void setModel(ButtonModel newModel) {
  1457. ButtonModel oldModel = getModel();
  1458. if (oldModel != null) {
  1459. oldModel.removeChangeListener(changeListener);
  1460. oldModel.removeActionListener(actionListener);
  1461. changeListener = null;
  1462. actionListener = null;
  1463. }
  1464. model = newModel;
  1465. if (newModel != null) {
  1466. changeListener = createChangeListener();
  1467. actionListener = createActionListener();
  1468. itemListener = createItemListener();
  1469. newModel.addChangeListener(changeListener);
  1470. newModel.addActionListener(actionListener);
  1471. newModel.addItemListener(itemListener);
  1472. mnemonic = newModel.getMnemonic();
  1473. } else {
  1474. mnemonic = '\0';
  1475. }
  1476. updateDisplayedMnemonicIndex(getText(), mnemonic);
  1477. firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel);
  1478. if (newModel != oldModel) {
  1479. revalidate();
  1480. repaint();
  1481. }
  1482. }
  1483. /**
  1484. * Returns the L&F object that renders this component.
  1485. * @return the ButtonUI object
  1486. * @see #setUI
  1487. */
  1488. public ButtonUI getUI() {
  1489. return (ButtonUI) ui;
  1490. }
  1491. /**
  1492. * Sets the L&F object that renders this component.
  1493. * @param ui the <code>ButtonUI</code> L&F object
  1494. * @see #getUI
  1495. * @beaninfo
  1496. * bound: true
  1497. * hidden: true
  1498. * attribute: visualUpdate true
  1499. * description: The UI object that implements the LookAndFeel.
  1500. */
  1501. public void setUI(ButtonUI ui) {
  1502. super.setUI(ui);
  1503. }
  1504. /**
  1505. * Resets the UI property to a value from the current look
  1506. * and feel. Subtypes of <code>AbstractButton</code>
  1507. * should override this to update the UI. For
  1508. * example, <code>JButton</code> might do the following:
  1509. * <pre>
  1510. * setUI((ButtonUI)UIManager.getUI(
  1511. * "ButtonUI", "javax.swing.plaf.basic.BasicButtonUI", this));
  1512. * </pre>
  1513. */
  1514. public void updateUI() {
  1515. }
  1516. /**
  1517. * Adds a <code>ChangeListener</code> to the button.
  1518. * @param l the listener to be added
  1519. */
  1520. public void addChangeListener(ChangeListener l) {
  1521. listenerList.add(ChangeListener.class, l);
  1522. }
  1523. /**
  1524. * Removes a ChangeListener from the button.
  1525. * @param l the listener to be removed
  1526. */
  1527. public void removeChangeListener(ChangeListener l) {
  1528. listenerList.remove(ChangeListener.class, l);
  1529. }
  1530. /**
  1531. * Returns an array of all the <code>ChangeListener</code>s added
  1532. * to this AbstractButton with addChangeListener().
  1533. *
  1534. * @return all of the <code>ChangeListener</code>s added or an empty
  1535. * array if no listeners have been added
  1536. * @since 1.4
  1537. */
  1538. public ChangeListener[] getChangeListeners() {
  1539. return (ChangeListener[])(listenerList.getListeners(
  1540. ChangeListener.class));
  1541. }
  1542. /**
  1543. * Notifies all listeners that have registered interest for
  1544. * notification on this event type. The event instance
  1545. * is lazily created.
  1546. * @see EventListenerList
  1547. */
  1548. protected void fireStateChanged() {
  1549. // Guaranteed to return a non-null array
  1550. Object[] listeners = listenerList.getListenerList();
  1551. // Process the listeners last to first, notifying
  1552. // those that are interested in this event
  1553. for (int i = listeners.length-2; i>=0; i-=2) {
  1554. if (listeners[i]==ChangeListener.class) {
  1555. // Lazily create the event:
  1556. if (changeEvent == null)
  1557. changeEvent = new ChangeEvent(this);
  1558. ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
  1559. }
  1560. }
  1561. }
  1562. /**
  1563. * Adds an <code>ActionListener</code> to the button.
  1564. * @param l the <code>ActionListener</code> to be added
  1565. */
  1566. public void addActionListener(ActionListener l) {
  1567. listenerList.add(ActionListener.class, l);
  1568. }
  1569. /**
  1570. * Removes an <code>ActionListener</code> from the button.
  1571. * If the listener is the currently set <code>Action</code>
  1572. * for the button, then the <code>Action</code>
  1573. * is set to <code>null</code>.
  1574. *
  1575. * @param l the listener to be removed
  1576. */
  1577. public void removeActionListener(ActionListener l) {
  1578. if ((l != null) && (getAction() == l)) {
  1579. setAction(null);
  1580. } else {
  1581. listenerList.remove(ActionListener.class, l);
  1582. }
  1583. }
  1584. /**
  1585. * Returns an array of all the <code>ActionListener</code>s added
  1586. * to this AbstractButton with addActionListener().
  1587. *
  1588. * @return all of the <code>ActionListener</code>s added or an empty
  1589. * array if no listeners have been added
  1590. * @since 1.4
  1591. */
  1592. public ActionListener[] getActionListeners() {
  1593. return (ActionListener[])(listenerList.getListeners(
  1594. ActionListener.class));
  1595. }
  1596. /**
  1597. * Subclasses that want to handle <code>ChangeEvents</code> differently
  1598. * can override this to return another <code>ChangeListener</code>
  1599. * implementation.
  1600. *
  1601. * @return the new <code>ButtonChangeListener</code>
  1602. */
  1603. protected ChangeListener createChangeListener() {
  1604. return (ChangeListener) new ButtonChangeListener();
  1605. }
  1606. /**
  1607. * Extends <code>ChangeListener</code> to be serializable.
  1608. * <p>
  1609. * <strong>Warning:</strong>
  1610. * Serialized objects of this class will not be compatible with
  1611. * future Swing releases. The current serialization support is
  1612. * appropriate for short term storage or RMI between applications running
  1613. * the same version of Swing. As of 1.4, support for long term storage
  1614. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  1615. * has been added to the <code>java.beans</code> package.
  1616. * Please see {@link java.beans.XMLEncoder}.
  1617. */
  1618. protected class ButtonChangeListener implements ChangeListener, Serializable {
  1619. ButtonChangeListener() {
  1620. }
  1621. public void stateChanged(ChangeEvent e) {
  1622. Object source = e.getSource();
  1623. updateMnemonicProperties();
  1624. fireStateChanged();
  1625. repaint();
  1626. }
  1627. }
  1628. /**
  1629. * Notifies all listeners that have registered interest for
  1630. * notification on this event type. The event instance
  1631. * is lazily created using the <code>event</code>
  1632. * parameter.
  1633. *
  1634. * @param event the <code>ActionEvent</code> object
  1635. * @see EventListenerList
  1636. */
  1637. protected void fireActionPerformed(ActionEvent event) {
  1638. // Guaranteed to return a non-null array
  1639. Object[] listeners = listenerList.getListenerList();
  1640. ActionEvent e = null;
  1641. // Process the listeners last to first, notifying
  1642. // those that are interested in this event
  1643. for (int i = listeners.length-2; i>=0; i-=2) {
  1644. if (listeners[i]==ActionListener.class) {
  1645. // Lazily create the event:
  1646. if (e == null) {
  1647. String actionCommand = event.getActionCommand();
  1648. if(actionCommand == null) {
  1649. actionCommand = getActionCommand();
  1650. }
  1651. e = new ActionEvent(AbstractButton.this,
  1652. ActionEvent.ACTION_PERFORMED,
  1653. actionCommand,
  1654. event.getWhen(),
  1655. event.getModifiers());
  1656. }
  1657. ((ActionListener)listeners[i+1]).actionPerformed(e);
  1658. }
  1659. }
  1660. }
  1661. /**
  1662. * Notifies all listeners that have registered interest for
  1663. * notification on this event type. The event instance
  1664. * is lazily created using the <code>event</code> parameter.
  1665. *
  1666. * @param event the <code>ItemEvent</code> object
  1667. * @see EventListenerList
  1668. */
  1669. protected void fireItemStateChanged(ItemEvent event) {
  1670. // Guaranteed to return a non-null array
  1671. Object[] listeners = listenerList.getListenerList();
  1672. ItemEvent e = null;
  1673. // Process the listeners last to first, notifying
  1674. // those that are interested in this event
  1675. for (int i = listeners.length-2; i>=0; i-=2) {
  1676. if (listeners[i]==ItemListener.class) {
  1677. // Lazily create the event:
  1678. if (e == null) {
  1679. e = new ItemEvent(AbstractButton.this,
  1680. ItemEvent.ITEM_STATE_CHANGED,
  1681. AbstractButton.this,
  1682. event.getStateChange());
  1683. }
  1684. ((ItemListener)listeners[i+1]).itemStateChanged(e);
  1685. }
  1686. }
  1687. if (accessibleContext != null) {
  1688. if (event.getStateChange() == ItemEvent.SELECTED) {
  1689. accessibleContext.firePropertyChange(
  1690. AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  1691. null, AccessibleState.SELECTED);
  1692. accessibleContext.firePropertyChange(
  1693. AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
  1694. new Integer(0), new Integer(1));
  1695. } else {
  1696. accessibleContext.firePropertyChange(
  1697. AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  1698. AccessibleState.SELECTED, null);
  1699. accessibleContext.firePropertyChange(
  1700. AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
  1701. new Integer(1), new Integer(0));
  1702. }
  1703. }
  1704. }
  1705. private class ForwardActionEvents implements ActionListener, Serializable {
  1706. public void actionPerformed(ActionEvent event) {
  1707. fireActionPerformed(event);
  1708. }
  1709. }
  1710. protected ActionListener createActionListener() {
  1711. return new ForwardActionEvents();
  1712. }
  1713. private class ForwardItemEvents implements ItemListener, Serializable {
  1714. public void itemStateChanged(ItemEvent event) {
  1715. fireItemStateChanged(event);
  1716. }
  1717. }
  1718. protected ItemListener createItemListener() {
  1719. return new ForwardItemEvents();
  1720. }
  1721. /**
  1722. * Enables (or disables) the button.
  1723. * @param b true to enable the button, otherwise false
  1724. */
  1725. public void setEnabled(boolean b) {
  1726. if (!b && model.isRollover()) {
  1727. model.setRollover(false);
  1728. }
  1729. super.setEnabled(b);
  1730. model.setEnabled(b);
  1731. }
  1732. // *** Deprecated java.awt.Button APIs below *** //
  1733. /**
  1734. * Returns the label text.
  1735. *
  1736. * @return a <code>String</code> containing the label
  1737. * @deprecated - Replaced by <code>getText</code>
  1738. */
  1739. public String getLabel() {
  1740. return getText();
  1741. }
  1742. /**
  1743. * Sets the label text.
  1744. *
  1745. * @param label a <code>String</code> containing the text
  1746. * @deprecated - Replaced by <code>setText(text)</code>
  1747. * @beaninfo
  1748. * bound: true
  1749. * description: Replace by setText(text)
  1750. */
  1751. public void setLabel(String label) {
  1752. setText(label);
  1753. }
  1754. /**
  1755. * Adds an <code>ItemListener</code> to the <code>checkbox</code>.
  1756. * @param l the <code>ItemListener</code> to be added
  1757. */
  1758. public void addItemListener(ItemListener l) {
  1759. listenerList.add(ItemListener.class, l);
  1760. }
  1761. /**
  1762. * Removes an <code>ItemListener</code> from the button.
  1763. * @param l the <code>ItemListener</code> to be removed
  1764. */
  1765. public void removeItemListener(ItemListener l) {
  1766. listenerList.remove(ItemListener.class, l);
  1767. }
  1768. /**
  1769. * Returns an array of all the <code>ItemListener</code>s added
  1770. * to this AbstractButton with addItemListener().
  1771. *
  1772. * @return all of the <code>ItemListener</code>s added or an empty
  1773. * array if no listeners have been added
  1774. * @since 1.4
  1775. */
  1776. public ItemListener[] getItemListeners() {
  1777. return (ItemListener[])listenerList.getListeners(ItemListener.class);
  1778. }
  1779. /**
  1780. * Returns an array (length 1) containing the label or
  1781. * <code>null</code> if the button is not selected.
  1782. *
  1783. * @return an array containing 1 Object: the text of the button,
  1784. * if the item is selected; otherwise <code>null</code>
  1785. */
  1786. public Object[] getSelectedObjects() {
  1787. if (isSelected() == false) {
  1788. return null;
  1789. }
  1790. Object[] selectedObjects = new Object[1];
  1791. selectedObjects[0] = getText();
  1792. return selectedObjects;
  1793. }
  1794. protected void init(String text, Icon icon) {
  1795. setLayout(new OverlayLayout(this));
  1796. if(text != null) {
  1797. setText(text);
  1798. }
  1799. if(icon != null) {
  1800. setIcon(icon);
  1801. }
  1802. // Set the UI
  1803. updateUI();
  1804. setAlignmentX(LEFT_ALIGNMENT);
  1805. setAlignmentY(CENTER_ALIGNMENT);
  1806. }
  1807. /**
  1808. * This is overridden to return false if the current <code>Icon</code>'s
  1809. * <code>Image</code> is not equal to the
  1810. * passed in <code>Image</code> <code>img</code>.
  1811. *
  1812. * @param img the <code>Image</code> to be compared
  1813. * @param infoflags flags used to repaint the button when the image
  1814. * is updated and which determine how much is to be painted
  1815. * @param x the x coordinate
  1816. * @param y the y coordinate
  1817. * @param w the width
  1818. * @param h the height
  1819. * @see java.awt.image.ImageObserver
  1820. * @see java.awt.Component#imageUpdate(java.awt.Image, int, int, int, int, int)
  1821. */
  1822. public boolean imageUpdate(Image img, int infoflags,
  1823. int x, int y, int w, int h) {
  1824. Icon iconDisplayed = getIcon();
  1825. if (iconDisplayed == null) {
  1826. return false;
  1827. }
  1828. if (!model.isEnabled()) {
  1829. if (model.isSelected()) {
  1830. iconDisplayed = getDisabledSelectedIcon();
  1831. } else {
  1832. iconDisplayed = getDisabledIcon();
  1833. }
  1834. } else if (model.isPressed() && model.isArmed()) {
  1835. iconDisplayed = getPressedIcon();
  1836. } else if (isRolloverEnabled() && model.isRollover()) {
  1837. if (model.isSelected()) {
  1838. iconDisplayed = getRolloverSelectedIcon();
  1839. } else {
  1840. iconDisplayed = getRolloverIcon();
  1841. }
  1842. } else if (model.isSelected()) {
  1843. iconDisplayed = getSelectedIcon();
  1844. }
  1845. if (!SwingUtilities.doesIconReferenceImage(iconDisplayed, img)) {
  1846. // We don't know about this image, disable the notification so
  1847. // we don't keep repainting.
  1848. return false;
  1849. }
  1850. return super.imageUpdate(img, infoflags, x, y, w, h);
  1851. }
  1852. /**
  1853. * Returns a string representation of this <code>AbstractButton</code>.
  1854. * This method
  1855. * is intended to be used only for debugging purposes, and the
  1856. * content and format of the returned string may vary between
  1857. * implementations. The returned string may be empty but may not
  1858. * be <code>null</code>.
  1859. * <P>
  1860. * Overriding <code>paramString</code> to provide information about the
  1861. * specific new aspects of the JFC components.
  1862. *
  1863. * @return a string representation of this <code>AbstractButton</code>
  1864. */
  1865. protected String paramString() {
  1866. String defaultIconString = ((defaultIcon != null)
  1867. && (defaultIcon != this) ?
  1868. defaultIcon.toString() : "");
  1869. String pressedIconString = ((pressedIcon != null)
  1870. && (pressedIcon != this) ?
  1871. pressedIcon.toString() : "");
  1872. String disabledIconString = ((disabledIcon != null)
  1873. && (disabledIcon != this) ?
  1874. disabledIcon.toString() : "");
  1875. String selectedIconString = ((selectedIcon != null)
  1876. && (selectedIcon != this) ?
  1877. selectedIcon.toString() : "");
  1878. String disabledSelectedIconString = ((disabledSelectedIcon != null) &&
  1879. (disabledSelectedIcon != this) ?
  1880. disabledSelectedIcon.toString()
  1881. : "");
  1882. String rolloverIconString = ((rolloverIcon != null)
  1883. && (rolloverIcon != this) ?
  1884. rolloverIcon.toString() : "");
  1885. String rolloverSelectedIconString = ((rolloverSelectedIcon != null) &&
  1886. (rolloverSelectedIcon != this) ?
  1887. rolloverSelectedIcon.toString()
  1888. : "");
  1889. String paintBorderString = (paintBorder ? "true" : "false");
  1890. String paintFocusString = (paintFocus ? "true" : "false");
  1891. String rolloverEnabledString = (rolloverEnabled ? "true" : "false");
  1892. return super.paramString() +
  1893. ",defaultIcon=" + defaultIconString +
  1894. ",disabledIcon=" + disabledIconString +
  1895. ",disabledSelectedIcon=" + disabledSelectedIconString +
  1896. ",margin=" + margin +
  1897. ",paintBorder=" + paintBorderString +
  1898. ",paintFocus=" + paintFocusString +
  1899. ",pressedIcon=" + pressedIconString +
  1900. ",rolloverEnabled=" + rolloverEnabledString +
  1901. ",rolloverIcon=" + rolloverIconString +
  1902. ",rolloverSelectedIcon=" + rolloverSelectedIconString +
  1903. ",selectedIcon=" + selectedIconString +
  1904. ",text=" + text;
  1905. }
  1906. ///////////////////
  1907. // Accessibility support
  1908. ///////////////////
  1909. /**
  1910. * This class implements accessibility support for the
  1911. * <code>AbstractButton</code> class. It provides an implementation of the
  1912. * Java Accessibility API appropriate to button and menu item
  1913. * user-interface elements.
  1914. * <p>
  1915. * <strong>Warning:</strong>
  1916. * Serialized objects of this class will not be compatible with
  1917. * future Swing releases. The current serialization support is
  1918. * appropriate for short term storage or RMI between applications running
  1919. * the same version of Swing. As of 1.4, support for long term storage
  1920. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  1921. * has been added to the <code>java.beans</code> package.
  1922. * Please see {@link java.beans.XMLEncoder}.
  1923. */
  1924. protected abstract class AccessibleAbstractButton
  1925. extends AccessibleJComponent implements AccessibleAction,
  1926. AccessibleValue, AccessibleText, AccessibleExtendedComponent {
  1927. /**
  1928. * Returns the accessible name of this object.
  1929. *
  1930. * @return the localized name of the object -- can be
  1931. * <code>null</code> if this
  1932. * object does not have a name
  1933. */
  1934. public String getAccessibleName() {
  1935. if (accessibleName != null) {
  1936. return accessibleName;
  1937. } else {
  1938. if (AbstractButton.this.getText() == null) {
  1939. return super.getAccessibleName();
  1940. } else {
  1941. return AbstractButton.this.getText();
  1942. }
  1943. }
  1944. }
  1945. /**
  1946. * Get the AccessibleIcons associated with this object if one
  1947. * or more exist. Otherwise return null.
  1948. */
  1949. public AccessibleIcon [] getAccessibleIcon() {
  1950. if (AbstractButton.this.accessibleIcon == null) {
  1951. return null;
  1952. } else {
  1953. AccessibleIcon [] ac = new AccessibleIcon[1];
  1954. ac[0] = AbstractButton.this.accessibleIcon;
  1955. return ac;
  1956. }
  1957. }
  1958. /**
  1959. * Get the state set of this object.
  1960. *
  1961. * @return an instance of AccessibleState containing the current state
  1962. * of the object
  1963. * @see AccessibleState
  1964. */
  1965. public AccessibleStateSet getAccessibleStateSet() {
  1966. AccessibleStateSet states = super.getAccessibleStateSet();
  1967. if (getModel().isArmed()) {
  1968. states.add(AccessibleState.ARMED);
  1969. }
  1970. if (isFocusOwner()) {
  1971. states.add(AccessibleState.FOCUSED);
  1972. }
  1973. if (getModel().isPressed()) {
  1974. states.add(AccessibleState.PRESSED);
  1975. }
  1976. if (isSelected()) {
  1977. states.add(AccessibleState.CHECKED);
  1978. }
  1979. return states;
  1980. }
  1981. /**
  1982. * Get the AccessibleRelationSet associated with this object if one
  1983. * exists. Otherwise return null.
  1984. * @see AccessibleRelation
  1985. */
  1986. public AccessibleRelationSet getAccessibleRelationSet() {
  1987. // Check where the AccessibleContext's relation
  1988. // set already contains a MEMBER_OF relation.
  1989. AccessibleRelationSet relationSet
  1990. = super.getAccessibleRelationSet();
  1991. if (!relationSet.contains(AccessibleRelation.MEMBER_OF)) {
  1992. // get the members of the button group if one exists
  1993. ButtonModel model = getModel();
  1994. if (model != null && model instanceof DefaultButtonModel) {
  1995. ButtonGroup group = ((DefaultButtonModel)model).getGroup();
  1996. if (group != null) {
  1997. // set the target of the MEMBER_OF relation to be
  1998. // the members of the button group.
  1999. int len = group.getButtonCount();
  2000. Object [] target = new Object[len];
  2001. Enumeration elem = group.getElements();
  2002. for (int i = 0; i < len; i++) {
  2003. if (elem.hasMoreElements()) {
  2004. target[i] = elem.nextElement();
  2005. }
  2006. }
  2007. AccessibleRelation relation =
  2008. new AccessibleRelation(AccessibleRelation.MEMBER_OF);
  2009. relation.setTarget(target);
  2010. relationSet.add(relation);
  2011. }
  2012. }
  2013. }
  2014. return relationSet;
  2015. }
  2016. /**
  2017. * Get the AccessibleAction associated with this object. In the
  2018. * implementation of the Java Accessibility API for this class,
  2019. * return this object, which is responsible for implementing the
  2020. * AccessibleAction interface on behalf of itself.
  2021. *
  2022. * @return this object
  2023. */
  2024. public AccessibleAction getAccessibleAction() {
  2025. return this;
  2026. }
  2027. /**
  2028. * Get the AccessibleValue associated with this object. In the
  2029. * implementation of the Java Accessibility API for this class,
  2030. * return this object, which is responsible for implementing the
  2031. * AccessibleValue interface on behalf of itself.
  2032. *
  2033. * @return this object
  2034. */
  2035. public AccessibleValue getAccessibleValue() {
  2036. return this;
  2037. }
  2038. /**
  2039. * Returns the number of Actions available in this object. The
  2040. * default behavior of a button is to have one action - toggle
  2041. * the button.
  2042. *
  2043. * @return 1, the number of Actions in this object
  2044. */
  2045. public int getAccessibleActionCount() {
  2046. return 1;
  2047. }
  2048. /**
  2049. * Return a description of the specified action of the object.
  2050. *
  2051. * @param i zero-based index of the actions
  2052. */
  2053. public String getAccessibleActionDescription(int i) {
  2054. if (i == 0) {
  2055. return UIManager.getString("AbstractButton.clickText");
  2056. } else {
  2057. return null;
  2058. }
  2059. }
  2060. /**
  2061. * Perform the specified Action on the object
  2062. *
  2063. * @param i zero-based index of actions
  2064. * @return true if the the action was performed; else false.
  2065. */
  2066. public boolean doAccessibleAction(int i) {
  2067. if (i == 0) {
  2068. doClick();
  2069. return true;
  2070. } else {
  2071. return false;
  2072. }
  2073. }
  2074. /**
  2075. * Get the value of this object as a Number.
  2076. *
  2077. * @return An Integer of 0 if this isn't selected or an Integer of 1 if
  2078. * this is selected.
  2079. * @see AbstractButton#isSelected
  2080. */
  2081. public Number getCurrentAccessibleValue() {
  2082. if (isSelected()) {
  2083. return new Integer(1);
  2084. } else {
  2085. return new Integer(0);
  2086. }
  2087. }
  2088. /**
  2089. * Set the value of this object as a Number.
  2090. *
  2091. * @return True if the value was set.
  2092. */
  2093. public boolean setCurrentAccessibleValue(Number n) {
  2094. if (n instanceof Integer) {
  2095. int i = n.intValue();
  2096. if (i == 0) {
  2097. setSelected(false);
  2098. } else {
  2099. setSelected(true);
  2100. }
  2101. return true;
  2102. } else {
  2103. return false;
  2104. }
  2105. }
  2106. /**
  2107. * Get the minimum value of this object as a Number.
  2108. *
  2109. * @return an Integer of 0.
  2110. */
  2111. public Number getMinimumAccessibleValue() {
  2112. return new Integer(0);
  2113. }
  2114. /**
  2115. * Get the maximum value of this object as a Number.
  2116. *
  2117. * @return An Integer of 1.
  2118. */
  2119. public Number getMaximumAccessibleValue() {
  2120. return new Integer(1);
  2121. }
  2122. /* AccessibleText ---------- */
  2123. public AccessibleText getAccessibleText() {
  2124. View view = (View)AbstractButton.this.getClientProperty("html");
  2125. if (view != null) {
  2126. return this;
  2127. } else {
  2128. return null;
  2129. }
  2130. }
  2131. /**
  2132. * Given a point in local coordinates, return the zero-based index
  2133. * of the character under that Point. If the point is invalid,
  2134. * this method returns -1.
  2135. *
  2136. * Note: the AbstractButton must have a valid size (e.g. have
  2137. * been added to a parent container whose ancestor container
  2138. * is a valid top-level window) for this method to be able
  2139. * to return a meaningful value.
  2140. *
  2141. * @param p the Point in local coordinates
  2142. * @return the zero-based index of the character under Point p; if
  2143. * Point is invalid returns -1.
  2144. */
  2145. public int getIndexAtPoint(Point p) {
  2146. View view = (View) AbstractButton.this.getClientProperty("html");
  2147. if (view != null) {
  2148. Rectangle r = getTextRectangle();
  2149. if (r == null) {
  2150. return -1;
  2151. }
  2152. Rectangle2D.Float shape =
  2153. new Rectangle2D.Float(r.x, r.y, r.width, r.height);
  2154. Position.Bias bias[] = new Position.Bias[1];
  2155. return view.viewToModel(p.x, p.y, shape, bias);
  2156. } else {
  2157. return -1;
  2158. }
  2159. }
  2160. /**
  2161. * Determine the bounding box of the character at the given
  2162. * index into the string. The bounds are returned in local
  2163. * coordinates. If the index is invalid an empty rectangle is
  2164. * returned.
  2165. *
  2166. * Note: the AbstractButton must have a valid size (e.g. have
  2167. * been added to a parent container whose ancestor container
  2168. * is a valid top-level window) for this method to be able
  2169. * to return a meaningful value.
  2170. *
  2171. * @param i the index into the String
  2172. * @return the screen coordinates of the character's the bounding box,
  2173. * if index is invalid returns an empty rectangle.
  2174. */
  2175. public Rectangle getCharacterBounds(int i) {
  2176. View view = (View) AbstractButton.this.getClientProperty("html");
  2177. if (view != null) {
  2178. Rectangle r = getTextRectangle();
  2179. if (r == null) {
  2180. return null;
  2181. }
  2182. Rectangle2D.Float shape =
  2183. new Rectangle2D.Float(r.x, r.y, r.width, r.height);
  2184. try {
  2185. Shape charShape =
  2186. view.modelToView(i, shape, Position.Bias.Forward);
  2187. return charShape.getBounds();
  2188. } catch (BadLocationException e) {
  2189. return null;
  2190. }
  2191. } else {
  2192. return null;
  2193. }
  2194. }
  2195. /**
  2196. * Return the number of characters (valid indicies)
  2197. *
  2198. * @return the number of characters
  2199. */
  2200. public int getCharCount() {
  2201. View view = (View) AbstractButton.this.getClientProperty("html");
  2202. if (view != null) {
  2203. Document d = view.getDocument();
  2204. if (d instanceof StyledDocument) {
  2205. StyledDocument doc = (StyledDocument)d;
  2206. return doc.getLength();
  2207. }
  2208. }
  2209. return accessibleContext.getAccessibleName().length();
  2210. }
  2211. /**
  2212. * Return the zero-based offset of the caret.
  2213. *
  2214. * Note: That to the right of the caret will have the same index
  2215. * value as the offset (the caret is between two characters).
  2216. * @return the zero-based offset of the caret.
  2217. */
  2218. public int getCaretPosition() {
  2219. // There is no caret.
  2220. return -1;
  2221. }
  2222. /**
  2223. * Returns the String at a given index.
  2224. *
  2225. * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
  2226. * or AccessibleText.SENTENCE to retrieve
  2227. * @param index an index within the text >= 0
  2228. * @return the letter, word, or sentence,
  2229. * null for an invalid index or part
  2230. */
  2231. public String getAtIndex(int part, int index) {
  2232. if (index < 0 || index >= getCharCount()) {
  2233. return null;
  2234. }
  2235. switch (part) {
  2236. case AccessibleText.CHARACTER:
  2237. try {
  2238. return getText(index, 1);
  2239. } catch (BadLocationException e) {
  2240. return null;
  2241. }
  2242. case AccessibleText.WORD:
  2243. try {
  2244. String s = getText(0, getCharCount());
  2245. BreakIterator words = BreakIterator.getWordInstance(getLocale());
  2246. words.setText(s);
  2247. int end = words.following(index);
  2248. return s.substring(words.previous(), end);
  2249. } catch (BadLocationException e) {
  2250. return null;
  2251. }
  2252. case AccessibleText.SENTENCE:
  2253. try {
  2254. String s = getText(0, getCharCount());
  2255. BreakIterator sentence =
  2256. BreakIterator.getSentenceInstance(getLocale());
  2257. sentence.setText(s);
  2258. int end = sentence.following(index);
  2259. return s.substring(sentence.previous(), end);
  2260. } catch (BadLocationException e) {
  2261. return null;
  2262. }
  2263. default:
  2264. return null;
  2265. }
  2266. }
  2267. /**
  2268. * Returns the String after a given index.
  2269. *
  2270. * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
  2271. * or AccessibleText.SENTENCE to retrieve
  2272. * @param index an index within the text >= 0
  2273. * @return the letter, word, or sentence, null for an invalid
  2274. * index or part
  2275. */
  2276. public String getAfterIndex(int part, int index) {
  2277. if (index < 0 || index >= getCharCount()) {
  2278. return null;
  2279. }
  2280. switch (part) {
  2281. case AccessibleText.CHARACTER:
  2282. if (index+1 >= getCharCount()) {
  2283. return null;
  2284. }
  2285. try {
  2286. return getText(index+1, 1);
  2287. } catch (BadLocationException e) {
  2288. return null;
  2289. }
  2290. case AccessibleText.WORD:
  2291. try {
  2292. String s = getText(0, getCharCount());
  2293. BreakIterator words = BreakIterator.getWordInstance(getLocale());
  2294. words.setText(s);
  2295. int start = words.following(index);
  2296. if (start == BreakIterator.DONE || start >= s.length()) {
  2297. return null;
  2298. }
  2299. int end = words.following(start);
  2300. if (end == BreakIterator.DONE || end >= s.length()) {
  2301. return null;
  2302. }
  2303. return s.substring(start, end);
  2304. } catch (BadLocationException e) {
  2305. return null;
  2306. }
  2307. case AccessibleText.SENTENCE:
  2308. try {
  2309. String s = getText(0, getCharCount());
  2310. BreakIterator sentence =
  2311. BreakIterator.getSentenceInstance(getLocale());
  2312. sentence.setText(s);
  2313. int start = sentence.following(index);
  2314. if (start == BreakIterator.DONE || start >= s.length()) {
  2315. return null;
  2316. }
  2317. int end = sentence.following(start);
  2318. if (end == BreakIterator.DONE || end >= s.length()) {
  2319. return null;
  2320. }
  2321. return s.substring(start, end);
  2322. } catch (BadLocationException e) {
  2323. return null;
  2324. }
  2325. default:
  2326. return null;
  2327. }
  2328. }
  2329. /**
  2330. * Returns the String before a given index.
  2331. *
  2332. * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
  2333. * or AccessibleText.SENTENCE to retrieve
  2334. * @param index an index within the text >= 0
  2335. * @return the letter, word, or sentence, null for an invalid index
  2336. * or part
  2337. */
  2338. public String getBeforeIndex(int part, int index) {
  2339. if (index < 0 || index > getCharCount()-1) {
  2340. return null;
  2341. }
  2342. switch (part) {
  2343. case AccessibleText.CHARACTER:
  2344. if (index == 0) {
  2345. return null;
  2346. }
  2347. try {
  2348. return getText(index-1, 1);
  2349. } catch (BadLocationException e) {
  2350. return null;
  2351. }
  2352. case AccessibleText.WORD:
  2353. try {
  2354. String s = getText(0, getCharCount());
  2355. BreakIterator words = BreakIterator.getWordInstance(getLocale());
  2356. words.setText(s);
  2357. int end = words.following(index);
  2358. end = words.previous();
  2359. int start = words.previous();
  2360. if (start == BreakIterator.DONE) {
  2361. return null;
  2362. }
  2363. return s.substring(start, end);
  2364. } catch (BadLocationException e) {
  2365. return null;
  2366. }
  2367. case AccessibleText.SENTENCE:
  2368. try {
  2369. String s = getText(0, getCharCount());
  2370. BreakIterator sentence =
  2371. BreakIterator.getSentenceInstance(getLocale());
  2372. sentence.setText(s);
  2373. int end = sentence.following(index);
  2374. end = sentence.previous();
  2375. int start = sentence.previous();
  2376. if (start == BreakIterator.DONE) {
  2377. return null;
  2378. }
  2379. return s.substring(start, end);
  2380. } catch (BadLocationException e) {
  2381. return null;
  2382. }
  2383. default:
  2384. return null;
  2385. }
  2386. }
  2387. /**
  2388. * Return the AttributeSet for a given character at a given index
  2389. *
  2390. * @param i the zero-based index into the text
  2391. * @return the AttributeSet of the character
  2392. */
  2393. public AttributeSet getCharacterAttribute(int i) {
  2394. View view = (View) AbstractButton.this.getClientProperty("html");
  2395. if (view != null) {
  2396. Document d = view.getDocument();
  2397. if (d instanceof StyledDocument) {
  2398. StyledDocument doc = (StyledDocument)d;
  2399. Element elem = doc.getCharacterElement(i);
  2400. if (elem != null) {
  2401. return elem.getAttributes();
  2402. }
  2403. }
  2404. }
  2405. return null;
  2406. }
  2407. /**
  2408. * Returns the start offset within the selected text.
  2409. * If there is no selection, but there is
  2410. * a caret, the start and end offsets will be the same.
  2411. *
  2412. * @return the index into the text of the start of the selection
  2413. */
  2414. public int getSelectionStart() {
  2415. // Text cannot be selected.
  2416. return -1;
  2417. }
  2418. /**
  2419. * Returns the end offset within the selected text.
  2420. * If there is no selection, but there is
  2421. * a caret, the start and end offsets will be the same.
  2422. *
  2423. * @return the index into teh text of the end of the selection
  2424. */
  2425. public int getSelectionEnd() {
  2426. // Text cannot be selected.
  2427. return -1;
  2428. }
  2429. /**
  2430. * Returns the portion of the text that is selected.
  2431. *
  2432. * @return the String portion of the text that is selected
  2433. */
  2434. public String getSelectedText() {
  2435. // Text cannot be selected.
  2436. return null;
  2437. }
  2438. /*
  2439. * Returns the text substring starting at the specified
  2440. * offset with the specified length.
  2441. */
  2442. private String getText(int offset, int length)
  2443. throws BadLocationException {
  2444. View view = (View) AbstractButton.this.getClientProperty("html");
  2445. if (view != null) {
  2446. Document d = view.getDocument();
  2447. if (d instanceof StyledDocument) {
  2448. StyledDocument doc = (StyledDocument)d;
  2449. return doc.getText(offset, length);
  2450. }
  2451. }
  2452. return null;
  2453. }
  2454. /*
  2455. * Returns the bounding rectangle for the component text.
  2456. */
  2457. private Rectangle getTextRectangle() {
  2458. String text = AbstractButton.this.getText();
  2459. Icon icon = (AbstractButton.this.isEnabled()) ? AbstractButton.this.getIcon() : AbstractButton.this.getDisabledIcon();
  2460. if ((icon == null) && (text == null)) {
  2461. return null;
  2462. }
  2463. Rectangle paintIconR = new Rectangle();
  2464. Rectangle paintTextR = new Rectangle();
  2465. Rectangle paintViewR = new Rectangle();
  2466. Insets paintViewInsets = new Insets(0, 0, 0, 0);
  2467. paintViewInsets = AbstractButton.this.getInsets(paintViewInsets);
  2468. paintViewR.x = paintViewInsets.left;
  2469. paintViewR.y = paintViewInsets.top;
  2470. paintViewR.width = AbstractButton.this.getWidth() - (paintViewInsets.left + paintViewInsets.right);
  2471. paintViewR.height = AbstractButton.this.getHeight() - (paintViewInsets.top + paintViewInsets.bottom);
  2472. Graphics g = AbstractButton.this.getGraphics();
  2473. if (g == null) {
  2474. return null;
  2475. }
  2476. String clippedText = SwingUtilities.layoutCompoundLabel(
  2477. (JComponent)AbstractButton.this,
  2478. g.getFontMetrics(),
  2479. text,
  2480. icon,
  2481. AbstractButton.this.getVerticalAlignment(),
  2482. AbstractButton.this.getHorizontalAlignment(),
  2483. AbstractButton.this.getVerticalTextPosition(),
  2484. AbstractButton.this.getHorizontalTextPosition(),
  2485. paintViewR,
  2486. paintIconR,
  2487. paintTextR,
  2488. 0);
  2489. return paintTextR;
  2490. }
  2491. // ----- AccessibleExtendedComponent
  2492. /**
  2493. * Returns the AccessibleExtendedComponent
  2494. *
  2495. * @return the AccessibleExtendedComponent
  2496. */
  2497. AccessibleExtendedComponent getAccessibleExtendedComponent() {
  2498. return this;
  2499. }
  2500. /**
  2501. * Returns the tool tip text
  2502. *
  2503. * @return the tool tip text, if supported, of the object;
  2504. * otherwise, null
  2505. */
  2506. public String getToolTipText() {
  2507. return AbstractButton.this.getToolTipText();
  2508. }
  2509. /**
  2510. * Returns the titled border text
  2511. *
  2512. * @return the titled border text, if supported, of the object;
  2513. * otherwise, null
  2514. */
  2515. public String getTitledBorderText() {
  2516. return super.getTitledBorderText();
  2517. }
  2518. /**
  2519. * Returns key bindings associated with this object
  2520. *
  2521. * @return the key bindings, if supported, of the object;
  2522. * otherwise, null
  2523. * @see AccessibleKeyBinding
  2524. */
  2525. public AccessibleKeyBinding getAccessibleKeyBinding() {
  2526. int mnemonic = AbstractButton.this.getMnemonic();
  2527. if (mnemonic == 0) {
  2528. return null;
  2529. }
  2530. return new ButtonKeyBinding(mnemonic);
  2531. }
  2532. class ButtonKeyBinding implements AccessibleKeyBinding {
  2533. int mnemonic;
  2534. ButtonKeyBinding(int mnemonic) {
  2535. this.mnemonic = mnemonic;
  2536. }
  2537. /**
  2538. * Returns the number of key bindings for this object
  2539. *
  2540. * @return the zero-based number of key bindings for this object
  2541. */
  2542. public int getAccessibleKeyBindingCount() {
  2543. return 1;
  2544. }
  2545. /**
  2546. * Returns a key binding for this object. The value returned is an
  2547. * java.lang.Object which must be cast to appropriate type depending
  2548. * on the underlying implementation of the key. For example, if the
  2549. * Object returned is a javax.swing.KeyStroke, the user of this
  2550. * method should do the following:
  2551. * <nf><code>
  2552. * Component c = <get the component that has the key bindings>
  2553. * AccessibleContext ac = c.getAccessibleContext();
  2554. * AccessibleKeyBinding akb = ac.getAccessibleKeyBinding();
  2555. * for (int i = 0; i < akb.getAccessibleKeyBindingCount(); i++) {
  2556. * Object o = akb.getAccessibleKeyBinding(i);
  2557. * if (o instanceof javax.swing.KeyStroke) {
  2558. * javax.swing.KeyStroke keyStroke = (javax.swing.KeyStroke)o;
  2559. * <do something with the key binding>
  2560. * }
  2561. * }
  2562. * </code></nf>
  2563. *
  2564. * @param i zero-based index of the key bindings
  2565. * @return a javax.lang.Object which specifies the key binding
  2566. * @exception IllegalArgumentException if the index is
  2567. * out of bounds
  2568. * @see #getAccessibleKeyBindingCount
  2569. */
  2570. public java.lang.Object getAccessibleKeyBinding(int i) {
  2571. if (i != 0) {
  2572. throw new IllegalArgumentException();
  2573. }
  2574. return KeyStroke.getKeyStroke(mnemonic, 0);
  2575. }
  2576. }
  2577. }
  2578. }