Revision: 7746
Author: [email protected]
Date: Thu Mar 18 11:37:10 2010
Log: Remove the glass panel from DOM when Popup#removeFromParent is called.
http://gwt-code-reviews.appspot.com/220801

Review by: [email protected]
http://code.google.com/p/google-web-toolkit/source/detail?r=7746

Modified:
 /trunk/user/src/com/google/gwt/user/client/ui/PopupPanel.java
 /trunk/user/test/com/google/gwt/user/client/ui/PopupTest.java

=======================================
--- /trunk/user/src/com/google/gwt/user/client/ui/PopupPanel.java Tue Feb 16 07:47:04 2010 +++ /trunk/user/src/com/google/gwt/user/client/ui/PopupPanel.java Thu Mar 18 11:37:10 2010
@@ -34,12 +34,11 @@
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.i18n.client.LocaleInfo;
-import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.DeferredCommand;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.EventPreview;
 import com.google.gwt.user.client.History;
+import com.google.gwt.user.client.Timer;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.Event.NativePreviewEvent;
 import com.google.gwt.user.client.Event.NativePreviewHandler;
@@ -133,6 +132,13 @@
      */
     private PopupPanel curPanel = null;

+    /**
+     * Indicates whether or not the {...@link PopupPanel} is in the process of
+     * unloading. If the popup is unloading, then the animation just does
+     * cleanup.
+     */
+    private boolean isUnloading;
+
     /**
      * The offset height and width of the current {...@link PopupPanel}.
      */
@@ -143,6 +149,11 @@
      */
     private boolean showing;

+    /**
+     * The timer used to delay the show animation.
+     */
+    private Timer showTimer;
+
     /**
* A boolean indicating whether the glass element is currently attached.
      */
@@ -166,12 +177,25 @@
      *
      * @param showing true if the popup is showing, false if not
      */
-    public void setState(boolean showing) {
+    public void setState(boolean showing, boolean isUnloading) {
       // Immediately complete previous open/close animation
+      this.isUnloading = isUnloading;
       cancel();

+ // If there is a pending timer to start a show animation, then just cancel
+      // the timer and complete the show operation.
+      if (showTimer != null) {
+        showTimer.cancel();
+        showTimer = null;
+        onComplete();
+      }
+
+      // Update the logical state.
+      curPanel.showing = showing;
+      curPanel.updateHandlers();
+
       // Determine if we need to animate
-      boolean animate = curPanel.isAnimationEnabled;
+      boolean animate = !isUnloading && curPanel.isAnimationEnabled;
       if (curPanel.animType != AnimationType.CENTER && !showing) {
         animate = false;
       }
@@ -196,14 +220,21 @@
           impl.setClip(curPanel.getElement(), getRectString(0, 0, 0, 0));
           RootPanel.get().add(curPanel);
           impl.onShow(curPanel.getElement());
-        }
-
- // Wait for the popup panel to be attached before running the animation
-        DeferredCommand.addCommand(new Command() {
-          public void execute() {
-            run(ANIMATION_DURATION);
-          }
-        });
+
+ // Wait for the popup panel and iframe to be attached before running + // the animation. We use a Timer instead of a DeferredCommand so we
+          // can cancel it if the popup is hidden synchronously.
+          showTimer = new Timer() {
+            @Override
+            public void run() {
+              showTimer = null;
+              ResizeAnimation.this.run(ANIMATION_DURATION);
+            }
+          };
+          showTimer.schedule(1);
+        } else {
+          run(ANIMATION_DURATION);
+        }
       } else {
         onInstantaneousRun();
       }
@@ -213,7 +244,9 @@
     protected void onComplete() {
       if (!showing) {
         maybeShowGlass();
-        RootPanel.get().remove(curPanel);
+        if (!isUnloading) {
+          RootPanel.get().remove(curPanel);
+        }
         impl.onHide(curPanel.getElement());
       }
       impl.setClip(curPanel.getElement(), "rect(auto, auto, auto, auto)");
@@ -311,7 +344,9 @@
         RootPanel.get().add(curPanel);
         impl.onShow(curPanel.getElement());
       } else {
-        RootPanel.get().remove(curPanel);
+        if (!isUnloading) {
+          RootPanel.get().remove(curPanel);
+        }
         impl.onHide(curPanel.getElement());
       }
       DOM.setStyleAttribute(curPanel.getElement(), "overflow", "visible");
