This fixes some menu layout issues as pointed out in http://gcc.gnu.org/bugzilla/show_bug.cgi?id=27624 .

I also implemented the timer for opening submenus some days ago. Unfortunately the javax.swing.Timer seems broken so this doesn't work right now. I wanted to hold this off until it works, but this overlaps here and goes in anyway. It doesn't hurt and as soon as Timer works this will automatically work too :-)

2006-08-02  Roman Kennke  <[EMAIL PROTECTED]>

        PR 27624
        * javax/swing/JMenu.java
        (JMenu()): Removed setting of delay.
        (JMenu(String)): Removed setting of delay.
        (JMenu(Action)): Removed setting of delay.
        (JMenu(String,boolean)): Removed setting of delay.
        (setSelectedHelper): Removed unneeded method.
        (setSelected): Simply set the model state.
        (setPopupMenuVisible): Recognize the popup location
        determined by getPopupMenuOrigin().
        (getPopupMenuOrigin): Recognize the UI properties for
        X and Y offset.
        (menuSelectionChanged): Call setSelected() directly.
        * javax/swing/JPopupMenu.java
        (menuSelectionChanged): If invoker is a JMenu, then delegate
        to that to get the position right.
        * javax/swing/Popup.java
        (LightweightPopup.show): Insert the popup as first component
        in the layer, so that it overlaps it's caller.
        * javax/swing/plaf/basic/BasicMenuItemUI.java
        (getPath): Don't include the popup.
        * javax/swing/plaf/basic/BasicMenuUI.java
        (SelectMenuAction): New class. This invokes the popup when
        a menu is selected.
        (installDefaults): Install delay of 200 ms.
        (setupPostTimer): Implemented.
        (MouseInputHandler.mouseClicked): Do nothing here.
        (MouseInputHandler.mouseEntered): Use MenuSelectionManager
        magic to handle the selection. Open the menu via a timer.
        (MouseInputHandler.mousePressed): Use MenuSelectionManager
        magic to handle the selection. Open the menu via a timer.
        (MenuDragMouseHandler.menuMouseDragged): Probably use
        timer.
        (menuDragMouseEntered): Do nothing here.

/Roman
Index: javax/swing/JMenu.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JMenu.java,v
retrieving revision 1.29
diff -u -1 -2 -r1.29 JMenu.java
--- javax/swing/JMenu.java	22 Jun 2006 13:21:02 -0000	1.29
+++ javax/swing/JMenu.java	2 Aug 2006 23:01:34 -0000
@@ -31,25 +31,24 @@
 independent module, the terms and conditions of the license of that
 module.  An independent module is a module which is not derived from
 or based on this library.  If you modify this library, you may extend
 this exception to your version of the library, but you are not
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
 
 package javax.swing;
 
 import java.awt.Component;
 import java.awt.Point;
-import java.awt.PopupMenu;
 import java.awt.event.KeyEvent;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.EventListener;
 
 import javax.accessibility.Accessible;
 import javax.accessibility.AccessibleContext;
 import javax.accessibility.AccessibleRole;
