The glasspane in JInternalFrames should be visible when the frame is deselected but invisible when the frame gets selected. The whole point of this glasspane is to catch MouseEvents and select the frame as soon as the mouse is pressed on it.

I have also rewritten parts of the GlassPane, it's been overly complicated before (maybe due to some previous problems with the LightweightDispatcher).

2006-07-25  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/plaf/basic/BasicInternalFrameUI.java
        (GlassPaneDispatcher.dragTarget): New field.
        (GlassPaneDispatcher.isDragging): New field.
        (GlassPaneDispatcher.pressedComponent): Removed field.
        (GlassPaneDispatcher.tempComponent): Removed field.
        (GlassPaneDispatcher.pressCount): Removed field.
        (GlassPaneDispatcher.mousePressed): Call
        borderListener.mousePressed() to activate the frame.
        (acquireComponentForMouseEvent): Removed method.
        (handleEvent): Rewritten.
        (redispatch): New method.
        (InternalFramePropertyChangeListener.propertyChange):
        Make glasspane invisible when frame is selected, and visible
        if it gets deselected.

/Roman
Index: javax/swing/plaf/basic/BasicInternalFrameUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java,v
retrieving revision 1.39
diff -u -1 -2 -r1.39 BasicInternalFrameUI.java
--- javax/swing/plaf/basic/BasicInternalFrameUI.java	23 Jun 2006 12:28:32 -0000	1.39
+++ javax/swing/plaf/basic/BasicInternalFrameUI.java	25 Jul 2006 09:55:26 -0000
@@ -29,25 +29,24 @@
 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.plaf.basic;
 
