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