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