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