This adds support for drag-selecting menu items in Swing.

2006-10-13  Roman Kennke  <[EMAIL PROTECTED]>

        PR 27780
        * javax/swing/JMenuItem.java
        (isDragging): New field. Indicates if we are inside a mouse
        drag.
        (createMenuDragMouseEvent): Removed unneeded method.
        (processMenuDragMouseEvent): Track if we are dragging.
        (processMouseEvent): Simply forward to processMenuDragMouseEvent().
        * javax/swing/plaf/basic/BasicMenuItemUI.java
        (MenuDragMouseHandler.menuDragMouseDragged): Fetch
        MenuSelectionManager from event.
        (MenuDragMouseHandler.menuDragMouseEntered): Fetch
        MenuSelectionManager from event.
        (MenuDragMouseHandler.menuDragMouseExited): Fetch
        MenuSelectionManager from event.
        (MenuDragMouseHandler.menuDragMouseReleased): Click on mouse
        release inside menu item, otherwise clear selection.
        (MenuInputHandler.mouseReleased): Avoid multiple calls to getX()
        and getY(). Call doClick() rather than the doClick() of JMenuItem.
        (doClick): Perform an immediate click.

/Roman

Index: javax/swing/JMenuItem.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JMenuItem.java,v
retrieving revision 1.34
diff -u -1 -5 -r1.34 JMenuItem.java
--- javax/swing/JMenuItem.java	19 Sep 2006 14:26:43 -0000	1.34
+++ javax/swing/JMenuItem.java	13 Oct 2006 08:50:30 -0000
@@ -27,31 +27,30 @@
 permission to link this library with independent modules to produce an
 executable, regardless of the license terms of these independent
 modules, and to copy and distribute the resulting executable under
 terms of your choice, provided that you also meet, for each linked
 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.event.InputEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseEvent;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.util.EventListener;
 
 import javax.accessibility.Accessible;
 import javax.accessibility.AccessibleContext;
 import javax.accessibility.AccessibleRole;
 import javax.accessibility.AccessibleState;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.event.MenuDragMouseEvent;
 import javax.swing.event.MenuDragMouseListener;
 import javax.swing.event.MenuKeyEvent;