-import java.awt.AWTEvent;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Container;
 import java.awt.Cursor;
 import java.awt.Dimension;
 import java.awt.Graphics;
 import java.awt.Insets;
 import java.awt.LayoutManager;
 import java.awt.LayoutManager2;
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
@@ -683,35 +682,30 @@
   }
 
   /**
    * This helper class is used to listen to the JDesktopPane's glassPane for
    * MouseEvents. The JInternalFrame can then be selected if a click is
    * detected on its children.
    */
   protected class GlassPaneDispatcher implements MouseInputListener
   {
     /** The MouseEvent target. */
     private transient Component mouseEventTarget;
 
-    /** The component pressed. */
-    private transient Component pressedComponent;
+    private Component dragTarget;
 
-    /** The last component entered. */
-    private transient Component lastComponentEntered;
-
-    /** Used to store/reset lastComponentEntered. */
-    private transient Component tempComponent;
-
-    /** The number of presses. */
-    private transient int pressCount;
+    /**
+     * Indicates if we are currently in a dragging operation or not.
+     */
+    private boolean isDragging;
 
     /**
      * This method is called when the mouse enters the glass pane.
      * 
      * @param e
      *          The MouseEvent.
      */
     public void mouseEntered(MouseEvent e)
     {
       handleEvent(e);
     }
 
@@ -758,184 +752,142 @@
     {
       handleEvent(e);
     }
 
     /**
      * This method is called when the mouse is pressed in the glass pane.
      * 
      * @param e
      *          The MouseEvent.
      */
     public void mousePressed(MouseEvent e)
     {
-      activateFrame(frame);
+      // Experiments show that this seems to call the
+      // borderListener.mousePressed() method to activate the frame.
+      if (borderListener != null)
+        borderListener.mousePressed(e);
       handleEvent(e);
     }
 
     /**
      * This method is called when the mouse is released in the glass pane.
      * 
      * @param e
      *          The MouseEvent.
      */
     public void mouseReleased(MouseEvent e)
     {
       handleEvent(e);
     }
 
     /**
-     * This method acquires a candidate component to dispatch the MouseEvent to.
+     * This is a helper method that dispatches the GlassPane MouseEvents to the
+     * proper component.
      * 
-     * @param me
-     *          The MouseEvent to acquire a component for.
+     * @param e the mouse event to be dispatched
      */
-    private void acquireComponentForMouseEvent(MouseEvent me)
+    private void handleEvent(MouseEvent e)
     {
-      int x = me.getX();
-      int y = me.getY();
+      // Find candidate component inside the JInternalFrame.
+      Component target = frame.getLayeredPane().findComponentAt(e.getX(),
+                                                                e.getY());
 
-      // Find the candidate which should receive this event.
-      Component parent = frame.getLayeredPane();
-      if (parent == null)
-        return;
-      Component candidate = null;
-      Point p = me.getPoint();
-      while (candidate == null && parent != null)
+      // Now search upwards to find a component that actually has
+      // a MouseListener attached.
+      while (target != null
+             && target.getMouseListeners().length == 0
+             && target.getMouseMotionListeners().length == 0
+             && target.getMouseWheelListeners().length == 0)
         {
-          candidate = SwingUtilities.getDeepestComponentAt(parent, p.x, p.y);
-          if (candidate == null)
-            {
-              p = SwingUtilities.convertPoint(parent, p.x, p.y,
-                                              parent.getParent());
-              parent = parent.getParent();
-            }
-        }
-
-      // If the only candidate we found was the native container itself,
-      // don't dispatch any event at all. We only care about the lightweight
-      // children here.
-      if (candidate == frame.getContentPane())
-        candidate = null;
-
-      // If our candidate is new, inform the old target we're leaving.
-      if (lastComponentEntered != null && lastComponentEntered.isShowing()
-          && lastComponentEntered != candidate)
-        {
-          Point tp = SwingUtilities.convertPoint(frame.getContentPane(), x, y,
-                                                 lastComponentEntered);
-          MouseEvent exited = new MouseEvent(lastComponentEntered,
-                                             MouseEvent.MOUSE_EXITED,
-                                             me.getWhen(), me.getModifiersEx(),
-                                             tp.x, tp.y, me.getClickCount(),
-                                             me.isPopupTrigger(),
-                                             me.getButton());
-          tempComponent = lastComponentEntered;
-          lastComponentEntered = null;
-          tempComponent.dispatchEvent(exited);
-        }
-
-      // If we have a candidate, maybe enter it.
-      if (candidate != null)
-        {
-          mouseEventTarget = candidate;
-          if (candidate.isLightweight() && candidate.isShowing()
-              && candidate != frame.getContentPane()
-              && candidate != lastComponentEntered)
-            {
-              lastComponentEntered = mouseEventTarget;
-              Point cp = SwingUtilities.convertPoint(frame.getContentPane(), x,
-                                                     y, lastComponentEntered);
-              MouseEvent entered = new MouseEvent(lastComponentEntered,
-                                                  MouseEvent.MOUSE_ENTERED,
-                                                  me.getWhen(),
-                                                  me.getModifiersEx(), cp.x,
-                                                  cp.y, me.getClickCount(),
-                                                  me.isPopupTrigger(),
-                                                  me.getButton());
-              lastComponentEntered.dispatchEvent(entered);
-            }
-        }
-
-      if (me.getID() == MouseEvent.MOUSE_RELEASED
-          || me.getID() == MouseEvent.MOUSE_PRESSED && pressCount > 0
-          || me.getID() == MouseEvent.MOUSE_DRAGGED)
-        // If any of the following events occur while a button is held down,
-        // they should be dispatched to the same component to which the
-        // original MOUSE_PRESSED event was dispatched:
-        // - MOUSE_RELEASED
-        // - MOUSE_PRESSED: another button pressed while the first is held down
-        // - MOUSE_DRAGGED
-        mouseEventTarget = pressedComponent;
-      else if (me.getID() == MouseEvent.MOUSE_CLICKED)
-        {
-          // Don't dispatch CLICKED events whose target is not the same as the
-          // target for the original PRESSED event.
-          if (candidate != pressedComponent)
-            mouseEventTarget = null;
-          else if (pressCount == 0)
-            pressedComponent = null;
+          target = target.getParent();
         }
-    }
 
-    /**
-     * This is a helper method that dispatches the GlassPane MouseEvents to the
-     * proper component.
-     * 
-     * @param e
-     *          The AWTEvent to be dispatched. Usually an instance of
-     *          MouseEvent.
-     */
-    private void handleEvent(AWTEvent e)
-    {
-      if (e instanceof MouseEvent)
+      if (target != null)
         {
-          MouseEvent me = (MouseEvent) e;
-          acquireComponentForMouseEvent(me);
-
-          //If there is no target, return
-          if (mouseEventTarget == null)
-            return;
-          
-          //Avoid re-dispatching to ourselves and causing an infinite loop
-          if (mouseEventTarget.equals(frame.getGlassPane()))
-            return;
-
-          // Avoid dispatching ENTERED and EXITED events twice.
-          if (mouseEventTarget.isShowing()
-              && e.getID() != MouseEvent.MOUSE_ENTERED
-              && e.getID() != MouseEvent.MOUSE_EXITED)
-            {
-              MouseEvent newEvt = SwingUtilities.convertMouseEvent(
-                                                                   frame.getGlassPane(),
-                                                                   me,
-                                                                   mouseEventTarget);
-              mouseEventTarget.dispatchEvent(newEvt);
-
-              switch (e.getID())
+          int id = e.getID();
+          switch (id)
+          {
+            case MouseEvent.MOUSE_ENTERED:
+              // Now redispatch the thing.
+              if (! isDragging || frame.isSelected())
                 {
-                case MouseEvent.MOUSE_PRESSED:
-                  if (pressCount++ == 0)
-                    pressedComponent = mouseEventTarget;
-                  break;
-                case MouseEvent.MOUSE_RELEASED:
-                  // Clear our memory of the original PRESSED event, only if
-                  // we're not expecting a CLICKED event after this. If
-                  // there is a CLICKED event after this, it will do clean up.
-                  if (--pressCount == 0 && mouseEventTarget != pressedComponent)
-                    pressedComponent = null;
-                  break;
+                  mouseEventTarget = target;
+                  redispatch(id, e, mouseEventTarget);
                 }
-            }
+              break;
+            case MouseEvent.MOUSE_EXITED:
+              if (! isDragging || frame.isSelected())
+                {
+                  redispatch(id, e, mouseEventTarget);
+                }
+              break;
+            case MouseEvent.MOUSE_PRESSED:
+              mouseEventTarget = target;
+              redispatch(id, e, mouseEventTarget);
+              // Start dragging.
+              dragTarget = target;
+              break;
+            case MouseEvent.MOUSE_RELEASED:
+              if (isDragging)
+                {
+                  redispatch(id, e, dragTarget);
+                  isDragging = false;
+                }
+              else
+                redispatch(id, e, mouseEventTarget);
+              break;
+            case MouseEvent.MOUSE_CLICKED:
+              redispatch(id, e, mouseEventTarget);
+              break;
+            case MouseEvent.MOUSE_MOVED:
+              if (target != mouseEventTarget)
+                {
+                  // Create additional MOUSE_EXITED/MOUSE_ENTERED pairs.
+                  redispatch(MouseEvent.MOUSE_EXITED, e, mouseEventTarget);
+                  mouseEventTarget = target;
+                  redispatch(MouseEvent.MOUSE_ENTERED, e, mouseEventTarget);
+                }
+              redispatch(id, e, mouseEventTarget);
+              break;
+            case MouseEvent.MOUSE_DRAGGED:
+              if (! isDragging)
+                isDragging = true;
+              redispatch(id, e, mouseEventTarget);
+              break;
+            case MouseEvent.MOUSE_WHEEL:
+              redispatch(id, e, mouseEventTarget);
+              break;
+            default:
+              assert false : "Must not reach here";
+          }
         }
     }
+
+    /**
+     * Redispatches the event to the real target with the specified id.
+     *
+     * @param id the new event ID
+     * @param e the original event
+     * @param target the real event target
+     */
+    private void redispatch(int id, MouseEvent e, Component target)
+    {
+      Point p = SwingUtilities.convertPoint(frame.getLayeredPane(), e.getX(),
+                                            e.getY(), target);
+      MouseEvent ev = new MouseEvent(target, id, e.getWhen(),
+                                     e.getModifiers() | e.getModifiersEx(),
+                                     p.x, p.y, e.getClickCount(),
+                                     e.isPopupTrigger());
+      target.dispatchEvent(ev);
+    }
   }
 
   /**
    * This helper class listens for PropertyChangeEvents from the
    * JInternalFrame.
    */
   public class InternalFramePropertyChangeListener
     implements PropertyChangeListener
   {
 
     /**
      * This method is called when one of the JInternalFrame's properties change.
@@ -953,28 +905,35 @@
           else
             minimizeFrame(frame);
         }
       else if (property.equals(JInternalFrame.IS_ICON_PROPERTY))
         {
           if (frame.isIcon())
             iconifyFrame(frame);
           else
             deiconifyFrame(frame);
         }
       else if (property.equals(JInternalFrame.IS_SELECTED_PROPERTY))
         {
+          Component glassPane = frame.getGlassPane();
           if (frame.isSelected())
-            activateFrame(frame);
+            {
+              activateFrame(frame);
+              glassPane.setVisible(false);
+            }
           else
-            deactivateFrame(frame);
+            {
+              deactivateFrame(frame);
+              glassPane.setVisible(true);
+            }
         }
       else if (property.equals(JInternalFrame.ROOT_PANE_PROPERTY)
                || property.equals(JInternalFrame.GLASS_PANE_PROPERTY))
         {
           Component old = (Component) evt.getOldValue();
           if (old != null)
             {
               old.removeMouseListener(glassPaneDispatcher);
               old.removeMouseMotionListener(glassPaneDispatcher);
             }
 
           Component newPane = (Component) evt.getNewValue();

Reply via email to