GNU Classpath (0.20) | |
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 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: if (action != null) 121: { 122: String name = (String) action.getValue(Action.NAME); 123: if (name != null) 124: setName(name); 125: 126: KeyStroke accel = (KeyStroke) action.getValue(Action.ACCELERATOR_KEY); 127: if (accel != null) 128: setAccelerator(accel); 129: 130: Integer mnemonic = (Integer) action.getValue(Action.MNEMONIC_KEY); 131: if (mnemonic != null) 132: setMnemonic(mnemonic.intValue()); 133: 134: String command = (String) action.getValue(Action.ACTION_COMMAND_KEY); 135: if (command != null) 136: setActionCommand(command); 137: } 138: } 139: 140: /** 141: * Creates a new JMenuItem with specified text and icon. 142: * Text is displayed to the left of icon by default. 143: * 144: * @param text label for this menu item 145: * @param icon icon that will be displayed on this menu item 146: */ 147: public JMenuItem(String text, Icon icon) 148: { 149: super(); 150: init(text, icon); 151: } 152: 153: /** 154: * Creates a new JMenuItem object. 155: * 156: * @param text label for this menu item 157: * @param mnemonic - Single key that can be used with a 158: * look-and-feel meta key to activate this menu item. However 159: * menu item should be visible on the screen when mnemonic is used. 160: */ 161: public JMenuItem(String text, int mnemonic) 162: { 163: this(text, null); 164: setMnemonic(mnemonic); 165: } 166: 167: /** 168: * Initializes this menu item 169: * 170: * @param text label for this menu item 171: * @param icon icon to be displayed for this menu item 172: */ 173: protected void init(String text, Icon icon) 174: { 175: super.init(text, icon); 176: setModel(new DefaultButtonModel()); 177: 178: // Initializes properties for this menu item, that are different 179: // from Abstract button properties. 180: /* NOTE: According to java specifications paint_border should be set to false, 181: since menu item should not have a border. However running few java programs 182: it seems that menu items and menues can have a border. Commenting 183: out statement below for now. */ 184: //borderPainted = false; 185: focusPainted = false; 186: horizontalAlignment = JButton.LEFT; 187: horizontalTextPosition = JButton.TRAILING; 188: } 189: 190: /** 191: * Set the "UI" property of the menu item, which is a look and feel class 192: * responsible for handling menuItem's input events and painting it. 193: * 194: * @param ui The new "UI" property 195: */ 196: public void setUI(MenuItemUI ui) 197: { 198: super.setUI(ui); 199: } 200: 201: /** 202: * This method sets this menuItem's UI to the UIManager's default for the 203: * current look and feel. 204: */ 205: public void updateUI() 206: { 207: MenuItemUI mi = ((MenuItemUI) UIManager.getUI(this)); 208: setUI(mi); 209: invalidate(); 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: // Need to implement. 402: } 403: 404: /** 405: * This method fires MenuDragMouseEvents to registered listeners. 406: * Different types of MenuDragMouseEvents are fired depending 407: * on the observed mouse event. 408: * 409: * @param event Mouse 410: */ 411: public void processMenuDragMouseEvent(MenuDragMouseEvent event) 412: { 413: switch (event.getID()) 414: { 415: case MouseEvent.MOUSE_ENTERED: 416: fireMenuDragMouseEntered(event); 417: break; 418: case MouseEvent.MOUSE_EXITED: 419: fireMenuDragMouseExited(event); 420: break; 421: case MouseEvent.MOUSE_DRAGGED: 422: fireMenuDragMouseDragged(event); 423: break; 424: case MouseEvent.MOUSE_RELEASED: 425: fireMenuDragMouseReleased(event); 426: break; 427: } 428: } 429: 430: /** 431: * This method fires MenuKeyEvent to registered listeners. 432: * Different types of MenuKeyEvents are fired depending 433: * on the observed key event. 434: * 435: * @param event DOCUMENT ME! 436: */ 437: public void processMenuKeyEvent(MenuKeyEvent event) 438: { 439: // Need to implement. 440: } 441: 442: /** 443: * Fires MenuDragMouseEvent to all of the menuItem's MouseInputListeners. 444: * 445: * @param event The event signifying that mouse entered menuItem while it was dragged 446: */ 447: protected void fireMenuDragMouseEntered(MenuDragMouseEvent event) 448: { 449: EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class); 450: 451: for (int i = 0; i < ll.length; i++) 452: ((MenuDragMouseListener) ll[i]).menuDragMouseEntered(event); 453: } 454: 455: /** 456: * Fires MenuDragMouseEvent to all of the menuItem's MouseInputListeners. 457: * 458: * @param event The event signifying that mouse has exited menu item, while it was dragged 459: */ 460: protected void fireMenuDragMouseExited(MenuDragMouseEvent event) 461: { 462: EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class); 463: 464: for (int i = 0; i < ll.length; i++) 465: ((MenuDragMouseListener) ll[i]).menuDragMouseExited(event); 466: } 467: 468: /** 469: * Fires MenuDragMouseEvent to all of the menuItem's MouseInputListeners. 470: * 471: * @param event The event signifying that mouse is being dragged over the menuItem 472: */ 473: protected void fireMenuDragMouseDragged(MenuDragMouseEvent event) 474: { 475: EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class); 476: 477: for (int i = 0; i < ll.length; i++) 478: ((MenuDragMouseListener) ll[i]).menuDragMouseDragged(event); 479: } 480: 481: /** 482: * This method fires a MenuDragMouseEvent to all the MenuItem's MouseInputListeners. 483: * 484: * @param event The event signifying that mouse was released while it was dragged over the menuItem 485: */ 486: protected void fireMenuDragMouseReleased(MenuDragMouseEvent event) 487: { 488: EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class); 489: 490: for (int i = 0; i < ll.length; i++) 491: ((MenuDragMouseListener) ll[i]).menuDragMouseReleased(event); 492: } 493: 494: /** 495: * This method fires a MenuKeyEvent to all the MenuItem's MenuKeyListeners. 496: * 497: * @param event The event signifying that key associated with this menu was pressed 498: */ 499: protected void fireMenuKeyPressed(MenuKeyEvent event) 500: { 501: EventListener[] ll = listenerList.getListeners(MenuKeyListener.class); 502: 503: for (int i = 0; i < ll.length; i++) 504: ((MenuKeyListener) ll[i]).menuKeyPressed(event); 505: } 506: 507: /** 508: * This method fires a MenuKeyEvent to all the MenuItem's MenuKeyListeners. 509: * 510: * @param event The event signifying that key associated with this menu was released 511: */ 512: protected void fireMenuKeyReleased(MenuKeyEvent event) 513: { 514: EventListener[] ll = listenerList.getListeners(MenuKeyListener.class); 515: 516: for (int i = 0; i < ll.length; i++) 517: ((MenuKeyListener) ll[i]).menuKeyTyped(event); 518: } 519: 520: /** 521: * This method fires a MenuKeyEvent to all the MenuItem's MenuKeyListeners. 522: * 523: * @param event The event signifying that key associated with this menu was typed. 524: * The key is typed when it was pressed and then released 525: */ 526: protected void fireMenuKeyTyped(MenuKeyEvent event) 527: { 528: EventListener[] ll = listenerList.getListeners(MenuKeyListener.class); 529: 530: for (int i = 0; i < ll.length; i++) 531: ((MenuKeyListener) ll[i]).menuKeyTyped(event); 532: } 533: 534: /** 535: * Method of the MenuElement interface. 536: * This method is invoked by MenuSelectionManager when selection of 537: * this menu item has changed. If this menu item was selected then 538: * arm it's model, and disarm the model otherwise. The menu item 539: * is considered to be selected, and thus highlighted when its model 540: * is armed. 541: * 542: * @param changed indicates selection status of this menu item. If changed is 543: * true then menu item is selected and deselected otherwise. 544: */ 545: public void menuSelectionChanged(boolean changed) 546: { 547: Component parent = this.getParent(); 548: if (changed) 549: { 550: model.setArmed(true); 551: 552: if (parent != null && parent instanceof JPopupMenu) 553: ((JPopupMenu) parent).setSelected(this); 554: } 555: else 556: { 557: model.setArmed(false); 558: 559: if (parent != null && parent instanceof JPopupMenu) 560: ((JPopupMenu) parent).getSelectionModel().clearSelection(); 561: } 562: } 563: 564: /** 565: * Method of the MenuElement interface. 566: * 567: * @return $MenuElement[]$ Returns array of sub-components for this menu 568: * item. By default menuItem doesn't have any subcomponents and so 569: * empty array is returned instead. 570: */ 571: public MenuElement[] getSubElements() 572: { 573: return new MenuElement[0]; 574: } 575: 576: /** 577: * Returns reference to the component that will paint this menu item. 578: * 579: * @return $Component$ Component that will paint this menu item. 580: * Simply returns reference to this menu item. 581: */ 582: public Component getComponent() 583: { 584: return this; 585: } 586: 587: /** 588: * Adds a MenuDragMouseListener to this menu item. When mouse 589: * is dragged over the menu item the MenuDragMouseEvents will be 590: * fired, and these listeners will be called. 591: * 592: * @param listener The new listener to add 593: */ 594: public void addMenuDragMouseListener(MenuDragMouseListener listener) 595: { 596: listenerList.add(MenuDragMouseListener.class, listener); 597: } 598: 599: /** 600: * Removes a MenuDragMouseListener from the menuItem's listener list. 601: * 602: * @param listener The listener to remove 603: */ 604: public void removeMenuDragMouseListener(MenuDragMouseListener listener) 605: { 606: listenerList.remove(MenuDragMouseListener.class, listener); 607: } 608: 609: /** 610: * Returns all added MenuDragMouseListener objects. 611: * 612: * @return an array of listeners 613: * 614: * @since 1.4 615: */ 616: public MenuDragMouseListener[] getMenuDragMouseListeners() 617: { 618: return (MenuDragMouseListener[]) listenerList.getListeners(MenuDragMouseListener.class); 619: } 620: 621: /** 622: * Adds an MenuKeyListener to this menu item. This listener will be 623: * invoked when MenuKeyEvents will be fired by this menu item. 624: * 625: * @param listener The new listener to add 626: */ 627: public void addMenuKeyListener(MenuKeyListener listener) 628: { 629: listenerList.add(MenuKeyListener.class, listener); 630: } 631: 632: /** 633: * Removes an MenuKeyListener from the menuItem's listener list. 634: * 635: * @param listener The listener to remove 636: */ 637: public void removeMenuKeyListener(MenuKeyListener listener) 638: { 639: listenerList.remove(MenuKeyListener.class, listener); 640: } 641: 642: /** 643: * Returns all added MenuKeyListener objects. 644: * 645: * @return an array of listeners 646: * 647: * @since 1.4 648: */ 649: public MenuKeyListener[] getMenuKeyListeners() 650: { 651: return (MenuKeyListener[]) listenerList.getListeners(MenuKeyListener.class); 652: } 653: 654: /** 655: * A string that describes this JMenuItem. Normally only used 656: * for debugging. 657: * 658: * @return A string describing this JMenuItem 659: */ 660: protected String paramString() 661: { 662: return super.paramString(); 663: } 664: 665: public AccessibleContext getAccessibleContext() 666: { 667: if (accessibleContext == null) 668: accessibleContext = new AccessibleJMenuItem(); 669: 670: return accessibleContext; 671: } 672: 673: protected class AccessibleJMenuItem extends AccessibleAbstractButton 674: implements ChangeListener 675: { 676: private static final long serialVersionUID = 6748924232082076534L; 677: 678: /** 679: * Creates a new AccessibleJMenuItem object. 680: */ 681: AccessibleJMenuItem() 682: { 683: //super(component); 684: } 685: 686: public void stateChanged(ChangeEvent event) 687: { 688: // TODO: What should be done here, if anything? 689: } 690: 691: public AccessibleRole getAccessibleRole() 692: { 693: return AccessibleRole.MENU_ITEM; 694: } 695: } 696: }
GNU Classpath (0.20) |