@@ -65,30 +64,35 @@
  * PropertyChangeEvents are fired when menuItems properties are modified;
  * ChangeEvents are fired when menuItem's state changes and actionEvents are
  * fired when menu item is selected. In addition to this events menuItem also
  * fire MenuDragMouseEvent and MenuKeyEvents when mouse is dragged over
  * the menu item or associated key with menu item is invoked respectively.
  */
 public class JMenuItem extends AbstractButton implements Accessible,
                                                          MenuElement
 {
   private static final long serialVersionUID = -1681004643499461044L;
 
   /** Combination of keyboard keys that can be used to activate this menu item */
   private KeyStroke accelerator;
 
   /**
+   * Indicates if we are currently dragging the mouse.
+   */
+  private boolean isDragging;
+
+  /**
    * Creates a new JMenuItem object.
    */
   public JMenuItem()
   {
     this(null, null);
   }
 
   /**
    * Creates a new JMenuItem with the given icon.
    *
    * @param icon Icon that will be displayed on the menu item
    */
   public JMenuItem(Icon icon)
   {
     // FIXME: The requestedFocusEnabled property should
@@ -307,95 +311,45 @@
   protected PropertyChangeListener createActionPropertyChangeListener(Action action)
   {
     return new PropertyChangeListener()
       {
 	public void propertyChange(PropertyChangeEvent e)
 	{
 	  Action act = (Action) (e.getSource());
 	  configurePropertiesFromAction(act);
 	}
       };
   }
 
   /**
    * Process mouse events forwarded from MenuSelectionManager.
    *
-   * @param event event forwarded from MenuSelectionManager
+   * @param ev event forwarded from MenuSelectionManager
    * @param path path to the menu element from which event was generated
    * @param manager MenuSelectionManager for the current menu hierarchy
    */
-  public void processMouseEvent(MouseEvent event, MenuElement[] path,
+  public void processMouseEvent(MouseEvent ev, MenuElement[] path,
                                 MenuSelectionManager manager)
   {
-    // Fire MenuDragMouseEvents if mouse is being dragged.
-    boolean dragged
-      = (event.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0;
-    if (dragged)
-      processMenuDragMouseEvent(createMenuDragMouseEvent(event, path, manager));
-
-    switch (event.getID())
-      {
-      case MouseEvent.MOUSE_CLICKED:
-	break;
-      case MouseEvent.MOUSE_ENTERED:
-	if (isRolloverEnabled())
-	  model.setRollover(true);
-	break;
-      case MouseEvent.MOUSE_EXITED:
-	if (isRolloverEnabled())
-	  model.setRollover(false);
-
-	// for JMenu last element on the path is its popupMenu.
-	// JMenu shouldn't me disarmed.	
-	if (! (path[path.length - 1] instanceof JPopupMenu) && ! dragged)
-	  setArmed(false);
-	break;
-      case MouseEvent.MOUSE_PRESSED:
-	if ((event.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0)
-	  {
-	    model.setArmed(true);
-	    model.setPressed(true);
-	  }
-	break;
-      case MouseEvent.MOUSE_RELEASED:
-	break;
-      case MouseEvent.MOUSE_MOVED:
-	break;
-      case MouseEvent.MOUSE_DRAGGED:
-	break;
-      }
-  }
-
-  /**
-   * Creates MenuDragMouseEvent.
-   *
-   * @param event MouseEvent that occured while mouse was pressed.
-   * @param path Path the the menu element where the dragging event was
-   *        originated
-   * @param manager MenuSelectionManager for the current menu hierarchy.
-   *
-   * @return new MenuDragMouseEvent
-   */
-  private MenuDragMouseEvent createMenuDragMouseEvent(MouseEvent event,
-                                                      MenuElement[] path,
-                                                      MenuSelectionManager manager)
-  {
-    return new MenuDragMouseEvent((Component) event.getSource(),
-                                  event.getID(), event.getWhen(),
-                                  event.getModifiers(), event.getX(),
-                                  event.getY(), event.getClickCount(),
-                                  event.isPopupTrigger(), path, manager);
+    MenuDragMouseEvent e = new MenuDragMouseEvent(ev.getComponent(),
+                                                  ev.getID(), ev.getWhen(),
+                                                  ev.getModifiers(), ev.getX(),
+                                                  ev.getY(),
+                                                  ev.getClickCount(),
+                                                  ev.isPopupTrigger(), path,
+                                                  manager);
+    processMenuDragMouseEvent(e);
   }
 
   /**
    * Process key events forwarded from MenuSelectionManager.
    *
    * @param event event forwarded from MenuSelectionManager
    * @param path path to the menu element from which event was generated
    * @param manager MenuSelectionManager for the current menu hierarchy
    */
   public void processKeyEvent(KeyEvent event, MenuElement[] path,
                               MenuSelectionManager manager)
   {
     MenuKeyEvent e = new MenuKeyEvent(event.getComponent(), event.getID(),
                                       event.getWhen(), event.getModifiers(),
                                       event.getKeyCode(), event.getKeyChar(),
@@ -407,40 +361,44 @@
       event.consume();
   }
 
   /**
    * This method fires MenuDragMouseEvents to registered listeners.
    * Different types of MenuDragMouseEvents are fired depending
    * on the observed mouse event.
    *
    * @param event Mouse
    */
   public void processMenuDragMouseEvent(MenuDragMouseEvent event)
   {
     switch (event.getID())
       {
       case MouseEvent.MOUSE_ENTERED:
+        isDragging = false;
 	fireMenuDragMouseEntered(event);
 	break;
       case MouseEvent.MOUSE_EXITED:
+        isDragging = false;
 	fireMenuDragMouseExited(event);
 	break;
       case MouseEvent.MOUSE_DRAGGED:
+        isDragging = true;
 	fireMenuDragMouseDragged(event);
 	break;
       case MouseEvent.MOUSE_RELEASED:
-	fireMenuDragMouseReleased(event);
+        if (isDragging)
+          fireMenuDragMouseReleased(event);
 	break;
       }
   }
 
   /**
    * This method fires MenuKeyEvent to registered listeners.
    * Different types of MenuKeyEvents are fired depending
    * on the observed key event.
    *
    * @param event DOCUMENT ME!
    */
   public void processMenuKeyEvent(MenuKeyEvent event)
   {
     switch (event.getID())
     {
Index: javax/swing/plaf/basic/BasicMenuItemUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java,v
retrieving revision 1.52
diff -u -1 -5 -r1.52 BasicMenuItemUI.java
--- javax/swing/plaf/basic/BasicMenuItemUI.java	27 Sep 2006 19:12:37 -0000	1.52
+++ javax/swing/plaf/basic/BasicMenuItemUI.java	13 Oct 2006 08:50:30 -0000
@@ -352,31 +352,31 @@
    * @return A BasicMenuItemUI for the [EMAIL PROTECTED] JComponent}.
    */
   public static ComponentUI createUI(JComponent c)
   {
     return new BasicMenuItemUI();
   }
 
   /**
    * Programatically clicks menu item.
    * 
    * @param msm
    *          MenuSelectionManager for the menu hierarchy
    */
   protected void doClick(MenuSelectionManager msm)
   {
-    menuItem.doClick();
+    menuItem.doClick(0);
     msm.clearSelectedPath();
   }
 
   /**
    * Returns maximum size for the specified menu item
    * 
    * @param c
    *          component for which to get maximum size
    * @return Maximum size for the specified menu item.
    */
   public Dimension getMaximumSize(JComponent c)
   {
     return null;
   }
 
@@ -1046,101 +1046,101 @@
     {
       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
       manager.processMouseEvent(e);
     }
 
     /**
      * This method is called when mouse is released. If the mouse is released
      * inside this menuItem, then this menu item is considered to be chosen and
      * the menu hierarchy should be closed.
      * 
      * @param e
      *          A [EMAIL PROTECTED] MouseEvent}.
      */
     public void mouseReleased(MouseEvent e)
     {
-      Rectangle size = menuItem.getBounds();
       MenuSelectionManager manager = MenuSelectionManager.defaultManager();
-      if (e.getX() > 0 && e.getX() < size.width && e.getY() > 0
-          && e.getY() < size.height)
+      int x = e.getX();
+      int y = e.getY();
+      if (x > 0 && x < menuItem.getWidth() && y > 0
+          && y < menuItem.getHeight())
         {
-          manager.clearSelectedPath();
-          menuItem.doClick();
+          doClick(manager);
         }
-
       else
         manager.processMouseEvent(e);
     }
   }
 
   /**
    * This class handles mouse dragged events.
    */
   private class MenuDragMouseHandler implements MenuDragMouseListener
   {
     /**
      * Tbis method is invoked when mouse is dragged over the menu item.
      * 
      * @param e
      *          The MenuDragMouseEvent
      */
     public void menuDragMouseDragged(MenuDragMouseEvent e)
     {
-      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
+      MenuSelectionManager manager = e.getMenuSelectionManager();
       manager.setSelectedPath(e.getPath());
     }
 
     /**
      * Tbis 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();
+      MenuSelectionManager manager = e.getMenuSelectionManager();
       manager.setSelectedPath(e.getPath());
     }
 
     /**
      * Tbis method is invoked when mouse exits the menu item while it is being
      * dragged
      * 
      * @param e the MenuDragMouseEvent
      */
     public void menuDragMouseExited(MenuDragMouseEvent e)
     {
-      // TODO: What should be done here, if anything?
+      // Nothing to do here yet.
     }
 
     /**
      * Tbis method is invoked when mouse was dragged and released inside the
      * menu item.
      * 
      * @param e
      *          The MenuDragMouseEvent
      */
     public void menuDragMouseReleased(MenuDragMouseEvent e)
     {
-      MenuElement[] path = e.getPath();
-
-      if (path[path.length - 1] instanceof JMenuItem)
-        ((JMenuItem) path[path.length - 1]).doClick();
-
-      MenuSelectionManager manager = MenuSelectionManager.defaultManager();
-      manager.clearSelectedPath();
+      MenuSelectionManager manager = e.getMenuSelectionManager();
+      int x = e.getX();
+      int y = e.getY();
+      if (x >= 0 && x < menuItem.getWidth() && y >= 0
+          && y < menuItem.getHeight())
+        doClick(manager);
+      else
+        manager.clearSelectedPath();
     }
   }
 
   /**
    * This class handles key events occuring when menu item is visible on the
    * screen.
    */
   private class MenuKeyHandler implements MenuKeyListener
   {
     /**
      * This method is invoked when key has been pressed
      * 
      * @param e
      *          A [EMAIL PROTECTED] MenuKeyEvent}.
      */

Reply via email to