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

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