Added style getters to UiRenderers
Now UiRendered templates with <ui:style>s can be retrieved with a getter.
Review at http://gwt-code-reviews.appspot.com/1700803
Review by: rdayal@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@11028 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
index 63241fa..fd6347c 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
@@ -1132,6 +1132,18 @@
}
/**
+ * Add call to {@code com.google.gwt.resources.client.CssResource#ensureInjected()}
+ * on each CSS resource field.
+ */
+ private void ensureInjectedCssFields() {
+ for (ImplicitCssResource css : bundleClass.getCssMethods()) {
+ String fieldName = css.getName();
+ FieldWriter cssField = fieldManager.require(fieldName);
+ cssField.addStatement("%s.ensureInjected();", fieldName);
+ }
+ }
+
+ /**
* Evaluate whether all @UiField attributes are also defined in the template.
* Dies if not.
*/
@@ -1364,13 +1376,10 @@
IndentedWriter niceWriter = new IndentedWriter(new PrintWriter(stringWriter));
if (isRenderer) {
+ ensureInjectedCssFields();
writeRenderer(niceWriter, rootField);
} else if (useLazyWidgetBuilders) {
- for (ImplicitCssResource css : bundleClass.getCssMethods()) {
- String fieldName = css.getName();
- FieldWriter cssField = fieldManager.require(fieldName);
- cssField.addStatement("%s.ensureInjected();", fieldName);
- }
+ ensureInjectedCssFields();
writeBinderForRenderableStrategy(niceWriter, rootField);
} else {
writeBinder(niceWriter, rootField);
@@ -1558,32 +1567,43 @@
/**
* Scan the base class for the getter methods. Assumes getters begin with
* "get" and validates that each corresponds to a field declared with
- * {@code ui:field}, it has a single parameter, the parameter type is
- * assignable to {@code Element} and its return type is assignable to
- * {@code Element}.
+ * {@code ui:field}. If the getter return type is assignable to
+ * {@code Element}, the getter must have a single parameter and the parameter
+ * must be assignable to {@code Element}. If the getter return type is assignable
+ * to {@code com.google.gwt.resources.client.CssResource}, the getter must
+ * have no parameters.
*/
private void validateRendererGetters(JClassType owner) throws UnableToCompleteException {
for (JMethod jMethod : owner.getInheritableMethods()) {
String getterName = jMethod.getName();
if (getterName.startsWith("get")) {
- if (jMethod.getParameterTypes().length != 1) {
- die("Getter %s must have exactly one parameter in %s", getterName,
- owner.getQualifiedSourceName());
- }
- String elementClassName = com.google.gwt.dom.client.Element.class.getCanonicalName();
- JClassType elementType = oracle.findType(elementClassName);
- JClassType getterParamType =
- jMethod.getParameterTypes()[0].getErasedType().isClassOrInterface();
-
- if (!elementType.isAssignableFrom(getterParamType)) {
- die("Getter %s must have exactly one parameter of type assignable to %s in %s",
- getterName, elementClassName, owner.getQualifiedSourceName());
- }
String fieldName = getterToFieldName(getterName);
FieldWriter field = fieldManager.lookup(fieldName);
- if (field == null || !FieldWriterType.DEFAULT.equals(field.getFieldType())) {
- die("%s does not match a \"ui:field='%s'\" declaration in %s", getterName, fieldName,
+ if (field == null || (!FieldWriterType.DEFAULT.equals(field.getFieldType())
+ && !FieldWriterType.GENERATED_CSS.equals(field.getFieldType()))) {
+ die("%s does not match a \"ui:field='%s'\" declaration in %s, "
+ + "or '%s' refers to something other than a ui:style"
+ + " or an HTML element in the template", getterName, fieldName,
+ owner.getQualifiedSourceName(), fieldName);
+ }
+ if (FieldWriterType.DEFAULT.equals(field.getFieldType())
+ && jMethod.getParameterTypes().length != 1) {
+ die("Field getter %s must have exactly one parameter in %s", getterName,
owner.getQualifiedSourceName());
+ } else if (FieldWriterType.GENERATED_CSS.equals(field.getFieldType())
+ && jMethod.getParameterTypes().length != 0) {
+ die("Style getter %s must have no parameters in %s", getterName,
+ owner.getQualifiedSourceName());
+ } else if (jMethod.getParameterTypes().length == 1) {
+ String elementClassName = com.google.gwt.dom.client.Element.class.getCanonicalName();
+ JClassType elementType = oracle.findType(elementClassName);
+ JClassType getterParamType =
+ jMethod.getParameterTypes()[0].getErasedType().isClassOrInterface();
+
+ if (!elementType.isAssignableFrom(getterParamType)) {
+ die("Getter %s must have exactly one parameter of type assignable to %s in %s",
+ getterName, elementClassName, owner.getQualifiedSourceName());
+ }
}
} else if (!getterName.equals("render") && !getterName.equals("onBrowserEvent")
&& !getterName.equals("isParentOrRenderer")) {
@@ -2199,18 +2219,26 @@
// public ElementSubclass getFoo(Element parent) {
w.write("%s {", getter.getReadableDeclaration(false, false, false, false, true));
w.indent();
- String elementParameter = getter.getParameters()[0].getName();
String getterFieldName = getterToFieldName(getter.getName());
- // The non-root elements are found by id
- if (!getterFieldName.equals(rootFieldName)) {
- // return (ElementSubclass) findUiField(parent);
- w.write("return (%s) findInnerField(%s, \"%s\", RENDERED_ATTRIBUTE);",
- getter.getReturnType().getErasedType().getQualifiedSourceName(), elementParameter,
- getterFieldName);
+ // Is this a CSS resource field?
+ FieldWriter fieldWriter = fieldManager.lookup(getterFieldName);
+ if (FieldWriterType.GENERATED_CSS.equals(fieldWriter.getFieldType())) {
+ // return (CssResourceSubclass) get_styleField;
+ w.write("return (%s) %s;", getter.getReturnType().getErasedType().getQualifiedSourceName(),
+ FieldManager.getFieldGetter(getterFieldName));
} else {
- // return (ElementSubclass) findPreviouslyRendered(parent);
- w.write("return (%s) findRootElement(%s, RENDERED_ATTRIBUTE);",
- getter.getReturnType().getErasedType().getQualifiedSourceName(), elementParameter);
+ // Else the non-root elements are found by id
+ String elementParameter = getter.getParameters()[0].getName();
+ if (!getterFieldName.equals(rootFieldName)) {
+ // return (ElementSubclass) findInnerField(parent, "foo", RENDERED_ATTRIBUTE);
+ w.write("return (%s) findInnerField(%s, \"%s\", RENDERED_ATTRIBUTE);",
+ getter.getReturnType().getErasedType().getQualifiedSourceName(), elementParameter,
+ getterFieldName);
+ } else {
+ // return (ElementSubclass) findRootElement(parent);
+ w.write("return (%s) findRootElement(%s, RENDERED_ATTRIBUTE);",
+ getter.getReturnType().getErasedType().getQualifiedSourceName(), elementParameter);
+ }
}
w.outdent();
w.write("}");
diff --git a/user/test/com/google/gwt/uibinder/rebind/AbstractUiBinderWriterTest.java b/user/test/com/google/gwt/uibinder/rebind/AbstractUiBinderWriterTest.java
index e8fb5f3..b9cd55f 100644
--- a/user/test/com/google/gwt/uibinder/rebind/AbstractUiBinderWriterTest.java
+++ b/user/test/com/google/gwt/uibinder/rebind/AbstractUiBinderWriterTest.java
@@ -102,6 +102,17 @@
}
};
+ public static final MockJavaResource UI_STYLE = new MockJavaResource("foo.UiStyle") {
+ @Override
+ public CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package foo;");
+ code.append("public interface UiStyle {");
+ code.append("}");
+ return code;
+ }
+ };
+
protected static final String BINDER_URI = "urn:ui:com.google.gwt.uibinder";
protected static final W3cDomHelper docHelper = new W3cDomHelper(TreeLogger.NULL,
@@ -153,6 +164,7 @@
resources.add(CLIENT_BUNDLE);
resources.add(DIV_ELEMENT);
resources.add(SPAN_ELEMENT);
+ resources.add(UI_STYLE);
resources.add(FOO);
resources.add(rendererClass);
resources.addAll(Arrays.asList(otherClasses));
diff --git a/user/test/com/google/gwt/uibinder/rebind/UiRendererValidationTest.java b/user/test/com/google/gwt/uibinder/rebind/UiRendererValidationTest.java
index ec5e469..97f821d 100644
--- a/user/test/com/google/gwt/uibinder/rebind/UiRendererValidationTest.java
+++ b/user/test/com/google/gwt/uibinder/rebind/UiRendererValidationTest.java
@@ -26,6 +26,7 @@
public class UiRendererValidationTest extends AbstractUiBinderWriterTest {
private static String UI_XML = "<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'>"
+ + "<ui:style field='styleField'>.foo {color:black;}</ui:style>"
+ "<ui:with field='withField' />"
+ " <div ui:field='root'>"
+ " <span ui:field='someField'><ui:text from='{withField.toString}'/></span>"
@@ -45,6 +46,7 @@
declaredMethods.append(" public void render(SafeHtmlBuilder sb, foo.Foo withField);");
declaredMethods.append(" public DivElement getRoot(Element foo);");
declaredMethods.append(" public SpanElement getSomeField(Element bar);");
+ declaredMethods.append(" public UiStyle getStyleField();");
init(UI_XML, generateRendererResource(declaredMethods));
writer.parseDocument(doc, printWriter);
}
@@ -74,7 +76,16 @@
init(UI_XML, generateRendererResource(declaredMethods));
assertParseFailure("Expected failure due to getter with no parameters.",
- "Getter getRoot must have exactly one parameter in renderer.OwnerClass.Renderer");
+ "Field getter getRoot must have exactly one parameter in renderer.OwnerClass.Renderer");
+ }
+
+ public void testStyleGetterWithParameter() throws SAXParseException, UnableToCompleteException {
+ initGetterTest();
+ declaredMethods.append(" public UiStyle getStyleField(DivElement bar);");
+ init(UI_XML, generateRendererResource(declaredMethods));
+
+ assertParseFailure("Expected failure due to style getter with a parameter.",
+ "Style getter getStyleField must have no parameters in renderer.OwnerClass.Renderer");
}
public void testGetterTooManyParameters() throws SAXParseException, UnableToCompleteException {
@@ -83,7 +94,7 @@
init(UI_XML, generateRendererResource(declaredMethods));
assertParseFailure("Expected failure due to bad getter signature.",
- "Getter getRoot must have exactly one parameter in renderer.OwnerClass.Renderer");
+ "Field getter getRoot must have exactly one parameter in renderer.OwnerClass.Renderer");
}
public void testGetterUnknownField() throws SAXParseException, UnableToCompleteException {
@@ -91,7 +102,9 @@
declaredMethods.append(" public DivElement getQuux(Element parent);");
init(UI_XML, generateRendererResource(declaredMethods));
assertParseFailure("Expected failure due to getter for an unexpected field name.",
- "getQuux does not match a \"ui:field='quux'\" declaration in renderer.OwnerClass.Renderer");
+ "getQuux does not match a \"ui:field='quux'\" declaration in renderer.OwnerClass.Renderer,"
+ + " or 'quux' refers to something other than a ui:style or an HTML element in"
+ + " the template");
}
public void testRenderBadReturnType() throws SAXParseException, UnableToCompleteException {
@@ -171,6 +184,7 @@
code.append("import com.google.gwt.dom.client.Element;\n");
code.append("import com.google.gwt.dom.client.SpanElement;\n");
code.append("import foo.Foo;\n");
+ code.append("import foo.UiStyle;\n");
code.append("public class OwnerClass {");
code.append(" public interface Renderer");
code.append(" extends UiRenderer {");
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiRendererTest.java b/user/test/com/google/gwt/uibinder/test/client/UiRendererTest.java
index db69ab4..0474a0e 100644
--- a/user/test/com/google/gwt/uibinder/test/client/UiRendererTest.java
+++ b/user/test/com/google/gwt/uibinder/test/client/UiRendererTest.java
@@ -248,6 +248,14 @@
spanNode2.getFirstChild());
}
+ public void testStyleManipulation() {
+ SpanElement nameSpan = renderer.getNameSpan(docDiv);
+ assertEquals(renderer.getUiStyle().enabled(), nameSpan.getClassName());
+ nameSpan.replaceClassName(renderer.getUiStyle().enabled(),
+ renderer.getUiStyle().disabled());
+ assertEquals(renderer.getUiStyle().disabled(), nameSpan.getClassName());
+ }
+
@Override
protected void gwtTearDown() {
docDiv.removeFromParent();
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.java b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.java
index 61758ff..12a6ebd 100644
--- a/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.java
+++ b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.java
@@ -77,7 +77,19 @@
}
}
- interface HtmlRenderer extends UiRenderer {
+ /**
+ * A style defined within the UiBinder file.
+ */
+ public interface UiStyle extends CssResource {
+ String enabled();
+ String disabled();
+ }
+
+ /**
+ * A UiRinder Cell renderer.
+ */
+ public interface HtmlRenderer extends UiRenderer {
+ UiStyle getUiStyle();
SpanElement getNameSpan(Element owner);
TableColElement getNarrowColumn(Element owner);
DivElement getRoot(Element owner);
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.ui.xml b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.ui.xml
index 9a1de11..e0eb3ba 100644
--- a/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.ui.xml
+++ b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.ui.xml
@@ -17,12 +17,16 @@
<ui:with field="aValue"/>
<ui:with field="aValueTwice"/>
+ <ui:style field="uiStyle" type="com.google.gwt.uibinder.test.client.UiRendererUi.UiStyle">
+ .enabled { color:black; }
+ .disabled { color:gray; }
+ </ui:style>
<div ui:field='root' class="{res.style.bodyColor} {res.style.bodyFont}"
title="The title of this div is localizable">
<ui:attribute name='title'/>
<span><ui:text from="{constants.getText}" /></span>
- Hello, <span ui:field="nameSpan"><ui:text from="{aValue.getBar}"/></span>.
+ Hello, <span ui:field="nameSpan" class="{uiStyle.enabled}"><ui:text from="{aValue.getBar}"/></span>.
<ui:msg>How goes it?</ui:msg>
<span/><span><ui:text from="{aValueTwice.getBar}{aValueTwice.getBar}"/></span>
<h2 class="{res.style.bodyColor} {res.style.bodyFont}">Placeholders in localizables</h2>