Revision: 8926
Author: [email protected]
Date: Sun Oct  3 11:35:25 2010
Log: Introduce OptionalFieldEditor to support editing nullable fields.
Update DynaTableRf sample to demonstrate.
Patch by: bobv
Review by: rjrjr
Suggested by: pjulien

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

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

Added:
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/MentorSelector.java /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/MentorSelector.ui.xml /trunk/user/src/com/google/gwt/editor/client/adapters/OptionalFieldEditor.java
Modified:
/trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/NameLabel.java /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.java /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.ui.xml /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java
 /trunk/user/src/com/google/gwt/editor/rebind/model/EditorModel.java
 /trunk/user/test/com/google/gwt/editor/client/SimpleBeanEditorTest.java

=======================================
--- /dev/null
+++ /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/MentorSelector.java Sun Oct 3 11:35:25 2010
@@ -0,0 +1,101 @@
+/*
+ * 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.sample.dynatablerf.client.widgets;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.editor.client.IsEditor;
+import com.google.gwt.editor.client.adapters.OptionalFieldEditor;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.requestfactory.shared.Receiver;
+import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory;
+import com.google.gwt.sample.dynatablerf.shared.PersonProxy;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.uibinder.client.UiHandler;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * This demonstrates how an editor can be constructed to handle optional fields. + * The Person domain object's mentor property is initially <code>null</code>.
+ * This type delegates editing control to an instance of the
+ * {...@link OptionalValueEditor} adapter class.
+ */
+public class MentorSelector extends Composite implements
+    IsEditor<OptionalFieldEditor<PersonProxy, NameLabel>> {
+
+  interface Binder extends UiBinder<Widget, MentorSelector> {
+  }
+
+  @UiField
+  Button choose;
+
+  @UiField
+  Button clear;
+
+  @UiField
+  NameLabel nameLabel;
+
+  private final OptionalFieldEditor<PersonProxy, NameLabel> editor;
+  private final DynaTableRequestFactory factory;
+
+  public MentorSelector(DynaTableRequestFactory factory) {
+    this.factory = factory;
+    initWidget(GWT.<Binder> create(Binder.class).createAndBindUi(this));
+    editor = OptionalFieldEditor.of(nameLabel);
+  }
+
+  public OptionalFieldEditor<PersonProxy, NameLabel> asEditor() {
+    return editor;
+  }
+
+  public void setEnabled(boolean enabled) {
+    choose.setEnabled(enabled);
+    clear.setEnabled(enabled);
+  }
+
+  @Override
+  protected void onUnload() {
+    nameLabel.cancelSubscription();
+  }
+
+  @UiHandler("choose")
+  void onChoose(ClickEvent event) {
+    setEnabled(false);
+    factory.schoolCalendarRequest().getRandomPerson().to(
+        new Receiver<PersonProxy>() {
+          @Override
+          public void onSuccess(PersonProxy response) {
+            setValue(response);
+            setEnabled(true);
+          }
+        }).fire();
+  }
+
+  @UiHandler("clear")
+  void onClear(ClickEvent event) {
+    setValue(null);
+  }
+
+  /**
+   * This method is not called by the Editor framework.
+   */
+  private void setValue(PersonProxy person) {
+    editor.setValue(person);
+    nameLabel.setVisible(person != null);
+  }
+}
=======================================
--- /dev/null
+++ /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/MentorSelector.ui.xml Sun Oct 3 11:35:25 2010
@@ -0,0 +1,10 @@
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'
+  xmlns:dt='urn:import:com.google.gwt.sample.dynatablerf.client.widgets'
+  xmlns:e='urn:import:com.google.gwt.editor.client.ui'>
+  <ui:style src="../common.css" />
+  <g:FlowPanel>
+ <dt:NameLabel ui:field="nameLabel" stylePrimaryName="{style.editField}" />
+    <g:Button ui:field="choose">Choose Randomly</g:Button>
+    <g:Button ui:field="clear">Clear</g:Button>
+  </g:FlowPanel>
+</ui:UiBinder>
=======================================
--- /dev/null
+++ /trunk/user/src/com/google/gwt/editor/client/adapters/OptionalFieldEditor.java Sun Oct 3 11:35:25 2010
@@ -0,0 +1,101 @@
+/*
+ * 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.adapters;
+
+import com.google.gwt.editor.client.CompositeEditor;
+import com.google.gwt.editor.client.Editor;
+import com.google.gwt.editor.client.EditorDelegate;
+import com.google.gwt.editor.client.LeafValueEditor;
+
+/**
+ * This adapter can be used when a type being edited has an optional field that + * may be nullified or reassigned as part of the editing process. This consumer
+ * of this adapter will typically expose it via the
+ * {...@link com.google.gwt.editor.client.IsEditor IsEditor} interface:
+ *
+ * <pre>
+ * class FooSelector extends Composite implements IsEditor&lt;OptionalFieldEditor&lt;Foo, FooEditor>> { + * private OptionalFieldEditor&lt;Foo, FooEditor> editor = OptionalFieldEditor.of(new FooEditor());
+ *   public OptionalFieldEditor&lt;Foo, FooEditor> asEditor() {
+ *     return editor;
+ *   }
+ * }
+ * </pre>
+ *
+ * @param <T> The type of data being managed
+ * @param <E> The type of Editor
+ */
+public class OptionalFieldEditor<T, E extends Editor<T>> implements
+    CompositeEditor<T, T, E>, LeafValueEditor<T> {
+
+  /**
+   * Construct an OptionalFieldEditor backed by the given sub-Editor.
+   *
+   * @param <T> The type of data being managed
+   * @param <E> The type of Editor
+   * @param subEditor the sub-Editor that will be attached to the Editor
+   *          hierarchy
+   * @return a new instance of OptionalFieldEditor
+   */
+  public static <T, E extends Editor<T>> OptionalFieldEditor<T, E> of(
+      E subEditor) {
+    return new OptionalFieldEditor<T, E>(subEditor);
+  }
+
+  private EditorChain<T, E> chain;
+  private T currentValue;
+  private final E subEditor;
+
+  protected OptionalFieldEditor(E subEditor) {
+    this.subEditor = subEditor;
+  }
+
+  public void flush() {
+    currentValue = chain.getValue(subEditor);
+  }
+
+  /**
+ * Returns an empty string because there is only ever one sub-editor used.
+   */
+  public String getPathElement(E subEditor) {
+    return "";
+  }
+
+  public T getValue() {
+    return currentValue;
+  }
+
+  public void onPropertyChange(String... paths) {
+  }
+
+  public void setDelegate(EditorDelegate<T> delegate) {
+  }
+
+  public void setEditorChain(EditorChain<T, E> chain) {
+    this.chain = chain;
+  }
+
+  public void setValue(T value) {
+    if (currentValue != null && value == null) {
+      chain.detach(subEditor);
+    }
+    currentValue = value;
+    if (value != null) {
+      chain.attach(value, subEditor);
+    }
+  }
+
+}
=======================================
--- /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java Fri Oct 1 18:15:55 2010 +++ /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java Sun Oct 3 11:35:25 2010
@@ -75,7 +75,7 @@
   @UiField
   CheckBox favorite;

