OSDN Git Service

2006-08-14 Mark Wielaard <mark@klomp.org>
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / awt / Container.java
index 85a68ce..409d164 100644 (file)
@@ -42,6 +42,7 @@ package java.awt;
 import java.awt.event.ComponentListener;
 import java.awt.event.ContainerEvent;
 import java.awt.event.ContainerListener;
+import java.awt.event.HierarchyEvent;
 import java.awt.event.KeyEvent;
 import java.awt.peer.ComponentPeer;
 import java.awt.peer.ContainerPeer;
@@ -88,14 +89,16 @@ public class Container extends Component
   Dimension maxSize;
 
   /**
-   * Keeps track if the Container was cleared during a paint/update.
+   * @since 1.4
    */
-  private boolean backCleared;
+  boolean focusCycleRoot;
 
   /**
-   * @since 1.4
+   * Indicates if this container provides a focus traversal policy.
+   *
+   * @since 1.5
    */
-  boolean focusCycleRoot;
+  private boolean focusTraversalPolicyProvider;
 
   int containerSerializedDataVersion;
 
@@ -341,7 +344,7 @@ public class Container extends Component
 
         if (component == null)
           component = new Component[4]; // FIXME, better initial size?
-
+   
         // This isn't the most efficient implementation.  We could do less
         // copying when growing the array.  It probably doesn't matter.
         if (ncomponents >= component.length)
@@ -362,6 +365,16 @@ public class Container extends Component
             ++ncomponents;
           }
 
+        // Update the counter for Hierarchy(Bounds)Listeners.
+        int childHierarchyListeners = comp.numHierarchyListeners;
+        if (childHierarchyListeners > 0)
+          updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK,
+                                       childHierarchyListeners);
+        int childHierarchyBoundsListeners = comp.numHierarchyBoundsListeners;
+        if (childHierarchyBoundsListeners > 0)
+          updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
+                                       childHierarchyListeners);
+
         // Notify the layout manager.
         if (layoutMgr != null)
           {
@@ -388,6 +401,10 @@ public class Container extends Component
         ContainerListener[] listeners = getContainerListeners();
         for (int i = 0; i < listeners.length; i++)
           listeners[i].componentAdded(ce);
+
+        // Notify hierarchy listeners.
+        comp.fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, comp,
+                                this, HierarchyEvent.PARENT_CHANGED);
       }
   }
 
@@ -412,6 +429,16 @@ public class Container extends Component
                          ncomponents - index - 1);
         component[--ncomponents] = null;
 
+        // Update the counter for Hierarchy(Bounds)Listeners.
+        int childHierarchyListeners = r.numHierarchyListeners;
+        if (childHierarchyListeners > 0)
+          updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK,
+                                       -childHierarchyListeners);
+        int childHierarchyBoundsListeners = r.numHierarchyBoundsListeners;
+        if (childHierarchyBoundsListeners > 0)
+          updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
+                                       -childHierarchyListeners);
+
         invalidate();
 
         if (layoutMgr != null)
@@ -423,10 +450,14 @@ public class Container extends Component
           {
             // Post event to notify of removing the component.
             ContainerEvent ce = new ContainerEvent(this,
-                                                   ContainerEvent.COMPONENT_REMOVED,
-                                                   r);
+                                               ContainerEvent.COMPONENT_REMOVED,
+                                               r);
             getToolkit().getSystemEventQueue().postEvent(ce);
           }
+
+        // Notify hierarchy listeners.
+        r.fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, r,
+                             this, HierarchyEvent.PARENT_CHANGED);
       }
   }
 
