Revision: 8754
Author: [email protected]
Date: Fri Sep 10 12:29:13 2010
Log: Initial add of IsEditor interface to allow views to work in an Editor
hierarchy without being an Editor.
This patch will serve as a base for an error-aware Editor decorator panel.
Patch by: bobv
Review by: rjrjr

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

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

Added:
 /trunk/user/src/com/google/gwt/editor/client/IsEditor.java
Modified:
 /trunk/user/src/com/google/gwt/editor/client/Editor.java
/trunk/user/src/com/google/gwt/editor/client/impl/AbstractEditorDelegate.java /trunk/user/src/com/google/gwt/editor/rebind/AbstractEditorDriverGenerator.java
 /trunk/user/src/com/google/gwt/editor/rebind/model/EditorAccess.java
 /trunk/user/src/com/google/gwt/editor/rebind/model/EditorModel.java
 /trunk/user/test/com/google/gwt/editor/client/SimpleBeanEditorTest.java
 /trunk/user/test/com/google/gwt/editor/rebind/model/EditorModelTest.java

=======================================
--- /dev/null
+++ /trunk/user/src/com/google/gwt/editor/client/IsEditor.java Fri Sep 10 12:29:13 2010
@@ -0,0 +1,34 @@
+/*
+ * 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.editor.client;
+
+/**
+ * Extended by view objects that wish to participate in an Editor hierarchy, but
+ * that do not implement the {...@link Editor} contract directly.
+ * <p>
+ * It is legal for a type to implement both Editor and IsEditor. In this case,
+ * the Editor returned from {...@link #asEditor()} will be a co-Editor of the
+ * IsEditor instance.
+ *
+ * @param <E> the type of Editor the view object will provide
+ * @see CompositeEditor
+ */
+public interface IsEditor<E extends Editor<?>> {
+  /**
+   * Returns the Editor encapsulated by the view object.
+   */
+  E asEditor();
+}
=======================================
--- /trunk/user/src/com/google/gwt/editor/client/Editor.java Thu Sep 2 10:32:07 2010 +++ /trunk/user/src/com/google/gwt/editor/client/Editor.java Fri Sep 10 12:29:13 2010
@@ -39,6 +39,10 @@
* <li>Sub-Editors may be null. In this case, the Editor framework will ignore
  * these sub-editors.</li>
  * </ul>
+ * Any exposed field or method whose type is Editor may also use the
+ * {...@link IsEditor} interface to provide an Editor instance. This allows view + * objects to be written that can be attached to an Editor hierarchy without the
+ * view directly implementing an Editor interface.
  *
  * @param <T> the type of object the editor displays.
  */
=======================================
--- /trunk/user/src/com/google/gwt/editor/client/impl/AbstractEditorDelegate.java Thu Sep 9 11:46:06 2010 +++ /trunk/user/src/com/google/gwt/editor/client/impl/AbstractEditorDelegate.java Fri Sep 10 12:29:13 2010
@@ -97,8 +97,8 @@
     if (getObject() == null) {
       return;
     }
-    flushSubEditors();
     setObject(ensureMutable(getObject()));
+    flushSubEditors();
     flushValues();
   }

=======================================
--- /trunk/user/src/com/google/gwt/editor/rebind/AbstractEditorDriverGenerator.java Thu Sep 9 11:46:06 2010 +++ /trunk/user/src/com/google/gwt/editor/rebind/AbstractEditorDriverGenerator.java Fri Sep 10 12:29:13 2010
@@ -21,6 +21,7 @@
 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.dev.generator.NameFactory;
 import com.google.gwt.dev.util.Name;
 import com.google.gwt.dev.util.Name.BinaryName;
 import com.google.gwt.editor.rebind.model.EditorData;
@@ -29,7 +30,9 @@
 import com.google.gwt.user.rebind.SourceWriter;

 import java.io.PrintWriter;
+import java.util.IdentityHashMap;
 import java.util.List;
