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