1. /*
  2. * @(#)Checkbox.java 1.59 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.CheckboxPeer;
  12. import java.awt.event.*;
  13. import java.util.EventListener;
  14. import java.io.ObjectOutputStream;
  15. import java.io.ObjectInputStream;
  16. import java.io.IOException;
  17. import javax.accessibility.*;
  18. /**
  19. * A check box is a graphical component that can be in either an
  20. * "on" (<code>true</code>) or "off" (<code>false</code>) state.
  21. * Clicking on a check box changes its state from
  22. * "on" to "off," or from "off" to "on."
  23. * <p>
  24. * The following code example creates a set of check boxes in
  25. * a grid layout:
  26. * <p>
  27. * <hr><blockquote><pre>
  28. * setLayout(new GridLayout(3, 1));
  29. * add(new Checkbox("one", null, true));
  30. * add(new Checkbox("two"));
  31. * add(new Checkbox("three"));
  32. * </pre></blockquote><hr>
  33. * <p>
  34. * This image depicts the check boxes and grid layout
  35. * created by this code example:
  36. * <p>
  37. * <img src="doc-files/Checkbox-1.gif"
  38. * ALIGN=center HSPACE=10 VSPACE=7>
  39. * <p>
  40. * The button labeled <code>one</code> is in the "on" state, and the
  41. * other two are in the "off" state. In this example, which uses the
  42. * <code>GridLayout</code> class, the states of the three check
  43. * boxes are set independently.
  44. * <p>
  45. * Alternatively, several check boxes can be grouped together under
  46. * the control of a single object, using the
  47. * <code>CheckboxGroup</code> class.
  48. * In a check box group, at most one button can be in the "on"
  49. * state at any given time. Clicking on a check box to turn it on
  50. * forces any other check box in the same group that is on
  51. * into the "off" state.
  52. *
  53. * @version 1.59 03/14/00
  54. * @author Sami Shaio
  55. * @see java.awt.GridLayout
  56. * @see java.awt.CheckboxGroup
  57. * @since JDK1.0
  58. */
  59. public class Checkbox extends Component implements ItemSelectable, Accessible {
  60. static {
  61. /* ensure that the necessary native libraries are loaded */
  62. Toolkit.loadLibraries();
  63. initIDs();
  64. }
  65. /**
  66. * The label of the Checkbox.
  67. * This field can be null. If a label is not specified it
  68. * defaults to null or "".
  69. * @serial
  70. * @see getLabel()
  71. * @see setLabel()
  72. */
  73. String label;
  74. /**
  75. * The state of the Checkbox.
  76. * @serial
  77. * @see getState()
  78. * @see setState()
  79. */
  80. boolean state;
  81. /**
  82. * The check box group.
  83. * This field can be null indicating that the checkbox
  84. * is not a group checkbox.
  85. * @serial
  86. * @see getCheckBoxGroup()
  87. * @see setCheckBoxGroup()
  88. */
  89. CheckboxGroup group;
  90. transient ItemListener itemListener;
  91. private static final String base = "checkbox";
  92. private static int nameCounter = 0;
  93. /*
  94. * JDK 1.1 serialVersionUID
  95. */
  96. private static final long serialVersionUID = 7270714317450821763L;
  97. /**
  98. * Helper function for setState and CheckboxGroup.setSelectedCheckbox
  99. * Should remain package-private.
  100. */
  101. void setStateInternal(boolean state) {
  102. this.state = state;
  103. CheckboxPeer peer = (CheckboxPeer)this.peer;
  104. if (peer != null) {
  105. peer.setState(state);
  106. }
  107. }
  108. /**
  109. * Creates a check box with no label. The state of this
  110. * check box is set to "off," and it is not part of any
  111. * check box group.
  112. */
  113. public Checkbox() {
  114. this("", false, null);
  115. }
  116. /**
  117. * Creates a check box with the specified label. The state
  118. * of this check box is set to "off," and it is not part of
  119. * any check box group.
  120. * @param label a string label for this check box,
  121. * or <code>null</code> for no label.
  122. */
  123. public Checkbox(String label) {
  124. this(label, false, null);
  125. }
  126. /**
  127. * Creates a check box with the specified label
  128. * and sets the specified state.
  129. * This check box is not part of any check box group.
  130. * @param label a string label for this check box,
  131. * or <code>null</code> for no label.
  132. * @param state the initial state of this check box.
  133. */
  134. public Checkbox(String label, boolean state) {
  135. this(label, state, null);
  136. }
  137. /**
  138. * Creates a check box with the specified label, in the specified
  139. * check box group, and set to the specified state.
  140. * @param label a string label for this check box,
  141. * or <code>null</code> for no label.
  142. * @param state the initial state of this check box.
  143. * @param group a check box group for this check box,
  144. * or <code>null</code> for no group.
  145. * @since JDK1.1
  146. */
  147. public Checkbox(String label, boolean state, CheckboxGroup group) {
  148. this.label = label;
  149. this.state = state;
  150. this.group = group;
  151. if (state && (group != null)) {
  152. group.setSelectedCheckbox(this);
  153. }
  154. }
  155. /**
  156. * Constructs a Checkbox with the specified label, set to the
  157. * specified state, and in the specified check box group.
  158. *
  159. * @param label a string label for this check box,
  160. * or <code>null</code> for no label.
  161. * @param group a check box group for this check box,
  162. * or <code>null</code> for no group.
  163. * @param state the initial state of this check box.
  164. * @since JDK1.1
  165. */
  166. public Checkbox(String label, CheckboxGroup group, boolean state) {
  167. this(label, state, group);
  168. }
  169. /**
  170. * Construct a name for this component. Called by getName() when the
  171. * name is null.
  172. */
  173. String constructComponentName() {
  174. synchronized (getClass()) {
  175. return base + nameCounter++;
  176. }
  177. }
  178. /**
  179. * Creates the peer of the Checkbox. The peer allows you to change the
  180. * look of the Checkbox without changing its functionality.
  181. * @see java.awt.Toolkit#createCheckbox(java.awt.Checkbox)
  182. * @see java.awt.Component#getToolkit()
  183. */
  184. public void addNotify() {
  185. synchronized (getTreeLock()) {
  186. if (peer == null)
  187. peer = getToolkit().createCheckbox(this);
  188. super.addNotify();
  189. }
  190. }
  191. /**
  192. * Gets the label of this check box.
  193. * @return the label of this check box, or <code>null</code>
  194. * if this check box has no label.
  195. * @see java.awt.Checkbox#setLabel
  196. */
  197. public String getLabel() {
  198. return label;
  199. }
  200. /**
  201. * Sets this check box's label to be the string argument.
  202. * @param label a string to set as the new label, or
  203. * <code>null</code> for no label.
  204. * @see java.awt.Checkbox#getLabel
  205. */
  206. public void setLabel(String label) {
  207. boolean testvalid = false;
  208. synchronized (this) {
  209. if (label != this.label && (this.label == null ||
  210. !this.label.equals(label))) {
  211. this.label = label;
  212. CheckboxPeer peer = (CheckboxPeer)this.peer;
  213. if (peer != null) {
  214. peer.setLabel(label);
  215. }
  216. testvalid = true;
  217. }
  218. }
  219. // This could change the preferred size of the Component.
  220. if (testvalid && valid) {
  221. invalidate();
  222. }
  223. }
  224. /**
  225. * Determines whether this check box is in the "on" or "off" state.
  226. * The boolean value <code>true</code> indicates the "on" state,
  227. * and <code>false</code> indicates the "off" state.
  228. * @return the state of this check box, as a boolean value.
  229. * @see java.awt.Checkbox#setState
  230. */
  231. public boolean getState() {
  232. return state;
  233. }
  234. /**
  235. * Sets the state of this check box to the specified state.
  236. * The boolean value <code>true</code> indicates the "on" state,
  237. * and <code>false</code> indicates the "off" state.
  238. * @param state the boolean state of the check box.
  239. * @see java.awt.Checkbox#getState
  240. */
  241. public void setState(boolean state) {
  242. /* Cannot hold check box lock when calling group.setSelectedCheckbox. */
  243. CheckboxGroup group = this.group;
  244. if (group != null) {
  245. if (state) {
  246. group.setSelectedCheckbox(this);
  247. } else if (group.getSelectedCheckbox() == this) {
  248. state = true;
  249. }
  250. }
  251. setStateInternal(state);
  252. }
  253. /**
  254. * Returns an array (length 1) containing the checkbox
  255. * label or null if the checkbox is not selected.
  256. * @see ItemSelectable
  257. */
  258. public Object[] getSelectedObjects() {
  259. if (state) {
  260. Object[] items = new Object[1];
  261. items[0] = label;
  262. return items;
  263. }
  264. return null;
  265. }
  266. /**
  267. * Determines this check box's group.
  268. * @return this check box's group, or <code>null</code>
  269. * if the check box is not part of a check box group.
  270. * @see java.awt.Checkbox#setCheckboxGroup
  271. */
  272. public CheckboxGroup getCheckboxGroup() {
  273. return group;
  274. }
  275. /**
  276. * Sets this check box's group to be the specified check box group.
  277. * If this check box is already in a different check box group,
  278. * it is first taken out of that group.
  279. * @param g the new check box group, or <code>null</code>
  280. * to remove this check box from any check box group.
  281. * @see java.awt.Checkbox#getCheckboxGroup
  282. */
  283. public void setCheckboxGroup(CheckboxGroup g) {
  284. CheckboxGroup group = this.group;
  285. if (group != null) {
  286. group.setSelectedCheckbox(null);
  287. }
  288. /* Locking check box above could cause deadlock with
  289. * CheckboxGroup's setSelectedCheckbox method.
  290. */
  291. synchronized (this) {
  292. this.group = g;
  293. CheckboxPeer peer = (CheckboxPeer)this.peer;
  294. if (peer != null) {
  295. peer.setCheckboxGroup(g);
  296. }
  297. }
  298. }
  299. /**
  300. * Adds the specified item listener to receive item events from
  301. * this check box.
  302. * If l is null, no exception is thrown and no action is performed.
  303. *
  304. * @param l the item listener
  305. * @see java.awt.event.ItemEvent
  306. * @see java.awt.event.ItemListener
  307. * @see java.awt.Checkbox#removeItemListener
  308. * @since JDK1.1
  309. */
  310. public synchronized void addItemListener(ItemListener l) {
  311. if (l == null) {
  312. return;
  313. }
  314. itemListener = AWTEventMulticaster.add(itemListener, l);
  315. newEventsOnly = true;
  316. }
  317. /**
  318. * Removes the specified item listener so that the item listener
  319. * no longer receives item events from this check box.
  320. * If l is null, no exception is thrown and no action is performed.
  321. *
  322. * @param l the item listener
  323. * @see java.awt.event.ItemEvent
  324. * @see java.awt.event.ItemListener
  325. * @see java.awt.Checkbox#addItemListener
  326. * @since JDK1.1
  327. */
  328. public synchronized void removeItemListener(ItemListener l) {
  329. if (l == null) {
  330. return;
  331. }
  332. itemListener = AWTEventMulticaster.remove(itemListener, l);
  333. }
  334. /**
  335. * Return an array of all the listeners that were added to the Checkbox
  336. * with addXXXListener(), where XXX is the name of the <code>listenerType</code>
  337. * argument. For example, to get all of the ItemListener(s) for the
  338. * given Checkbox <code>c</code>, one would write:
  339. * <pre>
  340. * ItemListener[] ils = (ItemListener[])(c.getListeners(ItemListener.class))
  341. * </pre>
  342. * If no such listener list exists, then an empty array is returned.
  343. *
  344. * @param listenerType Type of listeners requested
  345. * @return all of the listeners of the specified type supported by this checkbox
  346. * @since 1.3
  347. */
  348. public EventListener[] getListeners(Class listenerType) {
  349. EventListener l = null;
  350. if (listenerType == ItemListener.class) {
  351. l = itemListener;
  352. } else {
  353. return super.getListeners(listenerType);
  354. }
  355. return AWTEventMulticaster.getListeners(l, listenerType);
  356. }
  357. // REMIND: remove when filtering is done at lower level
  358. boolean eventEnabled(AWTEvent e) {
  359. if (e.id == ItemEvent.ITEM_STATE_CHANGED) {
  360. if ((eventMask & AWTEvent.ITEM_EVENT_MASK) != 0 ||
  361. itemListener != null) {
  362. return true;
  363. }
  364. return false;
  365. }
  366. return super.eventEnabled(e);
  367. }
  368. /**
  369. * Processes events on this check box.
  370. * If the event is an instance of <code>ItemEvent</code>,
  371. * this method invokes the <code>processItemEvent</code> method.
  372. * Otherwise, it calls its superclass's <code>processEvent</code> method.
  373. * @param e the event.
  374. * @see java.awt.event.ItemEvent
  375. * @see java.awt.Checkbox#processItemEvent
  376. * @since JDK1.1
  377. */
  378. protected void processEvent(AWTEvent e) {
  379. if (e instanceof ItemEvent) {
  380. processItemEvent((ItemEvent)e);
  381. return;
  382. }
  383. super.processEvent(e);
  384. }
  385. /**
  386. * Processes item events occurring on this check box by
  387. * dispatching them to any registered
  388. * <code>ItemListener</code> objects.
  389. * <p>
  390. * This method is not called unless item events are
  391. * enabled for this component. Item events are enabled
  392. * when one of the following occurs:
  393. * <p><ul>
  394. * <li>An <code>ItemListener</code> object is registered
  395. * via <code>addItemListener</code>.
  396. * <li>Item events are enabled via <code>enableEvents</code>.
  397. * </ul>
  398. * @param e the item event.
  399. * @see java.awt.event.ItemEvent
  400. * @see java.awt.event.ItemListener
  401. * @see java.awt.Checkbox#addItemListener
  402. * @see java.awt.Component#enableEvents
  403. * @since JDK1.1
  404. */
  405. protected void processItemEvent(ItemEvent e) {
  406. if (itemListener != null) {
  407. itemListener.itemStateChanged(e);
  408. }
  409. }
  410. /**
  411. * Returns the parameter string representing the state of
  412. * this check box. This string is useful for debugging.
  413. * @return the parameter string of this check box.
  414. */
  415. protected String paramString() {
  416. String str = super.paramString();
  417. String label = this.label;
  418. if (label != null) {
  419. str += ",label=" + label;
  420. }
  421. return str + ",state=" + state;
  422. }
  423. /* Serialization support.
  424. */
  425. /*
  426. * Serialized data version
  427. * @serial
  428. */
  429. private int checkboxSerializedDataVersion = 1;
  430. /**
  431. * Writes default serializable fields to stream. Writes
  432. * a list of serializable ItemListener(s) as optional data.
  433. * The non-serializable ItemListner(s) are detected and
  434. * no attempt is made to serialize them.
  435. *
  436. * @serialData Null terminated sequence of 0 or more pairs.
  437. * The pair consists of a String and Object.
  438. * The String indicates the type of object and
  439. * is one of the following :
  440. * itemListenerK indicating and ItemListener object.
  441. *
  442. * @see AWTEventMulticaster.save(ObjectOutputStream, String, EventListener)
  443. * @see java.awt.Component.itemListenerK
  444. */
  445. private void writeObject(ObjectOutputStream s)
  446. throws java.io.IOException
  447. {
  448. s.defaultWriteObject();
  449. AWTEventMulticaster.save(s, itemListenerK, itemListener);
  450. s.writeObject(null);
  451. }
  452. /*
  453. * Read the ObjectInputStream and if it isnt null
  454. * add a listener to receive item events fired
  455. * by the Checkbox.
  456. * Unrecognised keys or values will be Ignored.
  457. * @serial
  458. * @see removeActionListener()
  459. * @see addActionListener()
  460. */
  461. private void readObject(ObjectInputStream s)
  462. throws ClassNotFoundException, IOException
  463. {
  464. s.defaultReadObject();
  465. Object keyOrNull;
  466. while(null != (keyOrNull = s.readObject())) {
  467. String key = ((String)keyOrNull).intern();
  468. if (itemListenerK == key)
  469. addItemListener((ItemListener)(s.readObject()));
  470. else // skip value for unrecognized key
  471. s.readObject();
  472. }
  473. }
  474. /**
  475. * Initialize JNI field and method ids
  476. */
  477. private static native void initIDs();
  478. /////////////////
  479. // Accessibility support
  480. ////////////////
  481. /**
  482. * Gets the AccessibleContext associated with this Checkbox.
  483. * For checkboxes, the AccessibleContext takes the form of an
  484. * AccessibleAWTCheckbox.
  485. * A new AccessibleAWTCheckbox is created if necessary.
  486. *
  487. * @return an AccessibleAWTCheckbox that serves as the
  488. * AccessibleContext of this Checkbox
  489. */
  490. public AccessibleContext getAccessibleContext() {
  491. if (accessibleContext == null) {
  492. accessibleContext = new AccessibleAWTCheckbox();
  493. }
  494. return accessibleContext;
  495. }
  496. /**
  497. * This class implements accessibility support for the
  498. * <code>Checkbox</code> class. It provides an implementation of the
  499. * Java Accessibility API appropriate to checkbox user-interface elements.
  500. */
  501. protected class AccessibleAWTCheckbox extends AccessibleAWTComponent
  502. implements ItemListener, AccessibleAction, AccessibleValue {
  503. public AccessibleAWTCheckbox() {
  504. super();
  505. Checkbox.this.addItemListener(this);
  506. }
  507. /**
  508. * Fire accessible property change events when the state of the
  509. * toggle button changes.
  510. */
  511. public void itemStateChanged(ItemEvent e) {
  512. Checkbox cb = (Checkbox) e.getSource();
  513. if (Checkbox.this.accessibleContext != null) {
  514. if (cb.getState()) {
  515. Checkbox.this.accessibleContext.firePropertyChange(
  516. AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  517. null, AccessibleState.CHECKED);
  518. } else {
  519. Checkbox.this.accessibleContext.firePropertyChange(
  520. AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  521. AccessibleState.CHECKED, null);
  522. }
  523. }
  524. }
  525. /**
  526. * Get the AccessibleAction associated with this object. In the
  527. * implementation of the Java Accessibility API for this class,
  528. * return this object, which is responsible for implementing the
  529. * AccessibleAction interface on behalf of itself.
  530. *
  531. * @return this object
  532. */
  533. public AccessibleAction getAccessibleAction() {
  534. return this;
  535. }
  536. /**
  537. * Get the AccessibleValue associated with this object. In the
  538. * implementation of the Java Accessibility API for this class,
  539. * return this object, which is responsible for implementing the
  540. * AccessibleValue interface on behalf of itself.
  541. *
  542. * @return this object
  543. */
  544. public AccessibleValue getAccessibleValue() {
  545. return this;
  546. }
  547. /**
  548. * Returns the number of Actions available in this object.
  549. * If there is more than one, the first one is the "default"
  550. * action.
  551. *
  552. * @return the number of Actions in this object
  553. */
  554. public int getAccessibleActionCount() {
  555. return 0; // To be fully implemented in a future release
  556. }
  557. /**
  558. * Return a description of the specified action of the object.
  559. *
  560. * @param i zero-based index of the actions
  561. */
  562. public String getAccessibleActionDescription(int i) {
  563. return null; // To be fully implemented in a future release
  564. }
  565. /**
  566. * Perform the specified Action on the object
  567. *
  568. * @param i zero-based index of actions
  569. * @return true if the the action was performed; else false.
  570. */
  571. public boolean doAccessibleAction(int i) {
  572. return false; // To be fully implemented in a future release
  573. }
  574. /**
  575. * Get the value of this object as a Number. If the value has not been
  576. * set, the return value will be null.
  577. *
  578. * @return value of the object
  579. * @see #setCurrentAccessibleValue
  580. */
  581. public Number getCurrentAccessibleValue() {
  582. return null; // To be fully implemented in a future release
  583. }
  584. /**
  585. * Set the value of this object as a Number.
  586. *
  587. * @return True if the value was set; else False
  588. * @see #getCurrentAccessibleValue
  589. */
  590. public boolean setCurrentAccessibleValue(Number n) {
  591. return false; // To be fully implemented in a future release
  592. }
  593. /**
  594. * Get the minimum value of this object as a Number.
  595. *
  596. * @return Minimum value of the object; null if this object does not
  597. * have a minimum value
  598. * @see #getMaximumAccessibleValue
  599. */
  600. public Number getMinimumAccessibleValue() {
  601. return null; // To be fully implemented in a future release
  602. }
  603. /**
  604. * Get the maximum value of this object as a Number.
  605. *
  606. * @return Maximum value of the object; null if this object does not
  607. * have a maximum value
  608. * @see #getMinimumAccessibleValue
  609. */
  610. public Number getMaximumAccessibleValue() {
  611. return null; // To be fully implemented in a future release
  612. }
  613. /**
  614. * Get the role of this object.
  615. *
  616. * @return an instance of AccessibleRole describing the role of
  617. * the object
  618. * @see AccessibleRole
  619. */
  620. public AccessibleRole getAccessibleRole() {
  621. return AccessibleRole.CHECK_BOX;
  622. }
  623. /**
  624. * Get the state set of this object.
  625. *
  626. * @return an instance of AccessibleState containing the current state
  627. * of the object
  628. * @see AccessibleState
  629. */
  630. public AccessibleStateSet getAccessibleStateSet() {
  631. AccessibleStateSet states = super.getAccessibleStateSet();
  632. if (getState()) {
  633. states.add(AccessibleState.CHECKED);
  634. }
  635. return states;
  636. }
  637. } // inner class AccessibleAWTCheckbox
  638. }