1. /*
  2. * @(#)Checkbox.java 1.50 01/11/29
  3. *
  4. * Copyright 2002 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.CheckboxPeer;
  9. import java.awt.event.*;
  10. import java.io.ObjectOutputStream;
  11. import java.io.ObjectInputStream;
  12. import java.io.IOException;
  13. /**
  14. * A check box is a graphical component that can be in either an
  15. * "on" (<code>true</code>) or "off" (<code>false</code>) state.
  16. * Clicking on a check box changes its state from
  17. * "on" to "off," or from "off" to "on."
  18. * <p>
  19. * The following code example creates a set of check boxes in
  20. * a grid layout:
  21. * <p>
  22. * <hr><blockquote><pre>
  23. * setLayout(new GridLayout(3, 1));
  24. * add(new Checkbox("one", null, true));
  25. * add(new Checkbox("two"));
  26. * add(new Checkbox("three"));
  27. * </pre></blockquote><hr>
  28. * <p>
  29. * This image depicts the check boxes and grid layout
  30. * created by this code example:
  31. * <p>
  32. * <img src="doc-files/Checkbox-1.gif"
  33. * ALIGN=center HSPACE=10 VSPACE=7>
  34. * <p>
  35. * The button labeled <code>one</code> is in the "on" state, and the
  36. * other two are in the "off" state. In this example, which uses the
  37. * <code>GridLayout</code> class, the states of the three check
  38. * boxes are set independently.
  39. * <p>
  40. * Alternatively, several check boxes can be grouped together under
  41. * the control of a single object, using the
  42. * <code>CheckboxGroup</code> class.
  43. * In a check box group, at most one button can be in the "on"
  44. * state at any given time. Clicking on a check box to turn it on
  45. * forces any other check box in the same group that is on
  46. * into the "off" state.
  47. *
  48. * @version 1.50 11/29/01
  49. * @author Sami Shaio
  50. * @see java.awt.GridLayout
  51. * @see java.awt.CheckboxGroup
  52. * @since JDK1.0
  53. */
  54. public class Checkbox extends Component implements ItemSelectable {
  55. static {
  56. /* ensure that the necessary native libraries are loaded */
  57. Toolkit.loadLibraries();
  58. initIDs();
  59. }
  60. /**
  61. * The label of the Checkbox.
  62. * This field can be null. If a label is not specified it
  63. * defaults to null or "".
  64. * @serial
  65. * @see getLabel()
  66. * @see setLabel()
  67. */
  68. String label;
  69. /**
  70. * The state of the Checkbox.
  71. * @serial
  72. * @see getState()
  73. * @see setLabel()
  74. */
  75. boolean state;
  76. /**
  77. * The check box group.
  78. * This field can be null indicating that the checkbox
  79. * is not a group checkbox.
  80. * @serial
  81. * @see getCheckBoxGroup()
  82. * @see setCheckBoxGroup()
  83. */
  84. CheckboxGroup group;
  85. transient ItemListener itemListener;
  86. private static final String base = "checkbox";
  87. private static int nameCounter = 0;
  88. /*
  89. * JDK 1.1 serialVersionUID
  90. */
  91. private static final long serialVersionUID = 7270714317450821763L;
  92. /**
  93. * Helper function for setState and CheckboxGroup.setSelectedCheckbox
  94. * Should remain package-private.
  95. */
  96. void setStateInternal(boolean state) {
  97. this.state = state;
  98. CheckboxPeer peer = (CheckboxPeer)this.peer;
  99. if (peer != null) {
  100. peer.setState(state);
  101. }
  102. }
  103. /**
  104. * Creates a check box with no label. The state of this
  105. * check box is set to "off," and it is not part of any
  106. * check box group.
  107. */
  108. public Checkbox() {
  109. this("", false, null);
  110. }
  111. /**
  112. * Creates a check box with the specified label. The state
  113. * of this check box is set to "off," and it is not part of
  114. * any check box group.
  115. * @param label a string label for this check box,
  116. * or <code>null</code> for no label.
  117. */
  118. public Checkbox(String label) {
  119. this(label, false, null);
  120. }
  121. /**
  122. * Creates a check box with the specified label
  123. * and sets the specified state.
  124. * This check box is not part of any check box group.
  125. * @param label a string label for this check box,
  126. * or <code>null</code> for no label.
  127. * @param state the initial state of this check box.
  128. */
  129. public Checkbox(String label, boolean state) {
  130. this(label, state, null);
  131. }
  132. /**
  133. * Creates a check box with the specified label, in the specified
  134. * check box group, and set to the specified state.
  135. * @param label a string label for this check box,
  136. * or <code>null</code> for no label.
  137. * @param state the initial state of this check box.
  138. * @param group a check box group for this check box,
  139. * or <code>null</code> for no group.
  140. * @since JDK1.1
  141. */
  142. public Checkbox(String label, boolean state, CheckboxGroup group) {
  143. this.label = label;
  144. this.state = state;
  145. this.group = group;
  146. if (state && (group != null)) {
  147. group.setSelectedCheckbox(this);
  148. }
  149. }
  150. /**
  151. * Constructs a Checkbox with the specified label, set to the
  152. * specified state, and in the specified check box group.
  153. *
  154. * @param label a string label for this check box,
  155. * or <code>null</code> for no label.
  156. * @param group a check box group for this check box,
  157. * or <code>null</code> for no group.
  158. * @param state the initial state of this check box.
  159. * @since JDK1.1
  160. */
  161. public Checkbox(String label, CheckboxGroup group, boolean state) {
  162. this(label, state, group);
  163. }
  164. /**
  165. * Construct a name for this component. Called by getName() when the
  166. * name is null.
  167. */
  168. String constructComponentName() {
  169. synchronized (getClass()) {
  170. return base + nameCounter++;
  171. }
  172. }
  173. /**
  174. * Creates the peer of the Checkbox. The peer allows you to change the
  175. * look of the Checkbox without changing its functionality.
  176. * @see java.awt.Toolkit#createCheckbox(java.awt.Checkbox)
  177. * @see java.awt.Component#getToolkit()
  178. */
  179. public void addNotify() {
  180. synchronized (getTreeLock()) {
  181. if (peer == null)
  182. peer = getToolkit().createCheckbox(this);
  183. super.addNotify();
  184. }
  185. }
  186. /**
  187. * Gets the label of this check box.
  188. * @return the label of this check box, or <code>null</code>
  189. * if this check box has no label.
  190. * @see java.awt.Checkbox#setLabel
  191. */
  192. public String getLabel() {
  193. return label;
  194. }
  195. /**
  196. * Sets this check box's label to be the string argument.
  197. * @param label a string to set as the new label, or
  198. * <code>null</code> for no label.
  199. * @see java.awt.Checkbox#getLabel
  200. */
  201. public void setLabel(String label) {
  202. boolean testvalid = false;
  203. synchronized (this) {
  204. if (label != this.label && (this.label == null ||
  205. !this.label.equals(label))) {
  206. this.label = label;
  207. CheckboxPeer peer = (CheckboxPeer)this.peer;
  208. if (peer != null) {
  209. peer.setLabel(label);
  210. }
  211. testvalid = true;
  212. }
  213. }
  214. // This could change the preferred size of the Component.
  215. if (testvalid && valid) {
  216. invalidate();
  217. }
  218. }
  219. /**
  220. * Determines whether this check box is in the "on" or "off" state.
  221. * The boolean value <code>true</code> indicates the "on" state,
  222. * and <code>false</code> indicates the "off" state.
  223. * @return the state of this check box, as a boolean value.
  224. * @see java.awt.Checkbox#setState
  225. */
  226. public boolean getState() {
  227. return state;
  228. }
  229. /**
  230. * Sets the state of this check box to the specified state.
  231. * The boolean value <code>true</code> indicates the "on" state,
  232. * and <code>false</code> indicates the "off" state.
  233. * @param state the boolean state of the check box.
  234. * @see java.awt.Checkbox#getState
  235. */
  236. public void setState(boolean state) {
  237. /* Cannot hold check box lock when calling group.setSelectedCheckbox. */
  238. CheckboxGroup group = this.group;
  239. if (group != null) {
  240. if (state) {
  241. group.setSelectedCheckbox(this);
  242. } else if (group.getSelectedCheckbox() == this) {
  243. state = true;
  244. }
  245. }
  246. setStateInternal(state);
  247. }
  248. /**
  249. * Returns an array (length 1) containing the checkbox
  250. * label or null if the checkbox is not selected.
  251. * @see ItemSelectable
  252. */
  253. public Object[] getSelectedObjects() {
  254. if (state) {
  255. Object[] items = new Object[1];
  256. items[0] = label;
  257. return items;
  258. }
  259. return null;
  260. }
  261. /**
  262. * Determines this check box's group.
  263. * @return this check box's group, or <code>null</code>
  264. * if the check box is not part of a check box group.
  265. * @see java.awt.Checkbox#setCheckboxGroup
  266. */
  267. public CheckboxGroup getCheckboxGroup() {
  268. return group;
  269. }
  270. /**
  271. * Sets this check box's group to be the specified check box group.
  272. * If this check box is already in a different check box group,
  273. * it is first taken out of that group.
  274. * @param g the new check box group, or <code>null</code>
  275. * to remove this check box from any check box group.
  276. * @see java.awt.Checkbox#getCheckboxGroup
  277. */
  278. public void setCheckboxGroup(CheckboxGroup g) {
  279. CheckboxGroup group = this.group;
  280. if (group != null) {
  281. group.setSelectedCheckbox(null);
  282. }
  283. /* Locking check box above could cause deadlock with
  284. * CheckboxGroup's setSelectedCheckbox method.
  285. */
  286. synchronized (this) {
  287. this.group = g;
  288. CheckboxPeer peer = (CheckboxPeer)this.peer;
  289. if (peer != null) {
  290. peer.setCheckboxGroup(g);
  291. }
  292. }
  293. }
  294. /**
  295. * Adds the specified item listener to receive item events from
  296. * this check box.
  297. * If l is null, no exception is thrown and no action is performed.
  298. *
  299. * @param l the item listener
  300. * @see java.awt.event.ItemEvent
  301. * @see java.awt.event.ItemListener
  302. * @see java.awt.Checkbox#removeItemListener
  303. * @since JDK1.1
  304. */
  305. public synchronized void addItemListener(ItemListener l) {
  306. if (l == null) {
  307. return;
  308. }
  309. itemListener = AWTEventMulticaster.add(itemListener, l);
  310. newEventsOnly = true;
  311. }
  312. /**
  313. * Removes the specified item listener so that the item listener
  314. * no longer receives item events from this check box.
  315. * If l is null, no exception is thrown and no action is performed.
  316. *
  317. * @param l the item listener
  318. * @see java.awt.event.ItemEvent
  319. * @see java.awt.event.ItemListener
  320. * @see java.awt.Checkbox#addItemListener
  321. * @since JDK1.1
  322. */
  323. public synchronized void removeItemListener(ItemListener l) {
  324. if (l == null) {
  325. return;
  326. }
  327. itemListener = AWTEventMulticaster.remove(itemListener, l);
  328. }
  329. // REMIND: remove when filtering is done at lower level
  330. boolean eventEnabled(AWTEvent e) {
  331. if (e.id == ItemEvent.ITEM_STATE_CHANGED) {
  332. if ((eventMask & AWTEvent.ITEM_EVENT_MASK) != 0 ||
  333. itemListener != null) {
  334. return true;
  335. }
  336. return false;
  337. }
  338. return super.eventEnabled(e);
  339. }
  340. /**
  341. * Processes events on this check box.
  342. * If the event is an instance of <code>ItemEvent</code>,
  343. * this method invokes the <code>processItemEvent</code> method.
  344. * Otherwise, it calls its superclass's <code>processEvent</code> method.
  345. * @param e the event.
  346. * @see java.awt.event.ItemEvent
  347. * @see java.awt.Checkbox#processItemEvent
  348. * @since JDK1.1
  349. */
  350. protected void processEvent(AWTEvent e) {
  351. if (e instanceof ItemEvent) {
  352. processItemEvent((ItemEvent)e);
  353. return;
  354. }
  355. super.processEvent(e);
  356. }
  357. /**
  358. * Processes item events occurring on this check box by
  359. * dispatching them to any registered
  360. * <code>ItemListener</code> objects.
  361. * <p>
  362. * This method is not called unless item events are
  363. * enabled for this component. Item events are enabled
  364. * when one of the following occurs:
  365. * <p><ul>
  366. * <li>An <code>ItemListener</code> object is registered
  367. * via <code>addItemListener</code>.
  368. * <li>Item events are enabled via <code>enableEvents</code>.
  369. * </ul>
  370. * @param e the item event.
  371. * @see java.awt.event.ItemEvent
  372. * @see java.awt.event.ItemListener
  373. * @see java.awt.Checkbox#addItemListener
  374. * @see java.awt.Component#enableEvents
  375. * @since JDK1.1
  376. */
  377. protected void processItemEvent(ItemEvent e) {
  378. if (itemListener != null) {
  379. itemListener.itemStateChanged(e);
  380. }
  381. }
  382. /**
  383. * Returns the parameter string representing the state of
  384. * this check box. This string is useful for debugging.
  385. * @return the parameter string of this check box.
  386. */
  387. protected String paramString() {
  388. String str = super.paramString();
  389. String label = this.label;
  390. if (label != null) {
  391. str += ",label=" + label;
  392. }
  393. return str + ",state=" + state;
  394. }
  395. /* Serialization support.
  396. */
  397. /*
  398. * Serialized data version
  399. * @serial
  400. */
  401. private int checkboxSerializedDataVersion = 1;
  402. /**
  403. * Writes default serializable fields to stream. Writes
  404. * a list of serializable ItemListener(s) as optional data.
  405. * The non-serializable ItemListner(s) are detected and
  406. * no attempt is made to serialize them.
  407. *
  408. * @serialData Null terminated sequence of 0 or more pairs.
  409. * The pair consists of a String and Object.
  410. * The String indicates the type of object and
  411. * is one of the following :
  412. * itemListenerK indicating and ItemListener object.
  413. *
  414. * @see AWTEventMulticaster.save(ObjectOutputStream, String, EventListener)
  415. * @see java.awt.Component.itemListenerK
  416. */
  417. private void writeObject(ObjectOutputStream s)
  418. throws java.io.IOException
  419. {
  420. s.defaultWriteObject();
  421. AWTEventMulticaster.save(s, itemListenerK, itemListener);
  422. s.writeObject(null);
  423. }
  424. /*
  425. * Read the ObjectInputStream and if it isnt null
  426. * add a listener to receive item events fired
  427. * by the Checkbox.
  428. * Unrecognised keys or values will be Ignored.
  429. * @serial
  430. * @see removeActionListener()
  431. * @see addActionListener()
  432. */
  433. private void readObject(ObjectInputStream s)
  434. throws ClassNotFoundException, IOException
  435. {
  436. s.defaultReadObject();
  437. Object keyOrNull;
  438. while(null != (keyOrNull = s.readObject())) {
  439. String key = ((String)keyOrNull).intern();
  440. if (itemListenerK == key)
  441. addItemListener((ItemListener)(s.readObject()));
  442. else // skip value for unrecognized key
  443. s.readObject();
  444. }
  445. }
  446. /**
  447. * Initialize JNI field and method ids
  448. */
  449. private static native void initIDs();
  450. }