+import java.util.Map;

 /**
  * A base class for generating Editor drivers.
@@ -85,6 +88,8 @@
   protected String getEditorDelegate(EditorData delegateData) {
     JClassType edited = delegateData.getEditedType();
     JClassType editor = delegateData.getEditorType();
+ Map<EditorData, String> delegateFields = new IdentityHashMap<EditorData, String>();
+    NameFactory nameFactory = new NameFactory();

     /*
* The binary name of the edited type is included so that the same editor
@@ -139,11 +144,14 @@
       // Fields for the sub-delegates that must be managed
       for (EditorData d : data) {
         if (d.isBeanEditor() || d.isValueAwareEditor()) {
-          sw.println("%s<%s, %s> %sDelegate;",
+          String fieldName = nameFactory.createName(d.getPropertyName()
+              + "Delegate");
+          delegateFields.put(d, fieldName);
+          sw.println("%s<%s, %s> %s;",
               Name.getSourceNameForClass(getEditorDelegateType()),
               d.getEditedType().getParameterizedQualifiedSourceName(),
               d.getEditorType().getParameterizedQualifiedSourceName(),
-              d.getPropertyName());
+              fieldName);
         }
       }

@@ -156,8 +164,7 @@
           String subDelegateType = getEditorDelegate(d);
           sw.println("if (editor.%s != null) {", d.getSimpleExpression());
           sw.indent();
-          sw.println("%sDelegate = new %s();", d.getPropertyName(),
-              subDelegateType);
+ sw.println("%s = new %s();", delegateFields.get(d), subDelegateType);
           writeDelegateInitialization(sw, d);
           sw.outdent();
           sw.println("}");
@@ -171,13 +178,17 @@
       sw.indent();
       for (EditorData d : data) {
         if (d.isBeanEditor() || d.isValueAwareEditor()) {
-          sw.println("if (%1$sDelegate != null) { %1$sDelegate.flush();",
-              d.getPropertyName());
+ sw.println("if (%1$s != null) { %1$s.flush();", delegateFields.get(d));
           if (d.getSetterName() != null) {
- String mutableObjectExpression = mutableObjectExpression(String.format(
-                "getObject()%s", d.getBeanOwnerExpression()));
-            sw.println("%s.%s(%sDelegate.getObject());",
- mutableObjectExpression, d.getSetterName(), d.getPropertyName());
+            String mutableObjectExpression;
+            if (d.getBeanOwnerExpression().length() > 0) {
+ mutableObjectExpression = mutableObjectExpression(String.format(
+                  "getObject()%s", d.getBeanOwnerExpression()));
+            } else {
+              mutableObjectExpression = "getObject()";
+            }
+            sw.println("%s.%s(%s.getObject());", mutableObjectExpression,
+                d.getSetterName(), delegateFields.get(d));
           }
           sw.println("}");
         }
=======================================
--- /trunk/user/src/com/google/gwt/editor/rebind/model/EditorAccess.java Thu Sep 9 11:46:06 2010 +++ /trunk/user/src/com/google/gwt/editor/rebind/model/EditorAccess.java Fri Sep 10 12:29:13 2010
@@ -18,7 +18,10 @@
 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.JType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.editor.client.Editor;
+import com.google.gwt.editor.client.IsEditor;
 import com.google.gwt.editor.client.Editor.Path;

 /**
@@ -30,6 +33,14 @@
   public static EditorAccess root(JClassType rootType) {
     return new EditorAccess("", rootType, "");
   }
+
+  /**
+   * Constructs an EditorAccess for an IsEditor type.
+   */
+  public static EditorAccess via(EditorAccess access, JClassType type) {
+    return new EditorAccess(access.getPath(), type, access.getExpresson()
+        + ".asEditor()");
+  }

   public static EditorAccess via(JField field) {
     String path = field.getName();
@@ -57,6 +68,16 @@
         method.getName() + "()");
   }

+  private static boolean isEditor(JType type) {
+    JClassType classType = type.isClassOrInterface();
+    if (classType == null) {
+      return false;
+    }
+    TypeOracle oracle = classType.getOracle();
+ return oracle.findType(IsEditor.class.getName()).isAssignableFrom(classType);
+  }
+
+  private final boolean isEditor;
   private final String expression;
   private final String path;
   private final JClassType type;
