GNU Classpath (0.95) | |
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: * This method is not implemented and will throw an {@link Error} if called. 302: * 303: * @return This method never returns anything, it throws an exception. 304: */ 305: public JMenu getHelpMenu() 306: { 307: // the following error matches the behaviour of the reference 308: // implementation... 309: throw new Error("getHelpMenu() is not implemented"); 310: } 311: 312: /** 313: * Returns the margin between the menu bar's border and its menus. If the 314: * margin is <code>null</code>, this method returns 315: * <code>new Insets(0, 0, 0, 0)</code>. 316: * 317: * @return The margin (never <code>null</code>). 318: * 319: * @see #setMargin(Insets) 320: */ 321: public Insets getMargin() 322: { 323: if (margin == null) 324: return new Insets(0, 0, 0, 0); 325: else 326: return margin; 327: } 328: 329: /** 330: * Return menu at the specified index. If component at the 331: * specified index is not a menu, then null is returned. 332: * 333: * @param index index to look for the menu 334: * 335: * @return menu at specified index, or null if menu doesn't exist 336: * at the specified index. 337: */ 338: public JMenu getMenu(int index) 339: { 340: if (getComponentAtIndex(index) instanceof JMenu) 341: return (JMenu) getComponentAtIndex(index); 342: else 343: return null; 344: } 345: 346: /** 347: * Returns number of menu's in this menu bar 348: * 349: * @return number of menu's in this menu bar 350: */ 351: public int getMenuCount() 352: { 353: return getComponentCount(); 354: } 355: 356: /** 357: * Returns selection model for this menu bar. SelectionModel 358: * keeps track of the selected menu in the menu bar. Whenever 359: * selected property of selectionModel changes, the ChangeEvent 360: * will be fired its ChangeListeners. 361: * 362: * @return selection model for this menu bar. 363: */ 364: public SingleSelectionModel getSelectionModel() 365: { 366: return selectionModel; 367: } 368: 369: /** 370: * Method of MenuElement interface. It returns subcomponents 371: * of the menu bar, which are all the menues that it contains. 372: * 373: * @return MenuElement[] array containing menues in this menu bar 374: */ 375: public MenuElement[] getSubElements() 376: { 377: MenuElement[] subElements = new MenuElement[getComponentCount()]; 378: 379: int j = 0; 380: boolean doResize = false; 381: MenuElement menu; 382: for (int i = 0; i < getComponentCount(); i++) 383: { 384: menu = getMenu(i); 385: if (menu != null) 386: { 387: subElements[j++] = (MenuElement) menu; 388: } 389: else 390: doResize = true; 391: } 392: 393: if (! doResize) 394: return subElements; 395: else 396: { 397: MenuElement[] subElements2 = new MenuElement[j]; 398: for (int i = 0; i < j; i++) 399: subElements2[i] = subElements[i]; 400: 401: return subElements2; 402: } 403: } 404: 405: /** 406: * Set the "UI" property of the menu bar, which is a look and feel class 407: * responsible for handling the menuBar's input events and painting it. 408: * 409: * @return The current "UI" property 410: */ 411: public MenuBarUI getUI() 412: { 413: return (MenuBarUI) ui; 414: } 415: 416: /** 417: * This method returns a name to identify which look and feel class will be 418: * the UI delegate for the menu bar. 419: * 420: * @return The Look and Feel classID. "MenuBarUI" 421: */ 422: public String getUIClassID() 423: { 424: return "MenuBarUI"; 425: } 426: 427: /** 428: * Returns true if menu bar paints its border and false otherwise 429: * 430: * @return true if menu bar paints its border and false otherwise 431: */ 432: public boolean isBorderPainted() 433: { 434: return borderPainted; 435: } 436: 437: /** 438: * Returns true if some menu in menu bar is selected. 439: * 440: * @return true if some menu in menu bar is selected and false otherwise 441: */ 442: public boolean isSelected() 443: { 444: return selectionModel.isSelected(); 445: } 446: 447: /** 448: * This method does nothing by default. This method is need for the 449: * MenuElement interface to be implemented. 450: * 451: * @param isIncluded true if menuBar is included in the selection 452: * and false otherwise 453: */ 454: public void menuSelectionChanged(boolean isIncluded) 455: { 456: // Do nothing - needed for implementation of MenuElement interface 457: } 458: 459: /** 460: * Paints border of the menu bar, if its borderPainted property is set to 461: * true. 462: * 463: * @param g The graphics context with which to paint the border 464: */ 465: protected void paintBorder(Graphics g) 466: { 467: if (borderPainted) 468: { 469: Border border = getBorder(); 470: if (border != null) 471: getBorder().paintBorder(this, g, 0, 0, getSize(null).width, 472: getSize(null).height); 473: } 474: } 475: 476: /** 477: * A string that describes this JMenuBar. Normally only used 478: * for debugging. 479: * 480: * @return A string describing this JMenuBar 481: */ 482: protected String paramString() 483: { 484: StringBuffer sb = new StringBuffer(); 485: sb.append(super.paramString()); 486: sb.append(",margin="); 487: if (getMargin() != null) 488: sb.append(getMargin()); 489: sb.append(",paintBorder=").append(isBorderPainted()); 490: return sb.toString(); 491: } 492: 493: /** 494: * Process key events forwarded from MenuSelectionManager. This method 495: * doesn't do anything. It is here to conform to the MenuElement interface. 496: * 497: * @param e event forwarded from MenuSelectionManager 498: * @param path path to the menu element from which event was generated 499: * @param manager MenuSelectionManager for the current menu hierarchy 500: * 501: */ 502: public void processKeyEvent(KeyEvent e, MenuElement[] path, 503: MenuSelectionManager manager) 504: { 505: // Do nothing - needed for implementation of MenuElement interface 506: } 507: 508: /** 509: * This method overrides JComponent.processKeyBinding to allow the 510: * JMenuBar to check all the child components (recursiveley) to see 511: * if they'll consume the event. 512: * 513: * @param ks the KeyStroke for the event 514: * @param e the KeyEvent for the event 515: * @param condition the focus condition for the binding 516: * @param pressed true if the key is pressed 517: */ 518: protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, 519: boolean pressed) 520: { 521: // See if the regular JComponent behavior consumes the event 522: if (super.processKeyBinding(ks, e, condition, pressed)) 523: return true; 524: 525: // If not, have to recursively check all the child menu elements to see 526: // if they want it 527: MenuElement[] children = getSubElements(); 528: for (int i = 0; i < children.length; i++) 529: if (processKeyBindingHelper(children[i], ks, e, condition, pressed)) 530: return true; 531: return false; 532: } 533: 534: /** 535: * This is a helper method to recursively check the children of this 536: * JMenuBar to see if they will consume a key event via key bindings. 537: * This is used for menu accelerators. 538: * @param menuElement the menuElement to check (and check all its children) 539: * @param ks the KeyStroke for the event 540: * @param e the KeyEvent that may be consumed 541: * @param condition the focus condition for the binding 542: * @param pressed true if the key was pressed 543: * @return true <code>menuElement</code> or one of its children consume 544: * the event (processKeyBinding returns true for menuElement or one of 545: * its children). 546: */ 547: static boolean processKeyBindingHelper(MenuElement menuElement, KeyStroke ks, 548: KeyEvent e, int condition, 549: boolean pressed) 550: { 551: if (menuElement == null) 552: return false; 553: 554: // First check the menuElement itself, if it's a JComponent 555: if (menuElement instanceof JComponent 556: && ((JComponent) menuElement).processKeyBinding(ks, e, condition, 557: pressed)) 558: return true; 559: 560: // If that didn't consume it, check all the children recursively 561: MenuElement[] children = menuElement.getSubElements(); 562: for (int i = 0; i < children.length; i++) 563: if (processKeyBindingHelper(children[i], ks, e, condition, pressed)) 564: return true; 565: return false; 566: } 567: 568: /** 569: * Process mouse events forwarded from MenuSelectionManager. This method 570: * doesn't do anything. It is here to conform to the MenuElement interface. 571: * 572: * @param event event forwarded from MenuSelectionManager 573: * @param path path to the menu element from which event was generated 574: * @param manager MenuSelectionManager for the current menu hierarchy 575: * 576: */ 577: public void processMouseEvent(MouseEvent event, MenuElement[] path, 578: MenuSelectionManager manager) 579: { 580: // Do nothing - needed for implementation of MenuElement interface 581: } 582: 583: /** 584: * This method overrides removeNotify() in the Container to 585: * unregister this menu bar from the current keyboard manager. 586: */ 587: public void removeNotify() 588: { 589: KeyboardManager.getManager().unregisterJMenuBar(this); 590: super.removeNotify(); 591: } 592: 593: /** 594: * Sets painting status of the border. If 'b' is true then menu bar's 595: * border will be painted, and it will not be painted otherwise. 596: * 597: * @param b indicates if menu bar's border should be painted. 598: */ 599: public void setBorderPainted(boolean b) 600: { 601: if (b != borderPainted) 602: { 603: boolean old = borderPainted; 604: borderPainted = b; 605: firePropertyChange("borderPainted", old, b); 606: revalidate(); 607: repaint(); 608: } 609: } 610: 611: /** 612: * Sets help menu for this menu bar 613: * 614: * @param menu help menu 615: * 616: * @specnote The specification states that this method is not yet implemented 617: * and should throw an exception. 618: */ 619: public void setHelpMenu(JMenu menu) 620: { 621: // We throw an Error here, just as Sun's JDK does. 622: throw new Error("setHelpMenu() not yet implemented."); 623: } 624: 625: /** 626: * Sets the margin between the menu bar's border and its menus (this is a 627: * bound property with the name 'margin'). 628: * 629: * @param m the margin (<code>null</code> permitted). 630: * 631: * @see #getMargin() 632: */ 633: public void setMargin(Insets m) 634: { 635: if (m != margin) 636: { 637: Insets oldMargin = margin; 638: margin = m; 639: firePropertyChange("margin", oldMargin, margin); 640: } 641: } 642: 643: /** 644: * Changes menu bar's selection to the specified menu. 645: * This method updates selected index of menu bar's selection model, 646: * which results in a model firing change event. 647: * 648: * @param sel menu to select 649: */ 650: public void setSelected(Component sel) 651: { 652: int index = getComponentIndex(sel); 653: selectionModel.setSelectedIndex(index); 654: } 655: 656: /** 657: * Sets menuBar's selection model to the one specified 658: * 659: * @param model SingleSelectionModel that needs to be set for this menu bar 660: */ 661: public void setSelectionModel(SingleSelectionModel model) 662: { 663: if (selectionModel != model) 664: { 665: SingleSelectionModel oldModel = selectionModel; 666: selectionModel = model; 667: firePropertyChange("model", oldModel, selectionModel); 668: } 669: } 670: 671: /** 672: * Set the "UI" property of the menu bar, which is a look and feel class 673: * responsible for handling menuBar's input events and painting it. 674: * 675: * @param ui The new "UI" property 676: */ 677: public void setUI(MenuBarUI ui) 678: { 679: super.setUI(ui); 680: } 681: 682: /** 683: * Set the "UI" property to a class constructed, via the {@link 684: * UIManager}, from the current look and feel. 685: */ 686: public void updateUI() 687: { 688: setUI((MenuBarUI) UIManager.getUI(this)); 689: } 690: }
GNU Classpath (0.95) |