Added a test for issue 1897 "Attaching and detaching a RichTextArea too fast crashes GWT" to the museum.

Patch by: jlabanca
Review by: ecc (desk review)



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2535 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/eclipse/reference/code-museum/Museum.launch b/eclipse/reference/code-museum/DefaultMuseum.launch
similarity index 97%
rename from eclipse/reference/code-museum/Museum.launch
rename to eclipse/reference/code-museum/DefaultMuseum.launch
index 3d8c6aa..3c0cabf 100644
--- a/eclipse/reference/code-museum/Museum.launch
+++ b/eclipse/reference/code-museum/DefaultMuseum.launch
@@ -18,7 +18,7 @@
 </listAttribute>
 <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
 <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.GWTShell"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-out www com.google.gwt.museum.Museum/Museum.html -style PRETTY"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-out www com.google.gwt.museum.DefaultMuseum/DefaultMuseum.html"/>
 <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="code-museum"/>
 <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dgwt.devjar=&quot;/usr/local/jlabanca/gwt_all/latest/trunk/build/staging/gwt-linux-0.0.0/gwt-user.jar&quot;"/>
 </launchConfiguration>
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
index 7254e0d..cee913a 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
@@ -25,6 +25,7 @@
  */

 public class DefaultMuseum extends Museum implements EntryPoint {

   public DefaultMuseum() {

+    addIssue(new Issue1897());

     addIssue(new Issue2290());

     addIssue(new Issue2307());

     addIssue(new Issue2321());

diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1897.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1897.java
new file mode 100644
index 0000000..e6a0832
--- /dev/null
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1897.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.museum.client.defaultmuseum;
+
+import com.google.gwt.museum.client.common.AbstractIssue;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.RichTextArea;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * <h1> Attaching and detaching a RichTextArea too fast crashes GWT </h1>
+ * 
+ * <p>
+ * The RichTextArea uses a Timer or iframe.onload event (depending on the
+ * browser) to trigger the event system initialization. Basically, that
+ * introduces a small delay between the time the RichTextArea is attached to the
+ * page and the time that the event handlers are added.
+ * </p>
+ * <p>
+ * However, if you programmatically (or just very quickly) remove the
+ * RichTextArea from the page, you will immediately trigger the teardown methods
+ * that remove the event listeners. In some browsers, removing the event
+ * listeners before they are added throws a JavaScript exception do to an
+ * undefined variable, which messes up the rest of the onDetach mechanism, which
+ * gets your attach state out of sync, which means your app stops working
+ * properly.
+ * </p>
+ * <p>
+ * I am able to reliably reproduce these errors by attaching and removing a
+ * RichTextArea very quickly, even in user time. The errors affect all browsers,
+ * but Firefox is by far the most affected because it catches the iframe.onload
+ * event, whereas the others just use a 1ms timer. Also, Safari and IE seem to
+ * handle the javascript exceptions a little cleaner.
+ * </p>
+ */
+public class Issue1897 extends AbstractIssue {
+  /**
+   * A set of options used to set the caption and content in the caption panel.
+   */
+  private class ControlPanel extends Composite {
+    private final HorizontalPanel hPanel = new HorizontalPanel();
+
+    public ControlPanel() {
+      initWidget(hPanel);
+      hPanel.setSpacing(10);
+
+      // Add option to attach RichTextArea
+      Button attachButton = new Button("Attach RichText", new ClickListener() {
+        public void onClick(Widget sender) {
+          if (rta.isAttached()) {
+            Window.alert("RichTextArea is already attached.");
+          }
+          wrapper.add(rta);
+        }
+      });
+      hPanel.add(attachButton);
+
+      // Add option to detach RichTextArea
+      Button detachButton = new Button("Detach RichText", new ClickListener() {
+        public void onClick(Widget sender) {
+          if (!rta.isAttached()) {
+            Window.alert("RichTextArea is already detached.");
+            return;
+          }
+          wrapper.remove(rta);
+        }
+      });
+      hPanel.add(detachButton);
+
+      // Add option to attach and detach RichTextArea
+      Button quickDetachButton = new Button("Attach/Detach RichText",
+          new ClickListener() {
+            public void onClick(Widget sender) {
+              if (rta.isAttached()) {
+                Window.alert("RichTextArea is already attached.");
+                return;
+              }
+              wrapper.add(rta);
+              wrapper.remove(rta);
+            }
+          });
+      hPanel.add(quickDetachButton);
+    }
+  }
+
+  private RichTextArea rta;
+
+  private VerticalPanel wrapper;
+
+  @Override
+  public Widget createIssue() {
+    rta = new RichTextArea();
+    rta.setPixelSize(200, 100);
+
+    // Combine the control panel and RichTextArea in a wrapper
+    wrapper = new VerticalPanel();
+    wrapper.setSpacing(10);
+    wrapper.add(new ControlPanel());
+    wrapper.add(rta);
+
+    // Remove the RichTextArea after the wrapper is attached to the DOM
+    DeferredCommand.addCommand(new Command() {
+      public void execute() {
+        wrapper.remove(rta);
+      }
+    });
+
+    return wrapper;
+  }
+
+  @Override
+  public String getInstructions() {
+    return "You should <b>not</b> see a RichTextArea, and no errors should "
+        + "occur.  If you click the Attach/Detach button, the RichTextArea will"
+        + " be programmatically attached and detached from the DOM structure, "
+        + "and you should not see any errors.";
+  }
+
+  @Override
+  public String getSummary() {
+    return "Attaching and detaching a RichTextArea too fast crashes GWT";
+  }
+
+  @Override
+  public boolean hasCSS() {
+    return true;
+  }
+}
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/viewer/Museum.java b/reference/code-museum/src/com/google/gwt/museum/client/viewer/Museum.java
index fa258de..7bfc2ca 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/viewer/Museum.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/viewer/Museum.java
@@ -103,10 +103,7 @@
 
   /**
    * Add an issue to the list of issues.
-   * 
-   * @param issue the issue to add
    */
-
   private final Poller poller = new Poller();
 
   /**
@@ -174,7 +171,7 @@
       public void requestSuggestions(Request request, Callback callback) {
         String ofInterest = ("(.* )*" + request.getQuery() + ".*").toLowerCase();
         ArrayList<Suggestion> suggestions = new ArrayList<Suggestion>();
-        HashSet s = new HashSet();
+        HashSet<AbstractIssue> s = new HashSet<AbstractIssue>();
         for (AbstractIssue issue : issues) {
           if (issue.getHeadline().toLowerCase().matches(ofInterest)) {
             s.add(issue);
diff --git a/reference/code-museum/src/com/google/gwt/museum/public/issues/Issue1897.css b/reference/code-museum/src/com/google/gwt/museum/public/issues/Issue1897.css
new file mode 100644
index 0000000..10c8ed6
--- /dev/null
+++ b/reference/code-museum/src/com/google/gwt/museum/public/issues/Issue1897.css
@@ -0,0 +1,5 @@
+@import url("MasterIssue.css");

+

+.gwt-RichTextArea {
+  border: 1px solid black;
+}