Fixes issue 4435, Inconsistent behavior of setStyleName(), setPrimaryStyleName()
and addStyleName() on new layout widgets.

While we're at it, replace the RadioButtonParser with a @UiConstructor
declaration on the widget. Less code is less code.

http://code.google.com/p/google-web-toolkit/issues/detail?id=4435

Reviewe by jgw
http://gwt-code-reviews.appspot.com/130810

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7409 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java b/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java
index 8df9166..9ff7aeb 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/BeanParser.java
@@ -148,7 +148,7 @@
 
     if (!unfilledRequiredParams.isEmpty()) {
       StringBuilder b = new StringBuilder(String.format(
-          "%s missing required arguments:", elem));
+          "%s missing required attribute(s):", elem));
       for (String name : unfilledRequiredParams.keySet()) {
         b.append(" ").append(name);
       }
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/RadioButtonParser.java b/user/src/com/google/gwt/uibinder/elementparsers/RadioButtonParser.java
deleted file mode 100644
index c879dd1..0000000
--- a/user/src/com/google/gwt/uibinder/elementparsers/RadioButtonParser.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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;
-import com.google.gwt.user.client.ui.RadioButton;
-
-/**
- * Parses {@link RadioButton} widgets.
- */
-public class RadioButtonParser implements ElementParser {
-
-  public void parse(XMLElement elem, String fieldName, JClassType type,
-      UiBinderWriter writer) throws UnableToCompleteException {
-    if (!elem.hasAttribute("name")) {
-      writer.die("RadioButton requires a 'name' attribute: " + elem);
-    }
-
-    if (type.equals(writer.getOracle().findType(RadioButton.class.getName()))) {
-      writer.setFieldInitializerAsConstructor(fieldName, type,
-          elem.consumeStringAttribute("name"));
-    }
-  }
-}
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/UIObjectParser.java b/user/src/com/google/gwt/uibinder/elementparsers/UIObjectParser.java
index 74568b0..e4cc7de 100644
--- a/user/src/com/google/gwt/uibinder/elementparsers/UIObjectParser.java
+++ b/user/src/com/google/gwt/uibinder/elementparsers/UIObjectParser.java
@@ -21,8 +21,10 @@
 import com.google.gwt.uibinder.rebind.XMLElement;
 
 /**
- * Parser of all UIObject types. Basically bats cleanup if more specialized
- * parsers have left things around, or haven't been run.
+ * Parser of all UIObject types. Provides parsing of debugId,
+ * addStyleNames, addStyleDependentNames. Also handles
+ * other setStyle* calls to ensure they happen before the addStyle* 
+ * calls. 
  */
 public class UIObjectParser implements ElementParser {
 
@@ -33,14 +35,29 @@
     if (null != debugId) {
       writer.addStatement("%s.ensureDebugId(%s);", fieldName, debugId);
     }
+    
+    String styleName = elem.consumeStringAttribute("styleName", null);
+    String stylePrimaryName = elem.consumeStringAttribute("stylePrimaryName", null);
 
-    String[] styleNames = elem.consumeStringArrayAttribute("addStyleNames");
-    for (String s : styleNames) {
+    if (null != styleName && null != stylePrimaryName) {
+      writer.die("In %s, cannot set both \"styleName\" "
+          + "and \"stylePrimaryName\"", elem);
+    }
+    
+    if (null != styleName) {
+      writer.addStatement("%s.setStyleName(%s);", fieldName, styleName);
+    }
+    if (null != stylePrimaryName) {
+      writer.addStatement("%s.setStylePrimaryName(%s);", fieldName, stylePrimaryName);
+    }
+
+    String[] extraStyleNames = elem.consumeStringArrayAttribute("addStyleNames");
+    for (String s : extraStyleNames) {
       writer.addStatement("%s.addStyleName(%s);", fieldName, s);
     }
 
-    styleNames = elem.consumeStringArrayAttribute("addStyleDependentNames");
-    for (String s : styleNames) {
+    extraStyleNames = elem.consumeStringArrayAttribute("addStyleDependentNames");
+    for (String s : extraStyleNames) {
       writer.addStatement("%s.addStyleDependentName(%s);", fieldName, s);
     }
   }
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
index c538ec0..7cdc2b7 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
@@ -937,7 +937,6 @@
     addWidgetParser("TabPanel");
     addWidgetParser("MenuItem");
     addWidgetParser("MenuBar");
-    addWidgetParser("RadioButton");
     addWidgetParser("CellPanel");
     addWidgetParser("CustomButton");
     addWidgetParser("DialogBox");
diff --git a/user/src/com/google/gwt/user/client/ui/RadioButton.java b/user/src/com/google/gwt/user/client/ui/RadioButton.java
index 077463b..bd10087 100644
--- a/user/src/com/google/gwt/user/client/ui/RadioButton.java
+++ b/user/src/com/google/gwt/user/client/ui/RadioButton.java
@@ -18,6 +18,7 @@
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.EventTarget;
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.uibinder.client.UiConstructor;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Event;
 
@@ -57,6 +58,7 @@
    * 
    * @param name the group name with which to associate the radio button
    */
+  @UiConstructor
   public RadioButton(String name) {
     super(DOM.createInputRadio(name));
     setStyleName("gwt-RadioButton");
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/UIObjectParserTest.java b/user/test/com/google/gwt/uibinder/elementparsers/UIObjectParserTest.java
index d709045..ce24258 100644
--- a/user/test/com/google/gwt/uibinder/elementparsers/UIObjectParserTest.java
+++ b/user/test/com/google/gwt/uibinder/elementparsers/UIObjectParserTest.java
@@ -41,12 +41,14 @@
   public void testHappy() throws UnableToCompleteException, SAXException,
       IOException {
     StringBuffer b = new StringBuffer();
-    b.append("<g:UIObject debugId='blat' addStyleNames='foo, bar baz'");
+    b.append("<g:UIObject debugId='blat' styleName='primary' "
+        + "addStyleNames='foo, bar baz'");
     b.append("    addStyleDependentNames='able, baker charlie' >");
     b.append("</g:UIObject>");
 
     String[] expected = {
         "fieldName.ensureDebugId(\"blat\");",
+        "fieldName.setStyleName(\"primary\");",
         "fieldName.addStyleName(\"foo\");", "fieldName.addStyleName(\"bar\");",
         "fieldName.addStyleName(\"baz\");",
         "fieldName.addStyleDependentName(\"able\");",
@@ -62,4 +64,36 @@
     assertFalse(i.hasNext());
     assertNull(tester.logger.died);
   }
+
+  public void testSetPrimary() throws UnableToCompleteException, SAXException,
+      IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:UIObject stylePrimaryName='primary' >");
+    b.append("</g:UIObject>");
+
+    String[] expected = {"fieldName.setStylePrimaryName(\"primary\");",};
+
+    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);
+  }
+
+  public void testStyleConflict() throws SAXException, IOException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:UIObject stylePrimaryName='primary' styleName='otherPrimary'>");
+    b.append("</g:UIObject>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue("Expect to hear about bad styleName usage",
+          tester.logger.died.contains("\"styleName\" and \"stylePrimaryName\""));
+    }
+  }
 }
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
index 791a9b4..1072cc3 100644
--- a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
+++ b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
@@ -66,6 +66,7 @@
 
   @Override
   public void gwtTearDown() throws Exception {
+    domUi.root.getParentElement().removeChild(domUi.root);
     RootPanel.get().clear();
     super.gwtTearDown();
   }
