Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]

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

Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]