Revision: 6813
Author: [email protected]
Date: Tue Nov 10 12:33:30 2009
Log: <g:StackLayoutPanel> is now consistent with <g:TabLayoutPanel> and
<g:DisclosurePanel> in its use of <g:header> and <g:customHeader>.

The parsers for StackLayoutPanel, DockLayoutPanel and TabLayoutPanel
now all treat their unit (or barUnit) attributes as optional, and
default them to PX

Also,  yet another pass at making the generator more strict: if any extra
attributes, elements or body text are left after all the parsers are run,  
the
user is scolded.
http://code.google.com/p/google-web-toolkit/source/detail?r=6813

Added:
  /trunk/user/src/com/google/gwt/uibinder/elementparsers/IsEmptyParser.java
   
/trunk/user/test/com/google/gwt/uibinder/elementparsers/IsEmptyParserTest.java
   
/trunk/user/test/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParserTest.java
   
/trunk/user/test/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParserTest.java
   
/trunk/user/test/com/google/gwt/uibinder/elementparsers/UIObjectParserTest.java
Modified:
  /trunk/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.ui.xml
   
/trunk/user/src/com/google/gwt/uibinder/elementparsers/DockLayoutPanelParser.java
   
/trunk/user/src/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParser.java
   
/trunk/user/src/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParser.java
  /trunk/user/src/com/google/gwt/uibinder/elementparsers/UIObjectParser.java
  /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
  /trunk/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
  /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java
   
/trunk/user/test/com/google/gwt/uibinder/elementparsers/DockLayoutPanelParserTest.java
   
/trunk/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java
   
/trunk/user/test/com/google/gwt/uibinder/elementparsers/UiJavaResources.java
  /trunk/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java

=======================================
--- /dev/null
+++  
/trunk/user/src/com/google/gwt/uibinder/elementparsers/IsEmptyParser.java       
 
Tue Nov 10 12:33:30 2009
@@ -0,0 +1,34 @@
+/*
+ * 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.uibinder.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.uibinder.rebind.UiBinderWriter;
+import com.google.gwt.uibinder.rebind.XMLElement;
+
+/**
+ * The last parser, asserts that everything has been consumed
+ * and so the template has nothing unexpected.
+ */
+public class IsEmptyParser implements ElementParser {
+
+  public void parse(XMLElement elem, String fieldName, JClassType type,
+      UiBinderWriter writer) throws UnableToCompleteException {
+    elem.assertNoAttributes();
+    elem.assertNoBody();
+  }
+}
=======================================
--- /dev/null
+++  
/trunk/user/test/com/google/gwt/uibinder/elementparsers/IsEmptyParserTest.java  
 
Tue Nov 10 12:33:30 2009
@@ -0,0 +1,83 @@
+/*
+ * 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.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+
+import junit.framework.TestCase;
+
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+
+/**
+ * A unit test. Guess what of.
+ */
+public class IsEmptyParserTest extends TestCase {
+  private static final String PARSED_TYPE  
= "com.google.gwt.user.client.ui.UIObject";
+
+  private ElementParserTester tester;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    tester = new ElementParserTester(PARSED_TYPE, new IsEmptyParser());
+  }
+
+  public void testExtraText() throws SAXException, IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:UIObject>");
+    b.append("  I have some extra");
+    b.append("</g:UIObject>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue("Expect extra text echo",
+          tester.logger.died.contains("I have some extra"));
+    }
+  }
+
+  public void testExtraChildren() throws SAXException, IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:UIObject>");
+    b.append("  <blorp />");
+    b.append("</g:UIObject>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue("Expect extra text child",
+          tester.logger.died.contains("<blorp>"));
+    }
+  }
+
+  public void testExtraAttributes() throws SAXException, IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:UIObject blip='blap' blorp='bloop'>");
+    b.append("</g:UIObject>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue("Expect extra attributes list",
+          tester.logger.died.contains("\"blip\", \"blorp\""));
+    }
+  }
+}
=======================================
--- /dev/null
+++  
/trunk/user/test/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParserTest.java
  