@@ -103,12 +104,14 @@
     Label l = widgetUi.lblDebugId;
     assertEquals("gwt-debug-joe", l.getElement().getId());
 
+    assertEquals("styleName", l.getStylePrimaryName());
+    
     WidgetBasedUiExternalResources resources = GWT.create(WidgetBasedUiExternalResources.class);
     assertTrue(l.getStyleName().contains("newStyle"));
     assertTrue(l.getStyleName().contains("anotherStyle"));
-    assertTrue(l.getStyleName().contains("dependentStyle"));
-    assertTrue(l.getStyleName().contains("anotherDependentStyle"));
-    assertTrue(l.getStyleName().contains(resources.style().prettyText()));
+    assertTrue(l.getStyleName().contains("styleName-dependentStyle"));
+    assertTrue(l.getStyleName().contains("styleName-anotherDependentStyle"));
+    assertTrue(l.getStyleName().contains("styleName-" + resources.style().prettyText()));
   }
 
   // TODO(rjrjr) The direction stuff in these tests really belongs in
diff --git a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
index 285e3bc..47e9f74 100644
--- a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
+++ b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
@@ -539,49 +539,9 @@
       <gwt:Label>body</gwt:Label>
     </demo:FooDialog>
 
-    <h2>How to use the debugId, addStyleNames, addDependentStyleNames attributes</h2>
-    <p>You can use the <strong>debugId</strong>, <strong>addStyleNames</strong>, and <strong>addDependentStyleNames</strong>
-       attributes on any widget that extends UIObject.
-       <ul>
-         <li><b>debugId</b> will set an <em>id</em> on the element prefixed with <em>gwt-debug</em></li>
-         <li><b>addStyleNames</b> (comma separated) will add all class names to the existing style (space separated)</li>
-         <li><b>addDependentStyleNames</b> (comma separated) will concatenate all class names to the existing style with a "-" as a separator</li>
-       </ul>
-       You can/should use FireBug or a simple view source to see the attributes that were created.
-       <br />
-    </p>
-
-    <b>Template:</b>
-    <pre style="border: 1px dashed #666; padding: 5px 0;">
-  &lt;ui:UiBinder
-    xmlns:ui='urn:ui:com.google.gwt.uibinder'
-    xmlns:gwt='urn:import:com.google.gwt.user.client.ui'&gt;
-
-    &lt;gwt:FlowPanel&gt;
-      &lt;gwt:Label ui:field="lblDebugId" debugId="joe" 
-          addStyleNames="newStyle anotherStyle" 
-          addStyleDependentNames="dependentStyle anotherDependentStyle" 
-          text="a label with debug id" /&gt;
-
-      &lt;!-- A button that only adds a single style name, no comma's needed --&gt;
-      &lt;gwt:Button ui:field="btnGo" debugId="myButton" 
-          addStyleNames="buttonStyle" text="a button with extra attributes" /&gt;
-    &lt;/gwt:FlowPanel>
-
-  &lt;/ui:UiBinder&gt;</pre>
-
-    <b>HTML:</b>
-    <pre style="border: 1px dashed #666; padding: 5px 0;">
-  &lt;div id="gwt-debug-joe" 
-      class="gwt-Label newStyle anotherStyle gwt-Label-dependentStyle 
-        gwt-Label-anotherDependentStyle"&gt;
-    A label with a debug id
-  &lt;/div&gt;
-  &lt;button id="gwt-debug-myButton" class="gwt-Button buttonStyle" tabindex="0" 
-    type="button"&gt;Go&lt;/button&gt;</pre>
-
     <gwt:FlowPanel>
       <gwt:Label ui:field="lblDebugId" debugId="joe" 
