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