-  @UiField
+  @UiField(provided = true)
   PersonEditor personEditor;

   private Driver editorDriver;
@@ -88,6 +88,7 @@
     this.requestFactory = requestFactory;
     this.manager = manager;
     this.person = person;
+    personEditor = new PersonEditor(requestFactory);
     Binder.BINDER.createAndBindUi(this);
     contents.addDomHandler(new KeyUpHandler() {
       public void onKeyUp(KeyUpEvent event) {
@@ -99,13 +100,11 @@
   }

   @UiHandler("cancel")
-  @SuppressWarnings("unused")
   void onCancel(ClickEvent e) {
     dialog.hide();
   }

   @UiHandler("save")
-  @SuppressWarnings("unused")
   void onSave(ClickEvent e) {
     // MOVE TO ACTIVITY END
     RequestContext context = editorDriver.flush();
@@ -128,7 +127,6 @@
   }

   @UiHandler("favorite")
-  @SuppressWarnings("unused")
   void onValueChanged(ValueChangeEvent<Boolean> event) {
     manager.setFavorite(person, favorite.getValue());
   }
=======================================
--- /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/NameLabel.java Fri Sep 17 07:40:00 2010 +++ /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/NameLabel.java Sun Oct 3 11:35:25 2010
@@ -35,14 +35,20 @@
   private PersonProxy person;
   private HandlerRegistration subscription;

+  public NameLabel() {
+    this(null);
+  }
+
   public NameLabel(final EventBus eventBus) {
     initWidget(nameEditor);

-    nameEditor.addClickHandler(new ClickHandler() {
-      public void onClick(ClickEvent event) {
-        eventBus.fireEvent(new EditPersonEvent(person));
-      }
-    });
+    if (eventBus != null) {
+      nameEditor.addClickHandler(new ClickHandler() {
+        public void onClick(ClickEvent event) {
+          eventBus.fireEvent(new EditPersonEvent(person));
+        }
+      });
+    }
   }

   public void flush() {
=======================================
--- /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.java Wed Sep 15 02:26:39 2010 +++ /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.java Sun Oct 3 11:35:25 2010
@@ -20,6 +20,7 @@
 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
 import com.google.gwt.editor.client.Editor;
 import com.google.gwt.editor.client.ui.ValueBoxEditorDecorator;
+import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory;
 import com.google.gwt.sample.dynatablerf.shared.PersonProxy;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiField;
@@ -40,6 +41,9 @@
   @UiField
   ValueBoxEditorDecorator<String> description;

+  @UiField(provided = true)
+  MentorSelector mentor;
+
   @UiField
   ValueBoxEditorDecorator<String> name;

@@ -49,7 +53,8 @@
   @UiField
   Focusable nameBox;

-  public PersonEditor() {
+  public PersonEditor(DynaTableRequestFactory factory) {
+    mentor = new MentorSelector(factory);
     initWidget(GWT.<Binder> create(Binder.class).createAndBindUi(this));
   }

=======================================
--- /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.ui.xml Wed Sep 15 02:26:39 2010 +++ /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/PersonEditor.ui.xml Sun Oct 3 11:35:25 2010
@@ -33,5 +33,7 @@
     </div>
     Address:
<dt:AddressEditor ui:field="address" stylePrimaryName="{style.editField}" />
+    Mentor:
+ <dt:MentorSelector ui:field="mentor" stylePrimaryName="{style.editField}" />
   </g:HTMLPanel>
 </ui:UiBinder>
=======================================
--- /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java Fri Oct 1 18:15:55 2010 +++ /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java Sun Oct 3 11:35:25 2010
@@ -163,7 +163,6 @@
   }

   @UiHandler("create")
-  @SuppressWarnings("unused")
   void onCreate(ClickEvent event) {
     PersonRequest context = requestFactory.personRequest();
     AddressProxy address = context.create(AddressProxy.class);
=======================================
--- /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java Thu Sep 30 06:57:12 2010 +++ /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/domain/Person.java Sun Oct 3 11:35:25 2010
@@ -54,6 +54,8 @@
   @NotNull
   private String description = "DESC";

+  private Person mentor;
+
   @NotNull
   @Size(min = 2, message = "Persons aren't just characters")
   private String name;
@@ -82,6 +84,7 @@
     classSchedule = copyFrom.classSchedule;
     description = copyFrom.description;
     name = copyFrom.name;
+    mentor = copyFrom.mentor;
     id = copyFrom.id;
     version = copyFrom.version;
     note = copyFrom.note;
@@ -109,6 +112,10 @@
   public String getId() {
     return id;
   }
+
+  public Person getMentor() {
+    return mentor;
+  }

   public String getName() {
     return name;
@@ -165,6 +172,10 @@
     this.id = id;
     address.setId(id);
   }
+
+  public void setMentor(Person mentor) {
+    this.mentor = mentor;
+  }

   public void setName(String name) {
     this.name = name;
=======================================
--- /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java Fri Sep 24 12:10:50 2010 +++ /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/server/SchoolCalendarService.java Sun Oct 3 11:35:25 2010
@@ -20,6 +20,7 @@

 import java.io.IOException;
 import java.util.List;
+import java.util.Random;

 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
@@ -32,6 +33,9 @@
  * The server side service class.
  */
 public class SchoolCalendarService implements Filter {
+  private static final boolean[] ALL_DAYS = new boolean[] {
+      true, true, true, true, true, true, true};
+
private static final ThreadLocal<PersonSource> PERSON_SOURCE = new ThreadLocal<PersonSource>();

   public static Person createPerson() {
@@ -46,12 +50,14 @@
     return PERSON_SOURCE.get().findPerson(id);
   }

-  /**
-   * XXX Remove this once primitive lists work.
-   */
   public static List<Person> getPeople(int startIndex, int maxCount) {
-    return getPeople(startIndex, maxCount, new boolean[] {
-        true, true, true, true, true, true, true});
+    return getPeople(startIndex, maxCount, ALL_DAYS);
+  }
+
+  public static Person getRandomPerson() {
+    PersonSource source = PERSON_SOURCE.get();
+    return source.getPeople(new Random().nextInt(source.countPeople()), 1,
+        ALL_DAYS).get(0);
   }

   public static void persist(Address address) {
=======================================
--- /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java Fri Oct 1 18:15:55 2010 +++ /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/DynaTableRequestFactory.java Sun Oct 3 11:35:25 2010
@@ -55,6 +55,7 @@
   @Service(SchoolCalendarService.class)
   interface SchoolCalendarRequest extends RequestContext {
     Request<List<PersonProxy>> getPeople(int startIndex, int maxCount);
+    Request<PersonProxy> getRandomPerson();
   }

   AddressRequest addressRequest();
=======================================
--- /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java Fri Sep 24 12:10:50 2010 +++ /trunk/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java Sun Oct 3 11:35:25 2010
@@ -25,13 +25,15 @@
  */
 @ProxyFor(Person.class)
 public interface PersonProxy extends EntityProxy {
-
+
   AddressProxy getAddress();

   String getDescription();
-
+
   String getId();

+  PersonProxy getMentor();
+
   String getName();

   String getNote();
@@ -42,9 +44,11 @@

   void setDescription(String description);

+  void setMentor(PersonProxy mentor);
+
   void setName(String name);

   void setNote(String note);
-
+
   EntityProxyId<PersonProxy> stableId();
 }
=======================================
--- /trunk/user/src/com/google/gwt/editor/rebind/model/EditorModel.java Fri Oct 1 18:15:55 2010 +++ /trunk/user/src/com/google/gwt/editor/rebind/model/EditorModel.java Sun Oct 3 11:35:25 2010
@@ -78,8 +78,8 @@
       throws UnableToCompleteException {
     JClassType editorIntf = editorType.getOracle().findType(
         Editor.class.getName());
- JClassType parameterization[] = ModelUtils.findParameterizationOf(editorIntf,
-        editorType);
+    JClassType parameterization[] = ModelUtils.findParameterizationOf(
+        editorIntf, editorType);
     if (parameterization != null) {
       return parameterization[0];
     }
@@ -97,8 +97,8 @@
       JClassType editorType) throws UnableToCompleteException {
     JClassType editorIntf = editorType.getOracle().findType(
         IsEditor.class.getName());
- JClassType[] parameterization = ModelUtils.findParameterizationOf(editorIntf,
-        editorType);
+    JClassType[] parameterization = ModelUtils.findParameterizationOf(
+        editorIntf, editorType);
     if (parameterization != null) {
       return parameterization[0];
     }
@@ -222,7 +222,8 @@
       die(tooManyInterfacesMessage(intf));
     }

- JClassType[] parameters = ModelUtils.findParameterizationOf(driverType, intf);
+    JClassType[] parameters = ModelUtils.findParameterizationOf(driverType,
+        intf);
     assert parameters.length == 2 : "Unexpected number of type parameters";
     proxyType = parameters[0];
     editorType = parameters[1];
@@ -287,14 +288,14 @@
     flatData.addAll(data);
     allData.addAll(data);
     for (EditorData d : data) {
-      if (!d.isLeafValueEditor()) {
-        descendIntoSubEditor(allData, d);
-      }
+      descendIntoSubEditor(allData, d);
     }
   }

   /**
    * Create the EditorData objects for the {...@link #editorData} type.
+   * Essentially, the point of this method is to calculate the paths of all
+   * Editor types referenced by {...@link #editorType}.
    */
private EditorData[] calculateEditorData() throws UnableToCompleteException {
     List<EditorData> flatData = new ArrayList<EditorData>();
@@ -340,6 +341,16 @@
           editorSoFar).build();
       List<EditorData> accumulator = new ArrayList<EditorData>();
       descendIntoSubEditor(accumulator, subEditor);
+
+      /*
+ * It's necessary to generate a sub-Model here so that any Editor types + * reachable only through the composite type will be added to the types
+       * map. The path data isn't actually useful, since we rely on
+       * CompositeEditor.getPathElement() at runtime.
+       */
+ EditorModel subModel = new EditorModel(this, subEditor.getEditorType(),
+          subEditor, subEditor.getEditedType());
+      poisoned |= subModel.poisoned;
     }

     if (!typeData.containsKey(editorType)) {
=======================================
--- /trunk/user/test/com/google/gwt/editor/client/SimpleBeanEditorTest.java Mon Sep 13 09:30:34 2010 +++ /trunk/user/test/com/google/gwt/editor/client/SimpleBeanEditorTest.java Sun Oct 3 11:35:25 2010
@@ -18,6 +18,7 @@
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.editor.client.adapters.EditorSource;
 import com.google.gwt.editor.client.adapters.ListEditor;
+import com.google.gwt.editor.client.adapters.OptionalFieldEditor;
 import com.google.gwt.editor.client.adapters.SimpleEditor;
 import com.google.gwt.junit.client.GWTTestCase;

@@ -103,6 +104,19 @@
   interface PersonEditorWithLeafAddressEditorDriver extends
       SimpleBeanEditorDriver<Person, PersonEditorWithLeafAddressEditor> {
   }
+
+  interface PersonEditorWithOptionalAddressDriver extends
+ SimpleBeanEditorDriver<Person, PersonEditorWithOptionalAddressEditor> {
+  }
+
+  class PersonEditorWithOptionalAddressEditor implements Editor<Person> {
+    OptionalFieldEditor<Address, AddressEditor> address;
+    SimpleEditor<String> name = SimpleEditor.of(UNINITIALIZED);
+
+    public PersonEditorWithOptionalAddressEditor(AddressEditor delegate) {
+      address = OptionalFieldEditor.of(delegate);
+    }
+  }

   class PersonEditorWithValueAwareAddressEditor implements Editor<Person> {
     ValueAwareAddressEditor addressEditor = new ValueAwareAddressEditor();
@@ -419,6 +433,30 @@
     driver.flush();
     assertEquals("edited", person.addresses.get(1).getCity());
   }
+
+  public void testOptionalField() {
+ PersonEditorWithOptionalAddressDriver driver = GWT.create(PersonEditorWithOptionalAddressDriver.class);
+    person.address = null;
+
+    AddressEditor delegate = new AddressEditor();
+ PersonEditorWithOptionalAddressEditor editor = new PersonEditorWithOptionalAddressEditor(
+        delegate);
+    driver.initialize(editor);
+
+    // Make sure we don't blow up with the null field
+    driver.edit(person);
+    editor.address.setValue(personAddress);
+    assertEquals("City", delegate.city.getValue());
+    delegate.city.setValue("Hello");
+    driver.flush();
+    assertNotNull(person.address);
+    assertSame(personAddress, person.address);
+    assertEquals("Hello", personAddress.city);
+
+    editor.address.setValue(null);
+    driver.flush();
+    assertNull(person.address);
+  }

   public void testValueAwareEditorInDeclaredSlot() {
PersonEditorWithValueAwareAddressEditorDriver driver = GWT.create(PersonEditorWithValueAwareAddressEditorDriver.class);

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

Reply via email to