Tue Nov 10 12:33:30 2009
@@ -0,0 +1,104 @@
+/*
+ * 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.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.uibinder.rebind.FieldWriter;
+
+import junit.framework.TestCase;
+
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+/**
+ * A unit test. Guess what of.
+ */
+public class StackLayoutPanelParserTest extends TestCase {
+
+  private static final String PARSED_TYPE  
= "com.google.gwt.user.client.ui.StackLayoutPanel";
+
+  private ElementParserTester tester;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    tester = new ElementParserTester(PARSED_TYPE, new  
StackLayoutPanelParser());
+  }
+
+  public void testBadChild() throws SAXException, IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:StackLayoutPanel unit='EM'>");
+    b.append("  <g:west><foo/></g:west>");
+    b.append("</g:StackLayoutPanel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue("expect \"only g:stack\" error",
+          tester.logger.died.contains("only <g:stack> children"));
+    }
+  }
+
+  public void testHappy() throws UnableToCompleteException, SAXException,
+      IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:StackLayoutPanel unit='PX'>");
+    b.append("  <g:stack>");
+    b.append("    <g:header size='3'>Re<b>mark</b>able</g:header>");
+    b.append("    <g:Label id='able'>able</g:Label>");
+    b.append("  </g:stack>");
+    b.append("  <g:stack>");
+    b.append("    <g:customHeader size='3'>");
+    b.append("      <g:Label id='custom'>Custom</g:Label>");
+    b.append("    </g:customHeader>");
+    b.append("    <g:Label id='baker'>baker</g:Label>");
+    b.append("  </g:stack>");
+    b.append("</g:StackLayoutPanel>");
+
+    String[] expected = {
+        "fieldName.add(<g:Label id='able'>, "
+            + "new  
com.google.gwt.user.client.ui.HTML(\"Re<b>mark</b>able\"), 3);",
+        "fieldName.add(<g:Label id='baker'>, " + "<g:Label id='custom'>,  
3);",};
+
+    FieldWriter w = tester.parse(b.toString());
+    assertEquals("new " + PARSED_TYPE
+        + "(com.google.gwt.dom.client.Style.Unit.PX)", w.getInitializer());
+
+    Iterator<String> i = tester.writer.statements.iterator();
+    for (String e : expected) {
+      assertEquals(e, i.next());
+    }
+    assertFalse(i.hasNext());
+    assertNull(tester.logger.died);
+  }
+
+  public void testNoUnits() throws SAXException, IOException,
+      UnableToCompleteException {
+    StringBuffer b = new StringBuffer();
+    b.append("  <g:StackLayoutPanel>");
+    b.append("  </g:StackLayoutPanel>");
+
+    FieldWriter w = tester.parse(b.toString());
+    assertEquals("new " + PARSED_TYPE
+        + "(com.google.gwt.dom.client.Style.Unit.PX)", w.getInitializer());
+
+    Iterator<String> i = tester.writer.statements.iterator();
+    assertFalse(i.hasNext());
+  }
+}
=======================================
--- /dev/null
+++  
/trunk/user/test/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParserTest.java
    
Tue Nov 10 12:33:30 2009
@@ -0,0 +1,102 @@
+/*
+ * 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.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.uibinder.rebind.FieldWriter;
+
+import junit.framework.TestCase;
+
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+/**
+ * A unit test. Guess what of.
+ */
+public class TabLayoutPanelParserTest extends TestCase {
+
+  private static final String PARSED_TYPE  
= "com.google.gwt.user.client.ui.TabLayoutPanel";
+
+  private ElementParserTester tester;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    tester = new ElementParserTester(PARSED_TYPE, new  
TabLayoutPanelParser());
+  }
+
+  public void testBadChild() throws SAXException, IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabLayoutPanel unit='EM'>");
+    b.append("  <g:west><foo/></g:west>");
+    b.append("</g:TabLayoutPanel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertNotNull(tester.logger.died);
+    }
+  }
+
+  public void testHappy() throws UnableToCompleteException, SAXException,
+      IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabLayoutPanel barUnit='PX' barHeight='30'>");
+    b.append("  <g:tab>");
+    b.append("    <g:header size='3'>Re<b>mark</b>able</g:header>");
+    b.append("    <g:Label id='able'>able</g:Label>");
+    b.append("  </g:tab>");
+    b.append("  <g:tab>");
+    b.append("    <g:customHeader size='3'>");
+    b.append("      <g:Label id='custom'>Custom</g:Label>");
+    b.append("    </g:customHeader>");
+    b.append("    <g:Label id='baker'>baker</g:Label>");
+    b.append("  </g:tab>");
+    b.append("</g:TabLayoutPanel>");
+
+    String[] expected = {
+        "fieldName.add(<g:Label id='able'>, \"Re<b>mark</b>able\", true);",
+        "fieldName.add(<g:Label id='baker'>, " + "<g:Label  
id='custom'>);",};
+
+    FieldWriter w = tester.parse(b.toString());
+    assertEquals("new " + PARSED_TYPE
+        + "(30, com.google.gwt.dom.client.Style.Unit.PX)",  
w.getInitializer());
+
+    Iterator<String> i = tester.writer.statements.iterator();
+    for (String e : expected) {
+      assertEquals(e, i.next());
+    }
+    assertFalse(i.hasNext());
+    assertNull(tester.logger.died);
+  }
+
+  public void testNoUnits() throws SAXException, IOException,
+      UnableToCompleteException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabLayoutPanel barHeight='3'>");
+    b.append("  </g:TabLayoutPanel>");
+
+    FieldWriter w = tester.parse(b.toString());
+    assertEquals("new " + PARSED_TYPE
+        + "(3, com.google.gwt.dom.client.Style.Unit.PX)",  
w.getInitializer());
+
+    Iterator<String> i = tester.writer.statements.iterator();
+    assertFalse(i.hasNext());
+  }
+}
=======================================
--- /dev/null
+++  
/trunk/user/test/com/google/gwt/uibinder/elementparsers/UIObjectParserTest.java 
 
