Revision: 8595
Author: [email protected]
Date: Fri Aug 20 04:44:06 2010
Log: Add <ui:import> to UiBinder to allow access to static fields.
Patch by: bobv
Review by: jgw
Suggested by: sonnyf

Review at http://gwt-code-reviews.appspot.com/781801

http://code.google.com/p/google-web-toolkit/source/detail?r=8595

Added:
 /trunk/user/test/com/google/gwt/uibinder/test/client/Constants.java
Modified:
 /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
 /trunk/user/src/com/google/gwt/uibinder/rebind/model/OwnerClass.java
 /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
 /trunk/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml

=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/uibinder/test/client/Constants.java Fri Aug 20 04:44:06 2010
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2010 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.test.client;
+
+/**
+ * Used to test static imports in UiBinder templates.
+ */
+public class Constants {
+  /**
+   * Tests enum imports.
+   */
+  public enum MyEnum {
+    ENUM_1, ENUM_2;
+  }
+
+  /**
+   * Used to test a wildcard import.
+   */
+  public static class Inner {
+    String instance = "instance";
+    public static String CONST_BAR = "Bar";
+    static String CONST_BAZ = "Baz";
+    protected static String PROTECTED = "protected";
+    @SuppressWarnings("unused")
+    private static String PRIVATE = "private";
+  }
+
+  public static String CONST_FOO = "Foo";
+}
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java Wed Aug 11 09:22:23 2010 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java Fri Aug 20 04:44:06 2010
@@ -17,7 +17,10 @@

 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JField;
 import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
+import com.google.gwt.core.ext.typeinfo.JType;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.resources.client.CssResource;
 import com.google.gwt.resources.client.DataResource;