@@ -65,6 +86,7 @@
     this.expression = expression;
     this.path = path;
     this.type = type;
+    isEditor = isEditor(type);
   }

   public JClassType getEditorType() {
@@ -78,6 +100,14 @@
   public String getPath() {
     return path;
   }
+
+  /**
+   * Returns <code> true if the editor accessed by this EditorAccess
+   * implements the IsEditor interface.
+   */
+  public boolean isEditor() {
+    return isEditor;
+  }

   /**
    * For debugging use only.
=======================================
--- /trunk/user/src/com/google/gwt/editor/rebind/model/EditorModel.java Thu Sep 9 11:46:06 2010 +++ /trunk/user/src/com/google/gwt/editor/rebind/model/EditorModel.java Fri Sep 10 12:29:13 2010
@@ -27,6 +27,7 @@
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.editor.client.CompositeEditor;
 import com.google.gwt.editor.client.Editor;
+import com.google.gwt.editor.client.IsEditor;

 import java.util.ArrayList;
 import java.util.Arrays;
@@ -77,18 +78,29 @@
       throws UnableToCompleteException {
     JClassType editorIntf = editorType.getOracle().findType(
         Editor.class.getName());
- assert editorIntf.isAssignableFrom(editorType) : editorType.getQualifiedSourceName()
-        + " is not an Editor";
-
- for (JClassType supertype : editorType.getFlattenedSupertypeHierarchy()) {
-      JParameterizedType parameterized = supertype.isParameterized();
-      if (parameterized != null) {
-        // Found the Editor<Foo> supertype
-        if (editorIntf.equals(parameterized.getBaseType())) {
-          assert parameterized.getTypeArgs().length == 1;
-          return parameterized.getTypeArgs()[0].isClassOrInterface();
-        }
-      }
+    JClassType parameterization[] = findParameterizationOf(editorIntf,
+        editorType);
+    if (parameterization != null) {
+      return parameterization[0];
+    }
+ logger.log(TreeLogger.ERROR, noEditorParameterizationMessage(editorIntf,
+        editorType));
+    throw new UnableToCompleteException();
+  }
+
+  /**
+ * Given type assignable to <code>IsEditor&lt;Foo, FooEditor></code>, return + * <code>FooEditor</code>. It is an error to call this method with a type not
+   * assignable to {...@link IsEditor}.
+   */
+  static JClassType calculateIsEditedType(TreeLogger logger,
+      JClassType editorType) throws UnableToCompleteException {
+    JClassType editorIntf = editorType.getOracle().findType(
+        IsEditor.class.getName());
+    JClassType[] parameterization = findParameterizationOf(editorIntf,
+        editorType);
+    if (parameterization != null) {
+      return parameterization[0];
     }
logger.log(TreeLogger.ERROR, noEditorParameterizationMessage(editorIntf,
         editorType));
@@ -142,6 +154,25 @@
return String.format("Unexpected input type: %s is not assignable from %s", driverType.getQualifiedSourceName(), intf.getQualifiedSourceName());
   }
+
+  private static JClassType[] findParameterizationOf(JClassType intfType,
+      JClassType subType) {
+ assert intfType.isAssignableFrom(subType) : subType.getParameterizedQualifiedSourceName()
+        + " is not assignable to "
+        + subType.getParameterizedQualifiedSourceName();
+
+    for (JClassType supertype : subType.getFlattenedSupertypeHierarchy()) {
+      JParameterizedType parameterized = supertype.isParameterized();
+      if (parameterized != null) {
+        // Found the desired supertype
+        if (intfType.equals(parameterized.getBaseType())) {
+          assert parameterized.getTypeArgs().length == 1;
+          return parameterized.getTypeArgs();
+        }
+      }
+    }
+    return null;
+  }

   /**
    * The structural model.
@@ -156,6 +187,11 @@

   private final EditorData editorSoFar;

+  /**
+   * A reference to {...@link IsEditor}.
+   */
+  private final JGenericType isEditorIntf;
+
   private final TreeLogger logger;

   private final EditorModel parentModel;
@@ -193,6 +229,8 @@
     TypeOracle oracle = intf.getOracle();
     editorIntf = oracle.findType(Editor.class.getName()).isGenericType();
     assert editorIntf != null : "No Editor type";
+ isEditorIntf = oracle.findType(IsEditor.class.getName()).isGenericType();
+    assert isEditorIntf != null : "No IsEditor type";

     JClassType[] interfaces = intf.getImplementedInterfaces();
     if (interfaces.length != 1) {
@@ -218,6 +256,7 @@
     this.editorIntf = parent.editorIntf;
     this.editorType = editorType;
     this.editorSoFar = subEditor;
+    this.isEditorIntf = parent.isEditorIntf;
     this.parentModel = parent;
     this.proxyType = proxyType;
     this.typeData = parent.typeData;
@@ -266,14 +305,15 @@
         if (field.isPrivate() || field.isStatic()) {
           continue;
         }
-        JClassType fieldClassType = field.getType().isClassOrInterface();
-        if (fieldClassType != null
-            && editorIntf.isAssignableFrom(fieldClassType)) {
-          EditorData data = createEditorData(EditorAccess.via(field));
-          flatData.add(data);
-          toReturn.add(data);
-          if (!data.isLeafValueEditor()) {
-            descendIntoSubEditor(toReturn, data);
+        JType fieldClassType = field.getType();
+        if (shouldExamine(fieldClassType)) {
+ List<EditorData> data = createEditorData(EditorAccess.via(field));
+          flatData.addAll(data);
+          toReturn.addAll(data);
+          for (EditorData d : data) {
+            if (!d.isLeafValueEditor()) {
+              descendIntoSubEditor(toReturn, d);
+            }
           }
         }
       }
@@ -281,15 +321,22 @@
         if (method.isPrivate() || method.isStatic()) {
           continue;
         }
- JClassType methodReturnType = method.getReturnType().isClassOrInterface();
-        if (methodReturnType != null
-            && editorIntf.isAssignableFrom(methodReturnType)
+        JType methodReturnType = method.getReturnType();
+        if (shouldExamine(methodReturnType)
             && method.getParameters().length == 0) {
-          EditorData data = createEditorData(EditorAccess.via(method));
-          flatData.add(data);
-          toReturn.add(data);
-          if (!data.isLeafValueEditor()) {
-            descendIntoSubEditor(toReturn, data);
+          EditorAccess access = EditorAccess.via(method);
+          if (access.getPath().equals("as")
+              && isEditorIntf.isAssignableFrom(editorType)) {
+            // Ignore IsEditor.asEditor()
+            continue;
+          }
+          List<EditorData> data = createEditorData(access);
+          flatData.addAll(data);
+          toReturn.addAll(data);
+          for (EditorData d : data) {
+            if (!d.isLeafValueEditor()) {
+              descendIntoSubEditor(toReturn, d);
+            }
           }
         }
       }
@@ -310,10 +357,25 @@
     return sb.toString();
   }

-  private EditorData createEditorData(EditorAccess access)
+  private List<EditorData> createEditorData(EditorAccess access)
       throws UnableToCompleteException {
     TreeLogger subLogger = logger.branch(TreeLogger.DEBUG, "Examining "
         + access.toString());
+
+    List<EditorData> toReturn = new ArrayList<EditorData>();
+
+    // Are we looking at a view that implements IsEditor?
+    if (access.isEditor()) {
+ EditorAccess subAccess = EditorAccess.via(access, calculateIsEditedType(
+          subLogger, access.getEditorType()));
+      toReturn = createEditorData(subAccess);
+
+      // If an object only implements IsEditor, return now
+      if (!editorIntf.isAssignableFrom(access.getEditorType())) {
+        return toReturn;
+      }
+    }
+
     // Determine the Foo in Editor<Foo>
     JClassType expectedToEdit = calculateEditedType(subLogger,
         access.getEditorType());
@@ -322,8 +384,10 @@
String[] methods = findBeanPropertyMethods(access.getPath(), expectedToEdit);
     assert methods.length == 3;

-    return new EditorData(subLogger, editorSoFar, access, methods[0],
-        methods[1], methods[2]);
+    EditorData data = new EditorData(subLogger, editorSoFar, access,
+        methods[0], methods[1], methods[2]);
+    toReturn.add(data);
+    return toReturn;
   }

   /**
@@ -347,7 +411,8 @@
     if (!data.isLeafValueEditor()) {
EditorModel subModel = new EditorModel(this, data.getEditorType(), data,
           calculateEditedType(logger, data.getEditorType()));
-      accumulator.addAll(Arrays.asList(subModel.getEditorData()));
+      accumulator.addAll(accumulator.indexOf(data) + 1,
+          Arrays.asList(subModel.getEditorData()));
       poisoned |= subModel.poisoned;
     }
   }
@@ -431,4 +496,17 @@
     logger.log(TreeLogger.ERROR, message);
     poisoned = true;
   }
-}
+
+  /**
+   * Returns <code>true</code> if the given type participates in Editor
+   * hierarchies.
+   */
+  private boolean shouldExamine(JType type) {
+    JClassType classType = type.isClassOrInterface();
+    if (classType == null) {
+      return false;
+    }
+    return editorIntf.isAssignableFrom(classType)
+        || isEditorIntf.isAssignableFrom(classType);
+  }
+}
=======================================
--- /trunk/user/test/com/google/gwt/editor/client/SimpleBeanEditorTest.java Thu Sep 9 11:46:06 2010 +++ /trunk/user/test/com/google/gwt/editor/client/SimpleBeanEditorTest.java Fri Sep 10 12:29:13 2010
@@ -60,6 +60,23 @@
     SimpleEditor<String> city = SimpleEditor.of(UNINITIALIZED);
     SimpleEditor<String> street = SimpleEditor.of(UNINITIALIZED);
   }
+
+  class AddressCoEditorView extends LeafAddressEditor implements
+      IsEditor<LeafAddressEditor> {
+    private LeafAddressEditor addressEditor = new LeafAddressEditor();
+
+    public LeafAddressEditor asEditor() {
+      return addressEditor;
+    }
+  }
+
+  class AddressEditorView implements IsEditor<LeafAddressEditor> {
+    LeafAddressEditor addressEditor = new LeafAddressEditor();
+
+    public LeafAddressEditor asEditor() {
+      return addressEditor;
+    }
+  }

   class LeafAddressEditor extends AddressEditor implements
       LeafValueEditor<Address> {
@@ -127,6 +144,24 @@
   interface PersonEditorDriver extends
       SimpleBeanEditorDriver<Person, PersonEditor> {
   }
+
+  class PersonEditorWithAddressEditorView implements Editor<Person> {
+    AddressEditorView addressEditor = new AddressEditorView();
+    SimpleEditor<String> name = SimpleEditor.of(UNINITIALIZED);
+  }
+
+  interface PersonEditorWithAddressEditorViewDriver extends
+      SimpleBeanEditorDriver<Person, PersonEditorWithAddressEditorView> {
+  }
+
+  class PersonEditorWithCoAddressEditorView implements Editor<Person> {
+    AddressCoEditorView addressEditor = new AddressCoEditorView();
+    SimpleEditor<String> name = SimpleEditor.of(UNINITIALIZED);
+  }
+
+  interface PersonEditorWithCoAddressEditorViewDriver extends
+      SimpleBeanEditorDriver<Person, PersonEditorWithCoAddressEditorView> {
+  }

   class PersonEditorWithLeafAddressEditor implements Editor<Person> {
     LeafAddressEditor addressEditor = new LeafAddressEditor();
@@ -244,6 +279,38 @@
     assertEquals("12345", person.address.street);
     assertEquals("David", person.manager.name);
   }
+
+  /**
+   * Test the use of the IsEditor interface that allows a view object to
+   * encapsulate its Editor.
+   */
+  public void testIsEditorView() {
+ PersonEditorWithAddressEditorView personEditor = new PersonEditorWithAddressEditorView(); + PersonEditorWithAddressEditorViewDriver driver = GWT.create(PersonEditorWithAddressEditorViewDriver.class);
+    testLeafAddressEditor(driver, personEditor,
+        personEditor.addressEditor.asEditor());
+  }
+
+  /**
+   * Test the use of the IsEditor interface that allows a view object to
+   * encapsulate its Editor as well as be an editor itself.
+   */
+  public void testIsEditorViewWithCoEditorA() {
+ PersonEditorWithCoAddressEditorView personEditor = new PersonEditorWithCoAddressEditorView(); + PersonEditorWithCoAddressEditorViewDriver driver = GWT.create(PersonEditorWithCoAddressEditorViewDriver.class); + testLeafAddressEditor(driver, personEditor, personEditor.addressEditor);
+  }
+
+  /**
+   * Test the use of the IsEditor interface that allows a view object to
+   * encapsulate its Editor as well as be an editor itself.
+   */
+  public void testIsEditorViewWithCoEditorB() {
+ PersonEditorWithCoAddressEditorView personEditor = new PersonEditorWithCoAddressEditorView(); + PersonEditorWithCoAddressEditorViewDriver driver = GWT.create(PersonEditorWithCoAddressEditorViewDriver.class);
+    testLeafAddressEditor(driver, personEditor,
+        personEditor.addressEditor.asEditor());
+  }

   /**
    * We want to verify that the sub-editors of a LeafValueEditor are not
@@ -359,6 +426,14 @@
     assertEquals(editors, new ArrayList<SimpleEditor<String>>(
         positionMap.values()));
   }
+
+  public void testValueAwareEditorInDeclaredSlot() {
+ PersonEditorWithValueAwareAddressEditorDriver driver = GWT.create(PersonEditorWithValueAwareAddressEditorDriver.class); + PersonEditorWithValueAwareAddressEditor personEditor = new PersonEditorWithValueAwareAddressEditor();
+    ValueAwareAddressEditor addressEditor = personEditor.addressEditor;
+
+    testValueAwareAddressEditor(driver, personEditor, addressEditor);
+  }

   public void testValueAwareEditorInPlainSlot() {
     PersonEditorDriver driver = GWT.create(PersonEditorDriver.class);
@@ -371,14 +446,6 @@

     testValueAwareAddressEditor(driver, personEditor, addressEditor);
   }
-
-  public void testValueAwareEditorInDeclaredSlot() {
- PersonEditorWithValueAwareAddressEditorDriver driver = GWT.create(PersonEditorWithValueAwareAddressEditorDriver.class); - PersonEditorWithValueAwareAddressEditor personEditor = new PersonEditorWithValueAwareAddressEditor();
-    ValueAwareAddressEditor addressEditor = personEditor.addressEditor;
-
-    testValueAwareAddressEditor(driver, personEditor, addressEditor);
-  }

   public void testValueAwareLeafValueEditorInDeclaredSlot() {
PersonEditorWithValueAwareLeafAddressEditor personEditor = new PersonEditorWithValueAwareLeafAddressEditor();
@@ -419,52 +486,52 @@
     person.manager = manager;
   }

-  private <T extends Editor<Person>> void testValueAwareAddressEditor(
+  private <T extends Editor<Person>> void testLeafAddressEditor(
       SimpleBeanEditorDriver<Person, T> driver, T personEditor,
-      ValueAwareAddressEditor addressEditor) {
+      LeafAddressEditor addressEditor) {
     Address oldAddress = person.address;
     // Initialize
     driver.initialize(personEditor);
     assertEquals(0, addressEditor.setValueCalled);
-    assertEquals(0, addressEditor.setDelegateCalled);
-    assertEquals(0, addressEditor.flushCalled);
+    assertEquals(0, addressEditor.getValueCalled);

     // Edit
     driver.edit(person);
     assertEquals(1, addressEditor.setValueCalled);
-    assertEquals(1, addressEditor.setDelegateCalled);
-    assertEquals(0, addressEditor.flushCalled);
-    assertEquals("City", addressEditor.city.getValue());
+    assertEquals(0, addressEditor.getValueCalled);
+    assertEquals(UNINITIALIZED, addressEditor.city.getValue());

     // Flush
     driver.flush();
     assertEquals(1, addressEditor.setValueCalled);
-    assertEquals(1, addressEditor.setDelegateCalled);
-    assertEquals(1, addressEditor.flushCalled);
-    assertSame(oldAddress, person.address);
+    assertEquals(1, addressEditor.getValueCalled);
+    assertNotSame(oldAddress, person.address);
     assertSame(person.address, addressEditor.value);
   }

-  private <T extends Editor<Person>> void testLeafAddressEditor(
+  private <T extends Editor<Person>> void testValueAwareAddressEditor(
       SimpleBeanEditorDriver<Person, T> driver, T personEditor,
-      LeafAddressEditor addressEditor) {
+      ValueAwareAddressEditor addressEditor) {
     Address oldAddress = person.address;
     // Initialize
     driver.initialize(personEditor);
     assertEquals(0, addressEditor.setValueCalled);
-    assertEquals(0, addressEditor.getValueCalled);
+    assertEquals(0, addressEditor.setDelegateCalled);
+    assertEquals(0, addressEditor.flushCalled);

     // Edit
     driver.edit(person);
     assertEquals(1, addressEditor.setValueCalled);
-    assertEquals(0, addressEditor.getValueCalled);
-    assertEquals(UNINITIALIZED, addressEditor.city.getValue());
+    assertEquals(1, addressEditor.setDelegateCalled);
+    assertEquals(0, addressEditor.flushCalled);
+    assertEquals("City", addressEditor.city.getValue());

     // Flush
     driver.flush();
     assertEquals(1, addressEditor.setValueCalled);
-    assertEquals(1, addressEditor.getValueCalled);
-    assertNotSame(oldAddress, person.address);
+    assertEquals(1, addressEditor.setDelegateCalled);
+    assertEquals(1, addressEditor.flushCalled);
+    assertSame(oldAddress, person.address);
     assertSame(person.address, addressEditor.value);
   }
 }
=======================================
--- /trunk/user/test/com/google/gwt/editor/rebind/model/EditorModelTest.java Thu Sep 9 11:46:06 2010 +++ /trunk/user/test/com/google/gwt/editor/rebind/model/EditorModelTest.java Fri Sep 10 12:29:13 2010
@@ -29,6 +29,7 @@
 import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
 import com.google.gwt.editor.client.CompositeEditor;
 import com.google.gwt.editor.client.Editor;
+import com.google.gwt.editor.client.IsEditor;
 import com.google.gwt.editor.client.LeafValueEditor;
 import com.google.gwt.editor.client.ValueAwareEditor;
 import com.google.gwt.editor.client.adapters.SimpleEditor;
@@ -236,6 +237,44 @@
     assertEquals("city", address[0].getPropertyName());
     assertEquals("street", address[1].getPropertyName());
   }
+
+  /**
+ * Tests a plain IsEditor that allows the editor instance to be swapped in by
+   * a view object.
+   */
+  public void testIsEditor() throws UnableToCompleteException {
+    EditorModel m = new EditorModel(logger,
+        types.findType("t.UsesIsEditorDriver"), rfedType);
+
+    EditorData[] data = m.getEditorData();
+    assertNotNull(data);
+    assertEquals(2, data.length);
+    assertEquals(Arrays.asList("b", "b.string"), Arrays.asList(
+        data[0].getPath(), data[1].getPath()));
+    assertEquals(Arrays.asList("bEditor().asEditor()", "stringEditor()"),
+        Arrays.asList(data[0].getSimpleExpression(),
+            data[1].getSimpleExpression()));
+  }
+
+  /**
+   * Tests the case where an IsEditor also implements the Editor interface.
+   */
+  public void testIsEditorAndEditor() throws UnableToCompleteException {
+    EditorModel m = new EditorModel(logger,
+        types.findType("t.UsesIsEditorAndEditorDriver"), rfedType);
+
+    EditorData[] data = m.getEditorData();
+    assertNotNull(data);
+    assertEquals(4, data.length);
+    assertEquals(Arrays.asList("b", "b.string", "b", "b.string"),
+ Arrays.asList(data[0].getPath(), data[1].getPath(), data[2].getPath(),
+            data[3].getPath()));
+    assertEquals(Arrays.asList("bEditor().asEditor()",
+        "bEditor().asEditor().coEditor()", "bEditor()",
+        "bEditor().viewEditor()"), Arrays.asList(data[0].getExpression(),
+        data[1].getExpression(), data[2].getExpression(),
+        data[3].getExpression()));
+  }

   public void testListDriver() throws UnableToCompleteException {
     EditorModel m = new EditorModel(logger,
@@ -628,6 +667,64 @@
         code.append("}");
         return code;
       }
+    }, new MockJavaResource("t.UsesIsEditorDriver") {
+ // Tests error-detection when the editor structure doesn't match the proxy
+      @Override
+      protected CharSequence getContent() {
+        StringBuilder code = new StringBuilder();
+        code.append("package t;\n");
+        code.append("import " + Editor.class.getName() + ";\n");
+        code.append("import " + IsEditor.class.getName() + ";\n");
+        code.append("import " + EntityProxy.class.getName() + ";\n");
+        code.append("import " + RequestFactoryEditorDriver.class.getName()
+            + ";\n");
+        code.append("import " + SimpleEditor.class.getName() + ";\n");
+        code.append("interface UsesIsEditorDriver extends"
+            + " RequestFactoryEditorDriver<UsesIsEditorDriver.AProxy,"
+            + " UsesIsEditorDriver.AEditor> {\n");
+ code.append(" interface AProxy extends EntityProxy { BProxy getB();}"); + code.append(" interface BProxy extends EntityProxy { String getString();}");
+        code.append("  interface AEditor extends Editor<AProxy> {");
+        code.append("    BView bEditor();");
+        code.append("  }");
+        code.append("  interface BView extends IsEditor<BEditor> {");
+        code.append("    @Editor.Path(\"string\") BEditor unseen();");
+        code.append("  }");
+        code.append("  interface BEditor extends Editor<BProxy> {");
+        code.append("    SimpleEditor<String> stringEditor();");
+        code.append("  }");
+        code.append("}");
+        return code;
+      }
+    }, new MockJavaResource("t.UsesIsEditorAndEditorDriver") {
+ // Tests error-detection when the editor structure doesn't match the proxy
+      @Override
+      protected CharSequence getContent() {
+        StringBuilder code = new StringBuilder();
+        code.append("package t;\n");
+        code.append("import " + Editor.class.getName() + ";\n");
+        code.append("import " + IsEditor.class.getName() + ";\n");
+        code.append("import " + EntityProxy.class.getName() + ";\n");
+        code.append("import " + RequestFactoryEditorDriver.class.getName()
+            + ";\n");
+        code.append("import " + SimpleEditor.class.getName() + ";\n");
+        code.append("interface UsesIsEditorAndEditorDriver extends"
+ + " RequestFactoryEditorDriver<UsesIsEditorAndEditorDriver.AProxy,"
+            + " UsesIsEditorAndEditorDriver.AEditor> {\n");
+ code.append(" interface AProxy extends EntityProxy { BProxy getB();}"); + code.append(" interface BProxy extends EntityProxy { String getString();}");
+        code.append("  interface AEditor extends Editor<AProxy> {");
+        code.append("    BView bEditor();");
+        code.append("  }");
+ code.append(" interface BView extends IsEditor<BEditor>, Editor<BProxy> {"); + code.append(" @Editor.Path(\"string\") SimpleEditor<String> viewEditor();");
+        code.append("  }");
+        code.append("  interface BEditor extends Editor<BProxy> {");
+ code.append(" @Editor.Path(\"string\") SimpleEditor<String> coEditor();");
+        code.append("  }");
+        code.append("}");
+        return code;
+      }
     }, new MockJavaResource("java.util.List") {
       // Tests a Driver interface that extends more than RFED
       @Override
@@ -646,6 +743,7 @@
         new RealJavaResource(Editor.class),
         new EmptyMockJavaResource(EventBus.class),
         new RealJavaResource(HasText.class),
+        new RealJavaResource(IsEditor.class),
         new RealJavaResource(LeafValueEditor.class),
         new EmptyMockJavaResource(Property.class),
         new EmptyMockJavaResource(EntityProxy.class),

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

Reply via email to