+          styleName="styleName"
           addStyleNames="newStyle, anotherStyle {external.style.prettyText}" 
           addStyleDependentNames="dependentStyle anotherDependentStyle, {external.style.prettyText}">
         A label with a debug id
@@ -589,68 +549,8 @@
       <gwt:Button ui:field="btnGo" debugId="myButton" addStyleNames="buttonStyle">Go</gwt:Button>
     </gwt:FlowPanel>
 
-    <h2>How to tie handlers automatically!!</h2>
-    <p>You can add event handlers to template widgets as long as they have
-      valid ui:field attributes. If the template is shared, each widget can
-      register listeners for the events it's interested in. In the example
-      below, we listen to MouseOver events on the status label and clicks
-      on the button.</p>
-
     <demo:HandlerDemo />
 
-    <b>Template:</b>
-    <pre style="border: 1px dashed #666; padding: 5px 0;">
-  &lt;ui:UiBinder
-    xmlns:ui='urn:ui:com.google.gwt.uibinder'
-    xmlns:gwt='urn:import:com.google.gwt.user.client.ui'&gt;
-
-    &lt;gwt:FlowPanel&gt;
-      &lt;gwt:Label ui:field="label" text="Looking for happiness?" /&gt;
-      &lt;gwt:Button ui:field="button" text="Click here to happiness!!" /&gt;
-      &lt;gwt:TextBox ui:field="textbox" /&gt;
-    &lt;/gwt:FlowPanel>
-
-  &lt;/ui:UiBinder&gt;</pre>
-
-  <b>The code:</b>
-  <pre style="border: 1px dashed #666; padding: 5px 0;">
-  public class HandlerDemo extends Composite {
-
-    @UiTemplate("HandlerDemo.ui.xml")
-    interface MyUiBinder extends UiBinder&lt;FlowPanel, HandlerDemo&gt; {}
-    private static final MyUiBinder binder = GWT.create(MyUiBinder.class);
-
-    @UiField Label label;
-
-    // No need of declare button here via @UiField if it is not really used
-    // in the class. Just don't forget to "ui:field" it in the template.
-
-    private int counter;
-
-    public HandlerDemo() {
-      initWidget(binder.createAndBindUi(this));
-    }
-
-    @UiHandler({"label", "button"})
-    protected void doClick(ClickEvent event) {
-      Window.alert("Yes, now I'm happy!");
-      counter = 0;
-      label.setText("Don't mouse over, click me!!!");
-    }
-
-    @UiHandler("button")
-    protected void doMouseOver(MouseOverEvent event) {
-      ++counter;
-      label.setText(counter + ". Don't mouse over, click me!");
-    }
-
-    @UiHandler("textbox")
-    protected void doChangeValue(ValueChangeEvent&lt;String&gt; event) {
-      label.setText("Typing = " + event.getValue());
-    }
-  }</pre>
-
-
   <h2>People write the darndest markup</h2>
   <table border="1" bcolor="yellow" cellpadding="3" ui:field="widgetCrazyTable">
     <demo:ExplicitElementPanel tag="thead">