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