@@ -582,7 +617,7 @@
     if (!isShowing()) {
       return;
     }
-    setState(false, true);
+    resizeAnimation.setState(false, false);
     CloseEvent.fire(this, this, autoClosed);
   }

@@ -967,7 +1002,7 @@
     if (showing) {
       return;
     }
-    setState(true, true);
+    resizeAnimation.setState(true, false);
   }

   /**
@@ -1019,11 +1054,13 @@

   @Override
   protected void onUnload() {
+    super.onUnload();
+
     // Just to be sure, we perform cleanup when the popup is unloaded (i.e.
// removed from the DOM). This is normally taken care of in hide(), but it // can be missed if someone removes the popup directly from the RootPanel.
     if (isShowing()) {
-      setState(false, false);
+      resizeAnimation.setState(false, true);
     }
   }

@@ -1363,22 +1400,20 @@
   }

   /**
- * Set the showing state of the popup. If maybeAnimate is true, the animation
-   * will be used to set the state. If it is false, the animation will be
-   * cancelled.
-   *
-   * @param showing the new state
-   * @param maybeAnimate true to possibly run the animation
+   * Register or unregister the handlers used by {...@link PopupPanel}.
    */
-  private void setState(boolean showing, boolean maybeAnimate) {
-    if (maybeAnimate) {
-      resizeAnimation.setState(showing);
-    } else {
-      resizeAnimation.cancel();
-    }
-    this.showing = showing;
-
-    // Create or remove the native preview handler
+  private void updateHandlers() {
+    // Remove any existing handlers.
+    if (nativePreviewHandlerRegistration != null) {
+      nativePreviewHandlerRegistration.removeHandler();
+      nativePreviewHandlerRegistration = null;
+    }
+    if (historyHandlerRegistration != null) {
+      historyHandlerRegistration.removeHandler();
+      historyHandlerRegistration = null;
+    }
+
+    // Create handlers if showing.
     if (showing) {
nativePreviewHandlerRegistration = Event.addNativePreviewHandler(new NativePreviewHandler() {
         public void onPreviewNativeEvent(NativePreviewEvent event) {
@@ -1392,15 +1427,6 @@
           }
         }
       });
-    } else {
-      if (nativePreviewHandlerRegistration != null) {
-        nativePreviewHandlerRegistration.removeHandler();
-        nativePreviewHandlerRegistration = null;
-      }
-      if (historyHandlerRegistration != null) {
-        historyHandlerRegistration.removeHandler();
-        historyHandlerRegistration = null;
-      }
     }
   }
 }
=======================================
--- /trunk/user/test/com/google/gwt/user/client/ui/PopupTest.java Thu Feb 25 06:57:14 2010 +++ /trunk/user/test/com/google/gwt/user/client/ui/PopupTest.java Thu Mar 18 11:37:10 2010
@@ -269,6 +269,23 @@
     assertTrue(isAttached(glass));
     popup.hide();
   }
+
+  /**
+ * Test the hiding a popup while it is showing will not result in an illegal
+   * state.
+   */
+  public void testHideWhileShowing() {
+    PopupPanel popup = createPopupPanel();
+
+    // Start showing the popup.
+    popup.setAnimationEnabled(true);
+    popup.show();
+    assertTrue(popup.isShowing());
+
+    // Hide the popup while its showing.
+    popup.hide();
+    assertFalse(popup.isShowing());
+  }

   /**
* Test that the onLoad method is only called once when showing the popup.
@@ -365,6 +382,21 @@
     });
     popup.hide();
   }
+
+  /**
+   * Issue 4720: Glass is not removed when removeFromParent is called.
+   */
+  public void testRemoveFromParent() {
+    PopupPanel popup = createPopupPanel();
+    popup.setGlassEnabled(true);
+    assertNull(popup.getGlassElement().getParentElement());
+
+    popup.show();
+    assertNotNull(popup.getGlassElement().getParentElement());
+
+    popup.removeFromParent();
+    assertNull(popup.getGlassElement().getParentElement());
+  }

   public void testSeparateContainers() {
     TestablePopupPanel p1 = new TestablePopupPanel();

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

To unsubscribe from this group, send email to 
google-web-toolkit-contributors+unsubscribegooglegroups.com or reply to this email with 
the words "REMOVE ME" as the subject.

Reply via email to