Revision: 6714
Author: [email protected]
Date: Thu Nov  5 12:38:39 2009
Log: Fixes bad code gen on non-widget children in DockLayoutPanelParser,  
and allows
<g:center> to appear anywhere.

To allow real unit testing, refactored UiBinderWriter to be a bit more DI.  
This
included moving w3c parsing knowledge outside of the writer. In the process  
made
the w3c dom test helper into the actual production code--it was nearly  
identical
anyway, and now test and prod won't drift.

This took a little while. But the next one won't.

Review by jgw, scottb
http://gwt-code-reviews.appspot.com/93806
http://code.google.com/p/google-web-toolkit/source/detail?r=6714

Added:
  /trunk/user/src/com/google/gwt/uibinder/rebind/W3cDomHelper.java
   
/trunk/user/test/com/google/gwt/uibinder/parsers/DockLayoutPanelParserTest.java
  /trunk/user/test/com/google/gwt/uibinder/test/UiJavaResources.java
Deleted:
  /trunk/user/test/com/google/gwt/uibinder/rebind/DocumentTestHelp.java
Modified:
  /trunk/user/src/com/google/gwt/uibinder/parsers/DockLayoutPanelParser.java
  /trunk/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java
  /trunk/user/src/com/google/gwt/uibinder/rebind/AttributeParsers.java
  /trunk/user/src/com/google/gwt/uibinder/rebind/FieldManager.java
  /trunk/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java
  /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderGenerator.java
  /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
  /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
  /trunk/user/src/com/google/gwt/uibinder/rebind/XMLElementProvider.java
  /trunk/user/src/com/google/gwt/uibinder/rebind/XMLElementProviderImpl.java
  /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java
  /trunk/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java

