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