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