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