Tue Nov 10 12:33:30 2009
@@ -0,0 +1,65 @@
+/*
+ * 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.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+
+import junit.framework.TestCase;
+
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+/**
+ * A unit test. Guess what of.
+ */
+public class UIObjectParserTest extends TestCase {
+  private static final String PARSED_TYPE  
= "com.google.gwt.user.client.ui.UIObject";
+
+  private ElementParserTester tester;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    tester = new ElementParserTester(PARSED_TYPE, new UIObjectParser());
+  }
+
+  public void testHappy() throws UnableToCompleteException, SAXException,
+      IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:UIObject debugId='blat' addStyleNames='foo, bar baz'");
+    b.append("    addStyleDependentNames='able, baker charlie' >");
+    b.append("</g:UIObject>");
+
+    String[] expected = {
+        "fieldName.ensureDebugId(\"blat\");",
+        "fieldName.addStyleName(\"foo\");", "fieldName.addStyleName(\"bar\");",
+        "fieldName.addStyleName(\"baz\");",
+        "fieldName.addStyleDependentName(\"able\");",
+        "fieldName.addStyleDependentName(\"baker\");",
+        "fieldName.addStyleDependentName(\"charlie\");",};
+
+    tester.parse(b.toString());
+
+    Iterator<String> i = tester.writer.statements.iterator();
+    for (String e : expected) {
+      assertEquals(e, i.next());
+    }
+    assertFalse(i.hasNext());
+    assertNull(tester.logger.died);
+  }
+}
=======================================
---  
/trunk/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.ui.xml      
 
Mon Nov  9 10:52:41 2009
+++  
/trunk/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.ui.xml      
 
Tue Nov 10 12:33:30 2009
@@ -45,29 +45,17 @@

    <g:StackLayoutPanel styleName='{style.shortcuts}' unit='EM'>
      <g:stack>
-      <g:header size='3'>
-        <g:HTMLPanel styleName='{style.stackHeader}'>
-          <div class='{style.mailboxesIcon}'/> Mailboxes
-        </g:HTMLPanel>
-      </g:header>
+      <g:header size='3'><div class='{style.mailboxesIcon}'/>  
Mailboxes</g:header>
        <mail:Mailboxes ui:field='mailboxes'/>
      </g:stack>

      <g:stack>
-      <g:header size='3'>
-        <g:HTMLPanel styleName='{style.stackHeader}'>
-          <div class='{style.tasksIcon}'/> Tasks
-        </g:HTMLPanel>
-      </g:header>
+      <g:header size='3'><div class='{style.tasksIcon}'/> Tasks</g:header>
        <mail:Tasks ui:field='tasks'/>
      </g:stack>

      <g:stack>
-      <g:header size='3'>
-        <g:HTMLPanel styleName='{style.stackHeader}'>
-          <div class='{style.contactsIcon}'/> Contacts
-        </g:HTMLPanel>
-      </g:header>
+      <g:header size='3'><div class='{style.contactsIcon}'/>  
Contacts</g:header>
        <mail:Contacts ui:field='contacts'/>
      </g:stack>
    </g:StackLayoutPanel>
=======================================
---  
/trunk/user/src/com/google/gwt/uibinder/elementparsers/DockLayoutPanelParser.java
        
Fri Nov  6 16:08:46 2009
+++  
/trunk/user/src/com/google/gwt/uibinder/elementparsers/DockLayoutPanelParser.java
        
Tue Nov 10 12:33:30 2009
@@ -62,11 +62,13 @@
    public void parse(XMLElement elem, String fieldName, JClassType type,
        UiBinderWriter writer) throws UnableToCompleteException {
      // Generate instantiation (requires a 'unit' ctor param).
-    // (Don't generate a ctor for the SplitLayoutPanel; it's implicitly  
PX).
+    // (Don't generate a ctor for the SplitLayoutPanel, it has its own  
parser).
      if (type != getSplitLayoutPanelType(writer)) {
        JEnumType unitEnumType = writer.getOracle().findType(
            Unit.class.getCanonicalName()).isEnum();
-      String unit = elem.consumeAttribute("unit", unitEnumType);
+      String unit = elem.consumeAttributeWithDefault("unit",
+          String.format("%s.%s",  
unitEnumType.getQualifiedSourceName(), "PX"),
+          unitEnumType);
        writer.setFieldInitializerAsConstructor(fieldName,
            writer.getOracle().findType(DockLayoutPanel.class.getName()),  
unit);
      }
