Fix ListBox UiBinder parsing.

Review at http://gwt-code-reviews.appspot.com/1629803


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10891 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/ListBoxParser.java b/user/src/com/google/gwt/uibinder/elementparsers/ListBoxParser.java
index 708f625..c8221e6 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/ListBoxParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/ListBoxParser.java
@@ -36,7 +36,8 @@
         writer.die(elem, "Invalid ListBox child element: " + tagName);
       }
       String value = child.consumeStringAttribute("value");
-      String innerText = child.consumeInnerTextEscapedAsHtmlStringLiteral(new TextInterpreter(writer));
+      String innerText = child.consumeInnerTextEscapedAsStringLiteral(
+            new TextInterpreter(writer));
       if (value != null) {
         writer.addStatement("%s.addItem(\"%s\", %s);", fieldName, innerText, value);
       } else {
diff --git a/user/src/com/google/gwt/uibinder/rebind/GetInnerHtmlVisitor.java b/user/src/com/google/gwt/uibinder/rebind/GetInnerHtmlVisitor.java
index 4eae5dd..65eb141 100644
--- a/user/src/com/google/gwt/uibinder/rebind/GetInnerHtmlVisitor.java
+++ b/user/src/com/google/gwt/uibinder/rebind/GetInnerHtmlVisitor.java
@@ -20,7 +20,7 @@
 
 import org.w3c.dom.Element;
 
-class GetInnerHtmlVisitor extends GetEscapedInnerTextVisitor {
+class GetInnerHtmlVisitor extends GetInnerTextVisitor {
 
   /**
    * Recursively gathers an HTML representation of the children of the given
diff --git a/user/src/com/google/gwt/uibinder/rebind/GetEscapedInnerTextVisitor.java b/user/src/com/google/gwt/uibinder/rebind/GetInnerTextVisitor.java
similarity index 63%
rename from user/src/com/google/gwt/uibinder/rebind/GetEscapedInnerTextVisitor.java
rename to user/src/com/google/gwt/uibinder/rebind/GetInnerTextVisitor.java
index 24cf27c..06d3202 100644
--- a/user/src/com/google/gwt/uibinder/rebind/GetEscapedInnerTextVisitor.java
+++ b/user/src/com/google/gwt/uibinder/rebind/GetInnerTextVisitor.java
@@ -23,7 +23,7 @@
 import org.w3c.dom.Node;
 import org.w3c.dom.Text;
 
-class GetEscapedInnerTextVisitor implements NodeVisitor {
+class GetInnerTextVisitor implements NodeVisitor {
 
   /**
    * Gathers a text representation of the children of the given Elem, and stuffs
@@ -33,19 +33,39 @@
   public static void getEscapedInnerText(Element elem, StringBuffer buffer,
       Interpreter<String> interpreter, XMLElementProvider writer)
       throws UnableToCompleteException {
-    new ChildWalker().accept(elem, new GetEscapedInnerTextVisitor(buffer,
-        interpreter, writer));
+    new ChildWalker().accept(elem, new GetInnerTextVisitor(buffer,
+        interpreter, writer, false));
+  }
+
+  /**
+   * Gathers a text representation of the children of the given Elem, and stuffs
+   * it into the given StringBuffer. Applies the interpreter to each descendant,
+   * and uses the writer to report errors. Escapes HTML Entities.
+   */
+  public static void getHtmlEscapedInnerText(Element elem, StringBuffer buffer,
+      Interpreter<String> interpreter, XMLElementProvider writer)
+      throws UnableToCompleteException {
+    new ChildWalker().accept(elem, new GetInnerTextVisitor(buffer,
+        interpreter, writer, true));
   }
 
   protected final StringBuffer buffer;
   protected final Interpreter<String> interpreter;
   protected final XMLElementProvider elementProvider;
+  protected final boolean escapeHtmlEntities;
 
-  protected GetEscapedInnerTextVisitor(StringBuffer buffer,
+  protected GetInnerTextVisitor(StringBuffer buffer,
       Interpreter<String> interpreter, XMLElementProvider elementProvider) {
+    this(buffer, interpreter, elementProvider, true);
+  }
+
+  protected GetInnerTextVisitor(StringBuffer buffer,
+      Interpreter<String> interpreter, XMLElementProvider elementProvider,
+      boolean escapeHtmlEntities) {
     this.buffer = buffer;
     this.interpreter = interpreter;
     this.elementProvider = elementProvider;
+    this.escapeHtmlEntities = escapeHtmlEntities;
   }
 
   public void visitCData(CDATASection d) {
@@ -61,8 +81,18 @@
   }
 
   public void visitText(Text t) {
-    String escaped = UiBinderWriter.escapeText(t.getTextContent(),
+    String escaped;
+    if (escapeHtmlEntities) {
+      escaped = UiBinderWriter.escapeText(t.getTextContent(),
         preserveWhiteSpace(t));
+    } else {
+      escaped = t.getTextContent();
+      if (!preserveWhiteSpace(t)) {
+        escaped = escaped.replaceAll("\\s+", " ");
+      }
+      escaped = UiBinderWriter.escapeTextForJavaStringLiteral(escaped);
+    }
+
     buffer.append(escaped);
   }
 
diff --git a/user/src/com/google/gwt/uibinder/rebind/XMLElement.java b/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
index 99680f3..07bee2c 100644
--- a/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
+++ b/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
@@ -417,36 +417,35 @@
   /**
    * Consumes all child text nodes, and asserts that this element held only
    * text. Trailing and leading whitespace is trimmed, and escaped for use as a
-   * string literal. Notice that HTML entities in the text are also escaped--is
-   * this a source of errors?
+   * string literal. Notice that HTML entities in the text are also escaped
    * <p>
    * This call requires an interpreter to make sense of any special children.
    * The odds are you want to use
    * {@link com.google.gwt.uibinder.elementparsers.TextInterpreter}
-   * 
+   *
    * @throws UnableToCompleteException If any elements present are not consumed
    *           by the interpreter
    */
   public String consumeInnerTextEscapedAsHtmlStringLiteral(Interpreter<String> interpreter)
       throws UnableToCompleteException {
-    if (interpreter == null) {
-      throw new NullPointerException("interpreter must not be null");
-    }
-    StringBuffer buf = new StringBuffer();
+    return consumeInnerTextEscapedAsHtmlStringLiteral(interpreter, true);
+  }
 
-    GetEscapedInnerTextVisitor.getEscapedInnerText(elem, buf, interpreter, provider);
-
-    // Make sure there are no children left but empty husks
-    for (XMLElement child : consumeChildElementsNoEmptyCheck()) {
-      if (child.hasChildNodes() || child.getAttributeCount() > 0) {
-        logger.die(this, "Illegal child %s in a text-only context. "
-            + "Perhaps you are trying to use unescaped HTML "
-            + "where text is required, as in a HasText widget?", child);
-      }
-    }
-
-    clearChildren(elem);
-    return buf.toString().trim();
+  /**
+   * Consumes all child text nodes, and asserts that this element held only
+   * text. Trailing and leading whitespace is trimmed, and escaped for use as a
+   * string literal. Notice that HTML entities in the text are NOT escaped
+   * <p>
+   * This call requires an interpreter to make sense of any special children.
+   * The odds are you want to use
+   * {@link com.google.gwt.uibinder.elementparsers.TextInterpreter}
+   *
+   * @throws UnableToCompleteException If any elements present are not consumed
+   *           by the interpreter
+   */
+  public String consumeInnerTextEscapedAsStringLiteral(Interpreter<String> interpreter)
+      throws UnableToCompleteException {
+    return consumeInnerTextEscapedAsHtmlStringLiteral(interpreter, false);
   }
 
   /**
@@ -819,6 +818,45 @@
     }
   }
 
+  /**
+   * Consumes all child text nodes, and asserts that this element held only
+   * text. Trailing and leading whitespace is trimmed, and escaped for use as a
+   * string literal. If escapeHtmlEntities is true, HTML Entities are also escaped.
+   * <p>
+   * This call requires an interpreter to make sense of any special children.
+   * The odds are you want to use
+   * {@link com.google.gwt.uibinder.elementparsers.TextInterpreter}
+   *
+   * @throws UnableToCompleteException If any elements present are not consumed
+   *           by the interpreter
+   */
+  private String consumeInnerTextEscapedAsHtmlStringLiteral(Interpreter<String> interpreter,
+                                                           boolean escapeHtmlEntities)
+      throws UnableToCompleteException {
+    if (interpreter == null) {
+      throw new NullPointerException("interpreter must not be null");
+    }
+    StringBuffer buf = new StringBuffer();
+
+    if (escapeHtmlEntities) {
+      GetInnerTextVisitor.getHtmlEscapedInnerText(elem, buf, interpreter, provider);
+    } else {
+      GetInnerTextVisitor.getEscapedInnerText(elem, buf, interpreter, provider);
+    }
+
+    // Make sure there are no children left but empty husks
+    for (XMLElement child : consumeChildElementsNoEmptyCheck()) {
+      if (child.hasChildNodes() || child.getAttributeCount() > 0) {
+        logger.die(this, "Illegal child %s in a text-only context. "
+            + "Perhaps you are trying to use unescaped HTML "
+            + "where text is required, as in a HasText widget?", child);
+      }
+    }
+
+    clearChildren(elem);
+    return buf.toString().trim();
+  }
+
   private void failRequired(String name) throws UnableToCompleteException {
     logger.die(this, "Missing required attribute \"%s\"", name);
   }