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.KeyEvent; 29 import java.awt.peer.MenuBarPeer; 30 import java.io.IOException; 31 import java.io.ObjectInputStream; 32 import java.util.Enumeration; 33 import java.util.Vector; 34 35 import javax.accessibility.Accessible; 36 import javax.accessibility.AccessibleContext; 37 import javax.accessibility.AccessibleRole; 38 39 import sun.awt.AWTAccessor; 40 41 /** 42 * The {@code MenuBar} class encapsulates the platform's 43 * concept of a menu bar bound to a frame. In order to associate 44 * the menu bar with a {@code Frame} object, call the 45 * frame's {@code setMenuBar} method. 46 * <p> 47 * <A NAME="mbexample"></A><!-- target for cross references --> 48 * This is what a menu bar might look like: 49 * <p> 50 * <img src="doc-files/MenuBar-1.gif" 51 * alt="Diagram of MenuBar containing 2 menus: Examples and Options. 52 * Examples menu is expanded showing items: Basic, Simple, Check, and More Examples." 53 * style="float:center; margin: 7px 10px;"> 54 * <p> 55 * A menu bar handles keyboard shortcuts for menu items, passing them 56 * along to its child menus. 57 * (Keyboard shortcuts, which are optional, provide the user with 58 * an alternative to the mouse for invoking a menu item and the 59 * action that is associated with it.) 60 * Each menu item can maintain an instance of {@code MenuShortcut}. 61 * The {@code MenuBar} class defines several methods, 62 * {@link MenuBar#shortcuts} and 63 * {@link MenuBar#getShortcutMenuItem} 64 * that retrieve information about the shortcuts a given 65 * menu bar is managing. 66 * 67 * @author Sami Shaio 68 * @see java.awt.Frame 69 * @see java.awt.Frame#setMenuBar(java.awt.MenuBar) 70 * @see java.awt.Menu 71 * @see java.awt.MenuItem 72 * @see java.awt.MenuShortcut 73 * @since 1.0 74 */ 75 public class MenuBar extends MenuComponent implements MenuContainer, Accessible { 76 77 static { 78 /* ensure that the necessary native libraries are loaded */ 79 Toolkit.loadLibraries(); 80 if (!GraphicsEnvironment.isHeadless()) { 81 initIDs(); 82 } 83 AWTAccessor.setMenuBarAccessor( 84 new AWTAccessor.MenuBarAccessor() { 85 public Menu getHelpMenu(MenuBar menuBar) { 86 return menuBar.helpMenu; 87 } 88 89 public Vector<Menu> getMenus(MenuBar menuBar) { 90 return menuBar.menus; 91 } 92 }); 93 } 94 95 /** 96 * This field represents a vector of the 97 * actual menus that will be part of the MenuBar. 98 * 99 * @serial 100 * @see #countMenus() 101 */ 102 private final Vector<Menu> menus = new Vector<>(); 103 104 /** 105 * This menu is a special menu dedicated to 106 * help. The one thing to note about this menu 107 * is that on some platforms it appears at the 108 * right edge of the menubar. 109 * 110 * @serial 111 * @see #getHelpMenu() 112 * @see #setHelpMenu(Menu) 113 */ 114 private volatile Menu helpMenu; 115 116 private static final String base = "menubar"; 117 private static int nameCounter = 0; 118 119 /* 120 * JDK 1.1 serialVersionUID 121 */ 122 private static final long serialVersionUID = -4930327919388951260L; 123 124 /** 125 * Creates a new menu bar. 126 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 127 * returns true. 128 * @see java.awt.GraphicsEnvironment#isHeadless 129 */ 130 public MenuBar() throws HeadlessException { 131 } 132 133 /** 134 * Construct a name for this MenuComponent. Called by getName() when 135 * the name is null. 136 */ 137 String constructComponentName() { 138 synchronized (MenuBar.class) { 139 return base + nameCounter++; 140 } 141 } 142 143 /** 144 * Creates the menu bar's peer. The peer allows us to change the 145 * appearance of the menu bar without changing any of the menu bar's 146 * functionality. 147 */ 148 public void addNotify() { 149 synchronized (getTreeLock()) { 150 if (peer == null) 151 peer = getComponentFactory().createMenuBar(this); 152 153 int nmenus = getMenuCount(); 154 for (int i = 0 ; i < nmenus ; i++) { 155 getMenu(i).addNotify(); 156 } 157 } 158 } 159 160 /** 161 * Removes the menu bar's peer. The peer allows us to change the 162 * appearance of the menu bar without changing any of the menu bar's 163 * functionality. 164 */ 165 public void removeNotify() { 166 synchronized (getTreeLock()) { 167 int nmenus = getMenuCount(); 168 for (int i = 0 ; i < nmenus ; i++) { 169 getMenu(i).removeNotify(); 170 } 171 super.removeNotify(); 172 } 173 } 174 175 /** 176 * Gets the help menu on the menu bar. 177 * @return the help menu on this menu bar. 178 */ 179 public Menu getHelpMenu() { 180 return helpMenu; 181 } 182 183 /** 184 * Sets the specified menu to be this menu bar's help menu. 185 * If this menu bar has an existing help menu, the old help menu is 186 * removed from the menu bar, and replaced with the specified menu. 187 * @param m the menu to be set as the help menu 188 */ 189 public void setHelpMenu(final Menu m) { 190 synchronized (getTreeLock()) { 191 if (helpMenu == m) { 192 return; 193 } 194 if (helpMenu != null) { 195 remove(helpMenu); 196 } 197 helpMenu = m; 198 if (m != null) { 199 if (m.parent != this) { 200 add(m); 201 } 202 m.isHelpMenu = true; 203 m.parent = this; 204 MenuBarPeer peer = (MenuBarPeer)this.peer; 205 if (peer != null) { 206 if (m.peer == null) { 207 m.addNotify(); 208 } 209 peer.addHelpMenu(m); 210 } 211 } 212 } 213 } 214 215 /** 216 * Adds the specified menu to the menu bar. 217 * If the menu has been part of another menu bar, 218 * removes it from that menu bar. 219 * 220 * @param m the menu to be added 221 * @return the menu added 222 * @see java.awt.MenuBar#remove(int) 223 * @see java.awt.MenuBar#remove(java.awt.MenuComponent) 224 */ 225 public Menu add(Menu m) { 226 synchronized (getTreeLock()) { 227 if (m.parent != null) { 228 m.parent.remove(m); 229 } 230 m.parent = this; 231 232 MenuBarPeer peer = (MenuBarPeer)this.peer; 233 if (peer != null) { 234 if (m.peer == null) { 235 m.addNotify(); 236 } 237 menus.addElement(m); 238 peer.addMenu(m); 239 } else { 240 menus.addElement(m); 241 } 242 return m; 243 } 244 } 245 246 /** 247 * Removes the menu located at the specified 248 * index from this menu bar. 249 * @param index the position of the menu to be removed. 250 * @see java.awt.MenuBar#add(java.awt.Menu) 251 */ 252 public void remove(final int index) { 253 synchronized (getTreeLock()) { 254 Menu m = getMenu(index); 255 menus.removeElementAt(index); 256 MenuBarPeer peer = (MenuBarPeer)this.peer; 257 if (peer != null) { 258 peer.delMenu(index); 259 m.removeNotify(); 260 } 261 m.parent = null; 262 if (helpMenu == m) { 263 helpMenu = null; 264 m.isHelpMenu = false; 265 } 266 } 267 } 268 269 /** 270 * Removes the specified menu component from this menu bar. 271 * @param m the menu component to be removed. 272 * @see java.awt.MenuBar#add(java.awt.Menu) 273 */ 274 public void remove(MenuComponent m) { 275 synchronized (getTreeLock()) { 276 int index = menus.indexOf(m); 277 if (index >= 0) { 278 remove(index); 279 } 280 } 281 } 282 283 /** 284 * Gets the number of menus on the menu bar. 285 * @return the number of menus on the menu bar. 286 * @since 1.1 287 */ 288 public int getMenuCount() { 289 return countMenus(); 290 } 291 292 /** 293 * Gets the number of menus on the menu bar. 294 * 295 * @return the number of menus on the menu bar. 296 * @deprecated As of JDK version 1.1, 297 * replaced by {@code getMenuCount()}. 298 */ 299 @Deprecated 300 public int countMenus() { 301 return getMenuCountImpl(); 302 } 303 304 /* 305 * This is called by the native code, so client code can't 306 * be called on the toolkit thread. 307 */ 308 final int getMenuCountImpl() { 309 return menus.size(); 310 } 311 312 /** 313 * Gets the specified menu. 314 * @param i the index position of the menu to be returned. 315 * @return the menu at the specified index of this menu bar. 316 */ 317 public Menu getMenu(int i) { 318 return getMenuImpl(i); 319 } 320 321 /* 322 * This is called by the native code, so client code can't 323 * be called on the toolkit thread. 324 */ 325 final Menu getMenuImpl(int i) { 326 return menus.elementAt(i); 327 } 328 329 /** 330 * Gets an enumeration of all menu shortcuts this menu bar 331 * is managing. 332 * @return an enumeration of menu shortcuts that this 333 * menu bar is managing. 334 * @see java.awt.MenuShortcut 335 * @since 1.1 336 */ 337 public synchronized Enumeration<MenuShortcut> shortcuts() { 338 Vector<MenuShortcut> shortcuts = new Vector<>(); 339 int nmenus = getMenuCount(); 340 for (int i = 0 ; i < nmenus ; i++) { 341 Enumeration<MenuShortcut> e = getMenu(i).shortcuts(); 342 while (e.hasMoreElements()) { 343 shortcuts.addElement(e.nextElement()); 344 } 345 } 346 return shortcuts.elements(); 347 } 348 349 /** 350 * Gets the instance of {@code MenuItem} associated 351 * with the specified {@code MenuShortcut} object, 352 * or {@code null} if none of the menu items being managed 353 * by this menu bar is associated with the specified menu 354 * shortcut. 355 * @param s the specified menu shortcut. 356 * @return the menu item for the specified shortcut. 357 * @see java.awt.MenuItem 358 * @see java.awt.MenuShortcut 359 * @since 1.1 360 */ 361 public MenuItem getShortcutMenuItem(MenuShortcut s) { 362 int nmenus = getMenuCount(); 363 for (int i = 0 ; i < nmenus ; i++) { 364 MenuItem mi = getMenu(i).getShortcutMenuItem(s); 365 if (mi != null) { 366 return mi; 367 } 368 } 369 return null; // MenuShortcut wasn't found 370 } 371 372 /* 373 * Post an ACTION_EVENT to the target of the MenuPeer 374 * associated with the specified keyboard event (on 375 * keydown). Returns true if there is an associated 376 * keyboard event. 377 */ 378 @SuppressWarnings("deprecation") 379 boolean handleShortcut(KeyEvent e) { 380 // Is it a key event? 381 int id = e.getID(); 382 if (id != KeyEvent.KEY_PRESSED && id != KeyEvent.KEY_RELEASED) { 383 return false; 384 } 385 386 // Is the accelerator modifier key pressed? 387 int accelKey = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); 388 if ((e.getModifiers() & accelKey) == 0) { 389 return false; 390 } 391 392 // Pass MenuShortcut on to child menus. 393 int nmenus = getMenuCount(); 394 for (int i = 0 ; i < nmenus ; i++) { 395 Menu m = getMenu(i); 396 if (m.handleShortcut(e)) { 397 return true; 398 } 399 } 400 return false; 401 } 402 403 /** 404 * Deletes the specified menu shortcut. 405 * @param s the menu shortcut to delete. 406 * @since 1.1 407 */ 408 public void deleteShortcut(MenuShortcut s) { 409 int nmenus = getMenuCount(); 410 for (int i = 0 ; i < nmenus ; i++) { 411 getMenu(i).deleteShortcut(s); 412 } 413 } 414 415 /* Serialization support. Restore the (transient) parent 416 * fields of Menubar menus here. 417 */ 418 419 /** 420 * The MenuBar's serialized data version. 421 * 422 * @serial 423 */ 424 private int menuBarSerializedDataVersion = 1; 425 426 /** 427 * Writes default serializable fields to stream. 428 * 429 * @param s the {@code ObjectOutputStream} to write 430 * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener) 431 * @see #readObject(java.io.ObjectInputStream) 432 */ 433 private void writeObject(java.io.ObjectOutputStream s) 434 throws java.lang.ClassNotFoundException, 435 java.io.IOException 436 { 437 s.defaultWriteObject(); 438 } 439 440 /** 441 * Reads the {@code ObjectInputStream}. 442 * Unrecognized keys or values will be ignored. 443 * 444 * @param s the {@code ObjectInputStream} to read 445 * @exception HeadlessException if 446 * {@code GraphicsEnvironment.isHeadless} returns 447 * {@code true} 448 * @see java.awt.GraphicsEnvironment#isHeadless 449 * @see #writeObject(java.io.ObjectOutputStream) 450 */ 451 private void readObject(ObjectInputStream s) 452 throws ClassNotFoundException, IOException, HeadlessException 453 { 454 // HeadlessException will be thrown from MenuComponent's readObject 455 s.defaultReadObject(); 456 for (int i = 0; i < menus.size(); i++) { 457 Menu m = menus.elementAt(i); 458 m.parent = this; 459 } 460 } 461 462 /** 463 * Initialize JNI field and method IDs 464 */ 465 private static native void initIDs(); 466 467 468 ///////////////// 469 // Accessibility support 470 //////////////// 471 472 /** 473 * Gets the AccessibleContext associated with this MenuBar. 474 * For menu bars, the AccessibleContext takes the form of an 475 * AccessibleAWTMenuBar. 476 * A new AccessibleAWTMenuBar instance is created if necessary. 477 * 478 * @return an AccessibleAWTMenuBar that serves as the 479 * AccessibleContext of this MenuBar 480 * @since 1.3 481 */ 482 public AccessibleContext getAccessibleContext() { 483 if (accessibleContext == null) { 484 accessibleContext = new AccessibleAWTMenuBar(); 485 } 486 return accessibleContext; 487 } 488 489 /** 490 * Defined in MenuComponent. Overridden here. 491 */ 492 int getAccessibleChildIndex(MenuComponent child) { 493 return menus.indexOf(child); 494 } 495 496 /** 497 * Inner class of MenuBar used to provide default support for 498 * accessibility. This class is not meant to be used directly by 499 * application developers, but is instead meant only to be 500 * subclassed by menu component developers. 501 * <p> 502 * This class implements accessibility support for the 503 * {@code MenuBar} class. It provides an implementation of the 504 * Java Accessibility API appropriate to menu bar user-interface elements. 505 * @since 1.3 506 */ 507 protected class AccessibleAWTMenuBar extends AccessibleAWTMenuComponent 508 { 509 /* 510 * JDK 1.3 serialVersionUID 511 */ 512 private static final long serialVersionUID = -8577604491830083815L; 513 514 /** 515 * Get the role of this object. 516 * 517 * @return an instance of AccessibleRole describing the role of the 518 * object 519 * @since 1.4 520 */ 521 public AccessibleRole getAccessibleRole() { 522 return AccessibleRole.MENU_BAR; 523 } 524 525 } // class AccessibleAWTMenuBar 526 527 }