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