Revision: 7030 Author: j...@google.com Date: Thu Nov 19 12:57:33 2009 Log: Adds parsers for LayoutPanel and Length attributes. Review: http://gwt-code-reviews.appspot.com/103806 http://code.google.com/p/google-web-toolkit/source/detail?r=7030
Added: /trunk/user/src/com/google/gwt/uibinder/attributeparsers/LengthAttributeParser.java /trunk/user/src/com/google/gwt/uibinder/elementparsers/LayoutPanelParser.java /trunk/user/test/com/google/gwt/uibinder/attributeparsers/LengthAttributeParserTest.java /trunk/user/test/com/google/gwt/uibinder/elementparsers/LayoutPanelParserTest.java Modified: /trunk/user/javadoc/com/google/gwt/examples/StackLayoutPanelExample.java /trunk/user/src/com/google/gwt/uibinder/attributeparsers/AttributeParsers.java /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java /trunk/user/src/com/google/gwt/uibinder/rebind/XMLElement.java /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java /trunk/user/test/com/google/gwt/uibinder/test/UiJavaResources.java ======================================= --- /dev/null +++ /trunk/user/src/com/google/gwt/uibinder/attributeparsers/LengthAttributeParser.java Thu Nov 19 12:57:33 2009 @@ -0,0 +1,78 @@ +/* + * 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.attributeparsers; + +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.uibinder.rebind.MortalLogger; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Parses a CSS length value (e.g., "2em", "50%"), returning a comma-separated + * (double, Unit) pair. + */ +public class LengthAttributeParser implements AttributeParser { + + static final String UNIT = "com.google.gwt.dom.client.Style.Unit"; + + // This regular expression matches CSS length patterns of the form + // (value)(unit), where the two may be separated by whitespace. Either part + // can be a {class.method} expression. + private static final Pattern pattern = Pattern.compile( + "((?:\\{[\\w\\.]+\\})|[\\d\\.]+)\\s*(\\{?[\\w\\.\\%]*\\}?)?"); + + private final MortalLogger logger; + private final DoubleAttributeParser doubleParser; + private final EnumAttributeParser enumParser; + + public LengthAttributeParser(DoubleAttributeParser doubleParser, + EnumAttributeParser enumParser, MortalLogger logger) { + this.doubleParser = doubleParser; + this.enumParser = enumParser; + this.logger = logger; + } + + public String parse(String lengthStr) throws UnableToCompleteException { + Matcher matcher = pattern.matcher(lengthStr); + if (!matcher.matches()) { + logger.die("Unable to parse %s as length", lengthStr); + } + + String valueStr = matcher.group(1); + String value = doubleParser.parse(valueStr); + + String unit = null; + String unitStr = matcher.group(2); + if (unitStr.length() > 0) { + if (!unitStr.startsWith("{")) { + // For non-refs, convert % => PCT, px => PX, etc. + if ("%".equals(unitStr)) { + unitStr = "PCT"; + } + unitStr = unitStr.toUpperCase(); + } + + // Now let the default enum parser handle it. + unit = enumParser.parse(unitStr); + } else { + // Use PX by default. + unit = UNIT + ".PX"; + } + + return value + ", " + unit; + } +} ======================================= --- /dev/null +++ /trunk/user/src/com/google/gwt/uibinder/elementparsers/LayoutPanelParser.java Thu Nov 19 12:57:33 2009 @@ -0,0 +1,119 @@ +/* + * 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.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; + +/** + * Parses {...@link LayoutPanel} widgets. + */ +public class LayoutPanelParser implements ElementParser { + + private static final String ERR_PAIRING = "In %s %s, 'left' must be paired with 'right' or 'width'."; + private static final String ERR_TOO_MANY = "In %s %s, there are too many %s constraints."; + private static final String LAYER = "layer"; + + public void parse(XMLElement elem, String fieldName, JClassType type, + UiBinderWriter writer) throws UnableToCompleteException { + + // Parse children. + for (XMLElement layerElem : elem.consumeChildElements()) { + // Get the layer element. + if (!isElementType(elem, layerElem, LAYER)) { + writer.die("In %s, only <%s:%s> children are allowed.", elem, + elem.getPrefix(), LAYER); + } + + // Get the child widget element. + String childFieldName = writer.parseElementToField( + layerElem.consumeSingleChildElement()); + writer.addStatement("%1$s.add(%2$s);", fieldName, childFieldName); + + // Parse the horizontal layout constraints. + String left = maybeConsumeLengthAttribute(layerElem, "left"); + String right = maybeConsumeLengthAttribute(layerElem, "right"); + String width = maybeConsumeLengthAttribute(layerElem, "width"); + + if (left != null) { + if (right != null) { + if (width != null) { + writer.die(ERR_TOO_MANY, elem, layerElem, "horizontal"); + } + generateConstraint(fieldName, childFieldName, "LeftRight", left, + right, writer); + } else if (width != null) { + generateConstraint(fieldName, childFieldName, "LeftWidth", left, + width, writer); + } else { + writer.die(ERR_PAIRING, elem, layerElem, "left", "right", "width"); + } + } else if (right != null) { + if (width != null) { + generateConstraint(fieldName, childFieldName, "RightWidth", right, + width, writer); + } else { + writer.die(ERR_PAIRING, elem, layerElem, "right", "left", "width"); + } + } + + // Parse the vertical layout constraints. + String top = maybeConsumeLengthAttribute(layerElem, "top"); + String bottom = maybeConsumeLengthAttribute(layerElem, "bottom"); + String height = maybeConsumeLengthAttribute(layerElem, "height"); + + if (top != null) { + if (bottom != null) { + if (height != null) { + writer.die(ERR_TOO_MANY, elem, layerElem, "vertical"); + } + generateConstraint(fieldName, childFieldName, "TopBottom", top, + bottom, writer); + } else if (height != null) { + generateConstraint(fieldName, childFieldName, "TopHeight", top, + height, writer); + } else { + writer.die(ERR_PAIRING, elem, layerElem, "top", "bottom", "height"); + } + } else if (bottom != null) { + if (height != null) { + generateConstraint(fieldName, childFieldName, "BottomHeight", bottom, + height, writer); + } else { + writer.die(ERR_PAIRING, elem, layerElem, "bottom", "top", "height"); + } + } + } + } + + private void generateConstraint(String panelName, String widgetName, + String constraintName, String first, String second, UiBinderWriter writer) { + writer.addStatement("%s.setWidget%s(%s, %s, %s);", panelName, + constraintName, widgetName, first, second); + } + + private boolean isElementType(XMLElement parent, XMLElement child, String type) { + return parent.getNamespaceUri().equals(child.getNamespaceUri()) + && type.equals(child.getLocalName()); + } + + private String maybeConsumeLengthAttribute(XMLElement elem, String name) + throws UnableToCompleteException { + return elem.hasAttribute(name) ? elem.consumeLengthAttribute(name) : null; + } +} ======================================= --- /dev/null +++ /trunk/user/test/com/google/gwt/uibinder/attributeparsers/LengthAttributeParserTest.java Thu Nov 19 12:57:33 2009 @@ -0,0 +1,149 @@ +/* + * 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.attributeparsers; + +import static com.google.gwt.uibinder.attributeparsers.LengthAttributeParser.UNIT; + +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JEnumType; +import com.google.gwt.core.ext.typeinfo.TypeOracle; +import com.google.gwt.dev.javac.CompilationState; +import com.google.gwt.dev.javac.CompilationStateBuilder; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.uibinder.rebind.MortalLogger; +import com.google.gwt.uibinder.test.UiJavaResources; + +import junit.framework.TestCase; + +/** + * Tests {...@link LengthAttributeParser}. + */ +public class LengthAttributeParserTest extends TestCase { + + private LengthAttributeParser parser; + + @Override + public void setUp() throws Exception { + super.setUp(); + + MortalLogger logger = MortalLogger.NULL; + + CompilationState state = CompilationStateBuilder.buildFrom( + logger.getTreeLogger(), UiJavaResources.getUiResources()); + TypeOracle types = state.getTypeOracle(); + + FieldReferenceConverter converter = new FieldReferenceConverter(null); + DoubleAttributeParser doubleParser = new DoubleAttributeParser(converter, + types.parse("double"), logger); + + JEnumType enumType = (JEnumType) types.findType( + Unit.class.getCanonicalName()).isEnum(); + EnumAttributeParser enumParser = new EnumAttributeParser(converter, + enumType, logger); + parser = new LengthAttributeParser(doubleParser, enumParser, logger); + } + + public void testGood() throws UnableToCompleteException { + assertEquals(lengthString("0", "PX"), parser.parse("0")); + assertEquals(lengthString("0", "PT"), parser.parse("0pt")); + + assertEquals(lengthString("1", "PX"), parser.parse("1")); + + assertEquals(lengthString("1", "PX"), parser.parse("1px")); + assertEquals(lengthString("1", "PCT"), parser.parse("1%")); + assertEquals(lengthString("1", "CM"), parser.parse("1cm")); + assertEquals(lengthString("1", "MM"), parser.parse("1mm")); + assertEquals(lengthString("1", "IN"), parser.parse("1in")); + assertEquals(lengthString("1", "PC"), parser.parse("1pc")); + assertEquals(lengthString("1", "PT"), parser.parse("1pt")); + assertEquals(lengthString("1", "EM"), parser.parse("1em")); + assertEquals(lengthString("1", "EX"), parser.parse("1ex")); + + assertEquals(lengthString("1", "PX"), parser.parse("1PX")); + assertEquals(lengthString("1", "PCT"), parser.parse("1PCT")); + assertEquals(lengthString("1", "CM"), parser.parse("1CM")); + assertEquals(lengthString("1", "MM"), parser.parse("1MM")); + assertEquals(lengthString("1", "IN"), parser.parse("1IN")); + assertEquals(lengthString("1", "PC"), parser.parse("1PC")); + assertEquals(lengthString("1", "PT"), parser.parse("1PT")); + assertEquals(lengthString("1", "EM"), parser.parse("1EM")); + assertEquals(lengthString("1", "EX"), parser.parse("1EX")); + + assertEquals(lengthString("2.5", "EM"), parser.parse("2.5em")); + + assertEquals(lengthString("1", "EM"), parser.parse("1 em")); + + assertEquals("(double)foo.value(), " + UNIT + ".PX", + parser.parse("{foo.value}px")); + assertEquals("1, foo.unit()", + parser.parse("1{foo.unit}")); + assertEquals("(double)foo.value(), foo.unit()", + parser.parse("{foo.value}{foo.unit}")); + } + + public void testBad() { + // Garbage. + try { + parser.parse("fnord"); + fail("Expected UnableToCompleteException"); + } catch (UnableToCompleteException e) { + /* pass */ + } + + // Non-decimal value. + try { + parser.parse("xpx"); + fail("Expected UnableToCompleteException"); + } catch (UnableToCompleteException e) { + /* pass */ + } + + // Raw unit, no value. + try { + parser.parse("px"); + fail("Expected UnableToCompleteException"); + } catch (UnableToCompleteException e) { + /* pass */ + } + + // 0, but with invalid unit. + try { + parser.parse("0foo"); + fail("Expected UnableToCompleteException"); + } catch (UnableToCompleteException e) { + /* pass */ + } + + // Too many braces cases. + try { + parser.parse("{{foo.value}px"); + fail("Expected UnableToCompleteException"); + } catch (UnableToCompleteException e) { + /* pass */ + } + + try { + parser.parse("1{{foo.unit}"); + fail("Expected UnableToCompleteException"); + } catch (UnableToCompleteException e) { + /* pass */ + } + } + + private String lengthString(String value, String unit) { + return value + ", " + UNIT + "." + unit; + } +} ======================================= --- /dev/null +++ /trunk/user/test/com/google/gwt/uibinder/elementparsers/LayoutPanelParserTest.java Thu Nov 19 12:57:33 2009 @@ -0,0 +1,216 @@ +/* + * 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.elementparsers; + +import com.google.gwt.core.ext.UnableToCompleteException; + +import junit.framework.TestCase; + +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.util.Iterator; + +/** + * A unit test. Guess what of. + */ +public class LayoutPanelParserTest extends TestCase { + + private static final String PARSED_TYPE = "com.google.gwt.user.client.ui.LayoutPanel"; + + private ElementParserTester tester; + + @Override + public void setUp() throws Exception { + super.setUp(); + tester = new ElementParserTester(PARSED_TYPE, new LayoutPanelParser()); + } + + public void testBadChild() throws SAXException, IOException { + StringBuffer b = new StringBuffer(); + b.append("<g:LayoutPanel>"); + b.append(" <g:blah/>"); + b.append("</g:LayoutPanel>"); + + try { + tester.parse(b.toString()); + fail(); + } catch (UnableToCompleteException e) { + assertTrue("expect \"only g:layer\" error", + tester.logger.died.contains("only <g:layer> children")); + } + } + + public void testBadValue() throws SAXException, IOException { + StringBuffer b = new StringBuffer(); + b.append("<g:LayoutPanel>"); + b.append(" <g:layer left='goosnarg'><g:HTML/></g:layer>"); + b.append("</g:LayoutPanel>"); + + try { + tester.parse(b.toString()); + fail(); + } catch (UnableToCompleteException e) { + assertTrue("expect \"Unable to parse\" error", + tester.logger.died.contains("Unable to parse")); + } + } + + public void testHappy() throws UnableToCompleteException, SAXException, + IOException { + StringBuffer b = new StringBuffer(); + b.append("<g:LayoutPanel>"); + b.append(" <g:layer>"); + b.append(" <g:Label id='foo0'>nada</g:Label>"); + b.append(" </g:layer>"); + + b.append(" <g:layer left='1em' width='1px'>"); + b.append(" <g:Label id='foo1'>left-width</g:Label>"); + b.append(" </g:layer>"); + b.append(" <g:layer right='1em' width='1px'>"); + b.append(" <g:Label id='foo2'>right-width</g:Label>"); + b.append(" </g:layer>"); + b.append(" <g:layer left='1em' right='1px'>"); + b.append(" <g:Label id='foo3'>left-right</g:Label>"); + b.append(" </g:layer>"); + + b.append(" <g:layer top='1em' height='50%'>"); + b.append(" <g:Label id='foo4'>top-height</g:Label>"); + b.append(" </g:layer>"); + b.append(" <g:layer bottom='1em' height='50%'>"); + b.append(" <g:Label id='foo5'>bottom-height</g:Label>"); + b.append(" </g:layer>"); + b.append(" <g:layer top='1em' bottom='50%'>"); + b.append(" <g:Label id='foo6'>top-bottom</g:Label>"); + b.append(" </g:layer>"); + + b.append(" <g:layer top='{foo.value}em' height='50{foo.unit}'>"); + b.append(" <g:Label id='foo7'>top-height</g:Label>"); + b.append(" </g:layer>"); + b.append("</g:LayoutPanel>"); + + String[] expected = { + "fieldName.add(<g:Label id='foo0'>);", + + "fieldName.add(<g:Label id='foo1'>);", + "fieldName.setWidgetLeftWidth(<g:Label id='foo1'>, 1, " + + "com.google.gwt.dom.client.Style.Unit.EM, 1, com.google.gwt.dom.client.Style.Unit.PX);", + "fieldName.add(<g:Label id='foo2'>);", + "fieldName.setWidgetRightWidth(<g:Label id='foo2'>, 1, " + + "com.google.gwt.dom.client.Style.Unit.EM, 1, com.google.gwt.dom.client.Style.Unit.PX);", + "fieldName.add(<g:Label id='foo3'>);", + "fieldName.setWidgetLeftRight(<g:Label id='foo3'>, 1, " + + "com.google.gwt.dom.client.Style.Unit.EM, 1, com.google.gwt.dom.client.Style.Unit.PX);", + + "fieldName.add(<g:Label id='foo4'>);", + "fieldName.setWidgetTopHeight(<g:Label id='foo4'>, 1, " + + "com.google.gwt.dom.client.Style.Unit.EM, 50, com.google.gwt.dom.client.Style.Unit.PCT);", + "fieldName.add(<g:Label id='foo5'>);", + "fieldName.setWidgetBottomHeight(<g:Label id='foo5'>, 1, " + + "com.google.gwt.dom.client.Style.Unit.EM, 50, com.google.gwt.dom.client.Style.Unit.PCT);", + "fieldName.add(<g:Label id='foo6'>);", + "fieldName.setWidgetTopBottom(<g:Label id='foo6'>, 1, " + + "com.google.gwt.dom.client.Style.Unit.EM, 50, com.google.gwt.dom.client.Style.Unit.PCT);", + + "fieldName.add(<g:Label id='foo7'>);", + "fieldName.setWidgetTopHeight(<g:Label id='foo7'>, (double)foo.value(), " + + "com.google.gwt.dom.client.Style.Unit.EM, 50, foo.unit());" }; + + 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 testLonelyBottom() throws SAXException, IOException { + StringBuffer b = new StringBuffer(); + b.append("<g:LayoutPanel>"); + b.append(" <g:layer bottom='0'><g:HTML/></g:layer>"); + b.append("</g:LayoutPanel>"); + + try { + tester.parse(b.toString()); + fail(); + } catch (UnableToCompleteException e) { + assertTrue("expect \"must be paired\" error", + tester.logger.died.contains("must be paired")); + } + } + + public void testLonelyLeft() throws SAXException, IOException { + StringBuffer b = new StringBuffer(); + b.append("<g:LayoutPanel>"); + b.append(" <g:layer left='0'><g:HTML/></g:layer>"); + b.append("</g:LayoutPanel>"); + + try { + tester.parse(b.toString()); + fail(); + } catch (UnableToCompleteException e) { + assertTrue("expect \"must be paired\" error", + tester.logger.died.contains("must be paired")); + } + } + + public void testLonelyRight() throws SAXException, IOException { + StringBuffer b = new StringBuffer(); + b.append("<g:LayoutPanel>"); + b.append(" <g:layer right='0'><g:HTML/></g:layer>"); + b.append("</g:LayoutPanel>"); + + try { + tester.parse(b.toString()); + fail(); + } catch (UnableToCompleteException e) { + assertTrue("expect \"must be paired\" error", + tester.logger.died.contains("must be paired")); + } + } + + public void testLonelyTop() throws SAXException, IOException { + StringBuffer b = new StringBuffer(); + b.append("<g:LayoutPanel>"); + b.append(" <g:layer top='0'><g:HTML/></g:layer>"); + b.append("</g:LayoutPanel>"); + + try { + tester.parse(b.toString()); + fail(); + } catch (UnableToCompleteException e) { + assertTrue("expect \"must be paired\" error", + tester.logger.died.contains("must be paired")); + } + } + + public void testOverConstrained() throws SAXException, IOException { + StringBuffer b = new StringBuffer(); + b.append("<g:LayoutPanel>"); + b.append(" <g:layer left='0' width='0' right='0'><g:HTML/></g:layer>"); + b.append("</g:LayoutPanel>"); + + try { + tester.parse(b.toString()); + fail(); + } catch (UnableToCompleteException e) { + assertTrue("expect \"too many\" error", + tester.logger.died.contains("too many")); + } + } +} ======================================= --- /trunk/user/javadoc/com/google/gwt/examples/StackLayoutPanelExample.java Tue Nov 3 14:14:13 2009 +++ /trunk/user/javadoc/com/google/gwt/examples/StackLayoutPanelExample.java Thu Nov 19 12:57:33 2009 @@ -26,9 +26,9 @@ public void onModuleLoad() { // Create a three-item stack, with headers sized in EMs. StackLayoutPanel p = new StackLayoutPanel(Unit.EM); - p.add(new HTML("this"), new HTML("[this]"), 128); - p.add(new HTML("that"), new HTML("[that]"), 384); - p.add(new HTML("the other"), new HTML("[the other]"), 0); + p.add(new HTML("this"), new HTML("[this]"), 4); + p.add(new HTML("that"), new HTML("[that]"), 4); + p.add(new HTML("the other"), new HTML("[the other]"), 4); // Attach the LayoutPanel to the RootLayoutPanel. The latter will listen for // resize events on the window to ensure that its children are informed of ======================================= --- /trunk/user/src/com/google/gwt/uibinder/attributeparsers/AttributeParsers.java Wed Nov 11 22:08:47 2009 +++ /trunk/user/src/com/google/gwt/uibinder/attributeparsers/AttributeParsers.java Thu Nov 19 12:57:33 2009 @@ -37,6 +37,7 @@ private static final String STRING = String.class.getCanonicalName(); private static final String DOUBLE = "double"; private static final String BOOLEAN = "boolean"; + private static final String UNIT = "com.google.gwt.dom.client.Style.Unit"; private final MortalLogger logger; private final FieldReferenceConverter converter; @@ -77,6 +78,11 @@ addAttributeParser(STRING, new StringAttributeParser(converter, types.parse(STRING))); + + EnumAttributeParser unitParser = new EnumAttributeParser(converter, + (JEnumType) types.parse(UNIT), logger); + addAttributeParser(DOUBLE + "," + UNIT, new LengthAttributeParser( + doubleParser, unitParser, logger)); } catch (TypeOracleException e) { throw new RuntimeException(e); } ======================================= --- /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java Mon Nov 16 10:04:26 2009 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java Thu Nov 19 12:57:33 2009 @@ -941,6 +941,7 @@ addWidgetParser("CellPanel"); addWidgetParser("CustomButton"); addWidgetParser("DialogBox"); + addWidgetParser("LayoutPanel"); addWidgetParser("DockLayoutPanel"); addWidgetParser("StackLayoutPanel"); addWidgetParser("TabLayoutPanel"); ======================================= --- /trunk/user/src/com/google/gwt/uibinder/rebind/XMLElement.java Mon Nov 16 10:04:26 2009 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/XMLElement.java Thu Nov 19 12:57:33 2009 @@ -16,9 +16,11 @@ 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.JType; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.core.ext.typeinfo.TypeOracleException; +import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.uibinder.attributeparsers.AttributeParser; import com.google.gwt.uibinder.attributeparsers.AttributeParsers; @@ -223,7 +225,7 @@ */ public String consumeAttributeWithDefault(String name, String defaultValue, JType type) throws UnableToCompleteException { - return consumeAttributeWithDefault(name, defaultValue, new JType[] {type}); + return consumeAttributeWithDefault(name, defaultValue, new JType[] { type }); } /** @@ -442,6 +444,21 @@ clearChildren(elem); return buf.toString().trim(); } + + /** + * Convenience method for parsing the named attribute as a CSS length value. + * + * @return a (double, Unit) pair literal, an expression that will evaluate to + * such a pair in the generated code, or "" if there is no such + * attribute + * + * @throws UnableToCompleteException on unparseable value + */ + public String consumeLengthAttribute(String name) + throws UnableToCompleteException { + return consumeAttributeWithDefault(name, "", new JType[] { getDoubleType(), + getUnitType() }); + } /** * Consumes all attributes, and returns a string representing the entire @@ -516,10 +533,9 @@ public String consumeRequiredAttribute(String name, JType... types) throws UnableToCompleteException { /* - * TODO(rjrjr) We have to get the attribute to - * get the parser, and we must get the attribute before we consume the - * value. This nasty subtlety is all down to BundleParsers, which we'll - * hopefully kill off soon. + * TODO(rjrjr) We have to get the attribute to get the parser, and we must + * get the attribute before we consume the value. This nasty subtlety is all + * down to BundleParsers, which we'll hopefully kill off soon. */ XMLAttribute attribute = getAttribute(name); if (attribute == null) { @@ -807,7 +823,8 @@ private JType getImageResourceType() { if (imageResourceType == null) { - imageResourceType = oracle.findType(ImageResource.class.getCanonicalName()); + imageResourceType = oracle.findType( + ImageResource.class.getCanonicalName()); } return imageResourceType; } @@ -843,4 +860,8 @@ } return stringType; } -} + + private JClassType getUnitType() { + return oracle.findType(Unit.class.getCanonicalName()).isEnum(); + } +} ======================================= --- /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java Mon Nov 16 15:06:51 2009 +++ /trunk/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java Thu Nov 19 12:57:33 2009 @@ -18,11 +18,13 @@ import com.google.gwt.uibinder.attributeparsers.CssNameConverterTest; import com.google.gwt.uibinder.attributeparsers.FieldReferenceConverterTest; import com.google.gwt.uibinder.attributeparsers.IntAttributeParserTest; +import com.google.gwt.uibinder.attributeparsers.LengthAttributeParserTest; import com.google.gwt.uibinder.attributeparsers.StrictAttributeParserTest; import com.google.gwt.uibinder.attributeparsers.StringAttributeParserTest; import com.google.gwt.uibinder.elementparsers.DialogBoxParserTest; import com.google.gwt.uibinder.elementparsers.DockLayoutPanelParserTest; import com.google.gwt.uibinder.elementparsers.IsEmptyParserTest; +import com.google.gwt.uibinder.elementparsers.LayoutPanelParserTest; import com.google.gwt.uibinder.elementparsers.StackLayoutPanelParserTest; import com.google.gwt.uibinder.elementparsers.TabLayoutPanelParserTest; import com.google.gwt.uibinder.elementparsers.UIObjectParserTest; @@ -61,11 +63,13 @@ suite.addTestSuite(FieldReferenceConverterTest.class); suite.addTestSuite(StrictAttributeParserTest.class); suite.addTestSuite(StringAttributeParserTest.class); + suite.addTestSuite(LengthAttributeParserTest.class); // elementparsers suite.addTestSuite(DialogBoxParserTest.class); suite.addTestSuite(DockLayoutPanelParserTest.class); suite.addTestSuite(IsEmptyParserTest.class); + suite.addTestSuite(LayoutPanelParserTest.class); suite.addTestSuite(StackLayoutPanelParserTest.class); suite.addTestSuite(TabLayoutPanelParserTest.class); suite.addTestSuite(UIObjectParserTest.class); ======================================= --- /trunk/user/test/com/google/gwt/uibinder/test/UiJavaResources.java Wed Nov 11 22:08:47 2009 +++ /trunk/user/test/com/google/gwt/uibinder/test/UiJavaResources.java Thu Nov 19 12:57:33 2009 @@ -87,6 +87,17 @@ code.append("}\n"); return code; } + }; + public static final MockJavaResource LAYOUT_PANEL = new MockJavaResource( + "com.google.gwt.user.client.ui.LayoutPanel") { + @Override + protected CharSequence getContent() { + StringBuffer code = new StringBuffer(); + code.append("package com.google.gwt.user.client.ui;\n"); + code.append("public class LayoutPanel extends Widget {\n"); + code.append("}\n"); + return code; + } }; public static final MockJavaResource SPLIT_LAYOUT_PANEL = new MockJavaResource( "com.google.gwt.user.client.ui.SplitLayoutPanel") { @@ -117,7 +128,7 @@ StringBuffer code = new StringBuffer(); code.append("package com.google.gwt.dom.client;\n"); code.append("public class Style {\n"); - code.append(" public enum Unit { PX, PT, EM };\n"); + code.append(" public enum Unit { PX, PCT, EM, EX, PT, PC, IN, CM, MM };\n"); code.append("}\n"); return code; } @@ -179,6 +190,7 @@ rtn.add(HAS_HORIZONTAL_ALIGNMENT); rtn.add(HAS_VERTICAL_ALIGNMENT); rtn.add(LABEL); + rtn.add(LAYOUT_PANEL); rtn.add(SPLIT_LAYOUT_PANEL); rtn.add(STACK_LAYOUT_PANEL); rtn.add(STYLE); -- http://groups.google.com/group/Google-Web-Toolkit-Contributors