1. /*
  2. * @(#)MenuBar.java 1.63 03/01/23
  3. *
  4. * Copyright 2003 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.63, 01/23/03
  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. * @param m the menu to be added.
  170. * @return the menu added.
  171. * @see java.awt.MenuBar#remove(int)
  172. * @see java.awt.MenuBar#remove(java.awt.MenuComponent)
  173. */
  174. public Menu add(Menu m) {
  175. synchronized (getTreeLock()) {
  176. if (m.parent != null) {
  177. m.parent.remove(m);
  178. }
  179. menus.addElement(m);
  180. m.parent = this;
  181. MenuBarPeer peer = (MenuBarPeer)this.peer;
  182. if (peer != null) {
  183. if (m.peer == null) {
  184. m.addNotify();
  185. }
  186. peer.addMenu(m);
  187. }
  188. return m;
  189. }
  190. }
  191. /**
  192. * Removes the menu located at the specified
  193. * index from this menu bar.
  194. * @param index the position of the menu to be removed.
  195. * @see java.awt.MenuBar#add(java.awt.Menu)
  196. */
  197. public void remove(int index) {
  198. synchronized (getTreeLock()) {
  199. Menu m = getMenu(index);
  200. menus.removeElementAt(index);
  201. MenuBarPeer peer = (MenuBarPeer)this.peer;
  202. if (peer != null) {
  203. m.removeNotify();
  204. m.parent = null;
  205. peer.delMenu(index);
  206. }
  207. }
  208. }
  209. /**
  210. * Removes the specified menu component from this menu bar.
  211. * @param m the menu component to be removed.
  212. * @see java.awt.MenuBar#add(java.awt.Menu)
  213. */
  214. public void remove(MenuComponent m) {
  215. synchronized (getTreeLock()) {
  216. int index = menus.indexOf(m);
  217. if (index >= 0) {
  218. remove(index);
  219. }
  220. }
  221. }
  222. /**
  223. * Gets the number of menus on the menu bar.
  224. * @return the number of menus on the menu bar.
  225. * @since JDK1.1
  226. */
  227. public int getMenuCount() {
  228. return countMenus();
  229. }
  230. /**
  231. * @deprecated As of JDK version 1.1,
  232. * replaced by <code>getMenuCount()</code>.
  233. */
  234. public int countMenus() {
  235. return getMenuCountImpl();
  236. }
  237. /*
  238. * This is called by the native code, so client code can't
  239. * be called on the toolkit thread.
  240. */
  241. final int getMenuCountImpl() {
  242. return menus.size();
  243. }
  244. /**
  245. * Gets the specified menu.
  246. * @param i the index position of the menu to be returned.
  247. * @return the menu at the specified index of this menu bar.
  248. */
  249. public Menu getMenu(int i) {
  250. return getMenuImpl(i);
  251. }
  252. /*
  253. * This is called by the native code, so client code can't
  254. * be called on the toolkit thread.
  255. */
  256. final Menu getMenuImpl(int i) {
  257. return (Menu)menus.elementAt(i);
  258. }
  259. /**
  260. * Gets an enumeration of all menu shortcuts this menu bar
  261. * is managing.
  262. * @return an enumeration of menu shortcuts that this
  263. * menu bar is managing.
  264. * @see java.awt.MenuShortcut
  265. * @since JDK1.1
  266. */
  267. public synchronized Enumeration shortcuts() {
  268. Vector shortcuts = new Vector();
  269. int nmenus = getMenuCount();
  270. for (int i = 0 ; i < nmenus ; i++) {
  271. Enumeration e = getMenu(i).shortcuts();
  272. while (e.hasMoreElements()) {
  273. shortcuts.addElement(e.nextElement());
  274. }
  275. }
  276. return shortcuts.elements();
  277. }
  278. /**
  279. * Gets the instance of <code>MenuItem</code> associated
  280. * with the specified <code>MenuShortcut</code> object,
  281. * or <code>null</code> if none of the menu items being managed
  282. * by this menu bar is associated with the specified menu
  283. * shortcut.
  284. * @param s the specified menu shortcut.
  285. * @see java.awt.MenuItem
  286. * @see java.awt.MenuShortcut
  287. * @since JDK1.1
  288. */
  289. public MenuItem getShortcutMenuItem(MenuShortcut s) {
  290. int nmenus = getMenuCount();
  291. for (int i = 0 ; i < nmenus ; i++) {
  292. MenuItem mi = getMenu(i).getShortcutMenuItem(s);
  293. if (mi != null) {
  294. return mi;
  295. }
  296. }
  297. return null; // MenuShortcut wasn't found
  298. }
  299. /*
  300. * Post an ACTION_EVENT to the target of the MenuPeer
  301. * associated with the specified keyboard event (on
  302. * keydown). Returns true if there is an associated
  303. * keyboard event.
  304. */
  305. boolean handleShortcut(KeyEvent e) {
  306. // Is it a key event?
  307. int id = e.getID();
  308. if (id != KeyEvent.KEY_PRESSED && id != KeyEvent.KEY_RELEASED) {
  309. return false;
  310. }
  311. // Is the accelerator modifier key pressed?
  312. int accelKey = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
  313. if ((e.getModifiers() & accelKey) == 0) {
  314. return false;
  315. }
  316. // Pass MenuShortcut on to child menus.
  317. int nmenus = getMenuCount();
  318. for (int i = 0 ; i < nmenus ; i++) {
  319. Menu m = getMenu(i);
  320. if (m.handleShortcut(e)) {
  321. return true;
  322. }
  323. }
  324. return false;
  325. }
  326. /**
  327. * Deletes the specified menu shortcut.
  328. * @param s the menu shortcut to delete.
  329. * @since JDK1.1
  330. */
  331. public void deleteShortcut(MenuShortcut s) {
  332. int nmenus = getMenuCount();
  333. for (int i = 0 ; i < nmenus ; i++) {
  334. getMenu(i).deleteShortcut(s);
  335. }
  336. }
  337. /* Serialization support. Restore the (transient) parent
  338. * fields of Menubar menus here.
  339. */
  340. /**
  341. * The MenuBar's serialized data version.
  342. *
  343. * @serial
  344. */
  345. private int menuBarSerializedDataVersion = 1;
  346. /**
  347. * Writes default serializable fields to stream.
  348. *
  349. * @param s the <code>ObjectOutputStream</code> to write
  350. * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
  351. * @see #readObject(java.io.ObjectInputStream)
  352. */
  353. private void writeObject(java.io.ObjectOutputStream s)
  354. throws java.lang.ClassNotFoundException,
  355. java.io.IOException
  356. {
  357. s.defaultWriteObject();
  358. }
  359. /**
  360. * Reads the <code>ObjectInputStream</code>.
  361. * Unrecognized keys or values will be ignored.
  362. *
  363. * @param s the <code>ObjectInputStream</code> to read
  364. * @exception HeadlessException if
  365. * <code>GraphicsEnvironment.isHeadless</code> returns
  366. * <code>true</code>
  367. * @see java.awt.GraphicsEnvironment#isHeadless
  368. * @see #writeObject(java.io.ObjectOutputStream)
  369. */
  370. private void readObject(ObjectInputStream s)
  371. throws ClassNotFoundException, IOException, HeadlessException
  372. {
  373. // HeadlessException will be thrown from MenuComponent's readObject
  374. s.defaultReadObject();
  375. for (int i = 0; i < menus.size(); i++) {
  376. Menu m = (Menu)menus.elementAt(i);
  377. m.parent = this;
  378. }
  379. }
  380. /**
  381. * Initialize JNI field and method IDs
  382. */
  383. private static native void initIDs();
  384. /////////////////
  385. // Accessibility support
  386. ////////////////
  387. /**
  388. * Gets the AccessibleContext associated with this MenuBar.
  389. * For menu bars, the AccessibleContext takes the form of an
  390. * AccessibleAWTMenuBar.
  391. * A new AccessibleAWTMenuBar instance is created if necessary.
  392. *
  393. * @return an AccessibleAWTMenuBar that serves as the
  394. * AccessibleContext of this MenuBar
  395. */
  396. public AccessibleContext getAccessibleContext() {
  397. if (accessibleContext == null) {
  398. accessibleContext = new AccessibleAWTMenuBar();
  399. }
  400. return accessibleContext;
  401. }
  402. /**
  403. * Inner class of MenuBar used to provide default support for
  404. * accessibility. This class is not meant to be used directly by
  405. * application developers, but is instead meant only to be
  406. * subclassed by menu component developers.
  407. * <p>
  408. * This class implements accessibility support for the
  409. * <code>MenuBar</code> class. It provides an implementation of the
  410. * Java Accessibility API appropriate to menu bar user-interface elements.
  411. */
  412. protected class AccessibleAWTMenuBar extends AccessibleAWTMenuComponent {
  413. /**
  414. * Get the role of this object.
  415. *
  416. * @return an instance of AccessibleRole describing the role of the
  417. * object
  418. */
  419. public AccessibleRole getAccessibleRole() {
  420. return AccessibleRole.MENU_BAR;
  421. }
  422. } // class AccessibleAWTMenuBar
  423. }