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 */
  76         Toolkit.loadLibraries();
  77         if (!GraphicsEnvironment.isHeadless()) {
  78             initIDs();
  79         }
  80 
  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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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          */
 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          */
 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          */
 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          */
 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          */
 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          */
 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          */
 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          */
 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          */
 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          */
 642         public AccessibleRole getAccessibleRole() {
 643             return AccessibleRole.CHECK_BOX;
 644         }
 645 
 646     } // class AccessibleAWTMenuItem
 647 
 648 }