@@ -123,11 +125,7 @@
    }

    private boolean isValidChildElement(XMLElement parent, XMLElement child)  
{
-    String childNsUri = child.getNamespaceUri();
-    if (childNsUri == null) {
-      return false;
-    }
-    if (!childNsUri.equals(parent.getNamespaceUri())) {
+    if (!parent.getNamespaceUri().equals(child.getNamespaceUri())) {
        return false;
      }
      if (!DOCK_NAMES.containsKey(child.getLocalName())) {
=======================================
---  
/trunk/user/src/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParser.java
       
Fri Nov  6 16:08:46 2009
+++  
/trunk/user/src/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParser.java
       
Tue Nov 10 12:33:30 2009
@@ -27,56 +27,135 @@
   * Parses {...@link StackLayoutPanel} widgets.
   */
  public class StackLayoutPanelParser implements ElementParser {
-
-  private static final String HEADER_ELEM = "header";
-  private static final String STACK_ELEM = "stack";
-
-  public void parse(XMLElement elem, String fieldName, JClassType type,
+  private static class Children {
+    XMLElement body;
+    XMLElement header;
+    XMLElement customHeader;
+  }
+
+  private static final String CUSTOM = "customHeader";
+  private static final String HEADER = "header";
+  private static final String STACK = "stack";
+
+  public void parse(XMLElement panelElem, String fieldName, JClassType  
type,
        UiBinderWriter writer) throws UnableToCompleteException {
+
      JEnumType unitEnumType = writer.getOracle().findType(
          Unit.class.getCanonicalName()).isEnum();
-    String unit = elem.consumeAttribute("unit", unitEnumType);
+    String unit = panelElem.consumeAttributeWithDefault("unit",
+        String.format("%s.%s",  
unitEnumType.getQualifiedSourceName(), "PX"),
+        unitEnumType);
+
      writer.setFieldInitializerAsConstructor(fieldName,
          writer.getOracle().findType(StackLayoutPanel.class.getName()),
          unit);

      // Parse children.
-    for (XMLElement child : elem.consumeChildElements()) {
+    for (XMLElement stackElem : panelElem.consumeChildElements()) {
        // Get the stack element.
-      if (!isElementType(elem, child, STACK_ELEM)) {
-        writer.die("In %s, Only <stack> children are allowed.", elem);
-      }
-
-      XMLElement headerElem = null, widgetElem = null;
-      for (XMLElement stackChild : child.consumeChildElements()) {
-        // Get the header.
-        if (isElementType(elem, stackChild, HEADER_ELEM)) {
-          if (headerElem != null) {
-            writer.die("In %s, Only one <header> allowed per <stack>",  
elem);
-          }
-          headerElem = stackChild;
-          continue;
-        }
-
-        // Get the widget.
-        if (widgetElem != null) {
-          writer.die("In %s, Only one child widget allowed per <stack>",  
elem);
-        }
-        widgetElem = stackChild;
-      }
-
-      String size = headerElem.consumeDoubleAttribute("size");
-      XMLElement headerWidgetElem = headerElem.consumeSingleChildElement();
-      String headerFieldName =  
writer.parseElementToField(headerWidgetElem);
-      String childFieldName = writer.parseElementToField(widgetElem);
-
-      writer.addStatement("%s.add(%s, %s, %s);", fieldName, childFieldName,
-          headerFieldName, size);
-    }
-  }
+      if (!isElementType(panelElem, stackElem, STACK)) {
+        writer.die("In %s, only <%s:%s> children are allowed.", panelElem,
+            panelElem.getPrefix(), STACK);
+      }
+
+      // Find all the children of the <stack>.
+      Children children = findChildren(stackElem, writer);
+
+      // Parse the child widget.
+      if (children.body == null) {
+        writer.die("In %s, %s must have a child widget", panelElem,  
stackElem);
+      }
+      if (!writer.isWidgetElement(children.body)) {
+        writer.die("In %s, %s must be a widget", stackElem, children.body);
+      }
+      String childFieldName = writer.parseElementToField(children.body);
+
+      // Parse the header.
+      if (children.header != null) {
+        HtmlInterpreter htmlInt =  
HtmlInterpreter.newInterpreterForUiObject(
+            writer, fieldName);
+        String size = children.header.consumeDoubleAttribute("size");
+        if ("".equals(size)) {
+          writer.die("In %s, %s must have a size", panelElem, stackElem);
+        }
+        String html = children.header.consumeInnerHtml(htmlInt);
+        writer.addStatement("%s.add(%s, "
+            + "new com.google.gwt.user.client.ui.HTML(\"%s\"), "
+            + "%s);", fieldName,
+            childFieldName, html, size);
+      } else if (children.customHeader != null) {
+        XMLElement headerElement =
+          children.customHeader.consumeSingleChildElement();
+        String size = children.customHeader.consumeDoubleAttribute("size");
+        if ("".equals(size)) {
+          writer.die("In %s, %s must have a size", panelElem, stackElem);
+        }
+        if (!writer.isWidgetElement(headerElement)) {
+          writer.die("In %s of %s, %s is not a widget",  
children.customHeader,
+              stackElem, headerElement);
+        }
+
+        String headerField = writer.parseElementToField(headerElement);
+        writer.addStatement("%s.add(%s, %s, %s);", fieldName,  
childFieldName,
+            headerField, size);
+      } else {
+        // Neither a header or customHeader.
+        writer.die("In %1$s, %2$s requires either a <%3$s:%4$s> or  
<%3$s:%5$s>",
+            panelElem, stackElem, stackElem.getPrefix(), HEADER, CUSTOM);
+      }
+    }
+  }
+
+private Children findChildren(final XMLElement elem,
+    final UiBinderWriter writer) throws UnableToCompleteException {
+  final Children children = new Children();
+
+  elem.consumeChildElements(new XMLElement.Interpreter<Boolean>() {
+    public Boolean interpretElement(XMLElement child)
+        throws UnableToCompleteException {
+
+      if (hasTag(child, HEADER)) {
+        assertFirstHeader();
+        children.header = child;
+        return true;
+      }
+
+      if (hasTag(child, CUSTOM)) {
+        assertFirstHeader();
+        children.customHeader = child;
+        return true;
+      }
+
+      // Must be the body, then
+      if (null != children.body) {
+        writer.die("In %s, may have only one body element", elem);
+      }
+
+      children.body = child;
+      return true;
+    }
+
+    void assertFirstHeader() throws UnableToCompleteException {
+      if ((null != children.header) && (null != children.customHeader)) {
+        writer.die("In %1$s, may have only one %2$s:header "
+            + "or %2$s:customHeader", elem, elem.getPrefix());
+      }
+    }
+
+    private boolean hasTag(XMLElement child, final String attribute) {
+      return rightNamespace(child) &&  
child.getLocalName().equals(attribute);
+    }
+
+    private boolean rightNamespace(XMLElement child) {
+      return child.getNamespaceUri().equals(elem.getNamespaceUri());
+    }
+  });
+
+  return children;
+}

    private boolean isElementType(XMLElement parent, XMLElement child,  
String type) {
-    return child.getNamespaceUri().equals(parent.getNamespaceUri())
+    return parent.getNamespaceUri().equals(child.getNamespaceUri())
          && type.equals(child.getLocalName());
    }
  }
=======================================
---  
/trunk/user/src/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParser.java
         
Fri Nov  6 16:08:46 2009
+++  
/trunk/user/src/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParser.java
         
Tue Nov 10 12:33:30 2009
@@ -40,17 +40,21 @@

    public void parse(XMLElement panelElem, String fieldName, JClassType  
type,
        UiBinderWriter writer) throws UnableToCompleteException {
-    JEnumType unitEnumType = writer.getOracle().findType(
-        Unit.class.getCanonicalName()).isEnum();
-
      // TabLayoutPanel requires tabBar size and unit ctor args.
+
      String size = panelElem.consumeDoubleAttribute("barHeight");
-    String unit = panelElem.consumeAttribute("barUnit", unitEnumType);
-
-    JClassType tlpType = writer.getOracle().findType(
-        TabLayoutPanel.class.getName());
-    writer.setFieldInitializerAsConstructor(fieldName, tlpType,
-        size, unit);
+    if ("".equals(size)) {
+      writer.die("In %s, barHeight attribute is required", panelElem);
+    }
+
+    JEnumType unitEnumType = writer.getOracle().findType(
+        Unit.class.getCanonicalName()).isEnum();
+    String unit = panelElem.consumeAttributeWithDefault("barUnit",
+        String.format("%s.%s",  
unitEnumType.getQualifiedSourceName(), "PX"),
+        unitEnumType);
+
+    writer.setFieldInitializerAsConstructor(fieldName,
+        writer.getOracle().findType(TabLayoutPanel.class.getName()), size,  
unit);

      // Parse children.
      for (XMLElement tabElem : panelElem.consumeChildElements()) {
@@ -65,7 +69,7 @@

        // Parse the child widget.
        if (children.body == null) {
-        writer.die("%s must have a child widget", tabElem);
+        writer.die("In %s, %s must have a child widget", panelElem,  
tabElem);
        }
        if (!writer.isWidgetElement(children.body)) {
          writer.die("In %s, %s must be a widget", tabElem, children.body);
@@ -93,8 +97,8 @@
              headerField);
        } else {
          // Neither a header or customHeader.
-        writer.die("%1$s requires either a <%2$s:%3$s> or <%2$s:%4$s>",
-            tabElem, tabElem.getPrefix(), HEADER, CUSTOM);
+        writer.die("In %1$s, %2$s requires either a <%3$s:%4$s> or  
<%3$s:%5$s>",
+            panelElem, tabElem, tabElem.getPrefix(), HEADER, CUSTOM);
        }
      }
    }
@@ -148,7 +152,7 @@
    }

    private boolean isElementType(XMLElement parent, XMLElement child,  
String type) {
-    return child.getNamespaceUri().equals(parent.getNamespaceUri())
+    return parent.getNamespaceUri().equals(child.getNamespaceUri())
          && type.equals(child.getLocalName());
    }
  }
