1. /*
  2. * @(#)DefaultButtonModel.java 1.45 04/05/05
  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.io.Serializable;
  12. import java.util.EventListener;
  13. import javax.swing.event.*;
  14. /**
  15. * The default implementation of a <code>Button</code> component's data model.
  16. * <p>
  17. * <strong>Warning:</strong>
  18. * Serialized objects of this class will not be compatible with
  19. * future Swing releases. The current serialization support is
  20. * appropriate for short term storage or RMI between applications running
  21. * the same version of Swing. As of 1.4, support for long term storage
  22. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  23. * has been added to the <code>java.beans</code> package.
  24. * Please see {@link java.beans.XMLEncoder}.
  25. *
  26. * @version 1.45 05/05/04
  27. * @author Jeff Dinkins
  28. */
  29. public class DefaultButtonModel implements ButtonModel, Serializable {
  30. protected int stateMask = 0;
  31. protected String actionCommand = null;
  32. protected ButtonGroup group = null;
  33. protected int mnemonic = 0;
  34. /**
  35. * Only one <code>ChangeEvent</code> is needed per button model
  36. * instance since the
  37. * event's only state is the source property. The source of events
  38. * generated is always "this".
  39. */
  40. protected transient ChangeEvent changeEvent = null;
  41. protected EventListenerList listenerList = new EventListenerList();
  42. /**
  43. * Constructs a default <code>JButtonModel</code>.
  44. *
  45. */
  46. public DefaultButtonModel() {
  47. stateMask = 0;
  48. setEnabled(true);
  49. }
  50. /**
  51. * Indicates partial commitment towards choosing the
  52. * button.
  53. */
  54. public final static int ARMED = 1 << 0;
  55. /**
  56. * Indicates that the button has been selected. Only needed for
  57. * certain types of buttons - such as RadioButton or Checkbox.
  58. */
  59. public final static int SELECTED = 1 << 1;
  60. /**
  61. * Indicates that the button has been "pressed"
  62. * (typically, when the mouse is released).
  63. */
  64. public final static int PRESSED = 1 << 2;
  65. /**
  66. * Indicates that the button can be selected by
  67. * an input device (such as a mouse pointer).
  68. */
  69. public final static int ENABLED = 1 << 3;
  70. /**
  71. * Indicates that the mouse is over the button.
  72. */
  73. public final static int ROLLOVER = 1 << 4;
  74. /**
  75. * Sets the <code>actionCommand</code> string that gets sent as
  76. * part of the event when the button is pressed.
  77. *
  78. * @param actionCommand the <code>String</code> that identifies
  79. * the generated event
  80. */
  81. public void setActionCommand(String actionCommand) {
  82. this.actionCommand = actionCommand;
  83. }
  84. /**
  85. * Returns the action command for this button.
  86. *
  87. * @return the <code>String</code> that identifies the generated event
  88. * @see #setActionCommand
  89. */
  90. public String getActionCommand() {
  91. return actionCommand;
  92. }
  93. /**
  94. * Indicates partial commitment towards pressing the
  95. * button.
  96. *
  97. * @return true if the button is armed, and ready to be pressed
  98. * @see #setArmed
  99. */
  100. public boolean isArmed() {
  101. return (stateMask & ARMED) != 0;
  102. }
  103. /**
  104. * Indicates if the button has been selected. Only needed for
  105. * certain types of buttons - such as RadioButton or Checkbox.
  106. *
  107. * @return true if the button is selected
  108. */
  109. public boolean isSelected() {
  110. return (stateMask & SELECTED) != 0;
  111. }
  112. /**
  113. * Indicates whether the button can be selected or pressed by
  114. * an input device (such as a mouse pointer). (Checkbox-buttons
  115. * are selected, regular buttons are "pressed".)
  116. *
  117. * @return true if the button is enabled, and therefore
  118. * selectable (or pressable)
  119. */
  120. public boolean isEnabled() {
  121. return (stateMask & ENABLED) != 0;
  122. }
  123. /**
  124. * Indicates whether button has been pressed.
  125. *
  126. * @return true if the button has been pressed
  127. */
  128. public boolean isPressed() {
  129. return (stateMask & PRESSED) != 0;
  130. }
  131. /**
  132. * Indicates that the mouse is over the button.
  133. *
  134. * @return true if the mouse is over the button
  135. */
  136. public boolean isRollover() {
  137. return (stateMask & ROLLOVER) != 0;
  138. }
  139. /**
  140. * Marks the button as "armed". If the mouse button is
  141. * released while it is over this item, the button's action event
  142. * fires. If the mouse button is released elsewhere, the
  143. * event does not fire and the button is disarmed.
  144. *
  145. * @param b true to arm the button so it can be selected
  146. */
  147. public void setArmed(boolean b) {
  148. if((isArmed() == b) || !isEnabled()) {
  149. return;
  150. }
  151. if (b) {
  152. stateMask |= ARMED;
  153. } else {
  154. stateMask &= ~ARMED;
  155. }
  156. fireStateChanged();
  157. }
  158. /**
  159. * Enables or disables the button.
  160. *
  161. * @param b true to enable the button
  162. * @see #isEnabled
  163. */
  164. public void setEnabled(boolean b) {
  165. if(isEnabled() == b) {
  166. return;
  167. }
  168. if (b) {
  169. stateMask |= ENABLED;
  170. } else {
  171. stateMask &= ~ENABLED;
  172. // unarm and unpress, just in case
  173. stateMask &= ~ARMED;
  174. stateMask &= ~PRESSED;
  175. }
  176. fireStateChanged();
  177. }
  178. /**
  179. * Selects or deselects the button.
  180. *
  181. * @param b true selects the button,
  182. * false deselects the button
  183. */
  184. public void setSelected(boolean b) {
  185. if (this.isSelected() == b) {
  186. return;
  187. }
  188. if (b) {
  189. stateMask |= SELECTED;
  190. } else {
  191. stateMask &= ~SELECTED;
  192. }
  193. fireItemStateChanged(
  194. new ItemEvent(this,
  195. ItemEvent.ITEM_STATE_CHANGED,
  196. this,
  197. b ? ItemEvent.SELECTED : ItemEvent.DESELECTED));
  198. fireStateChanged();
  199. }
  200. /**
  201. * Sets the button to pressed or unpressed.
  202. *
  203. * @param b true to set the button to "pressed"
  204. * @see #isPressed
  205. */
  206. public void setPressed(boolean b) {
  207. if((isPressed() == b) || !isEnabled()) {
  208. return;
  209. }
  210. if (b) {
  211. stateMask |= PRESSED;
  212. } else {
  213. stateMask &= ~PRESSED;
  214. }
  215. if(!isPressed() && isArmed()) {
  216. int modifiers = 0;
  217. AWTEvent currentEvent = EventQueue.getCurrentEvent();
  218. if (currentEvent instanceof InputEvent) {
  219. modifiers = ((InputEvent)currentEvent).getModifiers();
  220. } else if (currentEvent instanceof ActionEvent) {
  221. modifiers = ((ActionEvent)currentEvent).getModifiers();
  222. }
  223. fireActionPerformed(
  224. new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
  225. getActionCommand(),
  226. EventQueue.getMostRecentEventTime(),
  227. modifiers));
  228. }
  229. fireStateChanged();
  230. }
  231. /**
  232. * Sets or clears the button's rollover state
  233. *
  234. * @param b true to turn on rollover
  235. * @see #isRollover
  236. */
  237. public void setRollover(boolean b) {
  238. if((isRollover() == b) || !isEnabled()) {
  239. return;
  240. }
  241. if (b) {
  242. stateMask |= ROLLOVER;
  243. } else {
  244. stateMask &= ~ROLLOVER;
  245. }
  246. fireStateChanged();
  247. }
  248. /**
  249. * Sets the keyboard mnemonic (shortcut key or
  250. * accelerator key) for this button.
  251. *
  252. * @param key an int specifying the accelerator key
  253. */
  254. public void setMnemonic(int key) {
  255. mnemonic = key;
  256. fireStateChanged();
  257. }
  258. /**
  259. * Gets the keyboard mnemonic for this model
  260. *
  261. * @return an int specifying the accelerator key
  262. * @see #setMnemonic
  263. */
  264. public int getMnemonic() {
  265. return mnemonic;
  266. }
  267. /**
  268. * Adds a <code>ChangeListener</code> to the button.
  269. *
  270. * @param l the listener to add
  271. */
  272. public void addChangeListener(ChangeListener l) {
  273. listenerList.add(ChangeListener.class, l);
  274. }
  275. /**
  276. * Removes a <code>ChangeListener</code> from the button.
  277. *
  278. * @param l the listener to remove
  279. */
  280. public void removeChangeListener(ChangeListener l) {
  281. listenerList.remove(ChangeListener.class, l);
  282. }
  283. /**
  284. * Returns an array of all the change listeners
  285. * registered on this <code>DefaultButtonModel</code>.
  286. *
  287. * @return all of this model's <code>ChangeListener</code>s
  288. * or an empty
  289. * array if no change listeners are currently registered
  290. *
  291. * @see #addChangeListener
  292. * @see #removeChangeListener
  293. *
  294. * @since 1.4
  295. */
  296. public ChangeListener[] getChangeListeners() {
  297. return (ChangeListener[])listenerList.getListeners(
  298. ChangeListener.class);
  299. }
  300. /**
  301. * Notifies all listeners that have registered interest for
  302. * notification on this event type. The event instance
  303. * is created lazily.
  304. *
  305. * @see EventListenerList
  306. */
  307. protected void fireStateChanged() {
  308. // Guaranteed to return a non-null array
  309. Object[] listeners = listenerList.getListenerList();
  310. // Process the listeners last to first, notifying
  311. // those that are interested in this event
  312. for (int i = listeners.length-2; i>=0; i-=2) {
  313. if (listeners[i]==ChangeListener.class) {
  314. // Lazily create the event:
  315. if (changeEvent == null)
  316. changeEvent = new ChangeEvent(this);
  317. ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
  318. }
  319. }
  320. }
  321. /**
  322. * Adds an <code>ActionListener</code> to the button.
  323. *
  324. * @param l the listener to add
  325. */
  326. public void addActionListener(ActionListener l) {
  327. listenerList.add(ActionListener.class, l);
  328. }
  329. /**
  330. * Removes an <code>ActionListener</code> from the button.
  331. *
  332. * @param l the listener to remove
  333. */
  334. public void removeActionListener(ActionListener l) {
  335. listenerList.remove(ActionListener.class, l);
  336. }
  337. /**
  338. * Returns an array of all the action listeners
  339. * registered on this <code>DefaultButtonModel</code>.
  340. *
  341. * @return all of this model's <code>ActionListener</code>s
  342. * or an empty
  343. * array if no action listeners are currently registered
  344. *
  345. * @see #addActionListener
  346. * @see #removeActionListener
  347. *
  348. * @since 1.4
  349. */
  350. public ActionListener[] getActionListeners() {
  351. return (ActionListener[])listenerList.getListeners(
  352. ActionListener.class);
  353. }
  354. /**
  355. * Notifies all listeners that have registered interest for
  356. * notification on this event type.
  357. *
  358. * @param e the <code>ActionEvent</code> to deliver to listeners
  359. * @see EventListenerList
  360. */
  361. protected void fireActionPerformed(ActionEvent e) {
  362. // Guaranteed to return a non-null array
  363. Object[] listeners = listenerList.getListenerList();
  364. // Process the listeners last to first, notifying
  365. // those that are interested in this event
  366. for (int i = listeners.length-2; i>=0; i-=2) {
  367. if (listeners[i]==ActionListener.class) {
  368. // Lazily create the event:
  369. // if (changeEvent == null)
  370. // changeEvent = new ChangeEvent(this);
  371. ((ActionListener)listeners[i+1]).actionPerformed(e);
  372. }
  373. }
  374. }
  375. /**
  376. * Adds an <code>ItemListener</code> to the button.
  377. *
  378. * @param l the listener to add
  379. */
  380. public void addItemListener(ItemListener l) {
  381. listenerList.add(ItemListener.class, l);
  382. }
  383. /**
  384. * Removes an <code>ItemListener</code> from the button.
  385. *
  386. * @param l the listener to remove
  387. */
  388. public void removeItemListener(ItemListener l) {
  389. listenerList.remove(ItemListener.class, l);
  390. }
  391. /**
  392. * Returns an array of all the item listeners
  393. * registered on this <code>DefaultButtonModel</code>.
  394. *
  395. * @return all of this model's <code>ItemListener</code>s
  396. * or an empty
  397. * array if no item listeners are currently registered
  398. *
  399. * @see #addItemListener
  400. * @see #removeItemListener
  401. *
  402. * @since 1.4
  403. */
  404. public ItemListener[] getItemListeners() {
  405. return (ItemListener[])listenerList.getListeners(ItemListener.class);
  406. }
  407. /**
  408. * Notifies all listeners that have registered interest for
  409. * notification on this event type.
  410. *
  411. * @param e the <code>ItemEvent</code> to deliver to listeners
  412. * @see EventListenerList
  413. */
  414. protected void fireItemStateChanged(ItemEvent e) {
  415. // Guaranteed to return a non-null array
  416. Object[] listeners = listenerList.getListenerList();
  417. // Process the listeners last to first, notifying
  418. // those that are interested in this event
  419. for (int i = listeners.length-2; i>=0; i-=2) {
  420. if (listeners[i]==ItemListener.class) {
  421. // Lazily create the event:
  422. // if (changeEvent == null)
  423. // changeEvent = new ChangeEvent(this);
  424. ((ItemListener)listeners[i+1]).itemStateChanged(e);
  425. }
  426. }
  427. }
  428. /**
  429. * Returns an array of all the objects currently registered as
  430. * <code><em>Foo</em>Listener</code>s
  431. * upon this model.
  432. * <code><em>Foo</em>Listener</code>s
  433. * are registered using the <code>add<em>Foo</em>Listener</code> method.
  434. * <p>
  435. * You can specify the <code>listenerType</code> argument
  436. * with a class literal, such as <code><em>Foo</em>Listener.class</code>.
  437. * For example, you can query a <code>DefaultButtonModel</code>
  438. * instance <code>m</code>
  439. * for its action listeners
  440. * with the following code:
  441. *
  442. * <pre>ActionListener[] als = (ActionListener[])(m.getListeners(ActionListener.class));</pre>
  443. *
  444. * If no such listeners exist,
  445. * this method returns an empty array.
  446. *
  447. * @param listenerType the type of listeners requested;
  448. * this parameter should specify an interface
  449. * that descends from <code>java.util.EventListener</code>
  450. * @return an array of all objects registered as
  451. * <code><em>Foo</em>Listener</code>s
  452. * on this model,
  453. * or an empty array if no such
  454. * listeners have been added
  455. * @exception ClassCastException if <code>listenerType</code> doesn't
  456. * specify a class or interface that implements
  457. * <code>java.util.EventListener</code>
  458. *
  459. * @see #getActionListeners
  460. * @see #getChangeListeners
  461. * @see #getItemListeners
  462. *
  463. * @since 1.3
  464. */
  465. public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
  466. return listenerList.getListeners(listenerType);
  467. }
  468. /** Overridden to return <code>null</code>. */
  469. public Object[] getSelectedObjects() {
  470. return null;
  471. }
  472. /**
  473. * Identifies the group this button belongs to --
  474. * needed for radio buttons, which are mutually
  475. * exclusive within their group.
  476. *
  477. * @param group the <code>ButtonGroup</code> this button belongs to
  478. */
  479. public void setGroup(ButtonGroup group) {
  480. this.group = group;
  481. }
  482. /**
  483. * Returns the group that this button belongs to.
  484. * Normally used with radio buttons, which are mutually
  485. * exclusive within their group.
  486. *
  487. * @return a <code>ButtonGroup</code> that this button belongs to
  488. *
  489. * @since 1.3
  490. */
  491. public ButtonGroup getGroup() {
  492. return group;
  493. }
  494. }