@@ -39,28 +42,35 @@
 public class UiBinderParser {

   private enum Resource {
-    data {
+    DATA {
       @Override
       void create(UiBinderParser parser, XMLElement elem)
           throws UnableToCompleteException {
         parser.createData(elem);
       }
     },
-    image {
+    IMAGE {
       @Override
       void create(UiBinderParser parser, XMLElement elem)
           throws UnableToCompleteException {
         parser.createImage(elem);
       }
     },
-    style {
+    IMPORT {
+      @Override
+      void create(UiBinderParser parser, XMLElement elem)
+          throws UnableToCompleteException {
+        parser.createImport(elem);
+      }
+    },
+    STYLE {
       @Override
       void create(UiBinderParser parser, XMLElement elem)
           throws UnableToCompleteException {
         parser.createStyle(elem);
       }
     },
-    with {
+    WITH {
       @Override
       void create(UiBinderParser parser, XMLElement elem)
           throws UnableToCompleteException {
@@ -74,8 +84,9 @@

   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";
+  private static final String SOURCE_ATTRIBUTE = "src";
+  private static final String TYPE_ATTRIBUTE = "type";

   // TODO(rjrjr) Make all the ElementParsers receive their dependencies via
   // constructor like this one does, and make this an ElementParser. I want
@@ -130,7 +141,7 @@

   private JClassType consumeCssResourceType(XMLElement elem)
       throws UnableToCompleteException {
-    String typeName = elem.consumeRawAttribute("type", null);
+    String typeName = elem.consumeRawAttribute(TYPE_ATTRIBUTE, null);
     if (typeName == null) {
       return cssResourceType;
     }
@@ -140,7 +151,7 @@

   private JClassType consumeTypeAttribute(XMLElement elem)
       throws UnableToCompleteException {
-    String resourceTypeName = elem.consumeRequiredRawAttribute("type");
+ String resourceTypeName = elem.consumeRequiredRawAttribute(TYPE_ATTRIBUTE);

     JClassType resourceType = oracle.findType(resourceTypeName);
     if (resourceType == null) {
@@ -192,6 +203,49 @@
field.setInitializer(String.format("%s.%s()", bundleClass.getFieldName(),
         imageMethod.getName()));
   }
+
+  /**
+   * Process <code>&lt;ui:import field="com.example.Blah.CONSTANT"></code>.
+   */
+ private void createImport(XMLElement elem) throws UnableToCompleteException { + String rawFieldName = elem.consumeRequiredRawAttribute(FIELD_ATTRIBUTE);
+    if (elem.getAttributeCount() > 0) {
+ writer.die(elem, "Should only find attribute \"%s\"", FIELD_ATTRIBUTE);
+    }
+
+    int idx = rawFieldName.lastIndexOf('.');
+    if (idx < 1) {
+      writer.die(elem, "Attribute %s does not look like a static import "
+          + "reference", FIELD_ATTRIBUTE);
+    }
+    String enclosingName = rawFieldName.substring(0, idx);
+    String constantName = rawFieldName.substring(idx + 1);
+
+    JClassType enclosingType = oracle.findType(enclosingName);
+    if (enclosingType == null) {
+      writer.die(elem, "Unable to locate type %s", enclosingName);
+    }
+
+    if ("*".equals(constantName)) {
+      for (JField field : enclosingType.getFields()) {
+        if (!field.isStatic()) {
+          continue;
+        } else if (field.isPublic()) {
+          // OK
+        } else if (field.isProtected() || field.isPrivate()) {
+          continue;
+        } else if (!enclosingType.getPackage().equals(
+            writer.getOwnerClass().getOwnerType().getPackage())) {
+          // package-protected in another package
+          continue;
+        }
+        createSingleImport(elem, enclosingType, enclosingName + "."
+            + field.getName(), field.getName());
+      }
+    } else {
+      createSingleImport(elem, enclosingType, rawFieldName, constantName);
+    }
+  }

   /**
    * Interprets <ui:with> elements.
@@ -234,6 +288,31 @@
      * do just fine.
      */
   }
+
+ private void createSingleImport(XMLElement elem, JClassType enclosingType,
+      String rawFieldName, String constantName)
+      throws UnableToCompleteException {
+    JField field = enclosingType.findField(constantName);
+    if (field == null) {
+ writer.die(elem, "Unable to locate a field named %s in %s", constantName,
+          enclosingType.getQualifiedSourceName());
+    } else if (!field.isStatic()) {
+      writer.die(elem, "Field %s in type %s is not static", constantName,
+          enclosingType.getQualifiedSourceName());
+    }
+
+    JType importType = field.getType();
+    JClassType fieldType;
+    if (importType instanceof JPrimitiveType) {
+ fieldType = oracle.findType(((JPrimitiveType) importType).getQualifiedBoxedSourceName());
+    } else {
+      fieldType = (JClassType) importType;
+    }
+
+    FieldWriter fieldWriter = fieldManager.registerField(fieldType,
+        constantName);
+    fieldWriter.setInitializer(rawFieldName);
+  }

private void createStyle(XMLElement elem) throws UnableToCompleteException {
     String body = elem.consumeUnescapedInnerText();
@@ -283,8 +362,8 @@

         if (writer.isBinderElement(elem)) {
           try {
- Resource.valueOf(elem.getLocalName()).create(UiBinderParser.this,
-                elem);
+            Resource.valueOf(elem.getLocalName().toUpperCase()).create(
+                UiBinderParser.this, elem);
           } catch (IllegalArgumentException e) {
             writer.die(elem,
"Unknown tag %s, or is not appropriate as a top level element",
=======================================
--- /trunk/user/src/com/google/gwt/uibinder/rebind/model/OwnerClass.java Thu Nov 19 13:38:23 2009 +++ /trunk/user/src/com/google/gwt/uibinder/rebind/model/OwnerClass.java Fri Aug 20 04:44:06 2010
@@ -67,6 +67,8 @@

   private final MortalLogger logger;

+  private final JClassType ownerType;
+
   /**
    * Constructor.
    *
@@ -75,10 +77,15 @@
    */
public OwnerClass(JClassType ownerType, MortalLogger logger) throws UnableToCompleteException {
     this.logger = logger;
+    this.ownerType = ownerType;
     findUiFields(ownerType);
     findUiFactories(ownerType);
     findUiHandlers(ownerType);
   }
+
+  public JClassType getOwnerType() {
+    return ownerType;
+  }

   /**
* Returns the method annotated with @UiFactory which returns the given type.
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java Thu Jul 29 11:09:15 2010 +++ /trunk/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java Fri Aug 20 04:44:06 2010
@@ -448,19 +448,19 @@
* AbsolutePanelParserTest and AbsolutePanelTest are enough to make up for
      * the lack. Leaving this here as a warning to the next guy.
      */
-//    {
-//      Widget w = widgetUi.myAbsolutePanelItemA;
-//      assertNotNull("Widget exists", w);
-//      assertEquals("Widget has left", 1, p.getWidgetLeft(w));
-//      assertEquals("Widget has top", 2, p.getWidgetTop(w));
-//    }
-//
-//    {
-//      Widget w = widgetUi.myAbsolutePanelItemC;
-//      assertNotNull("Widget exists", w);
-//      assertEquals("Widget has left", 10, p.getWidgetLeft(w));
-//      assertEquals("Widget has top", 20, p.getWidgetTop(w));
-//    }
+    // {
+    // Widget w = widgetUi.myAbsolutePanelItemA;
+    // assertNotNull("Widget exists", w);
+    // assertEquals("Widget has left", 1, p.getWidgetLeft(w));
+    // assertEquals("Widget has top", 2, p.getWidgetTop(w));
+    // }
+    //
+    // {
+    // Widget w = widgetUi.myAbsolutePanelItemC;
+    // assertNotNull("Widget exists", w);
+    // assertEquals("Widget has left", 10, p.getWidgetLeft(w));
+    // assertEquals("Widget has top", 20, p.getWidgetTop(w));
+    // }
   }

   public void testStringAttributeIgnoresStaticSetter() {
@@ -537,6 +537,16 @@
     assertEquals(widgetUi.prettyImage.getHeight(),
         widgetUi.simpleSpriteParagraph.getOffsetHeight());
   }
+
+  public void testStaticImport() {
+    assertEquals(Constants.CONST_FOO,
+        widgetUi.bracedParagraph.getAttribute("foo"));
+ assertEquals(Constants.Inner.CONST_BAR + " " + Constants.Inner.CONST_BAZ,
+        widgetUi.bracedParagraph.getAttribute("bar"));
+    assertEquals(Constants.MyEnum.ENUM_1.name() + " "
+        + Constants.MyEnum.ENUM_2.name(),
+        widgetUi.bracedParagraph.getAttribute("enum"));
+  }

   public void suppressForIEfail_testBizarrelyElementedWidgets() {
     assertInOrder(widgetUi.widgetCrazyTable.getInnerHTML().toLowerCase(),
=======================================
--- /trunk/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml Thu Jul 29 11:09:15 2010 +++ /trunk/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml Fri Aug 20 04:44:06 2010
@@ -72,6 +72,17 @@
for a resource to provide arbitrary objects to arbitrary attributes (look for FooLabel)
 </ui:with>

+<ui:import field='com.google.gwt.uibinder.test.client.Constants.CONST_FOO'>
+  Tests the static import of a single constant into the local namespace.
+</ui:import>
+
+<ui:import field='com.google.gwt.uibinder.test.client.Constants.Inner.*'>
+  Tests the static import of multiple constants into the local namespace.
+</ui:import>
+
+<ui:import field='com.google.gwt.uibinder.test.client.Constants.MyEnum.*'>
+  Tests the static import of an enum into the local namespace.
+</ui:import>
 <!--
   Tests creating a CssResource from an external file.
  -->
@@ -164,7 +175,10 @@
   </gwt:Dock>
   <gwt:Dock direction='CENTER'>
     <gwt:HTMLPanel>
- <p ui:field='bracedParagraph' fnord='blah di blah {{foo: "bar"} di blah'><ui:msg>This is a demonstration and test bed of GWT's shiny UiBinder + <p ui:field='bracedParagraph' fnord='blah di blah {{foo: "bar"} di blah'
+        foo='{CONST_FOO}' bar='{CONST_BAR} {CONST_BAZ}'
+        enum='{ENUM_1.name} {ENUM_2.name}' ><ui:msg>This is a
+      demonstration and test bed of GWT's shiny UiBinder
       package. At the moment it works mainly as described in
<a href="http://code.google.com/p/google-web-toolkit-incubator/wiki/DeclarativeUi";
         ui:ph="oldBlogLink">

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to