=======================================
---  
/trunk/user/src/com/google/gwt/uibinder/elementparsers/UIObjectParser.java      
 
Fri Nov  6 16:08:46 2009
+++  
/trunk/user/src/com/google/gwt/uibinder/elementparsers/UIObjectParser.java      
 
Tue Nov 10 12:33:30 2009
@@ -43,14 +43,5 @@
      for (String s : styleNames) {
        writer.addStatement("%s.addStyleDependentName(%s);", fieldName, s);
      }
-
-    HtmlInterpreter interpreter =  
HtmlInterpreter.newInterpreterForUiObject(
-        writer, fieldName);
-
-    String html = elem.consumeInnerHtml(interpreter);
-    if (html.trim().length() > 0) {
-      writer.setFieldInitializer(fieldName, String.format(
-          "new DomHolder(UiBinderUtil.fromHtml(\"%s\"))", html));
-    }
    }
  }
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java  Mon  
Nov  9 12:42:44 2009
+++ /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java  Tue  
Nov 10 12:33:30 2009
@@ -28,6 +28,7 @@
  import com.google.gwt.uibinder.elementparsers.AttributeMessageParser;
  import com.google.gwt.uibinder.elementparsers.BeanParser;
  import com.google.gwt.uibinder.elementparsers.ElementParser;
