1. /*
  2. * @(#)AbstractButton.java 1.161 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.*;
  9. import java.awt.event.*;
  10. import java.awt.image.*;
  11. import java.text.*;
  12. import java.awt.geom.*;
  13. import java.beans.*;
  14. import java.util.Enumeration;
  15. import java.util.Vector;
  16. import java.io.Serializable;
  17. import javax.swing.event.*;
  18. import javax.swing.border.*;
  19. import javax.swing.plaf.*;
  20. import javax.accessibility.*;
  21. import javax.swing.text.*;
  22. import javax.swing.text.html.*;
  23. import javax.swing.plaf.basic.*;
  24. import java.util.*;
  25. /**
  26. * Defines common behaviors for buttons and menu items.
  27. * For further information see
  28. * <a
  29. href="http://java.sun.com/docs/books/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons</a>,
  30. * a section in <em>The Java Tutorial</em>.
  31. *
  32. * <p>
  33. *
  34. * <strong>Warning:</strong>
  35. * Serialized objects of this class will not be compatible with
  36. * future Swing releases. The current serialization support is
  37. * appropriate for short term storage or RMI between applications running
  38. * the same version of Swing. As of 1.4, support for long term storage
  39. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  40. * has been added to the <code>java.beans</code> package.
  41. * Please see {@link java.beans.XMLEncoder}.
  42. *
  43. * @version 1.161 01/23/03
  44. * @author Jeff Dinkins
  45. */
  46. public abstract class AbstractButton extends JComponent implements ItemSelectable, SwingConstants {
  47. // *********************************
  48. // ******* Button properties *******
  49. // *********************************
  50. /** Identifies a change in the button model. */
  51. public static final String MODEL_CHANGED_PROPERTY = "model";
  52. /** Identifies a change in the button's text. */
  53. public static final String TEXT_CHANGED_PROPERTY = "text";
  54. /** Identifies a change to the button's mnemonic. */
  55. public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic";
  56. // Text positioning and alignment
  57. /** Identifies a change in the button's margins. */
  58. public static final String MARGIN_CHANGED_PROPERTY = "margin";
  59. /** Identifies a change in the button's vertical alignment. */
  60. public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";
  61. /** Identifies a change in the button's horizontal alignment. */
  62. public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = "horizontalAlignment";
  63. /** Identifies a change in the button's vertical text position. */
  64. public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = "verticalTextPosition";
  65. /** Identifies a change in the button's horizontal text position. */
  66. public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = "horizontalTextPosition";
  67. // Paint options
  68. /**
  69. * Identifies a change to having the border drawn,
  70. * or having it not drawn.
  71. */
  72. public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";
  73. /**
  74. * Identifies a change to having the border highlighted when focused,
  75. * or not.
  76. */
  77. public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
  78. /**
  79. * Identifies a change from rollover enabled to disabled or back
  80. * to enabled.
  81. */
  82. public static final String ROLLOVER_ENABLED_CHANGED_PROPERTY = "rolloverEnabled";
  83. /**
  84. * Identifies a change to having the button paint the content area.
  85. */
  86. public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled";
  87. // Icons
  88. /** Identifies a change to the icon that represents the button. */
  89. public static final String ICON_CHANGED_PROPERTY = "icon";
  90. /**
  91. * Identifies a change to the icon used when the button has been
  92. * pressed.
  93. */
  94. public static final String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";
  95. /**
  96. * Identifies a change to the icon used when the button has
  97. * been selected.
  98. */
  99. public static final String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";
  100. /**
  101. * Identifies a change to the icon used when the cursor is over
  102. * the button.
  103. */
  104. public static final String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";
  105. /**
  106. * Identifies a change to the icon used when the cursor is
  107. * over the button and it has been selected.
  108. */
  109. public static final String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = "rolloverSelectedIcon";
  110. /**
  111. * Identifies a change to the icon used when the button has
  112. * been disabled.
  113. */
  114. public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";
  115. /**
  116. * Identifies a change to the icon used when the button has been
  117. * disabled and selected.
  118. */
  119. public static final String DISABLED_SELECTED_ICON_CHANGED_PROPERTY = "disabledSelectedIcon";
  120. /** The data model that determines the button's state. */
  121. protected ButtonModel model = null;
  122. private String text = ""; // for BeanBox
  123. private Insets margin = null;
  124. private Insets defaultMargin = null;
  125. // Button icons
  126. // PENDING(jeff) - hold icons in an array
  127. private Icon defaultIcon = null;
  128. private Icon pressedIcon = null;
  129. private Icon disabledIcon = null;
  130. private Icon selectedIcon = null;
  131. private Icon disabledSelectedIcon = null;
  132. private Icon rolloverIcon = null;
  133. private Icon rolloverSelectedIcon = null;
  134. // Display properties
  135. private boolean paintBorder = true;
  136. private boolean paintFocus = true;
  137. private boolean rolloverEnabled = false;
  138. private boolean contentAreaFilled = true;
  139. // Icon/Label Alignment
  140. private int verticalAlignment = CENTER;
  141. private int horizontalAlignment = CENTER;
  142. private int verticalTextPosition = CENTER;
  143. private int horizontalTextPosition = TRAILING;
  144. private int iconTextGap = 4;
  145. private int mnemonic;
  146. private int mnemonicIndex = -1;
  147. private long multiClickThreshhold = 0;
  148. private AccessibleIcon accessibleIcon = null;
  149. /**
  150. * The button model's <code>changeListener</code>.
  151. */
  152. protected ChangeListener changeListener = null;
  153. /**
  154. * The button model's <code>ActionListener</code>.
  155. */
  156. protected ActionListener actionListener = null;
  157. /**
  158. * The button model's <code>ItemListener</code>.
  159. */
  160. protected ItemListener itemListener = null;
  161. /**
  162. * Only one <code>ChangeEvent</code> is needed per button
  163. * instance since the
  164. * event's only state is the source property. The source of events
  165. * generated is always "this".
  166. */
  167. protected transient ChangeEvent changeEvent;
  168. /**
  169. * Returns the button's text.
  170. * @return the buttons text
  171. * @see #setText
  172. */
  173. public String getText() {
  174. return text;
  175. }
  176. /**
  177. * Sets the button's text.
  178. * @param text the string used to set the text
  179. * @see #getText
  180. * @beaninfo
  181. * bound: true
  182. * preferred: true
  183. * attribute: visualUpdate true
  184. * description: The button's text.
  185. */
  186. public void setText(String text) {
  187. String oldValue = this.text;
  188. this.text = text;
  189. firePropertyChange(TEXT_CHANGED_PROPERTY, oldValue, text);
  190. updateDisplayedMnemonicIndex(text, getMnemonic());
  191. if (accessibleContext != null) {
  192. accessibleContext.firePropertyChange(
  193. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  194. oldValue, text);
  195. }
  196. if (text == null || oldValue == null || !text.equals(oldValue)) {
  197. revalidate();
  198. repaint();
  199. }
  200. }
  201. /**
  202. * Returns the state of the button. True if the
  203. * toggle button is selected, false if it's not.
  204. * @return true if the toggle button is selected, otherwise false
  205. */
  206. public boolean isSelected() {
  207. return model.isSelected();
  208. }
  209. /**
  210. * Sets the state of the button. Note that this method does not
  211. * trigger an <code>actionEvent</code>.
  212. * Call <code>doClick</code> to perform a programatic action change.
  213. *
  214. * @param b true if the button is selected, otherwise false
  215. */
  216. public void setSelected(boolean b) {
  217. boolean oldValue = isSelected();
  218. if (accessibleContext != null && oldValue != b) {
  219. if (b) {
  220. accessibleContext.firePropertyChange(
  221. AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  222. null, AccessibleState.SELECTED);
  223. } else {
  224. accessibleContext.firePropertyChange(
  225. AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  226. AccessibleState.SELECTED, null);
  227. }
  228. }
  229. model.setSelected(b);
  230. }
  231. /**
  232. * Programmatically perform a "click". This does the same
  233. * thing as if the user had pressed and released the button.
  234. */
  235. public void doClick() {
  236. doClick(68);
  237. }
  238. /**
  239. * Programmatically perform a "click". This does the same
  240. * thing as if the user had pressed and released the button.
  241. * The button stays visually "pressed" for <code>pressTime</code>
  242. * milliseconds.
  243. *
  244. * @param pressTime the time to "hold down" the button, in milliseconds
  245. */
  246. public void doClick(int pressTime) {
  247. Dimension size = getSize();
  248. model.setArmed(true);
  249. model.setPressed(true);
  250. paintImmediately(new Rectangle(0,0, size.width, size.height));
  251. try {
  252. Thread.currentThread().sleep(pressTime);
  253. } catch(InterruptedException ie) {
  254. }
  255. model.setPressed(false);
  256. model.setArmed(false);
  257. }
  258. /**
  259. * Sets space for margin between the button's border and
  260. * the label. Setting to <code>null</code> will cause the button to
  261. * use the default margin. The button's default <code>Border</code>
  262. * object will use this value to create the proper margin.
  263. * However, if a non-default border is set on the button,
  264. * it is that <code>Border</code> object's responsibility to create the
  265. * appropriate margin space (else this property will
  266. * effectively be ignored).
  267. *
  268. * @param m the space between the border and the label
  269. *
  270. * @beaninfo
  271. * bound: true
  272. * attribute: visualUpdate true
  273. * description: The space between the button's border and the label.
  274. */
  275. public void setMargin(Insets m) {
  276. // Cache the old margin if it comes from the UI
  277. if(m instanceof UIResource) {
  278. defaultMargin = m;
  279. } else if(margin instanceof UIResource) {
  280. defaultMargin = margin;
  281. }
  282. // If the client passes in a null insets, restore the margin
  283. // from the UI if possible
  284. if(m == null && defaultMargin != null) {
  285. m = defaultMargin;
  286. }
  287. Insets old = margin;
  288. margin = m;
  289. firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);
  290. if (old == null || !old.equals(m)) {
  291. revalidate();
  292. repaint();
  293. }
  294. }
  295. /**
  296. * Returns the margin between the button's border and
  297. * the label.
  298. *
  299. * @return an <code>Insets</code> object specifying the margin
  300. * between the botton's border and the label
  301. * @see #setMargin
  302. */
  303. public Insets getMargin() {
  304. return (margin == null) ? null : (Insets) margin.clone();
  305. }
  306. /**
  307. * Returns the default icon.
  308. * @return the default <code>Icon</code>
  309. * @see #setIcon
  310. */
  311. public Icon getIcon() {
  312. return defaultIcon;
  313. }
  314. /**
  315. * Sets the button's default icon. This icon is
  316. * also used as the "pressed" and "disabled" icon if
  317. * there is no explicitly set pressed icon.
  318. *
  319. * @param defaultIcon the icon used as the default image
  320. * @see #getIcon
  321. * @see #setPressedIcon
  322. * @beaninfo
  323. * bound: true
  324. * attribute: visualUpdate true
  325. * description: The button's default icon
  326. */
  327. public void setIcon(Icon defaultIcon) {
  328. Icon oldValue = this.defaultIcon;
  329. this.defaultIcon = defaultIcon;
  330. /* If the default icon has really changed and we had
  331. * generated the disabled icon for this component,
  332. * (i.e. setDisabledIcon() was never called) then
  333. * clear the disabledIcon field.
  334. */
  335. if (defaultIcon != oldValue && disabledIcon instanceof UIResource) {
  336. disabledIcon = null;
  337. }
  338. firePropertyChange(ICON_CHANGED_PROPERTY, oldValue, defaultIcon);
  339. if (accessibleContext != null) {
  340. accessibleContext.firePropertyChange(
  341. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  342. oldValue, defaultIcon);
  343. }
  344. if (defaultIcon != oldValue) {
  345. if (defaultIcon == null || oldValue == null ||
  346. defaultIcon.getIconWidth() != oldValue.getIconWidth() ||
  347. defaultIcon.getIconHeight() != oldValue.getIconHeight()) {
  348. revalidate();
  349. }
  350. repaint();
  351. }
  352. // set the accessible icon
  353. accessibleIcon = null;
  354. if (defaultIcon instanceof Accessible) {
  355. AccessibleContext ac =
  356. ((Accessible)defaultIcon).getAccessibleContext();
  357. if (ac != null && ac instanceof AccessibleIcon) {
  358. accessibleIcon = (AccessibleIcon)ac;
  359. }
  360. }
  361. }
  362. /**
  363. * Returns the pressed icon for the button.
  364. * @return the <code>pressedIcon</code> property
  365. * @see #setPressedIcon
  366. */
  367. public Icon getPressedIcon() {
  368. return pressedIcon;
  369. }
  370. /**
  371. * Sets the pressed icon for the button.
  372. * @param pressedIcon the icon used as the "pressed" image
  373. * @see #getPressedIcon
  374. * @beaninfo
  375. * bound: true
  376. * attribute: visualUpdate true
  377. * description: The pressed icon for the button.
  378. */
  379. public void setPressedIcon(Icon pressedIcon) {
  380. Icon oldValue = this.pressedIcon;
  381. this.pressedIcon = pressedIcon;
  382. firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, oldValue, pressedIcon);
  383. if (accessibleContext != null) {
  384. accessibleContext.firePropertyChange(
  385. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  386. oldValue, pressedIcon);
  387. }
  388. if (pressedIcon != oldValue) {
  389. if (getModel().isPressed()) {
  390. repaint();
  391. }
  392. }
  393. }
  394. /**
  395. * Returns the selected icon for the button.
  396. * @return the <code>selectedIcon</code> property
  397. * @see #setSelectedIcon
  398. */
  399. public Icon getSelectedIcon() {
  400. return selectedIcon;
  401. }
  402. /**
  403. * Sets the selected icon for the button.
  404. * @param selectedIcon the icon used as the "selected" image
  405. * @see #getSelectedIcon
  406. * @beaninfo
  407. * bound: true
  408. * attribute: visualUpdate true
  409. * description: The selected icon for the button.
  410. */
  411. public void setSelectedIcon(Icon selectedIcon) {
  412. Icon oldValue = this.selectedIcon;
  413. this.selectedIcon = selectedIcon;
  414. /* If the default selected icon has really changed and we had
  415. * generated the disabled selected icon for this component,
  416. * (i.e. setDisabledSelectedIcon() was never called) then
  417. * clear the disabledSelectedIcon field.
  418. */
  419. if (selectedIcon != oldValue &&
  420. disabledSelectedIcon instanceof UIResource) {
  421. disabledSelectedIcon = null;
  422. }
  423. firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, oldValue, selectedIcon);
  424. if (accessibleContext != null) {
  425. accessibleContext.firePropertyChange(
  426. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  427. oldValue, selectedIcon);
  428. }
  429. if (selectedIcon != oldValue) {
  430. if (isSelected()) {
  431. repaint();
  432. }
  433. }
  434. }
  435. /**
  436. * Returns the rollover icon for the button.
  437. * @return the <code>rolloverIcon</code> property
  438. * @see #setRolloverIcon
  439. */
  440. public Icon getRolloverIcon() {
  441. return rolloverIcon;
  442. }
  443. /**
  444. * Sets the rollover icon for the button.
  445. * @param rolloverIcon the icon used as the "rollover" image
  446. * @see #getRolloverIcon
  447. * @beaninfo
  448. * bound: true
  449. * attribute: visualUpdate true
  450. * description: The rollover icon for the button.
  451. */
  452. public void setRolloverIcon(Icon rolloverIcon) {
  453. Icon oldValue = this.rolloverIcon;
  454. this.rolloverIcon = rolloverIcon;
  455. firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, oldValue, rolloverIcon);
  456. if (accessibleContext != null) {
  457. accessibleContext.firePropertyChange(
  458. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  459. oldValue, rolloverIcon);
  460. }
  461. setRolloverEnabled(true);
  462. if (rolloverIcon != oldValue) {
  463. // No way to determine whether we are currently in
  464. // a rollover state, so repaint regardless
  465. repaint();
  466. }
  467. }
  468. /**
  469. * Returns the rollover selection icon for the button.
  470. * @return the <code>rolloverSelectedIcon</code> property
  471. * @see #setRolloverSelectedIcon
  472. */
  473. public Icon getRolloverSelectedIcon() {
  474. return rolloverSelectedIcon;
  475. }
  476. /**
  477. * Sets the rollover selected icon for the button.
  478. * @param rolloverSelectedIcon the icon used as the
  479. * "selected rollover" image
  480. * @see #getRolloverSelectedIcon
  481. * @beaninfo
  482. * bound: true
  483. * attribute: visualUpdate true
  484. * description: The rollover selected icon for the button.
  485. */
  486. public void setRolloverSelectedIcon(Icon rolloverSelectedIcon) {
  487. Icon oldValue = this.rolloverSelectedIcon;
  488. this.rolloverSelectedIcon = rolloverSelectedIcon;
  489. firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, oldValue, rolloverSelectedIcon);
  490. if (accessibleContext != null) {
  491. accessibleContext.firePropertyChange(
  492. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  493. oldValue, rolloverSelectedIcon);
  494. }
  495. setRolloverEnabled(true);
  496. if (rolloverSelectedIcon != oldValue) {
  497. // No way to determine whether we are currently in
  498. // a rollover state, so repaint regardless
  499. if (isSelected()) {
  500. repaint();
  501. }
  502. }
  503. }
  504. /**
  505. * Returns the icon used by the button when it's disabled.
  506. * If no disabled icon has been set, the button constructs
  507. * one from the default icon.
  508. * <!-- PENDING(jeff): the disabled icon really should be created
  509. * (if necessary) by the L&F.-->
  510. *
  511. * @return the <code>disabledIcon</code> property
  512. * @see #getPressedIcon
  513. * @see #setDisabledIcon
  514. */
  515. public Icon getDisabledIcon() {
  516. if (disabledIcon == null) {
  517. if (defaultIcon != null && defaultIcon instanceof ImageIcon) {
  518. disabledIcon = new IconUIResource(new ImageIcon(
  519. GrayFilter.createDisabledImage(
  520. ((ImageIcon)defaultIcon).getImage())));
  521. }
  522. }
  523. return disabledIcon;
  524. }
  525. /**
  526. * Sets the disabled icon for the button.
  527. * @param disabledIcon the icon used as the disabled image
  528. * @see #getDisabledIcon
  529. * @beaninfo
  530. * bound: true
  531. * attribute: visualUpdate true
  532. * description: The disabled icon for the button.
  533. */
  534. public void setDisabledIcon(Icon disabledIcon) {
  535. Icon oldValue = this.disabledIcon;
  536. this.disabledIcon = disabledIcon;
  537. firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, oldValue, disabledIcon);
  538. if (accessibleContext != null) {
  539. accessibleContext.firePropertyChange(
  540. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  541. oldValue, disabledIcon);
  542. }
  543. if (disabledIcon != oldValue) {
  544. if (!isEnabled()) {
  545. repaint();
  546. }
  547. }
  548. }
  549. /**
  550. * Returns the icon used by the button when it's disabled and selected.
  551. * If not no disabled selection icon has been set, the button constructs
  552. * one from the selection icon.
  553. * <!-- PENDING(jeff): the disabled selection icon really should be
  554. * created (if necessary) by the L&F. -->
  555. *
  556. * @return the <code>disabledSelectedIcon</code> property
  557. * @see #getPressedIcon
  558. * @see #setDisabledIcon
  559. */
  560. public Icon getDisabledSelectedIcon() {
  561. if(disabledSelectedIcon == null) {
  562. if(selectedIcon != null && selectedIcon instanceof ImageIcon) {
  563. disabledSelectedIcon = new IconUIResource(new ImageIcon(
  564. GrayFilter.createDisabledImage(
  565. ((ImageIcon)selectedIcon).getImage())));
  566. } else {
  567. return getDisabledIcon();
  568. }
  569. }
  570. return disabledSelectedIcon;
  571. }
  572. /**
  573. * Sets the disabled selection icon for the button.
  574. * @param disabledSelectedIcon the icon used as the disabled
  575. * selection image
  576. * @see #getDisabledSelectedIcon
  577. * @beaninfo
  578. * bound: true
  579. * attribute: visualUpdate true
  580. * description: The disabled selection icon for the button.
  581. */
  582. public void setDisabledSelectedIcon(Icon disabledSelectedIcon) {
  583. Icon oldValue = this.disabledSelectedIcon;
  584. this.disabledSelectedIcon = disabledSelectedIcon;
  585. firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, oldValue, disabledSelectedIcon);
  586. if (accessibleContext != null) {
  587. accessibleContext.firePropertyChange(
  588. AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  589. oldValue, disabledSelectedIcon);
  590. }
  591. if (disabledSelectedIcon != oldValue) {
  592. if (disabledSelectedIcon == null || oldValue == null ||
  593. disabledSelectedIcon.getIconWidth() != oldValue.getIconWidth() ||
  594. disabledSelectedIcon.getIconHeight() != oldValue.getIconHeight()) {
  595. revalidate();
  596. }
  597. if (!isEnabled() && isSelected()) {
  598. repaint();
  599. }
  600. }
  601. }
  602. /**
  603. * Returns the vertical alignment of the text and icon.
  604. *
  605. * @return the <code>verticalAlignment</code> property, one of the
  606. * following values:
  607. * <ul>
  608. * <li>SwingConstants.CENTER (the default)
  609. * <li>SwingConstants.TOP
  610. * <li>SwingConstants.BOTTOM
  611. * </ul>
  612. */
  613. public int getVerticalAlignment() {
  614. return verticalAlignment;
  615. }
  616. /**
  617. * Sets the vertical alignment of the icon and text.
  618. * @param alignment one of the following values:
  619. * <ul>
  620. * <li>SwingConstants.CENTER (the default)
  621. * <li>SwingConstants.TOP
  622. * <li>SwingConstants.BOTTOM
  623. * </ul>
  624. * @beaninfo
  625. * bound: true
  626. * enum: TOP SwingConstants.TOP
  627. * CENTER SwingConstants.CENTER
  628. * BOTTOM SwingConstants.BOTTOM
  629. * attribute: visualUpdate true
  630. * description: The vertical alignment of the icon and text.
  631. */
  632. public void setVerticalAlignment(int alignment) {
  633. if (alignment == verticalAlignment) return;
  634. int oldValue = verticalAlignment;
  635. verticalAlignment = checkVerticalKey(alignment, "verticalAlignment");
  636. firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, oldValue, verticalAlignment); repaint();
  637. }
  638. /**
  639. * Returns the horizontal alignment of the icon and text.
  640. * @return the <code>horizontalAlignment</code> property,
  641. * one of the following values:
  642. * <ul>
  643. * <li>SwingConstants.RIGHT (the default)
  644. * <li>SwingConstants.LEFT
  645. * <li>SwingConstants.CENTER
  646. * <li>SwingConstants.LEADING
  647. * <li>SwingConstants.TRAILING
  648. * </ul>
  649. */
  650. public int getHorizontalAlignment() {
  651. return horizontalAlignment;
  652. }
  653. /**
  654. * Sets the horizontal alignment of the icon and text.
  655. * @param alignment one of the following values:
  656. * <ul>
  657. * <li>SwingConstants.RIGHT (the default)
  658. * <li>SwingConstants.LEFT
  659. * <li>SwingConstants.CENTER
  660. * <li>SwingConstants.LEADING
  661. * <li>SwingConstants.TRAILING
  662. * </ul>
  663. * @beaninfo
  664. * bound: true
  665. * enum: LEFT SwingConstants.LEFT
  666. * CENTER SwingConstants.CENTER
  667. * RIGHT SwingConstants.RIGHT
  668. * LEADING SwingConstants.LEADING
  669. * TRAILING SwingConstants.TRAILING
  670. * attribute: visualUpdate true
  671. * description: The horizontal alignment of the icon and text.
  672. */
  673. public void setHorizontalAlignment(int alignment) {
  674. if (alignment == horizontalAlignment) return;
  675. int oldValue = horizontalAlignment;
  676. horizontalAlignment = checkHorizontalKey(alignment,
  677. "horizontalAlignment");
  678. firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY,
  679. oldValue, horizontalAlignment);
  680. repaint();
  681. }
  682. /**
  683. * Returns the vertical position of the text relative to the icon.
  684. * @return the <code>verticalTextPosition</code> property,
  685. * one of the following values:
  686. * <ul>
  687. * <li>SwingConstants.CENTER (the default)
  688. * <li>SwingConstants.TOP
  689. * <li>SwingConstants.BOTTOM
  690. * </ul>
  691. */
  692. public int getVerticalTextPosition() {
  693. return verticalTextPosition;
  694. }
  695. /**
  696. * Sets the vertical position of the text relative to the icon.
  697. * @param textPosition one of the following values:
  698. * <ul>
  699. * <li>SwingConstants.CENTER (the default)
  700. * <li>SwingConstants.TOP
  701. * <li>SwingConstants.BOTTOM
  702. * </ul>
  703. * @beaninfo
  704. * bound: true
  705. * enum: TOP SwingConstants.TOP
  706. * CENTER SwingConstants.CENTER
  707. * BOTTOM SwingConstants.BOTTOM
  708. * attribute: visualUpdate true
  709. * description: The vertical position of the text relative to the icon.
  710. */
  711. public void setVerticalTextPosition(int textPosition) {
  712. if (textPosition == verticalTextPosition) return;
  713. int oldValue = verticalTextPosition;
  714. verticalTextPosition = checkVerticalKey(textPosition, "verticalTextPosition");
  715. firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, oldValue, verticalTextPosition);
  716. repaint();
  717. }
  718. /**
  719. * Returns the horizontal position of the text relative to the icon.
  720. * @return the <code>horizontalTextPosition</code> property,
  721. * one of the following values:
  722. * <ul>
  723. * <li>SwingConstants.RIGHT
  724. * <li>SwingConstants.LEFT
  725. * <li>SwingConstants.CENTER
  726. * <li>SwingConstants.LEADING
  727. * <li>SwingConstants.TRAILING (the default)
  728. * </ul>
  729. */
  730. public int getHorizontalTextPosition() {
  731. return horizontalTextPosition;
  732. }
  733. /**
  734. * Sets the horizontal position of the text relative to the icon.
  735. * @param textPosition one of the following values:
  736. * <ul>
  737. * <li>SwingConstants.RIGHT
  738. * <li>SwingConstants.LEFT
  739. * <li>SwingConstants.CENTER
  740. * <li>SwingConstants.LEADING
  741. * <li>SwingConstants.TRAILING (the default)
  742. * </ul>
  743. * @exception IllegalArgumentException if <code>textPosition</code>
  744. * is not one of the legal values listed above
  745. * @beaninfo
  746. * bound: true
  747. * enum: LEFT SwingConstants.LEFT
  748. * CENTER SwingConstants.CENTER
  749. * RIGHT SwingConstants.RIGHT
  750. * LEADING SwingConstants.LEADING
  751. * TRAILING SwingConstants.TRAILING
  752. * attribute: visualUpdate true
  753. * description: The horizontal position of the text relative to the icon.
  754. */
  755. public void setHorizontalTextPosition(int textPosition) {
  756. if (textPosition == horizontalTextPosition) return;
  757. int oldValue = horizontalTextPosition;
  758. horizontalTextPosition = checkHorizontalKey(textPosition,
  759. "horizontalTextPosition");
  760. firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY,
  761. oldValue,
  762. horizontalTextPosition);
  763. repaint();
  764. }
  765. /**
  766. * Returns the amount of space between the text and the icon
  767. * displayed in this button.
  768. *
  769. * @return an int equal to the number of pixels between the text
  770. * and the icon.
  771. * @since 1.4
  772. * @see #setIconTextGap
  773. */
  774. public int getIconTextGap() {
  775. return iconTextGap;
  776. }
  777. /**
  778. * If both the icon and text properties are set, this property
  779. * defines the space between them.
  780. * <p>
  781. * The default value of this property is 4 pixels.
  782. * <p>
  783. * This is a JavaBeans bound property.
  784. *
  785. * @since 1.4
  786. * @see #getIconTextGap
  787. * @beaninfo
  788. * bound: true
  789. * attribute: visualUpdate true
  790. * description: If both the icon and text properties are set, this
  791. * property defines the space between them.
  792. */
  793. public void setIconTextGap(int iconTextGap) {
  794. int oldValue = this.iconTextGap;
  795. this.iconTextGap = iconTextGap;
  796. firePropertyChange("iconTextGap", oldValue, iconTextGap);
  797. if (iconTextGap != oldValue) {
  798. revalidate();
  799. repaint();
  800. }
  801. }
  802. /**
  803. * Verify that key is a legal value for the
  804. * <code>horizontalAlignment</code> properties.
  805. *
  806. * @param key the property value to check, one of the following values:
  807. * <ul>
  808. * <li>SwingConstants.RIGHT (the default)
  809. * <li>SwingConstants.LEFT
  810. * <li>SwingConstants.CENTER
  811. * <li>SwingConstants.LEADING
  812. * <li>SwingConstants.TRAILING
  813. * </ul>
  814. * @param exception the <code>IllegalArgumentException</code>
  815. * detail message
  816. * @exception IllegalArgumentException if key is not one of the legal
  817. * values listed above
  818. * @see #setHorizontalTextPosition
  819. * @see #setHorizontalAlignment
  820. */
  821. protected int checkHorizontalKey(int key, String exception) {
  822. if ((key == LEFT) ||
  823. (key == CENTER) ||
  824. (key == RIGHT) ||
  825. (key == LEADING) ||
  826. (key == TRAILING)) {
  827. return key;
  828. } else {
  829. throw new IllegalArgumentException(exception);
  830. }
  831. }
  832. /**
  833. * Ensures that the key is a valid. Throws an
  834. * <code>IllegalArgumentException</code>
  835. * exception otherwise.
  836. *
  837. * @param key the value to check, one of the following values:
  838. * <ul>
  839. * <li>SwingConstants.CENTER (the default)
  840. * <li>SwingConstants.TOP
  841. * <li>SwingConstants.BOTTOM
  842. * </ul>
  843. * @param exception a string to be passed to the
  844. * <code>IllegalArgumentException</code> call if key
  845. * is not one of the valid values listed above
  846. * @exception IllegalArgumentException if key is not one of the legal
  847. * values listed above
  848. */
  849. protected int checkVerticalKey(int key, String exception) {
  850. if ((key == TOP) || (key == CENTER) || (key == BOTTOM)) {
  851. return key;
  852. } else {
  853. throw new IllegalArgumentException(exception);
  854. }
  855. }
  856. /**
  857. * Sets the action command for this button.
  858. * @param actionCommand the action command for this button
  859. */
  860. public void setActionCommand(String actionCommand) {
  861. getModel().setActionCommand(actionCommand);
  862. }
  863. /**
  864. * Returns the action command for this button.
  865. * @return the action command for this button
  866. */
  867. public String getActionCommand() {
  868. String ac = getModel().getActionCommand();
  869. if(ac == null) {
  870. ac = getText();
  871. }
  872. return ac;
  873. }
  874. private Action action;
  875. private PropertyChangeListener actionPropertyChangeListener;
  876. /**
  877. * Sets the <code>Action</code> for the <code>ActionEvent</code> source.
  878. * The new <code>Action</code> replaces any previously set
  879. * <code>Action</code> but does not affect <code>ActionListeners</code>
  880. * independently added with <code>addActionListener</code>.
  881. * If the <code>Action</code> is already a registered
  882. * <code>ActionListener</code> for the button, it is not re-registered.
  883. * <p>
  884. * A side-effect of setting the <code>Action</code> is that the
  885. * <code>ActionEvent</code> source's properties are immediately
  886. * set from the values in the <code>Action</code> (performed by the
  887. * method <code>configurePropertiesFromAction</code>) and
  888. * subsequently updated as the <code>Action</code>'s properties change
  889. * (via a <code>PropertyChangeListener</code> created by the method
  890. * <code>createActionPropertyChangeListener</code>.
  891. *
  892. * @param a the <code>Action</code> for the <code>AbstractButton</code>,
  893. * or <code>null</code>
  894. * @since 1.3
  895. * @see Action
  896. * @see #getAction
  897. * @see #configurePropertiesFromAction
  898. * @see #createActionPropertyChangeListener
  899. * @beaninfo
  900. * bound: true
  901. * attribute: visualUpdate true
  902. * description: the Action instance connected with this ActionEvent source
  903. */
  904. public void setAction(Action a) {
  905. Action oldValue = getAction();
  906. if (action==null || !action.equals(a)) {
  907. action = a;
  908. if (oldValue!=null) {
  909. removeActionListener(oldValue);
  910. oldValue.removePropertyChangeListener(actionPropertyChangeListener);
  911. actionPropertyChangeListener = null;
  912. }
  913. configurePropertiesFromAction(action);
  914. if (action!=null) {
  915. // Don't add if it is already a listener
  916. if (!isListener(ActionListener.class, action)) {
  917. addActionListener(action);
  918. }
  919. // Reverse linkage:
  920. actionPropertyChangeListener = createActionPropertyChangeListener(action);
  921. action.addPropertyChangeListener(actionPropertyChangeListener);
  922. }
  923. firePropertyChange("action", oldValue, action);
  924. revalidate();
  925. repaint();
  926. }
  927. }
  928. private boolean isListener(Class c, ActionListener a) {
  929. boolean isListener = false;
  930. Object[] listeners = listenerList.getListenerList();
  931. for (int i = listeners.length-2; i>=0; i-=2) {
  932. if (listeners[i]==c && listeners[i+1]==a) {
  933. isListener=true;
  934. }
  935. }
  936. return isListener;
  937. }
  938. /**
  939. * Returns the currently set <code>Action</code> for this
  940. * <code>ActionEvent</code> source, or <code>null</code>
  941. * if no <code>Action</code> is set.
  942. *
  943. * @return the <code>Action</code> for this <code>ActionEvent</code>
  944. * source, or <code>null</code>
  945. * @since 1.3
  946. * @see Action
  947. * @see #setAction
  948. */
  949. public Action getAction() {
  950. return action;
  951. }
  952. /**
  953. * Factory method which sets the <code>ActionEvent</code>
  954. * source's properties according to values from the
  955. * <code>Action</code> instance. The properties
  956. * which are set may differ for subclasses. By default,
  957. * the properties which get set are <code>Text, Icon,
  958. * Enabled, ToolTipText, ActionCommand</code>, and <code>Mnemonic</code>.
  959. * <p>
  960. * If the <code>Action</code> passed in is <code>null</code>,
  961. * the following things will occur:
  962. * <ul>
  963. * <li>the text is set to <code>null</code>,
  964. * <li>the icon is set to <code>null</code>,
  965. * <li>enabled is set to true,
  966. * <li>the tooltip text is set to <code>null</code>
  967. * </ul>
  968. *
  969. * @param a the <code>Action</code> from which to get the properties,
  970. * or <code>null</code>
  971. * @since 1.3
  972. * @see Action
  973. * @see #setAction
  974. */
  975. protected void configurePropertiesFromAction(Action a) {
  976. configurePropertiesFromAction(a, null);
  977. }
  978. /**
  979. * Configures the AbstractButton's properties according to values
  980. * from the <code>Action</code> instance. Which properties to set
  981. * is determined by the <code>types</code> parameter.
  982. * <code>types</code> may hold the following keys:
  983. * <ul>
  984. * <li><code>Action.NAME</code> - set the <code>Text</code> property
  985. * from the <code>Action</code>,
  986. * <li><code>Action.SHORT_DESCRIPTION</code> - set the
  987. * <code>ToolTipText</code> property from the <code>Action</code>,
  988. * <li><code>Action.SMALL_ICON</code> - set the <code>Icon</code> property
  989. * from the <code>Action</code>,
  990. * <li><code>Action.MNEMONIC</code> - set the <code>Mnemonic</code>
  991. * property from the <code>Action</code>,
  992. * <li><code>Action.ACTION_COMMAND_KEY</code> - set the
  993. * <code>ActionCommand</code> property from the <code>Action</code>,
  994. * <li><code>"enabled"</code> - set <code>Enabled</code> property
  995. * from the <code>Action</code>
  996. * </ul>
  997. * <p>
  998. * If the <code>Action</code> passed in is <code>null</code>,
  999. * the following things will occur:
  1000. * <ul>
  1001. * <li>the text is set to <code>null</code>,
  1002. * <li>the icon is set to <code>null</code>,
  1003. * <li>enabled is set to true,
  1004. * <li>the tooltip text is set to <code>null</code>
  1005. * <li>the mnemonic is set to <code>'\0'</code>
  1006. * </ul>
  1007. *
  1008. * @param a the <code>Action</code> from which to get the properties,
  1009. * or <code>null</code>
  1010. * @param types determines which properties to set from the
  1011. * <code>Action</code>
  1012. * @since 1.4
  1013. * @see Action
  1014. * @see #setAction
  1015. * @see #configurePropertiesFromAction(javax.swing.Action)
  1016. */
  1017. void configurePropertiesFromAction(Action a, String[] types) {
  1018. if (types == null) {
  1019. String[] alltypes = { Action.MNEMONIC_KEY, Action.NAME,
  1020. Action.SHORT_DESCRIPTION, Action.SMALL_ICON,
  1021. Action.ACTION_COMMAND_KEY, "enabled" };
  1022. types = alltypes;
  1023. }
  1024. for (int i=0; i<types.length; i++) {
  1025. String type = types[i];
  1026. if (type == null) continue;
  1027. if (type.equals(Action.MNEMONIC_KEY)) {
  1028. Integer n = (a==null) ? null : (Integer)a.getValue(type);
  1029. setMnemonic(n==null ? '\0' : n.intValue());
  1030. } else if (type.equals(Action.NAME)) {
  1031. setText(a!=null ? (String)a.getValue(type) : null);
  1032. } else if (type.equals(Action.SHORT_DESCRIPTION)) {
  1033. setToolTipText(a!=null ? (String)a.getValue(type) : null);
  1034. } else if (type.equals(Action.SMALL_ICON)) {
  1035. setIcon(a!=null ? (Icon)a.getValue(type) : null);
  1036. } else if (type.equals(Action.ACTION_COMMAND_KEY)) {
  1037. setActionCommand(a!=null? (String)a.getValue(type) : null);
  1038. } else if (type.equals("enabled")) {
  1039. setEnabled(a!=null ? a.isEnabled() : true);
  1040. }
  1041. }
  1042. }
  1043. /**
  1044. * Factory method which creates the <code>PropertyChangeListener</code>
  1045. * used to update the <code>ActionEvent</code> source as properties
  1046. * change on its <code>Action</code> instance. Subclasses may
  1047. * override this in order to provide their own
  1048. * <code>PropertyChangeListener</code> if the set of
  1049. * properties which should be kept up to date differs from the
  1050. * default properties (<code>Text, Icon, Enabled, ToolTipText,
  1051. * Mnemonic</code>).
  1052. * <p>
  1053. * Note that <code>PropertyChangeListeners</code> should avoid holding
  1054. * strong references to the <code>ActionEvent</code> source,
  1055. * as this may hinder garbage collection of the
  1056. * <code>ActionEvent</code> source and all components
  1057. * in its containment hierarchy.
  1058. *
  1059. * @param a the new action for the button
  1060. * @since 1.3
  1061. * @see Action
  1062. * @see #setAction
  1063. */
  1064. protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
  1065. return new ButtonActionPropertyChangeListener(this, a);
  1066. }
  1067. private static class ButtonActionPropertyChangeListener extends AbstractActionPropertyChangeListener {
  1068. ButtonActionPropertyChangeListener(AbstractButton b, Action a) {
  1069. super(b, a);
  1070. }
  1071. public void propertyChange(PropertyChangeEvent e) {
  1072. String propertyName = e.getPropertyName();
  1073. AbstractButton button = (AbstractButton)getTarget();
  1074. if (button == null) { //WeakRef GC'ed in 1.2
  1075. Action action = (Action)e.getSource();
  1076. action.removePropertyChangeListener(this);
  1077. } else {
  1078. if (e.getPropertyName().equals(Action.NAME)) {
  1079. Boolean hide = (Boolean)button.getClientProperty("hideActionText");
  1080. if (hide == null || hide == Boolean.FALSE) {
  1081. String text = (String) e.getNewValue();
  1082. button.setText(text);
  1083. button.repaint();
  1084. }
  1085. } else if (e.getPropertyName().equals(Action.SHORT_DESCRIPTION)) {
  1086. String text = (String) e.getNewValue();
  1087. button.setToolTipText(text);
  1088. } else if (propertyName.equals("enabled")) {
  1089. Boolean enabledState = (Boolean) e.getNewValue();
  1090. button.setEnabled(enabledState.booleanValue());
  1091. button.repaint();
  1092. } else if (e.getPropertyName().equals(Action.SMALL_ICON)) {
  1093. Icon icon = (Icon) e.getNewValue();
  1094. button.setIcon(icon);
  1095. button.invalidate();
  1096. button.repaint();
  1097. } else if (e.getPropertyName().equals(Action.MNEMONIC_KEY)) {
  1098. Integer mn = (Integer) e.getNewValue();
  1099. button.setMnemonic(mn.intValue());
  1100. button.invalidate();
  1101. button.repaint();
  1102. } else if (e.getPropertyName().equals(Action.ACTION_COMMAND_KEY)) {
  1103. button.setActionCommand((String)e.getNewValue());
  1104. }
  1105. }
  1106. }
  1107. }
  1108. /**
  1109. * Gets the <code>borderPainted</code> property.
  1110. *
  1111. * @return the value of the <code>borderPainted</code> property
  1112. * @see #setBorderPainted
  1113. */
  1114. public boolean isBorderPainted() {
  1115. return paintBorder;
  1116. }
  1117. /**
  1118. * Sets the <code>borderPainted</code> property.
  1119. * If <code>true</code> and the button has a border,
  1120. * the border is painted. The default value for the
  1121. * <code>borderPainted</code> property is <code>true</code>.
  1122. *
  1123. * @param b if true and border property is not <code>null</code>,
  1124. * the border is painted
  1125. * @see #isBorderPainted
  1126. * @beaninfo
  1127. * bound: true
  1128. * attribute: visualUpdate true
  1129. * description: Whether the border should be painted.
  1130. */
  1131. public void setBorderPainted(boolean b) {
  1132. boolean oldValue = paintBorder;
  1133. paintBorder = b;
  1134. firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, oldValue, paintBorder);
  1135. if (b != oldValue) {
  1136. revalidate();
  1137. repaint();
  1138. }
  1139. }
  1140. /**
  1141. * Paint the button's border if <code>BorderPainted</code>
  1142. * property is true and the button has a border.
  1143. * @param g the <code>Graphics</code> context in which to paint
  1144. *
  1145. * @see #paint
  1146. * @see #setBorder
  1147. */
  1148. protected void paintBorder(Graphics g) {
  1149. if (isBorderPainted()) {
  1150. super.paintBorder(g);
  1151. }
  1152. }
  1153. /**
  1154. * Gets the <code>paintFocus</code> property.
  1155. *
  1156. * @return the <code>paintFocus</code> property
  1157. * @see #setFocusPainted
  1158. */
  1159. public boolean isFocusPainted() {
  1160. return paintFocus;
  1161. }
  1162. /**
  1163. * Sets the <code>paintFocus</code> property, which must
  1164. * be <code>true</code> for the focus state to be painted.
  1165. * The default value for the <code>paintFocus</code> property
  1166. * is <code>true</code>.
  1167. * Some look and feels might not paint focus state;
  1168. * they will ignore this property.
  1169. *
  1170. * @param b if <code>true</code>, the focus state should be painted
  1171. * @see #isFocusPainted
  1172. * @beaninfo
  1173. * bound: true
  1174. * attribute: visualUpdate true
  1175. * description: Whether focus should be painted
  1176. */
  1177. public void setFocusPainted(boolean b) {
  1178. boolean oldValue = paintFocus;
  1179. paintFocus = b;
  1180. firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, oldValue, paintFocus);
  1181. if (b != oldValue && isFocusOwner()) {
  1182. revalidate();
  1183. repaint();
  1184. }
  1185. }
  1186. /**
  1187. * Gets the <code>contentAreaFilled</code> property.
  1188. *
  1189. * @return the <code>contentAreaFilled</code> property
  1190. * @see #setContentAreaFilled
  1191. */
  1192. public boolean isContentAreaFilled() {
  1193. return contentAreaFilled;
  1194. }
  1195. /**
  1196. * Sets the <code>contentAreaFilled</code> property.
  1197. * If <code>true</code> the button will paint the content
  1198. * area. If you wish to have a transparent button, such as
  1199. * an icon only button, for example, then you should set
  1200. * this to <code>false</code>. Do not call <code>setOpaque(false)</code>.
  1201. * The default value for the the <code>contentAreaFilled</code>
  1202. * property is <code>true</code>.
  1203. * <p>
  1204. * This function may cause the component's opaque property to change.
  1205. * <p>
  1206. * The exact behavior of calling this function varies on a
  1207. * component-by-component and L&F-by-L&F basis.
  1208. *
  1209. * @param b if true, the content should be filled; if false
  1210. * the content area is not filled
  1211. * @see #isContentAreaFilled
  1212. * @see #setOpaque
  1213. * @beaninfo
  1214. * bound: true
  1215. * attribute: visualUpdate true
  1216. * description: Whether the button should paint the content area
  1217. * or leave it transparent.
  1218. */
  1219. public void setContentAreaFilled(boolean b) {
  1220. boolean oldValue = contentAreaFilled;
  1221. contentAreaFilled = b;
  1222. firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, oldValue, contentAreaFilled);
  1223. if (b != oldValue) {
  1224. repaint();
  1225. }
  1226. }
  1227. /**
  1228. * Gets the <code>rolloverEnabled</code> property.
  1229. *
  1230. * @return the value of the <code>rolloverEnabled</code> property
  1231. * @see #setRolloverEnabled
  1232. */
  1233. public boolean isRolloverEnabled() {
  1234. return rolloverEnabled;
  1235. }
  1236. /**
  1237. * Sets the <code>rolloverEnabled</code> property, which
  1238. * must be <code>true</code> for rollover effects to occur.
  1239. * The default value for the <code>rolloverEnabled</code>
  1240. * property is <code>false</code>.
  1241. * Some look and feels might not implement rollover effects;
  1242. * they will ignore this property.
  1243. *
  1244. * @param b if <code>true</code>, rollover effects should be painted
  1245. * @see #isRolloverEnabled
  1246. * @beaninfo
  1247. * bound: true
  1248. * attribute: visualUpdate true
  1249. * description: Whether rollover effects should be enabled.
  1250. */
  1251. public void setRolloverEnabled(boolean b) {
  1252. boolean oldValue = rolloverEnabled;
  1253. rolloverEnabled = b;
  1254. firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, oldValue, rolloverEnabled);
  1255. if (b != oldValue) {
  1256. repaint();
  1257. }
  1258. }
  1259. /**
  1260. * Returns the keyboard mnemonic from the the current model.
  1261. * @return the keyboard mnemonic from the model
  1262. */
  1263. public int getMnemonic() {
  1264. return mnemonic;
  1265. }
  1266. /**
  1267. * Sets the keyboard mnemonic on the current model.
  1268. * The mnemonic is the key which when combined with the look and feel's
  1269. * mouseless modifier (usually Alt) will activate this button
  1270. * if focus is contained somewhere within this button's ancestor
  1271. * window.
  1272. * <p>
  1273. * A mnemonic must correspond to a single key on the keyboard
  1274. * and should be specified using one of the <code>VK_XXX</code>
  1275. * keycodes defined in <code>java.awt.event.KeyEvent</code>.
  1276. * Mnemonics are case-insensitive, therefore a key event
  1277. * with the corresponding keycode would cause the button to be
  1278. * activated whether or not the Shift modifier was pressed.
  1279. * <p>
  1280. * If the character defined by the mnemonic is found within
  1281. * the button's label string, the first occurrence of it
  1282. * will be underlined to indicate the mnemonic to the user.
  1283. *
  1284. * @param mnemonic the key code which represents the mnemonic
  1285. * @see java.awt.event.KeyEvent
  1286. * @see #setDisplayedMnemonicIndex
  1287. *
  1288. * @beaninfo
  1289. * bound: true
  1290. * attribute: visualUpdate true
  1291. * description: the keyboard character mnemonic
  1292. */
  1293. public void setMnemonic(int mnemonic) {
  1294. int oldValue = getMnemonic();
  1295. model.setMnemonic(mnemonic);
  1296. updateMnemonicProperties();
  1297. }
  1298. /**
  1299. * This method is now obsolete, please use <code>setMnemonic(int)</code>
  1300. * to set the mnemonic for a button. This method is only designed
  1301. * to handle character values which fall between 'a' and 'z' or
  1302. * 'A' and 'Z'.
  1303. *
  1304. * @param mnemonic a char specifying the mnemonic value
  1305. * @see #setMnemonic(int)
  1306. * @beaninfo
  1307. * bound: true
  1308. * attribute: visualUpdate true
  1309. * description: the keyboard character mnemonic
  1310. */
  1311. public void setMnemonic(char mnemonic) {
  1312. int vk = (int) mnemonic;
  1313. if(vk >= 'a' && vk <='z')
  1314. vk -= ('a' - 'A');
  1315. setMnemonic(vk);
  1316. }
  1317. /**
  1318. * Provides a hint to the look and feel as to which character in the
  1319. * text should be decorated to represent the mnemonic. Not all look and
  1320. * feels may support this. A value of -1 indicates either there is no
  1321. * mnemonic, the mnemonic character is not contained in the string, or
  1322. * the developer does not wish the mnemonic to be displayed.
  1323. * <p>
  1324. * The value of this is updated as the properties relating to the
  1325. * mnemonic change (such as the mnemonic itself, the text...).
  1326. * You should only ever have to call this if
  1327. * you do not wish the default character to be underlined. For example, if
  1328. * the text was 'Save As', with a mnemonic of 'a', and you wanted the 'A'
  1329. * to be decorated, as 'Save <u>A</u>s', you would have to invoke
  1330. * <code>setDisplayedMnemonicIndex(5)</code> after invoking
  1331. * <code>setMnemonic(KeyEvent.VK_A)</code>.
  1332. *
  1333. * @since 1.4
  1334. * @param index Index into the String to underline
  1335. * @exception IllegalArgumentException will be thrown if <code>index</code>
  1336. * is >= length of the text, or < -1
  1337. * @see #getDisplayedMnemonicIndex
  1338. *
  1339. * @beaninfo
  1340. * bound: true
  1341. * attribute: visualUpdate true
  1342. * description: the index into the String to draw the keyboard character
  1343. * mnemonic at
  1344. */
  1345. public void setDisplayedMnemonicIndex(int index)
  1346. throws IllegalArgumentException {
  1347. int oldValue = mnemonicIndex;
  1348. if (index == -1) {
  1349. mnemonicIndex = -1;
  1350. } else {
  1351. String text = getText();
  1352. int textLength = (text == null) ? 0 : text.length();
  1353. if (index < -1 || index >= textLength) { // index out of range
  1354. throw new IllegalArgumentException("index == " + index);
  1355. }
  1356. }
  1357. mnemonicIndex = index;
  1358. firePropertyChange("displayedMnemonicIndex", oldValue, index);
  1359. if (index != oldValue) {
  1360. revalidate();
  1361. repaint();
  1362. }
  1363. }
  1364. /**
  1365. * Returns the character, as an index, that the look and feel should
  1366. * provide decoration for as representing the mnemonic character.
  1367. *
  1368. * @since 1.4
  1369. * @return index representing mnemonic character
  1370. * @see #setDisplayedMnemonicIndex
  1371. */
  1372. public int getDisplayedMnemonicIndex() {
  1373. return mnemonicIndex;
  1374. }
  1375. /**
  1376. * Update the displayedMnemonicIndex property. This method
  1377. * is called when either text or mnemonic changes. The new
  1378. * value of the displayedMnemonicIndex property is the index
  1379. * of the first occurrence of mnemonic in text.
  1380. */
  1381. private void updateDisplayedMnemonicIndex(String text, int mnemonic) {
  1382. setDisplayedMnemonicIndex(
  1383. SwingUtilities.findDisplayedMnemonicIndex(text, mnemonic));
  1384. }
  1385. /**
  1386. * Brings the mnemonic property in accordance with model's mnemonic.
  1387. * This is called when model's mnemonic changes. Also updates the
  1388. * displayedMnemonicIndex property.
  1389. */
  1390. private void updateMnemonicProperties() {
  1391. int newMnemonic = model.getMnemonic();
  1392. if (mnemonic != newMnemonic) {
  1393. int oldValue = mnemonic;
  1394. mnemonic = newMnemonic;
  1395. firePropertyChange(MNEMONIC_CHANGED_PROPERTY,
  1396. oldValue, mnemonic);
  1397. updateDisplayedMnemonicIndex(getText(), mnemonic);
  1398. revalidate();
  1399. repaint();
  1400. }
  1401. }
  1402. /**
  1403. * Sets the amount of time (in milliseconds) required between
  1404. * mouse press events for the button to generate the corresponding
  1405. * action events. After the initial mouse press occurs (and action
  1406. * event generated) any subsequent mouse press events which occur
  1407. * on intervals less than the threshhold will be ignored and no
  1408. * corresponding action event generated. By default the threshhold is 0,
  1409. * which means that for each mouse press, an action event will be
  1410. * fired, no matter how quickly the mouse clicks occur. In buttons
  1411. * where this behavior is not desirable (for example, the "OK" button
  1412. * in a dialog), this threshhold should be set to an appropriate
  1413. * positive value.
  1414. *
  1415. * @see #getMultiClickThreshhold
  1416. * @param threshhold the amount of time required between mouse
  1417. * press events to generate corresponding action events
  1418. * @exception IllegalArgumentException if threshhold < 0
  1419. * @since 1.4
  1420. */
  1421. public void setMultiClickThreshhold(long threshhold) {
  1422. if (threshhold < 0) {
  1423. throw new IllegalArgumentException("