Frames | No Frames |
1: /* JMenuBar.java -- 2: Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing; 40: 41: import java.awt.Component; 42: import java.awt.Graphics; 43: import java.awt.Insets; 44: import java.awt.event.KeyEvent; 45: import java.awt.event.MouseEvent; 46: 47: import javax.accessibility.Accessible; 48: import javax.accessibility.AccessibleContext; 49: import javax.accessibility.AccessibleRole; 50: import javax.accessibility.AccessibleSelection; 51: import javax.accessibility.AccessibleStateSet; 52: import javax.swing.plaf.MenuBarUI; 53: 54: import javax.swing.border.Border; 55: 56: /** 57: * JMenuBar is a container for menu's. For a menu bar to be seen on the 58: * screen, at least one menu should be added to it. Just like adding 59: * components to container, one can use add() to add menu's to the menu bar. 60: * Menu's will be displayed in the menu bar in the order they were added. 61: * The JMenuBar uses selectionModel to keep track of selected menu index. 62: * JMenuBar's selectionModel will fire ChangeEvents to its registered 63: * listeners when the selected index changes. 64: */ 65: public class JMenuBar extends JComponent implements Accessible, MenuElement 66: { 67: /** 68: * Provides accessibility support for <code>JMenuBar</code>. 69: * 70: * @author Roman Kennke (kennke@aicas.com) 71: */ 72: protected class AccessibleJMenuBar extends AccessibleJComponent 73: implements AccessibleSelection 74: { 75: 76: /** 77: * Returns the number of selected items in the menu bar. Possible values 78: * are <code>0</code> if nothing is selected, or <code>1</code> if one 79: * item is selected. 80: * 81: * @return the number of selected items in the menu bar 82: */ 83: public int getAccessibleSelectionCount() 84: { 85: int count = 0; 86: if (getSelectionModel().getSelectedIndex() != -1) 87: count = 1; 88: return count; 89: } 90: 91: /** 92: * Returns the selected with index <code>i</code> menu, or 93: * <code>null</code> if the specified menu is not selected. 94: * 95: * @param i the index of the menu to return 96: * 97: * @return the selected with index <code>i</code> menu, or 98: * <code>null</code> if the specified menu is not selected 99: */ 100: public Accessible getAccessibleSelection(int i) 101: { 102: if (getSelectionModel().getSelectedIndex() != i) 103: return null; 104: return getMenu(i); 105: } 106: 107: /** 108: * Returns <code>true</code> if the specified menu is selected, 109: * <code>false</code> otherwise. 110: * 111: * @param i the index of the menu to check 112: * 113: *@return <code>true</code> if the specified menu is selected, 114: * <code>false</code> otherwise 115: */ 116: public boolean isAccessibleChildSelected(int i) 117: { 118: return getSelectionModel().getSelectedIndex() == i; 119: } 120: 121: /** 122: * Selects the menu with index <code>i</code>. If another menu is already 123: * selected, this will be deselected. 124: * 125: * @param i the menu to be selected 126: */ 127: public void addAccessibleSelection(int i) 128: { 129: getSelectionModel().setSelectedIndex(i); 130: } 131: 132: /** 133: * Deselects the menu with index <code>i</code>. 134: * 135: * @param i the menu index to be deselected 136: */ 137: public void removeAccessibleSelection(int i) 138: { 139: if (getSelectionModel().getSelectedIndex() == i) 140: getSelectionModel().clearSelection(); 141: } 142: 143: /** 144: * Deselects all possibly selected menus. 145: */ 146: public void clearAccessibleSelection() 147: { 148: getSelectionModel().clearSelection(); 149: } 150: 151: /** 152: * In menu bars it is not possible to select all items, so this method 153: * does nothing. 154: */ 155: public void selectAllAccessibleSelection() 156: { 157: // In menu bars it is not possible to select all items, so this method 158: // does nothing. 159: } 160: 161: /** 162: * Returns the accessible role of <code>JMenuBar</code>, which is 163: * {@link AccessibleRole#MENU_BAR}. 164: * 165: * @return the accessible role of <code>JMenuBar</code>, which is 166: * {@link AccessibleRole#MENU_BAR} 167: */ 168: public AccessibleRole getAccessibleRole() 169: { 170: return AccessibleRole.MENU_BAR; 171: } 172: 173: /** 174: * Returns the <code>AccessibleSelection</code> for this object. This 175: * method returns <code>this</code>, since the 176: * <code>AccessibleJMenuBar</code> manages its selection itself. 177: * 178: * @return the <code>AccessibleSelection</code> for this object 179: */ 180: public AccessibleSelection getAccessibleSelection() 181: { 182: return this; 183: } 184: 185: /** 186: * Returns the state of this <code>AccessibleJMenuBar</code>. 187: * 188: * @return the state of this <code>AccessibleJMenuBar</code>. 189: */ 190: public AccessibleStateSet getAccessibleStateSet() 191: { 192: AccessibleStateSet stateSet = super.getAccessibleStateSet(); 193: // TODO: Figure out what state must be added to the super state set. 194: return stateSet; 195: } 196: } 197: 198: private static final long serialVersionUID = -8191026883931977036L; 199: 200: /** JMenuBar's model. It keeps track of selected menu's index */ 201: private transient SingleSelectionModel selectionModel; 202: 203: /* borderPainted property indicating if the menuBar's border will be painted*/ 204: private boolean borderPainted; 205: 206: /* margin between menu bar's border and its menues*/ 207: private Insets margin; 208: 209: /** 210: * Creates a new JMenuBar object. 211: */ 212: public JMenuBar() 213: { 214: selectionModel = new DefaultSingleSelectionModel(); 215: borderPainted = true; 216: updateUI(); 217: } 218: 219: /** 220: * Adds menu to the menu bar 221: * 222: * @param c menu to add 223: * 224: * @return reference to the added menu 225: */ 226: public JMenu add(JMenu c) 227: { 228: c.setAlignmentX(Component.LEFT_ALIGNMENT); 229: super.add(c); 230: return c; 231: } 232: 233: /** 234: * This method overrides addNotify() in the Container to register 235: * this menu bar with the current keyboard manager. 236: */ 237: public void addNotify() 238: { 239: super.addNotify(); 240: KeyboardManager.getManager().registerJMenuBar(this); 241: } 242: 243: public AccessibleContext getAccessibleContext() 244: { 245: if (accessibleContext == null) 246: accessibleContext = new AccessibleJMenuBar(); 247: return accessibleContext; 248: } 249: 250: /** 251: * Returns reference to this menu bar 252: * 253: * @return reference to this menu bar 254: */ 255: public Component getComponent() 256: { 257: return this; 258: } 259: 260: /** 261: * Returns component at the specified index. 262: * 263: * @param i index of the component to get 264: * 265: * @return component at the specified index. Null is returned if 266: * component at the specified index doesn't exist. 267: * @deprecated Replaced by getComponent(int) 268: */ 269: public Component getComponentAtIndex(int i) 270: { 271: return getComponent(i); 272: } 273: 274: /** 275: * Returns index of the specified component 276: * 277: * @param c Component to search for 278: * 279: * @return index of the specified component. -1 is returned if 280: * specified component doesnt' exist in the menu bar. 281: */ 282: public int getComponentIndex(Component c) 283: { 284: Component[] comps = getComponents(); 285: 286: int index = -1; 287: 288: for (int i = 0; i < comps.length; i++) 289: { 290: if (comps[i].equals(c)) 291: { 292: index = i; 293: break; 294: } 295: } 296: 297: return index; 298: } 299: 300: /** 301: * DOCUMENT ME! 302: * 303: * @return DOCUMENT ME! 304: */ 305: public JMenu getHelpMenu() 306: { 307: return null; 308: } 309: 310: /** 311: * Returns margin betweeen menu bar's border and its menues 312: * 313: * @return margin between menu bar's border and its menues 314: */ 315: public Insets getMargin() 316: { 317: if (margin == null) 318: return new Insets(0, 0, 0, 0); 319: else 320: return margin; 321: } 322: 323: /** 324: * Return menu at the specified index. If component at the 325: * specified index is not a menu, then null is returned. 326: * 327: * @param index index to look for the menu 328: * 329: * @return menu at specified index, or null if menu doesn't exist 330: * at the specified index. 331: */ 332: public JMenu getMenu(int index) 333: { 334: if (getComponentAtIndex(index) instanceof JMenu) 335: return (JMenu) getComponentAtIndex(index); 336: else 337: return null; 338: } 339: 340: /** 341: * Returns number of menu's in this menu bar 342: * 343: * @return number of menu's in this menu bar 344: */ 345: public int getMenuCount() 346: { 347: return getComponentCount(); 348: } 349: 350: /** 351: * Returns selection model for this menu bar. SelectionModel 352: * keeps track of the selected menu in the menu bar. Whenever 353: * selected property of selectionModel changes, the ChangeEvent 354: * will be fired its ChangeListeners. 355: * 356: * @return selection model for this menu bar. 357: */ 358: public SingleSelectionModel getSelectionModel() 359: { 360: return selectionModel; 361: } 362: 363: /** 364: * Method of MenuElement interface. It returns subcomponents 365: * of the menu bar, which are all the menues that it contains. 366: * 367: * @return MenuElement[] array containing menues in this menu bar 368: */ 369: public MenuElement[] getSubElements() 370: { 371: MenuElement[] subElements = new MenuElement[getComponentCount()]; 372: 373: int j = 0; 374: boolean doResize = false; 375: MenuElement menu; 376: for (int i = 0; i < getComponentCount(); i++) 377: { 378: menu = getMenu(i); 379: if (menu != null) 380: { 381: subElements[j++] = (MenuElement) menu; 382: } 383: else 384: doResize = true; 385: } 386: 387: if (! doResize) 388: return subElements; 389: else 390: { 391: MenuElement[] subElements2 = new MenuElement[j]; 392: for (int i = 0; i < j; i++) 393: subElements2[i] = subElements[i]; 394: 395: return subElements2; 396: } 397: } 398: 399: /** 400: * Set the "UI" property of the menu bar, which is a look and feel class 401: * responsible for handling the menuBar's input events and painting it. 402: * 403: * @return The current "UI" property 404: */ 405: public MenuBarUI getUI() 406: { 407: return (MenuBarUI) ui; 408: } 409: 410: /** 411: * This method returns a name to identify which look and feel class will be 412: * the UI delegate for the menu bar. 413: * 414: * @return The Look and Feel classID. "MenuBarUI" 415: */ 416: public String getUIClassID() 417: { 418: return "MenuBarUI"; 419: } 420: 421: /** 422: * Returns true if menu bar paints its border and false otherwise 423: * 424: * @return true if menu bar paints its border and false otherwise 425: */ 426: public boolean isBorderPainted() 427: { 428: return borderPainted; 429: } 430: 431: /** 432: * Returns true if some menu in menu bar is selected. 433: * 434: * @return true if some menu in menu bar is selected and false otherwise 435: */ 436: public boolean isSelected() 437: { 438: return selectionModel.isSelected(); 439: } 440: 441: /** 442: * This method does nothing by default. This method is need for the 443: * MenuElement interface to be implemented. 444: * 445: * @param isIncluded true if menuBar is included in the selection 446: * and false otherwise 447: */ 448: public void menuSelectionChanged(boolean isIncluded) 449: { 450: // Do nothing - needed for implementation of MenuElement interface 451: } 452: 453: /** 454: * Paints border of the menu bar, if its borderPainted property is set to 455: * true. 456: * 457: * @param g The graphics context with which to paint the border 458: */ 459: protected void paintBorder(Graphics g) 460: { 461: if (borderPainted) 462: { 463: Border border = getBorder(); 464: if (border != null) 465: getBorder().paintBorder(this, g, 0, 0, getSize(null).width, 466: getSize(null).height); 467: } 468: } 469: 470: /** 471: * A string that describes this JMenuBar. Normally only used 472: * for debugging. 473: * 474: * @return A string describing this JMenuBar 475: */ 476: protected String paramString() 477: { 478: StringBuffer sb = new StringBuffer(); 479: sb.append(super.paramString()); 480: sb.append(",margin="); 481: if (getMargin() != null) 482: sb.append(getMargin()); 483: sb.append(",paintBorder=").append(isBorderPainted()); 484: return sb.toString(); 485: } 486: 487: /** 488: * Process key events forwarded from MenuSelectionManager. This method 489: * doesn't do anything. It is here to conform to the MenuElement interface. 490: * 491: * @param e event forwarded from MenuSelectionManager 492: * @param path path to the menu element from which event was generated 493: * @param manager MenuSelectionManager for the current menu hierarchy 494: * 495: */ 496: public void processKeyEvent(KeyEvent e, MenuElement[] path, 497: MenuSelectionManager manager) 498: { 499: // Do nothing - needed for implementation of MenuElement interface 500: } 501: 502: /** 503: * This method overrides JComponent.processKeyBinding to allow the 504: * JMenuBar to check all the child components (recursiveley) to see 505: * if they'll consume the event. 506: * 507: * @param ks the KeyStroke for the event 508: * @param e the KeyEvent for the event 509: * @param condition the focus condition for the binding 510: * @param pressed true if the key is pressed 511: */ 512: protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, 513: boolean pressed) 514: { 515: // See if the regular JComponent behavior consumes the event 516: if (super.processKeyBinding(ks, e, condition, pressed)) 517: return true; 518: 519: // If not, have to recursively check all the child menu elements to see 520: // if they want it 521: MenuElement[] children = getSubElements(); 522: for (int i = 0; i < children.length; i++) 523: if (processKeyBindingHelper(children[i], ks, e, condition, pressed)) 524: return true; 525: return false; 526: } 527: 528: /** 529: * This is a helper method to recursively check the children of this 530: * JMenuBar to see if they will consume a key event via key bindings. 531: * This is used for menu accelerators. 532: * @param menuElement the menuElement to check (and check all its children) 533: * @param ks the KeyStroke for the event 534: * @param e the KeyEvent that may be consumed 535: * @param condition the focus condition for the binding 536: * @param pressed true if the key was pressed 537: * @return true <code>menuElement</code> or one of its children consume 538: * the event (processKeyBinding returns true for menuElement or one of 539: * its children). 540: */ 541: static boolean processKeyBindingHelper(MenuElement menuElement, KeyStroke ks, 542: KeyEvent e, int condition, 543: boolean pressed) 544: { 545: if (menuElement == null) 546: return false; 547: 548: // First check the menuElement itself, if it's a JComponent 549: if (menuElement instanceof JComponent 550: && ((JComponent) menuElement).processKeyBinding(ks, e, condition, 551: pressed)) 552: return true; 553: 554: // If that didn't consume it, check all the children recursively 555: MenuElement[] children = menuElement.getSubElements(); 556: for (int i = 0; i < children.length; i++) 557: if (processKeyBindingHelper(children[i], ks, e, condition, pressed)) 558: return true; 559: return false; 560: } 561: 562: /** 563: * Process mouse events forwarded from MenuSelectionManager. This method 564: * doesn't do anything. It is here to conform to the MenuElement interface. 565: * 566: * @param event event forwarded from MenuSelectionManager 567: * @param path path to the menu element from which event was generated 568: * @param manager MenuSelectionManager for the current menu hierarchy 569: * 570: */ 571: public void processMouseEvent(MouseEvent event, MenuElement[] path, 572: MenuSelectionManager manager) 573: { 574: // Do nothing - needed for implementation of MenuElement interface 575: } 576: 577: /** 578: * This method overrides removeNotify() in the Container to 579: * unregister this menu bar from the current keyboard manager. 580: */ 581: public void removeNotify() 582: { 583: KeyboardManager.getManager().unregisterJMenuBar(this); 584: super.removeNotify(); 585: } 586: 587: /** 588: * Sets painting status of the border. If 'b' is true then menu bar's 589: * border will be painted, and it will not be painted otherwise. 590: * 591: * @param b indicates if menu bar's border should be painted. 592: */ 593: public void setBorderPainted(boolean b) 594: { 595: if (b != borderPainted) 596: { 597: boolean old = borderPainted; 598: borderPainted = b; 599: firePropertyChange("borderPainted", old, b); 600: revalidate(); 601: repaint(); 602: } 603: } 604: 605: /** 606: * Sets help menu for this menu bar 607: * 608: * @param menu help menu 609: * 610: * @specnote The specification states that this method is not yet implemented 611: * and should throw an exception. 612: */ 613: public void setHelpMenu(JMenu menu) 614: { 615: // We throw an Error here, just as Sun's JDK does. 616: throw new Error("setHelpMenu() not yet implemented."); 617: } 618: 619: /** 620: * Sets the menu bar's "margin" bound property, which represents 621: * distance between the menubar's border and its menus. 622: * icon. When marging property is modified, PropertyChangeEvent will 623: * be fired to menuBar's PropertyChangeListener's. 624: * 625: * @param m distance between the menubar's border and its menus. 626: * 627: */ 628: public void setMargin(Insets m) 629: { 630: if (m != margin) 631: { 632: Insets oldMargin = margin; 633: margin = m; 634: firePropertyChange("margin", oldMargin, margin); 635: } 636: } 637: 638: /** 639: * Changes menu bar's selection to the specified menu. 640: * This method updates selected index of menu bar's selection model, 641: * which results in a model firing change event. 642: * 643: * @param sel menu to select 644: */ 645: public void setSelected(Component sel) 646: { 647: int index = getComponentIndex(sel); 648: selectionModel.setSelectedIndex(index); 649: } 650: 651: /** 652: * Sets menuBar's selection model to the one specified 653: * 654: * @param model SingleSelectionModel that needs to be set for this menu bar 655: */ 656: public void setSelectionModel(SingleSelectionModel model) 657: { 658: if (selectionModel != model) 659: { 660: SingleSelectionModel oldModel = selectionModel; 661: selectionModel = model; 662: firePropertyChange("model", oldModel, selectionModel); 663: } 664: } 665: 666: /** 667: * Set the "UI" property of the menu bar, which is a look and feel class 668: * responsible for handling menuBar's input events and painting it. 669: * 670: * @param ui The new "UI" property 671: */ 672: public void setUI(MenuBarUI ui) 673: { 674: super.setUI(ui); 675: } 676: 677: /** 678: * Set the "UI" property to a class constructed, via the {@link 679: * UIManager}, from the current look and feel. 680: */ 681: public void updateUI() 682: { 683: setUI((MenuBarUI) UIManager.getUI(this)); 684: } 685: }