1 /*
   2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.swing.plaf.basic;
  27 
  28 import sun.swing.DefaultLookup;
  29 import sun.swing.UIAction;
  30 import java.awt.*;
  31 import java.awt.event.*;
  32 import java.beans.*;
  33 import javax.swing.*;
  34 import javax.swing.event.*;
  35 import javax.swing.plaf.*;
  36 import javax.swing.border.*;
  37 import java.util.Arrays;
  38 import java.util.ArrayList;
  39 
  40 
  41 /**
  42  * A default L&F implementation of MenuUI.  This implementation
  43  * is a "combined" view/controller.
  44  *
  45  * @author Georges Saab
  46  * @author David Karlton
  47  * @author Arnaud Weber
  48  */
  49 public class BasicMenuUI extends BasicMenuItemUI
  50 {
  51     /**
  52      * The instance of {@code ChangeListener}.
  53      */
  54     protected ChangeListener         changeListener;
  55 
  56     /**
  57      * The instance of {@code MenuListener}.
  58      */
  59     protected MenuListener           menuListener;
  60 
  61     private int lastMnemonic = 0;
  62 
  63     /** Uses as the parent of the windowInputMap when selected. */
  64     private InputMap selectedWindowInputMap;
  65 
  66     /* diagnostic aids -- should be false for production builds. */
  67     private static final boolean TRACE =   false; // trace creates and disposes
  68     private static final boolean VERBOSE = false; // show reuse hits/misses
  69     private static final boolean DEBUG =   false;  // show bad params, misc.
  70 
  71     private static boolean crossMenuMnemonic = true;
  72 
  73     /**
  74      * Constructs a new instance of {@code BasicMenuUI}.
  75      *
  76      * @param x a component
  77      * @return a new instance of {@code BasicMenuUI}
  78      */
  79     public static ComponentUI createUI(JComponent x) {
  80         return new BasicMenuUI();
  81     }
  82 
  83     static void loadActionMap(LazyActionMap map) {
  84         BasicMenuItemUI.loadActionMap(map);
  85         map.put(new Actions(Actions.SELECT, null, true));
  86     }
  87 
  88 
  89     protected void installDefaults() {
  90         super.installDefaults();
  91         updateDefaultBackgroundColor();
  92         ((JMenu)menuItem).setDelay(200);
  93         crossMenuMnemonic = UIManager.getBoolean("Menu.crossMenuMnemonic");
  94     }
  95 
  96     protected String getPropertyPrefix() {
  97         return "Menu";
  98     }
  99 
 100     protected void installListeners() {
 101         super.installListeners();
 102 
 103         if (changeListener == null)
 104             changeListener = createChangeListener(menuItem);
 105 
 106         if (changeListener != null)
 107             menuItem.addChangeListener(changeListener);
 108 
 109         if (menuListener == null)
 110             menuListener = createMenuListener(menuItem);
 111 
 112         if (menuListener != null)
 113             ((JMenu)menuItem).addMenuListener(menuListener);
 114     }
 115 
 116     protected void installKeyboardActions() {
 117         super.installKeyboardActions();
 118         updateMnemonicBinding();
 119     }
 120 
 121     void installLazyActionMap() {
 122         LazyActionMap.installLazyActionMap(menuItem, BasicMenuUI.class,
 123                                            getPropertyPrefix() + ".actionMap");
 124     }
 125 
 126     @SuppressWarnings("deprecation")
 127     void updateMnemonicBinding() {
 128         int mnemonic = menuItem.getModel().getMnemonic();
 129         int[] shortcutKeys = (int[])DefaultLookup.get(menuItem, this,
 130                                                    "Menu.shortcutKeys");
 131         if (shortcutKeys == null) {
 132             shortcutKeys = new int[] {KeyEvent.ALT_MASK};
 133         }
 134         if (mnemonic == lastMnemonic) {
 135             return;
 136         }
 137         InputMap windowInputMap = SwingUtilities.getUIInputMap(
 138                        menuItem, JComponent.WHEN_IN_FOCUSED_WINDOW);
 139         if (lastMnemonic != 0 && windowInputMap != null) {
 140             for (int shortcutKey : shortcutKeys) {
 141                 windowInputMap.remove(KeyStroke.getKeyStroke
 142                         (lastMnemonic, shortcutKey, false));
 143             }
 144         }
 145         if (mnemonic != 0) {
 146             if (windowInputMap == null) {
 147                 windowInputMap = createInputMap(JComponent.
 148                                               WHEN_IN_FOCUSED_WINDOW);
 149                 SwingUtilities.replaceUIInputMap(menuItem, JComponent.
 150                                        WHEN_IN_FOCUSED_WINDOW, windowInputMap);
 151             }
 152             for (int shortcutKey : shortcutKeys) {
 153                 windowInputMap.put(KeyStroke.getKeyStroke(mnemonic,
 154                         shortcutKey, false), "selectMenu");
 155             }
 156         }
 157         lastMnemonic = mnemonic;
 158     }
 159 
 160     protected void uninstallKeyboardActions() {
 161         super.uninstallKeyboardActions();
 162         lastMnemonic = 0;
 163     }
 164 
 165     protected MouseInputListener createMouseInputListener(JComponent c) {
 166         return getHandler();
 167     }
 168 
 169     /**
 170      * Returns an instance of {@code MenuListener}.
 171      *
 172      * @param c a component
 173      * @return an instance of {@code MenuListener}
 174      */
 175     protected MenuListener createMenuListener(JComponent c) {
 176         return null;
 177     }
 178 
 179     /**
 180      * Returns an instance of {@code ChangeListener}.
 181      *
 182      * @param c a component
 183      * @return an instance of {@code ChangeListener}
 184      */
 185     protected ChangeListener createChangeListener(JComponent c) {
 186         return null;
 187     }
 188 
 189     protected PropertyChangeListener createPropertyChangeListener(JComponent c) {
 190         return getHandler();
 191     }
 192 
 193     BasicMenuItemUI.Handler getHandler() {
 194         if (handler == null) {
 195             handler = new Handler();
 196         }
 197         return handler;
 198     }
 199 
 200     protected void uninstallDefaults() {
 201         menuItem.setArmed(false);
 202         menuItem.setSelected(false);
 203         menuItem.resetKeyboardActions();
 204         super.uninstallDefaults();
 205     }
 206 
 207     protected void uninstallListeners() {
 208         super.uninstallListeners();
 209 
 210         if (changeListener != null)
 211             menuItem.removeChangeListener(changeListener);
 212 
 213         if (menuListener != null)
 214             ((JMenu)menuItem).removeMenuListener(menuListener);
 215 
 216         changeListener = null;
 217         menuListener = null;
 218         handler = null;
 219     }
 220 
 221     protected MenuDragMouseListener createMenuDragMouseListener(JComponent c) {
 222         return getHandler();
 223     }
 224 
 225     protected MenuKeyListener createMenuKeyListener(JComponent c) {
 226         return (MenuKeyListener)getHandler();
 227     }
 228 
 229     public Dimension getMinimumSize(JComponent c) {
 230         return (((JMenu)menuItem).isTopLevelMenu() == true) ?
 231             c.getPreferredSize() : null;
 232     }
 233 
 234     public Dimension getMaximumSize(JComponent c) {
 235         if (((JMenu)menuItem).isTopLevelMenu() == true) {
 236             Dimension d = c.getPreferredSize();
 237             return new Dimension(d.width, Short.MAX_VALUE);
 238         }
 239         return null;
 240     }
 241 
 242     /**
 243      * Sets timer to the {@code menu}.
 244      *
 245      * @param menu an instance of {@code JMenu}.
 246      */
 247     protected void setupPostTimer(JMenu menu) {
 248         Timer timer = new Timer(menu.getDelay(), new Actions(
 249                                     Actions.SELECT, menu,false));
 250         timer.setRepeats(false);
 251         timer.start();
 252     }
 253 
 254     private static void appendPath(MenuElement[] path, MenuElement elem) {
 255         MenuElement newPath[] = new MenuElement[path.length+1];
 256         System.arraycopy(path, 0, newPath, 0, path.length);
 257         newPath[path.length] = elem;
 258         MenuSelectionManager.defaultManager().setSelectedPath(newPath);
 259     }
 260 
 261     private static class Actions extends UIAction {
 262         private static final String SELECT = "selectMenu";
 263 
 264         // NOTE: This will be null if the action is registered in the
 265         // ActionMap. For the timer use it will be non-null.
 266         private JMenu menu;
 267         private boolean force=false;
 268 
 269         Actions(String key, JMenu menu, boolean shouldForce) {
 270             super(key);
 271             this.menu = menu;
 272             this.force = shouldForce;
 273         }
 274 
 275         private JMenu getMenu(ActionEvent e) {
 276             if (e.getSource() instanceof JMenu) {
 277                 return (JMenu)e.getSource();
 278             }
 279             return menu;
 280         }
 281 
 282         public void actionPerformed(ActionEvent e) {
 283             JMenu menu = getMenu(e);
 284             if (!crossMenuMnemonic) {
 285                 JPopupMenu pm = BasicPopupMenuUI.getLastPopup();
 286                 if (pm != null && pm != menu.getParent()) {
 287                     return;
 288                 }
 289             }
 290 
 291             final MenuSelectionManager defaultManager = MenuSelectionManager.defaultManager();
 292             if(force) {
 293                 Container cnt = menu.getParent();
 294                 if(cnt != null && cnt instanceof JMenuBar) {
 295                     MenuElement me[];
 296                     MenuElement subElements[];
 297 
 298                     subElements = menu.getPopupMenu().getSubElements();
 299                     if(subElements.length > 0) {
 300                         me = new MenuElement[4];
 301                         me[0] = (MenuElement) cnt;
 302                         me[1] = menu;
 303                         me[2] = menu.getPopupMenu();
 304                         me[3] = subElements[0];
 305                     } else {
 306                         me = new MenuElement[3];
 307                         me[0] = (MenuElement)cnt;
 308                         me[1] = menu;
 309                         me[2] = menu.getPopupMenu();
 310                     }
 311                     defaultManager.setSelectedPath(me);
 312                 }
 313             } else {
 314                 MenuElement path[] = defaultManager.getSelectedPath();
 315                 if(path.length > 0 && path[path.length-1] == menu) {
 316                     appendPath(path, menu.getPopupMenu());
 317                 }
 318             }
 319         }
 320 
 321         @Override
 322         public boolean accept(Object c) {
 323             if (c instanceof JMenu) {
 324                 return ((JMenu)c).isEnabled();
 325             }
 326             return true;
 327         }
 328     }
 329 
 330     /*
 331      * Set the background color depending on whether this is a toplevel menu
 332      * in a menubar or a submenu of another menu.
 333      */
 334     private void updateDefaultBackgroundColor() {
 335         if (!UIManager.getBoolean("Menu.useMenuBarBackgroundForTopLevel")) {
 336            return;
 337         }
 338         JMenu menu = (JMenu)menuItem;
 339         if (menu.getBackground() instanceof UIResource) {
 340             if (menu.isTopLevelMenu()) {
 341                 menu.setBackground(UIManager.getColor("MenuBar.background"));
 342             } else {
 343                 menu.setBackground(UIManager.getColor(getPropertyPrefix() + ".background"));
 344             }
 345         }
 346     }
 347 
 348     /**
 349      * Instantiated and used by a menu item to handle the current menu selection
 350      * from mouse events. A MouseInputHandler processes and forwards all mouse events
 351      * to a shared instance of the MenuSelectionManager.
 352      * <p>
 353      * This class is protected so that it can be subclassed by other look and
 354      * feels to implement their own mouse handling behavior. All overridden
 355      * methods should call the parent methods so that the menu selection
 356      * is correct.
 357      *
 358      * @see javax.swing.MenuSelectionManager
 359      * @since 1.4
 360      */
 361     protected class MouseInputHandler implements MouseInputListener {
 362         // NOTE: This class exists only for backward compatibility. All
 363         // its functionality has been moved into Handler. If you need to add
 364         // new functionality add it to the Handler, but make sure this
 365         // class calls into the Handler.
 366 
 367         public void mouseClicked(MouseEvent e) {
 368             getHandler().mouseClicked(e);
 369         }
 370 
 371         /**
 372          * Invoked when the mouse has been clicked on the menu. This
 373          * method clears or sets the selection path of the
 374          * MenuSelectionManager.
 375          *
 376          * @param e the mouse event
 377          */
 378         public void mousePressed(MouseEvent e) {
 379             getHandler().mousePressed(e);
 380         }
 381 
 382         /**
 383          * Invoked when the mouse has been released on the menu. Delegates the
 384          * mouse event to the MenuSelectionManager.
 385          *
 386          * @param e the mouse event
 387          */
 388         public void mouseReleased(MouseEvent e) {
 389             getHandler().mouseReleased(e);
 390         }
 391 
 392         /**
 393          * Invoked when the cursor enters the menu. This method sets the selected
 394          * path for the MenuSelectionManager and handles the case
 395          * in which a menu item is used to pop up an additional menu, as in a
 396          * hierarchical menu system.
 397          *
 398          * @param e the mouse event; not used
 399          */
 400         public void mouseEntered(MouseEvent e) {
 401             getHandler().mouseEntered(e);
 402         }
 403         public void mouseExited(MouseEvent e) {
 404             getHandler().mouseExited(e);
 405         }
 406 
 407         /**
 408          * Invoked when a mouse button is pressed on the menu and then dragged.
 409          * Delegates the mouse event to the MenuSelectionManager.
 410          *
 411          * @param e the mouse event
 412          * @see java.awt.event.MouseMotionListener#mouseDragged
 413          */
 414         public void mouseDragged(MouseEvent e) {
 415             getHandler().mouseDragged(e);
 416         }
 417 
 418         public void mouseMoved(MouseEvent e) {
 419             getHandler().mouseMoved(e);
 420         }
 421     }
 422 
 423     /**
 424      * As of Java 2 platform 1.4, this previously undocumented class
 425      * is now obsolete. KeyBindings are now managed by the popup menu.
 426      */
 427     public class ChangeHandler implements ChangeListener {
 428         /**
 429          * The instance of {@code JMenu}.
 430          */
 431         public JMenu    menu;
 432 
 433         /**
 434          * The instance of {@code BasicMenuUI}.
 435          */
 436         public BasicMenuUI ui;
 437 
 438         /**
 439          * {@code true} if an item of popup menu is selected.
 440          */
 441         public boolean  isSelected = false;
 442 
 443         /**
 444          * The component that was focused.
 445          */
 446         public Component wasFocused;
 447 
 448         /**
 449          * Constructs a new instance of {@code ChangeHandler}.
 450          *
 451          * @param m an instance of {@code JMenu}
 452          * @param ui an instance of {@code BasicMenuUI}
 453          */
 454         public ChangeHandler(JMenu m, BasicMenuUI ui) {
 455             menu = m;
 456             this.ui = ui;
 457         }
 458 
 459         public void stateChanged(ChangeEvent e) { }
 460     }
 461 
 462     private class Handler extends BasicMenuItemUI.Handler implements MenuKeyListener {
 463         //
 464         // PropertyChangeListener
 465         //
 466         public void propertyChange(PropertyChangeEvent e) {
 467             if (e.getPropertyName() == AbstractButton.
 468                              MNEMONIC_CHANGED_PROPERTY) {
 469                 updateMnemonicBinding();
 470             }
 471             else {
 472                 if (e.getPropertyName().equals("ancestor")) {
 473                     updateDefaultBackgroundColor();
 474                 }
 475                 super.propertyChange(e);
 476             }
 477         }
 478 
 479         //
 480         // MouseInputListener
 481         //
 482         public void mouseClicked(MouseEvent e) {
 483         }
 484 
 485         /**
 486          * Invoked when the mouse has been clicked on the menu. This
 487          * method clears or sets the selection path of the
 488          * MenuSelectionManager.
 489          *
 490          * @param e the mouse event
 491          */
 492         public void mousePressed(MouseEvent e) {
 493             JMenu menu = (JMenu)menuItem;
 494             if (!menu.isEnabled())
 495                 return;
 496 
 497             MenuSelectionManager manager =
 498                 MenuSelectionManager.defaultManager();
 499             if(menu.isTopLevelMenu()) {
 500                 if(menu.isSelected() && menu.getPopupMenu().isShowing()) {
 501                     manager.clearSelectedPath();
 502                 } else {
 503                     Container cnt = menu.getParent();
 504                     if(cnt != null && cnt instanceof JMenuBar) {
 505                         MenuElement me[] = new MenuElement[2];
 506                         me[0]=(MenuElement)cnt;
 507                         me[1]=menu;
 508                         manager.setSelectedPath(me);
 509                     }
 510                 }
 511             }
 512 
 513             MenuElement selectedPath[] = manager.getSelectedPath();
 514             if (selectedPath.length > 0 &&
 515                 selectedPath[selectedPath.length-1] != menu.getPopupMenu()) {
 516 
 517                 if(menu.isTopLevelMenu() ||
 518                    menu.getDelay() == 0) {
 519                     appendPath(selectedPath, menu.getPopupMenu());
 520                 } else {
 521                     setupPostTimer(menu);
 522                 }
 523             }
 524         }
 525 
 526         /**
 527          * Invoked when the mouse has been released on the menu. Delegates the
 528          * mouse event to the MenuSelectionManager.
 529          *
 530          * @param e the mouse event
 531          */
 532         public void mouseReleased(MouseEvent e) {
 533             JMenu menu = (JMenu)menuItem;
 534             if (!menu.isEnabled())
 535                 return;
 536             MenuSelectionManager manager =
 537                 MenuSelectionManager.defaultManager();
 538             manager.processMouseEvent(e);
 539             if (!e.isConsumed())
 540                 manager.clearSelectedPath();
 541         }
 542 
 543         /**
 544          * Invoked when the cursor enters the menu. This method sets the selected
 545          * path for the MenuSelectionManager and handles the case
 546          * in which a menu item is used to pop up an additional menu, as in a
 547          * hierarchical menu system.
 548          *
 549          * @param e the mouse event; not used
 550          */
 551         public void mouseEntered(MouseEvent e) {
 552             JMenu menu = (JMenu)menuItem;
 553             // only disable the menu highlighting if it's disabled and the property isn't
 554             // true. This allows disabled rollovers to work in WinL&F
 555             if (!menu.isEnabled() && !UIManager.getBoolean("MenuItem.disabledAreNavigable")) {
 556                 return;
 557             }
 558 
 559             MenuSelectionManager manager =
 560                 MenuSelectionManager.defaultManager();
 561             MenuElement selectedPath[] = manager.getSelectedPath();
 562             if (!menu.isTopLevelMenu()) {
 563                 if(!(selectedPath.length > 0 &&
 564                      selectedPath[selectedPath.length-1] ==
 565                      menu.getPopupMenu())) {
 566                     if(menu.getDelay() == 0) {
 567                         appendPath(getPath(), menu.getPopupMenu());
 568                     } else {
 569                         manager.setSelectedPath(getPath());
 570                         setupPostTimer(menu);
 571                     }
 572                 }
 573             } else {
 574                 if(selectedPath.length > 0 &&
 575                    selectedPath[0] == menu.getParent()) {
 576                     MenuElement newPath[] = new MenuElement[3];
 577                     // A top level menu's parent is by definition
 578                     // a JMenuBar
 579                     newPath[0] = (MenuElement)menu.getParent();
 580                     newPath[1] = menu;
 581                     if (BasicPopupMenuUI.getLastPopup() != null) {
 582                         newPath[2] = menu.getPopupMenu();
 583                     }
 584                     manager.setSelectedPath(newPath);
 585                 }
 586             }
 587         }
 588         public void mouseExited(MouseEvent e) {
 589         }
 590 
 591         /**
 592          * Invoked when a mouse button is pressed on the menu and then dragged.
 593          * Delegates the mouse event to the MenuSelectionManager.
 594          *
 595          * @param e the mouse event
 596          * @see java.awt.event.MouseMotionListener#mouseDragged
 597          */
 598         public void mouseDragged(MouseEvent e) {
 599             JMenu menu = (JMenu)menuItem;
 600             if (!menu.isEnabled())
 601                 return;
 602             MenuSelectionManager.defaultManager().processMouseEvent(e);
 603         }
 604         public void mouseMoved(MouseEvent e) {
 605         }
 606 
 607 
 608         //
 609         // MenuDragHandler
 610         //
 611         public void menuDragMouseEntered(MenuDragMouseEvent e) {}
 612         public void menuDragMouseDragged(MenuDragMouseEvent e) {
 613             if (menuItem.isEnabled() == false)
 614                 return;
 615 
 616             MenuSelectionManager manager = e.getMenuSelectionManager();
 617             MenuElement path[] = e.getPath();
 618 
 619             Point p = e.getPoint();
 620             if(p.x >= 0 && p.x < menuItem.getWidth() &&
 621                p.y >= 0 && p.y < menuItem.getHeight()) {
 622                 JMenu menu = (JMenu)menuItem;
 623                 MenuElement selectedPath[] = manager.getSelectedPath();
 624                 if(!(selectedPath.length > 0 &&
 625                      selectedPath[selectedPath.length-1] ==
 626                      menu.getPopupMenu())) {
 627                     if(menu.isTopLevelMenu() ||
 628                        menu.getDelay() == 0  ||
 629                        e.getID() == MouseEvent.MOUSE_DRAGGED) {
 630                         appendPath(path, menu.getPopupMenu());
 631                     } else {
 632                         manager.setSelectedPath(path);
 633                         setupPostTimer(menu);
 634                     }
 635                 }
 636             } else if(e.getID() == MouseEvent.MOUSE_RELEASED) {
 637                 Component comp = manager.componentForPoint(e.getComponent(), e.getPoint());
 638                 if (comp == null)
 639                     manager.clearSelectedPath();
 640             }
 641 
 642         }
 643         public void menuDragMouseExited(MenuDragMouseEvent e) {}
 644         public void menuDragMouseReleased(MenuDragMouseEvent e) {}
 645 
 646         //
 647         // MenuKeyListener
 648         //
 649         /**
 650          * Open the Menu
 651          */
 652         public void menuKeyTyped(MenuKeyEvent e) {
 653             if (!crossMenuMnemonic && BasicPopupMenuUI.getLastPopup() != null) {
 654                 // when crossMenuMnemonic is not set, we don't open a toplevel
 655                 // menu if another toplevel menu is already open
 656                 return;
 657             }
 658 
 659             if (BasicPopupMenuUI.getPopups().size() != 0) {
 660                 //Fix 6939261: to return in case not on the main menu
 661                 //and has a pop-up.
 662                 //after return code will be handled in BasicPopupMenuUI.java
 663                 return;
 664             }
 665 
 666             char key = Character.toLowerCase((char)menuItem.getMnemonic());
 667             MenuElement path[] = e.getPath();
 668             if (key == Character.toLowerCase(e.getKeyChar())) {
 669                 JPopupMenu popupMenu = ((JMenu)menuItem).getPopupMenu();
 670                 ArrayList<MenuElement> newList = new ArrayList<>(Arrays.asList(path));
 671                 newList.add(popupMenu);
 672                 MenuElement subs[] = popupMenu.getSubElements();
 673                 MenuElement sub =
 674                         BasicPopupMenuUI.findEnabledChild(subs, -1, true);
 675                 if(sub != null) {
 676                     newList.add(sub);
 677                 }
 678                 MenuSelectionManager manager = e.getMenuSelectionManager();
 679                 MenuElement newPath[] = new MenuElement[0];;
 680                 newPath = newList.toArray(newPath);
 681                 manager.setSelectedPath(newPath);
 682                 e.consume();
 683             }
 684         }
 685 
 686         public void menuKeyPressed(MenuKeyEvent e) {}
 687         public void menuKeyReleased(MenuKeyEvent e) {}
 688     }
 689 }