@@ -90,69 +89,65 @@
 
   /** Location at which popup menu associated with this menu will be
      displayed */
   private Point menuLocation;
 
   /**
    * Creates a new JMenu object.
    */
   public JMenu()
   {
     super();
     setOpaque(false);
-    setDelay(200);
   }
 
   /**
    * Creates a new <code>JMenu</code> with the specified label.
    *
    * @param text label for this menu
    */
   public JMenu(String text)
   {
     super(text);
     popupMenu = new JPopupMenu(); 
     popupMenu.setInvoker(this);
     setOpaque(false);
-    setDelay(200);
   }
 
   /**
    * Creates a new <code>JMenu</code> object.
    *
    * @param action Action that is used to create menu item tha will be
    * added to the menu.
    */
   public JMenu(Action action)
   {
     super(action);
     createActionChangeListener(this);
     popupMenu = new JPopupMenu();
     popupMenu.setInvoker(this);
     setOpaque(false);
-    setDelay(200);
   }
 
   /**
    * Creates a new <code>JMenu</code> with specified label and an option
    * for this menu to be tear-off menu.
    *
    * @param text label for this menu
    * @param tearoff true if this menu should be tear-off and false otherwise
    */
   public JMenu(String text, boolean tearoff)
   {
     // FIXME: tearoff not implemented
     this(text);
-    setDelay(200);
   }
 
   /**
    * Adds specified menu item to this menu
    *
    * @param item Menu item to add to this menu
    *
    * @return Menu item that was added
    */
   public JMenuItem add(JMenuItem item)
   {
     return getPopupMenu().add(item);
@@ -333,126 +328,90 @@
 
   /**
    * Returns true if the menu is selected and false otherwise
    *
    * @return true if the menu is selected and false otherwise
    */
   public boolean isSelected()
   {
     return super.isSelected();
   }
 
   /**
-   * A helper method to handle setSelected calls from both mouse events and 
-   * direct calls to setSelected.  Direct calls shouldn't expand the popup
-   * menu and should select the JMenu even if it is disabled.  Mouse events
-   * only select the JMenu if it is enabled and should expand the popup menu
-   * associated with this JMenu.
-   * @param selected whether or not the JMenu was selected
-   * @param menuEnabled whether or not selecting the menu is "enabled".  This
-   * is always true for direct calls, and is set to isEnabled() for mouse 
-   * based calls.
-   * @param showMenu whether or not to show the popup menu
-   */
-  private void setSelectedHelper(boolean selected, boolean menuEnabled, boolean showMenu)
-  {
-    // If menu is selected and enabled, activates the menu and 
-    // displays associated popup.	
-    if (selected && menuEnabled)
-      {
-	super.setArmed(true);
-	super.setSelected(true);
-
-        // FIXME: The popup menu should be shown on the screen after certain
-        // number of seconds pass. The 'delay' property of this menu indicates
-        // this amount of seconds. 'delay' property is 0 by default.
-	if (isShowing())
-	  {
-	    fireMenuSelected();
-            
-	    int x = 0;
-	    int y = 0;
-            if (showMenu)
-              if (menuLocation == null)
-                {
-                  // Calculate correct position of the popup. Note that location of the popup 
-                  // passed to show() should be relative to the popup's invoker
-                  if (isTopLevelMenu())
-                    y = this.getHeight();
-                  else
-                    x = this.getWidth();
-                  getPopupMenu().show(this, x, y);
-                }
-              else
-                {
-                  getPopupMenu().show(this, menuLocation.x, menuLocation.y);
-                }
-	  }
-      }
-    
-    else
-      {
-	super.setSelected(false);
-	super.setArmed(false);
-	fireMenuDeselected();
-        getPopupMenu().setVisible(false);
-      }
-  }
-
-  /**
    * Changes this menu selected state if selected is true and false otherwise
    * This method fires menuEvents to menu's registered listeners.
    *
    * @param selected true if the menu should be selected and false otherwise
    */
   public void setSelected(boolean selected)
   {
-    setSelectedHelper(selected, true, false); 
+    ButtonModel m = getModel();
+    if (selected != m.isSelected())
+      m.setSelected(selected);
   }
 
   /**
    * Checks if PopupMenu associated with this menu is visible
    *
    * @return true if the popup associated with this menu is currently visible
    * on the screen and false otherwise.
    */
   public boolean isPopupMenuVisible()
   {
     return getPopupMenu().isVisible();
   }
 
   /**
    * Sets popup menu visibility
    *
    * @param popup true if popup should be visible and false otherwise
    */
   public void setPopupMenuVisible(boolean popup)
   {
-    if (getModel().isEnabled())
-      getPopupMenu().setVisible(popup);
+    if (popup != isPopupMenuVisible() && (isEnabled() || ! popup))
+      {
+        if (popup && isShowing())
+          {
+            // Set location as determined by getPopupLocation().
+            Point loc = getPopupMenuOrigin();
+            getPopupMenu().show(this, loc.x, loc.y);
+          }
+        else
+          getPopupMenu().setVisible(false);
+      }
   }
 
   /**
    * Returns origin point of the popup menu
    *
    * @return Point containing
    */
   protected Point getPopupMenuOrigin()
   {
+    Point point;
+
     // if menu in the menu bar
     if (isTopLevelMenu())
-      return new Point(0, this.getHeight());
+      point = new Point(0, this.getHeight());
 
-    // if submenu            
-    return new Point(this.getWidth(), 0);
+    // if submenu
+    else
+      {
+        int xOffset = UIManager.getInt("Menu.submenuPopupOffsetX");
+        int yOffset = UIManager.getInt("Menu.submenuPopupOffsetY");
+        int x = getWidth() + xOffset;
+        int y = yOffset;
+        point = new Point(x, y);
+      }
+    return point;
   }
 
   /**
    * Returns delay property.
    *
    * @return delay property, indicating number of milliseconds before
    * popup menu associated with the menu appears or disappears after
    * menu was selected or deselected respectively
    */
   public int getDelay()
   {
     return delay;
@@ -739,25 +698,25 @@
   /**
    * Method of the MenuElementInterface. It reacts to the selection
    * changes in the menu. If this menu was selected, then it
    * displayes popup menu associated with it and if this menu was
    * deselected it hides the popup menu.
    *
    * @param changed true if the menu was selected and false otherwise
    */
   public void menuSelectionChanged(boolean changed)
   {
     // if this menu selection is true, then activate this menu and 
     // display popup associated with this menu
-    setSelectedHelper(changed, isEnabled(), true);
+    setSelected(changed);
   }
 
   /**
    * Method of MenuElement interface. Returns sub components of
    * this menu.
    *
    * @return array containing popupMenu that is associated with this menu
    */
   public MenuElement[] getSubElements()
   {
     return new MenuElement[] { popupMenu };
   }
Index: javax/swing/JPopupMenu.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JPopupMenu.java,v
retrieving revision 1.37
diff -u -1 -2 -r1.37 JPopupMenu.java
--- javax/swing/JPopupMenu.java	24 Jul 2006 15:04:05 -0000	1.37
+++ javax/swing/JPopupMenu.java	2 Aug 2006 23:01:34 -0000
@@ -811,25 +811,32 @@
     // of MenuElement interface
   }
 
   /**
    * Method of MenuElement Interface. It is invoked when
    * popupMenu's selection has changed
    *
    * @param changed true if this popupMenu is part of current menu
    * hierarchy and false otherwise.
    */
   public void menuSelectionChanged(boolean changed)
   {
-    if (! changed)
+    if (invoker instanceof JMenu)
+      {
+        // We need to special case this since the JMenu calculates the
+        // position etc of the popup.
+        JMenu menu = (JMenu) invoker;
+        menu.setPopupMenuVisible(changed);
+      }
+    else if (! changed)
       setVisible(false);
   }
 
   /**
    * Return subcomonents of this popup menu. This method returns only
    * components that implement the <code>MenuElement</code> interface.
    *
    * @return array of menu items belonging to this popup menu
    */
   public MenuElement[] getSubElements()
   {
     Component[] items = getComponents();
Index: javax/swing/Popup.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/Popup.java,v
retrieving revision 1.10
diff -u -1 -2 -r1.10 Popup.java
--- javax/swing/Popup.java	15 Mar 2006 15:28:05 -0000	1.10
+++ javax/swing/Popup.java	2 Aug 2006 23:01:34 -0000
@@ -275,25 +275,25 @@
       // can fiddle with the setLocation() method without disturbing a
       // JPopupMenu (which overrides setLocation in an unusual manner).
       if (panel == null)
         {
           panel = new JPanel();
           panel.setLayout(new FlowLayout(0, 0, 0));
         }
       
       panel.add(contents);
       panel.setSize(contents.getSize());
       Point layeredPaneLoc = layeredPane.getLocationOnScreen();
       panel.setLocation(x - layeredPaneLoc.x, y - layeredPaneLoc.y);
-      layeredPane.add(panel, JLayeredPane.POPUP_LAYER);
+      layeredPane.add(panel, JLayeredPane.POPUP_LAYER, 0);
       panel.repaint();
     }
 
     /**
      * Removes the popup from the JLayeredPane thus making it invisible.
      */
     public void hide()
     {
       Rectangle bounds = panel.getBounds();
       layeredPane.remove(panel);
       layeredPane.repaint(bounds.x, bounds.y, bounds.width, bounds.height);
     }
Index: javax/swing/plaf/basic/BasicMenuItemUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java,v
retrieving revision 1.49
diff -u -1 -2 -r1.49 BasicMenuItemUI.java
--- javax/swing/plaf/basic/BasicMenuItemUI.java	17 Jul 2006 08:36:48 -0000	1.49
+++ javax/swing/plaf/basic/BasicMenuItemUI.java	2 Aug 2006 23:01:35 -0000
@@ -402,28 +402,24 @@
   }
 
   /**
    * Returns path to this menu item.
    * 
    * @return $MenuElement[]$ Returns array of menu elements that constitute a
    *         path to this menu item.
    */
   public MenuElement[] getPath()
   {
     ArrayList path = new ArrayList();
 
-    // Path to menu should also include its popup menu.
-    if (menuItem instanceof JMenu)
-      path.add(((JMenu) menuItem).getPopupMenu());
-
     Component c = menuItem;
     while (c instanceof MenuElement)
       {
         path.add(0, (MenuElement) c);
 
         if (c instanceof JPopupMenu)
           c = ((JPopupMenu) c).getInvoker();
         else
           c = c.getParent();
       }
 
     MenuElement[] pathArray = new MenuElement[path.size()];
Index: javax/swing/plaf/basic/BasicMenuUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicMenuUI.java,v
retrieving revision 1.25
diff -u -1 -2 -r1.25 BasicMenuUI.java
--- javax/swing/plaf/basic/BasicMenuUI.java	4 Jul 2006 16:14:54 -0000	1.25
+++ javax/swing/plaf/basic/BasicMenuUI.java	2 Aug 2006 23:01:37 -0000
@@ -32,52 +32,84 @@
 module.  An independent module is a module which is not derived from
 or based on this library.  If you modify this library, you may extend
 this exception to your version of the library, but you are not
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
 
 package javax.swing.plaf.basic;
 
 import gnu.classpath.NotImplementedException;
 
 import java.awt.Component;
+import java.awt.Container;
 import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
 import java.awt.event.MouseEvent;
 import java.beans.PropertyChangeListener;
 
+import javax.swing.AbstractAction;
 import javax.swing.JComponent;
 import javax.swing.JMenu;
 import javax.swing.JMenuBar;
 import javax.swing.JPopupMenu;
 import javax.swing.LookAndFeel;
+import javax.swing.MenuElement;
 import javax.swing.MenuSelectionManager;
+import javax.swing.Timer;
 import javax.swing.UIDefaults;
 import javax.swing.UIManager;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.event.MenuDragMouseEvent;
 import javax.swing.event.MenuDragMouseListener;
 import javax.swing.event.MenuEvent;
 import javax.swing.event.MenuKeyEvent;
 import javax.swing.event.MenuKeyListener;
 import javax.swing.event.MenuListener;
 import javax.swing.event.MouseInputListener;
 import javax.swing.plaf.ComponentUI;
 
 /**
  * UI Delegate for JMenu
  */
 public class BasicMenuUI extends BasicMenuItemUI
 {
+  /**
+   * Selects a menu. This is used to delay menu selection.
+   */
+  class SelectMenuAction
+    extends AbstractAction
+  {
+    /**
+     * Performs the action.
+     */
+    public void actionPerformed(ActionEvent event)
+    {
+      JMenu menu = (JMenu) menuItem;
+      MenuSelectionManager defaultManager =
+        MenuSelectionManager.defaultManager();
+      MenuElement path[] = defaultManager.getSelectedPath();
+      if(path.length > 0 && path[path.length - 1] == menu)
+        {
+          MenuElement newPath[] = new MenuElement[path.length + 1];
+          System.arraycopy(path, 0, newPath, 0, path.length);
+          newPath[path.length] = menu.getPopupMenu();
+          defaultManager.setSelectedPath(newPath);
+      }
+    }
+    
+  }
+
   protected ChangeListener changeListener;
 
   /* MenuListener listens to MenuEvents fired by JMenu */
   protected MenuListener menuListener;
 
   /* PropertyChangeListner that listens to propertyChangeEvents occuring in JMenu*/
   protected PropertyChangeListener propertyChangeListener;
 
   /**
    * Creates a new BasicMenuUI object.
    */
   public BasicMenuUI()
@@ -192,60 +224,63 @@
    */
   protected String getPropertyPrefix()
   {
     return "Menu";
   }
 
   /**
    * Initializes any default properties that this UI has from the defaults for
    * the Basic look and feel.
    */
   protected void installDefaults()
   {
+    
     LookAndFeel.installBorder(menuItem, "Menu.border");
     LookAndFeel.installColorsAndFont(menuItem, "Menu.background",
                                      "Menu.foreground", "Menu.font");
     menuItem.setMargin(UIManager.getInsets("Menu.margin"));
     acceleratorFont = UIManager.getFont("Menu.acceleratorFont");
     acceleratorForeground = UIManager.getColor("Menu.acceleratorForeground");
     acceleratorSelectionForeground = UIManager.getColor("Menu.acceleratorSelectionForeground");
     selectionBackground = UIManager.getColor("Menu.selectionBackground");
     selectionForeground = UIManager.getColor("Menu.selectionForeground");
     arrowIcon = UIManager.getIcon("Menu.arrowIcon");
     oldBorderPainted = UIManager.getBoolean("Menu.borderPainted");
+    ((JMenu) menuItem).setDelay(200);
   }
 
   /**
    * Installs any keyboard actions. The list of keys that need to be bound are
    * listed in Basic look and feel's defaults.
    *
    */
   protected void installKeyboardActions()
   {
     super.installKeyboardActions();
   }
 
   /**
    * Creates and registers all the listeners for this UI delegate.
    */
   protected void installListeners()
   {
     super.installListeners();
     ((JMenu) menuItem).addMenuListener(menuListener);
   }
 
   protected void setupPostTimer(JMenu menu)
-  throws NotImplementedException
   {
-    // TODO: Implement this properly.
+    Timer timer = new Timer(menu.getDelay(), new SelectMenuAction());
+    timer.setRepeats(false);
+    timer.start();
   }
 
   /**
    * This method uninstalls the defaults and sets any objects created during
    * install to null
    */
   protected void uninstallDefaults()
   {
     menuItem.setBackground(null);
     menuItem.setBorder(null);
     menuItem.setFont(null);
     menuItem.setForeground(null);
@@ -276,26 +311,25 @@
     super.uninstallListeners();
     ((JMenu) menuItem).removeMenuListener(menuListener);
   }
 
   /**
    * This class is used by menus to handle mouse events occuring in the
    * menu.
    */
   protected class MouseInputHandler implements MouseInputListener
   {
     public void mouseClicked(MouseEvent e)
     {
-      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
-      manager.processMouseEvent(e);
+      // Nothing to do here.
     }
 
     public void mouseDragged(MouseEvent e)
     {
       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
       manager.processMouseEvent(e);
     }
 
     private boolean popupVisible()
     {
       JMenuBar mb = (JMenuBar) ((JMenu) menuItem).getParent();
       // check if mb.isSelected because if no menus are selected
@@ -304,88 +338,124 @@
         return false;
       for (int i = 0; i < mb.getMenuCount(); i++)
       {
          JMenu m = mb.getMenu(i);
         if (m != null && m.isPopupMenuVisible())
           return true;
       }
       return false;
     }
 
     public void mouseEntered(MouseEvent e)
     {
-      /* When mouse enters menu item, it should be considered selected
-
-       if (i) if this menu is a submenu in some other menu
-          (ii) or if this menu is in a menu bar and some other menu in a 
-          menu bar was just selected and has its popup menu visible. 
-               (If nothing was selected, menu should be pressed before
-               it will be selected)
-      */
       JMenu menu = (JMenu) menuItem;
-
-      // NOTE: the following if used to require !menu.isArmed but I could find
-      // no reason for this and it was preventing some JDK-compatible behaviour.
-      // Specifically, if a menu is selected but its popup menu not visible,
-      // and then another menu is selected whose popup menu IS visible, when
-      // the mouse is moved over the first menu, its popup menu should become
-      // visible.
-
-      if (! menu.isTopLevelMenu() || popupVisible())
+      if (menu.isEnabled())
         {
-	  // set new selection and forward this event to MenuSelectionManager
-	  MenuSelectionManager manager = MenuSelectionManager.defaultManager();
-	  manager.setSelectedPath(getPath());
-	  manager.processMouseEvent(e);
+          MenuSelectionManager manager =
+            MenuSelectionManager.defaultManager();
+          MenuElement[] selectedPath = manager.getSelectedPath();
+          if (! menu.isTopLevelMenu())
+            {
+              // Open the menu immediately or delayed, depending on the
+              // delay value.
+              if(! (selectedPath.length > 0
+                  && selectedPath[selectedPath.length - 1] == menu.getPopupMenu()))
+                {
+                  if(menu.getDelay() == 0)
+                    {
+                      MenuElement[] path = getPath();
+                      MenuElement[] newPath = new MenuElement[path.length + 1];
+                      System.arraycopy(path, 0, newPath, 0, path.length);
+                      newPath[path.length] = menu.getPopupMenu();
+                      manager.setSelectedPath(newPath);
+                    }
+                  else
+                    {
+                      manager.setSelectedPath(getPath());
+                      setupPostTimer(menu);
+                    }
+                }
+            }
+          else
+            {
+              if(selectedPath.length > 0
+                  && selectedPath[0] == menu.getParent())
+                {
+                  MenuElement[] newPath = new MenuElement[3];
+                  newPath[0] = (MenuElement) menu.getParent();
+                  newPath[1] = menu;
+                  newPath[2] = menu.getPopupMenu();
+                  manager.setSelectedPath(newPath);
+                }
+            }
         }
     }
 
     public void mouseExited(MouseEvent e)
     {
       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
       manager.processMouseEvent(e);
     }
 
     public void mouseMoved(MouseEvent e)
     {
       // Nothing to do here.
     }
 
     public void mousePressed(MouseEvent e)
     {
       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
       JMenu menu = (JMenu) menuItem;
-      manager.processMouseEvent(e);
-
-      // Menu should be displayed when the menu is pressed only if 
-      // it is top-level menu
-      if (menu.isTopLevelMenu())
+      if (menu.isEnabled())
         {
-	  if (menu.getPopupMenu().isVisible())
-	    // If menu is visible and menu button was pressed.. 
-	    // then need to cancel the menu
-	    manager.clearSelectedPath();
-	  else
-	    {
-	      // Display the menu
-	      int x = 0;
-	      int y = menu.getHeight();
-
-	      manager.setSelectedPath(getPath());
-
-	      JMenuBar mb = (JMenuBar) menu.getParent();
-
-	      // set selectedIndex of the selectionModel of a menuBar
-	      mb.getSelectionModel().setSelectedIndex(mb.getComponentIndex(menu));
-	    }
+          // Open up the menu immediately if it's a toplevel menu.
+          // But not yet the popup, which might be opened delayed, see below.
+          if (menu.isTopLevelMenu())
+            {
+              if (menu.isSelected())
+                manager.clearSelectedPath();
+              else
+                {
+                  Container cnt = menu.getParent();
+                  if (cnt != null && cnt instanceof JMenuBar)
+                    {
+                      MenuElement[] me = new MenuElement[2];
+                      me[0] = (MenuElement) cnt;
+                      me[1] = menu;
+                      manager.setSelectedPath(me);
+                   }
+                }
+            }
+
+          // Open the menu's popup. Either do that immediately if delay == 0,
+          // or delayed when delay > 0.
+          MenuElement[] selectedPath = manager.getSelectedPath();
+          if (selectedPath.length > 0
+              && selectedPath[selectedPath.length - 1] != menu.getPopupMenu())
+            {
+              if(menu.isTopLevelMenu() || menu.getDelay() == 0)
+                {
+                  MenuElement[] newPath =
+                    new MenuElement[selectedPath.length + 1];
+                  System.arraycopy(selectedPath, 0, newPath, 0,
+                                   selectedPath.length);
+                  newPath[selectedPath.length] = menu.getPopupMenu();
+                  manager.setSelectedPath(newPath);
+                }
+              else
+                {
+                  setupPostTimer(menu);
+                }
+            }
+
         }
     }
 
     public void mouseReleased(MouseEvent e)
     {
       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
       manager.processMouseEvent(e);
     }
   }
 
   /**
    * This class handles MenuEvents fired by the JMenu
@@ -484,38 +554,73 @@
   /**
    * This class handles mouse dragged events occuring in the menu.
    */
   private class MenuDragMouseHandler implements MenuDragMouseListener
   {
     /**
      * This method is invoked when mouse is dragged over the menu item.
      *
      * @param e The MenuDragMouseEvent
      */
     public void menuDragMouseDragged(MenuDragMouseEvent e)
     {
-      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
-      manager.setSelectedPath(e.getPath());
+      if (menuItem.isEnabled())
+        {
+          MenuSelectionManager manager = e.getMenuSelectionManager();
+          MenuElement path[] = e.getPath();
+
+          Point p = e.getPoint();
+          if(p.x >= 0 && p.x < menuItem.getWidth()
+              && p.y >= 0 && p.y < menuItem.getHeight())
+            {
+              JMenu menu = (JMenu) menuItem;
+              MenuElement[] selectedPath = manager.getSelectedPath();
+              if(! (selectedPath.length > 0
+                  && selectedPath[selectedPath.length-1]
+                                  == menu.getPopupMenu()))
+                {
+                  if(menu.isTopLevelMenu() || menu.getDelay() == 0
+                     || e.getID() == MouseEvent.MOUSE_DRAGGED)
+                    {
+                      MenuElement[] newPath = new MenuElement[path.length + 1];
+                      System.arraycopy(path, 0, newPath, 0, path.length);
+                      newPath[path.length] = menu.getPopupMenu();
+                      manager.setSelectedPath(newPath);
+                    }
+                  else
+                    {
+                      manager.setSelectedPath(path);
+                      setupPostTimer(menu);
+                    }
+                }
+            }
+          else if (e.getID() == MouseEvent.MOUSE_RELEASED)
+            {
+              Component comp = manager.componentForPoint(e.getComponent(),
+                                                         e.getPoint());
+              if (comp == null)
+                manager.clearSelectedPath();
+            }
+        }
     }
 
     /**
      * This method is invoked when mouse enters the menu item while it is
      * being dragged.
      *
      * @param e The MenuDragMouseEvent
      */
     public void menuDragMouseEntered(MenuDragMouseEvent e)
     {
-      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
-      manager.setSelectedPath(e.getPath());
+      // Nothing to do here.
     }
 
     /**
      * This method is invoked when mouse exits the menu item while
      * it is being dragged
      *
      * @param e The MenuDragMouseEvent
      */
     public void menuDragMouseExited(MenuDragMouseEvent e)
     {
       // Nothing to do here.
     }

Reply via email to