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;">
- <ui:UiBinder
- xmlns:ui='urn:ui:com.google.gwt.uibinder'
- xmlns:gwt='urn:import:com.google.gwt.user.client.ui'>
-
- <gwt:FlowPanel>
- <gwt:Label ui:field="lblDebugId" debugId="joe"
- addStyleNames="newStyle anotherStyle"
- addStyleDependentNames="dependentStyle anotherDependentStyle"
- text="a label with debug id" />
-
- <!-- A button that only adds a single style name, no comma's needed -->
- <gwt:Button ui:field="btnGo" debugId="myButton"
- addStyleNames="buttonStyle" text="a button with extra attributes" />
- </gwt:FlowPanel>
-
- </ui:UiBinder></pre>
-
- <b>HTML:</b>
- <pre style="border: 1px dashed #666; padding: 5px 0;">
- <div id="gwt-debug-joe"
- class="gwt-Label newStyle anotherStyle gwt-Label-dependentStyle
- gwt-Label-anotherDependentStyle">
- A label with a debug id
- </div>
- <button id="gwt-debug-myButton" class="gwt-Button buttonStyle" tabindex="0"
- type="button">Go</button></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;">
- <ui:UiBinder
- xmlns:ui='urn:ui:com.google.gwt.uibinder'
- xmlns:gwt='urn:import:com.google.gwt.user.client.ui'>
-
- <gwt:FlowPanel>
- <gwt:Label ui:field="label" text="Looking for happiness?" />
- <gwt:Button ui:field="button" text="Click here to happiness!!" />
- <gwt:TextBox ui:field="textbox" />
- </gwt:FlowPanel>
-
- </ui:UiBinder></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<FlowPanel, HandlerDemo> {}
- 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<String> 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">