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