OSDN Git Service

Imported Classpath 0.18.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / awt / Container.java
index 303d13b..13d32f8 100644 (file)
@@ -42,6 +42,7 @@ import java.awt.event.ContainerEvent;
 import java.awt.event.ContainerListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseEvent;
+import java.awt.peer.ComponentPeer;
 import java.awt.peer.ContainerPeer;
 import java.awt.peer.LightweightPeer;
 import java.beans.PropertyChangeListener;
@@ -59,7 +60,8 @@ import java.util.Iterator;
 import java.util.Set;
 
 import javax.accessibility.Accessible;
-import javax.swing.SwingUtilities;
+
+import gnu.java.awt.AWTUtilities;
 
 /**
  * A generic window toolkit object that acts as a container for other objects.
@@ -338,8 +340,12 @@ public class Container extends Component
         if (comp.parent != null)
           comp.parent.remove(comp);
         comp.parent = this;
+
         if (peer != null)
           {
+           // Notify the component that it has a new parent.
+           comp.addNotify();
+
             if (comp.isLightweight ())
              {
                enableEvents (comp.eventMask);
@@ -348,7 +354,8 @@ public class Container extends Component
              }
           }
 
-        invalidate();
+        // Invalidate the layout of the added component and its ancestors.
+        comp.invalidate();
 
         if (component == null)
           component = new Component[4]; // FIXME, better initial size?
@@ -394,6 +401,9 @@ public class Container extends Component
                                                    ContainerEvent.COMPONENT_ADDED,
                                                    comp);
             getToolkit().getSystemEventQueue().postEvent(ce);
+
+            // Repaint this container.
+            repaint();
           }
       }
   }
@@ -429,6 +439,9 @@ public class Container extends Component
                                                    ContainerEvent.COMPONENT_REMOVED,
                                                    r);
             getToolkit().getSystemEventQueue().postEvent(ce);
+
+            // Repaint this container.
+            repaint();
           }
       }
   }
@@ -513,6 +526,11 @@ public class Container extends Component
   public void invalidate()
   {
     super.invalidate();
+    if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
+      {
+        LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
+        lm2.invalidateLayout(this);
+      }
   }
 
   /**
@@ -534,6 +552,7 @@ public class Container extends Component
    */
   void invalidateTree()
   {
+    super.invalidate();  // Clean cached layout state.
     for (int i = 0; i < ncomponents; i++)
       {
         Component comp = component[i];
@@ -541,6 +560,12 @@ public class Container extends Component
         if (comp instanceof Container)
           ((Container) comp).invalidateTree();
       }
+
+    if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
+      {
+        LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
+        lm2.invalidateLayout(this);
+      }
   }
 
   /**
@@ -596,11 +621,15 @@ public class Container extends Component
 
   public void setFont(Font f)
   {
-    super.setFont(f);
-    // FIXME: Although it might make more sense to invalidate only
-    // those children whose font == null, Sun invalidates all children.
-    // So we'll do the same.
-    invalidateTree();
+    if( (f != null && (font == null || !font.equals(f)))
+        || f == null)
+      {
+        super.setFont(f);
+        // FIXME: Although it might make more sense to invalidate only
+        // those children whose font == null, Sun invalidates all children.
+        // So we'll do the same.
+        invalidateTree();
+      }
   }
 
   /**
@@ -622,10 +651,21 @@ public class Container extends Component
    */
   public Dimension preferredSize()
   {
-    if (layoutMgr != null)
-      return layoutMgr.preferredLayoutSize (this);
-    else
-      return super.preferredSize ();
+    synchronized(treeLock)
+      {  
+        if(valid && prefSize != null)
+          return new Dimension(prefSize);
+        LayoutManager layout = getLayout();
+        if (layout != null)
+          {
+            Dimension layoutSize = layout.preferredLayoutSize(this);
+            if(valid)
+              prefSize = layoutSize;
+            return new Dimension(layoutSize);
+          }
+        else
+          return super.preferredSize ();
+      }
   }
 
   /**
@@ -647,8 +687,15 @@ public class Container extends Component
    */
   public Dimension minimumSize()
   {
-    if (layoutMgr != null)
-      return layoutMgr.minimumLayoutSize (this);
+    if(valid && minSize != null)
+      return new Dimension(minSize);
+
+    LayoutManager layout = getLayout();
+    if (layout != null)
+      {
+        minSize = layout.minimumLayoutSize (this);
+        return minSize;
+      }    
     else
       return super.minimumSize ();
   }
