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