1 /*
2  * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package java.awt;
27 
28 import java.awt.event.ActionListener;
29 import java.awt.event.ItemEvent;
30 import java.awt.event.ItemListener;
31 import java.awt.peer.CheckboxMenuItemPeer;
32 import java.io.IOException;
33 import java.io.ObjectInputStream;
34 import java.io.ObjectOutputStream;
35 import java.util.EventListener;
36 
37 import javax.accessibility.Accessible;
38 import javax.accessibility.AccessibleAction;
39 import javax.accessibility.AccessibleContext;
40 import javax.accessibility.AccessibleRole;
41 import javax.accessibility.AccessibleValue;
42 
43 import sun.awt.AWTAccessor;
44 
45 /**
46  * This class represents a check box that can be included in a menu.
47  * Selecting the check box in the menu changes its state from
48  * "on" to "off" or from "off" to "on."
49  * <p>
50  * The following picture depicts a menu which contains an instance
51  * of {@code CheckBoxMenuItem}:
52  * <p>
53  * <img src="doc-files/MenuBar-1.gif"
54  * alt="Menu labeled Examples, containing items Basic, Simple, Check, and More
55  * Examples. The Check item is a CheckBoxMenuItem instance, in the off state."
56  * style="margin: 7px 10px;">
57  * <p>
58  * The item labeled {@code Check} shows a check box menu item
59  * in its "off" state.
60  * <p>
61  * When a check box menu item is selected, AWT sends an item event to
62  * the item. Since the event is an instance of {@code ItemEvent},
63  * the {@code processEvent} method examines the event and passes
64  * it along to {@code processItemEvent}. The latter method redirects
65  * the event to any {@code ItemListener} objects that have
66  * registered an interest in item events generated by this menu item.
67  *
68  * @author      Sami Shaio
69  * @see         java.awt.event.ItemEvent
70  * @see         java.awt.event.ItemListener
71  * @since       1.0
72  */
73 public class CheckboxMenuItem extends MenuItem implements ItemSelectable, Accessible {
74 
75     static {
76         /* ensure that the necessary native libraries are loaded */
Toolkit.loadLibraries()77         Toolkit.loadLibraries();
78         if (!GraphicsEnvironment.isHeadless()) {
initIDs()79             initIDs();
80         }
81 
AWTAccessor.setCheckboxMenuItemAccessor( new AWTAccessor.CheckboxMenuItemAccessor() { public boolean getState(CheckboxMenuItem cmi) { return cmi.state; } })82         AWTAccessor.setCheckboxMenuItemAccessor(
83             new AWTAccessor.CheckboxMenuItemAccessor() {
84                 public boolean getState(CheckboxMenuItem cmi) {
85                     return cmi.state;
86                 }
87             });
88     }
89 
90    /**
91     * The state of a checkbox menu item
92     * @serial
93     * @see #getState()
94     * @see #setState(boolean)
95     */
96     private volatile boolean state;
97 
98     private transient volatile ItemListener itemListener;
99 
100     private static final String base = "chkmenuitem";
101     private static int nameCounter = 0;
102 
103     /*
104      * JDK 1.1 serialVersionUID
105      */
106      private static final long serialVersionUID = 6190621106981774043L;
107 
108     /**
109      * Create a check box menu item with an empty label.
110      * The item's state is initially set to "off."
111      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
112      * returns true
113      * @see java.awt.GraphicsEnvironment#isHeadless
114      * @since   1.1
115      */
CheckboxMenuItem()116     public CheckboxMenuItem() throws HeadlessException {
117         this("", false);
118     }
119 
120     /**
121      * Create a check box menu item with the specified label.
122      * The item's state is initially set to "off."
123 
124      * @param     label   a string label for the check box menu item,
125      *                or {@code null} for an unlabeled menu item.
126      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
127      * returns true
128      * @see java.awt.GraphicsEnvironment#isHeadless
129      */
CheckboxMenuItem(String label)130     public CheckboxMenuItem(String label) throws HeadlessException {
131         this(label, false);
132     }
133 
134     /**
135      * Create a check box menu item with the specified label and state.
136      * @param      label   a string label for the check box menu item,
137      *                     or {@code null} for an unlabeled menu item.
138      * @param      state   the initial state of the menu item, where
139      *                     {@code true} indicates "on" and
140      *                     {@code false} indicates "off."
141      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
142      * returns true
143      * @see java.awt.GraphicsEnvironment#isHeadless
144      * @since      1.1
145      */
CheckboxMenuItem(String label, boolean state)146     public CheckboxMenuItem(String label, boolean state)
147         throws HeadlessException {
148         super(label);
149         this.state = state;
150     }
151 
152     /**
153      * Construct a name for this MenuComponent.  Called by getName() when
154      * the name is null.
155      */
constructComponentName()156     String constructComponentName() {
157         synchronized (CheckboxMenuItem.class) {
158             return base + nameCounter++;
159         }
160     }
161 
162     /**
163      * Creates the peer of the checkbox item.  This peer allows us to
164      * change the look of the checkbox item without changing its
165      * functionality.
166      * Most applications do not call this method directly.
167      * @see     java.awt.Component#getToolkit()
168      */
addNotify()169     public void addNotify() {
170         synchronized (getTreeLock()) {
171             if (peer == null)
172                 peer = getComponentFactory().createCheckboxMenuItem(this);
173             super.addNotify();
174         }
175     }
176 
177     /**
178      * Determines whether the state of this check box menu item
179      * is "on" or "off."
180      *
181      * @return      the state of this check box menu item, where
182      *                     {@code true} indicates "on" and
183      *                     {@code false} indicates "off"
184      * @see        #setState
185      */
getState()186     public boolean getState() {
187         return state;
188     }
189 
190     /**
191      * Sets this check box menu item to the specified state.
192      * The boolean value {@code true} indicates "on" while
193      * {@code false} indicates "off."
194      *
195      * <p>Note that this method should be primarily used to
196      * initialize the state of the check box menu item.
197      * Programmatically setting the state of the check box
198      * menu item will <i>not</i> trigger
199      * an {@code ItemEvent}.  The only way to trigger an
200      * {@code ItemEvent} is by user interaction.
201      *
202      * @param      b   {@code true} if the check box
203      *             menu item is on, otherwise {@code false}
204      * @see        #getState
205      */
setState(boolean b)206     public synchronized void setState(boolean b) {
207         state = b;
208         CheckboxMenuItemPeer peer = (CheckboxMenuItemPeer)this.peer;
209         if (peer != null) {
210             peer.setState(b);
211         }
212     }
213 
214     /**
215      * Returns the an array (length 1) containing the checkbox menu item
216      * label or null if the checkbox is not selected.
217      * @see ItemSelectable
218      */
getSelectedObjects()219     public synchronized Object[] getSelectedObjects() {
220         if (state) {
221             Object[] items = new Object[1];
222             items[0] = label;
223             return items;
224         }
225         return null;
226     }
227 
228     /**
229      * Adds the specified item listener to receive item events from
230      * this check box menu item.  Item events are sent in response to user
231      * actions, but not in response to calls to setState().
232      * If l is null, no exception is thrown and no action is performed.
233      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
234      * >AWT Threading Issues</a> for details on AWT's threading model.
235      *
236      * @param         l the item listener
237      * @see           #removeItemListener
238      * @see           #getItemListeners
239      * @see           #setState
240      * @see           java.awt.event.ItemEvent
241      * @see           java.awt.event.ItemListener
242      * @since         1.1
243      */
addItemListener(ItemListener l)244     public synchronized void addItemListener(ItemListener l) {
245         if (l == null) {
246             return;
247         }
248         itemListener = AWTEventMulticaster.add(itemListener, l);
249         newEventsOnly = true;
250     }
251 
252     /**
253      * Removes the specified item listener so that it no longer receives
254      * item events from this check box menu item.
255      * If l is null, no exception is thrown and no action is performed.
256      * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
257      * >AWT Threading Issues</a> for details on AWT's threading model.
258      *
259      * @param         l the item listener
260      * @see           #addItemListener
261      * @see           #getItemListeners
262      * @see           java.awt.event.ItemEvent
263      * @see           java.awt.event.ItemListener
264      * @since         1.1
265      */
removeItemListener(ItemListener l)266     public synchronized void removeItemListener(ItemListener l) {
267         if (l == null) {
268             return;
269         }
270         itemListener = AWTEventMulticaster.remove(itemListener, l);
271     }
272 
273     /**
274      * Returns an array of all the item listeners
275      * registered on this checkbox menuitem.
276      *
277      * @return all of this checkbox menuitem's {@code ItemListener}s
278      *         or an empty array if no item
279      *         listeners are currently registered
280      *
281      * @see           #addItemListener
282      * @see           #removeItemListener
283      * @see           java.awt.event.ItemEvent
284      * @see           java.awt.event.ItemListener
285      * @since 1.4
286      */
getItemListeners()287     public synchronized ItemListener[] getItemListeners() {
288         return getListeners(ItemListener.class);
289     }
290 
291     /**
292      * Returns an array of all the objects currently registered
293      * as <code><em>Foo</em>Listener</code>s
294      * upon this {@code CheckboxMenuItem}.
295      * <code><em>Foo</em>Listener</code>s are registered using the
296      * <code>add<em>Foo</em>Listener</code> method.
297      *
298      * <p>
299      * You can specify the {@code listenerType} argument
300      * with a class literal, such as
301      * <code><em>Foo</em>Listener.class</code>.
302      * For example, you can query a
303      * {@code CheckboxMenuItem c}
304      * for its item listeners with the following code:
305      *
306      * <pre>ItemListener[] ils = (ItemListener[])(c.getListeners(ItemListener.class));</pre>
307      *
308      * If no such listeners exist, this method returns an empty array.
309      *
310      * @param listenerType the type of listeners requested; this parameter
311      *          should specify an interface that descends from
312      *          {@code java.util.EventListener}
313      * @return an array of all objects registered as
314      *          <code><em>Foo</em>Listener</code>s on this checkbox menuitem,
315      *          or an empty array if no such
316      *          listeners have been added
317      * @exception ClassCastException if {@code listenerType}
318      *          doesn't specify a class or interface that implements
319      *          {@code java.util.EventListener}
320      *
321      * @see #getItemListeners
322      * @since 1.3
323      */
getListeners(Class<T> listenerType)324     public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
325         EventListener l = null;
326         if  (listenerType == ItemListener.class) {
327             l = itemListener;
328         } else {
329             return super.getListeners(listenerType);
330         }
331         return AWTEventMulticaster.getListeners(l, listenerType);
332     }
333 
334     // REMIND: remove when filtering is done at lower level
eventEnabled(AWTEvent e)335     boolean eventEnabled(AWTEvent e) {
336         if (e.id == ItemEvent.ITEM_STATE_CHANGED) {
337             if ((eventMask & AWTEvent.ITEM_EVENT_MASK) != 0 ||
338                 itemListener != null) {
339                 return true;
340             }
341             return false;
342         }
343         return super.eventEnabled(e);
344     }
345 
346     /**
347      * Processes events on this check box menu item.
348      * If the event is an instance of {@code ItemEvent},
349      * this method invokes the {@code processItemEvent} method.
350      * If the event is not an item event,
351      * it invokes {@code processEvent} on the superclass.
352      * <p>
353      * Check box menu items currently support only item events.
354      * <p>Note that if the event parameter is {@code null}
355      * the behavior is unspecified and may result in an
356      * exception.
357      *
358      * @param        e the event
359      * @see          java.awt.event.ItemEvent
360      * @see          #processItemEvent
361      * @since        1.1
362      */
processEvent(AWTEvent e)363     protected void processEvent(AWTEvent e) {
364         if (e instanceof ItemEvent) {
365             processItemEvent((ItemEvent)e);
366             return;
367         }
368         super.processEvent(e);
369     }
370 
371     /**
372      * Processes item events occurring on this check box menu item by
373      * dispatching them to any registered {@code ItemListener} objects.
374      * <p>
375      * This method is not called unless item events are
376      * enabled for this menu item. Item events are enabled
377      * when one of the following occurs:
378      * <ul>
379      * <li>An {@code ItemListener} object is registered
380      * via {@code addItemListener}.
381      * <li>Item events are enabled via {@code enableEvents}.
382      * </ul>
383      * <p>Note that if the event parameter is {@code null}
384      * the behavior is unspecified and may result in an
385      * exception.
386      *
387      * @param       e the item event
388      * @see         java.awt.event.ItemEvent
389      * @see         java.awt.event.ItemListener
390      * @see         #addItemListener
391      * @see         java.awt.MenuItem#enableEvents
392      * @since       1.1
393      */
processItemEvent(ItemEvent e)394     protected void processItemEvent(ItemEvent e) {
395         ItemListener listener = itemListener;
396         if (listener != null) {
397             listener.itemStateChanged(e);
398         }
399     }
400 
401     /*
402      * Post an ItemEvent and toggle state.
403      */
doMenuEvent(long when, int modifiers)404     void doMenuEvent(long when, int modifiers) {
405         setState(!state);
406         Toolkit.getEventQueue().postEvent(
407             new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
408                           getLabel(),
409                           state ? ItemEvent.SELECTED :
410                                   ItemEvent.DESELECTED));
411     }
412 
413     /**
414      * Returns a string representing the state of this
415      * {@code CheckBoxMenuItem}. This
416      * method is intended to be used only for debugging purposes, and the
417      * content and format of the returned string may vary between
418      * implementations. The returned string may be empty but may not be
419      * {@code null}.
420      *
421      * @return     the parameter string of this check box menu item
422      */
paramString()423     public String paramString() {
424         return super.paramString() + ",state=" + state;
425     }
426 
427     /* Serialization support.
428      */
429 
430     /**
431      * Serialized data version.
432      * @serial
433      */
434     private int checkboxMenuItemSerializedDataVersion = 1;
435 
436     /**
437      * Writes default serializable fields to stream.  Writes
438      * a list of serializable {@code ItemListeners}
439      * as optional data.  The non-serializable
440      * {@code ItemListeners} are detected and
441      * no attempt is made to serialize them.
442      *
443      * @param  s the {@code ObjectOutputStream} to write
444      * @throws IOException if an I/O error occurs
445      * @serialData {@code null} terminated sequence of
446      *  0 or more pairs; the pair consists of a {@code String}
447      *  and an {@code Object}; the {@code String} indicates
448      *  the type of object and is one of the following:
449      *  {@code itemListenerK} indicating an
450      *    {@code ItemListener} object
451      *
452      * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
453      * @see java.awt.Component#itemListenerK
454      * @see #readObject(ObjectInputStream)
455      */
writeObject(ObjectOutputStream s)456     private void writeObject(ObjectOutputStream s)
457       throws java.io.IOException
458     {
459       s.defaultWriteObject();
460 
461       AWTEventMulticaster.save(s, itemListenerK, itemListener);
462       s.writeObject(null);
463     }
464 
465     /**
466      * Reads the {@code ObjectInputStream} and if it
467      * isn't {@code null} adds a listener to receive
468      * item events fired by the {@code Checkbox} menu item.
469      * Unrecognized keys or values will be ignored.
470      *
471      * @param  s the {@code ObjectInputStream} to read
472      * @throws ClassNotFoundException if the class of a serialized object could
473      *         not be found
474      * @throws IOException if an I/O error occurs
475      * @serial
476      * @see #removeActionListener(ActionListener)
477      * @see #addActionListener(ActionListener)
478      * @see #writeObject(ObjectOutputStream)
479      */
readObject(ObjectInputStream s)480     private void readObject(ObjectInputStream s)
481       throws ClassNotFoundException, IOException
482     {
483       s.defaultReadObject();
484 
485       Object keyOrNull;
486       while(null != (keyOrNull = s.readObject())) {
487         String key = ((String)keyOrNull).intern();
488 
489         if (itemListenerK == key)
490           addItemListener((ItemListener)(s.readObject()));
491 
492         else // skip value for unrecognized key
493           s.readObject();
494       }
495     }
496 
497     /**
498      * Initialize JNI field and method IDs
499      */
initIDs()500     private static native void initIDs();
501 
502 
503 /////////////////
504 // Accessibility support
505 ////////////////
506 
507     /**
508      * Gets the AccessibleContext associated with this CheckboxMenuItem.
509      * For checkbox menu items, the AccessibleContext takes the
510      * form of an AccessibleAWTCheckboxMenuItem.
511      * A new AccessibleAWTCheckboxMenuItem is created if necessary.
512      *
513      * @return an AccessibleAWTCheckboxMenuItem that serves as the
514      *         AccessibleContext of this CheckboxMenuItem
515      * @since 1.3
516      */
getAccessibleContext()517     public AccessibleContext getAccessibleContext() {
518         if (accessibleContext == null) {
519             accessibleContext = new AccessibleAWTCheckboxMenuItem();
520         }
521         return accessibleContext;
522     }
523 
524     /**
525      * Inner class of CheckboxMenuItem used to provide default support for
526      * accessibility.  This class is not meant to be used directly by
527      * application developers, but is instead meant only to be
528      * subclassed by menu component developers.
529      * <p>
530      * This class implements accessibility support for the
531      * {@code CheckboxMenuItem} class.  It provides an implementation
532      * of the Java Accessibility API appropriate to checkbox menu item
533      * user-interface elements.
534      * @since 1.3
535      */
536     protected class AccessibleAWTCheckboxMenuItem extends AccessibleAWTMenuItem
537         implements AccessibleAction, AccessibleValue
538     {
539         /*
540          * JDK 1.3 serialVersionUID
541          */
542         private static final long serialVersionUID = -1122642964303476L;
543 
544         /**
545          * Constructs an {@code AccessibleAWTCheckboxMenuItem}.
546          */
AccessibleAWTCheckboxMenuItem()547         protected AccessibleAWTCheckboxMenuItem() {}
548 
549         /**
550          * Get the AccessibleAction associated with this object.  In the
551          * implementation of the Java Accessibility API for this class,
552          * return this object, which is responsible for implementing the
553          * AccessibleAction interface on behalf of itself.
554          *
555          * @return this object
556          */
getAccessibleAction()557         public AccessibleAction getAccessibleAction() {
558             return this;
559         }
560 
561         /**
562          * Get the AccessibleValue associated with this object.  In the
563          * implementation of the Java Accessibility API for this class,
564          * return this object, which is responsible for implementing the
565          * AccessibleValue interface on behalf of itself.
566          *
567          * @return this object
568          */
getAccessibleValue()569         public AccessibleValue getAccessibleValue() {
570             return this;
571         }
572 
573         /**
574          * Returns the number of Actions available in this object.
575          * If there is more than one, the first one is the "default"
576          * action.
577          *
578          * @return the number of Actions in this object
579          */
getAccessibleActionCount()580         public int getAccessibleActionCount() {
581             return 0;  //  To be fully implemented in a future release
582         }
583 
584         /**
585          * Return a description of the specified action of the object.
586          *
587          * @param i zero-based index of the actions
588          */
getAccessibleActionDescription(int i)589         public String getAccessibleActionDescription(int i) {
590             return null;  //  To be fully implemented in a future release
591         }
592 
593         /**
594          * Perform the specified Action on the object
595          *
596          * @param i zero-based index of actions
597          * @return true if the action was performed; otherwise false.
598          */
doAccessibleAction(int i)599         public boolean doAccessibleAction(int i) {
600             return false;    //  To be fully implemented in a future release
601         }
602 
603         /**
604          * Get the value of this object as a Number.  If the value has not been
605          * set, the return value will be null.
606          *
607          * @return value of the object
608          * @see #setCurrentAccessibleValue
609          */
getCurrentAccessibleValue()610         public Number getCurrentAccessibleValue() {
611             return null;  //  To be fully implemented in a future release
612         }
613 
614         /**
615          * Set the value of this object as a Number.
616          *
617          * @return true if the value was set; otherwise false
618          * @see #getCurrentAccessibleValue
619          */
setCurrentAccessibleValue(Number n)620         public boolean setCurrentAccessibleValue(Number n) {
621             return false;  //  To be fully implemented in a future release
622         }
623 
624         /**
625          * Get the minimum value of this object as a Number.
626          *
627          * @return Minimum value of the object; null if this object does not
628          * have a minimum value
629          * @see #getMaximumAccessibleValue
630          */
getMinimumAccessibleValue()631         public Number getMinimumAccessibleValue() {
632             return null;  //  To be fully implemented in a future release
633         }
634 
635         /**
636          * Get the maximum value of this object as a Number.
637          *
638          * @return Maximum value of the object; null if this object does not
639          * have a maximum value
640          * @see #getMinimumAccessibleValue
641          */
getMaximumAccessibleValue()642         public Number getMaximumAccessibleValue() {
643             return null;  //  To be fully implemented in a future release
644         }
645 
646         /**
647          * Get the role of this object.
648          *
649          * @return an instance of AccessibleRole describing the role of the
650          * object
651          */
getAccessibleRole()652         public AccessibleRole getAccessibleRole() {
653             return AccessibleRole.CHECK_BOX;
654         }
655 
656     } // class AccessibleAWTMenuItem
657 
658 }
659