jdk/src/share/classes/java/awt/Container.java
changeset 4261 126dc6fe0d7b
parent 4259 b41995ac0c17
child 4263 db2d1f69a60e
--- a/jdk/src/share/classes/java/awt/Container.java	Mon Oct 19 16:06:41 2009 +0400
+++ b/jdk/src/share/classes/java/awt/Container.java	Wed Oct 21 17:06:41 2009 +0400
@@ -1492,20 +1492,59 @@
     }
 
     /**
-     * Invalidates the container.  The container and all parents
-     * above it are marked as needing to be laid out.  This method can
-     * be called often, so it needs to execute quickly.
+     * Indicates if this container is a <i>validate root</i>.
+     * <p>
+     * Layout-related changes, such as bounds of the validate root descendants,
+     * do not affect the layout of the validate root parent. This peculiarity
+     * enables the {@code invalidate()} method to stop invalidating the
+     * component hierarchy when the method encounters a validate root.
+     * <p>
+     * If a component hierarchy contains validate roots, the {@code validate()}
+     * method must be invoked on the validate root of a previously invalidated
+     * component, rather than on the top-level container (such as a {@code
+     * Frame} object) to restore the validity of the hierarchy later.
+     * <p>
+     * The {@code Window} class and the {@code Applet} class are the validate
+     * roots in AWT.  Swing introduces more validate roots.
      *
-     * <p> If the {@code LayoutManager} installed on this container is
-     * an instance of {@code LayoutManager2}, then
-     * {@link LayoutManager2#invalidateLayout(Container)} is invoked on
-     * it supplying this {@code Container} as the argument.
+     * @return whether this container is a validate root
+     * @see #invalidate
+     * @see java.awt.Component#invalidate
+     * @see javax.swing.JComponent#isValidateRoot
+     * @see javax.swing.JComponent#revalidate
+     * @since 1.7
+     */
+    public boolean isValidateRoot() {
+        return false;
+    }
+
+    /**
+     * Invalidates the parent of the container unless the container
+     * is a validate root.
+     */
+    @Override
+    void invalidateParent() {
+        if (!isValidateRoot()) {
+            super.invalidateParent();
+        }
+    }
+
+    /**
+     * Invalidates the container.
+     * <p>
+     * If the {@code LayoutManager} installed on this container is an instance
+     * of the {@code LayoutManager2} interface, then
+     * the {@link LayoutManager2#invalidateLayout(Container)} method is invoked
+     * on it supplying this {@code Container} as the argument.
+     * <p>
+     * Afterwards this method marks this container invalid, and invalidates its
+     * ancestors. See the {@link Component#invalidate} method for more details.
      *
      * @see #validate
      * @see #layout
-     * @see LayoutManager
-     * @see LayoutManager2#invalidateLayout(Container)
+     * @see LayoutManager2
      */
