1. /*
  2. * @(#)Button.java 1.58 00/03/14
  3. *
  4. * Copyright 1995-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.awt;
  11. import java.awt.peer.ButtonPeer;
  12. import java.util.EventListener;
  13. import java.awt.event.*;
  14. import java.io.ObjectOutputStream;
  15. import java.io.ObjectInputStream;
  16. import java.io.IOException;
  17. import javax.accessibility.*;
  18. /**
  19. * This class creates a labeled button. The application can cause
  20. * some action to happen when the button is pushed. This image
  21. * depicts three views of a "<code>Quit</code>" button as it appears
  22. * under the Solaris operating system:
  23. * <p>
  24. * <img src="doc-files/Button-1.gif"
  25. * ALIGN=center HSPACE=10 VSPACE=7>
  26. * <p>
  27. * The first view shows the button as it appears normally.
  28. * The second view shows the button
  29. * when it has input focus. Its outline is darkened to let the
  30. * user know that it is an active object. The third view shows the
  31. * button when the user clicks the mouse over the button, and thus
  32. * requests that an action be performed.
  33. * <p>
  34. * The gesture of clicking on a button with the mouse
  35. * is associated with one instance of <code>ActionEvent</code>,
  36. * which is sent out when the mouse is both pressed and released
  37. * over the button. If an application is interested in knowing
  38. * when the button has been pressed but not released, as a separate
  39. * gesture, it can specialize <code>processMouseEvent</code>,
  40. * or it can register itself as a listener for mouse events by
  41. * calling <code>addMouseListener</code>. Both of these methods are
  42. * defined by <code>Component</code>, the abstract superclass of
  43. * all components.
  44. * <p>
  45. * When a button is pressed and released, AWT sends an instance
  46. * of <code>ActionEvent</code> to the button, by calling
  47. * <code>processEvent</code> on the button. The button's
  48. * <code>processEvent</code> method receives all events
  49. * for the button; it passes an action event along by
  50. * calling its own <code>processActionEvent</code> method.
  51. * The latter method passes the action event on to any action
  52. * listeners that have registered an interest in action
  53. * events generated by this button.
  54. * <p>
  55. * If an application wants to perform some action based on
  56. * a button being pressed and released, it should implement
  57. * <code>ActionListener</code> and register the new listener
  58. * to receive events from this button, by calling the button's
  59. * <code>addActionListener</code> method. The application can
  60. * make use of the button's action command as a messaging protocol.
  61. *
  62. * @version 1.58 03/14/00
  63. * @author Sami Shaio
  64. * @see java.awt.event.ActionEvent
  65. * @see java.awt.event.ActionListener
  66. * @see java.awt.Component#processMouseEvent
  67. * @see java.awt.Component#addMouseListener
  68. * @since JDK1.0
  69. */
  70. public class Button extends Component implements Accessible {
  71. /*
  72. * The button's Label.
  73. * If the Label is not specified it will default to "".
  74. * @serial
  75. * @see getLabel()
  76. * @see setLabel()
  77. */
  78. String label;
  79. /*
  80. * The action to be performed once a button has been
  81. * pressed.
  82. * actionCommand can be null.
  83. * @serial
  84. * @see getActionCommand()
  85. * @see setActionCommand()
  86. */
  87. String actionCommand;
  88. transient ActionListener actionListener;
  89. private static final String base = "button";
  90. private static int nameCounter = 0;
  91. /*
  92. * JDK 1.1 serialVersionUID
  93. */
  94. private static final long serialVersionUID = -8774683716313001058L;
  95. static {
  96. /* ensure that the necessary native libraries are loaded */
  97. Toolkit.loadLibraries();
  98. initIDs();
  99. }
  100. /**
  101. * Initialize JNI field and method IDs for fields that may be
  102. accessed from C.
  103. */
  104. private static native void initIDs();
  105. /**
  106. * Constructs a Button with no label.
  107. */
  108. public Button() {
  109. this("");
  110. }
  111. /**
  112. * Constructs a Button with the specified label.
  113. * @param label A string label for the button.
  114. */
  115. public Button(String label) {
  116. this.label = label;
  117. }
  118. /**
  119. * Construct a name for this component. Called by getName() when the
  120. * name is null.
  121. */
  122. String constructComponentName() {
  123. synchronized (getClass()) {
  124. return base + nameCounter++;
  125. }
  126. }
  127. /**
  128. * Creates the peer of the button. The button's peer allows the
  129. * application to change the look of the button without changing
  130. * its functionality.
  131. * @see java.awt.Toolkit#createButton(java.awt.Button)
  132. * @see java.awt.Component#getToolkit()
  133. */
  134. public void addNotify() {
  135. synchronized(getTreeLock()) {
  136. if (peer == null)
  137. peer = getToolkit().createButton(this);
  138. super.addNotify();
  139. }
  140. }
  141. /**
  142. * Gets the label of this button.
  143. * @return the button's label, or <code>null</code>
  144. * if the button has no label.
  145. * @see java.awt.Button#setLabel
  146. */
  147. public String getLabel() {
  148. return label;
  149. }
  150. /**
  151. * Sets the button's label to be the specified string.
  152. * @param label the new label, or <code>null</code>
  153. * if the button has no label.
  154. * @see java.awt.Button#getLabel
  155. */
  156. public void setLabel(String label) {
  157. boolean testvalid = false;
  158. synchronized (this) {
  159. if (label != this.label && (this.label == null ||
  160. !this.label.equals(label))) {
  161. this.label = label;
  162. ButtonPeer peer = (ButtonPeer)this.peer;
  163. if (peer != null) {
  164. peer.setLabel(label);
  165. }
  166. testvalid = true;
  167. }
  168. }
  169. // This could change the preferred size of the Component.
  170. if (testvalid && valid) {
  171. invalidate();
  172. }
  173. }
  174. /**
  175. * Sets the command name for the action event fired
  176. * by this button. By default this action command is
  177. * set to match the label of the button.
  178. * @param command A string used to set the button's
  179. * action command.
  180. * If the string is <code>null</code> then the action command
  181. * is set to match the label of the button.
  182. * @see java.awt.event.ActionEvent
  183. * @since JDK1.1
  184. */
  185. public void setActionCommand(String command) {
  186. actionCommand = command;
  187. }
  188. /**
  189. * Returns the command name of the action event fired by this button.
  190. * If the command name is <code>null</code> (default) then this method
  191. * returns the label of the button.
  192. */
  193. public String getActionCommand() {
  194. return (actionCommand == null? label : actionCommand);
  195. }
  196. /**
  197. * Adds the specified action listener to receive action events from
  198. * this button. Action events occur when a user presses or releases
  199. * the mouse over this button.
  200. * If l is null, no exception is thrown and no action is performed.
  201. *
  202. * @param l the action listener
  203. * @see java.awt.event.ActionListener
  204. * @see java.awt.Button#removeActionListener
  205. * @since JDK1.1
  206. */
  207. public synchronized void addActionListener(ActionListener l) {
  208. if (l == null) {
  209. return;
  210. }
  211. actionListener = AWTEventMulticaster.add(actionListener, l);
  212. newEventsOnly = true;
  213. }
  214. /**
  215. * Removes the specified action listener so that it no longer
  216. * receives action events from this button. Action events occur
  217. * when a user presses or releases the mouse over this button.
  218. * If l is null, no exception is thrown and no action is performed.
  219. *
  220. * @param l the action listener
  221. * @see java.awt.event.ActionListener
  222. * @see java.awt.Button#addActionListener
  223. * @since JDK1.1
  224. */
  225. public synchronized void removeActionListener(ActionListener l) {
  226. if (l == null) {
  227. return;
  228. }
  229. actionListener = AWTEventMulticaster.remove(actionListener, l);
  230. }
  231. /**
  232. * Return an array of all the listeners that were added to the Button
  233. * with addXXXListener(), where XXX is the name of the <code>listenerType</code>
  234. * argument. For example, to get all of the ActionListener(s) for the
  235. * given Button <code>b</code>, one would write:
  236. * <pre>
  237. * ActionListener[] als = (ActionListener[])(b.getListeners(ActionListener.class))
  238. * </pre>
  239. * If no such listener list exists, then an empty array is returned.
  240. *
  241. * @param listenerType Type of listeners requested
  242. * @return all of the listeners of the specified type supported by this button
  243. * @since 1.3
  244. */
  245. public EventListener[] getListeners(Class listenerType) {
  246. EventListener l = null;
  247. if (listenerType == ActionListener.class) {
  248. l = actionListener;
  249. } else {
  250. return super.getListeners(listenerType);
  251. }
  252. return AWTEventMulticaster.getListeners(l, listenerType);
  253. }
  254. // REMIND: remove when filtering is done at lower level
  255. boolean eventEnabled(AWTEvent e) {
  256. if (e.id == ActionEvent.ACTION_PERFORMED) {
  257. if ((eventMask & AWTEvent.ACTION_EVENT_MASK) != 0 ||
  258. actionListener != null) {
  259. return true;
  260. }
  261. return false;
  262. }
  263. return super.eventEnabled(e);
  264. }
  265. /**
  266. * Processes events on this button. If an event is
  267. * an instance of <code>ActionEvent</code>, this method invokes
  268. * the <code>processActionEvent</code> method. Otherwise,
  269. * it invokes <code>processEvent</code> on the superclass.
  270. * @param e the event.
  271. * @see java.awt.event.ActionEvent
  272. * @see java.awt.Button#processActionEvent
  273. * @since JDK1.1
  274. */
  275. protected void processEvent(AWTEvent e) {
  276. if (e instanceof ActionEvent) {
  277. processActionEvent((ActionEvent)e);
  278. return;
  279. }
  280. super.processEvent(e);
  281. }
  282. /**
  283. * Processes action events occurring on this button
  284. * by dispatching them to any registered
  285. * <code>ActionListener</code> objects.
  286. * <p>
  287. * This method is not called unless action events are
  288. * enabled for this button. Action events are enabled
  289. * when one of the following occurs:
  290. * <p><ul>
  291. * <li>An <code>ActionListener</code> object is registered
  292. * via <code>addActionListener</code>.
  293. * <li>Action events are enabled via <code>enableEvents</code>.
  294. * </ul>
  295. * @param e the action event.
  296. * @see java.awt.event.ActionListener
  297. * @see java.awt.Button#addActionListener
  298. * @see java.awt.Component#enableEvents
  299. * @since JDK1.1
  300. */
  301. protected void processActionEvent(ActionEvent e) {
  302. if (actionListener != null) {
  303. actionListener.actionPerformed(e);
  304. }
  305. }
  306. /**
  307. * Returns the parameter string representing the state of this
  308. * button. This string is useful for debugging.
  309. * @return the parameter string of this button.
  310. */
  311. protected String paramString() {
  312. return super.paramString() + ",label=" + label;
  313. }
  314. /* Serialization support.
  315. */
  316. /*
  317. * Button Serial Data Version.
  318. * @serial
  319. */
  320. private int buttonSerializedDataVersion = 1;
  321. /**
  322. * Writes default serializable fields to stream. Writes
  323. * a list of serializable ItemListener(s) as optional data.
  324. * The non-serializable ItemListener(s) are detected and
  325. * no attempt is made to serialize them.
  326. *
  327. * @serialData Null terminated sequence of 0 or more pairs.
  328. * The pair consists of a String and Object.
  329. * The String indicates the type of object and
  330. * is one of the following :
  331. * itemListenerK indicating and ItemListener object.
  332. *
  333. * @see AWTEventMulticaster.save(ObjectOutputStream, String, EventListener)
  334. * @see java.awt.Component.itemListenerK
  335. */
  336. private void writeObject(ObjectOutputStream s)
  337. throws IOException
  338. {
  339. s.defaultWriteObject();
  340. AWTEventMulticaster.save(s, actionListenerK, actionListener);
  341. s.writeObject(null);
  342. }
  343. /*
  344. * Read the ObjectInputStream and if it isnt null
  345. * add a listener to receive item events fired
  346. * by the button.
  347. * Unrecognised keys or values will be Ignored.
  348. * @serial
  349. * @see removeActionListener()
  350. * @see addActionListener()
  351. */
  352. private void readObject(ObjectInputStream s)
  353. throws ClassNotFoundException, IOException
  354. {
  355. s.defaultReadObject();
  356. Object keyOrNull;
  357. while(null != (keyOrNull = s.readObject())) {
  358. String key = ((String)keyOrNull).intern();
  359. if (actionListenerK == key)
  360. addActionListener((ActionListener)(s.readObject()));
  361. else // skip value for unrecognized key
  362. s.readObject();
  363. }
  364. }
  365. /////////////////
  366. // Accessibility support
  367. ////////////////
  368. /**
  369. * Gets the AccessibleContext associated with this Button.
  370. * For buttons, the AccessibleContext takes the form of an
  371. * AccessibleAWTButton.
  372. * A new AccessibleAWTButton instance is created if necessary.
  373. *
  374. * @return an AccessibleAWTButton that serves as the
  375. * AccessibleContext of this Button
  376. * @beaninfo
  377. * expert: true
  378. * description: The AccessibleContext associated with this Button.
  379. */
  380. public AccessibleContext getAccessibleContext() {
  381. if (accessibleContext == null) {
  382. accessibleContext = new AccessibleAWTButton();
  383. }
  384. return accessibleContext;
  385. }
  386. /**
  387. * This class implements accessibility support for the
  388. * <code>Button</code> class. It provides an implementation of the
  389. * Java Accessibility API appropriate to button user-interface elements.
  390. */
  391. protected class AccessibleAWTButton extends AccessibleAWTComponent
  392. implements AccessibleAction, AccessibleValue {
  393. /**
  394. * Get the accessible name of this object.
  395. *
  396. * @return the localized name of the object -- can be null if this
  397. * object does not have a name
  398. */
  399. public String getAccessibleName() {
  400. if (accessibleName != null) {
  401. return accessibleName;
  402. } else {
  403. if (getLabel() == null) {
  404. return super.getAccessibleName();
  405. } else {
  406. return getLabel();
  407. }
  408. }
  409. }
  410. /**
  411. * Get the AccessibleAction associated with this object. In the
  412. * implementation of the Java Accessibility API for this class,
  413. * return this object, which is responsible for implementing the
  414. * AccessibleAction interface on behalf of itself.
  415. *
  416. * @return this object
  417. */
  418. public AccessibleAction getAccessibleAction() {
  419. return this;
  420. }
  421. /**
  422. * Get the AccessibleValue associated with this object. In the
  423. * implementation of the Java Accessibility API for this class,
  424. * return this object, which is responsible for implementing the
  425. * AccessibleValue interface on behalf of itself.
  426. *
  427. * @return this object
  428. */
  429. public AccessibleValue getAccessibleValue() {
  430. return this;
  431. }
  432. /**
  433. * Returns the number of Actions available in this object. The
  434. * default behavior of a button is to have one action - toggle
  435. * the button.
  436. *
  437. * @return 1, the number of Actions in this object
  438. */
  439. public int getAccessibleActionCount() {
  440. return 1;
  441. }
  442. /**
  443. * Return a description of the specified action of the object.
  444. *
  445. * @param i zero-based index of the actions
  446. */
  447. public String getAccessibleActionDescription(int i) {
  448. if (i == 0) {
  449. // [[[PENDING: WDW -- need to provide a localized string]]]
  450. return new String("click");
  451. } else {
  452. return null;
  453. }
  454. }
  455. /**
  456. * Perform the specified Action on the object
  457. *
  458. * @param i zero-based index of actions
  459. * @return true if the the action was performed; else false.
  460. */
  461. public boolean doAccessibleAction(int i) {
  462. if (i == 0) {
  463. // Simulate a button click
  464. Toolkit.getEventQueue().postEvent(
  465. new ActionEvent(Button.this,
  466. ActionEvent.ACTION_PERFORMED,
  467. Button.this.getActionCommand()));
  468. return true;
  469. } else {
  470. return false;
  471. }
  472. }
  473. /**
  474. * Get the value of this object as a Number.
  475. *
  476. * @return An Integer of 0 if this isn't selected or an Integer of 1 if
  477. * this is selected.
  478. * @see AbstractButton#isSelected
  479. */
  480. public Number getCurrentAccessibleValue() {
  481. return new Integer(0);
  482. }
  483. /**
  484. * Set the value of this object as a Number.
  485. *
  486. * @return True if the value was set.
  487. */
  488. public boolean setCurrentAccessibleValue(Number n) {
  489. return false;
  490. }
  491. /**
  492. * Get the minimum value of this object as a Number.
  493. *
  494. * @return An Integer of 0.
  495. */
  496. public Number getMinimumAccessibleValue() {
  497. return new Integer(0);
  498. }
  499. /**
  500. * Get the maximum value of this object as a Number.
  501. *
  502. * @return An Integer of 0.
  503. */
  504. public Number getMaximumAccessibleValue() {
  505. return new Integer(0);
  506. }
  507. /**
  508. * Get the role of this object.
  509. *
  510. * @return an instance of AccessibleRole describing the role of the
  511. * object
  512. * @see AccessibleRole
  513. */
  514. public AccessibleRole getAccessibleRole() {
  515. return AccessibleRole.PUSH_BUTTON;
  516. }
  517. } // inner class AccessibleAWTButton
  518. }