@@ -517,7 +548,8 @@ public class Container extends Component
   public void setLayout(LayoutManager mgr)
   {
     layoutMgr = mgr;
-    invalidate();
+    if (valid)
+      invalidate();
   }
 
   /**
@@ -572,19 +604,22 @@ public class Container extends Component
    */
   void invalidateTree()
   {
-    super.invalidate();  // Clean cached layout state.
-    for (int i = 0; i < ncomponents; i++)
+    synchronized (getTreeLock())
       {
-        Component comp = component[i];
-        comp.invalidate();
-        if (comp instanceof Container)
-          ((Container) comp).invalidateTree();
-      }
+        super.invalidate();  // Clean cached layout state.
+        for (int i = 0; i < ncomponents; i++)
+          {
+            Component comp = component[i];
+            comp.invalidate();
+            if (comp instanceof Container)
+              ((Container) comp).invalidateTree();
+          }
 
-    if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
-      {
-        LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
-        lm2.invalidateLayout(this);
+        if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
+          {
+            LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
+            lm2.invalidateLayout(this);
+          }
       }
   }
 
@@ -671,21 +706,25 @@ public class Container extends Component
    */
   public Dimension preferredSize()
   {
-    synchronized(treeLock)
-      {  
-        if(valid && prefSize != null)
-          return new Dimension(prefSize);
-        LayoutManager layout = getLayout();
-        if (layout != null)
+    Dimension size = prefSize;
+    // Try to return cached value if possible.
+    if (size == null || !(prefSizeSet || valid))
+      {
+        // Need to lock here.
+        synchronized (getTreeLock())
           {
-            Dimension layoutSize = layout.preferredLayoutSize(this);
-            if(valid)
-              prefSize = layoutSize;
-            return new Dimension(layoutSize);
+            LayoutManager l = layoutMgr;
+            if (l != null)
+              prefSize = l.preferredLayoutSize(this);
+            else
+              prefSize = super.preferredSizeImpl();
+            size = prefSize;
           }
-        else
-          return super.preferredSize ();
       }
+    if (size != null)
+      return new Dimension(size);
+    else
+      return size;
   }
 
   /**
@@ -707,17 +746,25 @@ public class Container extends Component
    */
   public Dimension minimumSize()
   {
-    if(valid && minSize != null)
-      return new Dimension(minSize);
-
-    LayoutManager layout = getLayout();
-    if (layout != null)
+    Dimension size = minSize;
+    // Try to return cached value if possible.
+    if (size == null || !(minSizeSet || valid))
       {
-        minSize = layout.minimumLayoutSize (this);
-        return minSize;
-      }    
+        // Need to lock here.
+        synchronized (getTreeLock())
+          {
+            LayoutManager l = layoutMgr;
+            if (l != null)
+              minSize = l.minimumLayoutSize(this);
+            else
+              minSize = super.minimumSizeImpl();
+            size = minSize;
+          }
+      }
+    if (size != null)
+      return new Dimension(size);
     else
-      return super.minimumSize ();
+      return size;
   }
 
   /**
@@ -727,18 +774,25 @@ public class Container extends Component
    */
   public Dimension getMaximumSize()
   {
-    if (valid && maxSize != null)
-      return new Dimension(maxSize);
-
-    LayoutManager layout = getLayout();
-    if (layout != null && layout instanceof LayoutManager2)
+    Dimension size = maxSize;
+    // Try to return cached value if possible.
+    if (size == null || !(maxSizeSet || valid))
       {
-        LayoutManager2 lm2 = (LayoutManager2) layout;
-        maxSize = lm2.maximumLayoutSize(this);
-        return maxSize;
+        // Need to lock here.
+        synchronized (getTreeLock())
+          {
+            LayoutManager l = layoutMgr;
+            if (l instanceof LayoutManager2)
+              maxSize = ((LayoutManager2) l).maximumLayoutSize(this);
+            else
+              maxSize = super.maximumSizeImpl();
+            size = maxSize;
+          }
       }
+    if (size != null)
+      return new Dimension(size);
     else
-      return super.getMaximumSize();
+      return size;
   }
 
   /**
@@ -754,8 +808,11 @@ public class Container extends Component
     float alignmentX = 0.0F;
     if (layout != null && layout instanceof LayoutManager2)
       {
-        LayoutManager2 lm2 = (LayoutManager2) layout;
-        alignmentX = lm2.getLayoutAlignmentX(this);
+        synchronized (getTreeLock())
+          {
+            LayoutManager2 lm2 = (LayoutManager2) layout;
+            alignmentX = lm2.getLayoutAlignmentX(this);
+          }
       }
     else
       alignmentX = super.getAlignmentX();
@@ -775,8 +832,11 @@ public class Container extends Component
     float alignmentY = 0.0F;
     if (layout != null && layout instanceof LayoutManager2)
       {
-        LayoutManager2 lm2 = (LayoutManager2) layout;
-        alignmentY = lm2.getLayoutAlignmentY(this);
+        synchronized (getTreeLock())
+          {
+            LayoutManager2 lm2 = (LayoutManager2) layout;
+            alignmentY = lm2.getLayoutAlignmentY(this);
+          }
       }
     else
       alignmentY = super.getAlignmentY();
@@ -794,13 +854,10 @@ public class Container extends Component
    */
   public void paint(Graphics g)
   {
-    if (!isShowing())
-      return;
-
-    // Visit heavyweights if the background was cleared
-    // for this container.
-    visitChildren(g, GfxPaintVisitor.INSTANCE, !backCleared);
-    backCleared = false;
+    if (isShowing())
+      {
+        visitChildren(g, GfxPaintVisitor.INSTANCE, true);
+      }
   }
 
   /**
@@ -830,14 +887,15 @@ public class Container extends Component
     // 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))
+    if (isShowing())
       {
-        g.clearRect(0, 0, getWidth(), getHeight());
-        backCleared = true;
+        ComponentPeer p = peer;
+        if (! (p instanceof LightweightPeer))
+          {
+            g.clearRect(0, 0, getWidth(), getHeight());
+          }
+        paint(g);
       }
-
-    paint(g);
   }
 
   /**
@@ -1173,8 +1231,11 @@ public class Container extends Component
    */
   public void addNotify()
   {
-    super.addNotify();
-    addNotifyContainerChildren();
+    synchronized (getTreeLock())
+      {
+        super.addNotify();
+        addNotifyContainerChildren();
+      }
   }
 
   /**
@@ -1549,6 +1610,42 @@ public class Container extends Component
   }
 
   /**
+   * Set to <code>true</code> if this container provides a focus traversal
+   * policy, <code>false</code> when the root container's focus
+   * traversal policy should be used.
+   *
+   * @return <code>true</code> if this container provides a focus traversal
+   *        policy, <code>false</code> when the root container's focus
+   *        traversal policy should be used
+   *
+   * @see #setFocusTraversalPolicyProvider(boolean)
+   *
+   * @since 1.5
+   */
+  public final boolean isFocusTraversalPolicyProvider()
+  {
+    return focusTraversalPolicyProvider;
+  }
+
+  /**
+   * Set to <code>true</code> if this container provides a focus traversal
+   * policy, <code>false</code> when the root container's focus
+   * traversal policy should be used.
+   *
+   * @param b <code>true</code> if this container provides a focus traversal
+   *        policy, <code>false</code> when the root container's focus
+   *        traversal policy should be used
+   * 
+   * @see #isFocusTraversalPolicyProvider()
+   *
+   * @since 1.5
+   */
+  public final void setFocusTraversalPolicyProvider(boolean b)
+  {
+    focusTraversalPolicyProvider = b;
+  }
+
+  /**
    * Check whether this Container is a focus cycle root.
    *
    * @return true if this is a focus cycle root, false otherwise
@@ -1594,7 +1691,16 @@ public class Container extends Component
   public void applyComponentOrientation (ComponentOrientation orientation)
   {
     if (orientation == null)
-      throw new NullPointerException ();
+      throw new NullPointerException();
+
+    setComponentOrientation(orientation);
+    for (int i = 0; i < ncomponents; i++)
+      {
+        if (component[i] instanceof Container)
+             ((Container) component[i]).applyComponentOrientation(orientation); 
+          else
+             component[i].setComponentOrientation(orientation);
+      }
   }
 
   public void addPropertyChangeListener (PropertyChangeListener listener)
@@ -1646,24 +1752,27 @@ public class Container extends Component
     if (comp == this)
       throw new IllegalArgumentException("cannot add component to itself");
 
-    // FIXME: Implement reparenting.
-    if ( comp.getParent() != this)
-      throw new AssertionError("Reparenting is not implemented yet");
-    else
+    synchronized (getTreeLock())
       {
-        // Find current component index.
-        int currentIndex = getComponentZOrder(comp);
-        if (currentIndex < index)
-          {
-            System.arraycopy(component, currentIndex + 1, component,
-                             currentIndex, index - currentIndex);
-          }
+        // FIXME: Implement reparenting.
+        if ( comp.getParent() != this)
+          throw new AssertionError("Reparenting is not implemented yet");
         else
           {
-            System.arraycopy(component, index, component, index + 1,
-                             currentIndex - index);
+            // Find current component index.
+            int currentIndex = getComponentZOrder(comp);
+            if (currentIndex < index)
+              {
+                System.arraycopy(component, currentIndex + 1, component,
+                                 currentIndex, index - currentIndex);
+              }
+            else
+              {
+                System.arraycopy(component, index, component, index + 1,
+                                 currentIndex - index);
+              }
+            component[index] = comp;
           }
-        component[index] = comp;
       }
   }
 
@@ -1682,19 +1791,22 @@ public class Container extends Component
    */
   public final int getComponentZOrder(Component comp)
   {
-    int index = -1;
-    if (component != null)
+    synchronized (getTreeLock())
       {
-        for (int i = 0; i < component.length; i++)
+        int index = -1;
+        if (component != null)
           {
-            if (component[i] == comp)
+            for (int i = 0; i < ncomponents; i++)
               {
-                index = i;
-                break;
+                if (component[i] == comp)
+                  {
+                    index = i;
+                    break;
+                  }
               }
           }
+        return index;
       }
-    return index;
   }
 
   // Hidden helper methods.
