Revision: 9229
Author: jlaba...@google.com
Date: Mon Nov 15 04:05:13 2010
Log: Adding a new widget CellWidget that can wrap any Cell and turn it into a Widget. CellWidget can be used on its own (it isn't abstract) to wrap a widget. It can also be used inside a Composite to create a formal version of an existing Cell, such as creating EditText from EditTextCell. This feature will not be included in GWT 2.1.1.

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

Review by: sbruba...@google.com
http://code.google.com/p/google-web-toolkit/source/detail?r=9229

Added:
 /trunk/user/src/com/google/gwt/user/cellview/client/CellWidget.java
 /trunk/user/test/com/google/gwt/user/cellview/client/CellWidgetTest.java
Modified:
 /trunk/user/test/com/google/gwt/user/cellview/CellViewSuite.java

=======================================
--- /dev/null
+++ /trunk/user/src/com/google/gwt/user/cellview/client/CellWidget.java Mon Nov 15 04:05:13 2010
@@ -0,0 +1,231 @@
+/*
+ * 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.user.cellview.client;
+
+import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.ValueUpdater;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.resources.client.CommonResources;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.HasValue;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.view.client.HasKeyProvider;
+import com.google.gwt.view.client.ProvidesKey;
+
+/**
+ * A {...@link Widget} that wraps a {...@link Cell}.
+ *
+ * @param <C> the type that the Cell represents
+ */
+public class CellWidget<C> extends Widget implements HasKeyProvider<C>,
+    HasValue<C> {
+
+  /**
+ * Create the default element used to wrap the Cell. The default element is a
+   * div with display set to inline-block.
+   *
+   * @return the default wrapper element
+   */
+  private static Element createDefaultWrapperElement() {
+    Element div = Document.get().createDivElement();
+    div.setClassName(CommonResources.getInlineBlockStyle());
+    return div;
+  }
+
+  /**
+   * The cell being wrapped.
+   */
+  private final Cell<C> cell;
+
+  /**
+   * The key provider for the value.
+   */
+  private final ProvidesKey<C> keyProvider;
+
+  /**
+   * The current cell value.
+   */
+  private C value;
+
+  /**
+   * The {...@link ValueUpdater} used to trigger value update events.
+   */
+  private final ValueUpdater<C> valueUpdater = new ValueUpdater<C>() {
+    public void update(C value) {
+      ValueChangeEvent.fire(CellWidget.this, value);
+    }
+  };
+
+  /**
+ * Construct a new {...@link CellWidget} with the specified cell and an initial
+   * value of <code>null</code>.
+   *
+   * @param cell the cell to wrap
+   */
+  public CellWidget(Cell<C> cell) {
+    this(cell, null, null);
+  }
+
+  /**
+   * Construct a new {...@link CellWidget} with the specified cell and key
+   * provider, and an initial value of <code>null</code>.
+   *
+   * @param cell the cell to wrap
+   * @param keyProvider the key provider used to get keys from values
+   */
+  public CellWidget(Cell<C> cell, ProvidesKey<C> keyProvider) {
+    this(cell, null, keyProvider);
+  }
+
+  /**
+   * Construct a new {...@link CellWidget} with the specified cell and initial
+   * value.
+   *
+   * @param cell the cell to wrap
+   * @param initialValue the initial value of the Cell
+   */
+  public CellWidget(Cell<C> cell, C initialValue) {
+    this(cell, initialValue, null);
+  }
+
+  /**
+ * Construct a new {...@link CellWidget} with the specified cell, initial value,
+   * and key provider.
+   *
+   * @param cell the cell to wrap
+   * @param initialValue the initial value of the Cell
+   * @param keyProvider the key provider used to get keys from values
+   */
+ public CellWidget(Cell<C> cell, C initialValue, ProvidesKey<C> keyProvider) {
+    this(cell, initialValue, keyProvider, createDefaultWrapperElement());
+  }
+
+  /**
+ * Creates a {...@link CellWidget} with the specified cell, initial value, key
+   * provider, using the specified element as the wrapper around the cell.
+   *
+   * @param cell the cell to wrap
+   * @param initialValue the initial value of the Cell
+   * @param keyProvider the key provider used to get keys from values
+   * @param elem the browser element to use
+   */
+  protected CellWidget(Cell<C> cell, C initialValue,
+      ProvidesKey<C> keyProvider, Element elem) {
+    this.cell = cell;
+    this.keyProvider = keyProvider;
+    setElement(elem);
+    CellBasedWidgetImpl.get().sinkEvents(this, cell.getConsumedEvents());
+    setValue(initialValue);
+  }
+
+ public HandlerRegistration addValueChangeHandler(ValueChangeHandler<C> handler) {
+    return addHandler(handler, ValueChangeEvent.getType());
+  }
+
+  /**
+   * Get the {...@link Cell} wrapped by this widget.
+   *
+   * @return the {...@link Cell} being wrapped
+   */
+  public Cell<C> getCell() {
+    return cell;
+  }
+
+  public ProvidesKey<C> getKeyProvider() {
+    return keyProvider;
+  }
+
+  public C getValue() {
+    return value;
+  }
+
+  @Override
+  public void onBrowserEvent(Event event) {
+    CellBasedWidgetImpl.get().onBrowserEvent(this, event);
+    super.onBrowserEvent(event);
+
+    // Forward the event to the cell.
+    String eventType = event.getType();
+    if (cell.getConsumedEvents().contains(eventType)) {
+      cell.onBrowserEvent(getElement(), value, getKey(value), event,
+          valueUpdater);
+    }
+  }
+
+  /**
+   * Redraw the widget.
+   */
+  public void redraw() {
+    SafeHtmlBuilder sb = new SafeHtmlBuilder();
+    cell.render(value, getKey(value), sb);
+    getElement().setInnerHTML(sb.toSafeHtml().asString());
+  }
+
+  /**
+   * {...@inheritdoc}
+   * <p>
+   * This method will redraw the widget using the new value.
+   * </p>
+   */
+  public void setValue(C value) {
+    setValue(value, false, true);
+  }
+
+  /**
+   * {...@inheritdoc}
+   * <p>
+   * This method will redraw the widget using the new value.
+   * </p>
+   */
+  public void setValue(C value, boolean fireEvents) {
+    setValue(value, fireEvents, true);
+  }
+
+  /**
+   * Sets this object's value and optionally redraw the widget. Fires
+   * {...@link com.google.gwt.event.logical.shared.ValueChangeEvent} when
+ * fireEvents is true and the new value does not equal the existing value.
+   *
+   * @param value the object's new value
+   * @param fireEvents fire events if true and value is new
+   * @param redraw true to redraw the widget, false not to
+   */
+  public void setValue(C value, boolean fireEvents, boolean redraw) {
+    this.value = value;
+    if (redraw) {
+      redraw();
+    }
+    if (fireEvents) {
+      ValueChangeEvent.fire(this, value);
+    }
+  }
+
+  /**
+   * Get the key for the specified value.
+   *
+   * @param value the value
+   * @return the key
+   */
+  private Object getKey(C value) {
+    return (keyProvider == null || value == null) ? value
+        : keyProvider.getKey(value);
+  }
+}
=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/user/cellview/client/CellWidgetTest.java Mon Nov 15 04:05:13 2010
@@ -0,0 +1,196 @@
+/*
+ * 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.user.cellview.client;
+
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.ValueUpdater;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.view.client.ProvidesKey;
+
+/**
+ * Tests for {...@link CellWidget}.
+ */
+public class CellWidgetTest extends GWTTestCase {
+
+  /**
+   * A custom cell used for testing.
+   */
+  private static class CustomCell extends AbstractCell<String> {
+
+    private String lastEventValue;
+    private Object lastEventKey;
+
+    public CustomCell() {
+      super("change");
+    }
+
+    public void assertLastEventKey(String expected) {
+      assertEquals(expected, lastEventKey);
+      lastEventKey = null;
+    }
+
+    public void assertLastEventValue(String expected) {
+      assertEquals(expected, lastEventValue);
+      lastEventValue = null;
+    }
+
+    @Override
+    public void onBrowserEvent(Element parent, String value, Object key,
+        NativeEvent event, ValueUpdater<String> valueUpdater) {
+      lastEventValue = value;
+      lastEventKey = key;
+      if (valueUpdater != null) {
+        valueUpdater.update("newValue");
+      }
+    }
+
+    @Override
+    public void render(String value, Object key, SafeHtmlBuilder sb) {
+      if (value != null) {
+        sb.appendEscaped(value);
+      }
+    }
+  }
+
+  /**
+   * A mock value change handler used for testing.
+   *
+   * @param <C> the data type
+   */
+  private static class MockValueChangeHandler<C> implements
+      ValueChangeHandler<C> {
+
+    private boolean onValueChangeCalled = false;
+    private C lastValue;
+
+    public void assertOnValueChangeNotCalled() {
+      assertFalse(onValueChangeCalled);
+    }
+
+    public void assertLastValue(C expected) {
+      assertTrue(onValueChangeCalled);
+      assertEquals(expected, lastValue);
+      lastValue = null;
+      onValueChangeCalled = false;
+    }
+
+    public void onValueChange(ValueChangeEvent<C> event) {
+      assertFalse("ValueChangeEvent fired twice", onValueChangeCalled);
+      onValueChangeCalled = true;
+      lastValue = event.getValue();
+    }
+  }
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.user.cellview.CellView";
+  }
+
+  public void testOnBrowserEvent() {
+    CustomCell cell = new CustomCell();
+    CellWidget<String> cw = new CellWidget<String>(cell, "test");
+    assertEquals("test", cw.getValue());
+
+    Event event = Document.get().createChangeEvent().cast();
+    cw.onBrowserEvent(event);
+    cell.assertLastEventKey("test");
+    cell.assertLastEventValue("test");
+  }
+
+  public void testOnBrowserEventWithKeyProvider() {
+    ProvidesKey<String> keyProvider = new ProvidesKey<String>() {
+      public Object getKey(String item) {
+        // Return the first character as the key.
+        return (item == null) ? null : item.substring(0, 1);
+      }
+    };
+    CustomCell cell = new CustomCell();
+    final CellWidget<String> cw = new CellWidget<String>(cell, "test",
+        keyProvider);
+    assertEquals("test", cw.getValue());
+    assertEquals(keyProvider, cw.getKeyProvider());
+
+    Event event = Document.get().createChangeEvent().cast();
+    cw.onBrowserEvent(event);
+    cell.assertLastEventKey("t");
+    cell.assertLastEventValue("test");
+  }
+
+  public void testOnBrowserEventWithValueChangeHandler() {
+    CustomCell cell = new CustomCell();
+    final CellWidget<String> cw = new CellWidget<String>(cell, "test");
+    assertEquals("test", cw.getValue());
+
+    // Add a ValueChangeHandler.
+ MockValueChangeHandler<String> handler = new MockValueChangeHandler<String>();
+    cw.addValueChangeHandler(handler);
+
+    // Fire an native event that will trigger a value change event.
+    Event event = Document.get().createChangeEvent().cast();
+    cw.onBrowserEvent(event);
+    cell.assertLastEventKey("test");
+    cell.assertLastEventValue("test");
+    handler.assertLastValue("newValue");
+  }
+
+  public void testRedraw() {
+    CellWidget<String> cw = new CellWidget<String>(new CustomCell());
+
+    // Set value without redrawing.
+    cw.setValue("test", false, false);
+    assertEquals("", cw.getElement().getInnerText());
+
+    // Redraw.
+    cw.redraw();
+    assertEquals("test", cw.getElement().getInnerText());
+  }
+
+  public void testSetValue() {
+    CustomCell cell = new CustomCell();
+    CellWidget<String> cw = new CellWidget<String>(cell, "initial");
+ MockValueChangeHandler<String> handler = new MockValueChangeHandler<String>();
+    cw.addValueChangeHandler(handler);
+
+    // Check the intial value.
+    assertEquals("initial", cw.getValue());
+    assertEquals("initial", cw.getElement().getInnerText());
+
+    // Set value without firing events.
+    cw.setValue("test0");
+    assertEquals("test0", cw.getValue());
+    assertEquals("test0", cw.getElement().getInnerText());
+    handler.assertOnValueChangeNotCalled();
+
+    // Set value and fire events.
+    cw.setValue("test1", true);
+    assertEquals("test1", cw.getValue());
+    assertEquals("test1", cw.getElement().getInnerText());
+    handler.assertLastValue("test1");
+
+    // Set value, fire events, but do not redraw.
+    cw.setValue("test no redraw", true, false);
+    assertEquals("test no redraw", cw.getValue());
+    assertEquals("test1", cw.getElement().getInnerText());
+    handler.assertLastValue("test no redraw");
+  }
+}
=======================================
--- /trunk/user/test/com/google/gwt/user/cellview/CellViewSuite.java Wed Sep 22 12:58:01 2010 +++ /trunk/user/test/com/google/gwt/user/cellview/CellViewSuite.java Mon Nov 15 04:05:13 2010
@@ -22,6 +22,7 @@
 import com.google.gwt.user.cellview.client.CellListTest;
 import com.google.gwt.user.cellview.client.CellTableTest;
 import com.google.gwt.user.cellview.client.CellTreeTest;
+import com.google.gwt.user.cellview.client.CellWidgetTest;
 import com.google.gwt.user.cellview.client.ColumnTest;
 import com.google.gwt.user.cellview.client.HasDataPresenterTest;
 import com.google.gwt.user.cellview.client.PageSizePagerTest;
@@ -42,6 +43,7 @@
     suite.addTestSuite(CellListTest.class);
     suite.addTestSuite(CellTableTest.class);
     suite.addTestSuite(CellTreeTest.class);
+    suite.addTestSuite(CellWidgetTest.class);
     suite.addTestSuite(ColumnTest.class);
     suite.addTestSuite(HasDataPresenterTest.class);
     suite.addTestSuite(PageSizePagerTest.class);

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

Reply via email to