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