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