Revision: 8676
Author: gwt.mirror...@gmail.com
Date: Tue Aug 31 12:33:22 2010
Log: Tests and tweaks for DisclosurePanel and StackLayoutPanel parsers.

1. Problems in assertFirstHeader().
1.1. invalid condition;
1.2. invalid reference on second argument.
2. Use addStatement() instead of addInitStatement(), because same is done
everywhere.
3. Small tweaks.
4. Set of tests, including all bad cases.

Patch by konstantin.scheg...@gmail.com
Review by rj...@google.com

http://gwt-code-reviews.appspot.com/736801/show

Review by: robertvaw...@google.com
http://code.google.com/p/google-web-toolkit/source/detail?r=8676

Added:
/trunk/user/test/com/google/gwt/uibinder/elementparsers/DisclosurePanelParserTest.java /trunk/user/test/com/google/gwt/uibinder/elementparsers/StackPanelParserTest.java /trunk/user/test/com/google/gwt/uibinder/elementparsers/TabPanelParserTest.java
Modified:
/trunk/user/src/com/google/gwt/uibinder/elementparsers/DisclosurePanelParser.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/TabPanelParser.java
 /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.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/test/UiJavaResources.java

=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/uibinder/elementparsers/DisclosurePanelParserTest.java Tue Aug 31 12:33:22 2010
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2010 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 java.util.Iterator;
+
+/**
+ * Test for {...@link DisclosurePanelParser}.
+ */
+public class DisclosurePanelParserTest extends TestCase {
+
+ private static final String PARSED_TYPE = "com.google.gwt.user.client.ui.DisclosurePanel";
+
+  private ElementParserTester tester;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+ tester = new ElementParserTester(PARSED_TYPE, new DisclosurePanelParser());
+  }
+
+  public void testBad_notWidget() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DisclosurePanel>");
+    b.append("  <div/>");
+    b.append("</g:DisclosurePanel>");
+
+    parseAndFail(b, "Must be a widget");
+  }
+
+  public void testBad_twoWidgets() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DisclosurePanel>");
+    b.append("  <g:Button id='1'/>");
+    b.append("  <g:Button id='2'/>");
+    b.append("</g:DisclosurePanel>");
+
+    parseAndFail(b, "May have only one body element");
+  }
+
+  public void testBad_twoHeaders() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DisclosurePanel>");
+    b.append("  <g:header>111</g:header>");
+    b.append("  <g:header>222</g:header>");
+    b.append("  <g:Button/>");
+    b.append("</g:DisclosurePanel>");
+
+    parseAndFail(b, "May have only one <g:header> or <g:customHeader>");
+  }
+
+  public void testBad_twoCustomHeaders() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DisclosurePanel>");
+    b.append("  <g:customHeader><g:Label>111</g:Label></g:customHeader>");
+    b.append("  <g:customHeader><g:Label>222</g:Label></g:customHeader>");
+    b.append("  <g:Button/>");
+    b.append("</g:DisclosurePanel>");
+
+    parseAndFail(b, "May have only one <g:header> or <g:customHeader>");
+  }
+
+  public void testBad_withHeader_onlyOpenImage() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DisclosurePanel>");
+    b.append("  <g:header openImage='{open}'>foo</g:header>");
+    b.append("  <g:Button/>");
+    b.append("</g:DisclosurePanel>");
+
+    parseAndFail(b,
+        "Both openImage and closedImage must be specified, or neither");
+  }
+
+  public void testBad_withHeader_onlyClosedImage() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DisclosurePanel>");
+    b.append("  <g:header closedImage='{closed}'>foo</g:header>");
+    b.append("  <g:Button/>");
+    b.append("</g:DisclosurePanel>");
+
+    parseAndFail(b,
+        "Both openImage and closedImage must be specified, or neither");
+  }
+
+  public void testBad_withCustomHeader_notWidget() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DisclosurePanel>");
+    b.append("  <g:customHeader><div/></g:customHeader>");
+    b.append("  <g:Button/>");
+    b.append("</g:DisclosurePanel>");
+
+    parseAndFail(b, "Must be a widget", "<div>");
+  }
+
+  /**
+   * Parses bad code in given {...@link StringBuffer} and asserts that failure
+   * message has expected strings.
+   */
+  private void parseAndFail(StringBuffer b, String... expectedFailures)
+      throws Exception {
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      String died = tester.logger.died;
+      for (String expectedFailure : expectedFailures) {
+        assertTrue(died, died.contains(expectedFailure));
+      }
+    }
+  }
+
+  public void testGood_onlyWidget() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DisclosurePanel>");
+    b.append("  <g:Button/>");
+    b.append("</g:DisclosurePanel>");
+
+    tester.parse(b.toString());
+
+    assertStatements("fieldName.add(<g:Button>);");
+  }
+
+  public void testGood_withHeader() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DisclosurePanel>");
+    b.append("  <g:header>foo</g:header>");
+    b.append("  <g:Button/>");
+    b.append("</g:DisclosurePanel>");
+
+    FieldWriter w = tester.parse(b.toString());
+ assertEquals("new com.google.gwt.user.client.ui.DisclosurePanel(\"foo\")",
+        w.getInitializer());
+
+    assertStatements("fieldName.add(<g:Button>);");
+  }
+
+  public void testGood_withHeader_withImages() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DisclosurePanel>");
+ b.append(" <g:header openImage='{open}' closedImage='{closed}'>foo</g:header>");
+    b.append("  <g:Button/>");
+    b.append("</g:DisclosurePanel>");
+
+    FieldWriter w = tester.parse(b.toString());
+    assertEquals(
+ "new com.google.gwt.user.client.ui.DisclosurePanel(open, closed, \"foo\")",
+        w.getInitializer());
+
+    assertStatements("fieldName.add(<g:Button>);");
+  }
+
+  public void testGood_withCustomHeader() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DisclosurePanel>");
+    b.append("  <g:customHeader><g:Label>foo</g:Label></g:customHeader>");
+    b.append("  <g:Button/>");
+    b.append("</g:DisclosurePanel>");
+
+    FieldWriter w = tester.parse(b.toString());
+    assertEquals(null, w.getInitializer());
+
+    assertStatements("fieldName.add(<g:Button>);",
+        "fieldName.setHeader(<g:Label>);");
+  }
+
+  private void assertStatements(String... expected) {
+    Iterator<String> i = tester.writer.statements.iterator();
+    for (String e : expected) {
+      assertEquals(e, i.next());
+    }
+    assertFalse(i.hasNext());
+    assertNull(tester.logger.died);
+  }
+}
=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/uibinder/elementparsers/StackPanelParserTest.java Tue Aug 31 12:33:22 2010
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2010 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 junit.framework.TestCase;
+
+import java.util.Iterator;
+
+/**
+ * Test for {...@link StackPanelParser}.
+ */
+public class StackPanelParserTest extends TestCase {
+
+ private static final String PARSED_TYPE = "com.google.gwt.user.client.ui.StackPanel";
+
+  private ElementParserTester tester;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    tester = new ElementParserTester(PARSED_TYPE, new StackPanelParser());
+  }
+
+  public void testHappy_noStackText() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:StackPanel>");
+    b.append("  <g:Button/>");
+    b.append("</g:StackPanel>");
+
+    tester.parse(b.toString());
+
+    assertStatements("fieldName.add(<g:Button>);");
+  }
+
+  public void testHappy_hasStackText() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:StackPanel>");
+    b.append("  <g:Button g:StackPanel-text='Foo'/>");
+    b.append("</g:StackPanel>");
+
+    tester.parse(b.toString());
+
+    assertStatements("fieldName.add(<g:Button>, \"Foo\");");
+  }
+
+  private void assertStatements(String... expected) {
+    Iterator<String> i = tester.writer.statements.iterator();
+    for (String e : expected) {
+      assertEquals(e, i.next());
+    }
+    assertFalse(i.hasNext());
+    assertNull(tester.logger.died);
+  }
+}
=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/uibinder/elementparsers/TabPanelParserTest.java Tue Aug 31 12:33:22 2010
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2010 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 java.util.Iterator;
+
+/**
+ * Test for {...@link TabPanelParser}.
+ */
+public class TabPanelParserTest extends TestCase {
+
+ private static final String PARSED_TYPE = "com.google.gwt.user.client.ui.TabPanel";
+
+  private ElementParserTester tester;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    tester = new ElementParserTester(PARSED_TYPE, new TabPanelParser());
+  }
+
+  public void testBad_notTab() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabPanel>");
+    b.append("  <div/>");
+    b.append("</g:TabPanel>");
+
+    parseAndFail(b, "Only <g:Tab> children are allowed");
+  }
+
+  public void testBad_noWidget() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabPanel>");
+    b.append("  <g:Tab>");
+    b.append("  </g:Tab>");
+    b.append("</g:TabPanel>");
+
+    parseAndFail(b, "Must have a child widget");
+  }
+
+  public void testBad_notWidget() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabPanel>");
+    b.append("  <g:Tab>");
+    b.append("    <div/>");
+    b.append("  </g:Tab>");
+    b.append("</g:TabPanel>");
+
+    parseAndFail(b, "Must be a widget");
+  }
+
+  public void testBad_twoWidgets() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabPanel>");
+    b.append("  <g:Tab>");
+    b.append("    <g:Button/>");
+    b.append("    <g:Button/>");
+    b.append("  </g:Tab>");
+    b.append("</g:TabPanel>");
+
+    parseAndFail(b, "May only have a single child widget");
+  }
+
+  public void testBad_noHeader() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabPanel>");
+    b.append("  <g:Tab>");
+    b.append("    <g:Button/>");
+    b.append("  </g:Tab>");
+    b.append("</g:TabPanel>");
+
+    parseAndFail(b, "Requires either a \"text\" attribute or <g:TabHTML>");
+  }
+
+  public void testBad_twoHeaders() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabPanel>");
+    b.append("  <g:Tab text='Foo'>");
+    b.append("    <g:TabHTML>Bar</g:TabHTML>");
+    b.append("    <g:Button/>");
+    b.append("  </g:Tab>");
+    b.append("</g:TabPanel>");
+
+    parseAndFail(b, "May have only one \"text\" attribute or <g:TabHTML>");
+  }
+
+  public void testBad_twoCustomHeaders() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabPanel>");
+    b.append("  <g:Tab>");
+    b.append("    <g:TabHTML>Foo</g:TabHTML>");
+    b.append("    <g:TabHTML>Bar</g:TabHTML>");
+    b.append("    <g:Button/>");
+    b.append("  </g:Tab>");
+    b.append("</g:TabPanel>");
+
+    parseAndFail(b, "May have only one \"text\" attribute or <g:TabHTML>");
+  }
+
+  /**
+   * Parses bad code in given {...@link StringBuffer} and asserts that failure
+   * message has expected strings.
+   */
+  private void parseAndFail(StringBuffer b, String... expectedFailures)
+      throws Exception {
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      String died = tester.logger.died;
+      for (String expectedFailure : expectedFailures) {
+        assertTrue(died, died.contains(expectedFailure));
+      }
+    }
+  }
+
+  public void testHappy() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabPanel>");
+    b.append("  <g:Tab text='Foo'>");
+    b.append("    <g:Label id='0'/>");
+    b.append("  </g:Tab>");
+    b.append("  <g:Tab>");
+    b.append("    <g:TabHTML>B<b>a</b>r</g:TabHTML>");
+    b.append("    <g:Label id='1'/>");
+    b.append("  </g:Tab>");
+    b.append("</g:TabPanel>");
+
+    tester.parse(b.toString());
+
+    assertStatements("fieldName.add(<g:Label id='0'>, \"Foo\");",
+        "fieldName.add(<g:Label id='1'>, \"B<b>a</b>r\", true);");
+  }
+
+  private void assertStatements(String... expected) {
+    Iterator<String> i = tester.writer.statements.iterator();
+    for (String e : expected) {
+      assertEquals(e, i.next());
+    }
+    assertFalse(i.hasNext());
+    assertNull(tester.logger.died);
+  }
+}
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/DisclosurePanelParser.java Mon Jun 7 12:20:31 2010 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/DisclosurePanelParser.java Tue Aug 31 08:46:42 2010
@@ -41,16 +41,16 @@
       throws UnableToCompleteException {
     Children children = findChildren(panelElem, writer);

-    if (null != children.body) {
+    if (children.body != null) {
       if (!writer.isWidgetElement(children.body)) {
         writer.die(children.body, "Must be a widget");
       }

       String bodyField = writer.parseElementToField(children.body);
-      writer.addInitStatement("%s.add(%s);", panelField, bodyField);
+      writer.addStatement("%s.add(%s);", panelField, bodyField);
     }

-    if (null != children.customHeader) {
+    if (children.customHeader != null) {
XMLElement headerElement = children.customHeader.consumeSingleChildElement();

       if (!writer.isWidgetElement(headerElement)) {
@@ -58,16 +58,16 @@
       }

       String headerField = writer.parseElementToField(headerElement);
- writer.addInitStatement("%s.setHeader(%s);", panelField, headerField);
+      writer.addStatement("%s.setHeader(%s);", panelField, headerField);
     }

-    if (null != children.header) {
+    if (children.header != null) {
String openImage = children.header.consumeImageResourceAttribute(OPEN_IMAGE); String closedImage = children.header.consumeImageResourceAttribute(CLOSED_IMAGE); String headerText = children.header.consumeInnerTextEscapedAsHtmlStringLiteral(new TextInterpreter(
           writer));

-      if ((openImage == null) ^ (closedImage == null)) {
+      if (openImage == null ^ closedImage == null) {
         writer.die(children.header,
             "Both %s and %s must be specified, or neither", OPEN_IMAGE,
             CLOSED_IMAGE);
@@ -79,8 +79,8 @@
"new %s(%s, %s, \"%s\")", panelTypeName, openImage, closedImage,
             headerText));
       } else {
- writer.setFieldInitializer(panelField, String.format("new %s(\"%s\")",
-            panelTypeName, headerText));
+        writer.setFieldInitializer(panelField,
+            String.format("new %s(\"%s\")", panelTypeName, headerText));
       }
     }
   }
@@ -93,20 +93,20 @@
       public Boolean interpretElement(XMLElement child)
           throws UnableToCompleteException {

-        if (hasAttribute(child, HEADER)) {
+        if (hasTag(child, HEADER)) {
           assertFirstHeader();
           children.header = child;
           return true;
         }

-        if (hasAttribute(child, CUSTOM)) {
+        if (hasTag(child, CUSTOM)) {
           assertFirstHeader();
           children.customHeader = child;
           return true;
         }

         // Must be the body, then
-        if (null != children.body) {
+        if (children.body != null) {
           writer.die(elem, "May have only one body element");
         }

@@ -115,18 +115,15 @@
       }

       void assertFirstHeader() throws UnableToCompleteException {
-        if ((null != children.header) && (null != children.customHeader)) {
-          writer.die(elem, "May have only one %2$s:header "
-              + "or %2$s:customHeader", elem.getPrefix());
+        if (children.header != null || children.customHeader != null) {
+          writer.die(elem, "May have only one <%1$s:header> "
+              + "or <%1$s:customHeader>", elem.getPrefix());
         }
       }

- private boolean hasAttribute(XMLElement child, final String attribute) { - return rightNamespace(child) && child.getLocalName().equals(attribute);
-      }
-
-      private boolean rightNamespace(XMLElement child) {
-        return child.getNamespaceUri().equals(elem.getNamespaceUri());
+      private boolean hasTag(XMLElement child, String tag) {
+        return elem.getNamespaceUri().equals(child.getNamespaceUri())
+            && tag.equals(child.getLocalName());
       }
     });

=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParser.java Mon Jun 7 12:20:31 2010 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParser.java Tue Aug 31 08:46:42 2010
@@ -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
@@ -47,17 +47,16 @@
         unitEnumType);

     writer.setFieldInitializerAsConstructor(fieldName,
-        writer.getOracle().findType(StackLayoutPanel.class.getName()),
-        unit);
+ writer.getOracle().findType(StackLayoutPanel.class.getName()), unit);

     // Parse children.
     for (XMLElement stackElem : panelElem.consumeChildElements()) {
       // Get the stack element.
       if (!isElementType(panelElem, stackElem, STACK)) {
-        writer.die(stackElem, "Only <%s:%s> children are allowed.",
+        writer.die(stackElem, "Only <%s:%s> children are allowed.",
             panelElem.getPrefix(), STACK);
       }
-
+
       // Find all the children of the <stack>.
       Children children = findChildren(stackElem, writer);

@@ -79,8 +78,7 @@
         writer.addStatement("%s.add(%s, \"%s\", true, %s);", fieldName,
             childFieldName, html, size);
       } else if (children.customHeader != null) {
-        XMLElement headerElement =
-          children.customHeader.consumeSingleChildElement();
+ XMLElement headerElement = children.customHeader.consumeSingleChildElement(); String size = children.customHeader.consumeRequiredDoubleAttribute("size");
         if (!writer.isWidgetElement(headerElement)) {
           writer.die(headerElement, "Is not a widget");
@@ -97,53 +95,45 @@
     }
   }

-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;
+  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 (isElementType(elem, child, HEADER)) {
+          assertFirstHeader();
+          children.header = child;
+          return true;
+        }
+
+        if (isElementType(elem, child, CUSTOM)) {
+          assertFirstHeader();
+          children.customHeader = child;
+          return true;
+        }
+
+        // Must be the body, then
+        if (children.body != null) {
+          writer.die(children.body, "May have only one body element");
+        }
+
+        children.body = child;
         return true;
       }

-      // Must be the body, then
-      if (null != children.body) {
-        writer.die(children.body, "May have only one body element");
-      }
-
-      children.body = child;
-      return true;
-    }
-
-    void assertFirstHeader() throws UnableToCompleteException {
-      if ((null != children.header) && (null != children.customHeader)) {
-        writer.die(elem, "May have only one %2$s:header "
-            + "or %2$s:customHeader", 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;
-}
+      void assertFirstHeader() throws UnableToCompleteException {
+        if (children.header != null || children.customHeader != null) {
+          writer.die(elem, "May have only one <%1$s:header> "
+              + "or <%1$s:customHeader>", elem.getPrefix());
+        }
+      }
+    });
+
+    return children;
+  }

private boolean isElementType(XMLElement parent, XMLElement child, String type) {
     return parent.getNamespaceUri().equals(child.getNamespaceUri())
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParser.java Mon Jun 7 12:20:31 2010 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParser.java Tue Aug 31 08:46:42 2010
@@ -43,9 +43,6 @@
     // TabLayoutPanel requires tabBar size and unit ctor args.

     String size = panelElem.consumeRequiredDoubleAttribute("barHeight");
-    if ("".equals(size)) {
-      writer.die(panelElem, "barHeight attribute is required");
-    }

     JEnumType unitEnumType = writer.getOracle().findType(
         Unit.class.getCanonicalName()).isEnum();
@@ -84,8 +81,7 @@
         writer.addStatement("%s.add(%s, \"%s\", true);", fieldName,
             childFieldName, html);
       } else if (children.customHeader != null) {
-        XMLElement headerElement =
-          children.customHeader.consumeSingleChildElement();
+ XMLElement headerElement = children.customHeader.consumeSingleChildElement();

         if (!writer.isWidgetElement(headerElement)) {
           writer.die(headerElement, "Is not a widget");
@@ -110,20 +106,20 @@
       public Boolean interpretElement(XMLElement child)
           throws UnableToCompleteException {

-        if (hasTag(child, HEADER)) {
+        if (isElementType(elem, child, HEADER)) {
           assertFirstHeader();
           children.header = child;
           return true;
         }

-        if (hasTag(child, CUSTOM)) {
+        if (isElementType(elem, child, CUSTOM)) {
           assertFirstHeader();
           children.customHeader = child;
           return true;
         }

         // Must be the body, then
-        if (null != children.body) {
+        if (children.body != null) {
           writer.die(children.body, "May have only one body element");
         }

@@ -132,19 +128,11 @@
       }

       void assertFirstHeader() throws UnableToCompleteException {
-        if ((null != children.header) && (null != children.customHeader)) {
-          writer.die(elem, "May have only one %1$s:header "
-              + "or %1$s:customHeader", elem.getPrefix());
+        if (children.header != null || children.customHeader != null) {
+          writer.die(elem, "May have only one <%1$s:header> "
+              + "or <%1$s:customHeader>", 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;
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/elementparsers/TabPanelParser.java Mon Jun 7 12:20:31 2010 +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/TabPanelParser.java Tue Aug 31 08:46:42 2010
@@ -28,57 +28,65 @@
   private static final String TAG_TAB = "Tab";
   private static final String TAG_TABHTML = "TabHTML";

-  public void parse(XMLElement elem, String fieldName, JClassType type,
+ public void parse(XMLElement panelElem, String fieldName, JClassType type,
       UiBinderWriter writer) throws UnableToCompleteException {
-    writer.warn(elem,
+    writer.warn(panelElem,
         "%1$s:%2$s is deprecated. Use the %1$s:TabLayoutPanel instead.",
-        elem.getPrefix(), elem.getLocalName());
+        panelElem.getPrefix(), panelElem.getLocalName());
     // Parse children.
-    for (XMLElement child : elem.consumeChildElements()) {
+    for (XMLElement tabElem : panelElem.consumeChildElements()) {
       // TabPanel can only contain Tab elements.
-      String ns = child.getNamespaceUri();
-      String tagName = child.getLocalName();
-
-      if (!ns.equals(elem.getNamespaceUri())) {
-        writer.die(elem, "Invalid TabPanel child namespace: " + ns);
-      }
-      if (!tagName.equals(TAG_TAB)) {
-        writer.die(elem, "Invalid TabPanel child element: " + tagName);
+      if (!isElementType(panelElem, tabElem, TAG_TAB)) {
+        writer.die(tabElem, "Only <%s:%s> children are allowed.",
+            panelElem.getPrefix(), TAG_TAB);
       }

-      // Get the caption, if any.
-      String tabCaption = "";
-      if (child.hasAttribute("text")) {
-        tabCaption = child.consumeRawAttribute("text");
-      }
+      // Get the caption, or null if there is none
+      String tabCaption = tabElem.consumeStringAttribute("text");

       // Get the single required child widget.
       String tabHTML = null;
       String childFieldName = null;
-      for (XMLElement tabChild : child.consumeChildElements()) {
+      for (XMLElement tabChild : tabElem.consumeChildElements()) {
         if (tabChild.getLocalName().equals(TAG_TABHTML)) {
+          if (tabCaption != null || tabHTML != null) {
+            writer.die(tabElem,
+                "May have only one \"text\" attribute or <%1$s:%2$s>",
+                tabElem.getPrefix(), TAG_TABHTML);
+          }
HtmlInterpreter interpreter = HtmlInterpreter.newInterpreterForUiObject(
               writer, fieldName);
           tabHTML = tabChild.consumeInnerHtml(interpreter);
         } else {
           if (childFieldName != null) {
- writer.die(elem, "%s may only have a single child widget", child);
+            writer.die(tabChild, "May only have a single child widget");
+          }
+          if (!writer.isWidgetElement(tabChild)) {
+            writer.die(tabChild, "Must be a widget");
           }
           childFieldName = writer.parseElementToField(tabChild);
         }
       }

       if (childFieldName == null) {
-        writer.die(elem, "%s must have a child widget", child);
-      }
-
+        writer.die(tabElem, "Must have a child widget");
+      }
       if (tabHTML != null) {
         writer.addStatement("%1$s.add(%2$s, \"%3$s\", true);", fieldName,
             childFieldName, tabHTML);
+      } else if (tabCaption != null) {
+ writer.addStatement("%1$s.add(%2$s, %3$s);", fieldName, childFieldName,
+            tabCaption);
       } else {
-        writer.addStatement("%1$s.add(%2$s, \"%3$s\");", fieldName,
-            childFieldName, tabCaption);
+        writer.die(tabElem,
+            "Requires either a \"text\" attribute or <%1$s:%2$s>",
+            tabElem.getPrefix(), TAG_TABHTML);
       }
     }
   }
-}
+
+ private boolean isElementType(XMLElement parent, XMLElement child, String type) {
+    return parent.getNamespaceUri().equals(child.getNamespaceUri())
+        && type.equals(child.getLocalName());
+  }
+}
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java Mon Aug 2 18:45:49 2010 +++ /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java Tue Aug 31 08:46:42 2010
@@ -27,6 +27,7 @@
import com.google.gwt.uibinder.attributeparsers.VerticalAlignmentConstantParserTest;
 import com.google.gwt.uibinder.elementparsers.AbsolutePanelParserTest;
 import com.google.gwt.uibinder.elementparsers.DialogBoxParserTest;
+import com.google.gwt.uibinder.elementparsers.DisclosurePanelParserTest;
 import com.google.gwt.uibinder.elementparsers.DockLayoutPanelParserTest;
 import com.google.gwt.uibinder.elementparsers.GridParserTest;
 import com.google.gwt.uibinder.elementparsers.ImageParserTest;
@@ -36,7 +37,9 @@
 import com.google.gwt.uibinder.elementparsers.MenuBarParserTest;
 import com.google.gwt.uibinder.elementparsers.MenuItemParserTest;
 import com.google.gwt.uibinder.elementparsers.StackLayoutPanelParserTest;
+import com.google.gwt.uibinder.elementparsers.StackPanelParserTest;
 import com.google.gwt.uibinder.elementparsers.TabLayoutPanelParserTest;
+import com.google.gwt.uibinder.elementparsers.TabPanelParserTest;
 import com.google.gwt.uibinder.elementparsers.UIObjectParserTest;
 import com.google.gwt.uibinder.rebind.DesignTimeUtilsTest;
import com.google.gwt.uibinder.rebind.FieldWriterOfGeneratedCssResourceTest;
@@ -86,6 +89,7 @@
     // elementparsers
     suite.addTestSuite(AbsolutePanelParserTest.class);
     suite.addTestSuite(DialogBoxParserTest.class);
+    suite.addTestSuite(DisclosurePanelParserTest.class);
     suite.addTestSuite(DockLayoutPanelParserTest.class);
     suite.addTestSuite(GridParserTest.class);
     suite.addTestSuite(ImageParserTest.class);
@@ -95,7 +99,9 @@
     suite.addTestSuite(MenuBarParserTest.class);
     suite.addTestSuite(MenuItemParserTest.class);
     suite.addTestSuite(StackLayoutPanelParserTest.class);
+    suite.addTestSuite(StackPanelParserTest.class);
     suite.addTestSuite(TabLayoutPanelParserTest.class);
+    suite.addTestSuite(TabPanelParserTest.class);
     suite.addTestSuite(UIObjectParserTest.class);

     return suite;
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParserTest.java Mon Jun 7 12:20:31 2010 +++ /trunk/user/test/com/google/gwt/uibinder/elementparsers/StackLayoutPanelParserTest.java Tue Aug 31 08:46:42 2010
@@ -20,13 +20,10 @@

 import junit.framework.TestCase;

-import org.xml.sax.SAXException;
-
-import java.io.IOException;
 import java.util.Iterator;

 /**
- * A unit test. Guess what of.
+ * Test for {...@link StackLayoutPanelParser}.
  */
 public class StackLayoutPanelParserTest extends TestCase {

@@ -40,23 +37,115 @@
tester = new ElementParserTester(PARSED_TYPE, new StackLayoutPanelParser());
   }

-  public void testBadChild() throws SAXException, IOException {
+  public void testBad_notStack() throws Exception {
     StringBuffer b = new StringBuffer();
     b.append("<g:StackLayoutPanel unit='EM'>");
-    b.append("  <g:west><foo/></g:west>");
+    b.append("  <div/>");
     b.append("</g:StackLayoutPanel>");

+    parseAndFail(b, "Only <g:stack> children are allowed");
+  }
+
+  public void testBad_noWidget() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:StackLayoutPanel unit='EM'>");
+    b.append("  <g:stack>");
+    b.append("  </g:stack>");
+    b.append("</g:StackLayoutPanel>");
+
+    parseAndFail(b, "Must have a child widget");
+  }
+
+  public void testBad_notWidget() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:StackLayoutPanel unit='EM'>");
+    b.append("  <g:stack>");
+    b.append("    <div/>");
+    b.append("  </g:stack>");
+    b.append("</g:StackLayoutPanel>");
+
+    parseAndFail(b, "Must be a widget");
+  }
+
+  public void testBad_twoWidgets() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:StackLayoutPanel unit='EM'>");
+    b.append("  <g:stack>");
+    b.append("    <g:Button/>");
+    b.append("    <g:Button/>");
+    b.append("  </g:stack>");
+    b.append("</g:StackLayoutPanel>");
+
+    parseAndFail(b, "May have only one body element");
+  }
+
+  public void testBad_noHeader() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:StackLayoutPanel unit='EM'>");
+    b.append("  <g:stack>");
+    b.append("    <g:Button/>");
+    b.append("  </g:stack>");
+    b.append("</g:StackLayoutPanel>");
+
+    parseAndFail(b, "Requires either a <g:header> or <g:customHeader>");
+  }
+
+  public void testBad_twoHeaders() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:StackLayoutPanel unit='EM'>");
+    b.append("  <g:stack>");
+    b.append("    <g:header size='3'>foo</g:header>");
+    b.append("    <g:header size='3'>bar</g:header>");
+    b.append("    <g:Button/>");
+    b.append("  </g:stack>");
+    b.append("</g:StackLayoutPanel>");
+
+    parseAndFail(b, "May have only one <g:header> or <g:customHeader>");
+  }
+
+  public void testBad_twoCustomHeaders() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:StackLayoutPanel unit='EM'>");
+    b.append("  <g:stack>");
+ b.append(" <g:customHeader size='3'><g:Label>111</g:Label></g:customHeader>"); + b.append(" <g:customHeader size='3'><g:Label>222</g:Label></g:customHeader>");
+    b.append("    <g:Button/>");
+    b.append("  </g:stack>");
+    b.append("</g:StackLayoutPanel>");
+
+    parseAndFail(b, "May have only one <g:header> or <g:customHeader>");
+  }
+
+  public void testBad_withCustomHeader_notWidget() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:StackLayoutPanel unit='EM'>");
+    b.append("  <g:stack>");
+    b.append("    <g:customHeader size='3'><div/></g:customHeader>");
+    b.append("    <g:Button/>");
+    b.append("  </g:stack>");
+    b.append("</g:StackLayoutPanel>");
+
+    parseAndFail(b, "Is not a widget", "<div>");
+  }
+
+  /**
+   * Parses bad code in given {...@link StringBuffer} and asserts that failure
+   * message has expected strings.
+   */
+  private void parseAndFail(StringBuffer b, String... expectedFailures)
+      throws Exception {
     try {
       tester.parse(b.toString());
       fail();
     } catch (UnableToCompleteException e) {
-      assertTrue("expect \"Only g:stack\" error",
-          tester.logger.died.contains("Only <g:stack> children"));
+      String died = tester.logger.died;
+      for (String expectedFailure : expectedFailures) {
+        assertTrue(died, died.contains(expectedFailure));
+      }
     }
   }

-  public void testHappy() throws UnableToCompleteException, SAXException,
-      IOException {
+  public void testHappy() throws Exception {
     StringBuffer b = new StringBuffer();
     b.append("<g:StackLayoutPanel unit='PX'>");
     b.append("  <g:stack>");
@@ -71,24 +160,16 @@
     b.append("  </g:stack>");
     b.append("</g:StackLayoutPanel>");

-    String[] expected = {
- "fieldName.add(<g:Label id='able'>, \"Re<b>mark</b>able\", true, 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);
+    assertStatements(
+ "fieldName.add(<g:Label id='able'>, \"Re<b>mark</b>able\", true, 3);", + "fieldName.add(<g:Label id='baker'>, " + "<g:Label id='custom'>, 3);");
   }

-  public void testNoUnits() throws SAXException, IOException,
-      UnableToCompleteException {
+  public void testNoUnits() throws Exception {
     StringBuffer b = new StringBuffer();
     b.append("  <g:StackLayoutPanel>");
     b.append("  </g:StackLayoutPanel>");
@@ -97,7 +178,15 @@
     assertEquals("new " + PARSED_TYPE
         + "(com.google.gwt.dom.client.Style.Unit.PX)", w.getInitializer());

+    assertStatements();
+  }
+
+  private void assertStatements(String... expected) {
     Iterator<String> i = tester.writer.statements.iterator();
+    for (String e : expected) {
+      assertEquals(e, i.next());
+    }
     assertFalse(i.hasNext());
+    assertNull(tester.logger.died);
   }
 }
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParserTest.java Tue Nov 10 12:33:30 2009 +++ /trunk/user/test/com/google/gwt/uibinder/elementparsers/TabLayoutPanelParserTest.java Tue Aug 31 08:46:42 2010
@@ -20,13 +20,10 @@

 import junit.framework.TestCase;

-import org.xml.sax.SAXException;
-
-import java.io.IOException;
 import java.util.Iterator;

 /**
- * A unit test. Guess what of.
+ * Test for {...@link TabLayoutPanelParser}.
  */
 public class TabLayoutPanelParserTest extends TestCase {

@@ -40,22 +37,122 @@
tester = new ElementParserTester(PARSED_TYPE, new TabLayoutPanelParser());
   }

-  public void testBadChild() throws SAXException, IOException {
+  public void testBad_noBarHeight() throws Exception {
     StringBuffer b = new StringBuffer();
-    b.append("<g:TabLayoutPanel unit='EM'>");
-    b.append("  <g:west><foo/></g:west>");
+    b.append("<g:TabLayoutPanel/>");
+
+    parseAndFail(b, "Missing required attribute", "barHeight");
+  }
+
+  public void testBad_notTab() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabLayoutPanel barHeight='2'>");
+    b.append("  <div/>");
     b.append("</g:TabLayoutPanel>");

+    parseAndFail(b, "Only <g:tab> children are allowed");
+  }
+
+  public void testBad_noWidget() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabLayoutPanel barHeight='2'>");
+    b.append("  <g:tab>");
+    b.append("  </g:tab>");
+    b.append("</g:TabLayoutPanel>");
+
+    parseAndFail(b, "Must have a child widget");
+  }
+
+  public void testBad_notWidget() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabLayoutPanel barHeight='2'>");
+    b.append("  <g:tab>");
+    b.append("    <div/>");
+    b.append("  </g:tab>");
+    b.append("</g:TabLayoutPanel>");
+
+    parseAndFail(b, "Must be a widget");
+  }
+
+  public void testBad_twoWidgets() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabLayoutPanel barHeight='2'>");
+    b.append("  <g:tab>");
+    b.append("    <g:Button/>");
+    b.append("    <g:Button/>");
+    b.append("  </g:tab>");
+    b.append("</g:TabLayoutPanel>");
+
+    parseAndFail(b, "May have only one body element");
+  }
+
+  public void testBad_noHeader() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabLayoutPanel barHeight='2'>");
+    b.append("  <g:tab>");
+    b.append("    <g:Button/>");
+    b.append("  </g:tab>");
+    b.append("</g:TabLayoutPanel>");
+
+    parseAndFail(b, "Requires either a <g:header> or <g:customHeader>");
+  }
+
+  public void testBad_twoHeaders() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabLayoutPanel barHeight='2'>");
+    b.append("  <g:tab>");
+    b.append("    <g:header size='3'>foo</g:header>");
+    b.append("    <g:header size='3'>bar</g:header>");
+    b.append("    <g:Button/>");
+    b.append("  </g:tab>");
+    b.append("</g:TabLayoutPanel>");
+
+    parseAndFail(b, "May have only one <g:header> or <g:customHeader>");
+  }
+
+  public void testBad_twoCustomHeaders() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabLayoutPanel barHeight='2'>");
+    b.append("  <g:tab>");
+ b.append(" <g:customHeader size='3'><g:Label>foo</g:Label></g:customHeader>"); + b.append(" <g:customHeader size='3'><g:Label>bar</g:Label></g:customHeader>");
+    b.append("    <g:Button/>");
+    b.append("  </g:tab>");
+    b.append("</g:TabLayoutPanel>");
+
+    parseAndFail(b, "May have only one <g:header> or <g:customHeader>");
+  }
+
+  public void testBad_customHeader_notWidget() throws Exception {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:TabLayoutPanel barHeight='2'>");
+    b.append("  <g:tab>");
+    b.append("    <g:customHeader size='3'><div/></g:customHeader>");
+    b.append("    <g:Button/>");
+    b.append("  </g:tab>");
+    b.append("</g:TabLayoutPanel>");
+
+    parseAndFail(b, "Is not a widget", "<div>");
+  }
+
+  /**
+   * Parses bad code in given {...@link StringBuffer} and asserts that failure
+   * message has expected strings.
+   */
+  private void parseAndFail(StringBuffer b, String... expectedFailures)
+      throws Exception {
     try {
       tester.parse(b.toString());
       fail();
     } catch (UnableToCompleteException e) {
-      assertNotNull(tester.logger.died);
+      String died = tester.logger.died;
+      for (String expectedFailure : expectedFailures) {
+        assertTrue(died, died.contains(expectedFailure));
+      }
     }
   }

-  public void testHappy() throws UnableToCompleteException, SAXException,
-      IOException {
+  public void testHappy() throws Exception {
     StringBuffer b = new StringBuffer();
     b.append("<g:TabLayoutPanel barUnit='PX' barHeight='30'>");
     b.append("  <g:tab>");
@@ -86,8 +183,7 @@
     assertNull(tester.logger.died);
   }

-  public void testNoUnits() throws SAXException, IOException,
-      UnableToCompleteException {
+  public void testNoUnits() throws Exception {
     StringBuffer b = new StringBuffer();
     b.append("<g:TabLayoutPanel barHeight='3'>");
     b.append("  </g:TabLayoutPanel>");
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/test/UiJavaResources.java Mon Aug 2 18:45:49 2010 +++ /trunk/user/test/com/google/gwt/uibinder/test/UiJavaResources.java Tue Aug 31 08:46:42 2010
@@ -106,6 +106,17 @@
       code.append("}\n");
       return code;
     }
+  };
+ public static final MockJavaResource DISCLOSURE_PANEL = new MockJavaResource(
+      "com.google.gwt.user.client.ui.DisclosurePanel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("public class DisclosurePanel extends Widget {\n");
+      code.append("}\n");
+      return code;
+    }
   };
public static final MockJavaResource DOCK_LAYOUT_PANEL = new MockJavaResource(
       "com.google.gwt.user.client.ui.DockLayoutPanel") {
@@ -362,6 +373,17 @@
       code.append("}\n");
       return code;
     }
+  };
+  public static final MockJavaResource STACK_PANEL = new MockJavaResource(
+      "com.google.gwt.user.client.ui.StackPanel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("public class StackPanel extends Widget {\n");
+      code.append("}\n");
+      return code;
+    }
   };
   public static final MockJavaResource STYLE = new MockJavaResource(
       "com.google.gwt.dom.client.Style") {
@@ -385,6 +407,17 @@
       code.append("}\n");
       return code;
     }
+  };
+  public static final MockJavaResource TAB_PANEL = new MockJavaResource(
+      "com.google.gwt.user.client.ui.TabPanel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("public class TabPanel extends Widget {\n");
+      code.append("}\n");
+      return code;
+    }
   };
public static final MockJavaResource TEXT_BOX_BASE = new MockJavaResource(
       "com.google.gwt.user.client.ui.TextBoxBase") {
@@ -459,6 +492,7 @@
     rtn.add(CLICK_HANDLER);
     rtn.add(COMMAND);
     rtn.add(DIALOG_BOX);
+    rtn.add(DISCLOSURE_PANEL);
     rtn.add(DOCK_LAYOUT_PANEL);
     rtn.add(ELEMENT);
     rtn.add(EVENT_HANDLER);
@@ -480,8 +514,10 @@
     rtn.add(MOUSE_OVER_HANDLER);
     rtn.add(SPLIT_LAYOUT_PANEL);
     rtn.add(STACK_LAYOUT_PANEL);
+    rtn.add(STACK_PANEL);
     rtn.add(STYLE);
     rtn.add(TAB_LAYOUT_PANEL);
+    rtn.add(TAB_PANEL);
     rtn.add(TEXT_BOX_BASE);
     rtn.add(UI_OBJECT);
     rtn.add(UI_BINDER);

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

Reply via email to