Frames | No Frames |
1: /* JMenuItem.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.event.InputEvent; 43: import java.awt.event.KeyEvent; 44: import java.awt.event.MouseEvent; 45: import java.beans.PropertyChangeEvent; 46: import java.beans.PropertyChangeListener; 47: import java.util.EventListener; 48: 49: import javax.accessibility.Accessible; 50: import javax.accessibility.AccessibleContext; 51: import javax.accessibility.AccessibleRole; 52: import javax.swing.event.ChangeEvent; 53: import javax.swing.event.ChangeListener; 54: import javax.swing.event.MenuDragMouseEvent; 55: import javax.swing.event.MenuDragMouseListener; 56: import javax.swing.event.MenuKeyEvent; 57: import javax.swing.event.MenuKeyListener; 58: import javax.swing.plaf.MenuItemUI; 59: 60: /** 61: * JMenuItem represents element in the menu. It inherits most of 62: * its functionality from AbstractButton, however its behavior somewhat 63: * varies from it. JMenuItem fire different kinds of events. 64: * PropertyChangeEvents are fired when menuItems properties are modified; 65: * ChangeEvents are fired when menuItem's state changes and actionEvents are 66: * fired when menu item is selected. In addition to this events menuItem also 67: * fire MenuDragMouseEvent and MenuKeyEvents when mouse is dragged over 68: * the menu item or associated key with menu item is invoked respectively. 69: */ 70: public class JMenuItem extends AbstractButton implements Accessible, 71: MenuElement 72: { 73: private static final long serialVersionUID = -1681004643499461044L; 74: 75: /** Combination of keyboard keys that can be used to activate this menu item */ 76: private KeyStroke accelerator; 77: 78: /** 79: * Creates a new JMenuItem object. 80: */ 81: public JMenuItem() 82: { 83: super(); 84: init(null, null); 85: } 86: 87: /** 88: * Creates a new JMenuItem with the given icon. 89: * 90: * @param icon Icon that will be displayed on the menu item 91: */ 92: public JMenuItem(Icon icon) 93: { 94: // FIXME: The requestedFocusEnabled property should 95: // be set to false, when only icon is set for menu item. 96: super(); 97: init(null, icon); 98: } 99: 100: /** 101: * Creates a new JMenuItem with the given label. 102: * 103: * @param text label for the menu item 104: */ 105: public JMenuItem(String text) 106: { 107: this(text, null); 108: } 109: 110: /** 111: * Creates a new JMenuItem associated with the specified action. 112: * 113: * @param action action for this menu item 114: */ 115: public JMenuItem(Action action) 116: { 117: super(); 118: super.setAction(action); 119: init(null, null); 120: } 121: 122: /** 123: * Creates a new JMenuItem with specified text and icon. 124: * Text is displayed to the left of icon by default. 125: * 126: * @param text label for this menu item 127: * @param icon icon that will be displayed on this menu item 128: */ 129: public JMenuItem(String text, Icon icon) 130: { 131: super(); 132: init(text, icon); 133: } 134: 135: /** 136: * Creates a new JMenuItem object. 137: * 138: * @param text label for this menu item 139: * @param mnemonic - Single key that can be used with a 140: * look-and-feel meta key to activate this menu item. However 141: * menu item should be visible on the screen when mnemonic is used. 142: */ 143: public JMenuItem(String text, int mnemonic) 144: { 145: this(text, null); 146: setMnemonic(mnemonic); 147: } 148: 149: /** 150: * Initializes this menu item 151: * 152: * @param text label for this menu item 153: * @param icon icon to be displayed for this menu item 154: */ 155: protected void init(String text, Icon icon) 156: { 157: super.init(text, icon); 158: setModel(new DefaultButtonModel()); 159: 160: // Initializes properties for this menu item, that are different 161: // from Abstract button properties. 162: /* NOTE: According to java specifications paint_border should be set to false, 163: since menu item should not have a border. However running few java programs 164: it seems that menu items and menues can have a border. Commenting 165: out statement below for now. */ 166: //borderPainted = false; 167: focusPainted = false; 168: horizontalAlignment = JButton.LEFT; 169: horizontalTextPosition = JButton.TRAILING; 170: } 171: 172: /** 173: * Set the "UI" property of the menu item, which is a look and feel class 174: * responsible for handling menuItem's input events and painting it. 175: * 176: * @param ui The new "UI" property 177: */ 178: public void setUI(MenuItemUI ui) 179: { 180: super.setUI(ui); 181: } 182: 183: /** 184: * This method sets this menuItem's UI to the UIManager's default for the 185: * current look and feel. 186: */ 187: public void updateUI() 188: { 189: MenuItemUI mi = ((MenuItemUI) UIManager.getUI(this)); 190: setUI(mi); 191: invalidate(); 192: } 193: 194: /** 195: * This method returns a name to identify which look and feel class will be 196: * the UI delegate for the menuItem. 197: * 198: * @return The Look and Feel classID. "MenuItemUI" 199: */ 200: public String getUIClassID() 201: { 202: return "MenuItemUI"; 203: } 204: 205: /** 206: * Returns true if button's model is armed and false otherwise. The 207: * button model is armed if menu item has focus or it is selected. 208: * 209: * @return $boolean$ true if button's model is armed and false otherwise 210: */ 211: public boolean isArmed() 212: { 213: return getModel().isArmed(); 214: } 215: 216: /** 217: * Sets menuItem's "ARMED" property 218: * 219: * @param armed DOCUMENT ME! 220: */ 221: public void setArmed(boolean armed) 222: { 223: getModel().setArmed(armed); 224: } 225: 226: /** 227: * Enable or disable menu item. When menu item is disabled, 228: * its text and icon are grayed out if they exist. 229: * 230: * @param enabled if true enable menu item, and disable otherwise. 231: */ 232: public void setEnabled(boolean enabled) 233: { 234: super.setEnabled(enabled); 235: } 236: 237: /** 238: * Return accelerator for this menu item. 239: * 240: * @return $KeyStroke$ accelerator for this menu item. 241: */ 242: public KeyStroke getAccelerator() 243: { 244: return accelerator; 245: } 246: 247: /** 248: * Sets the key combination which invokes the menu item's action 249: * listeners without navigating the menu hierarchy. Note that when the 250: * keyboard accelerator is typed, it will work whether or not the 251: * menu is currently displayed. 252: * 253: * @param keystroke accelerator for this menu item. 254: */ 255: public void setAccelerator(KeyStroke keystroke) 256: { 257: KeyStroke old = this.accelerator; 258: this.accelerator = keystroke; 259: firePropertyChange ("accelerator", old, keystroke); 260: } 261: 262: /** 263: * Configures menu items' properties from properties of the specified action. 264: * This method overrides configurePropertiesFromAction from AbstractButton 265: * to also set accelerator property. 266: * 267: * @param action action to configure properties from 268: */ 269: protected void configurePropertiesFromAction(Action action) 270: { 271: super.configurePropertiesFromAction(action); 272: 273: if (! (this instanceof JMenu) && action != null) 274: { 275: setAccelerator((KeyStroke) (action.getValue(Action.ACCELERATOR_KEY))); 276: super.registerKeyboardAction(action, accelerator, 277: JComponent.WHEN_IN_FOCUSED_WINDOW); 278: } 279: } 280: 281: /** 282: * Creates PropertyChangeListener to listen for the changes in action 283: * properties. 284: * 285: * @param action action to listen to for property changes 286: * 287: * @return $PropertyChangeListener$ Listener that listens to changes in 288: * action properties. 289: */ 290: protected PropertyChangeListener createActionPropertyChangeListener(Action action) 291: { 292: return new PropertyChangeListener() 293: { 294: public void propertyChange(PropertyChangeEvent e) 295: { 296: Action act = (Action) (e.getSource()); 297: configurePropertiesFromAction(act); 298: } 299: }; 300: } 301: 302: /** 303: * Process mouse events forwarded from MenuSelectionManager. 304: * 305: * @param event event forwarded from MenuSelectionManager 306: * @param path path to the menu element from which event was generated 307: * @param manager MenuSelectionManager for the current menu hierarchy 308: */ 309: public void processMouseEvent(MouseEvent event, MenuElement[] path, 310: MenuSelectionManager manager) 311: { 312: // Fire MenuDragMouseEvents if mouse is being dragged. 313: boolean dragged 314: = (event.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0; 315: if (dragged) 316: processMenuDragMouseEvent(createMenuDragMouseEvent(event, path, manager)); 317: 318: switch (event.getID()) 319: { 320: case MouseEvent.MOUSE_CLICKED: 321: break; 322: case MouseEvent.MOUSE_ENTERED: 323: if (isRolloverEnabled()) 324: model.setRollover(true); 325: break; 326: case MouseEvent.MOUSE_EXITED: 327: if (isRolloverEnabled()) 328: model.setRollover(false); 329: 330: // for JMenu last element on the path is its popupMenu. 331: // JMenu shouldn't me disarmed. 332: if (! (path[path.length - 1] instanceof JPopupMenu) && ! dragged) 333: setArmed(false); 334: break; 335: case MouseEvent.MOUSE_PRESSED: 336: if ((event.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0) 337: { 338: model.setArmed(true); 339: model.setPressed(true); 340: } 341: break; 342: case MouseEvent.MOUSE_RELEASED: 343: break; 344: case MouseEvent.MOUSE_MOVED: 345: break; 346: case MouseEvent.MOUSE_DRAGGED: 347: break; 348: } 349: } 350: 351: /** 352: * Creates MenuDragMouseEvent. 353: * 354: * @param event MouseEvent that occured while mouse was pressed. 355: * @param path Path the the menu element where the dragging event was 356: * originated 357: * @param manager MenuSelectionManager for the current menu hierarchy. 358: * 359: * @return new MenuDragMouseEvent 360: */ 361: private MenuDragMouseEvent createMenuDragMouseEvent(MouseEvent event, 362: MenuElement[] path, 363: MenuSelectionManager manager) 364: { 365: return new MenuDragMouseEvent((Component) event.getSource(), 366: event.getID(), event.getWhen(), 367: event.getModifiers(), event.getX(), 368: event.getY(), event.getClickCount(), 369: event.isPopupTrigger(), path, manager); 370: } 371: 372: /** 373: * Process key events forwarded from MenuSelectionManager. 374: * 375: * @param event event forwarded from MenuSelectionManager 376: * @param path path to the menu element from which event was generated 377: * @param manager MenuSelectionManager for the current menu hierarchy 378: */ 379: public void processKeyEvent(KeyEvent event, MenuElement[] path, 380: MenuSelectionManager manager) 381: { 382: // Need to implement. 383: } 384: 385: /** 386: * This method fires MenuDragMouseEvents to registered listeners. 387: * Different types of MenuDragMouseEvents are fired depending 388: * on the observed mouse event. 389: * 390: * @param event Mouse 391: */ 392: public void processMenuDragMouseEvent(MenuDragMouseEvent event) 393: { 394: switch (event.getID()) 395: { 396: case MouseEvent.MOUSE_ENTERED: 397: fireMenuDragMouseEntered(event); 398: break; 399: case MouseEvent.MOUSE_EXITED: 400: fireMenuDragMouseExited(event); 401: break; 402: case MouseEvent.MOUSE_DRAGGED: 403: fireMenuDragMouseDragged(event); 404: break; 405: case MouseEvent.MOUSE_RELEASED: 406: fireMenuDragMouseReleased(event); 407: break; 408: } 409: } 410: 411: /** 412: * This method fires MenuKeyEvent to registered listeners. 413: * Different types of MenuKeyEvents are fired depending 414: * on the observed key event. 415: * 416: * @param event DOCUMENT ME! 417: */ 418: public void processMenuKeyEvent(MenuKeyEvent event) 419: { 420: // Need to implement. 421: } 422: 423: /** 424: * Fires MenuDragMouseEvent to all of the menuItem's MouseInputListeners. 425: * 426: * @param event The event signifying that mouse entered menuItem while it was dragged 427: */ 428: protected void fireMenuDragMouseEntered(MenuDragMouseEvent event) 429: { 430: EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class); 431: 432: for (int i = 0; i < ll.length; i++) 433: ((MenuDragMouseListener) ll[i]).menuDragMouseEntered(event); 434: } 435: 436: /** 437: * Fires MenuDragMouseEvent to all of the menuItem's MouseInputListeners. 438: * 439: * @param event The event signifying that mouse has exited menu item, while it was dragged 440: */ 441: protected void fireMenuDragMouseExited(MenuDragMouseEvent event) 442: { 443: EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class); 444: 445: for (int i = 0; i < ll.length; i++) 446: ((MenuDragMouseListener) ll[i]).menuDragMouseExited(event); 447: } 448: 449: /** 450: * Fires MenuDragMouseEvent to all of the menuItem's MouseInputListeners. 451: * 452: * @param event The event signifying that mouse is being dragged over the menuItem 453: */ 454: protected void fireMenuDragMouseDragged(MenuDragMouseEvent event) 455: { 456: EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class); 457: 458: for (int i = 0; i < ll.length; i++) 459: ((MenuDragMouseListener) ll[i]).menuDragMouseDragged(event); 460: } 461: 462: /** 463: * This method fires a MenuDragMouseEvent to all the MenuItem's MouseInputListeners. 464: * 465: * @param event The event signifying that mouse was released while it was dragged over the menuItem 466: */ 467: protected void fireMenuDragMouseReleased(MenuDragMouseEvent event) 468: { 469: EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class); 470: 471: for (int i = 0; i < ll.length; i++) 472: ((MenuDragMouseListener) ll[i]).menuDragMouseReleased(event); 473: } 474: 475: /** 476: * This method fires a MenuKeyEvent to all the MenuItem's MenuKeyListeners. 477: * 478: * @param event The event signifying that key associated with this menu was pressed 479: */ 480: protected void fireMenuKeyPressed(MenuKeyEvent event) 481: { 482: EventListener[] ll = listenerList.getListeners(MenuKeyListener.class); 483: 484: for (int i = 0; i < ll.length; i++) 485: ((MenuKeyListener) ll[i]).menuKeyPressed(event); 486: } 487: 488: /** 489: * This method fires a MenuKeyEvent to all the MenuItem's MenuKeyListeners. 490: * 491: * @param event The event signifying that key associated with this menu was released 492: */ 493: protected void fireMenuKeyReleased(MenuKeyEvent event) 494: { 495: EventListener[] ll = listenerList.getListeners(MenuKeyListener.class); 496: 497: for (int i = 0; i < ll.length; i++) 498: ((MenuKeyListener) ll[i]).menuKeyTyped(event); 499: } 500: 501: /** 502: * This method fires a MenuKeyEvent to all the MenuItem's MenuKeyListeners. 503: * 504: * @param event The event signifying that key associated with this menu was typed. 505: * The key is typed when it was pressed and then released 506: */ 507: protected void fireMenuKeyTyped(MenuKeyEvent event) 508: { 509: EventListener[] ll = listenerList.getListeners(MenuKeyListener.class); 510: 511: for (int i = 0; i < ll.length; i++) 512: ((MenuKeyListener) ll[i]).menuKeyTyped(event); 513: } 514: 515: /** 516: * Method of the MenuElement interface. 517: * This method is invoked by MenuSelectionManager when selection of 518: * this menu item has changed. If this menu item was selected then 519: * arm it's model, and disarm the model otherwise. The menu item 520: * is considered to be selected, and thus highlighted when its model 521: * is armed. 522: * 523: * @param changed indicates selection status of this menu item. If changed is 524: * true then menu item is selected and deselected otherwise. 525: */ 526: public void menuSelectionChanged(boolean changed) 527: { 528: Component parent = this.getParent(); 529: if (changed) 530: { 531: model.setArmed(true); 532: 533: if (parent != null && parent instanceof JPopupMenu) 534: ((JPopupMenu) parent).setSelected(this); 535: } 536: else 537: { 538: model.setArmed(false); 539: 540: if (parent != null && parent instanceof JPopupMenu) 541: ((JPopupMenu) parent).getSelectionModel().clearSelection(); 542: } 543: } 544: 545: /** 546: * Method of the MenuElement interface. 547: * 548: * @return $MenuElement[]$ Returns array of sub-components for this menu 549: * item. By default menuItem doesn't have any subcomponents and so 550: * empty array is returned instead. 551: */ 552: public MenuElement[] getSubElements() 553: { 554: return new MenuElement[0]; 555: } 556: 557: /** 558: * Returns reference to the component that will paint this menu item. 559: * 560: * @return $Component$ Component that will paint this menu item. 561: * Simply returns reference to this menu item. 562: */ 563: public Component getComponent() 564: { 565: return this; 566: } 567: 568: /** 569: * Adds a MenuDragMouseListener to this menu item. When mouse 570: * is dragged over the menu item the MenuDragMouseEvents will be 571: * fired, and these listeners will be called. 572: * 573: * @param listener The new listener to add 574: */ 575: public void addMenuDragMouseListener(MenuDragMouseListener listener) 576: { 577: listenerList.add(MenuDragMouseListener.class, listener); 578: } 579: 580: /** 581: * Removes a MenuDragMouseListener from the menuItem's listener list. 582: * 583: * @param listener The listener to remove 584: */ 585: public void removeMenuDragMouseListener(MenuDragMouseListener listener) 586: { 587: listenerList.remove(MenuDragMouseListener.class, listener); 588: } 589: 590: /** 591: * Returns all added MenuDragMouseListener objects. 592: * 593: * @return an array of listeners 594: * 595: * @since 1.4 596: */ 597: public MenuDragMouseListener[] getMenuDragMouseListeners() 598: { 599: return (MenuDragMouseListener[]) listenerList.getListeners(MenuDragMouseListener.class); 600: } 601: 602: /** 603: * Adds an MenuKeyListener to this menu item. This listener will be 604: * invoked when MenuKeyEvents will be fired by this menu item. 605: * 606: * @param listener The new listener to add 607: */ 608: public void addMenuKeyListener(MenuKeyListener listener) 609: { 610: listenerList.add(MenuKeyListener.class, listener); 611: } 612: 613: /** 614: * Removes an MenuKeyListener from the menuItem's listener list. 615: * 616: * @param listener The listener to remove 617: */ 618: public void removeMenuKeyListener(MenuKeyListener listener) 619: { 620: listenerList.remove(MenuKeyListener.class, listener); 621: } 622: 623: /** 624: * Returns all added MenuKeyListener objects. 625: * 626: * @return an array of listeners 627: * 628: * @since 1.4 629: */ 630: public MenuKeyListener[] getMenuKeyListeners() 631: { 632: return (MenuKeyListener[]) listenerList.getListeners(MenuKeyListener.class); 633: } 634: 635: /** 636: * A string that describes this JMenuItem. Normally only used 637: * for debugging. 638: * 639: * @return A string describing this JMenuItem 640: */ 641: protected String paramString() 642: { 643: return super.paramString(); 644: } 645: 646: public AccessibleContext getAccessibleContext() 647: { 648: if (accessibleContext == null) 649: accessibleContext = new AccessibleJMenuItem(); 650: 651: return accessibleContext; 652: } 653: 654: protected class AccessibleJMenuItem extends AccessibleAbstractButton 655: implements ChangeListener 656: { 657: private static final long serialVersionUID = 6748924232082076534L; 658: 659: /** 660: * Creates a new AccessibleJMenuItem object. 661: */ 662: AccessibleJMenuItem() 663: { 664: //super(component); 665: } 666: 667: public void stateChanged(ChangeEvent event) 668: { 669: // TODO: What should be done here, if anything? 670: } 671: 672: public AccessibleRole getAccessibleRole() 673: { 674: return AccessibleRole.MENU_ITEM; 675: } 676: } 677: }