1. /*
  2. * @(#)MenuBar.java 1.47 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt;
  8. import java.util.Vector;
  9. import java.util.Enumeration;
  10. import java.awt.peer.MenuBarPeer;
  11. import java.awt.event.KeyEvent;
  12. /**
  13. * The <code>MenuBar</code> class encapsulates the platform's
  14. * concept of a menu bar bound to a frame. In order to associate
  15. * the menu bar with a <code>Frame</code> object, call the
  16. * frame's <code>setMenuBar</code> method.
  17. * <p>
  18. * <A NAME="mbexample"></A><!-- target for cross references -->
  19. * This is what a menu bar might look like:
  20. * <p>
  21. * <img src="doc-files/MenuBar-1.gif"
  22. * ALIGN=center HSPACE=10 VSPACE=7>
  23. * <p>
  24. * A menu bar handles keyboard shortcuts for menu items, passing them
  25. * along to its child menus.
  26. * (Keyboard shortcuts, which are optional, provide the user with
  27. * an alternative to the mouse for invoking a menu item and the
  28. * action that is associated with it.)
  29. * Each menu item can maintain an instance of <code>MenuShortcut</code>.
  30. * The <code>MenuBar</code> class defines several methods,
  31. * {@link MenuBar#shortcuts} and
  32. * {@link MenuBar#getShortcutMenuItem}
  33. * that retrieve information about the shortcuts a given
  34. * menu bar is managing.
  35. *
  36. * @version 1.47, 11/29/01
  37. * @author Sami Shaio
  38. * @see java.awt.Frame
  39. * @see java.awt.Frame#setMenuBar(java.awt.MenuBar)
  40. * @see java.awt.Menu
  41. * @see java.awt.MenuItem
  42. * @see java.awt.MenuShortcut
  43. * @since JDK1.0
  44. */
  45. public class MenuBar extends MenuComponent implements MenuContainer {
  46. static {
  47. /* ensure that the necessary native libraries are loaded */
  48. Toolkit.loadLibraries();
  49. initIDs();
  50. }
  51. /**
  52. * This field represents a vector of the
  53. * actual menus that will be part of the MenuBar.
  54. *
  55. * @serial
  56. * @see countMenus()
  57. */
  58. Vector menus = new Vector();
  59. /**
  60. * This menu is a special menu dedicated to
  61. * help. The one thing to note about this menu
  62. * is that on some platforms it appears at the
  63. * right edge of the menubar.
  64. *
  65. * @serial
  66. * @see getHelpMenu()
  67. * @see setHelpMenu()
  68. */
  69. Menu helpMenu;
  70. private static final String base = "menubar";
  71. private static int nameCounter = 0;
  72. /*
  73. * JDK 1.1 serialVersionUID
  74. */
  75. private static final long serialVersionUID = -4930327919388951260L;
  76. /**
  77. * Creates a new menu bar.
  78. */
  79. public MenuBar() {
  80. }
  81. /**
  82. * Construct a name for this MenuComponent. Called by getName() when
  83. * the name is null.
  84. */
  85. String constructComponentName() {
  86. synchronized (getClass()) {
  87. return base + nameCounter++;
  88. }
  89. }
  90. /**
  91. * Creates the menu bar's peer. The peer allows us to change the
  92. * appearance of the menu bar without changing any of the menu bar's
  93. * functionality.
  94. */
  95. public void addNotify() {
  96. synchronized (getTreeLock()) {
  97. if (peer == null)
  98. peer = Toolkit.getDefaultToolkit().createMenuBar(this);
  99. int nmenus = getMenuCount();
  100. for (int i = 0 ; i < nmenus ; i++) {
  101. getMenu(i).addNotify();
  102. }
  103. }
  104. }
  105. /**
  106. * Removes the menu bar's peer. The peer allows us to change the
  107. * appearance of the menu bar without changing any of the menu bar's
  108. * functionality.
  109. */
  110. public void removeNotify() {
  111. synchronized (getTreeLock()) {
  112. int nmenus = getMenuCount();
  113. for (int i = 0 ; i < nmenus ; i++) {
  114. getMenu(i).removeNotify();
  115. }
  116. super.removeNotify();
  117. }
  118. }
  119. /**
  120. * Gets the help menu on the menu bar.
  121. * @return the help menu on this menu bar.
  122. */
  123. public Menu getHelpMenu() {
  124. return helpMenu;
  125. }
  126. /**
  127. * Sets the help menu on this menu bar to be the specified menu.
  128. * @param m the menu to be set as the help menu.
  129. */
  130. public void setHelpMenu(Menu m) {
  131. synchronized (getTreeLock()) {
  132. if (helpMenu == m) {
  133. return;
  134. }
  135. if (helpMenu != null) {
  136. helpMenu.removeNotify();
  137. helpMenu.parent = null;
  138. }
  139. if (m.parent != this) {
  140. add(m);
  141. }
  142. helpMenu = m;
  143. if (m != null) {
  144. m.isHelpMenu = true;
  145. m.parent = this;
  146. MenuBarPeer peer = (MenuBarPeer)this.peer;
  147. if (peer != null) {
  148. if (m.peer == null) {
  149. m.addNotify();
  150. }
  151. peer.addHelpMenu(m);
  152. }
  153. }
  154. }
  155. }
  156. /**
  157. * Adds the specified menu to the menu bar.
  158. * @param m the menu to be added.
  159. * @return the menu added.
  160. * @see java.awt.MenuBar#remove(int)
  161. * @see java.awt.MenuBar#remove(java.awt.MenuComponent)
  162. */
  163. public Menu add(Menu m) {
  164. synchronized (getTreeLock()) {
  165. if (m.parent != null) {
  166. m.parent.remove(m);
  167. }
  168. menus.addElement(m);
  169. m.parent = this;
  170. MenuBarPeer peer = (MenuBarPeer)this.peer;
  171. if (peer != null) {
  172. if (m.peer == null) {
  173. m.addNotify();
  174. }
  175. peer.addMenu(m);
  176. }
  177. return m;
  178. }
  179. }
  180. /**
  181. * Removes the menu located at the specified
  182. * index from this menu bar.
  183. * @param index the position of the menu to be removed.
  184. * @see java.awt.MenuBar#add(java.awt.Menu)
  185. */
  186. public void remove(int index) {
  187. synchronized (getTreeLock()) {
  188. MenuBarPeer peer = (MenuBarPeer)this.peer;
  189. if (peer != null) {
  190. Menu m = getMenu(index);
  191. m.removeNotify();
  192. m.parent = null;
  193. peer.delMenu(index);
  194. }
  195. menus.removeElementAt(index);
  196. }
  197. }
  198. /**
  199. * Removes the specified menu component from this menu bar.
  200. * @param m the menu component to be removed.
  201. * @see java.awt.MenuBar#add(java.awt.Menu)
  202. */
  203. public void remove(MenuComponent m) {
  204. synchronized (getTreeLock()) {
  205. int index = menus.indexOf(m);
  206. if (index >= 0) {
  207. remove(index);
  208. }
  209. }
  210. }
  211. /**
  212. * Gets the number of menus on the menu bar.
  213. * @return the number of menus on the menu bar.
  214. * @since JDK1.1
  215. */
  216. public int getMenuCount() {
  217. return countMenus();
  218. }
  219. /**
  220. * @deprecated As of JDK version 1.1,
  221. * replaced by <code>getMenuCount()</code>.
  222. */
  223. public int countMenus() {
  224. return getMenuCountImpl();
  225. }
  226. /*
  227. * This is called by the native code, so client code can't
  228. * be called on the toolkit thread.
  229. */
  230. final int getMenuCountImpl() {
  231. return menus.size();
  232. }
  233. /**
  234. * Gets the specified menu.
  235. * @param i the index position of the menu to be returned.
  236. * @return the menu at the specified index of this menu bar.
  237. */
  238. public Menu getMenu(int i) {
  239. return getMenuImpl(i);
  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 Menu getMenuImpl(int i) {
  246. return (Menu)menus.elementAt(i);
  247. }
  248. /**
  249. * Gets an enumeration of all menu shortcuts this menu bar
  250. * is managing.
  251. * @return an enumeration of menu shortcuts that this
  252. * menu bar is managing.
  253. * @see java.awt.MenuShortcut
  254. * @since JDK1.1
  255. */
  256. public synchronized Enumeration shortcuts() {
  257. Vector shortcuts = new Vector();
  258. int nmenus = getMenuCount();
  259. for (int i = 0 ; i < nmenus ; i++) {
  260. Enumeration e = getMenu(i).shortcuts();
  261. while (e.hasMoreElements()) {
  262. shortcuts.addElement(e.nextElement());
  263. }
  264. }
  265. return shortcuts.elements();
  266. }
  267. /**
  268. * Gets the instance of <code>MenuItem</code> associated
  269. * with the specified <code>MenuShortcut</code> object,
  270. * or <code>null</code> if none of the menu items being managed
  271. * by this menu bar is associated with the specified menu
  272. * shortcut.
  273. * @param s the specified menu shortcut.
  274. * @see java.awt.MenuItem
  275. * @see java.awt.MenuShortcut
  276. * @since JDK1.1
  277. */
  278. public MenuItem getShortcutMenuItem(MenuShortcut s) {
  279. int nmenus = getMenuCount();
  280. for (int i = 0 ; i < nmenus ; i++) {
  281. MenuItem mi = getMenu(i).getShortcutMenuItem(s);
  282. if (mi != null) {
  283. return mi;
  284. }
  285. }
  286. return null; // MenuShortcut wasn't found
  287. }
  288. /*
  289. * Post an ACTION_EVENT to the target of the MenuPeer
  290. * associated with the specified keyboard event (on
  291. * keydown). Returns true if there is an associated
  292. * keyboard event.
  293. */
  294. boolean handleShortcut(KeyEvent e) {
  295. // Is it a key event?
  296. int id = e.getID();
  297. if (id != KeyEvent.KEY_PRESSED && id != KeyEvent.KEY_RELEASED) {
  298. return false;
  299. }
  300. // Is the accelerator modifier key pressed?
  301. int accelKey = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
  302. if ((e.getModifiers() & accelKey) == 0) {
  303. return false;
  304. }
  305. // Pass MenuShortcut on to child menus.
  306. int nmenus = getMenuCount();
  307. for (int i = 0 ; i < nmenus ; i++) {
  308. Menu m = getMenu(i);
  309. if (m.handleShortcut(e)) {
  310. return true;
  311. }
  312. }
  313. return false;
  314. }
  315. /**
  316. * Deletes the specified menu shortcut.
  317. * @param s the menu shortcut to delete.
  318. * @since JDK1.1
  319. */
  320. public void deleteShortcut(MenuShortcut s) {
  321. int nmenus = getMenuCount();
  322. for (int i = 0 ; i < nmenus ; i++) {
  323. getMenu(i).deleteShortcut(s);
  324. }
  325. }
  326. /* Serialization support. Restore the (transient) parent
  327. * fields of Menubar menus here.
  328. */
  329. /**
  330. * The MenuBar's serialized data version.
  331. *
  332. * @serial
  333. */
  334. private int menuBarSerializedDataVersion = 1;
  335. /**
  336. * Writes default serializable fields to stream. Writes
  337. * a list of serializable ItemListener(s) as optional data.
  338. * The non-serializable ItemListner(s) are detected and
  339. * no attempt is made to serialize them.
  340. *
  341. * @serialData Null terminated sequence of 0 or more pairs.
  342. * The pair consists of a String and Object.
  343. * The String indicates the type of object and
  344. * is one of the following :
  345. * itemListenerK indicating and ItemListener object.
  346. *
  347. * @see AWTEventMulticaster.save(ObjectOutputStream, String, EventListener)
  348. * @see java.awt.Component.itemListenerK
  349. */
  350. private void writeObject(java.io.ObjectOutputStream s)
  351. throws java.lang.ClassNotFoundException,
  352. java.io.IOException
  353. {
  354. s.defaultWriteObject();
  355. }
  356. /**
  357. * Read the ObjectInputStream and if it isnt null
  358. * add a listener to receive item events fired
  359. * by the MenuBar.
  360. * Unrecognised keys or values will be Ignored.
  361. *
  362. * @see removeActionListener()
  363. * @see addActionListener()
  364. */
  365. private void readObject(java.io.ObjectInputStream s)
  366. throws java.lang.ClassNotFoundException,
  367. java.io.IOException
  368. {
  369. s.defaultReadObject();
  370. for (int i = 0; i < menus.size(); i++) {
  371. Menu m = (Menu)menus.elementAt(i);
  372. m.parent = this;
  373. }
  374. }
  375. /**
  376. * Initialize JNI field and method IDs
  377. */
  378. private static native void initIDs();
  379. }