@@ -1850,6 +1962,48 @@ public class Container extends Component
       }
   }
 
+  /**
+   * Fires hierarchy events to the children of this container and this
+   * container itself. This overrides {@link Component#fireHierarchyEvent}
+   * in order to forward this event to all children.
+   */
+  void fireHierarchyEvent(int id, Component changed, Container parent,
+                          long flags)
+  {
+    // Only propagate event if there is actually a listener waiting for it.
+    if ((id == HierarchyEvent.HIERARCHY_CHANGED && numHierarchyListeners > 0)
+        || ((id == HierarchyEvent.ANCESTOR_MOVED
+             || id == HierarchyEvent.ANCESTOR_RESIZED)
+            && numHierarchyBoundsListeners > 0))
+      {
+        for (int i = 0; i < ncomponents; i++)
+          component[i].fireHierarchyEvent(id, changed, parent, flags);
+        super.fireHierarchyEvent(id, changed, parent, flags);
+      }
+  }
+
+  /**
+   * Adjusts the number of hierarchy listeners of this container and all of
+   * its parents. This is called by the add/remove listener methods and
+   * structure changing methods in Container.
+   *
+   * @param type the type, either {@link AWTEvent#HIERARCHY_BOUNDS_EVENT_MASK}
+   *        or {@link AWTEvent#HIERARCHY_EVENT_MASK}
+   * @param delta the number of listeners added or removed
+   */
+  void updateHierarchyListenerCount(long type, int delta)
+  {
+    if (type == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)
+      numHierarchyBoundsListeners += delta;
+    else if (type == AWTEvent.HIERARCHY_EVENT_MASK)
+      numHierarchyListeners += delta;
+    else
+      assert false : "Should not reach here";
+
+    if (parent != null)
+      parent.updateHierarchyListenerCount(type, delta);
+  }
+
   private void addNotifyContainerChildren()
   {
     synchronized (getTreeLock ())