Restore "Introduces ui:image--ImageResource in UiBinder",
this time without breaking checkstyle (sorry).
Review by: bobv
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6339 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/parsers/HasTextParser.java b/user/src/com/google/gwt/uibinder/parsers/HasTextParser.java
index 742205b..a01ce36 100644
--- a/user/src/com/google/gwt/uibinder/parsers/HasTextParser.java
+++ b/user/src/com/google/gwt/uibinder/parsers/HasTextParser.java
@@ -28,7 +28,7 @@
public void parse(XMLElement elem, String fieldName, JClassType type,
UiBinderWriter writer) throws UnableToCompleteException {
// Widgets that implement HasText will use their elements' inner text.
- String text = elem.consumeInnerText(new TextInterpreter(writer));
+ String text = elem.consumeInnerTextEscapedAsHtmlStringLiteral(new TextInterpreter(writer));
if (text.trim().length() > 0) {
writer.genStringPropertySet(fieldName, "text", text);
}
diff --git a/user/src/com/google/gwt/uibinder/parsers/TextPlaceholderInterpreter.java b/user/src/com/google/gwt/uibinder/parsers/TextPlaceholderInterpreter.java
index fadb67b..549ad10 100644
--- a/user/src/com/google/gwt/uibinder/parsers/TextPlaceholderInterpreter.java
+++ b/user/src/com/google/gwt/uibinder/parsers/TextPlaceholderInterpreter.java
@@ -34,6 +34,6 @@
@Override protected String consumePlaceholderInnards(XMLElement elem)
throws UnableToCompleteException {
- return elem.consumeInnerText(new NullInterpreter<String>());
+ return elem.consumeInnerTextEscapedAsHtmlStringLiteral(new NullInterpreter<String>());
}
}
diff --git a/user/src/com/google/gwt/uibinder/rebind/BundleWriter.java b/user/src/com/google/gwt/uibinder/rebind/BundleWriter.java
index 5187e6a..b134c8b 100644
--- a/user/src/com/google/gwt/uibinder/rebind/BundleWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/BundleWriter.java
@@ -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
@@ -16,11 +16,16 @@
package com.google.gwt.uibinder.rebind;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.resources.client.CssResource.Strict;
+import com.google.gwt.resources.client.ImageResource.ImageOptions;
+import com.google.gwt.resources.client.ImageResource.RepeatStyle;
import com.google.gwt.uibinder.rebind.model.ImplicitClientBundle;
import com.google.gwt.uibinder.rebind.model.ImplicitCssResource;
+import com.google.gwt.uibinder.rebind.model.ImplicitImageResource;
/**
* Writes source implementing an {@link ImplicitClientBundle}.
@@ -31,8 +36,12 @@
private final IndentedWriter writer;
private final PrintWriterManager writerManager;
private final TypeOracle oracle;
- private final String clientBundleType;
- private final String strictAnnotationType;
+
+ private final JClassType clientBundleType;
+ private final JClassType strictAnnotationType;
+ private final JClassType imageOptionType;
+ private final JClassType imageResourceType;
+ private final JClassType repeatStyleType;
public BundleWriter(ImplicitClientBundle bundleClass,
PrintWriterManager writerManager, TypeOracle oracle,
@@ -43,8 +52,11 @@
this.writerManager = writerManager;
this.oracle = oracle;
- clientBundleType = oracle.findType(ClientBundle.class.getName()).getQualifiedSourceName();
- strictAnnotationType = oracle.findType(Strict.class.getCanonicalName()).getQualifiedSourceName();
+ clientBundleType = oracle.findType(ClientBundle.class.getName());
+ strictAnnotationType = oracle.findType(Strict.class.getCanonicalName());
+ imageOptionType = oracle.findType(ImageOptions.class.getCanonicalName());
+ imageResourceType = oracle.findType(ImageResource.class.getCanonicalName());
+ repeatStyleType = oracle.findType(RepeatStyle.class.getCanonicalName());
}
public void write() throws UnableToCompleteException {
@@ -64,9 +76,10 @@
}
// Imports
- writer.write("import %s;",
- clientBundleType);
- writer.write("import %s;", strictAnnotationType);
+ writer.write("import %s;", imageResourceType.getQualifiedSourceName());
+ writer.write("import %s;", imageOptionType.getQualifiedSourceName());
+ writer.write("import %s;", clientBundleType.getQualifiedSourceName());
+ writer.write("import %s;", strictAnnotationType.getQualifiedSourceName());
writer.newline();
// Open interface
@@ -81,8 +94,41 @@
writer.newline();
}
+ writer.newline();
+ writeImageMethods();
+
// Close interface.
writer.outdent();
writer.write("}");
}
+
+ private void writeImageMethods() {
+ for (ImplicitImageResource image : bundleClass.getImageMethods()) {
+ if (null != image.getSource()) {
+ writer.write("@Source(\"%s\")", image.getSource());
+ }
+
+ writeImageOptionsAnnotation(image.getFlipRtl(), image.getRepeatStyle());
+ writer.write("%s %s();", imageResourceType.getName(), image.getName());
+ }
+ }
+
+ private void writeImageOptionsAnnotation(Boolean flipRtl,
+ RepeatStyle repeatStyle) {
+ if (flipRtl != null || repeatStyle != null) {
+ StringBuilder b = new StringBuilder("@ImageOptions(");
+ if (null != flipRtl) {
+ b.append("flipRtl=").append(flipRtl);
+ if (repeatStyle != null) {
+ b.append(", ");
+ }
+ }
+ if (repeatStyle != null) {
+ b.append(String.format("repeatStyle=%s.%s", repeatStyleType.getName(),
+ repeatStyle.toString()));
+ }
+ b.append(")");
+ writer.write(b.toString());
+ }
+ }
}
diff --git a/user/src/com/google/gwt/uibinder/rebind/GetInnerTextVisitor.java b/user/src/com/google/gwt/uibinder/rebind/GetEscapedInnerTextVisitor.java
similarity index 90%
rename from user/src/com/google/gwt/uibinder/rebind/GetInnerTextVisitor.java
rename to user/src/com/google/gwt/uibinder/rebind/GetEscapedInnerTextVisitor.java
index 4cf561a..d3de434 100644
--- a/user/src/com/google/gwt/uibinder/rebind/GetInnerTextVisitor.java
+++ b/user/src/com/google/gwt/uibinder/rebind/GetEscapedInnerTextVisitor.java
@@ -23,7 +23,7 @@
import org.w3c.dom.Node;
import org.w3c.dom.Text;
-class GetInnerTextVisitor implements NodeVisitor {
+class GetEscapedInnerTextVisitor implements NodeVisitor {
/**
* Gathers a text representation of the children of the given Elem, and stuffs
@@ -33,7 +33,7 @@
public static void getEscapedInnerText(Element elem, StringBuffer buffer,
Interpreter<String> interpreter, UiBinderWriter writer)
throws UnableToCompleteException {
- new ChildWalker().accept(elem, new GetInnerTextVisitor(buffer, interpreter,
+ new ChildWalker().accept(elem, new GetEscapedInnerTextVisitor(buffer, interpreter,
writer));
}
@@ -41,7 +41,7 @@
protected final Interpreter<String> interpreter;
protected final UiBinderWriter writer;
- protected GetInnerTextVisitor(StringBuffer buffer,
+ protected GetEscapedInnerTextVisitor(StringBuffer buffer,
Interpreter<String> interpreter, UiBinderWriter writer) {
this.buffer = buffer;
this.interpreter = interpreter;
@@ -73,6 +73,7 @@
boolean preserveWhitespace =
parent != null && "pre".equals(parent.getTagName());
+ // TODO(rjrjr) What about script blocks?
return preserveWhitespace;
}
}
diff --git a/user/src/com/google/gwt/uibinder/rebind/GetInnerHtmlVisitor.java b/user/src/com/google/gwt/uibinder/rebind/GetInnerHtmlVisitor.java
index 1f7d7a4..79ab82a 100644
--- a/user/src/com/google/gwt/uibinder/rebind/GetInnerHtmlVisitor.java
+++ b/user/src/com/google/gwt/uibinder/rebind/GetInnerHtmlVisitor.java
@@ -20,7 +20,7 @@
import org.w3c.dom.Element;
-class GetInnerHtmlVisitor extends GetInnerTextVisitor {
+class GetInnerHtmlVisitor extends GetEscapedInnerTextVisitor {
/**
* Recursively gathers an HTML representation of the children of the given
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
index fd00756..c5aa2a7 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
@@ -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
@@ -20,10 +20,12 @@
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.resources.client.CssResource;
-import com.google.gwt.uibinder.parsers.NullInterpreter;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.resources.client.ImageResource.RepeatStyle;
import com.google.gwt.uibinder.rebind.messages.MessagesWriter;
import com.google.gwt.uibinder.rebind.model.ImplicitClientBundle;
import com.google.gwt.uibinder.rebind.model.ImplicitCssResource;
+import com.google.gwt.uibinder.rebind.model.ImplicitImageResource;
import com.google.gwt.uibinder.rebind.model.OwnerField;
/**
@@ -31,8 +33,11 @@
* document.
*/
public class UiBinderParser {
+
+ private static final String FLIP_RTL_ATTRIBUTE = "flipRtl";
private static final String FIELD_ATTRIBUTE = "field";
private static final String SOURCE_ATTRIBUTE = "src";
+ private static final String REPEAT_STYLE_ATTRIBUTE = "repeatStyle";
// TODO(rjrjr) Make all the ElementParsers receive their dependencies via
// constructor like this one does, and make this an ElementParser. I want
@@ -44,6 +49,7 @@
private final FieldManager fieldManager;
private final ImplicitClientBundle bundleClass;
private final JClassType cssResourceType;
+ private final JClassType imageResourceType;
public UiBinderParser(UiBinderWriter writer, MessagesWriter messagesWriter,
FieldManager fieldManager, TypeOracle oracle,
@@ -54,7 +60,8 @@
this.fieldManager = fieldManager;
this.bundleClass = bundleClass;
this.cssResourceType = oracle.findType(CssResource.class.getCanonicalName());
- }
+ this.imageResourceType = oracle.findType(ImageResource.class.getCanonicalName());
+ }
/**
* Parses the root UiBinder element, and kicks off the parsing of the rest of
@@ -65,6 +72,7 @@
// parsers, an so need a registration scheme for uibinder-specific parsers
findStyles(elem);
findResources(elem);
+ findImages(elem);
messagesWriter.findMessagesConfig(elem);
XMLElement uiRoot = elem.consumeSingleChildElement();
return writer.parseElementToField(uiRoot);
@@ -103,13 +111,48 @@
}
/**
+ * Interprets <ui:image> elements
+ */
+ private void createImage(XMLElement elem) throws UnableToCompleteException {
+ String name = elem.consumeRequiredAttribute(FIELD_ATTRIBUTE);
+ String source = elem.consumeAttribute(SOURCE_ATTRIBUTE, null); // @source is
+ // optional
+ // on
+ // ImageResource
+
+ Boolean flipRtl = null;
+ if (elem.hasAttribute(FLIP_RTL_ATTRIBUTE)) {
+ flipRtl = elem.consumeBooleanAttribute(FLIP_RTL_ATTRIBUTE);
+ }
+
+ RepeatStyle repeatStyle = null;
+ if (elem.hasAttribute(REPEAT_STYLE_ATTRIBUTE)) {
+ String value = elem.consumeAttribute(REPEAT_STYLE_ATTRIBUTE);
+ try {
+ repeatStyle = RepeatStyle.valueOf(value);
+ } catch (IllegalArgumentException e) {
+ writer.die("In %s, bad repeatStyle value %s", elem, value);
+ }
+ }
+
+ ImplicitImageResource imageMethod = bundleClass.createImageResource(name,
+ source, flipRtl, repeatStyle);
+
+ FieldWriter field = fieldManager.registerField(imageResourceType,
+ imageMethod.getName());
+ field.setInitializer(String.format("%s.%s()", bundleClass.getFieldName(),
+ imageMethod.getName()));
+ }
+
+ /**
* Interprets <ui:with> elements.
*/
private void createResource(XMLElement elem) throws UnableToCompleteException {
String resourceName = elem.consumeRequiredAttribute(FIELD_ATTRIBUTE);
JClassType resourceType = consumeTypeAttribute(elem);
if (elem.getAttributeCount() > 0) {
- writer.die("In %s, should only find attributes \"field\" and \"type\"", elem);
+ writer.die("In %s, should only find attributes \"field\" and \"type\"",
+ elem);
}
FieldWriter fieldWriter = fieldManager.registerField(resourceType,
@@ -145,9 +188,11 @@
}
private void createStyle(XMLElement elem) throws UnableToCompleteException {
- String body = elem.consumeInnerText(new NullInterpreter<String>());
+ String body = elem.consumeUnescapedInnerText();
if (body.length() > 0 && elem.hasAttribute(SOURCE_ATTRIBUTE)) {
- writer.die("In %s, cannot use both a source attribute and inline css text.", elem);
+ writer.die(
+ "In %s, cannot use both a source attribute and inline css text.",
+ elem);
}
String source = elem.consumeAttribute(SOURCE_ATTRIBUTE);
@@ -164,6 +209,22 @@
cssMethod.getName()));
}
+ private void findImages(XMLElement binderElement)
+ throws UnableToCompleteException {
+ binderElement.consumeChildElements(new XMLElement.Interpreter<Boolean>() {
+ public Boolean interpretElement(XMLElement elem)
+ throws UnableToCompleteException {
+ if (!(writer.isBinderElement(elem) && "image".equals(elem.getLocalName()))) {
+ return false; // Not of interest, do not consume
+ }
+
+ createImage(elem);
+
+ return true; // Yum
+ }
+ });
+ }
+
private void findResources(XMLElement binderElement)
throws UnableToCompleteException {
binderElement.consumeChildElements(new XMLElement.Interpreter<Boolean>() {
diff --git a/user/src/com/google/gwt/uibinder/rebind/XMLElement.java b/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
index a1c8055..20d08a2 100644
--- a/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
+++ b/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -22,6 +22,7 @@
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
import java.util.ArrayList;
import java.util.Collection;
@@ -47,7 +48,7 @@
public interface Interpreter<T> {
/**
* Given an XMLElement, return its filtered value.
- *
+ *
* @throws UnableToCompleteException on error
*/
T interpretElement(XMLElement elem) throws UnableToCompleteException;
@@ -115,7 +116,7 @@
/**
* Consumes the given attribute and returns its trimmed value, or null if it
* was unset. The returned string is not escaped.
- *
+ *
* @param name the attribute's full name (including prefix)
* @return the attribute's value, or null
*/
@@ -128,7 +129,7 @@
/**
* Consumes the given attribute and returns its trimmed value, or the given
* default value if it was unset. The returned string is not escaped.
- *
+ *
* @param name the attribute's full name (including prefix)
* @param defaultValue the value to return if the attribute was unset
* @return the attribute's value, or defaultValue
@@ -143,7 +144,7 @@
/**
* Consumes the given attribute as a boolean value.
- *
+ *
* @throws UnableToCompleteException
*/
public boolean consumeBooleanAttribute(String attr)
@@ -177,7 +178,7 @@
* Consumes and returns all child elements selected by the interpreter. Note
* that text nodes are not elements, and so are not presented for
* interpretation, and are not consumed.
- *
+ *
* @param interpreter Should return true for any child that should be consumed
* and returned by the consumeChildElements call
* @throws UnableToCompleteException
@@ -265,7 +266,7 @@
* The odds are you want to use
* {@link com.google.gwt.templates.parsers.HtmlInterpreter} for an HTML value,
* or {@link com.google.gwt.templates.parsers.TextInterpreter} for text.
- *
+ *
* @param interpreter Called for each element, expected to return a string
* replacement for it, or null if it should be left as is
*/
@@ -292,24 +293,37 @@
}
/**
+ * Refines {@link #consumeInnerTextEscapedAsHtmlStringLiteral(Interpreter)} to
+ * handle PostProcessingInterpreter.
+ */
+ public String consumeInnerText(PostProcessingInterpreter<String> interpreter)
+ throws UnableToCompleteException {
+ String text = consumeInnerTextEscapedAsHtmlStringLiteral((Interpreter<String>) interpreter);
+ return interpreter.postProcess(text);
+ }
+
+ /**
* Consumes all child text nodes, and asserts that this element held only
- * text. Trailing and leading whitespace is trimmed.
+ * text. Trailing and leading whitespace is trimmed, and escaped for use as a
+ * string literal. Notice that HTML entities in the text are also escaped--is
+ * this a source of errors?
* <p>
* This call requires an interpreter to make sense of any special children.
* The odds are you want to use
* {@link com.google.gwt.templates.parsers.TextInterpreter}
- *
+ *
* @throws UnableToCompleteException If any elements present are not consumed
* by the interpreter
*/
- public String consumeInnerText(Interpreter<String> interpreter)
- throws UnableToCompleteException {
+ public String consumeInnerTextEscapedAsHtmlStringLiteral(
+ Interpreter<String> interpreter) throws UnableToCompleteException {
if (interpreter == null) {
throw new NullPointerException("interpreter must not be null");
}
StringBuffer buf = new StringBuffer();
- GetInnerTextVisitor.getEscapedInnerText(elem, buf, interpreter, writer);
+ GetEscapedInnerTextVisitor.getEscapedInnerText(elem, buf, interpreter,
+ writer);
// Make sure there are no children left but empty husks
for (XMLElement child : consumeChildElements()) {
@@ -325,16 +339,6 @@
}
/**
- * Refines {@link #consumeInnerText(Interpreter)} to handle
- * PostProcessingInterpreter.
- */
- public String consumeInnerText(PostProcessingInterpreter<String> interpreter)
- throws UnableToCompleteException {
- String text = consumeInnerText((Interpreter<String>) interpreter);
- return interpreter.postProcess(text);
- }
-
- /**
* Consumes the given attribute as an int value.
*
* @param attr the attribute's full name (including prefix)
@@ -379,14 +383,16 @@
/**
* Consumes a single child element, ignoring any text nodes and throwing an
* exception if more than one child element is found.
+ *
+ * @throws UnableToCompleteException
*/
- public XMLElement consumeSingleChildElement() {
+ public XMLElement consumeSingleChildElement()
+ throws UnableToCompleteException {
XMLElement ret = null;
for (XMLElement child : consumeChildElements()) {
if (ret != null) {
- throw new RuntimeException(String.format(
- "%s may only contain a single child element, but found"
- + "%s and %s.", getLocalName(), ret, child));
+ writer.die("%s may only contain a single child element, but found"
+ + "%s and %s.", getLocalName(), ret, child);
}
ret = child;
@@ -396,6 +402,28 @@
}
/**
+ * Returns the unprocessed, unescaped, raw inner text of the receiver. Dies if
+ * the receiver has non-text children.
+ * <p>
+ * You probably want to use
+ * {@link #consumeInnerTextEscapedAsHtmlStringLiteral} instead.
+ *
+ * @return the text
+ * @throws UnableToCompleteException if it held anything other than text nodes
+ */
+ public String consumeUnescapedInnerText() throws UnableToCompleteException {
+ final NodeList children = elem.getChildNodes();
+ if (children.getLength() < 1) {
+ return "";
+ }
+ if (children.getLength() > 1 || Node.TEXT_NODE != children.item(0).getNodeType()) {
+ writer.die("%s must contain only text", this);
+ }
+ Text t = (Text) children.item(0);
+ return t.getTextContent();
+ }
+
+ /**
* Get the attribute at the given index. If you are consuming attributes,
* remember to traverse them in reverse.
*/
diff --git a/user/src/com/google/gwt/uibinder/rebind/model/ImplicitClientBundle.java b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitClientBundle.java
index 3f17973..7727606 100644
--- a/user/src/com/google/gwt/uibinder/rebind/model/ImplicitClientBundle.java
+++ b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitClientBundle.java
@@ -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
@@ -16,6 +16,7 @@
package com.google.gwt.uibinder.rebind.model;
import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.resources.client.ImageResource.RepeatStyle;
import com.google.gwt.uibinder.rebind.MortalLogger;
import java.util.Collections;
@@ -28,6 +29,7 @@
public class ImplicitClientBundle {
private final Set<ImplicitCssResource> cssMethods = new HashSet<ImplicitCssResource>();
+ private final Set<ImplicitImageResource> imageMethods = new HashSet<ImplicitImageResource>();
private final String packageName;
private final String className;
private final String fieldName;
@@ -39,20 +41,19 @@
* @param uiBinderImplClassName The name of the generated ui binder
* implementation that owns the bundle
* @param fieldName The bundle's field name
- * @param logger TODO
*/
public ImplicitClientBundle(String packageName, String uiBinderImplClassName,
String fieldName, MortalLogger logger) {
this.packageName = packageName;
this.className = uiBinderImplClassName + "_GenBundle";
- this.cssBaseName = uiBinderImplClassName + "_GenCss";
+ this.cssBaseName = uiBinderImplClassName + "_GenCss_";
this.fieldName = fieldName;
this.logger = logger;
}
/**
* Called to declare a new CssResource accessor on this bundle.
- *
+ *
* @param name the method name
* @param source path to the .css file resource
* @param extendedInterface the public interface implemented by this
@@ -68,6 +69,24 @@
return css;
}
+ /**
+ * Called to declare a new ImageResource accessor on this bundle.
+ *
+ * @param name the method name
+ * @param source path the image resource, or null if none was specified
+ * @param flipRtl value for the flipRtl ImageOption, or null if none was
+ * specified
+ * @param repeatStyle value of the RepeatStyle ImageOption, or null if none
+ * was specified
+ * @return
+ */
+ public ImplicitImageResource createImageResource(String name, String source,
+ Boolean flipRtl, RepeatStyle repeatStyle) {
+ ImplicitImageResource image = new ImplicitImageResource(name, source, flipRtl, repeatStyle);
+ imageMethods.add(image);
+ return image;
+ }
+
public String getClassName() {
return className;
}
@@ -80,6 +99,10 @@
return fieldName;
}
+ public Set<ImplicitImageResource> getImageMethods() {
+ return Collections.unmodifiableSet(imageMethods);
+ }
+
public String getPackageName() {
return packageName;
}
diff --git a/user/src/com/google/gwt/uibinder/rebind/model/ImplicitCssResource.java b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitCssResource.java
index 5742cec..b940167 100644
--- a/user/src/com/google/gwt/uibinder/rebind/model/ImplicitCssResource.java
+++ b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitCssResource.java
@@ -32,9 +32,7 @@
import java.util.Set;
/**
- * Models a method returning a CssResource on a generated ClientBundle. At the
- * moment, they must be tied to an external .css file. That should improve in
- * the next day or so.
+ * Models a method returning a CssResource on a generated ClientBundle.
*/
public class ImplicitCssResource {
private final String packageName;
diff --git a/user/src/com/google/gwt/uibinder/rebind/model/ImplicitImageResource.java b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitImageResource.java
new file mode 100644
index 0000000..4ae80d9
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/rebind/model/ImplicitImageResource.java
@@ -0,0 +1,52 @@
+/*
+ * 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.rebind.model;
+
+import com.google.gwt.resources.client.ImageResource.RepeatStyle;
+
+/**
+ * Models a method returning an ImageResource on a generated ClientBundle.
+ */
+public class ImplicitImageResource {
+ private final String name;
+ private final String source;
+ private final Boolean flipRtl;
+ private final RepeatStyle repeatStyle;
+
+ public ImplicitImageResource(
+ String name, String source, Boolean flipRtl, RepeatStyle repeatStyle) {
+ this.name = name;
+ this.source = source;
+ this.flipRtl = flipRtl;
+ this.repeatStyle = repeatStyle;
+ }
+
+ public Boolean getFlipRtl() {
+ return flipRtl;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public RepeatStyle getRepeatStyle() {
+ return repeatStyle;
+ }
+
+ public String getSource() {
+ return source;
+ }
+}
diff --git a/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.java b/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.java
index edb568f..ebe0b27 100644
--- a/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.java
+++ b/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.java
@@ -25,6 +25,7 @@
import com.google.gwt.dom.client.StyleInjector;
import com.google.gwt.dom.client.TableElement;
import com.google.gwt.resources.client.CssResource;
+import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.resources.client.CssResource.Shared;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
@@ -34,6 +35,7 @@
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.HTMLPanel;
+import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItem;
@@ -113,6 +115,10 @@
@UiField ParagraphElement privateStyleParagraph;
@UiField ParagraphElement reallyPrivateStyleParagraph;
@UiField SpanElement totallyPrivateStyleSpan;
+ @UiField ImageResource prettyImage;
+ @UiField ImageResource prettyTilingImage;
+ @UiField Image babyWidget;
+ @UiField ParagraphElement simpleSpriteParagraph;
public WidgetBasedUi() {
this.bundledLabel = new Label();
diff --git a/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml b/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml
index 7f40dfd..2a12e97 100644
--- a/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml
+++ b/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml
@@ -96,6 +96,29 @@
}
</ui:style>
+<ui:style field='mySpritelyStyle'>
+ @sprite .simpleSprite {
+ gwt-image: "prettyImage";
+ }
+
+ @sprite .tilingSprite {
+ gwt-image: "prettyTilingImage";
+ }
+
+ .garish {
+ color: Purple;
+ font-weight: bold;
+ font-family: sans-serif;
+ text-shadow: white 1px 1px 1px;
+ }
+
+ .garish.tilingSprite {
+ font-size: 1.5em;
+ }
+</ui:style>
+<ui:image field='prettyImage' />
+<ui:image field='prettyTilingImage' src='prettyImage.png' flipRtl='true' repeatStyle='Both'/>
+
<gwt:DockPanel ui:field="root" width="100%">
<gwt:Dock direction='NORTH'>
<gwt:HTML>
@@ -149,6 +172,21 @@
<demo:ClickyLink text="hyperlink based on a custom widget"
ui:field="customLinkWidget" popupText="That tickles! "/>.
</p>
+
+ <p>I bet you like babies in your Image widgets.</p>
+ <gwt:Image ui:field='babyWidget' resource='{prettyImage}'/>
+
+ <p ui:field='simpleSpriteParagraph'
+ class='{mySpritelyStyle.simpleSprite} {mySpritelyStyle.garish}' >
+ And sprites too
+ </p>
+
+ <p class='{mySpritelyStyle.tilingSprite} {mySpritelyStyle.garish}'>
+ Well how do you like <br/>
+ tiled sprited images...of babies!! <br/>
+ Well of course you do. Who wouldn't?
+ </p>
+
<p>
<ui:msg description="">
Of course, it could just as easily be a Tree under a MenuBar...
@@ -389,17 +427,24 @@
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" />
+ <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: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>
+ <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>
@@ -505,6 +550,7 @@
<tr><td>Even HTMLPanel gets in on the game</td></tr>
<tr><td>Lately, anyway.</td></tr>
</gwt:HTMLPanel>
+
</gwt:HTMLPanel>
</gwt:Dock>
</gwt:DockPanel>
diff --git a/user/src/com/google/gwt/uibinder/sample/client/prettyImage.png b/user/src/com/google/gwt/uibinder/sample/client/prettyImage.png
new file mode 100644
index 0000000..a7a9ae6
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/sample/client/prettyImage.png
Binary files differ
diff --git a/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java b/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java
index 5096590..bde2493 100644
--- a/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java
+++ b/user/test/com/google/gwt/uibinder/rebind/XMLElementTest.java
@@ -16,12 +16,14 @@
package com.google.gwt.uibinder.rebind;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.uibinder.parsers.NullInterpreter;
import com.google.gwt.uibinder.testing.UiBinderTesting;
import junit.framework.TestCase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.Text;
import org.xml.sax.SAXException;
import java.io.IOException;
@@ -34,6 +36,10 @@
* Tests XMLElement.
*/
public class XMLElementTest extends TestCase {
+ /**
+ *
+ */
+ private static final String STRING_WITH_DOUBLEQUOTE = "I have a \" quote in me";
private static final String dom =
"<doc><elm attr1=\"attr1Value\" attr2=\"attr2Value\"/></doc>";
private Document doc;
@@ -47,6 +53,7 @@
item = (Element) doc.getDocumentElement().getElementsByTagName(
"elm").item(0);
elm = new XMLElement(item, null);
+
}
public void testConsumeAttribute() {
@@ -63,7 +70,7 @@
public void testConsumeRequired() throws UnableToCompleteException {
assertEquals("attr1Value", elm.consumeRequiredAttribute("attr1"));
- // TODO(rjrjr) Can't test this until die() is factored out of UiBinderWriter
+ // TODO(rjrjr) Can't test this until UiBinderWriter can be mocked
// try {
// elm.consumeRequiredAttribute("unsetthing");
// fail("Should have thrown UnableToCompleteException");
@@ -72,6 +79,31 @@
// }
}
+ public void testConsumeInnerTextEscapedAsHtmlStringLiteral() throws UnableToCompleteException {
+ appendText(STRING_WITH_DOUBLEQUOTE);
+ assertEquals(UiBinderWriter.escapeTextForJavaStringLiteral(STRING_WITH_DOUBLEQUOTE),
+ elm.consumeInnerTextEscapedAsHtmlStringLiteral(new NullInterpreter<String>()));
+ }
+
+ public void testConsumeInnerTextEscapedAsHtmlStringLiteralEmpty() throws UnableToCompleteException {
+ assertEquals("",
+ elm.consumeInnerTextEscapedAsHtmlStringLiteral(new NullInterpreter<String>()));
+ }
+
+ private void appendText(final String text) {
+ Text t = doc.createTextNode(STRING_WITH_DOUBLEQUOTE);
+ item.appendChild(t);
+ }
+
+ public void testConsumeUnescapedInnerText() throws UnableToCompleteException {
+ appendText(STRING_WITH_DOUBLEQUOTE);
+ assertEquals(STRING_WITH_DOUBLEQUOTE, elm.consumeUnescapedInnerText());
+ }
+
+ public void testConsumeUnescapedInnerTextEmpty() throws UnableToCompleteException {
+ assertEquals("", elm.consumeUnescapedInnerText());
+ }
+
public void testEmptyStringOnMissingAttribute()
throws ParserConfigurationException, SAXException, IOException {
assertEquals("", elm.consumeAttribute("fnord"));
diff --git a/user/test/com/google/gwt/uibinder/sample/client/UiBinderTest.java b/user/test/com/google/gwt/uibinder/sample/client/UiBinderTest.java
index e2ba40c..1f426ea 100644
--- a/user/test/com/google/gwt/uibinder/sample/client/UiBinderTest.java
+++ b/user/test/com/google/gwt/uibinder/sample/client/UiBinderTest.java
@@ -344,6 +344,18 @@
String t = clicky.getPopupText();
assertEquals("funny characters \" ' ' & < > > { }", t);
}
+
+ public void testImageResourceInImageWidget() {
+ assertEquals(widgetUi.prettyImage.getWidth(), widgetUi.babyWidget.getOffsetWidth());
+ assertEquals(widgetUi.prettyImage.getHeight(), widgetUi.babyWidget.getOffsetHeight());
+ assertEquals(widgetUi.prettyImage.getTop(), widgetUi.babyWidget.getOriginTop());
+ assertEquals(widgetUi.prettyImage.getLeft(), widgetUi.babyWidget.getOriginLeft());
+ }
+
+ public void testSpritedElement() {
+ assertEquals(widgetUi.prettyImage.getWidth(), widgetUi.simpleSpriteParagraph.getOffsetWidth());
+ assertEquals(widgetUi.prettyImage.getHeight(), widgetUi.simpleSpriteParagraph.getOffsetHeight());
+ }
public void suppressForIEfail_testBizarrelyElementedWidgets() {
assertInOrder(widgetUi.widgetCrazyTable.getInnerHTML().toLowerCase(),