+import com.google.gwt.uibinder.elementparsers.IsEmptyParser;
  import com.google.gwt.uibinder.rebind.messages.MessagesWriter;
  import com.google.gwt.uibinder.rebind.model.ImplicitClientBundle;
  import com.google.gwt.uibinder.rebind.model.ImplicitCssResource;
@@ -833,7 +834,8 @@
      }

      parsers.add(new BeanParser());
-
+    parsers.add(new IsEmptyParser());
+
      return parsers;
    }

=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/XMLElement.java      Mon Nov 
  
9 12:42:44 2009
+++ /trunk/user/src/com/google/gwt/uibinder/rebind/XMLElement.java      Tue Nov 
 
10 12:33:30 2009
@@ -86,7 +86,7 @@

    private static void clearChildren(Element elem) {
      // TODO(rjrjr) I'm nearly positive that anywhere this is called
-    // we should instead be calling assertEmpty
+    // we should instead be calling assertNoBody
      Node child;
      while ((child = elem.getFirstChild()) != null) {
        elem.removeChild(child);
@@ -145,6 +145,57 @@

      this.debugString = getOpeningTag();
    }
+
+  /**
+   * Ensure that the receiver has no attributes left
+   *
+   * @throws UnableToCompleteException if it does
+   */
+  public void assertNoAttributes() throws UnableToCompleteException {
+    int numAtts = getAttributeCount();
+    if (numAtts == 0) {
+      return;
+    }
+
+    StringBuilder b = new StringBuilder();
+    for (int i = 0; i < numAtts; i++) {
+      if (i > 0) {
+        b.append(", ");
+      }
+      b.append('"').append(getAttribute(i).getName()).append('"');
+    }
+    logger.die("Unexpected attributes in %s: %s", this, b);
+  }
+
+  /**
+   * Require that the receiver's body is empty of text and has no child  
nodes
+   *
+   * @throws UnableToCompleteException if it isn't
+   */
+  public void assertNoBody() throws UnableToCompleteException {
+    consumeChildElements(new Interpreter<Boolean>() {
+      public Boolean interpretElement(XMLElement elem)
+          throws UnableToCompleteException {
+        logger.die("In %s, found unexpected child \"%s\"", this, elem);
+        return false; // unreachable
+      }
+    });
+    assertNoText();
+  }
+
+  /**
+   * Require that the receiver's body is empty of text
+   *
+   * @throws UnableToCompleteException if it isn't
+   */
+  public void assertNoText() throws UnableToCompleteException {
+    NoBrainInterpeter<String> nullInterpreter = new  
NoBrainInterpeter<String>(
+        null);
+    String s = consumeInnerTextEscapedAsHtmlStringLiteral(nullInterpreter);
+    if (!"".equals(s)) {
+      logger.die("Unexpected text in %s: \"%s\"", this, s);
+    }
+  }

    /**
     * Consumes the given attribute as a literal or field reference. The  
optional
@@ -259,7 +310,7 @@
    public Iterable<XMLElement> consumeChildElements()
        throws UnableToCompleteException {
      Iterable<XMLElement> rtn = consumeChildElementsNoEmptyCheck();
-    assertEmpty();
+    assertNoText();
      return rtn;
    }

@@ -651,15 +702,6 @@
    public String toString() {
      return debugString;
    }
-
-  private void assertEmpty() throws UnableToCompleteException {
-    NoBrainInterpeter<String> nullInterpreter = new  
NoBrainInterpeter<String>(
-        null);
-    String s = consumeInnerTextEscapedAsHtmlStringLiteral(nullInterpreter);
-    if (!"".equals(s)) {
-      logger.die("Unexpected text in %s: \"%s\"", this, s);
-    }
-  }

    private Iterable<XMLElement> consumeChildElementsNoEmptyCheck() {
      try {
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java      Mon Nov 
  
9 12:42:44 2009
+++ /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java      Tue Nov 
 
10 12:33:30 2009
@@ -1,12 +1,12 @@
  /*
   * 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
@@ -21,6 +21,10 @@
  import com.google.gwt.uibinder.attributeparsers.StringAttributeParserTest;
  import com.google.gwt.uibinder.elementparsers.DialogBoxParserTest;
  import com.google.gwt.uibinder.elementparsers.DockLayoutPanelParserTest;
+import com.google.gwt.uibinder.elementparsers.IsEmptyParserTest;
+import com.google.gwt.uibinder.elementparsers.StackLayoutPanelParserTest;
+import com.google.gwt.uibinder.elementparsers.TabLayoutPanelParserTest;
+import com.google.gwt.uibinder.elementparsers.UIObjectParserTest;
  import com.google.gwt.uibinder.rebind.GwtResourceEntityResolverTest;
  import com.google.gwt.uibinder.rebind.HandlerEvaluatorTest;
  import com.google.gwt.uibinder.rebind.TokenatorTest;
@@ -50,14 +54,20 @@
      suite.addTestSuite(OwnerFieldClassTest.class);
      suite.addTestSuite(OwnerFieldTest.class);

-    // parsers
-    suite.addTestSuite(DialogBoxParserTest.class);
-    suite.addTestSuite(DockLayoutPanelParserTest.class);
-    suite.addTestSuite(FieldReferenceConverterTest.class);
+    // attributeparsers
      suite.addTestSuite(IntAttributeParserTest.class);
+    suite.addTestSuite(FieldReferenceConverterTest.class);
      suite.addTestSuite(StrictAttributeParserTest.class);
      suite.addTestSuite(StringAttributeParserTest.class);

+    // elementparsers
+    suite.addTestSuite(DialogBoxParserTest.class);
+    suite.addTestSuite(DockLayoutPanelParserTest.class);
+    suite.addTestSuite(IsEmptyParserTest.class);
+    suite.addTestSuite(StackLayoutPanelParserTest.class);
+    suite.addTestSuite(TabLayoutPanelParserTest.class);
+    suite.addTestSuite(UIObjectParserTest.class);
+
      return suite;
    }

=======================================
---  
/trunk/user/test/com/google/gwt/uibinder/elementparsers/DockLayoutPanelParserTest.java
   
Mon Nov  9 12:42:44 2009
+++  
/trunk/user/test/com/google/gwt/uibinder/elementparsers/DockLayoutPanelParserTest.java
   
Tue Nov 10 12:33:30 2009
@@ -50,7 +50,8 @@
        tester.parse(b.toString());
        fail();
      } catch (UnableToCompleteException e) {
-      assertNotNull(tester.logger.died);
+      assertTrue("expect \"must contain a widget\" error",
+          tester.logger.died.contains("must contain a widget"));
      }
    }

@@ -127,4 +128,17 @@
        assertNotNull(tester.logger.died);
      }
    }
-}
+
+  public void testNoUnits() throws SAXException, IOException,  
UnableToCompleteException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DockLayoutPanel>");
+    b.append("</g:DockLayoutPanel>");
+
+    FieldWriter w = tester.parse(b.toString());
+    assertEquals("new " + PARSED_TYPE
+        + "(com.google.gwt.dom.client.Style.Unit.PX)", w.getInitializer());
+
+    Iterator<String> i = tester.writer.statements.iterator();
+    assertFalse(i.hasNext());
+  }
+}
=======================================
---  
/trunk/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java
         
Mon Nov  9 19:37:01 2009
+++  
/trunk/user/test/com/google/gwt/uibinder/elementparsers/ElementParserTester.java
         
Tue Nov 10 12:33:30 2009
@@ -23,6 +23,7 @@
  import com.google.gwt.dev.javac.CompilationStateBuilder;
  import com.google.gwt.dev.javac.impl.MockJavaResource;
  import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
  import com.google.gwt.uibinder.attributeparsers.AttributeParsers;
  import com.google.gwt.uibinder.rebind.FieldManager;
  import com.google.gwt.uibinder.rebind.FieldWriter;
@@ -33,13 +34,21 @@
  import com.google.gwt.uibinder.rebind.XMLElementProviderImpl;
  import com.google.gwt.uibinder.rebind.messages.MessagesWriter;

+import junit.framework.Assert;
+
  import org.w3c.dom.Document;
  import org.w3c.dom.Element;
  import org.xml.sax.SAXException;

  import java.io.IOException;
+import java.io.PrintWriter;
  import java.util.Set;

+/**
+ * Utility for testing {...@link ElementParser} implementations in
+ * isolation. For a new test you'll probably need to extend the
+ * mock class hierarchy in {...@link UiJavaResources}.
+ */
  class ElementParserTester {
     static final MockJavaResource BINDER_OWNER_JAVA = new MockJavaResource(
        "my.Ui") {
@@ -59,14 +68,21 @@
    static final String FIELD_NAME = "fieldName";
    static final String BINDER_URI = "binderUri";

+  private static TreeLogger createLogger() {
+    PrintWriterTreeLogger logger = new PrintWriterTreeLogger(new  
PrintWriter(
+        System.err, true));
+    logger.setMaxDetail(TreeLogger.ERROR);
+    return logger;
+  }
    final JClassType parsedType;
    final MockMortalLogger logger = new MockMortalLogger();
-  final W3cDomHelper docHelper = new W3cDomHelper(TreeLogger.NULL);
-
+
+  final W3cDomHelper docHelper = new W3cDomHelper(createLogger());
    final TypeOracle types;
    final XMLElementProvider elemProvider;
    final MockUiBinderWriter writer;
    final FieldManager fieldManager;
+
    final ElementParser parser;

    ElementParserTester(String parsedTypeName, ElementParser parser)
@@ -74,7 +90,7 @@
      this.parser = parser;
      String templatePath = "TemplatePath.ui.xml";
      String implName = "ImplClass";
-    CompilationState state =  
CompilationStateBuilder.buildFrom(TreeLogger.NULL,
+    CompilationState state =  
CompilationStateBuilder.buildFrom(createLogger(),
          getUiResources());
      types = state.getTypeOracle();

@@ -107,8 +123,11 @@

    private XMLElement getElem(String string) throws SAXException,  
IOException {
      Document doc = docHelper.documentFor(string);
+    String tag = "g:" + parsedType.getName();
      Element w3cElem = (Element)  
doc.getDocumentElement().getElementsByTagName(
-        "g:" + parsedType.getName()).item(0);
+        tag).item(0);
+    Assert.assertNotNull(String.format("Expected to find <%s> element in  
test DOM", tag),
+        w3cElem);
      XMLElement elem = elemProvider.get(w3cElem);
      return elem;
    }
=======================================
---  
/trunk/user/test/com/google/gwt/uibinder/elementparsers/UiJavaResources.java    
 
Mon Nov  9 19:37:01 2009
+++  
/trunk/user/test/com/google/gwt/uibinder/elementparsers/UiJavaResources.java    
 
Tue Nov 10 12:33:30 2009
@@ -72,6 +72,17 @@
        code.append("}\n");
        return code;
      }
+  };
+  public static final MockJavaResource STACK_LAYOUT_PANEL = new  
MockJavaResource(
+      "com.google.gwt.user.client.ui.StackLayoutPanel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("public class StackLayoutPanel extends Widget {\n");
+      code.append("}\n");
+      return code;
+    }
    };
    public static final MockJavaResource STYLE = new MockJavaResource(
        "com.google.gwt.dom.client.Style") {
@@ -84,6 +95,17 @@
        code.append("}\n");
        return code;
      }
+  };
+  public static final MockJavaResource TAB_LAYOUT_PANEL = new  
MockJavaResource(
+      "com.google.gwt.user.client.ui.TabLayoutPanel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("public class TabLayoutPanel extends Widget {\n");
+      code.append("}\n");
+      return code;
+    }
    };
    public static final MockJavaResource UI_BINDER = new MockJavaResource(
        "com.google.gwt.uibinder.client.UiBinder") {
@@ -95,6 +117,17 @@
        code.append("}\n");
        return code;
      }
+  };
+  public static final MockJavaResource UI_OBJECT = new MockJavaResource(
+  "com.google.gwt.user.client.ui.UIObject") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("public class UIObject {\n");
+      code.append("}\n");
+      return code;
+    }
    };
    public static final MockJavaResource WIDGET = new MockJavaResource(
        "com.google.gwt.user.client.ui.Widget") {
@@ -102,7 +135,7 @@
      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("public class Widget extends UIObject {\n");
        code.append("}\n");
        return code;
      }
