GNU Classpath (0.91) | |
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: for (int i = 0; i < getComponentCount(); i++) 374: subElements[i] = (MenuElement) getMenu(i); 375: 376: return subElements; 377: } 378: 379: /** 380: * Set the "UI" property of the menu bar, which is a look and feel class 381: * responsible for handling the menuBar's input events and painting it. 382: * 383: * @return The current "UI" property 384: */ 385: public MenuBarUI getUI() 386: { 387: return (MenuBarUI) ui; 388: } 389: 390: /** 391: * This method returns a name to identify which look and feel class will be 392: * the UI delegate for the menu bar. 393: * 394: * @return The Look and Feel classID. "MenuBarUI" 395: */ 396: public String getUIClassID() 397: { 398: return "MenuBarUI"; 399: } 400: 401: /** 402: * Returns true if menu bar paints its border and false otherwise 403: * 404: * @return true if menu bar paints its border and false otherwise 405: */ 406: public boolean isBorderPainted() 407: { 408: return borderPainted; 409: } 410: 411: /** 412: * Returns true if some menu in menu bar is selected. 413: * 414: * @return true if some menu in menu bar is selected and false otherwise 415: */ 416: public boolean isSelected() 417: { 418: return selectionModel.isSelected(); 419: } 420: 421: /** 422: * This method does nothing by default. This method is need for the 423: * MenuElement interface to be implemented. 424: * 425: * @param isIncluded true if menuBar is included in the selection 426: * and false otherwise 427: */ 428: public void menuSelectionChanged(boolean isIncluded) 429: { 430: // Do nothing - needed for implementation of MenuElement interface 431: } 432: 433: /** 434: * Paints border of the menu bar, if its borderPainted property is set to 435: * true. 436: * 437: * @param g The graphics context with which to paint the border 438: */ 439: protected void paintBorder(Graphics g) 440: { 441: if (borderPainted) 442: { 443: Border border = getBorder(); 444: if (border != null) 445: getBorder().paintBorder(this, g, 0, 0, getSize(null).width, 446: getSize(null).height); 447: } 448: } 449: 450: /** 451: * A string that describes this JMenuBar. Normally only used 452: * for debugging. 453: * 454: * @return A string describing this JMenuBar 455: */ 456: protected String paramString() 457: { 458: StringBuffer sb = new StringBuffer(); 459: sb.append(super.paramString()); 460: sb.append(",margin="); 461: if (getMargin() != null) 462: sb.append(getMargin()); 463: sb.append(",paintBorder=").append(isBorderPainted()); 464: return sb.toString(); 465: } 466: 467: /** 468: * Process key events forwarded from MenuSelectionManager. This method 469: * doesn't do anything. It is here to conform to the MenuElement interface. 470: * 471: * @param e event forwarded from MenuSelectionManager 472: * @param path path to the menu element from which event was generated 473: * @param manager MenuSelectionManager for the current menu hierarchy 474: * 475: */ 476: public void processKeyEvent(KeyEvent e, MenuElement[] path, 477: MenuSelectionManager manager) 478: { 479: // Do nothing - needed for implementation of MenuElement interface 480: } 481: 482: /** 483: * This method overrides JComponent.processKeyBinding to allow the 484: * JMenuBar to check all the child components (recursiveley) to see 485: * if they'll consume the event. 486: * 487: * @param ks the KeyStroke for the event 488: * @param e the KeyEvent for the event 489: * @param condition the focus condition for the binding 490: * @param pressed true if the key is pressed 491: */ 492: protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, 493: boolean pressed) 494: { 495: // See if the regular JComponent behavior consumes the event 496: if (super.processKeyBinding(ks, e, condition, pressed)) 497: return true; 498: 499: // If not, have to recursively check all the child menu elements to see 500: // if they want it 501: MenuElement[] children = getSubElements(); 502: for (int i = 0; i < children.length; i++) 503: if (processKeyBindingHelper(children[i], ks, e, condition, pressed)) 504: return true; 505: return false; 506: } 507: 508: /** 509: * This is a helper method to recursively check the children of this 510: * JMenuBar to see if they will consume a key event via key bindings. 511: * This is used for menu accelerators. 512: * @param menuElement the menuElement to check (and check all its children) 513: * @param ks the KeyStroke for the event 514: * @param e the KeyEvent that may be consumed 515: * @param condition the focus condition for the binding 516: * @param pressed true if the key was pressed 517: * @return true <code>menuElement</code> or one of its children consume 518: * the event (processKeyBinding returns true for menuElement or one of 519: * its children). 520: */ 521: static boolean processKeyBindingHelper(MenuElement menuElement, KeyStroke ks, 522: KeyEvent e, int condition, 523: boolean pressed) 524: { 525: // First check the menuElement itself, if it's a JComponent 526: if (menuElement instanceof JComponent 527: && ((JComponent) menuElement).processKeyBinding(ks, e, condition, 528: pressed)) 529: return true; 530: 531: // If that didn't consume it, check all the children recursively 532: MenuElement[] children = menuElement.getSubElements(); 533: for (int i = 0; i < children.length; i++) 534: if (processKeyBindingHelper(children[i], ks, e, condition, pressed)) 535: return true; 536: return false; 537: } 538: 539: /** 540: * Process mouse events forwarded from MenuSelectionManager. This method 541: * doesn't do anything. It is here to conform to the MenuElement interface. 542: * 543: * @param event event forwarded from MenuSelectionManager 544: * @param path path to the menu element from which event was generated 545: * @param manager MenuSelectionManager for the current menu hierarchy 546: * 547: */ 548: public void processMouseEvent(MouseEvent event, MenuElement[] path, 549: MenuSelectionManager manager) 550: { 551: // Do nothing - needed for implementation of MenuElement interface 552: } 553: 554: /** 555: * This method overrides removeNotify() in the Container to 556: * unregister this menu bar from the current keyboard manager. 557: */ 558: public void removeNotify() 559: { 560: KeyboardManager.getManager().unregisterJMenuBar(this); 561: super.removeNotify(); 562: } 563: 564: /** 565: * Sets painting status of the border. If 'b' is true then menu bar's 566: * border will be painted, and it will not be painted otherwise. 567: * 568: * @param b indicates if menu bar's border should be painted. 569: */ 570: public void setBorderPainted(boolean b) 571: { 572: if (b != borderPainted) 573: { 574: boolean old = borderPainted; 575: borderPainted = b; 576: firePropertyChange("borderPainted", old, b); 577: revalidate(); 578: repaint(); 579: } 580: } 581: 582: /** 583: * Sets help menu for this menu bar 584: * 585: * @param menu help menu 586: * 587: * @specnote The specification states that this method is not yet implemented 588: * and should throw an exception. 589: */ 590: public void setHelpMenu(JMenu menu) 591: { 592: // We throw an Error here, just as Sun's JDK does. 593: throw new Error("setHelpMenu() not yet implemented."); 594: } 595: 596: /** 597: * Sets the menu bar's "margin" bound property, which represents 598: * distance between the menubar's border and its menus. 599: * icon. When marging property is modified, PropertyChangeEvent will 600: * be fired to menuBar's PropertyChangeListener's. 601: * 602: * @param m distance between the menubar's border and its menus. 603: * 604: */ 605: public void setMargin(Insets m) 606: { 607: if (m != margin) 608: { 609: Insets oldMargin = margin; 610: margin = m; 611: firePropertyChange("margin", oldMargin, margin); 612: } 613: } 614: 615: /** 616: * Changes menu bar's selection to the specified menu. 617: * This method updates selected index of menu bar's selection model, 618: * which results in a model firing change event. 619: * 620: * @param sel menu to select 621: */ 622: public void setSelected(Component sel) 623: { 624: int index = getComponentIndex(sel); 625: selectionModel.setSelectedIndex(index); 626: } 627: 628: /** 629: * Sets menuBar's selection model to the one specified 630: * 631: * @param model SingleSelectionModel that needs to be set for this menu bar 632: */ 633: public void setSelectionModel(SingleSelectionModel model) 634: { 635: if (selectionModel != model) 636: { 637: SingleSelectionModel oldModel = selectionModel; 638: selectionModel = model; 639: firePropertyChange("model", oldModel, selectionModel); 640: } 641: } 642: 643: /** 644: * Set the "UI" property of the menu bar, which is a look and feel class 645: * responsible for handling menuBar's input events and painting it. 646: * 647: * @param ui The new "UI" property 648: */ 649: public void setUI(MenuBarUI ui) 650: { 651: super.setUI(ui); 652: } 653: 654: /** 655: * Set the "UI" property to a class constructed, via the {@link 656: * UIManager}, from the current look and feel. 657: */ 658: public void updateUI() 659: { 660: setUI((MenuBarUI) UIManager.getUI(this)); 661: } 662: }
GNU Classpath (0.91) |