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 JDK1.0 63 */ 64 public class CheckboxMenuItem extends MenuItem implements ItemSelectable, Accessible { 65 66 static { 67 /* ensure that the necessary native libraries are loaded */ Toolkit.loadLibraries()68 Toolkit.loadLibraries(); 69 if (!GraphicsEnvironment.isHeadless()) { initIDs()70 initIDs(); 71 } 72 AWTAccessor.setCheckboxMenuItemAccessor( new AWTAccessor.CheckboxMenuItemAccessor() { public boolean getState(CheckboxMenuItem cmi) { return cmi.state; } })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 JDK1.1 106 */ CheckboxMenuItem()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 */ CheckboxMenuItem(String label)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 JDK1.1 136 */ CheckboxMenuItem(String label, boolean state)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 */ constructComponentName()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 */ addNotify()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 */ getState()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 */ setState(boolean b)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 */ getSelectedObjects()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 JDK1.1 235 */ addItemListener(ItemListener l)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 JDK1.1 257 */ removeItemListener(ItemListener l)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 */ getItemListeners()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 */ getListeners(Class<T> listenerType)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 eventEnabled(AWTEvent e)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 JDK1.1 354 */ processEvent(AWTEvent e)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 JDK1.1 385 */ processItemEvent(ItemEvent e)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 */ doMenuEvent(long when, int modifiers)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 */ paramString()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 */ writeObject(ObjectOutputStream s)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 */ readObject(ObjectInputStream s)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 */ initIDs()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 */ getAccessibleContext()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 */ getAccessibleAction()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 */ getAccessibleValue()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 */ getAccessibleActionCount()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 */ getAccessibleActionDescription(int i)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 */ doAccessibleAction(int i)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 */ getCurrentAccessibleValue()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 */ setCurrentAccessibleValue(Number n)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 */ getMinimumAccessibleValue()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 */ getMaximumAccessibleValue()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 */ getAccessibleRole()635 public AccessibleRole getAccessibleRole() { 636 return AccessibleRole.CHECK_BOX; 637 } 638 639 } // class AccessibleAWTMenuItem 640 641 } 642