@@ -660,10 +707,15 @@ public class Container extends Component
    */
   public Dimension getMaximumSize()
   {
-    if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
+    if (valid && maxSize != null)
+      return new Dimension(maxSize);
+
+    LayoutManager layout = getLayout();
+    if (layout != null && layout instanceof LayoutManager2)
       {
-        LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
-        return lm2.maximumLayoutSize(this);
+        LayoutManager2 lm2 = (LayoutManager2) layout;
+        maxSize = lm2.maximumLayoutSize(this);
+        return maxSize;
       }
     else
       return super.getMaximumSize();
@@ -678,13 +730,7 @@ public class Container extends Component
    */
   public float getAlignmentX()
   {
-    if (layoutMgr instanceof LayoutManager2)
-      {
-        LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
-        return lm2.getLayoutAlignmentX(this);
-      }
-    else
-      return super.getAlignmentX();
+    return super.getAlignmentX();
   }
 
   /**
@@ -696,13 +742,7 @@ public class Container extends Component
    */
   public float getAlignmentY()
   {
-    if (layoutMgr instanceof LayoutManager2)
-      {
-        LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
-        return lm2.getLayoutAlignmentY(this);
-      }
-    else
-      return super.getAlignmentY();
+    return super.getAlignmentY();
   }
 
   /**
@@ -718,8 +758,7 @@ public class Container extends Component
   {
     if (!isShowing())
       return;
-    // Paint self first.
-    super.paint(g);
+
     // Visit heavyweights as well, in case they were
     // erased when we cleared the background for this container.
     visitChildren(g, GfxPaintVisitor.INSTANCE, false);
@@ -733,10 +772,30 @@ public class Container extends Component
    * drawn.
    *
    * @param g The graphics context for this update.
+   *
+   * @specnote The specification suggests that this method forwards the
+   *           update() call to all its lightweight children. Tests show
+   *           that this is not done either in the JDK. The exact behaviour
+   *           seems to be that the background is cleared in heavyweight
+   *           Containers, and all other containers
+   *           directly call paint(), causing the (lightweight) children to
+   *           be painted.
    */
   public void update(Graphics g)
   {
-    super.update(g);
+    // It seems that the JDK clears the background of containers like Panel
+    // and Window (within this method) but not of 'plain' Containers or
+    // JComponents. This could
+    // lead to the assumption that it only clears heavyweight containers.
+    // However that is not quite true. In a test with a custom Container
+    // that overrides isLightweight() to return false, the background is
+    // also not cleared. So we do a check on !(peer instanceof LightweightPeer)
+    // instead.
+    ComponentPeer p = peer;
+    if (p != null && !(p instanceof LightweightPeer))
+      g.clearRect(0, 0, getWidth(), getHeight());
+
+    paint(g);
   }
 
   /**
@@ -1198,7 +1257,7 @@ public class Container extends Component
       }
 
     if (focusTraversalKeys == null)
-      focusTraversalKeys = new Set[3];
+      focusTraversalKeys = new Set[4];
 
     keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes));
     firePropertyChange (name, focusTraversalKeys[id], keystrokes);
@@ -1465,12 +1524,8 @@ public class Container extends Component
         for (int i = ncomponents - 1; i >= 0; --i)
           {
             Component comp = component[i];
-            // If we're visiting heavyweights as well,
-            // don't recurse into Containers here. This avoids
-            // painting the same nested child multiple times.
             boolean applicable = comp.isVisible()
-              && (comp.isLightweight()
-                  || !lightweightOnly && ! (comp instanceof Container));
+              && (comp.isLightweight() || !lightweightOnly);
 
             if (applicable)
               visitChild(gfx, visitor, comp);
@@ -1525,11 +1580,9 @@ public class Container extends Component
   void dispatchEventImpl(AWTEvent e)
   {
     // Give lightweight dispatcher a chance to handle it.
-    if (eventTypeEnabled (e.id)
-        && dispatcher != null 
-        && dispatcher.handleEvent (e))
+    if (dispatcher != null && dispatcher.handleEvent (e))
       return;
-    
+
     if ((e.id <= ContainerEvent.CONTAINER_LAST
              && e.id >= ContainerEvent.CONTAINER_FIRST)
         && (containerListener != null
@@ -1539,6 +1592,26 @@ public class Container extends Component
       super.dispatchEventImpl(e);
   }
 
+  /**
+   * Tests if this container has an interest in the given event id.
+   *
+   * @param eventId The event id to check.
+   *
+   * @return <code>true</code> if a listener for the event id exists or
+   *         if the eventMask is set for the event id.
+   *
+   * @see java.awt.Component#eventTypeEnabled(int)
+   */
+  boolean eventTypeEnabled(int eventId)
+  {
+    if(eventId <= ContainerEvent.CONTAINER_LAST 
+       && eventId >= ContainerEvent.CONTAINER_FIRST)
+      return containerListener != null
+        || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0;
+      else 
+        return super.eventTypeEnabled(eventId);
+  }
+
   // This is used to implement Component.transferFocus.
   Component findNextFocusComponent(Component child)
   {
@@ -1603,12 +1676,11 @@ public class Container extends Component
 
                 // If we're not lightweight, and we just got a lightweight
                 // child, we need a lightweight dispatcher to feed it events.
-                if (! this.isLightweight()) 
-                  {
-                    if (dispatcher == null)
-                      dispatcher = new LightweightDispatcher (this);
-                  }    
-         
+                if (!this.isLightweight() && dispatcher == null) 
+                  dispatcher = new LightweightDispatcher (this);
+
+                if (dispatcher != null)
+                  dispatcher.enableEvents(component[i].eventMask);
 
                enableEvents(component[i].eventMask);
                if (peer != null && !isLightweight ())
@@ -1862,7 +1934,6 @@ public class Container extends Component
  * rather than mimic it exactly we write something which does "roughly
  * the same thing".
  */
-
 class LightweightDispatcher implements Serializable
 {
   private static final long serialVersionUID = 5184291520170872969L;
@@ -1870,10 +1941,8 @@ class LightweightDispatcher implements Serializable
   private Cursor nativeCursor;
   private long eventMask;
   
-  private transient Component mouseEventTarget;
   private transient Component pressedComponent;
   private transient Component lastComponentEntered;
-  private transient Component tempComponent;
   private transient int pressCount;
   
   LightweightDispatcher(Container c)
@@ -1881,11 +1950,17 @@ class LightweightDispatcher implements Serializable
     nativeContainer = c;
   }
 
-  void acquireComponentForMouseEvent(MouseEvent me)
+  void enableEvents(long l)
+  {
+    eventMask |= l;
+  }
+
+  Component acquireComponentForMouseEvent(MouseEvent me)
   {
     int x = me.getX ();
     int y = me.getY ();
 
+    Component mouseEventTarget = null;
     // Find the candidate which should receive this event.
     Component parent = nativeContainer;
     Component candidate = null;
@@ -1893,13 +1968,13 @@ class LightweightDispatcher implements Serializable
     while (candidate == null && parent != null)
       {
         candidate =
-          SwingUtilities.getDeepestComponentAt(parent, p.x, p.y);
+          AWTUtilities.getDeepestComponentAt(parent, p.x, p.y);
         if (candidate == null || (candidate.eventMask & me.getID()) == 0)
-        {
-          candidate = null;
-          p = SwingUtilities.convertPoint(parent, p.x, p.y, parent.parent);
-          parent = parent.parent;
-        }
+          {
+            candidate = null;
+            p = AWTUtilities.convertPoint(parent, p.x, p.y, parent.parent);
+            parent = parent.parent;
+          }
       }
 
     // If the only candidate we found was the native container itself,
@@ -1915,25 +1990,24 @@ class LightweightDispatcher implements Serializable
       {
         // Old candidate could have been removed from 
         // the nativeContainer so we check first.
-        if (SwingUtilities.isDescendingFrom(lastComponentEntered, nativeContainer))
-        {
-          Point tp = 
-            SwingUtilities.convertPoint(nativeContainer, 
-                                        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 (AWTUtilities.isDescendingFrom(lastComponentEntered,
+                                          nativeContainer))
+          {
+            Point tp = AWTUtilities.convertPoint(nativeContainer, 
+                                                 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 ());
+            lastComponentEntered.dispatchEvent (exited); 
+          }
         lastComponentEntered = null;
       }
+
     // If we have a candidate, maybe enter it.
     if (candidate != null)
       {
@@ -1942,10 +2016,10 @@ class LightweightDispatcher implements Serializable
             && candidate.isShowing()
             && candidate != nativeContainer
             && candidate != lastComponentEntered)
-         {                     
+         {
             lastComponentEntered = mouseEventTarget;
-            Point cp = SwingUtilities.convertPoint(nativeContainer, 
-                                                   x, y, lastComponentEntered);
+            Point cp = AWTUtilities.convertPoint(nativeContainer, 
+                                                 x, y, lastComponentEntered);
             MouseEvent entered = new MouseEvent (lastComponentEntered, 
                                                  MouseEvent.MOUSE_ENTERED,
                                                  me.getWhen (), 
@@ -1958,17 +2032,38 @@ class LightweightDispatcher implements Serializable
           }
       }
 
+    // Check which buttons where pressed except the last button that
+    // changed state.
+    int modifiers = me.getModifiersEx() & (MouseEvent.BUTTON1_DOWN_MASK
+                                           | MouseEvent.BUTTON2_DOWN_MASK
+                                           | MouseEvent.BUTTON3_DOWN_MASK);
+    switch(me.getButton())
+      {
+      case MouseEvent.BUTTON1:
+        modifiers &= ~MouseEvent.BUTTON1_DOWN_MASK;
+        break;
+      case MouseEvent.BUTTON2:
+        modifiers &= ~MouseEvent.BUTTON2_DOWN_MASK;
+        break;
+      case MouseEvent.BUTTON3:
+        modifiers &= ~MouseEvent.BUTTON3_DOWN_MASK;
+        break;
+      }
+
     if (me.getID() == MouseEvent.MOUSE_RELEASED
-        || me.getID() == MouseEvent.MOUSE_PRESSED && pressCount > 0
+        || me.getID() == MouseEvent.MOUSE_PRESSED && modifiers > 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
-      if (SwingUtilities.isDescendingFrom(pressedComponent, nativeContainer))
-        mouseEventTarget = pressedComponent;
+      {
+        // 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
+        if (AWTUtilities.isDescendingFrom(pressedComponent, nativeContainer))
+          mouseEventTarget = pressedComponent;
+      }
     else if (me.getID() == MouseEvent.MOUSE_CLICKED)
       {
         // Don't dispatch CLICKED events whose target is not the same as the
@@ -1978,6 +2073,7 @@ class LightweightDispatcher implements Serializable
         else if (pressCount == 0)
           pressedComponent = null;
       }
+    return mouseEventTarget;
   }
 
   boolean handleEvent(AWTEvent e)
@@ -1986,41 +2082,42 @@ class LightweightDispatcher implements Serializable
       {
         MouseEvent me = (MouseEvent) e;
 
-        acquireComponentForMouseEvent(me);
-       
+        // Make the LightWeightDispatcher reentrant. This is necessary when
+        // a lightweight component does its own modal event queue.
+        Component mouseEventTarget = acquireComponentForMouseEvent(me);
+
         // Avoid dispatching ENTERED and EXITED events twice.
         if (mouseEventTarget != null
             && mouseEventTarget.isShowing()
             && e.getID() != MouseEvent.MOUSE_ENTERED
             && e.getID() != MouseEvent.MOUSE_EXITED)
           {
-            MouseEvent newEvt = 
-              SwingUtilities.convertMouseEvent(nativeContainer, me, 
-                                               mouseEventTarget);
-            mouseEventTarget.dispatchEvent(newEvt);
-
             switch (e.getID())
               {
-                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;
+              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;
               }
-              if (newEvt.isConsumed())
-                e.consume();
+
+            MouseEvent newEvt =
+              AWTUtilities.convertMouseEvent(nativeContainer, me,
+                                             mouseEventTarget);
+            mouseEventTarget.dispatchEvent(newEvt);
+
+            if (newEvt.isConsumed())
+              e.consume();
           }
       }
-    
+
     return e.isConsumed();
   }
-
-} // class LightweightDispatcher
+}