@@ -119,7 +152,10 @@
      rtn.add(DOCK_LAYOUT_PANEL);
      rtn.add(LABEL);
      rtn.add(SPLIT_LAYOUT_PANEL);
+    rtn.add(STACK_LAYOUT_PANEL);
      rtn.add(STYLE);
+    rtn.add(TAB_LAYOUT_PANEL);
+    rtn.add(UI_OBJECT);
      rtn.add(UI_BINDER);
      rtn.add(WIDGET);
      return rtn;
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java Mon  
Nov  9 19:37:01 2009
+++ /trunk/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java Tue  
Nov 10 12:33:30 2009
@@ -64,6 +64,40 @@

      init("<doc><elm attr1=\"attr1Value\" attr2=\"attr2Value\"/></doc>");
    }
+
+  public void testAssertNoAttributes() throws SAXException, IOException {
+    init("<doc><elm yes='true' no='false'>Blah <blah/> blah</elm></doc>");
+    try {
+      elm.assertNoAttributes();
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue("Expect extra attributes list",
+          logger.died.contains("\"yes\""));
+      assertTrue("Expect extra attributes list",
+          logger.died.contains("\"no\""));
+    }
+  }
+
+  public void testAssertNoBody() throws SAXException, IOException {
+    init("<doc><elm yes='true' no='false'>Blah <blah/> blah</elm></doc>");
+    try {
+      elm.assertNoBody();
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue("Expect extra child", logger.died.contains("<blah>"));
+    }
+  }
+
+  public void testAssertNoText() throws SAXException, IOException {
+    init("<doc><elm yes='true' no='false'>Blah <blah/> blah</elm></doc>");
+    try {
+      elm.assertNoText();
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue("Expect extra text", logger.died.contains("Blah"));
+      assertTrue("Expect extra text", logger.died.contains("blah"));
+    }
+  }

    public void testConsumeBoolean() throws SAXException, IOException,
        UnableToCompleteException {

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

Reply via email to