+    @Override
     public void invalidate() {
         LayoutManager layoutMgr = this.layoutMgr;
         if (layoutMgr instanceof LayoutManager2) {
@@ -1518,35 +1557,39 @@
     /**
      * Validates this container and all of its subcomponents.
      * <p>
-     * The <code>validate</code> method is used to cause a container
-     * to lay out its subcomponents again. It should be invoked when
-     * this container's subcomponents are modified (added to or
-     * removed from the container, or layout-related information
-     * changed) after the container has been displayed.
-     *
-     * <p>If this {@code Container} is not valid, this method invokes
+     * Validating a container means laying out its subcomponents.
+     * Layout-related changes, such as setting the bounds of a component, or
+     * adding a component to the container, invalidate the container
+     * automatically.  Note that the ancestors of the container may be
+     * invalidated also (see {@link Component#invalidate} for details.)
+     * Therefore, to restore the validity of the hierarchy, the {@code
+     * validate()} method should be invoked on a validate root of an
+     * invalidated component, or on the top-most container if the hierarchy
+     * does not contain validate roots.
+     * <p>
+     * Validating the container may be a quite time-consuming operation. For
+     * performance reasons a developer may postpone the validation of the
+     * hierarchy till a set of layout-related operations completes, e.g. after
+     * adding all the children to the container.
+     * <p>
+     * If this {@code Container} is not valid, this method invokes
      * the {@code validateTree} method and marks this {@code Container}
      * as valid. Otherwise, no action is performed.
-     * <p>
-     * Note that the {@code invalidate()} method may invalidate not only the
-     * component it is called upon, but also the parents of the component.
-     * Therefore, to restore the validity of the hierarchy, the {@code
-     * validate()} method must be invoked on the top-most invalid container of
-     * the hierarchy. For performance reasons a developer may postpone the
-     * validation of the hierarchy till a bunch of layout-related operations
-     * completes, e.g. after adding all the children to the container.
      *
      * @see #add(java.awt.Component)
      * @see #invalidate
+     * @see Container#isValidateRoot
      * @see javax.swing.JComponent#revalidate()
      * @see #validateTree
      */
     public void validate() {
         /* Avoid grabbing lock unless really necessary. */
-        if (!isValid()) {
+        if (!isValid() || descendUnconditionallyWhenValidating) {
             boolean updateCur = false;
             synchronized (getTreeLock()) {
-                if (!isValid() && peer != null) {
+                if ((!isValid() || descendUnconditionallyWhenValidating)
+                        && peer != null)
+                {
                     ContainerPeer p = null;
                     if (peer instanceof ContainerPeer) {
                         p = (ContainerPeer) peer;
@@ -1557,7 +1600,11 @@
                     validateTree();
                     if (p != null) {
                         p.endValidate();
-                        updateCur = isVisible();
+                        // Avoid updating cursor if this is an internal call.
+                        // See validateUnconditionally() for details.
+                        if (!descendUnconditionallyWhenValidating) {
+                            updateCur = isVisible();
+                        }
                     }
                 }
             }
@@ -1568,6 +1615,39 @@
     }
 
     /**
+     * Indicates whether valid containers should also traverse their
+     * children and call the validateTree() method on them.
+     *
+     * Synchronization: TreeLock.
+     *
+     * The field is allowed to be static as long as the TreeLock itself is
+     * static.
+     *
+     * @see #validateUnconditionally()
+     */
+    private static boolean descendUnconditionallyWhenValidating = false;
+
+    /**
+     * Unconditionally validate the component hierarchy.
+     */
+    final void validateUnconditionally() {
+        boolean updateCur = false;
+        synchronized (getTreeLock()) {
+            descendUnconditionallyWhenValidating = true;
+
+            validate();
+            if (peer instanceof ContainerPeer) {
+                updateCur = isVisible();
+            }
+
+            descendUnconditionallyWhenValidating = false;
+        }
+        if (updateCur) {
+            updateCursorImmediately();
+        }
+    }
+
+    /**
      * Recursively descends the container tree and recomputes the
      * layout for any subtrees marked as needing it (those marked as
      * invalid).  Synchronization should be provided by the method
@@ -1578,16 +1658,20 @@
      */
     protected void validateTree() {
         checkTreeLock();
-        if (!isValid()) {
+        if (!isValid() || descendUnconditionallyWhenValidating) {
             if (peer instanceof ContainerPeer) {
                 ((ContainerPeer)peer).beginLayout();
             }
-            doLayout();
+            if (!isValid()) {
+                doLayout();
+            }
             for (int i = 0; i < component.size(); i++) {
                 Component comp = component.get(i);
                 if (   (comp instanceof Container)
                        && !(comp instanceof Window)
-                       && !comp.isValid()) {
+                       && (!comp.isValid() ||
+                           descendUnconditionallyWhenValidating))
+                {
                     ((Container)comp).validateTree();
                 } else {
                     comp.validate();