Path: blob/master/src/java.desktop/share/classes/java/awt/Checkbox.java
41152 views
/*1* Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.awt;2627import java.awt.event.ItemEvent;28import java.awt.event.ItemListener;29import java.awt.peer.CheckboxPeer;30import java.io.IOException;31import java.io.ObjectInputStream;32import java.io.ObjectOutputStream;33import java.io.Serial;34import java.util.EventListener;3536import javax.accessibility.Accessible;37import javax.accessibility.AccessibleAction;38import javax.accessibility.AccessibleContext;39import javax.accessibility.AccessibleRole;40import javax.accessibility.AccessibleState;41import javax.accessibility.AccessibleStateSet;42import javax.accessibility.AccessibleValue;4344/**45* A check box is a graphical component that can be in either an46* "on" ({@code true}) or "off" ({@code false}) state.47* Clicking on a check box changes its state from48* "on" to "off," or from "off" to "on."49* <p>50* The following code example creates a set of check boxes in51* a grid layout:52*53* <hr><blockquote><pre>54* setLayout(new GridLayout(3, 1));55* add(new Checkbox("one", null, true));56* add(new Checkbox("two"));57* add(new Checkbox("three"));58* </pre></blockquote><hr>59* <p>60* This image depicts the check boxes and grid layout61* created by this code example:62* <p>63* <img src="doc-files/Checkbox-1.gif" alt="The following context describes the64* graphic." style="margin: 7px 10px;">65* <p>66* The button labeled {@code one} is in the "on" state, and the67* other two are in the "off" state. In this example, which uses the68* {@code GridLayout} class, the states of the three check69* boxes are set independently.70* <p>71* Alternatively, several check boxes can be grouped together under72* the control of a single object, using the73* {@code CheckboxGroup} class.74* In a check box group, at most one button can be in the "on"75* state at any given time. Clicking on a check box to turn it on76* forces any other check box in the same group that is on77* into the "off" state.78*79* @author Sami Shaio80* @see java.awt.GridLayout81* @see java.awt.CheckboxGroup82* @since 1.083*/84public class Checkbox extends Component implements ItemSelectable, Accessible {8586static {87/* ensure that the necessary native libraries are loaded */88Toolkit.loadLibraries();89if (!GraphicsEnvironment.isHeadless()) {90initIDs();91}92}9394/**95* The label of the Checkbox.96* This field can be null.97* @serial98* @see #getLabel()99* @see #setLabel(String)100*/101String label;102103/**104* The state of the {@code Checkbox}.105* @serial106* @see #getState()107* @see #setState(boolean)108*/109boolean state;110111/**112* The check box group.113* This field can be null indicating that the checkbox114* is not a group checkbox.115* @serial116* @see #getCheckboxGroup()117* @see #setCheckboxGroup(CheckboxGroup)118*/119CheckboxGroup group;120121transient ItemListener itemListener;122123private static final String base = "checkbox";124private static int nameCounter = 0;125126/**127* Use serialVersionUID from JDK 1.1 for interoperability.128*/129@Serial130private static final long serialVersionUID = 7270714317450821763L;131132/**133* Helper function for setState and CheckboxGroup.setSelectedCheckbox134* Should remain package-private.135*/136void setStateInternal(boolean state) {137this.state = state;138CheckboxPeer peer = (CheckboxPeer)this.peer;139if (peer != null) {140peer.setState(state);141}142}143144/**145* Creates a check box with an empty string for its label.146* The state of this check box is set to "off," and it is not147* part of any check box group.148* @exception HeadlessException if GraphicsEnvironment.isHeadless()149* returns true150* @see java.awt.GraphicsEnvironment#isHeadless151*/152public Checkbox() throws HeadlessException {153this("", false, null);154}155156/**157* Creates a check box with the specified label. The state158* of this check box is set to "off," and it is not part of159* any check box group.160*161* @param label a string label for this check box,162* or {@code null} for no label.163* @exception HeadlessException if164* {@code GraphicsEnvironment.isHeadless}165* returns {@code true}166* @see java.awt.GraphicsEnvironment#isHeadless167*/168public Checkbox(String label) throws HeadlessException {169this(label, false, null);170}171172/**173* Creates a check box with the specified label174* and sets the specified state.175* This check box is not part of any check box group.176*177* @param label a string label for this check box,178* or {@code null} for no label179* @param state the initial state of this check box180* @exception HeadlessException if181* {@code GraphicsEnvironment.isHeadless}182* returns {@code true}183* @see java.awt.GraphicsEnvironment#isHeadless184*/185public Checkbox(String label, boolean state) throws HeadlessException {186this(label, state, null);187}188189/**190* Constructs a Checkbox with the specified label, set to the191* specified state, and in the specified check box group.192*193* @param label a string label for this check box,194* or {@code null} for no label.195* @param state the initial state of this check box.196* @param group a check box group for this check box,197* or {@code null} for no group.198* @exception HeadlessException if199* {@code GraphicsEnvironment.isHeadless}200* returns {@code true}201* @see java.awt.GraphicsEnvironment#isHeadless202* @since 1.1203*/204public Checkbox(String label, boolean state, CheckboxGroup group)205throws HeadlessException {206GraphicsEnvironment.checkHeadless();207this.label = label;208this.state = state;209this.group = group;210if (state && (group != null)) {211group.setSelectedCheckbox(this);212}213}214215/**216* Creates a check box with the specified label, in the specified217* check box group, and set to the specified state.218*219* @param label a string label for this check box,220* or {@code null} for no label.221* @param group a check box group for this check box,222* or {@code null} for no group.223* @param state the initial state of this check box.224* @exception HeadlessException if225* {@code GraphicsEnvironment.isHeadless}226* returns {@code true}227* @see java.awt.GraphicsEnvironment#isHeadless228* @since 1.1229*/230public Checkbox(String label, CheckboxGroup group, boolean state)231throws HeadlessException {232this(label, state, group);233}234235/**236* Constructs a name for this component. Called by237* {@code getName} when the name is {@code null}.238*239* @return a name for this component240*/241String constructComponentName() {242synchronized (Checkbox.class) {243return base + nameCounter++;244}245}246247/**248* Creates the peer of the Checkbox. The peer allows you to change the249* look of the Checkbox without changing its functionality.250*251* @see java.awt.Component#getToolkit()252*/253public void addNotify() {254synchronized (getTreeLock()) {255if (peer == null)256peer = getComponentFactory().createCheckbox(this);257super.addNotify();258}259}260261/**262* Gets the label of this check box.263*264* @return the label of this check box, or {@code null}265* if this check box has no label.266* @see #setLabel(String)267*/268public String getLabel() {269return label;270}271272/**273* Sets this check box's label to be the string argument.274*275* @param label a string to set as the new label, or276* {@code null} for no label.277* @see #getLabel278*/279public void setLabel(String label) {280boolean testvalid = false;281282synchronized (this) {283if (label != this.label && (this.label == null ||284!this.label.equals(label))) {285this.label = label;286CheckboxPeer peer = (CheckboxPeer)this.peer;287if (peer != null) {288peer.setLabel(label);289}290testvalid = true;291}292}293294// This could change the preferred size of the Component.295if (testvalid) {296invalidateIfValid();297}298}299300/**301* Determines whether this check box is in the "on" or "off" state.302* The boolean value {@code true} indicates the "on" state,303* and {@code false} indicates the "off" state.304*305* @return the state of this check box, as a boolean value306* @see #setState307*/308public boolean getState() {309return state;310}311312/**313* Sets the state of this check box to the specified state.314* The boolean value {@code true} indicates the "on" state,315* and {@code false} indicates the "off" state.316*317* <p>Note that this method should be primarily used to318* initialize the state of the checkbox. Programmatically319* setting the state of the checkbox will <i>not</i> trigger320* an {@code ItemEvent}. The only way to trigger an321* {@code ItemEvent} is by user interaction.322*323* @param state the boolean state of the check box324* @see #getState325*/326public void setState(boolean state) {327/* Cannot hold check box lock when calling group.setSelectedCheckbox. */328CheckboxGroup group = this.group;329if (group != null) {330if (state) {331group.setSelectedCheckbox(this);332} else if (group.getSelectedCheckbox() == this) {333state = true;334}335}336setStateInternal(state);337}338339/**340* Returns an array (length 1) containing the checkbox341* label or null if the checkbox is not selected.342* @see ItemSelectable343*/344public Object[] getSelectedObjects() {345if (state) {346Object[] items = new Object[1];347items[0] = label;348return items;349}350return null;351}352353/**354* Determines this check box's group.355* @return this check box's group, or {@code null}356* if the check box is not part of a check box group.357* @see #setCheckboxGroup(CheckboxGroup)358*/359public CheckboxGroup getCheckboxGroup() {360return group;361}362363/**364* Sets this check box's group to the specified check box group.365* If this check box is already in a different check box group,366* it is first taken out of that group.367* <p>368* If the state of this check box is {@code true} and the new369* group already has a check box selected, this check box's state370* is changed to {@code false}. If the state of this check371* box is {@code true} and the new group has no check box372* selected, this check box becomes the selected checkbox for373* the new group and its state is {@code true}.374*375* @param g the new check box group, or {@code null}376* to remove this check box from any check box group377* @see #getCheckboxGroup378*/379public void setCheckboxGroup(CheckboxGroup g) {380CheckboxGroup oldGroup;381boolean oldState;382383/* Do nothing if this check box has already belonged384* to the check box group g.385*/386if (this.group == g) {387return;388}389390synchronized (this) {391oldGroup = this.group;392oldState = getState();393394this.group = g;395CheckboxPeer peer = (CheckboxPeer)this.peer;396if (peer != null) {397peer.setCheckboxGroup(g);398}399if (this.group != null && getState()) {400if (this.group.getSelectedCheckbox() != null) {401setState(false);402} else {403this.group.setSelectedCheckbox(this);404}405}406}407408/* Locking check box below could cause deadlock with409* CheckboxGroup's setSelectedCheckbox method.410*411* Fix for 4726853 by [email protected]412* Here we should check if this check box was selected413* in the previous group and set selected check box to414* null for that group if so.415*/416if (oldGroup != null && oldState) {417oldGroup.setSelectedCheckbox(null);418}419}420421/**422* Adds the specified item listener to receive item events from423* this check box. Item events are sent to listeners in response424* to user input, but not in response to calls to setState().425* If l is null, no exception is thrown and no action is performed.426* <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"427* >AWT Threading Issues</a> for details on AWT's threading model.428*429* @param l the item listener430* @see #removeItemListener431* @see #getItemListeners432* @see #setState433* @see java.awt.event.ItemEvent434* @see java.awt.event.ItemListener435* @since 1.1436*/437public synchronized void addItemListener(ItemListener l) {438if (l == null) {439return;440}441itemListener = AWTEventMulticaster.add(itemListener, l);442newEventsOnly = true;443}444445/**446* Removes the specified item listener so that the item listener447* no longer receives item events from this check box.448* If l is null, no exception is thrown and no action is performed.449* <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"450* >AWT Threading Issues</a> for details on AWT's threading model.451*452* @param l the item listener453* @see #addItemListener454* @see #getItemListeners455* @see java.awt.event.ItemEvent456* @see java.awt.event.ItemListener457* @since 1.1458*/459public synchronized void removeItemListener(ItemListener l) {460if (l == null) {461return;462}463itemListener = AWTEventMulticaster.remove(itemListener, l);464}465466/**467* Returns an array of all the item listeners468* registered on this checkbox.469*470* @return all of this checkbox's {@code ItemListener}s471* or an empty array if no item472* listeners are currently registered473*474* @see #addItemListener475* @see #removeItemListener476* @see java.awt.event.ItemEvent477* @see java.awt.event.ItemListener478* @since 1.4479*/480public synchronized ItemListener[] getItemListeners() {481return getListeners(ItemListener.class);482}483484/**485* Returns an array of all the objects currently registered486* as <code><em>Foo</em>Listener</code>s487* upon this {@code Checkbox}.488* <code><em>Foo</em>Listener</code>s are registered using the489* <code>add<em>Foo</em>Listener</code> method.490*491* <p>492* You can specify the {@code listenerType} argument493* with a class literal, such as494* <code><em>Foo</em>Listener.class</code>.495* For example, you can query a496* {@code Checkbox c}497* for its item listeners with the following code:498*499* <pre>ItemListener[] ils = (ItemListener[])(c.getListeners(ItemListener.class));</pre>500*501* If no such listeners exist, this method returns an empty array.502*503* @param listenerType the type of listeners requested; this parameter504* should specify an interface that descends from505* {@code java.util.EventListener}506* @return an array of all objects registered as507* <code><em>Foo</em>Listener</code>s on this checkbox,508* or an empty array if no such509* listeners have been added510* @exception ClassCastException if {@code listenerType}511* doesn't specify a class or interface that implements512* {@code java.util.EventListener}513*514* @see #getItemListeners515* @since 1.3516*/517public <T extends EventListener> T[] getListeners(Class<T> listenerType) {518EventListener l = null;519if (listenerType == ItemListener.class) {520l = itemListener;521} else {522return super.getListeners(listenerType);523}524return AWTEventMulticaster.getListeners(l, listenerType);525}526527// REMIND: remove when filtering is done at lower level528boolean eventEnabled(AWTEvent e) {529if (e.id == ItemEvent.ITEM_STATE_CHANGED) {530if ((eventMask & AWTEvent.ITEM_EVENT_MASK) != 0 ||531itemListener != null) {532return true;533}534return false;535}536return super.eventEnabled(e);537}538539/**540* Processes events on this check box.541* If the event is an instance of {@code ItemEvent},542* this method invokes the {@code processItemEvent} method.543* Otherwise, it calls its superclass's {@code processEvent} method.544* <p>Note that if the event parameter is {@code null}545* the behavior is unspecified and may result in an546* exception.547*548* @param e the event549* @see java.awt.event.ItemEvent550* @see #processItemEvent551* @since 1.1552*/553protected void processEvent(AWTEvent e) {554if (e instanceof ItemEvent) {555processItemEvent((ItemEvent)e);556return;557}558super.processEvent(e);559}560561/**562* Processes item events occurring on this check box by563* dispatching them to any registered564* {@code ItemListener} objects.565* <p>566* This method is not called unless item events are567* enabled for this component. Item events are enabled568* when one of the following occurs:569* <ul>570* <li>An {@code ItemListener} object is registered571* via {@code addItemListener}.572* <li>Item events are enabled via {@code enableEvents}.573* </ul>574* <p>Note that if the event parameter is {@code null}575* the behavior is unspecified and may result in an576* exception.577*578* @param e the item event579* @see java.awt.event.ItemEvent580* @see java.awt.event.ItemListener581* @see #addItemListener582* @see java.awt.Component#enableEvents583* @since 1.1584*/585protected void processItemEvent(ItemEvent e) {586ItemListener listener = itemListener;587if (listener != null) {588listener.itemStateChanged(e);589}590}591592/**593* Returns a string representing the state of this {@code Checkbox}.594* This method is intended to be used only for debugging purposes, and the595* content and format of the returned string may vary between596* implementations. The returned string may be empty but may not be597* {@code null}.598*599* @return the parameter string of this check box600*/601protected String paramString() {602String str = super.paramString();603String label = this.label;604if (label != null) {605str += ",label=" + label;606}607return str + ",state=" + state;608}609610611/* Serialization support.612*/613614/**615* Serialized data version.616* @serial617*/618private int checkboxSerializedDataVersion = 1;619620/**621* Writes default serializable fields to stream. Writes622* a list of serializable {@code ItemListeners}623* as optional data. The non-serializable624* {@code ItemListeners} are detected and625* no attempt is made to serialize them.626*627* @param s the {@code ObjectOutputStream} to write628* @throws IOException if an I/O error occurs629* @serialData {@code null} terminated sequence of 0630* or more pairs; the pair consists of a {@code String}631* and an {@code Object}; the {@code String} indicates632* the type of object and is one of the following:633* {@code itemListenerK} indicating an634* {@code ItemListener} object635*636* @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)637* @see java.awt.Component#itemListenerK638* @see #readObject(ObjectInputStream)639*/640@Serial641private void writeObject(ObjectOutputStream s)642throws java.io.IOException643{644s.defaultWriteObject();645646AWTEventMulticaster.save(s, itemListenerK, itemListener);647s.writeObject(null);648}649650/**651* Reads the {@code ObjectInputStream} and if it652* isn't {@code null} adds a listener to receive653* item events fired by the {@code Checkbox}.654* Unrecognized keys or values will be ignored.655*656* @param s the {@code ObjectInputStream} to read657* @throws ClassNotFoundException if the class of a serialized object could658* not be found659* @throws IOException if an I/O error occurs660* @throws HeadlessException if {@code GraphicsEnvironment.isHeadless()}661* returns {@code true}662* @serial663* @see #removeItemListener(ItemListener)664* @see #addItemListener(ItemListener)665* @see java.awt.GraphicsEnvironment#isHeadless666* @see #writeObject(ObjectOutputStream)667*/668@Serial669private void readObject(ObjectInputStream s)670throws ClassNotFoundException, IOException, HeadlessException671{672GraphicsEnvironment.checkHeadless();673s.defaultReadObject();674675Object keyOrNull;676while(null != (keyOrNull = s.readObject())) {677String key = ((String)keyOrNull).intern();678679if (itemListenerK == key)680addItemListener((ItemListener)(s.readObject()));681682else // skip value for unrecognized key683s.readObject();684}685}686687/**688* Initialize JNI field and method ids689*/690private static native void initIDs();691692693/////////////////694// Accessibility support695////////////////696697698/**699* Gets the AccessibleContext associated with this Checkbox.700* For checkboxes, the AccessibleContext takes the form of an701* AccessibleAWTCheckbox.702* A new AccessibleAWTCheckbox is created if necessary.703*704* @return an AccessibleAWTCheckbox that serves as the705* AccessibleContext of this Checkbox706* @since 1.3707*/708public AccessibleContext getAccessibleContext() {709if (accessibleContext == null) {710accessibleContext = new AccessibleAWTCheckbox();711}712return accessibleContext;713}714715/**716* This class implements accessibility support for the717* {@code Checkbox} class. It provides an implementation of the718* Java Accessibility API appropriate to checkbox user-interface elements.719* @since 1.3720*/721protected class AccessibleAWTCheckbox extends AccessibleAWTComponent722implements ItemListener, AccessibleAction, AccessibleValue723{724/**725* Use serialVersionUID from JDK 1.3 for interoperability.726*/727@Serial728private static final long serialVersionUID = 7881579233144754107L;729730/**731* Constructor for {@code AccessibleAWTCheckbox}732*/733public AccessibleAWTCheckbox() {734super();735Checkbox.this.addItemListener(this);736}737738/**739* Fire accessible property change events when the state of the740* toggle button changes.741*/742public void itemStateChanged(ItemEvent e) {743Checkbox cb = (Checkbox) e.getSource();744if (Checkbox.this.accessibleContext != null) {745if (cb.getState()) {746Checkbox.this.accessibleContext.firePropertyChange(747AccessibleContext.ACCESSIBLE_STATE_PROPERTY,748null, AccessibleState.CHECKED);749} else {750Checkbox.this.accessibleContext.firePropertyChange(751AccessibleContext.ACCESSIBLE_STATE_PROPERTY,752AccessibleState.CHECKED, null);753}754}755}756757/**758* Get the AccessibleAction associated with this object. In the759* implementation of the Java Accessibility API for this class,760* return this object, which is responsible for implementing the761* AccessibleAction interface on behalf of itself.762*763* @return this object764*/765public AccessibleAction getAccessibleAction() {766return this;767}768769/**770* Get the AccessibleValue associated with this object. In the771* implementation of the Java Accessibility API for this class,772* return this object, which is responsible for implementing the773* AccessibleValue interface on behalf of itself.774*775* @return this object776*/777public AccessibleValue getAccessibleValue() {778return this;779}780781/**782* Returns the number of Actions available in this object.783* If there is more than one, the first one is the "default"784* action.785*786* @return the number of Actions in this object787*/788public int getAccessibleActionCount() {789return 0; // To be fully implemented in a future release790}791792/**793* Return a description of the specified action of the object.794*795* @param i zero-based index of the actions796*/797public String getAccessibleActionDescription(int i) {798return null; // To be fully implemented in a future release799}800801/**802* Perform the specified Action on the object803*804* @param i zero-based index of actions805* @return true if the action was performed; else false.806*/807public boolean doAccessibleAction(int i) {808return false; // To be fully implemented in a future release809}810811/**812* Get the value of this object as a Number. If the value has not been813* set, the return value will be null.814*815* @return value of the object816* @see #setCurrentAccessibleValue817*/818public Number getCurrentAccessibleValue() {819return null; // To be fully implemented in a future release820}821822/**823* Set the value of this object as a Number.824*825* @return True if the value was set; else False826* @see #getCurrentAccessibleValue827*/828public boolean setCurrentAccessibleValue(Number n) {829return false; // To be fully implemented in a future release830}831832/**833* Get the minimum value of this object as a Number.834*835* @return Minimum value of the object; null if this object does not836* have a minimum value837* @see #getMaximumAccessibleValue838*/839public Number getMinimumAccessibleValue() {840return null; // To be fully implemented in a future release841}842843/**844* Get the maximum value of this object as a Number.845*846* @return Maximum value of the object; null if this object does not847* have a maximum value848* @see #getMinimumAccessibleValue849*/850public Number getMaximumAccessibleValue() {851return null; // To be fully implemented in a future release852}853854/**855* Get the role of this object.856*857* @return an instance of AccessibleRole describing the role of858* the object859* @see AccessibleRole860*/861public AccessibleRole getAccessibleRole() {862return AccessibleRole.CHECK_BOX;863}864865/**866* Get the state set of this object.867*868* @return an instance of AccessibleState containing the current state869* of the object870* @see AccessibleState871*/872public AccessibleStateSet getAccessibleStateSet() {873AccessibleStateSet states = super.getAccessibleStateSet();874if (getState()) {875states.add(AccessibleState.CHECKED);876}877return states;878}879880881} // inner class AccessibleAWTCheckbox882883}884885886