=======================================
--- /dev/null
+++ /trunk/user/src/com/google/gwt/uibinder/rebind/W3cDomHelper.java    Thu  
Nov  5 12:38:39 2009
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2009 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.uibinder.rebind;
+
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+/**
+ * Simplifies instantiation of the w3c XML parser, in just the style
+ * that UiBinder likes it. Used by both prod and test.
+ */
+public class W3cDomHelper {
+  private final DocumentBuilderFactory factory;
+  private final DocumentBuilder builder;
+
+  public W3cDomHelper() {
+    factory = DocumentBuilderFactory.newInstance();
+    factory.setNamespaceAware(true);
+    factory.setExpandEntityReferences(true);
+    try {
+      builder = factory.newDocumentBuilder();
+    } catch (ParserConfigurationException e) {
+      throw new RuntimeException(e);
+    }
+    builder.setEntityResolver(new GwtResourceEntityResolver());
+  }
+
+  /**
+   * Creates an XML document model with the given contents. Nice for  
testing.
+   *
+   * @param string the document contents
+   */
+  public Document documentFor(String string) throws SAXException,
+      IOException {
+    return builder.parse(new ByteArrayInputStream(string.getBytes()));
+  }
+
+  public Document documentFor(URL url) throws SAXParseException {
+    try {
+      InputStream stream = url.openStream();
+      InputSource input = new InputSource(stream);
+      input.setSystemId(url.toExternalForm());
+
+      return builder.parse(input);
+    } catch (SAXParseException e) {
+      // Let SAXParseExceptions through.
+      throw e;
+    } catch (SAXException e) {
+      throw new RuntimeException(e);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+}
=======================================
--- /dev/null
+++  
/trunk/user/test/com/google/gwt/uibinder/parsers/DockLayoutPanelParserTest.java 
 
Thu Nov  5 12:38:39 2009
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2009 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.uibinder.parsers;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.javac.impl.MockJavaResource;
+import com.google.gwt.dev.javac.impl.MockResourceOracle;
+import com.google.gwt.dev.util.collect.Lists;
+import com.google.gwt.uibinder.rebind.AttributeParsers;
+import com.google.gwt.uibinder.rebind.FieldManager;
+import com.google.gwt.uibinder.rebind.FieldWriter;
+import com.google.gwt.uibinder.rebind.MortalLogger;
+import com.google.gwt.uibinder.rebind.UiBinderWriter;
+import com.google.gwt.uibinder.rebind.W3cDomHelper;
+import com.google.gwt.uibinder.rebind.XMLElement;
+import com.google.gwt.uibinder.rebind.XMLElementProvider;
+import com.google.gwt.uibinder.rebind.XMLElementProviderImpl;
+import com.google.gwt.uibinder.rebind.messages.MessagesWriter;
+import com.google.gwt.uibinder.test.UiJavaResources;
+import com.google.gwt.user.client.ui.DockLayoutPanel;
+
+import junit.framework.TestCase;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A unit test. Guess what of.
+ */
+public class DockLayoutPanelParserTest extends TestCase {
+  private static class MyUiBinderWriter extends UiBinderWriter {
+    final List<String> statements = new ArrayList<String>();
+    String died;
+
+    public MyUiBinderWriter(JClassType baseClass, String implClassName,
+        String templatePath, TypeOracle oracle, MortalLogger logger,
+        FieldManager fieldManager, MessagesWriter messagesWriter)
+        throws UnableToCompleteException {
+      super(baseClass, implClassName, templatePath, oracle, logger,
+          fieldManager, messagesWriter);
+    }
+
+    @Override
+    public void addStatement(String format, Object... args) {
+      statements.add(String.format(format, args));
+    }
+
+    @Override
+    public String parseElementToField(XMLElement elem)
+        throws UnableToCompleteException {
+      return elem.consumeOpeningTag();
+    }
+
+    @Override
+    public void die(String message, Object... params)
+        throws UnableToCompleteException {
+      noteDeath(String.format(message, params));
+      super.die(message, params);
+    }
+
+    @Override
+    public void die(String message) throws UnableToCompleteException {
+      noteDeath(message);
+      super.die(message);
+    }
+
+    /** Handy place to set a break point and inspect suicide notes. */
+    void noteDeath(String s) {
+      died = s;
+    }
+  }
+
+  private static final W3cDomHelper docHelper = new W3cDomHelper();
+  private static final String BINDER_URI = "binderUri";
+
+  private static final String fieldName = "fieldName";
+
+  // TODO(rjrjr) Move this to JavaResourceBase. Have to do it atomically  
for
+  // all other tests that define their own Enum.
+  private static final MockJavaResource ENUM = new MockJavaResource(
+  "java.lang.Enum") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package java.lang;\n");
+      code.append("public abstract class Enum<E extends Enum<E>> {\n");
+      code.append("  protected Enum(String name, int ordinal) {}\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+  private static final MockJavaResource MY_UI_JAVA = new MockJavaResource(
+      "my.Ui") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package my;\n");
+      code.append("import com.google.gwt.user.client.ui.Widget;\n");
+      code.append("public class Ui {\n");
+      code.append("  public interface BaseClass extends "
+          + "com.google.gwt.uibinder.client.UiBinder<Widget, BaseClass>  
{}\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+
+  private TypeOracle types;
+  private XMLElementProvider elemProvider;
+  private Document doc;
+  private MyUiBinderWriter writer;
+  private DockLayoutPanelParser parser;
+  private JClassType dockLayoutPanelType;
+  private FieldManager fieldManager;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+
+    MockResourceOracle resources = new  
MockResourceOracle(getUiResources());
+    CompilationState state = new CompilationState(TreeLogger.NULL,  
resources);
+    types = state.getTypeOracle();
+    dockLayoutPanelType =  
types.findType("com.google.gwt.user.client.ui.DockLayoutPanel");
+
+    elemProvider = new XMLElementProviderImpl(new AttributeParsers(), null,
+        types, MortalLogger.NULL);
+
+    fieldManager = new FieldManager(MortalLogger.NULL);
+    fieldManager.registerField(
+        types.findType(DockLayoutPanel.class.getCanonicalName()),  
fieldName);
+
+    String templatePath = "TemplatePath.ui.xml";
+    String implName = "ImplClass";
+    JClassType baseType = types.findType("my.Ui.BaseClass");
+    MessagesWriter messages = new MessagesWriter(BINDER_URI,  
MortalLogger.NULL,
+        templatePath, baseType.getPackage().getName(), implName);
+
+    writer = new MyUiBinderWriter(baseType, implName, templatePath, types,
+        MortalLogger.NULL, fieldManager, messages);
+    parser = new DockLayoutPanelParser();
+  }
+
+  public void testHappy() throws UnableToCompleteException, SAXException,
+      IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<ui:UiBinder xmlns:ui='" + BINDER_URI + "'");
+    b.append("    xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+    b.append("  <g:DockLayoutPanel unit='EM'>");
+    b.append("    <g:north size='5'>");
+    b.append("      <g:Label id='north'>north</g:Label>");
+    b.append("    </g:north>");
+    b.append("    <g:center>");
+    b.append("      <g:Label id='center'>center</g:Label>");
+    b.append("    </g:center>");
+    b.append("  </g:DockLayoutPanel>");
+    b.append("</ui:UiBinder>");
+
+    String[] expected = {
+        "fieldName.addNorth(<g:Label id='north'>, 5);",
+        "fieldName.add(<g:Label id='center'>);",};
+
+    parser.parse(getElem(b.toString()), fieldName, dockLayoutPanelType,  
writer);
+    FieldWriter w = fieldManager.lookup(fieldName);
+    assertEquals(
+        "new  
com.google.gwt.user.client.ui.DockLayoutPanel(com.google.gwt.dom.client.Style.Unit.EM)",
+        w.getInitializer());
+
+    Iterator<String> i = writer.statements.iterator();
+    for (String e : expected) {
+      assertEquals(e, i.next());
+    }
+    assertFalse(i.hasNext());
+    assertNull(writer.died);
+  }
+
+  public void testNiceCenter() throws UnableToCompleteException,  
SAXException,
+      IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<ui:UiBinder xmlns:ui='" + BINDER_URI + "'");
+    b.append("    xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+    b.append("  <g:DockLayoutPanel unit='EM'>");
+    b.append("    <g:center>");
+    b.append("      <g:Label id='center'>center</g:Label>");
+    b.append("    </g:center>");
+    b.append("    <g:north size='5'>");
+    b.append("      <g:Label id='north'>north</g:Label>");
+    b.append("    </g:north>");
+    b.append("  </g:DockLayoutPanel>");
+    b.append("</ui:UiBinder>");
+
+    String[] expected = {
+        "fieldName.addNorth(<g:Label id='north'>, 5);",
+        "fieldName.add(<g:Label id='center'>);",};
+
+    parser.parse(getElem(b.toString()), fieldName, dockLayoutPanelType,  
writer);
+    FieldWriter w = fieldManager.lookup(fieldName);
+    assertEquals(
+        "new  
com.google.gwt.user.client.ui.DockLayoutPanel(com.google.gwt.dom.client.Style.Unit.EM)",
+        w.getInitializer());
+
+    Iterator<String> i = writer.statements.iterator();
+    for (String e : expected) {
+      assertEquals(e, i.next());
+    }
+    assertFalse(i.hasNext());
+  }
+
+  public void testTooManyCenters() throws SAXException, IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<ui:UiBinder xmlns:ui='" + BINDER_URI + "'");
+    b.append("    xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+    b.append("  <g:DockLayoutPanel unit='EM'>");
+    b.append("    <g:center>");
+    b.append("      <g:Label id='center'>center</g:Label>");
+    b.append("    </g:center>");
+    b.append("    <g:center>");
+    b.append("      <g:Label id='centerAlso'>centaur</g:Label>");
+    b.append("    </g:center>");
+    b.append("  </g:DockLayoutPanel>");
+    b.append("</ui:UiBinder>");
+
+    try {
+      parser.parse(getElem(b.toString()), fieldName, dockLayoutPanelType,
+          writer);
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertNotNull(writer.died);
+    }
+  }
+
+  public void testBadChild() throws SAXException, IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<ui:UiBinder xmlns:ui='" + BINDER_URI + "'");
+    b.append("    xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+    b.append("  <g:DockLayoutPanel unit='EM'>");
+    b.append("    <g:west><foo/></g:west>");
+    b.append("  </g:DockLayoutPanel>");
+    b.append("</ui:UiBinder>");
+
+    try {
+      parser.parse(getElem(b.toString()), fieldName, dockLayoutPanelType,
+          writer);
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertNotNull(writer.died);
+    }
+  }
+
+  MockJavaResource[] getUiResources() {
+    List<MockJavaResource> rtn =  
Lists.create(UiJavaResources.getUiResources());
+    rtn.add(MY_UI_JAVA);
+    rtn.add(ENUM);
+    return rtn.toArray(new MockJavaResource[rtn.size()]);
+  }
+
+  private XMLElement getElem(String string) throws SAXException,  
IOException {
+    doc = docHelper.documentFor(string);
+    Element w3cElem = (Element)  
doc.getDocumentElement().getElementsByTagName(
+        "g:DockLayoutPanel").item(0);
+    XMLElement elem = elemProvider.get(w3cElem);
+    return elem;
+  }
+}
=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/uibinder/test/UiJavaResources.java  Thu  
Nov  5 12:38:39 2009
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2009 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.uibinder.test;
+
+import com.google.gwt.dev.javac.impl.JavaResourceBase;
+import com.google.gwt.dev.javac.impl.MockJavaResource;
+import com.google.gwt.dev.util.collect.Lists;
+
+import java.util.List;
+
+/**
+ * A paired down set of GWT widget Java source files for code generator  
testing.
+ */
+public class UiJavaResources {
+
+  public static final MockJavaResource WIDGET = new MockJavaResource(
+      "com.google.gwt.user.client.ui.Widget") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("public class Widget {\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+  public static final MockJavaResource DOCK_LAYOUT_PANEL = new  
MockJavaResource(
+      "com.google.gwt.user.client.ui.DockLayoutPanel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("public class DockLayoutPanel extends Widget {\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+  public static final MockJavaResource SPLIT_LAYOUT_PANEL = new  
MockJavaResource(
+      "com.google.gwt.user.client.ui.SplitLayoutPanel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("public class SplitLayoutPanel extends DockLayoutPanel  
{\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+  public static final MockJavaResource LABEL = new MockJavaResource(
+      "com.google.gwt.user.client.ui.Label") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("public class Label extends Widget {\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+  public static final MockJavaResource UI_BINDER = new MockJavaResource(
+      "com.google.gwt.uibinder.client.UiBinder") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.uibinder.client;\n");
+      code.append("public interface UiBinder<U, O> {\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+  public static final MockJavaResource STYLE = new MockJavaResource(
+      "com.google.gwt.dom.client.Style") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.dom.client;\n");
+      code.append("public class Style  {\n");
+      code.append("  public enum Unit { PX, PT, EM };\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+
+  /**
+   * @return a pale reflection of com.google.gwt.user.ui, plus
+   *         {...@link JavaResourceBase#getStandardResources}
+   */
+  public static MockJavaResource[] getUiResources() {
+    MockJavaResource[] base = JavaResourceBase.getStandardResources();
+    List<MockJavaResource> rtn = Lists.create(base);
+    rtn.add(WIDGET);
+    rtn.add(DOCK_LAYOUT_PANEL);
+    rtn.add(SPLIT_LAYOUT_PANEL);
+    rtn.add(LABEL);
+    rtn.add(UI_BINDER);
+    rtn.add(STYLE);
+    return rtn.toArray(new MockJavaResource[rtn.size()]);
+  }
+}
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/rebind/DocumentTestHelp.java       
 
Thu Oct 29 21:43:40 2009
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2007 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.uibinder.rebind;
-
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-/**
- * Support methods for testing uibinder.
- */
-class DocumentTestHelp {
-  /**
-   * Creates an XML document model with the given contents.
-   *
-   * @param string the document contents
-   */
-  public static Document documentForString(String string)
-      throws ParserConfigurationException, SAXException, IOException {
-    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-    factory.setNamespaceAware(true);
-    factory.setExpandEntityReferences(true);
-    DocumentBuilder builder = factory.newDocumentBuilder();
-    Document doc = builder.parse(new  
ByteArrayInputStream(string.getBytes()));
-    return doc;
-  }
-
-  /**
-   * Not instantiable.
-   */
-  private DocumentTestHelp() {
-  }
-}
=======================================
---  
/trunk/user/src/com/google/gwt/uibinder/parsers/DockLayoutPanelParser.java      
 
Wed Nov  4 13:42:26 2009
+++  
/trunk/user/src/com/google/gwt/uibinder/parsers/DockLayoutPanelParser.java      
 
Thu Nov  5 12:38:39 2009
@@ -39,6 +39,16 @@
   */
  public class DockLayoutPanelParser implements ElementParser {

+  private static class CenterChild {
+    final String widgetName;
+    final XMLElement child;
+
+    public CenterChild(XMLElement child, String widgetName) {
+      this.widgetName = widgetName;
+      this.child = child;
+    }
+  }
+
    private static final Map<String, String> DOCK_NAMES = new  
HashMap<String, String>();

    static {
@@ -60,31 +70,44 @@
        writer.setFieldInitializerAsConstructor(fieldName,
            writer.getOracle().findType(DockLayoutPanel.class.getName()),  
unit);
      }
+
+    CenterChild center = null;

      // Parse children.
      for (XMLElement child : elem.consumeChildElements()) {
        // Make sure the element is one of the fixed set of valid directions.
        if (!isValidChildElement(elem, child)) {
          writer.die(
-            "In %1$s, child must be one of " +
-            "<%2$s:north>, <%2$s:south>, <%2$s:east>, <%2$s:west> or  
<%2$s:center>, " +
-            "but found %3$s",
-            elem, elem.getPrefix(), child);
+            "In %1$s, child must be one of "
+                + "<%2$s:north>, <%2$s:south>, <%2$s:east>, <%2$s:west> or  
<%2$s:center>, "
+                + "but found %3$s", elem, elem.getPrefix(), child);
        }

        // Consume the single widget element.
        XMLElement widget = child.consumeSingleChildElement();
-      String childFieldName = writer.parseElementToField(widget);
-
-      if (requiresSize(child)) {
+      if (!writer.isWidgetElement(widget)) {
+        writer.die("In %s, %s must contain a widget, but found %s", elem,  
child,
+            widget);
+      }
+      String widgetName = writer.parseElementToField(widget);
+
+      if (child.getLocalName().equals("center")) {
+        if (center != null) {
+          writer.die("In %s, only one <%s:center> is allowed", elem,
+              elem.getPrefix());
+        }
+        center = new CenterChild(child, widgetName);
+      } else {
          String size = child.consumeDoubleAttribute("size");
          writer.addStatement("%s.%s(%s, %s);", fieldName,  
addMethodName(child),
-            childFieldName, size);
-      } else {
-        writer.addStatement("%s.%s(%s);", fieldName, addMethodName(child),
-            childFieldName);
+            widgetName, size);
        }
      }
+
+    if (center != null) {
+      writer.addStatement("%s.%s(%s);", fieldName,  
addMethodName(center.child),
+          center.widgetName);
+    }
    }

    private String addMethodName(XMLElement elem) {
@@ -102,8 +125,8 @@
    private boolean isValidChildElement(XMLElement parent, XMLElement child)  
{
      String childNsUri = child.getNamespaceUri();
      if (childNsUri == null) {
-        return false;
-    }
+      return false;
+    }
      if (!childNsUri.equals(parent.getNamespaceUri())) {
        return false;
      }
@@ -113,8 +136,4 @@
      // Made it through the gauntlet.
      return true;
    }
-
-  private boolean requiresSize(XMLElement elem) {
-    return !elem.getLocalName().equals("center");
-  }
-}
+}
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java     
 
Wed Oct 28 09:10:53 2009
+++ /trunk/user/src/com/google/gwt/uibinder/rebind/AbstractFieldWriter.java     
 
Thu Nov  5 12:38:39 2009
@@ -45,6 +45,10 @@
      this.name = name;
      this.logger = logger;
    }
+
+  public String getInitializer() {
+    return initializer;
+  }

    public void needs(FieldWriter f) {
      needs.add(f);
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/AttributeParsers.java        
 
Wed Nov  4 11:14:50 2009
+++ /trunk/user/src/com/google/gwt/uibinder/rebind/AttributeParsers.java        
 
Thu Nov  5 12:38:39 2009
@@ -24,7 +24,10 @@
  import java.util.HashMap;
  import java.util.Map;

-class AttributeParsers {
+/**
+ * Managers access to all implementations of {...@link AttributeParser}
+ */
+public class AttributeParsers {
    private static final String DOUBLE = "double";
    private static final String BOOLEAN = "boolean";

=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/FieldManager.java    Wed  
Oct 28 09:10:53 2009
+++ /trunk/user/src/com/google/gwt/uibinder/rebind/FieldManager.java    Thu  
Nov  5 12:38:39 2009
@@ -26,7 +26,7 @@
   * This class handles all {...@link FieldWriter} instances created for the  
current
   * template.
   */
-class FieldManager {
+public class FieldManager {

    private static final String DUPLICATE_FIELD_ERROR = "Duplicate  
declaration of field %1$s.";

@@ -46,8 +46,8 @@
    /**
     * Basic constructor just injects an oracle instance.
     */
-  public FieldManager(MortalLogger logger2) {
-    this.logger = logger2;
+  public FieldManager(MortalLogger logger) {
+    this.logger = logger;
    }

    /**
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java     Wed Oct 
 
28 09:10:53 2009
+++ /trunk/user/src/com/google/gwt/uibinder/rebind/FieldWriter.java     Thu  
Nov  5 12:38:39 2009
@@ -36,6 +36,8 @@

    String getQualifiedSourceName();

+  String getInitializer();
+
    /**
     * @return the type of this field, or null if this field is of a type  
that has
     *         not yet been generated
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderGenerator.java       
 
Mon Nov  2 20:08:34 2009
+++ /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderGenerator.java       
 
Thu Nov  5 12:38:39 2009
@@ -26,7 +26,11 @@
  import com.google.gwt.uibinder.rebind.messages.MessagesWriter;
  import com.google.gwt.uibinder.rebind.model.ImplicitClientBundle;

+import org.w3c.dom.Document;
+import org.xml.sax.SAXParseException;
+
  import java.io.PrintWriter;
+import java.net.URL;

  /**
   * Generator for implementations of
@@ -36,6 +40,8 @@

    private static final String TEMPLATE_SUFFIX = ".ui.xml";

+  static final String BINDER_URI = "urn:ui:com.google.gwt.uibinder";
+
    /**
     * Given a UiBinder interface, return the path to its ui.xml file,  
suitable
     * for any classloader to find it as a resource.
@@ -103,18 +109,22 @@
    }

    private void generateOnce(JClassType interfaceType, String implName,
-      PrintWriter binderPrintWrier, TreeLogger treeLogger, TypeOracle  
oracle,
+      PrintWriter binderPrintWriter, TreeLogger treeLogger, TypeOracle  
oracle,
        PrintWriterManager writerManager)
-      throws UnableToCompleteException {
+ throws UnableToCompleteException {

      MortalLogger logger = new MortalLogger(treeLogger);
      String templatePath = deduceTemplateFile(logger, interfaceType);
+    MessagesWriter messages = new MessagesWriter(BINDER_URI, logger,
+        templatePath, interfaceType.getPackage().getName(), implName);

      UiBinderWriter uiBinderWriter = new UiBinderWriter(interfaceType,  
implName,
-        templatePath, oracle, logger);
-    uiBinderWriter.parseDocument(binderPrintWrier);
-
-    MessagesWriter messages = uiBinderWriter.getMessages();
+        templatePath, oracle, logger, new FieldManager(logger), messages);
+
+    Document doc = getW3cDoc(logger, templatePath);
+
+    uiBinderWriter.parseDocument(doc, binderPrintWriter);
+
      if (messages.hasMessages()) {
         
messages.write(writerManager.makePrintWriterFor(messages.getMessagesClassName()));
      }
@@ -124,4 +134,21 @@

      writerManager.commit();
    }
-}
+
+  private Document getW3cDoc(MortalLogger logger, String templatePath)
+      throws UnableToCompleteException {
+    URL url =  
UiBinderGenerator.class.getClassLoader().getResource(templatePath);
+    if (null == url) {
+      logger.die("Unable to find resource: " + templatePath);
+    }
+
+    Document doc = null;
+    try {
+      doc = new W3cDomHelper().documentFor(url);
+    } catch (SAXParseException e) {
+      logger.die("Error parsing XML (line " + e.getLineNumber() + "): "
+          + e.getMessage(), e);
+    }
+    return doc;
+  }
+}
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java  Wed  
Nov  4 11:14:50 2009
+++ /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java  Thu  
Nov  5 12:38:39 2009
@@ -110,7 +110,7 @@
        writer.die("Bad prefix on <%s:%s>? The root element must be in "
            + "xml namespace \"%s\" (usually with prefix \"ui:\"), "
            + "but this has prefix \"%s\"", elem.getPrefix(),
-          elem.getLocalName(), UiBinderWriter.BINDER_URI,  
elem.getPrefix());
+          elem.getLocalName(), UiBinderGenerator.BINDER_URI,  
elem.getPrefix());
      }

      if (!TAG.equals(elem.getLocalName())) {
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java  Wed  
Nov  4 11:14:50 2009
+++ /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java  Thu  
Nov  5 12:38:39 2009
@@ -33,15 +33,9 @@

  import org.w3c.dom.Document;
  import org.w3c.dom.Element;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-
-import java.io.IOException;
-import java.io.InputStream;
+
  import java.io.PrintWriter;
  import java.io.StringWriter;
-import java.net.URL;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashMap;
@@ -50,10 +44,6 @@
  import java.util.Locale;
  import java.util.Map;

-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
  /**
   * Writer for UiBinder generated classes.
   *
@@ -64,7 +54,6 @@
   */
  @SuppressWarnings("deprecation")
  public class UiBinderWriter {
-  static final String BINDER_URI = "urn:ui:com.google.gwt.uibinder";
    private static final String PACKAGE_URI_SCHEME = "urn:import:";

    // TODO(rjrjr) Another place that we need a general anonymous field
@@ -226,17 +215,17 @@
    private final AttributeParsers attributeParsers;
    private final BundleAttributeParsers bundleParsers;

-  UiBinderWriter(JClassType baseClass, String implClassName,
-      String templatePath, TypeOracle oracle, MortalLogger logger)
+  public UiBinderWriter(JClassType baseClass, String implClassName,
+      String templatePath, TypeOracle oracle, MortalLogger logger,
+      FieldManager fieldManager, MessagesWriter messagesWriter)
        throws UnableToCompleteException {
      this.baseClass = baseClass;
      this.implClassName = implClassName;
      this.oracle = oracle;
      this.logger = logger;
      this.templatePath = templatePath;
-
-    this.messages = new MessagesWriter(BINDER_URI, logger, templatePath,
-        baseClass.getPackage().getName(), this.implClassName);
+    this.fieldManager = fieldManager;
+    this.messages = messagesWriter;

      // Check for possible misuse 'GWT.create(UiBinder.class)'
      JClassType uibinderItself =
@@ -267,7 +256,6 @@
      bundleClass = new  
ImplicitClientBundle(baseClass.getPackage().getName(),
          this.implClassName, CLIENT_BUNDLE_FIELD, logger);
      handlerEvaluator = new HandlerEvaluator(ownerClass, logger, oracle);
-    fieldManager = new FieldManager(logger);

      attributeParsers = new AttributeParsers();
      bundleParsers = new BundleAttributeParsers(oracle, gwtPrefix, logger,
@@ -563,7 +551,7 @@

    public boolean isBinderElement(XMLElement elem) {
      String uri = elem.getNamespaceUri();
-    return uri != null && BINDER_URI.equals(uri);
+    return uri != null && UiBinderGenerator.BINDER_URI.equals(uri);
    }

    public boolean isWidgetElement(XMLElement elem) {
@@ -659,23 +647,16 @@
     * Entry point for the code generation logic. It generates the
     * implementation's superstructure, and parses the root widget (leading  
to all
     * of its children being parsed as well).
+   * @param doc TODO
     */
-  void parseDocument(PrintWriter printWriter) throws  
UnableToCompleteException {
-    Document doc = null;
-    try {
-      doc = parseXmlResource(templatePath);
-    } catch (SAXParseException e) {
-      die("Error parsing XML (line " + e.getLineNumber() + "): "
-          + e.getMessage(), e);
-    }
-
+  void parseDocument(Document doc, PrintWriter printWriter) throws  
UnableToCompleteException {
      JClassType uiBinderClass =  
getOracle().findType(UiBinder.class.getName());
      if (!baseClass.isAssignableTo(uiBinderClass)) {
        die(baseClass.getName() + " must implement UiBinder");
      }

      Element documentElement = doc.getDocumentElement();
-    gwtPrefix = documentElement.lookupPrefix(BINDER_URI);
+    gwtPrefix = documentElement.lookupPrefix(UiBinderGenerator.BINDER_URI);

      XMLElement elem = new XMLElementProviderImpl(attributeParsers,
          bundleParsers, oracle, logger).get(documentElement);
@@ -910,45 +891,6 @@

      return null;
    }
-
-  private Document parseXmlResource(final String resourcePath)
-      throws SAXParseException, UnableToCompleteException {
-    // Get the document builder. We need namespaces, and automatic  
expanding
-    // of entity references (the latter of which makes life somewhat easier
-    // for XMLElement).
-    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-    factory.setNamespaceAware(true);
-    factory.setExpandEntityReferences(true);
-    DocumentBuilder builder;
-    try {
-      builder = factory.newDocumentBuilder();
-    } catch (ParserConfigurationException e) {
-      throw new RuntimeException(e);
-    }
-
-    try {
-      ClassLoader classLoader = UiBinderGenerator.class.getClassLoader();
-      URL url = classLoader.getResource(resourcePath);
-      if (null == url) {
-        die("Unable to find resource: " + resourcePath);
-      }
-
-      InputStream stream = url.openStream();
-      InputSource input = new InputSource(stream);
-      input.setSystemId(url.toExternalForm());
-
-      builder.setEntityResolver(new GwtResourceEntityResolver());
-
-      return builder.parse(input);
-    } catch (SAXParseException e) {
-      // Let SAXParseExceptions through.
-      throw e;
-    } catch (SAXException e) {
-      throw new RuntimeException(e);
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-  }

    private void registerParsers() {
      // TODO(rjrjr): Allow third-party parsers to register themselves
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/XMLElementProvider.java      
 
Mon Nov  2 12:47:15 2009
+++ /trunk/user/src/com/google/gwt/uibinder/rebind/XMLElementProvider.java      
 
Thu Nov  5 12:38:39 2009
@@ -17,6 +17,9 @@

  import org.w3c.dom.Element;

-interface XMLElementProvider {
+/**
+ * Implemented by objects that instantiate XMLElement.
+ */
+public interface XMLElementProvider {
    XMLElement get(Element e);
  }
=======================================
---  
/trunk/user/src/com/google/gwt/uibinder/rebind/XMLElementProviderImpl.java      
 
Wed Nov  4 11:14:50 2009
+++  
/trunk/user/src/com/google/gwt/uibinder/rebind/XMLElementProviderImpl.java      
 
Thu Nov  5 12:38:39 2009
@@ -19,7 +19,10 @@

  import org.w3c.dom.Element;

-class XMLElementProviderImpl implements XMLElementProvider {
+/**
+ * The default implemenatation of {...@link XMLElementProvider}.
+ */
+public class XMLElementProviderImpl implements XMLElementProvider {
    private final AttributeParsers attributeParsers;
    @SuppressWarnings("deprecation")
    // bundleParsers for legacy templates
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java      Mon Nov 
  
2 12:47:15 2009
+++ /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java      Thu Nov 
  
5 12:38:39 2009
@@ -15,6 +15,7 @@
   */
  package com.google.gwt.uibinder;

+import com.google.gwt.uibinder.parsers.DockLayoutPanelParserTest;
  import com.google.gwt.uibinder.parsers.FieldReferenceConverterTest;
  import com.google.gwt.uibinder.parsers.IntAttributeParserTest;
  import com.google.gwt.uibinder.parsers.StrictAttributeParserTest;
@@ -49,6 +50,7 @@
      suite.addTestSuite(OwnerFieldTest.class);

      // parsers
+    suite.addTestSuite(DockLayoutPanelParserTest.class);
      suite.addTestSuite(FieldReferenceConverterTest.class);
      suite.addTestSuite(IntAttributeParserTest.class);
      suite.addTestSuite(StrictAttributeParserTest.class);
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java Wed  
Nov  4 13:42:26 2009
+++ /trunk/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java Thu  
Nov  5 12:38:39 2009
@@ -34,35 +34,35 @@
  import java.util.HashSet;
  import java.util.Set;

-import javax.xml.parsers.ParserConfigurationException;
-
  /**
   * Tests XMLElement.
   */
  public class XMLElementTest extends TestCase {
    private static final String STRING_WITH_DOUBLEQUOTE = "I have a \" quote  
in me";
+  private static final W3cDomHelper docHelper = new W3cDomHelper();
    private Document doc;
    private Element item;
    private XMLElement elm;
    private XMLElementProvider elemProvider;
-
-  TypeOracle oracle;
-
+  private TypeOracle oracle;
+
    @Override
    public void setUp() throws Exception {
      super.setUp();
-    init("<doc><elm attr1=\"attr1Value\" attr2=\"attr2Value\"/></doc>");
-
      MockResourceOracle resourceOracle = new MockResourceOracle(
          JavaResourceBase.getStandardResources());
-
      CompilationState state = new CompilationState(TreeLogger.NULL,
          resourceOracle);
      oracle = state.getTypeOracle();
+
+    elemProvider = new XMLElementProviderImpl(new AttributeParsers(), null,
+        oracle, MortalLogger.NULL);
+
+    init("<doc><elm attr1=\"attr1Value\" attr2=\"attr2Value\"/></doc>");
    }

-  public void testConsumeBoolean() throws ParserConfigurationException,
-      SAXException, IOException, UnableToCompleteException {
+  public void testConsumeBoolean() throws SAXException, IOException,
+      UnableToCompleteException {
      init("<doc><elm yes='true' no='false' "
          + "fnord='fnord' ref='{foo.bar.baz}'/></doc>");

@@ -84,8 +84,8 @@
      }
    }

-  public void testConsumeBooleanConstant() throws  
ParserConfigurationException,
-      SAXException, IOException, UnableToCompleteException {
+  public void testConsumeBooleanConstant() throws SAXException,  
IOException,
+      UnableToCompleteException {
      init("<doc><elm yes='true' no='false' "
          + "fnord='fnord' ref='{foo.bar.baz}'/></doc>");

@@ -113,7 +113,7 @@
    }

    public void testConsumeDouble() throws UnableToCompleteException,
-      ParserConfigurationException, SAXException, IOException {
+      SAXException, IOException {
      init("<doc><elm minus='-123.45' plus='123.45' minus-one='-1' "
          + "plus-one='1' fnord='fnord' ref='{foo.bar.baz}'/></doc>");
      assertEquals("1", elm.consumeDoubleAttribute("plus-one"));
@@ -167,9 +167,8 @@
      }
    }

-  public void testConsumeSingleChildElementEmpty()
-      throws ParserConfigurationException, SAXException, IOException,
-      UnableToCompleteException {
+  public void testConsumeSingleChildElementEmpty() throws SAXException,
+      IOException, UnableToCompleteException {
      try {
        elm.consumeSingleChildElement();
        fail("Should throw on single child element");
@@ -220,10 +219,9 @@
    }

    public void testNoEndTags() throws Exception {
-    Document doc = DocumentTestHelp.documentForString("<doc><br/></doc>");
-
-    Element item = (Element)  
doc.getDocumentElement().getElementsByTagName("br").item(
-        0);
+    doc = docHelper.documentFor("<doc><br/></doc>");
+    Element documentElement = doc.getDocumentElement();
+    Element item = (Element)  
documentElement.getElementsByTagName("br").item(0);
      XMLElement elm = elemProvider.get(item);
      assertEquals("br", item.getTagName());
      assertEquals("", elm.getClosingTag());
@@ -234,14 +232,10 @@
      item.appendChild(t);
    }

-  private void init(final String domString)
-      throws ParserConfigurationException, SAXException, IOException {
-    doc = DocumentTestHelp.documentForString(domString);
+  private void init(final String domString) throws SAXException,  
IOException {
+    doc = docHelper.documentFor(domString);
      item = (Element)  
doc.getDocumentElement().getElementsByTagName("elm").item(
          0);
-
-    elemProvider = new XMLElementProviderImpl(new AttributeParsers(), null,
-        oracle, MortalLogger.NULL);
      elm = elemProvider.get(item);
    }
  }

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

Reply via email to