Passing a ViewDataUpdater into Cell#onBrowserEvent so that cells can update view data after the event has passed. Some editable cells did not fully use view data, but now they use it to store their current state. Also adding view data support to all cell widgets.
Review at http://gwt-code-reviews.appspot.com/689801/show
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8383 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/CellSamplerRecipe.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/CellSamplerRecipe.java
new file mode 100644
index 0000000..8594d8c
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/CellSamplerRecipe.java
@@ -0,0 +1,370 @@
+/*
+ * 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.bikeshed.cookbook.client;
+
+import com.google.gwt.cell.client.AbstractEditableCell;
+import com.google.gwt.cell.client.ActionCell;
+import com.google.gwt.cell.client.ButtonCell;
+import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.CheckboxCell;
+import com.google.gwt.cell.client.ClickableTextCell;
+import com.google.gwt.cell.client.DateCell;
+import com.google.gwt.cell.client.DatePickerCell;
+import com.google.gwt.cell.client.EditTextCell;
+import com.google.gwt.cell.client.FieldUpdater;
+import com.google.gwt.cell.client.IconCellDecorator;
+import com.google.gwt.cell.client.NumberCell;
+import com.google.gwt.cell.client.SelectionCell;
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.cell.client.TextInputCell;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.user.cellview.client.CellTable;
+import com.google.gwt.user.cellview.client.Column;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.view.client.ListViewAdapter;
+import com.google.gwt.view.client.ProvidesKey;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * A table containing most cell types.
+ *
+ * TODO (jlabanca): Refactor this sample to use more realistic data.
+ */
+public class CellSamplerRecipe extends Recipe {
+
+ /**
+ * A generic status.
+ */
+ private static enum Status {
+ ACTIVE("Active"), INACTIVE("Inactive"), ARCHIVED("Archived");
+
+ private final String displayName;
+
+ private Status(String displayName) {
+ this.displayName = displayName;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+ }
+
+ /**
+ * The images used for this recipe.
+ */
+ static interface Images extends ClientBundle {
+ ImageResource gwtLogo();
+ }
+
+ /**
+ * Get a cell value from a record.
+ *
+ * @param <C> the cell type
+ */
+ private static interface GetValue<C> {
+ C getValue(Record record);
+ }
+
+ /**
+ * The record object used for each row.
+ */
+ @SuppressWarnings("deprecation")
+ private static class Record implements Comparable<Record> {
+
+ private final int id;
+ private Date date;
+ private Status status;
+ private String text;
+
+ /**
+ * The pending values are set by field updaters until they are committed.
+ */
+ private Status pendingStatus;
+ private Date pendingDate;
+ private String pendingText;
+
+ public Record(int id) {
+ this.id = id;
+ this.date = new Date(2010 - 1900, 1, id);
+ this.text = "Item " + id;
+ this.status = Status.ACTIVE;
+ }
+
+ public void commit() {
+ if (pendingDate != null) {
+ date = pendingDate;
+ pendingDate = null;
+ }
+ if (pendingText != null) {
+ text = pendingText;
+ pendingText = null;
+ }
+ if (pendingStatus != null) {
+ status = pendingStatus;
+ pendingStatus = null;
+ }
+ }
+
+ public int compareTo(Record o) {
+ return o == null ? 1 : id - o.id;
+ }
+
+ public void setDate(Date date) {
+ this.pendingDate = date;
+ }
+
+ public void setStatus(Status status) {
+ this.pendingStatus = status;
+ }
+
+ public void setText(String text) {
+ this.pendingText = text;
+ }
+ }
+
+ private List<AbstractEditableCell<?, ?>> editableCells;
+ private CellTable<Record> table;
+
+ public CellSamplerRecipe() {
+ super("Cell Sampler");
+ }
+
+ @Override
+ protected Widget createWidget() {
+ Images images = GWT.create(Images.class);
+
+ // Create the adapter.
+ final ProvidesKey<Record> keyProvider = new ProvidesKey<Record>() {
+ public Object getKey(Record item) {
+ return item.id;
+ }
+ };
+ final ListViewAdapter<Record> adapter = new ListViewAdapter<Record>();
+ adapter.setKeyProvider(keyProvider);
+ for (int i = 0; i < 10; ++i) {
+ adapter.getList().add(new Record(i));
+ }
+
+ // Create the table.
+ editableCells = new ArrayList<AbstractEditableCell<?, ?>>();
+ table = new CellTable<Record>(10);
+ table.setKeyProvider(keyProvider);
+ adapter.addView(table);
+
+ // CheckboxCell.
+ addColumn(new CheckboxCell(), "CheckboxCell", new GetValue<Boolean>() {
+ public Boolean getValue(Record record) {
+ return Status.ACTIVE.equals(record.status);
+ }
+ }, new FieldUpdater<Record, Boolean>() {
+ public void update(int index, Record object, Boolean value) {
+ if (value) {
+ object.setStatus(Status.ACTIVE);
+ } else {
+ object.setStatus(Status.INACTIVE);
+ }
+ }
+ });
+
+ // TextCell.
+ addColumn(new TextCell(), "TextCell", new GetValue<String>() {
+ public String getValue(Record record) {
+ return record.text;
+ }
+ }, null);
+
+ // ActionCell.
+ addColumn(
+ new ActionCell<Record>("Click Me", new ActionCell.Delegate<Record>() {
+ public void execute(Record object) {
+ Window.alert("You clicked #" + object.id);
+ }
+ }), "ActionCell", new GetValue<Record>() {
+ public Record getValue(Record record) {
+ return record;
+ }
+ }, null);
+
+ // ButtonCell.
+ addColumn(new ButtonCell(), "ButtonCell", new GetValue<String>() {
+ public String getValue(Record record) {
+ return "Click " + record.id;
+ }
+ }, new FieldUpdater<Record, String>() {
+ public void update(int index, Record object, String value) {
+ Window.alert("You clicked " + object.id);
+ }
+ });
+
+ // ClickableTextCell.
+ addColumn(
+ new ClickableTextCell(), "ClickableTextCell", new GetValue<String>() {
+ public String getValue(Record record) {
+ return "Click " + record.id;
+ }
+ }, new FieldUpdater<Record, String>() {
+ public void update(int index, Record object, String value) {
+ Window.alert("You clicked " + object.id);
+ }
+ });
+
+ // DateCell.
+ DateTimeFormat dateFormat = DateTimeFormat.getFormat(
+ PredefinedFormat.DATE_MEDIUM);
+ addColumn(new DateCell(dateFormat), "DateCell", new GetValue<Date>() {
+ public Date getValue(Record record) {
+ return record.date;
+ }
+ }, null);
+
+ // DatePickerCell.
+ addColumn(
+ new DatePickerCell(dateFormat), "DatePickerCell", new GetValue<Date>() {
+ public Date getValue(Record record) {
+ return record.date;
+ }
+ }, new FieldUpdater<Record, Date>() {
+ public void update(int index, Record object, Date value) {
+ object.setDate(value);
+ }
+ });
+
+ // EditTextCell.
+ addColumn(new EditTextCell(), "EditTextCell", new GetValue<String>() {
+ public String getValue(Record record) {
+ return record.text;
+ }
+ }, new FieldUpdater<Record, String>() {
+ public void update(int index, Record object, String value) {
+ object.setText(value);
+ }
+ });
+
+ // IconCellDecorator.
+ addColumn(new IconCellDecorator<String>(images.gwtLogo(), new TextCell()),
+ "IconCellDecorator", new GetValue<String>() {
+ public String getValue(Record record) {
+ return record.text;
+ }
+ }, null);
+
+ // NumberCell.
+ addColumn(new NumberCell(), "NumberCell", new GetValue<Number>() {
+ public Number getValue(Record record) {
+ return record.id;
+ }
+ }, null);
+
+ // SelectionCell.
+ List<String> options = new ArrayList<String>();
+ options.add(Status.ACTIVE.getDisplayName());
+ options.add(Status.INACTIVE.getDisplayName());
+ options.add(Status.ARCHIVED.getDisplayName());
+ addColumn(
+ new SelectionCell(options), "SelectionCell", new GetValue<String>() {
+ public String getValue(Record record) {
+ return record.status.getDisplayName();
+ }
+ }, new FieldUpdater<Record, String>() {
+ public void update(int index, Record object, String value) {
+ if (Status.ACTIVE.getDisplayName().equals(value)) {
+ object.setStatus(Status.ACTIVE);
+ } else if (Status.INACTIVE.getDisplayName().equals(value)) {
+ object.setStatus(Status.INACTIVE);
+ } else {
+ object.setStatus(Status.ARCHIVED);
+ }
+ }
+ });
+
+ // TextInputCell.
+ addColumn(new TextInputCell(), "TextInputCellCell", new GetValue<String>() {
+ public String getValue(Record record) {
+ return record.text;
+ }
+ }, new FieldUpdater<Record, String>() {
+ public void update(int index, Record object, String value) {
+ object.setText(value);
+ }
+ });
+
+ // Add buttons to redraw or refresh.
+ Button redrawButton = new Button("Redraw Table", new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ table.redraw();
+ }
+ });
+ Button commitButton = new Button("Commit Data", new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ // Commit the changes.
+ for (Record record : adapter.getList()) {
+ record.commit();
+
+ // Clear all view data.
+ Object key = keyProvider.getKey(record);
+ for (AbstractEditableCell<?, ?> cell : editableCells) {
+ cell.setViewData(key, null);
+ }
+ }
+
+ // Update the table.
+ adapter.refresh();
+ }
+ });
+
+ // Add the table to a flowPanel so it doesn't fill the height.
+ FlowPanel fp = new FlowPanel();
+ fp.add(table);
+ fp.add(redrawButton);
+ fp.add(commitButton);
+ return fp;
+ }
+
+ /**
+ * Add a column with a header.
+ *
+ * @param <C> the cell type
+ * @param cell the cell used to render the column
+ * @param headerText the header string
+ * @param getter the value getter for the cell
+ */
+ private <C> void addColumn(Cell<C> cell, String headerText,
+ final GetValue<C> getter, FieldUpdater<Record, C> fieldUpdater) {
+ Column<Record, C> column = new Column<Record, C>(cell) {
+ @Override
+ public C getValue(Record object) {
+ return getter.getValue(object);
+ }
+ };
+ column.setFieldUpdater(fieldUpdater);
+ if (cell instanceof AbstractEditableCell<?, ?>) {
+ editableCells.add((AbstractEditableCell<?, ?>) cell);
+ }
+ table.addColumn(column, headerText);
+ }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Cookbook.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Cookbook.java
index ccf4670..ae72a40 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Cookbook.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/Cookbook.java
@@ -96,7 +96,7 @@
@UiField LayoutPanel container;
private RecipeTreeModel recipeTreeModel;
- private CellListRecipe defaultRecipe;
+ private Recipe defaultRecipe;
private Recipe curRecipe;
public void onModuleLoad() {
@@ -129,7 +129,8 @@
cats.add(new Category("Lists", new Recipe[] {defaultRecipe}));
cats.add(new Category("Tables", new Recipe[] {
- new BasicTableRecipe(), new EditableTableRecipe(),}));
+ new BasicTableRecipe(), new EditableTableRecipe(),
+ new CellSamplerRecipe()}));
cats.add(new Category("Trees", new Recipe[] {
new CellTreeRecipe(), new CellBrowserRecipe(),}));
cats.add(new Category("Other", new Recipe[] {
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidatableInputCell.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidatableInputCell.java
index f6137d9..29c8d48 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidatableInputCell.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidatableInputCell.java
@@ -15,47 +15,19 @@
*/
package com.google.gwt.sample.bikeshed.cookbook.client;
-import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.AbstractEditableCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.sample.bikeshed.cookbook.client.ValidatableField.DefaultValidatableField;
-import com.google.gwt.view.client.HasViewData;
/**
- * A String {@link AbstractCell} that supports validation using a
+ * A String {@link AbstractEditableCell} that supports validation using a
* {@link ValidatableField}.
*/
-public class ValidatableInputCell extends AbstractCell<String> {
-
- /**
- * Marks the cell as invalid.
- *
- * @param container the viewData provider (usually a column or list view)
- * @param key the key identifying this item
- * @param value the new, invalid value
- */
- @SuppressWarnings("unchecked") // cast to ValidatableField<String>
- public static void invalidate(HasViewData container, Object key, String value) {
- ValidatableField<String> vf = (ValidatableField<String>) container.getViewData(key);
- if (vf == null) {
- vf = new DefaultValidatableField<String>(value);
- }
-
- vf.setInvalid(true);
- container.setViewData(key, vf);
- }
-
- /**
- * Marks the cell as valid.
- *
- * @param container the viewData provider (usually a column or list view)
- * @param key the key identifying this item
- */
- public static void validate(HasViewData container, Object key) {
- container.setViewData(key, null);
- }
+public class ValidatableInputCell extends AbstractEditableCell<
+ String, ValidatableField<String>> {
@Override
public boolean consumesEvents() {
@@ -63,11 +35,9 @@
}
@Override
- @SuppressWarnings("unchecked") // cast to ValidatableField<String>
- public Object onBrowserEvent(Element parent, String value,
- Object viewData, NativeEvent event,
- ValueUpdater<String> valueUpdater) {
- ValidatableField<String> vf = (ValidatableField<String>) viewData;
+ public void onBrowserEvent(Element parent, String value, Object key,
+ NativeEvent event, ValueUpdater<String> valueUpdater) {
+ ValidatableField<String> vf = getViewData(key);
if (event.getType().equals("change")) {
InputElement input = parent.getFirstChild().cast();
@@ -78,18 +48,21 @@
// Create a new ValidatableField if needed
if (vf == null) {
vf = new DefaultValidatableField<String>(input.getValue());
+ setViewData(key, vf);
}
vf.setValue(input.getValue());
valueUpdater.update(vf.getValue());
}
-
- return vf;
}
@Override
- @SuppressWarnings("unchecked") // cast to ValidatableField<String>
- public void render(String value, Object viewData, StringBuilder sb) {
- ValidatableField<String> vf = (ValidatableField<String>) viewData;
+ public void render(String value, Object key, StringBuilder sb) {
+ // Get the view data.
+ ValidatableField<String> vf = getViewData(key);
+ if (vf != null && vf.getValue().equals(value)) {
+ clearViewData(key);
+ vf = null;
+ }
/*
* If viewData is null, just paint the contents black. If it is non-null,
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidationRecipe.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidationRecipe.java
index d164699..1f6c927 100644
--- a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidationRecipe.java
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/ValidationRecipe.java
@@ -22,6 +22,7 @@
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListViewAdapter;
+import com.google.gwt.view.client.ProvidesKey;
import java.util.List;
@@ -73,7 +74,7 @@
@Override
protected Widget createWidget() {
- ListViewAdapter<Address> adapter = new ListViewAdapter<Address>();
+ final ListViewAdapter<Address> adapter = new ListViewAdapter<Address>();
final List<Address> list = adapter.getList();
for (int i = 10; i < 50; i++) {
if (zipInvalid(30000 + i)) {
@@ -84,7 +85,13 @@
list.add(new Address("GA", zip));
}
+ final ProvidesKey<Address> keyProvider = new ProvidesKey<Address>() {
+ public Object getKey(Address item) {
+ return item.key;
+ }
+ };
CellTable<Address> table = new CellTable<Address>(10);
+ table.setKeyProvider(keyProvider);
adapter.addView(table);
TextColumn<Address> stateColumn = new TextColumn<Address>() {
@Override
@@ -93,16 +100,17 @@
}
};
- final Column<Address, String> zipColumn =
- new Column<Address, String>(new ValidatableInputCell()) {
+ final ValidatableInputCell zipCell = new ValidatableInputCell();
+ Column<Address, String> zipColumn = new Column<Address, String>(
+ zipCell) {
@Override
public String getValue(Address object) {
return object.zip;
}
};
zipColumn.setFieldUpdater(new FieldUpdater<Address, String>() {
- public void update(final int index, final Address address,
- final String value) {
+ public void update(
+ final int index, final Address address, final String value) {
// Perform validation after a 2-second delay
new Timer() {
@Override
@@ -118,14 +126,16 @@
// Update the value.
final Address newAddress = new Address(address);
- newAddress.zip = value;
newAddress.zipInvalid = zipInvalid;
-
if (zipInvalid) {
- ValidatableInputCell.invalidate(zipColumn, newAddress,
- newAddress.zip);
+ // Update the view data to mark the pending value as invalid.
+ ValidatableField<String> vf = zipCell.getViewData(
+ keyProvider.getKey(address));
+ vf.setInvalid(true);
+ adapter.refresh();
} else {
- ValidatableInputCell.validate(zipColumn, newAddress);
+ // The cell will clear the view data when it sees the updated zip.
+ newAddress.zip = value;
}
list.set(index, newAddress);
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/gwtLogo.png b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/gwtLogo.png
new file mode 100644
index 0000000..f08094e
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/gwtLogo.png
Binary files differ
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseDetails.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseDetails.java
index d23547f..ebefcd5 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseDetails.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/client/ExpenseDetails.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -15,11 +15,11 @@
*/
package com.google.gwt.sample.expenses.gwt.client;
+import com.google.gwt.cell.client.AbstractEditableCell;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.DateCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.NumberCell;
-import com.google.gwt.cell.client.SelectionCell;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
@@ -87,8 +87,8 @@
* Details about the current expense report on the right side of the app,
* including the list of expenses.
*/
-public class ExpenseDetails extends Composite implements
- ExpenseRecordChanged.Handler, ReportRecordChanged.Handler {
+public class ExpenseDetails extends Composite
+ implements ExpenseRecordChanged.Handler, ReportRecordChanged.Handler {
/**
* The maximum amount that can be approved for a given report.
@@ -131,31 +131,38 @@
/**
* The cell used for approval status.
*/
- private class ApprovalCell extends SelectionCell {
+ private class ApprovalCell extends AbstractEditableCell<
+ String, ApprovalViewData> {
private final String approvedText = Expenses.Approval.APPROVED.getText();
private final String deniedText = Expenses.Approval.DENIED.getText();
private final String errorIconHtml;
private final String pendingIconHtml;
- public ApprovalCell(List<String> options) {
- super(options);
-
+ public ApprovalCell() {
// Cache the html string for the error icon.
ImageResource errorIcon = Styles.resources().errorIcon();
- AbstractImagePrototype errorImg = AbstractImagePrototype.create(errorIcon);
+ AbstractImagePrototype errorImg = AbstractImagePrototype.create(
+ errorIcon);
errorIconHtml = errorImg.getHTML();
// Cache the html string for the pending icon.
ImageResource pendingIcon = Styles.resources().pendingCommit();
- AbstractImagePrototype pendingImg = AbstractImagePrototype.create(pendingIcon);
+ AbstractImagePrototype pendingImg = AbstractImagePrototype.create(
+ pendingIcon);
pendingIconHtml = pendingImg.getHTML();
}
@Override
- public Object onBrowserEvent(Element parent, String value, Object viewData,
+ public boolean consumesEvents() {
+ return true;
+ }
+
+ @Override
+ public void onBrowserEvent(Element parent, String value, Object key,
NativeEvent event, ValueUpdater<String> valueUpdater) {
String type = event.getType();
+ ApprovalViewData viewData = getViewData(key);
if ("change".equals(type)) {
// Disable the select box.
SelectElement select = parent.getFirstChild().cast();
@@ -172,6 +179,12 @@
int index = select.getSelectedIndex();
String pendingValue = select.getOptions().getItem(index).getValue();
viewData = new ApprovalViewData(pendingValue);
+ setViewData(key, viewData);
+
+ // Update the value updater.
+ if (valueUpdater != null) {
+ valueUpdater.update(pendingValue);
+ }
} else if ("click".equals(type) && viewData != null
&& parent.getChildCount() >= 3) {
// Alert the user of the error
@@ -179,37 +192,37 @@
Element anchor = img.getNextSiblingElement();
if (anchor.isOrHasChild(Element.as(event.getEventTarget().cast()))) {
// Alert the user of the error.
- ApprovalViewData avd = (ApprovalViewData) viewData;
- showErrorPopup(avd.getRejectionText());
+ showErrorPopup(viewData.getRejectionText());
// Clear the view data now that we've viewed the message.
- viewData = null;
+ clearViewData(key);
parent.removeChild(anchor);
parent.removeChild(img);
}
}
- super.onBrowserEvent(parent, value, viewData, event, valueUpdater);
- return viewData;
}
@Override
- public void render(String value, Object viewData, StringBuilder sb) {
+ public void render(String value, Object key, StringBuilder sb) {
// Get the view data.
+ ApprovalViewData viewData = getViewData(key);
+ if (viewData != null && viewData.getPendingApproval().equals(value)) {
+ clearViewData(key);
+ viewData = null;
+ }
+
boolean isRejected = false;
boolean isDisabled = false;
String pendingValue = null;
String renderValue = value;
if (viewData != null) {
- ApprovalViewData avd = (ApprovalViewData) viewData;
- if (!avd.getPendingApproval().equals(value)) {
- isRejected = avd.isRejected();
- pendingValue = avd.getPendingApproval();
- if (!isRejected) {
- renderValue = pendingValue;
- // If there is a delta value that has not been rejected, then the
- // combo box should remain disabled.
- isDisabled = true;
- }
+ isRejected = viewData.isRejected();
+ pendingValue = viewData.getPendingApproval();
+ if (!isRejected) {
+ renderValue = pendingValue;
+ // If there is a delta value that has not been rejected, then the
+ // combo box should remain disabled.
+ isDisabled = true;
}
}
boolean isApproved = approvedText.equals(renderValue);
@@ -244,7 +257,8 @@
if (isRejected) {
// Add error icon if viewData does not match.
sb.append(errorIconHtml);
- sb.append("<a style='padding-left:3px;color:red;' href='javascript:;'>Error!</a>");
+ sb.append(
+ "<a style='padding-left:3px;color:red;' href='javascript:;'>Error!</a>");
} else if (pendingValue != null) {
// Add refresh icon if pending.
sb.append(pendingIconHtml);
@@ -340,7 +354,8 @@
TableStyle cellTableStyle();
}
- private static ExpenseDetailsUiBinder uiBinder = GWT.create(ExpenseDetailsUiBinder.class);
+ private static ExpenseDetailsUiBinder uiBinder = GWT.create(
+ ExpenseDetailsUiBinder.class);
@UiField
Element approvedLabel;
@@ -379,7 +394,7 @@
private List<SortableHeader> allHeaders = new ArrayList<SortableHeader>();
- private Column<ExpenseRecord, String> approvalColumn;
+ private ApprovalCell approvalCell;
/**
* The default {@link Comparator} used for sorting.
@@ -490,7 +505,7 @@
list.set(index, newRecord);
// Update the view data if the approval has been updated.
- ApprovalViewData avd = (ApprovalViewData) approvalColumn.getViewData(newKey);
+ ApprovalViewData avd = approvalCell.getViewData(newKey);
if (avd != null
&& avd.getPendingApproval().equals(newRecord.getApproval())) {
syncCommit(newRecord, null);
@@ -520,13 +535,13 @@
/**
* Set the {@link ReportRecord} to show.
- *
+ *
* @param report the {@link ReportRecord}
* @param department the selected department
* @param employee the selected employee
*/
- public void setReportRecord(ReportRecord report, String department,
- EmployeeRecord employee) {
+ public void setReportRecord(
+ ReportRecord report, String department, EmployeeRecord employee) {
this.report = report;
knownExpenseKeys = null;
reportName.setInnerText(report.getPurpose());
@@ -557,7 +572,8 @@
@UiFactory
CellTable<ExpenseRecord> createTable() {
CellTable.Resources resources = GWT.create(TableResources.class);
- CellTable<ExpenseRecord> view = new CellTable<ExpenseRecord>(100, resources);
+ CellTable<ExpenseRecord> view = new CellTable<ExpenseRecord>(
+ 100, resources);
Styles.Common common = Styles.common();
view.addColumnStyleName(0, common.spacerColumn());
view.addColumnStyleName(1, common.expenseDetailsDateColumn());
@@ -575,7 +591,8 @@
});
// Created column.
- GetValue<ExpenseRecord, Date> createdGetter = new GetValue<ExpenseRecord, Date>() {
+ GetValue<ExpenseRecord, Date> createdGetter = new GetValue<
+ ExpenseRecord, Date>() {
public Date getValue(ExpenseRecord object) {
return object.getCreated();
}
@@ -583,8 +600,8 @@
defaultComparator = createColumnComparator(createdGetter, false);
Comparator<ExpenseRecord> createdDesc = createColumnComparator(
createdGetter, true);
- addColumn(view, "Created", new DateCell(
- DateTimeFormat.getFormat("MMM dd yyyy")), createdGetter,
+ addColumn(view, "Created",
+ new DateCell(DateTimeFormat.getFormat("MMM dd yyyy")), createdGetter,
defaultComparator, createdDesc);
lastComparator = defaultComparator;
@@ -605,15 +622,16 @@
});
// Amount column.
- final GetValue<ExpenseRecord, Double> amountGetter = new GetValue<ExpenseRecord, Double>() {
+ final GetValue<ExpenseRecord, Double> amountGetter = new GetValue<
+ ExpenseRecord, Double>() {
public Double getValue(ExpenseRecord object) {
return object.getAmount();
}
};
- Comparator<ExpenseRecord> amountAsc = createColumnComparator(amountGetter,
- false);
- Comparator<ExpenseRecord> amountDesc = createColumnComparator(amountGetter,
- true);
+ Comparator<ExpenseRecord> amountAsc = createColumnComparator(
+ amountGetter, false);
+ Comparator<ExpenseRecord> amountDesc = createColumnComparator(
+ amountGetter, true);
addColumn(view, "Amount", new NumberCell(NumberFormat.getCurrencyFormat()),
new GetValue<ExpenseRecord, Number>() {
public Number getValue(ExpenseRecord object) {
@@ -637,17 +655,13 @@
});
// Approval column.
- List<String> options = new ArrayList<String>();
- // TODO(rice): I18N
- options.add("");
- options.add("Approved");
- options.add("Denied");
- approvalColumn = addColumn(view, "Approval Status", new ApprovalCell(
- options), new GetValue<ExpenseRecord, String>() {
- public String getValue(ExpenseRecord object) {
- return object.getApproval();
- }
- });
+ approvalCell = new ApprovalCell();
+ Column<ExpenseRecord, String> approvalColumn = addColumn(view,
+ "Approval Status", approvalCell, new GetValue<ExpenseRecord, String>() {
+ public String getValue(ExpenseRecord object) {
+ return object.getApproval();
+ }
+ });
approvalColumn.setFieldUpdater(new FieldUpdater<ExpenseRecord, String>() {
public void update(int index, final ExpenseRecord object, String value) {
if ("Denied".equals(value)) {
@@ -673,7 +687,7 @@
/**
* Add a column of a {@link Comparable} type using default comparators.
- *
+ *
* @param <C> the column type
* @param table the table
* @param text the header text
@@ -684,13 +698,14 @@
private <C extends Comparable<C>> Column<ExpenseRecord, C> addColumn(
final CellTable<ExpenseRecord> table, final String text,
final Cell<C> cell, final GetValue<ExpenseRecord, C> getter) {
- return addColumn(table, text, cell, getter, createColumnComparator(getter,
- false), createColumnComparator(getter, true));
+ return addColumn(table, text, cell, getter,
+ createColumnComparator(getter, false),
+ createColumnComparator(getter, true));
}
/**
* Add a column with the specified comparators.
- *
+ *
* @param <C> the column type
* @param table the table
* @param text the header text
@@ -729,8 +744,8 @@
}
}
- sortExpenses(items.getList(), header.getReverseSort() ? descComparator
- : ascComparator);
+ sortExpenses(items.getList(),
+ header.getReverseSort() ? descComparator : ascComparator);
table.redrawHeaders();
}
});
@@ -740,13 +755,14 @@
/**
* Create a comparator for the column.
- *
+ *
* @param <C> the column type
* @param getter the {@link GetValue} used to get the cell value
* @param descending true if descending, false if ascending
* @return the comparator
*/
- private <C extends Comparable<C>> Comparator<ExpenseRecord> createColumnComparator(
+ private <C extends Comparable<C>> Comparator<
+ ExpenseRecord> createColumnComparator(
final GetValue<ExpenseRecord, C> getter, final boolean descending) {
return new Comparator<ExpenseRecord>() {
public int compare(ExpenseRecord o1, ExpenseRecord o2) {
@@ -781,7 +797,8 @@
private void createErrorPopup() {
errorPopup.setGlassEnabled(true);
errorPopup.setStyleName(Styles.common().popupPanel());
- errorPopupMessage.addStyleName(Styles.common().expenseDetailsErrorPopupMessage());
+ errorPopupMessage.addStyleName(
+ Styles.common().expenseDetailsErrorPopupMessage());
Button closeButton = new Button("Dismiss", new ClickHandler() {
public void onClick(ClickEvent event) {
@@ -799,7 +816,7 @@
/**
* Return a formatted currency string.
- *
+ *
* @param amount the amount in dollars
* @return a formatted string
*/
@@ -827,7 +844,7 @@
/**
* Get the error message from a sync operation.
- *
+ *
* @param response the response of the operation
* @return the error message, or an empty string if no error.
*/
@@ -937,7 +954,7 @@
setNotesEditState(false, true, pendingNotes);
// Submit the delta.
- DeltaValueStore deltas = expensesRequestFactory.getValueStore().spawnDeltaView();
+ DeltaValueStore deltas = expensesRequestFactory.getValueStore().spawnDeltaView();
deltas.set(ReportRecord.notes, report, pendingNotes);
expensesRequestFactory.syncRequest(deltas).to(
new Receiver<Set<SyncResult>>() {
@@ -954,13 +971,13 @@
/**
* Set the state of the notes section.
- *
+ *
* @param editable true for edit state, false for view state
* @param pending true if changes are pending, false if not
* @param notesText the current notes
*/
- private void setNotesEditState(boolean editable, boolean pending,
- String notesText) {
+ private void setNotesEditState(
+ boolean editable, boolean pending, String notesText) {
notesBox.setText(notesText);
notes.setInnerText(notesText);
@@ -973,7 +990,7 @@
/**
* Show the error popup.
- *
+ *
* @param errorMessage the error message
*/
private void showErrorPopup(String errorMessage) {
@@ -981,35 +998,33 @@
errorPopup.center();
}
- private void sortExpenses(List<ExpenseRecord> list,
- final Comparator<ExpenseRecord> comparator) {
+ private void sortExpenses(
+ List<ExpenseRecord> list, final Comparator<ExpenseRecord> comparator) {
lastComparator = comparator;
Collections.sort(list, comparator);
}
/**
* Update the state of a pending approval change.
- *
+ *
* @param record the {@link ExpenseRecord} to sync
* @param message the error message if rejected, or null if accepted
*/
private void syncCommit(ExpenseRecord record, String message) {
final Object key = items.getKey(record);
if (message != null) {
- final ApprovalViewData avd = (ApprovalViewData) approvalColumn.getViewData(key);
+ final ApprovalViewData avd = approvalCell.getViewData(key);
if (avd != null) {
avd.reject(message);
}
- } else {
- approvalColumn.setViewData(key, null);
}
// Redraw the table so the changes are applied.
table.redraw();
}
- private void updateExpenseRecord(final ExpenseRecord record, String approval,
- String reasonDenied) {
+ private void updateExpenseRecord(
+ final ExpenseRecord record, String approval, String reasonDenied) {
// Verify that the total is under the cap.
if (Expenses.Approval.APPROVED.is(approval)
&& !Expenses.Approval.APPROVED.is(record.getApproval())) {
@@ -1023,7 +1038,7 @@
}
// Create a delta and sync with the value store.
- DeltaValueStore deltas = expensesRequestFactory.getValueStore().spawnDeltaView();
+ DeltaValueStore deltas = expensesRequestFactory.getValueStore().spawnDeltaView();
deltas.set(ExpenseRecord.approval, record, approval);
deltas.set(ExpenseRecord.reasonDenied, record, reasonDenied);
expensesRequestFactory.syncRequest(deltas).to(
@@ -1031,8 +1046,8 @@
public void onSuccess(Set<SyncResult> response) {
String errorMessage = getErrorMessageFromSync(response);
if (errorMessage.length() > 0) {
- syncCommit(record, errorMessage.length() > 0 ? errorMessage
- : null);
+ syncCommit(
+ record, errorMessage.length() > 0 ? errorMessage : null);
}
}
}).fire();
diff --git a/user/src/com/google/gwt/cell/client/AbstractCell.java b/user/src/com/google/gwt/cell/client/AbstractCell.java
index 85c2402..ad01ec0 100644
--- a/user/src/com/google/gwt/cell/client/AbstractCell.java
+++ b/user/src/com/google/gwt/cell/client/AbstractCell.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -20,11 +20,11 @@
/**
* A default implementation of the {@link Cell} interface.
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
- *
+ *
* @param <C> the type that this Cell represents
*/
public abstract class AbstractCell<C> implements Cell<C> {
@@ -37,16 +37,15 @@
return false;
}
- public Object onBrowserEvent(Element parent, C value, Object viewData,
+ public void onBrowserEvent(Element parent, C value, Object key,
NativeEvent event, ValueUpdater<C> valueUpdater) {
- return null;
}
- public abstract void render(C value, Object viewData, StringBuilder sb);
+ public abstract void render(C value, Object key, StringBuilder sb);
- public void setValue(Element parent, C value, Object viewData) {
+ public void setValue(Element parent, C value, Object key) {
StringBuilder sb = new StringBuilder();
- render(value, viewData, sb);
+ render(value, key, sb);
parent.setInnerHTML(sb.toString());
}
}
diff --git a/user/src/com/google/gwt/cell/client/AbstractEditableCell.java b/user/src/com/google/gwt/cell/client/AbstractEditableCell.java
new file mode 100644
index 0000000..26c49f7
--- /dev/null
+++ b/user/src/com/google/gwt/cell/client/AbstractEditableCell.java
@@ -0,0 +1,98 @@
+/*
+ * 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.cell.client;
+
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A default implementation of the {@link Cell} interface used for editable
+ * cells that need to save view data state for specific values.
+ *
+ * <p>
+ * Note: This class is new and its interface subject to change.
+ * </p>
+ *
+ * @param <C> the type that this Cell represents
+ * @param <V> the data type of the view data state
+ */
+public abstract class AbstractEditableCell<C, V> implements Cell<C> {
+
+ /**
+ * The map of value keys to the associated view data.
+ */
+ private final Map<Object, V> viewDataMap = new HashMap<Object, V>();
+
+ /**
+ * Clear the view data associated with the specified key.
+ *
+ * @param key the key identifying the row value
+ */
+ public void clearViewData(Object key) {
+ if (key != null) {
+ viewDataMap.remove(key);
+ }
+ }
+
+ public abstract boolean consumesEvents();
+
+ public boolean dependsOnSelection() {
+ return false;
+ }
+
+ /**
+ * Get the view data associated with the specified key.
+ *
+ * @param key the key identifying the row object
+ * @return the view data, or null if none has been set
+ */
+ public V getViewData(Object key) {
+ return (key == null) ? null : viewDataMap.get(key);
+ }
+
+ public abstract void onBrowserEvent(Element parent, C value, Object key,
+ NativeEvent event, ValueUpdater<C> valueUpdater);
+
+ public abstract void render(C value, Object key, StringBuilder sb);
+
+ public void setValue(Element parent, C value, Object key) {
+ StringBuilder sb = new StringBuilder();
+ render(value, key, sb);
+ parent.setInnerHTML(sb.toString());
+ }
+
+ /**
+ * Associate view data with the specified key. If the key is null, the view
+ * data will be ignored.
+ *
+ * @param key the key of the view data
+ * @param viewData the view data to associate
+ */
+ public void setViewData(Object key, V viewData) {
+ if (key == null) {
+ return;
+ }
+
+ if (viewData == null) {
+ clearViewData(key);
+ } else {
+ viewDataMap.put(key, viewData);
+ }
+ }
+}
diff --git a/user/src/com/google/gwt/cell/client/ActionCell.java b/user/src/com/google/gwt/cell/client/ActionCell.java
index 46e3352..988fc06 100644
--- a/user/src/com/google/gwt/cell/client/ActionCell.java
+++ b/user/src/com/google/gwt/cell/client/ActionCell.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -21,18 +21,18 @@
/**
* A cell that renders a button and takes a delegate to perform actions on
* mouseUp.
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
- *
+ *
* @param <C> the type that this Cell represents
*/
public class ActionCell<C> extends AbstractCell<C> {
/**
* The delegate that will handle events from the cell.
- *
+ *
* @param <T> the type that this delegate acts on
*/
public static interface Delegate<T> {
@@ -44,7 +44,7 @@
/**
* Construct a new {@link ActionCell}.
- *
+ *
* @param message the message to display on the button
* @param delegate the delegate that will handle events
*/
@@ -59,16 +59,15 @@
}
@Override
- public Void onBrowserEvent(Element parent, C value, Object viewData,
+ public void onBrowserEvent(Element parent, C value, Object key,
NativeEvent event, ValueUpdater<C> valueUpdater) {
if ("click".equals(event.getType())) {
delegate.execute(value);
}
- return null;
}
@Override
- public void render(C value, Object viewData, StringBuilder sb) {
+ public void render(C value, Object key, StringBuilder sb) {
sb.append("<button>" + message + "</button>");
}
}
diff --git a/user/src/com/google/gwt/cell/client/ButtonCell.java b/user/src/com/google/gwt/cell/client/ButtonCell.java
index 864c8a3..8c275ed 100644
--- a/user/src/com/google/gwt/cell/client/ButtonCell.java
+++ b/user/src/com/google/gwt/cell/client/ButtonCell.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -20,7 +20,7 @@
/**
* A {@link Cell} used to render a button.
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
@@ -33,17 +33,15 @@
}
@Override
- public Object onBrowserEvent(Element parent, String value, Object viewData,
+ public void onBrowserEvent(Element parent, String value, Object key,
NativeEvent event, ValueUpdater<String> valueUpdater) {
if (valueUpdater != null && "mouseup".equals(event.getType())) {
valueUpdater.update(value);
}
-
- return viewData;
}
@Override
- public void render(String data, Object viewData, StringBuilder sb) {
+ public void render(String data, Object key, StringBuilder sb) {
sb.append("<button>");
if (data != null) {
sb.append(data);
diff --git a/user/src/com/google/gwt/cell/client/Cell.java b/user/src/com/google/gwt/cell/client/Cell.java
index 816f50a..e313377 100644
--- a/user/src/com/google/gwt/cell/client/Cell.java
+++ b/user/src/com/google/gwt/cell/client/Cell.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -20,11 +20,11 @@
/**
* A light weight representation of a renderable object.
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
- *
+ *
* @param <C> the type that this Cell represents
*/
public interface Cell<C> {
@@ -37,44 +37,43 @@
/**
* Check if this cell depends on the selection state.
- *
- * @return true if dependant on selection, false if not
+ *
+ * @return true if dependent on selection, false if not
*/
boolean dependsOnSelection();
/**
* Handle a browser event that took place within the cell. The default
* implementation returns null.
- *
+ *
* @param parent the parent Element
* @param value the value associated with the cell
- * @param viewData the view data associated with the cell, or null
+ * @param key the unique key associated with the row object
* @param event the native browser event
- * @param valueUpdater a {@link ValueUpdater}, or null
- * @return a view data object which may be the one passed in or a new object
+ * @param valueUpdater a {@link ValueUpdater}, or null if not specified
*/
- Object onBrowserEvent(Element parent, C value,
- Object viewData, NativeEvent event, ValueUpdater<C> valueUpdater);
+ void onBrowserEvent(Element parent, C value, Object key, NativeEvent event,
+ ValueUpdater<C> valueUpdater);
/**
* Render a cell as HTML into a StringBuilder, suitable for passing to
* {@link Element#setInnerHTML} on a container element.
- *
+ *
* @param value the cell value to be rendered
- * @param viewData view data associated with the cell
+ * @param key the unique key associated with the row object
* @param sb the StringBuilder to be written to
*/
- void render(C value, Object viewData, StringBuilder sb);
+ void render(C value, Object key, StringBuilder sb);
/**
* This method may be used by cell containers to set the value on a single
* cell directly, rather than using {@link Element#setInnerHTML(String)}. See
* {@link AbstractCell#setValue(Element, Object, Object)} for a default
* implementation that uses {@link #render(Object, Object, StringBuilder)}.
- *
+ *
* @param parent the parent Element
* @param value the value associated with the cell
- * @param viewData the view data associated with the cell, or null
+ * @param key the unique key associated with the row object
*/
- void setValue(Element parent, C value, Object viewData);
+ void setValue(Element parent, C value, Object key);
}
diff --git a/user/src/com/google/gwt/cell/client/CheckboxCell.java b/user/src/com/google/gwt/cell/client/CheckboxCell.java
index 0835b99..a52fbb8 100644
--- a/user/src/com/google/gwt/cell/client/CheckboxCell.java
+++ b/user/src/com/google/gwt/cell/client/CheckboxCell.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -21,12 +21,12 @@
/**
* A {@link Cell} used to render a checkbox.
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
*/
-public class CheckboxCell extends AbstractCell<Boolean> {
+public class CheckboxCell extends AbstractEditableCell<Boolean, Boolean> {
@Override
public boolean consumesEvents() {
@@ -34,22 +34,34 @@
}
@Override
- public Object onBrowserEvent(Element parent, Boolean value, Object viewData,
+ public void onBrowserEvent(Element parent, Boolean value, Object key,
NativeEvent event, ValueUpdater<Boolean> valueUpdater) {
String type = event.getType();
- if (valueUpdater != null && "change".equals(type)) {
+ if ("change".equals(type)) {
InputElement input = parent.getFirstChild().cast();
- valueUpdater.update(input.isChecked());
+ Boolean isChecked = input.isChecked();
+ setViewData(key, isChecked);
+ if (valueUpdater != null) {
+ valueUpdater.update(isChecked);
+ }
}
-
- return viewData;
}
@Override
- public void render(Boolean data, Object viewData, StringBuilder sb) {
+ public void render(Boolean value, Object key, StringBuilder sb) {
+ // Get the view data.
+ Boolean viewData = getViewData(key);
+ if (viewData != null && viewData.equals(value)) {
+ clearViewData(key);
+ viewData = null;
+ }
+
sb.append("<input type=\"checkbox\"");
- if ((data != null) && (data == true)) {
- sb.append(" checked");
+ if (value != null) {
+ boolean isChecked = (viewData != null) ? viewData : value;
+ if (isChecked) {
+ sb.append(" checked");
+ }
}
sb.append("/>");
}
diff --git a/user/src/com/google/gwt/cell/client/ClickableTextCell.java b/user/src/com/google/gwt/cell/client/ClickableTextCell.java
index bab5b45..20d63df 100644
--- a/user/src/com/google/gwt/cell/client/ClickableTextCell.java
+++ b/user/src/com/google/gwt/cell/client/ClickableTextCell.java
@@ -21,7 +21,7 @@
/**
* A {@link Cell} used to render text. Clicking on the call causes its
* {@link ValueUpdater} to be called.
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
@@ -34,17 +34,16 @@
}
@Override
- public Object onBrowserEvent(Element parent, String value, Object viewData,
+ public void onBrowserEvent(Element parent, String value, Object key,
NativeEvent event, ValueUpdater<String> valueUpdater) {
String type = event.getType();
if (valueUpdater != null && type.equals("click")) {
valueUpdater.update(value);
}
- return null;
}
@Override
- public void render(String value, Object viewData, StringBuilder sb) {
+ public void render(String value, Object key, StringBuilder sb) {
if (value != null) {
sb.append(value);
}
diff --git a/user/src/com/google/gwt/cell/client/CompositeCell.java b/user/src/com/google/gwt/cell/client/CompositeCell.java
index 07814d9..44c5c37 100644
--- a/user/src/com/google/gwt/cell/client/CompositeCell.java
+++ b/user/src/com/google/gwt/cell/client/CompositeCell.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -26,25 +26,25 @@
* <p>
* A {@link Cell} that is composed of other {@link Cell}s.
* </p>
- *
+ *
* <p>
* When this cell is rendered, it will render each component {@link Cell} inside
* a span. If the component {@link Cell} uses block level elements (such as a
* Div), the component cells will stack vertically.
* </p>
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
- *
+ *
* @param <C> the type that this Cell represents
*/
public class CompositeCell<C> extends AbstractCell<C> {
/**
* The cells that compose this {@link Cell}.
- *
- * NOTE: Do not add add/insert/remove hasCells methods to the API. This cell
+ *
+ * NOTE: Do not add add/insert/remove hasCells methods to the API. This cell
* assumes that the index of the cellParent corresponds to the index in the
* hasCells array.
*/
@@ -52,7 +52,7 @@
/**
* Construct a new {@link CompositeCell}.
- *
+ *
* @param hasCells the cells that makeup the composite
*/
public CompositeCell(List<HasCell<C, ?>> hasCells) {
@@ -83,7 +83,7 @@
}
@Override
- public Object onBrowserEvent(Element parent, C value, Object viewData,
+ public void onBrowserEvent(Element parent, C value, Object key,
NativeEvent event, ValueUpdater<C> valueUpdater) {
int index = 0;
EventTarget eventTarget = event.getEventTarget();
@@ -92,43 +92,42 @@
Element wrapper = parent.getFirstChildElement();
while (wrapper != null) {
if (wrapper.isOrHasChild(target)) {
- return onBrowserEventImpl(wrapper, value, viewData, event,
- valueUpdater, hasCells.get(index));
+ onBrowserEventImpl(
+ wrapper, value, key, event, valueUpdater, hasCells.get(index));
}
index++;
wrapper = wrapper.getNextSiblingElement();
}
}
- return viewData;
}
@Override
- public void render(C value, Object viewData, StringBuilder sb) {
+ public void render(C value, Object key, StringBuilder sb) {
for (HasCell<C, ?> hasCell : hasCells) {
- render(value, viewData, sb, hasCell);
+ render(value, key, sb, hasCell);
}
}
@Override
- public void setValue(Element parent, C object, Object viewData) {
+ public void setValue(Element parent, C object, Object key) {
Element curChild = parent.getFirstChildElement();
for (HasCell<C, ?> hasCell : hasCells) {
- setValueImpl(curChild, object, viewData, hasCell);
+ setValueImpl(curChild, object, key, hasCell);
curChild = curChild.getNextSiblingElement();
}
}
- protected <X> void render(C value, Object viewData, StringBuilder sb,
- HasCell<C, X> hasCell) {
+ protected <X> void render(
+ C value, Object key, StringBuilder sb, HasCell<C, X> hasCell) {
Cell<X> cell = hasCell.getCell();
sb.append("<span>");
- cell.render(hasCell.getValue(value), viewData, sb);
+ cell.render(hasCell.getValue(value), key, sb);
sb.append("</span>");
}
- private <X> Object onBrowserEventImpl(Element parent, final C object,
- Object viewData, NativeEvent event, final ValueUpdater<C> valueUpdater,
+ private <X> void onBrowserEventImpl(Element parent, final C object,
+ Object key, NativeEvent event, final ValueUpdater<C> valueUpdater,
final HasCell<C, X> hasCell) {
ValueUpdater<X> tempUpdater = null;
final FieldUpdater<C, X> fieldUpdater = hasCell.getFieldUpdater();
@@ -143,12 +142,12 @@
};
}
Cell<X> cell = hasCell.getCell();
- return cell.onBrowserEvent(parent, hasCell.getValue(object), viewData,
- event, tempUpdater);
+ cell.onBrowserEvent(
+ parent, hasCell.getValue(object), key, event, tempUpdater);
}
- private <X> void setValueImpl(Element cellParent, C object, Object viewData,
- HasCell<C, X> hasCell) {
- hasCell.getCell().setValue(cellParent, hasCell.getValue(object), viewData);
+ private <X> void setValueImpl(
+ Element cellParent, C object, Object key, HasCell<C, X> hasCell) {
+ hasCell.getCell().setValue(cellParent, hasCell.getValue(object), key);
}
}
diff --git a/user/src/com/google/gwt/cell/client/DateCell.java b/user/src/com/google/gwt/cell/client/DateCell.java
index bfa0096..9aeaf3c 100644
--- a/user/src/com/google/gwt/cell/client/DateCell.java
+++ b/user/src/com/google/gwt/cell/client/DateCell.java
@@ -16,12 +16,13 @@
package com.google.gwt.cell.client;
import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
import java.util.Date;
/**
* A {@link Cell} used to render {@link Date}s.
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
@@ -31,23 +32,24 @@
private final DateTimeFormat format;
/**
- * TODO: doc.
+ * Construct a new {@link DateCell} using the format
+ * {@link PredefinedFormat#DATE_FULL}.
*/
public DateCell() {
- this(DateTimeFormat.getFullDateFormat());
+ this(DateTimeFormat.getFormat(PredefinedFormat.DATE_FULL));
}
/**
- * TODO: doc.
- *
- * @param format
+ * Construct a new {@link DateCell} using the specified format.
+ *
+ * @param format the {@link DateTimeFormat} used to render the date
*/
public DateCell(DateTimeFormat format) {
this.format = format;
}
@Override
- public void render(Date value, Object viewData, StringBuilder sb) {
+ public void render(Date value, Object key, StringBuilder sb) {
if (value != null) {
sb.append(format.format(value));
}
diff --git a/user/src/com/google/gwt/cell/client/DatePickerCell.java b/user/src/com/google/gwt/cell/client/DatePickerCell.java
index 4ce2cd2..4ac0344 100644
--- a/user/src/com/google/gwt/cell/client/DatePickerCell.java
+++ b/user/src/com/google/gwt/cell/client/DatePickerCell.java
@@ -43,12 +43,12 @@
* if a single DatePickerCell is used as the cell for a column in a table, only
* one entry in that column will be editable at a given time.
* </p>
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
*/
-public class DatePickerCell extends AbstractCell<Date> {
+public class DatePickerCell extends AbstractEditableCell<Date, Date> {
private static final int ESCAPE = 27;
@@ -56,13 +56,17 @@
private final DateTimeFormat format;
private int offsetX = 10;
private int offsetY = 10;
+ private Object lastKey;
+ private Element lastParent;
+ private Date lastValue;
private PopupPanel panel;
private ValueUpdater<Date> valueUpdater;
/**
- * Constructs a new DatePickerCell that uses the date/time format
- * given by {@link DateTimeFormat#getFullDateFormat}.
+ * Constructs a new DatePickerCell that uses the date/time format given by
+ * {@link DateTimeFormat#getFullDateFormat}.
*/
+ @SuppressWarnings("deprecation")
public DatePickerCell() {
this(DateTimeFormat.getFullDateFormat());
}
@@ -91,19 +95,34 @@
datePicker.addValueChangeHandler(new ValueChangeHandler<Date>() {
public void onValueChange(ValueChangeEvent<Date> event) {
panel.hide();
- valueUpdater.update(event.getValue());
+ Date date = event.getValue();
+ setViewData(lastKey, date);
+ setValue(lastParent, lastValue, lastKey);
+ if (valueUpdater != null) {
+ valueUpdater.update(date);
+ }
}
});
}
@Override
- public Object onBrowserEvent(final Element parent, Date value, Object viewData,
+ public boolean consumesEvents() {
+ return true;
+ }
+
+ @Override
+ public void onBrowserEvent(final Element parent, Date value, Object key,
NativeEvent event, ValueUpdater<Date> valueUpdater) {
- if (event.getType().equals("click")) {
+ if (value != null && event.getType().equals("click")) {
+ this.lastKey = key;
+ this.lastParent = parent;
+ this.lastValue = value;
this.valueUpdater = valueUpdater;
- datePicker.setCurrentMonth(value);
- datePicker.setValue(value);
+ Date viewData = getViewData(key);
+ Date date = (viewData == null) ? value : viewData;
+ datePicker.setCurrentMonth(date);
+ datePicker.setValue(date);
panel.setPopupPositionAndShow(new PositionCallback() {
public void setPosition(int offsetWidth, int offsetHeight) {
panel.setPopupPosition(parent.getAbsoluteLeft() + offsetX,
@@ -111,12 +130,20 @@
}
});
}
- return viewData;
}
@Override
- public void render(Date value, Object viewData, StringBuilder sb) {
- if (value != null) {
+ public void render(Date value, Object key, StringBuilder sb) {
+ // Get the view data.
+ Date viewData = getViewData(key);
+ if (viewData != null && viewData.equals(value)) {
+ clearViewData(key);
+ viewData = null;
+ }
+
+ if (viewData != null) {
+ sb.append(format.format(viewData));
+ } else if (value != null) {
sb.append(format.format(value));
}
}
diff --git a/user/src/com/google/gwt/cell/client/EditTextCell.java b/user/src/com/google/gwt/cell/client/EditTextCell.java
index a836469..8e91218 100644
--- a/user/src/com/google/gwt/cell/client/EditTextCell.java
+++ b/user/src/com/google/gwt/cell/client/EditTextCell.java
@@ -22,16 +22,104 @@
/**
* An editable text cell. Click to edit, escape to cancel, return to commit.
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
- *
+ *
* Important TODO: This cell still treats its value as HTML for rendering
* purposes, which is entirely wrong. It should be able to treat it as a proper
* string (especially since that's all the user can enter).
*/
-public class EditTextCell extends AbstractCell<String> {
+public class EditTextCell extends AbstractEditableCell<
+ String, EditTextCell.ViewData> {
+
+ /**
+ * The view data object used by this cell. We need to store both the text and
+ * the state because this cell is rendered differently in edit mode. If we did
+ * not store the edit state, refreshing the cell with view data would always
+ * put us in to edit state, rendering a text box instead of the new text
+ * string.
+ */
+ static class ViewData {
+ /**
+ * Keep track of the original value at the start of the edit, which might be
+ * the edited value from the previous edit and NOT the actual value.
+ */
+ private String original;
+ private String text;
+ private boolean isEditing;
+
+ /**
+ * If true, this is not the first edit.
+ */
+ private boolean isEditingAgain;
+
+ /**
+ * Construct a new ViewData in editing mode.
+ *
+ * @param text the text to edit
+ */
+ public ViewData(String text) {
+ this.original = text;
+ this.text = text;
+ this.isEditing = true;
+ this.isEditingAgain = false;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) {
+ return false;
+ }
+ ViewData vd = (ViewData) o;
+ return equalsOrBothNull(original, vd.original)
+ && equalsOrBothNull(text, vd.text) && isEditing == vd.isEditing
+ && isEditingAgain == vd.isEditingAgain;
+ }
+
+ public String getOriginal() {
+ return original;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ @Override
+ public int hashCode() {
+ return original.hashCode() + text.hashCode()
+ + Boolean.valueOf(isEditing).hashCode() * 29
+ + Boolean.valueOf(isEditingAgain).hashCode();
+ }
+
+ public boolean isEditing() {
+ return isEditing;
+ }
+
+ public boolean isEditingAgain() {
+ return isEditingAgain;
+ }
+
+ public void setEditing(boolean isEditing) {
+ boolean wasEditing = this.isEditing;
+ this.isEditing = isEditing;
+
+ // This is a subsequent edit, so start from where we left off.
+ if (!wasEditing && isEditing) {
+ isEditingAgain = true;
+ original = text;
+ }
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ private boolean equalsOrBothNull(Object o1, Object o2) {
+ return (o1 == null) ? o2 == null : o1.equals(o2);
+ }
+ }
@Override
public boolean consumesEvents() {
@@ -39,60 +127,124 @@
}
@Override
- public String onBrowserEvent(Element parent, String value, Object viewData,
+ public void onBrowserEvent(Element parent, String value, Object key,
NativeEvent event, ValueUpdater<String> valueUpdater) {
- if (viewData != null) {
- return editEvent(parent, value, (String) viewData, event, valueUpdater);
+ ViewData viewData = getViewData(key);
+ if (viewData != null && viewData.isEditing()) {
+ // Handle the edit event.
+ editEvent(parent, key, viewData, event, valueUpdater);
+ } else if ("click".equals(event.getType())) {
+ // Go into edit mode.
+ if (viewData == null) {
+ viewData = new ViewData(value);
+ setViewData(key, viewData);
+ } else {
+ viewData.setEditing(true);
+ }
+ edit(parent, value, key);
}
- return nonEditEvent(parent, value, event);
}
@Override
- public void render(String value, Object viewData, StringBuilder sb) {
+ public void render(String value, Object key, StringBuilder sb) {
+ // Get the view data.
+ ViewData viewData = getViewData(key);
+ if (viewData != null && !viewData.isEditing() && value != null
+ && value.equals(viewData.getText())) {
+ clearViewData(key);
+ viewData = null;
+ }
+
if (viewData != null) {
- sb.append("<input type='text' value='" + viewData + "'></input>");
+ if (viewData.isEditing()) {
+ sb.append(
+ "<input type='text' value='" + viewData.getText() + "'></input>");
+ } else {
+ // The user pressed enter, but view data still exists.
+ sb.append(viewData.getText());
+ }
} else if (value != null) {
sb.append(value);
}
}
- protected String edit(Element parent, String value) {
- setValue(parent, value, value);
+ /**
+ * Convert the cell to edit mode.
+ *
+ * @param parent the parent element
+ * @param value the current value
+ * @param key the key of the row object
+ */
+ protected void edit(Element parent, String value, Object key) {
+ setValue(parent, value, key);
InputElement input = (InputElement) parent.getFirstChild();
input.focus();
input.select();
- return value;
}
- private String cancel(Element parent, String value) {
+ /**
+ * Convert the cell to non-edit mode.
+ *
+ * @param parent the parent element
+ * @param value the current value
+ */
+ private void cancel(Element parent, String value) {
setValue(parent, value, null);
- return null;
}
- private String commit(Element parent, ValueUpdater<String> valueUpdater) {
+ /**
+ * Commit the current value.
+ *
+ * @param parent the parent element
+ * @param viewData the {@link ViewData} object
+ * @param valueUpdater the {@link ValueUpdater}
+ */
+ private void commit(
+ Element parent, ViewData viewData, ValueUpdater<String> valueUpdater) {
+ String value = updateViewData(parent, viewData, false);
+ setValue(parent, value, viewData);
+ valueUpdater.update(value);
+ }
+
+ private void editEvent(Element parent, Object key, ViewData viewData,
+ NativeEvent event, ValueUpdater<String> valueUpdater) {
+ String type = event.getType();
+ if ("keydown".equals(type)) {
+ int keyCode = event.getKeyCode();
+ if (keyCode == KeyCodes.KEY_ENTER) {
+ // Commit the change.
+ commit(parent, viewData, valueUpdater);
+ } else if (keyCode == KeyCodes.KEY_ESCAPE) {
+ // Cancel edit mode.
+ String originalText = viewData.getOriginal();
+ if (viewData.isEditingAgain()) {
+ viewData.setText(originalText);
+ viewData.setEditing(false);
+ } else {
+ setViewData(key, null);
+ }
+ cancel(parent, originalText);
+ }
+ } else if ("keyup".equals(type)) {
+ // Update the text in the view data on each key.
+ updateViewData(parent, viewData, true);
+ }
+ }
+
+ /**
+ * Update the view data based on the current value.
+ *
+ * @param parent the parent element
+ * @param viewData the {@link ViewData} object to update
+ * @param isEditing true if in edit mode
+ * @return the new value
+ */
+ private String updateViewData(
+ Element parent, ViewData viewData, boolean isEditing) {
InputElement input = (InputElement) parent.getFirstChild();
String value = input.getValue();
- valueUpdater.update(value);
- return cancel(parent, value);
- }
-
- private String editEvent(Element parent, String value, String viewData,
- NativeEvent event, ValueUpdater<String> valueUpdater) {
- if ("keydown".equals(event.getType())) {
- if (event.getKeyCode() == KeyCodes.KEY_ENTER) {
- return commit(parent, valueUpdater);
- }
- if (event.getKeyCode() == KeyCodes.KEY_ESCAPE) {
- return cancel(parent, value);
- }
- }
- return viewData;
- }
-
- private String nonEditEvent(Element parent, String value, NativeEvent event) {
- if ("click".equals(event.getType())) {
- return edit(parent, value);
- }
- return null;
+ viewData.setText(value);
+ viewData.setEditing(isEditing);
+ return value;
}
}
diff --git a/user/src/com/google/gwt/cell/client/IconCellDecorator.java b/user/src/com/google/gwt/cell/client/IconCellDecorator.java
index 086ba49..3af51ef 100644
--- a/user/src/com/google/gwt/cell/client/IconCellDecorator.java
+++ b/user/src/com/google/gwt/cell/client/IconCellDecorator.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -23,11 +23,11 @@
/**
* A {@link Cell} decorator that adds an icon to another {@link Cell}.
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
- *
+ *
* @param <C> the type that this Cell represents
*/
public class IconCellDecorator<C> extends AbstractCell<C> {
@@ -40,7 +40,7 @@
/**
* Construct a new {@link IconCellDecorator}. The icon and the content will be
* middle aligned by default.
- *
+ *
* @param icon the icon to use
* @param cell the cell to decorate
*/
@@ -50,7 +50,7 @@
/**
* Construct a new {@link IconCellDecorator}.
- *
+ *
* @param icon the icon to use
* @param cell the cell to decorate
* @param valign the vertical alignment attribute of the contents
@@ -75,14 +75,13 @@
}
@Override
- public Object onBrowserEvent(Element parent, C value, Object viewData,
+ public void onBrowserEvent(Element parent, C value, Object key,
NativeEvent event, ValueUpdater<C> valueUpdater) {
- return cell.onBrowserEvent(getCellParent(parent), value, viewData, event,
- valueUpdater);
+ cell.onBrowserEvent(getCellParent(parent), value, key, event, valueUpdater);
}
@Override
- public void render(C value, Object viewData, StringBuilder sb) {
+ public void render(C value, Object key, StringBuilder sb) {
sb.append("<div style='position:relative;padding-left:");
sb.append(imageWidth);
sb.append("px;'>");
@@ -92,19 +91,19 @@
sb.append(placeHolderHtml);
}
sb.append("<div>");
- cell.render(value, viewData, sb);
+ cell.render(value, key, sb);
sb.append("</div></div>");
}
@Override
- public void setValue(Element parent, C value, Object viewData) {
- cell.setValue(getCellParent(parent), value, viewData);
+ public void setValue(Element parent, C value, Object key) {
+ cell.setValue(getCellParent(parent), value, key);
}
/**
* Get the HTML string that represents the icon. Override this method to
* change the icon based on the value.
- *
+ *
* @param value the value being rendered
* @return the HTML string that represents the icon
*/
@@ -116,7 +115,7 @@
* Check if the icon should be used for the value. If the icon should not be
* used, a placeholder of the same size will be used instead. The default
* implementations returns true.
- *
+ *
* @param value the value being rendered
* @return true to use the icon, false to use a placeholder
*/
@@ -126,28 +125,29 @@
/**
* Get the HTML representation of an image. Visible for testing.
- *
+ *
* @param res the {@link ImageResource} to render as HTML
* @param valign the vertical alignment
* @param isPlaceholder if true, do not include the background image
* @return the rendered HTML
*/
// TODO(jlabanca): Move this to a Utility class.
- String getImageHtml(ImageResource res,
- VerticalAlignmentConstant valign, boolean isPlaceholder) {
+ String getImageHtml(ImageResource res, VerticalAlignmentConstant valign,
+ boolean isPlaceholder) {
// Add the position and dimensions.
StringBuilder sb = new StringBuilder();
sb.append("<div style=\"position:absolute;left:0px;top:0px;height:100%;");
sb.append("width:").append(res.getWidth()).append("px;");
-
+
// Add the background, vertically centered.
if (!isPlaceholder) {
- String vert = valign == HasVerticalAlignment.ALIGN_MIDDLE ? "center"
- : valign.getVerticalAlignString();
+ String vert = valign == HasVerticalAlignment.ALIGN_MIDDLE
+ ? "center" : valign.getVerticalAlignString();
sb.append("background:url('").append(res.getURL()).append("') ");
- sb.append("no-repeat scroll ").append(vert).append(" center transparent;");
+ sb.append("no-repeat scroll ").append(vert).append(
+ " center transparent;");
}
-
+
// Close the div and return.
sb.append("\"></div>");
return sb.toString();
@@ -155,7 +155,7 @@
/**
* Get the parent element of the decorated cell.
- *
+ *
* @param parent the parent of this cell
* @return the decorated cell's parent
*/
diff --git a/user/src/com/google/gwt/cell/client/NumberCell.java b/user/src/com/google/gwt/cell/client/NumberCell.java
index 5888c0e..27fab7e 100644
--- a/user/src/com/google/gwt/cell/client/NumberCell.java
+++ b/user/src/com/google/gwt/cell/client/NumberCell.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -36,7 +36,7 @@
/**
* Construct a new {@link NumberCell}.
- *
+ *
* @param format the {@link NumberFormat} used to render the number
*/
public NumberCell(NumberFormat format) {
@@ -44,7 +44,7 @@
}
@Override
- public void render(Number value, Object viewData, StringBuilder sb) {
+ public void render(Number value, Object key, StringBuilder sb) {
if (value != null) {
sb.append(format.format(value));
}
diff --git a/user/src/com/google/gwt/cell/client/SelectionCell.java b/user/src/com/google/gwt/cell/client/SelectionCell.java
index 6bfedb0..f53bc0f 100644
--- a/user/src/com/google/gwt/cell/client/SelectionCell.java
+++ b/user/src/com/google/gwt/cell/client/SelectionCell.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -25,19 +25,20 @@
/**
* A {@link Cell} used to render a drop-down list.
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
*/
-public class SelectionCell extends AbstractCell<String> {
+public class SelectionCell extends AbstractEditableCell<String, String> {
- private HashMap<String, Integer> indexForOption = new HashMap<String, Integer>();
+ private HashMap<String, Integer> indexForOption = new HashMap<
+ String, Integer>();
private final List<String> options;
/**
- * Contruct a new {@link SelectionCell} with the specified options.
- *
+ * Construct a new {@link SelectionCell} with the specified options.
+ *
* @param options the options in the cell.s
*/
public SelectionCell(List<String> options) {
@@ -49,19 +50,34 @@
}
@Override
- public Object onBrowserEvent(Element parent, String value, Object viewData,
- NativeEvent event, ValueUpdater<String> valueUpdater) {
- String type = event.getType();
- if (valueUpdater != null && "change".equals(type)) {
- SelectElement select = parent.getFirstChild().cast();
- valueUpdater.update(options.get(select.getSelectedIndex()));
- }
- return viewData;
+ public boolean consumesEvents() {
+ return true;
}
@Override
- public void render(String value, Object viewData, StringBuilder sb) {
- int selectedIndex = getSelectedIndex(value);
+ public void onBrowserEvent(Element parent, String value, Object key,
+ NativeEvent event, ValueUpdater<String> valueUpdater) {
+ String type = event.getType();
+ if ("change".equals(type)) {
+ SelectElement select = parent.getFirstChild().cast();
+ String newValue = options.get(select.getSelectedIndex());
+ setViewData(key, newValue);
+ if (valueUpdater != null) {
+ valueUpdater.update(newValue);
+ }
+ }
+ }
+
+ @Override
+ public void render(String value, Object key, StringBuilder sb) {
+ // Get the view data.
+ String viewData = getViewData(key);
+ if (viewData != null && viewData.equals(value)) {
+ clearViewData(key);
+ viewData = null;
+ }
+
+ int selectedIndex = getSelectedIndex(viewData == null ? value : viewData);
sb.append("<select>");
int index = 0;
for (String option : options) {
diff --git a/user/src/com/google/gwt/cell/client/TextCell.java b/user/src/com/google/gwt/cell/client/TextCell.java
index 9811fab..57a4eb5 100644
--- a/user/src/com/google/gwt/cell/client/TextCell.java
+++ b/user/src/com/google/gwt/cell/client/TextCell.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -17,11 +17,11 @@
/**
* A {@link Cell} used to render text.
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
- *
+ *
* Important TODO: This cell treats its value as HTML. We need to properly treat
* its value as a raw string, so that it's safe to use with unsanitized data.
* See the related comment in {@link EditTextCell}.
@@ -29,7 +29,7 @@
public class TextCell extends AbstractCell<String> {
@Override
- public void render(String value, Object viewData, StringBuilder sb) {
+ public void render(String value, Object key, StringBuilder sb) {
if (value != null) {
sb.append(value);
}
diff --git a/user/src/com/google/gwt/cell/client/TextInputCell.java b/user/src/com/google/gwt/cell/client/TextInputCell.java
index a885e07..61d5d16 100644
--- a/user/src/com/google/gwt/cell/client/TextInputCell.java
+++ b/user/src/com/google/gwt/cell/client/TextInputCell.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -21,12 +21,12 @@
/**
* A {@link AbstractCell} used to render a text input.
- *
+ *
* <p>
* Note: This class is new and its interface subject to change.
* </p>
*/
-public class TextInputCell extends AbstractCell<String> {
+public class TextInputCell extends AbstractEditableCell<String, String> {
@Override
public boolean consumesEvents() {
@@ -34,21 +34,37 @@
}
@Override
- public Object onBrowserEvent(Element parent, String value, Object viewData,
+ public void onBrowserEvent(Element parent, String value, Object key,
NativeEvent event, ValueUpdater<String> valueUpdater) {
- if (valueUpdater != null && "change".equals(event.getType())) {
+ String eventType = event.getType();
+ if ("change".equals(eventType)) {
InputElement input = parent.getFirstChild().cast();
- valueUpdater.update(input.getValue());
+ String newValue = input.getValue();
+ setViewData(key, newValue);
+ if (valueUpdater != null) {
+ valueUpdater.update(newValue);
+ }
+ } else if ("keyup".equals(eventType)) {
+ // Record keys as they are typed.
+ InputElement input = parent.getFirstChild().cast();
+ setViewData(key, input.getValue());
}
-
- return viewData;
}
@Override
- public void render(String data, Object viewData, StringBuilder sb) {
+ public void render(String value, Object key, StringBuilder sb) {
+ // Get the view data.
+ String viewData = getViewData(key);
+ if (viewData != null && viewData.equals(value)) {
+ clearViewData(key);
+ viewData = null;
+ }
+
sb.append("<input type='text'");
- if (data != null) {
- sb.append(" value='" + data + "'");
+ if (viewData != null) {
+ sb.append(" value='" + viewData + "'");
+ } else if (value != null) {
+ sb.append(" value='" + value + "'");
}
sb.append("></input>");
}
diff --git a/user/src/com/google/gwt/user/cellview/client/CellBrowser.java b/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
index 2fb3685..4d83d62 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -58,8 +58,8 @@
* A "browsable" view of a tree in which only a single node per level may be
* open at one time.
*/
-public class CellBrowser extends Composite implements ProvidesResize,
- RequiresResize, HasAnimation {
+public class CellBrowser extends Composite
+ implements ProvidesResize, RequiresResize, HasAnimation {
/**
* A ClientBundle that provides images for this widget.
@@ -138,7 +138,7 @@
/**
* A wrapper around a cell that adds an open button.
- *
+ *
* @param <C> the data type of the cell
*/
private class CellDecorator<C> extends AbstractCell<C> {
@@ -170,7 +170,7 @@
/**
* Construct a new {@link CellDecorator}.
- *
+ *
* @param nodeInfo the {@link NodeInfo} associated with the cell
* @param level the level of items rendered by this decorator
*/
@@ -192,12 +192,12 @@
}
@Override
- public Object onBrowserEvent(Element parent, C value, Object viewData,
+ public void onBrowserEvent(Element parent, C value, Object key,
NativeEvent event, ValueUpdater<C> valueUpdater) {
// Fire the event to the inner cell.
- viewData = cell.onBrowserEvent(getCellParent(parent), value, viewData,
- event, valueUpdater);
+ cell.onBrowserEvent(
+ getCellParent(parent), value, key, event, valueUpdater);
// Open child nodes.
if (Event.getTypeInt(event.getType()) == Event.ONMOUSEDOWN) {
@@ -220,16 +220,14 @@
}
}
}
-
- return viewData;
}
@Override
public void render(C value, Object viewData, StringBuilder sb) {
- boolean isOpen = (openKey == null) ? false
- : openKey.equals(providesKey.getKey(value));
- boolean isSelected = (selectionModel == null) ? false
- : selectionModel.isSelected(value);
+ boolean isOpen = (openKey == null) ? false : openKey.equals(
+ providesKey.getKey(value));
+ boolean isSelected = (selectionModel == null)
+ ? false : selectionModel.isSelected(value);
sb.append("<div style='position:relative;padding-right:");
sb.append(imageWidth);
sb.append("px;'");
@@ -264,7 +262,7 @@
/**
* Get the parent element of the decorated cell.
- *
+ *
* @param parent the parent of this cell
* @return the decorated cell's parent
*/
@@ -274,7 +272,7 @@
/**
* Get the image element of the decorated cell.
- *
+ *
* @param parent the parent of this cell
* @return the image element
*/
@@ -284,7 +282,7 @@
/**
* Get the ID of the open element.
- *
+ *
* @return the ID
*/
private String getOpenId() {
@@ -294,7 +292,7 @@
/**
* Replace the image element of a cell and update the styles associated with
* the open state.
- *
+ *
* @param parent the parent element of the cell
* @param open true if open, false if closed
*/
@@ -362,7 +360,7 @@
/**
* A node in the tree.
- *
+ *
* @param <C> the data type of the children of the node
*/
private class TreeNode<C> {
@@ -373,7 +371,7 @@
/**
* Construct a new {@link TreeNode}.
- *
+ *
* @param nodeInfo the nodeInfo for the children nodes
* @param listView the list view assocated with the node
* @param widget the widget that represents the list view
@@ -388,7 +386,7 @@
/**
* Get the {@link CellDecorator} used to render the node.
- *
+ *
* @return the cell decorator
*/
public CellDecorator<C> getCell() {
@@ -408,7 +406,8 @@
/**
* The element used in place of an image when a node has no children.
*/
- private static final String LEAF_IMAGE = "<div style='position:absolute;display:none;'></div>";
+ private static final String LEAF_IMAGE =
+ "<div style='position:absolute;display:none;'></div>";
private static Resources DEFAULT_RESOURCES;
@@ -496,7 +495,7 @@
/**
* Construct a new {@link CellBrowser}.
- *
+ *
* @param <T> the type of data in the root node
* @param viewModel the {@link TreeViewModel} that backs the tree
* @param rootValue the hidden root value of the tree
@@ -507,14 +506,14 @@
/**
* Construct a new {@link CellBrowser} with the specified {@link Resources}.
- *
+ *
* @param <T> the type of data in the root node
* @param viewModel the {@link TreeViewModel} that backs the tree
* @param rootValue the hidden root value of the tree
* @param resources the {@link Resources} used for images
*/
- public <T> CellBrowser(TreeViewModel viewModel, T rootValue,
- Resources resources) {
+ public <T> CellBrowser(
+ TreeViewModel viewModel, T rootValue, Resources resources) {
this.viewModel = viewModel;
this.style = resources.cellBrowserStyle();
this.style.ensureInjected();
@@ -551,7 +550,7 @@
/**
* Get the default width of new columns.
- *
+ *
* @return the default width in pixels
*/
public int getDefaultColumnWidth() {
@@ -560,7 +559,7 @@
/**
* Get the minimum width of columns.
- *
+ *
* @return the minimum width in pixels
*/
public int getMinimumColumnWidth() {
@@ -592,7 +591,7 @@
/**
* Set the default width of new columns.
- *
+ *
* @param width the default width in pixels
*/
public void setDefaultColumnWidth(int width) {
@@ -601,7 +600,7 @@
/**
* Set the minimum width of columns.
- *
+ *
* @param minWidth the minimum width in pixels
*/
public void setMinimumColumnWidth(int minWidth) {
@@ -611,7 +610,7 @@
/**
* Create a Pager to control the list view. The {@link ListView} must extend
* {@link Widget}.
- *
+ *
* @param <C> the item type in the list view
* @param listView the list view to add paging too
* @return the {@link Pager}
@@ -623,16 +622,17 @@
/**
* Create a {@link PagingListView} that will display items. The
* {@link PagingListView} must extend {@link Widget}.
- *
+ *
* @param <C> the item type in the list view
* @param nodeInfo the node info with child data
* @param cell the cell to use in the list view
* @return the {@link ListView}
*/
- protected <C> PagingListView<C> createPagingListView(NodeInfo<C> nodeInfo,
- Cell<C> cell) {
+ protected <C> PagingListView<C> createPagingListView(
+ NodeInfo<C> nodeInfo, Cell<C> cell) {
CellList<C> pagingListView = new CellList<C>(cell, getCellListResources());
pagingListView.setValueUpdater(nodeInfo.getValueUpdater());
+ pagingListView.setKeyProvider(nodeInfo.getProvidesKey());
return pagingListView;
}
@@ -652,7 +652,7 @@
/**
* Create a new {@link TreeNode} and append it to the end of the LayoutPanel.
- *
+ *
* @param <C> the data type of the children
* @param nodeInfo the info about the node
*/
@@ -726,8 +726,8 @@
};
// Create a TreeNode.
- TreeNode<C> treeNode = new TreeNode<C>(nodeInfo, listViewDelegate, cell,
- scrollable);
+ TreeNode<C> treeNode = new TreeNode<C>(
+ nodeInfo, listViewDelegate, cell, scrollable);
treeNodes.add(treeNode);
// Attach the view to the selection model and node info.
@@ -746,7 +746,7 @@
/**
* Get the HTML representation of an image.
- *
+ *
* @param res the {@link ImageResource} to render as HTML
* @return the rendered HTML
*/
@@ -767,7 +767,7 @@
/**
* Get the {@link SplitLayoutPanel} used to lay out the views.
- *
+ *
* @return the {@link SplitLayoutPanel}
*/
private SplitLayoutPanel getSplitLayoutPanel() {
@@ -776,7 +776,7 @@
/**
* Reduce the number of {@link ListView}s down to the specified level.
- *
+ *
* @param level the level to trim to
*/
private void trimToLevel(int level) {
diff --git a/user/src/com/google/gwt/user/cellview/client/CellList.java b/user/src/com/google/gwt/user/cellview/client/CellList.java
index b41fcdb..83e1a68 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellList.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellList.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -30,7 +30,9 @@
import com.google.gwt.user.cellview.client.PagingListViewPresenter.LoadingState;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.view.client.HasKeyProvider;
import com.google.gwt.view.client.PagingListView;
+import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.Range;
import com.google.gwt.view.client.SelectionModel;
@@ -39,10 +41,11 @@
/**
* A single column list of cells.
- *
+ *
* @param <T> the data type of list items
*/
-public class CellList<T> extends Widget implements PagingListView<T> {
+public class CellList<T> extends Widget
+ implements PagingListView<T>, HasKeyProvider<T> {
/**
* A ClientBundle that provides images for this widget.
@@ -102,8 +105,8 @@
int end = start + length;
for (int i = start; i < end; i++) {
T value = values.get(i - start);
- boolean isSelected = selectionModel == null ? false
- : selectionModel.isSelected(value);
+ boolean isSelected = selectionModel == null
+ ? false : selectionModel.isSelected(value);
// TODO(jlabanca): Factor out __idx because rows can move.
sb.append("<div onclick='' __idx='").append(i).append("'");
sb.append(" class='");
@@ -146,6 +149,7 @@
private final Element childContainer;
private String emptyListMessage = "";
private final Element emptyMessageElem;
+ private ProvidesKey<T> keyProvider;
private final PagingListViewPresenter<T> presenter;
private final Style style;
private ValueUpdater<T> valueUpdater;
@@ -153,7 +157,7 @@
/**
* Construct a new {@link CellList}.
- *
+ *
* @param cell the cell used to render each item
*/
public CellList(final Cell<T> cell) {
@@ -162,11 +166,10 @@
/**
* Construct a new {@link CellList} with the specified {@link Resources}.
- *
+ *
* @param cell the cell used to render each item
* @param resources the resources used for this widget
*/
- // TODO(jlabanca): Should cell support ViewData?
public CellList(final Cell<T> cell, Resources resources) {
this.cell = cell;
this.style = resources.cellListStyle();
@@ -196,7 +199,7 @@
/**
* Get the value of a displayed item.
- *
+ *
* @param indexOnPage the index on the page
* @return the value
*/
@@ -211,13 +214,17 @@
/**
* Get the message that is displayed when there is no data.
- *
+ *
* @return the empty message
*/
public String getEmptyListMessage() {
return emptyListMessage;
}
+ public ProvidesKey<T> getKeyProvider() {
+ return keyProvider;
+ }
+
public final int getPageSize() {
return getRange().getLength();
}
@@ -233,7 +240,7 @@
/**
* Get the {@link Element} for the specified index. If the element has not
* been created, null is returned.
- *
+ *
* @param indexOnPage the index on the page
* @return the element, or null if it doesn't exists
* @throws IndexOutOfBoundsException if the index is outside of the current
@@ -265,9 +272,10 @@
if (idxString.length() > 0) {
int idx = Integer.parseInt(idxString);
T value = presenter.getData().get(idx - getPageStart());
- cell.onBrowserEvent(target, value, null, event, valueUpdater);
+ cell.onBrowserEvent(target, value, getKey(value), event, valueUpdater);
+
if (event.getTypeInt() == Event.ONCLICK && !cell.consumesEvents()) {
- SelectionModel<? super T> selectionModel = presenter.getSelectionModel();
+ SelectionModel<? super T> selectionModel = presenter.getSelectionModel();
if (selectionModel != null) {
selectionModel.setSelected(value, true);
}
@@ -296,7 +304,7 @@
/**
* Set the message to display when there is no data.
- *
+ *
* @param html the message to display when there are no results
*/
public void setEmptyListMessage(String html) {
@@ -304,13 +312,17 @@
emptyMessageElem.setInnerHTML(html);
}
+ public void setKeyProvider(ProvidesKey<T> keyProvider) {
+ this.keyProvider = keyProvider;
+ }
+
public void setPager(Pager<T> pager) {
presenter.setPager(pager);
}
/**
* Set the page size.
- *
+ *
* @param pageSize the new page size
*/
public final void setPageSize(int pageSize) {
@@ -319,7 +331,7 @@
/**
* Set the page start index.
- *
+ *
* @param pageStart the new page start
*/
public final void setPageStart(int pageStart) {
@@ -330,13 +342,14 @@
presenter.setRange(start, length);
}
- public void setSelectionModel(final SelectionModel<? super T> selectionModel) {
+ public void setSelectionModel(
+ final SelectionModel<? super T> selectionModel) {
presenter.setSelectionModel(selectionModel);
}
/**
* Set the value updater to use when cells modify items.
- *
+ *
* @param valueUpdater the {@link ValueUpdater}
*/
public void setValueUpdater(ValueUpdater<T> valueUpdater) {
@@ -345,21 +358,32 @@
/**
* Checks that the row is within the correct bounds.
- *
+ *
* @param row row index to check
* @throws IndexOutOfBoundsException
*/
protected void checkRowBounds(int row) {
int rowCount = view.getChildCount();
if ((row >= rowCount) || (row < 0)) {
- throw new IndexOutOfBoundsException("Row index: " + row + ", Row size: "
- + rowCount);
+ throw new IndexOutOfBoundsException(
+ "Row index: " + row + ", Row size: " + rowCount);
}
}
/**
+ * Get the key for a given value. Defaults to the value if new
+ * {@link ProvidesKey} is specified.
+ *
+ * @param value the value
+ * @return the key for the value
+ */
+ private Object getKey(T value) {
+ return keyProvider == null ? value : keyProvider.getKey(value);
+ }
+
+ /**
* Show or hide an element.
- *
+ *
* @param element the element
* @param show true to show, false to hide
*/
diff --git a/user/src/com/google/gwt/user/cellview/client/CellTable.java b/user/src/com/google/gwt/user/cellview/client/CellTable.java
index 2abc00e..450c0c7 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellTable.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellTable.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -34,6 +34,7 @@
import com.google.gwt.user.cellview.client.PagingListViewPresenter.LoadingState;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.view.client.HasKeyProvider;
import com.google.gwt.view.client.PagingListView;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.Range;
@@ -44,10 +45,11 @@
/**
* A list view that supports paging and columns.
- *
+ *
* @param <T> the data type of each row
*/
-public class CellTable<T> extends Widget implements PagingListView<T> {
+public class CellTable<T> extends Widget
+ implements PagingListView<T>, HasKeyProvider<T> {
/**
* A cleaner version of the table that uses less graphics.
@@ -194,13 +196,13 @@
/**
* Convert the rowHtml into Elements wrapped by the specifeid table section.
- *
+ *
* @param sectionTag the table section tag
* @param rowHtml the Html for the rows
* @return the section element
*/
- protected TableSectionElement convertToSectionElement(String sectionTag,
- String rowHtml) {
+ protected TableSectionElement convertToSectionElement(
+ String sectionTag, String rowHtml) {
// Render the rows into a table.
// IE doesn't support innerHtml on a TableSection or Table element, so we
// generate the entire table.
@@ -218,13 +220,13 @@
} else if ("tfoot".equals(sectionTag)) {
return tableElem.getTFoot();
}
- throw new IllegalArgumentException("Invalid table section tag: "
- + sectionTag);
+ throw new IllegalArgumentException(
+ "Invalid table section tag: " + sectionTag);
}
/**
* Render and replace a table section in the table.
- *
+ *
* @param section the {@link TableSectionElement} to replace
* @param html the html to render
* @return the new section element
@@ -301,8 +303,8 @@
int end = start + length;
for (int i = start; i < end; i++) {
T value = values.get(i - start);
- boolean isSelected = (selectionModel == null || value == null) ? false
- : selectionModel.isSelected(value);
+ boolean isSelected = (selectionModel == null || value == null)
+ ? false : selectionModel.isSelected(value);
sb.append("<tr onclick=''");
sb.append(" class='");
sb.append(i % 2 == 0 ? style.evenRow() : style.oddRow());
@@ -413,16 +415,17 @@
/**
* The command used to redraw the table after adding columns.
*/
- private final Scheduler.ScheduledCommand redrawCommand = new Scheduler.ScheduledCommand() {
- public void execute() {
- redrawScheduled = false;
- if (redrawCancelled) {
- redrawCancelled = false;
- return;
- }
- redraw();
- }
- };
+ private final Scheduler.ScheduledCommand redrawCommand =
+ new Scheduler.ScheduledCommand() {
+ public void execute() {
+ redrawScheduled = false;
+ if (redrawCancelled) {
+ redrawCancelled = false;
+ return;
+ }
+ redraw();
+ }
+ };
/**
* Indicates whether or not a redraw is scheduled.
@@ -446,7 +449,7 @@
/**
* Constructs a table with the given page size.
- *
+ *
* @param pageSize the page size
*/
public CellTable(final int pageSize) {
@@ -456,7 +459,7 @@
/**
* Constructs a table with the given page size with the specified
* {@link Resources}.
- *
+ *
* @param pageSize the page size
* @param resources the resources to use for this widget
*/
@@ -495,8 +498,9 @@
// TODO: Total hack. It would almost definitely be preferable to sink only
// those events actually needed by cells.
- sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.KEYEVENTS
- | Event.ONCHANGE | Event.FOCUSEVENTS);
+ sinkEvents(
+ Event.ONCLICK | Event.MOUSEEVENTS | Event.KEYEVENTS | Event.ONCHANGE
+ | Event.FOCUSEVENTS);
}
/**
@@ -534,15 +538,15 @@
/**
* Adds a column to the table with an associated String header and footer.
*/
- public void addColumn(Column<T, ?> col, String headerString,
- String footerString) {
+ public void addColumn(
+ Column<T, ?> col, String headerString, String footerString) {
addColumn(col, new TextHeader(headerString), new TextHeader(footerString));
}
/**
* Add a style name to the {@link TableColElement} at the specified index,
* creating it if necessary.
- *
+ *
* @param index the column index
* @param styleName the style name to add
*/
@@ -592,7 +596,7 @@
/**
* Get the {@link TableRowElement} for the specified row. If the row element
* has not been created, null is returned.
- *
+ *
* @param row the row index
* @return the row element, or null if it doesn't exists
* @throws IndexOutOfBoundsException if the row index is outside of the
@@ -610,7 +614,7 @@
/**
* Check whether or not mouse selection is enabled.
- *
+ *
* @return true if enabled, false if disabled
*/
public boolean isSelectionEnabled() {
@@ -661,12 +665,12 @@
T value = presenter.getData().get(row);
Column<T, ?> column = columns.get(col);
- column.onBrowserEvent(cell, getPageStart() + row, value, event,
- providesKey);
+ column.onBrowserEvent(
+ cell, getPageStart() + row, value, event, providesKey);
// Update selection.
if (isSelectionEnabled && event.getTypeInt() == Event.ONCLICK) {
- SelectionModel<? super T> selectionModel = presenter.getSelectionModel();
+ SelectionModel<? super T> selectionModel = presenter.getSelectionModel();
if (selectionModel != null) {
selectionModel.setSelected(value, true);
}
@@ -694,7 +698,7 @@
/**
* Remove a column.
- *
+ *
* @param index the column index
*/
public void removeColumn(int index) {
@@ -711,7 +715,7 @@
/**
* Remove a column.
- *
+ *
* @param col the column to remove
*/
public void removeColumn(Column<T, ?> col) {
@@ -725,7 +729,7 @@
/**
* Remove a style from the {@link TableColElement} at the specified index.
- *
+ *
* @param index the column index
* @param styleName the style name to remove
*/
@@ -748,16 +752,8 @@
presenter.setDelegate(delegate);
}
- /**
- * Sets the {@link ProvidesKey} instance that will be used to generate keys
- * for each record object as needed.
- *
- * @param providesKey an instance of {@link ProvidesKey} used to generate keys
- * for record objects.
- */
- // TODO - when is this valid? Do we rehash column view data if it changes?
- public void setKeyProvider(ProvidesKey<T> providesKey) {
- this.providesKey = providesKey;
+ public void setKeyProvider(ProvidesKey<T> keyProvider) {
+ this.providesKey = keyProvider;
}
public void setPager(PagingListView.Pager<T> pager) {
@@ -766,9 +762,9 @@
/**
* Set the number of rows per page and refresh the table.
- *
+ *
* @param pageSize the page size
- *
+ *
* @throws IllegalArgumentException if pageSize is negative or 0
*/
public final void setPageSize(int pageSize) {
@@ -778,7 +774,7 @@
/**
* Set the starting index of the current visible page. The actual page start
* will be clamped in the range [0, getSize() - 1].
- *
+ *
* @param pageStart the index of the row that should appear at the start of
* the page
*/
@@ -792,7 +788,7 @@
/**
* Enable mouse and keyboard selection.
- *
+ *
* @param isSelectionEnabled true to enable, false to disable
*/
public void setSelectionEnabled(boolean isSelectionEnabled) {
@@ -805,21 +801,21 @@
/**
* Checks that the row is within the correct bounds.
- *
+ *
* @param row row index to check
* @throws IndexOutOfBoundsException
*/
protected void checkRowBounds(int row) {
int rowCount = view.getChildCount();
if ((row >= rowCount) || (row < 0)) {
- throw new IndexOutOfBoundsException("Row index: " + row + ", Row size: "
- + rowCount);
+ throw new IndexOutOfBoundsException(
+ "Row index: " + row + ", Row size: " + rowCount);
}
}
/**
* Render the header of footer.
- *
+ *
* @param isFooter true if this is the footer table, false if the header table
*/
private void createHeaders(boolean isFooter) {
@@ -836,14 +832,14 @@
sb.append("<th class='").append(className);
if (curColumn == 0) {
sb.append(" ");
- sb.append(isFooter ? style.firstColumnFooter()
- : style.firstColumnHeader());
+ sb.append(
+ isFooter ? style.firstColumnFooter() : style.firstColumnHeader());
}
// The first and last columns could be the same column.
if (curColumn == columnCount - 1) {
sb.append(" ");
- sb.append(isFooter ? style.lastColumnFooter()
- : style.lastColumnHeader());
+ sb.append(
+ isFooter ? style.lastColumnFooter() : style.lastColumnHeader());
}
sb.append("'>");
if (header != null) {
@@ -878,7 +874,7 @@
/**
* Get the {@link TableColElement} at the specified index, creating it if
* necessary.
- *
+ *
* @param index the column index
* @return the {@link TableColElement}
*/
@@ -920,7 +916,7 @@
/**
* Show or hide the loading icon.
- *
+ *
* @param visible true to show, false to hide.
*/
private void setLoadingIconVisible(boolean visible) {
diff --git a/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java b/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java
index 0905387..ad9904c 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -25,11 +25,11 @@
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.user.cellview.client.PagingListViewPresenter.LoadingState;
import com.google.gwt.user.client.ui.UIObject;
-import com.google.gwt.view.client.TreeViewModel;
import com.google.gwt.view.client.PagingListView;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.Range;
import com.google.gwt.view.client.SelectionModel;
+import com.google.gwt.view.client.TreeViewModel;
import com.google.gwt.view.client.TreeViewModel.NodeInfo;
import java.util.ArrayList;
@@ -41,7 +41,7 @@
/**
* A view of a tree node.
- *
+ *
* @param <T> the type that this view contains
*/
class CellTreeNodeView<T> extends UIObject {
@@ -49,21 +49,23 @@
/**
* The element used in place of an image when a node has no children.
*/
- private static final String LEAF_IMAGE = "<div style='position:absolute;display:none;'></div>";
+ private static final String LEAF_IMAGE =
+ "<div style='position:absolute;display:none;'></div>";
/**
* Returns the element that parents the cell contents of the node.
- *
+ *
* @param nodeElem the element that represents the node
* @return the cell parent within the node
*/
private static Element getCellParent(Element nodeElem) {
- return getSelectionElement(nodeElem).getFirstChildElement().getChild(1).cast();
+ return getSelectionElement(nodeElem).getFirstChildElement().getChild(
+ 1).cast();
}
/**
* Returns the element that selection is applied to.
- *
+ *
* @param nodeElem the element that represents the node
* @return the cell parent within the node
*/
@@ -73,7 +75,7 @@
/**
* Returns the element that selection is applied to.
- *
+ *
* @param nodeElem the element that represents the node
* @return the cell parent within the node
*/
@@ -83,7 +85,7 @@
/**
* Show or hide an element.
- *
+ *
* @param element the element to show or hide
* @param show true to show, false to hide
*/
@@ -98,7 +100,7 @@
/**
* The {@link com.google.gwt.view.client.ListView ListView} used to show
* children.
- *
+ *
* @param <C> the child item type
*/
private static class NodeCellList<C> implements PagingListView<C> {
@@ -233,7 +235,7 @@
/**
* Reload the open children after rendering new items in this node.
- *
+ *
* @param values the values being replaced
* @param start the start index
* @param savedViews the open nodes
@@ -244,12 +246,13 @@
int end = start + len;
int childCount = nodeView.getChildCount();
ProvidesKey<C> providesKey = nodeInfo.getProvidesKey();
- Element childElem = nodeView.ensureChildContainer().getFirstChildElement();
+ Element childElem = nodeView.ensureChildContainer().getFirstChildElement();
for (int i = start; i < end; i++) {
C childValue = values.get(i - start);
- CellTreeNodeView<C> child = nodeView.createTreeNodeView(nodeInfo,
- childElem, childValue, null);
- CellTreeNodeView<?> savedChild = savedViews.remove(providesKey.getKey(childValue));
+ CellTreeNodeView<C> child = nodeView.createTreeNodeView(
+ nodeInfo, childElem, childValue, null);
+ CellTreeNodeView<?> savedChild = savedViews.remove(
+ providesKey.getKey(childValue));
// Copy the saved child's state into the new child
if (savedChild != null) {
child.animationFrame = savedChild.animationFrame;
@@ -288,13 +291,13 @@
* Save the state of the open child nodes within the range of the
* specified values. Use {@link #loadChildState(List, int, Map)} to
* re-attach the open nodes after they have been replaced.
- *
+ *
* @param values the values being replaced
* @param start the start index
* @return the map of open nodes
*/
- private Map<Object, CellTreeNodeView<?>> saveChildState(List<C> values,
- int start) {
+ private Map<Object, CellTreeNodeView<?>> saveChildState(
+ List<C> values, int start) {
// Ensure that we have a children array.
if (nodeView.children == null) {
nodeView.children = new ArrayList<CellTreeNodeView<?>>();
@@ -304,7 +307,8 @@
int len = values.size();
int end = start + len;
int childCount = nodeView.getChildCount();
- Map<Object, CellTreeNodeView<?>> openNodes = new HashMap<Object, CellTreeNodeView<?>>();
+ Map<Object, CellTreeNodeView<?>> openNodes = new HashMap<
+ Object, CellTreeNodeView<?>>();
for (int i = start; i < end && i < childCount; i++) {
CellTreeNodeView<?> child = nodeView.getChildNode(i);
// Ignore child nodes that are closed.
@@ -315,7 +319,8 @@
// Trim the saved views down to the children that still exists.
ProvidesKey<C> providesKey = nodeInfo.getProvidesKey();
- Map<Object, CellTreeNodeView<?>> savedViews = new HashMap<Object, CellTreeNodeView<?>>();
+ Map<Object, CellTreeNodeView<?>> savedViews = new HashMap<
+ Object, CellTreeNodeView<?>>();
for (C childValue : values) {
// Remove any child elements that correspond to prior children
// so the call to setInnerHtml will not destroy them
@@ -343,8 +348,8 @@
this.nodeView = nodeView;
cell = nodeInfo.getCell();
- presenter = new PagingListViewPresenter<C>(this, new View(
- nodeView.ensureChildContainer()), pageSize);
+ presenter = new PagingListViewPresenter<C>(
+ this, new View(nodeView.ensureChildContainer()), pageSize);
// Use a pager to update buttons.
presenter.setPager(new Pager<C>() {
@@ -400,13 +405,14 @@
presenter.setRange(start, length);
}
- public void setSelectionModel(final SelectionModel<? super C> selectionModel) {
+ public void setSelectionModel(
+ final SelectionModel<? super C> selectionModel) {
presenter.setSelectionModel(selectionModel);
}
/**
* Assign this {@link PagingListView} to a new {@link CellTreeNodeView}.
- *
+ *
* @param nodeView the new node view
*/
private void setNodeView(CellTreeNodeView<?> nodeView) {
@@ -501,7 +507,7 @@
/**
* Construct a {@link CellTreeNodeView}.
- *
+ *
* @param tree the parent {@link CellTreeNodeView}
* @param parent the parent {@link CellTreeNodeView}
* @param parentNodeInfo the {@link NodeInfo} of the parent
@@ -528,7 +534,7 @@
/**
* Check whether or not this node is open.
- *
+ *
* @return true if open, false if closed
*/
public boolean isOpen() {
@@ -539,7 +545,7 @@
* Select this node.
*/
public void select() {
- SelectionModel<? super T> selectionModel = parentNodeInfo.getSelectionModel();
+ SelectionModel<? super T> selectionModel = parentNodeInfo.getSelectionModel();
if (selectionModel != null) {
selectionModel.setSelected(value, true);
}
@@ -547,7 +553,7 @@
/**
* Sets whether this item's children are displayed.
- *
+ *
* @param open whether the item is open
*/
public void setOpen(boolean open) {
@@ -615,7 +621,7 @@
/**
* Returns an instance of TreeNodeView of the same subclass as the calling
* object.
- *
+ *
* @param <C> the data type of the node's children
* @param nodeInfo a NodeInfo object describing the child nodes
* @param childElem the DOM element used to parent the new TreeNodeView
@@ -623,14 +629,14 @@
* @param viewData view data associated with the node
* @return a TreeNodeView of suitable type
*/
- protected <C> CellTreeNodeView<C> createTreeNodeView(NodeInfo<C> nodeInfo,
- Element childElem, C childValue, Object viewData) {
+ protected <C> CellTreeNodeView<C> createTreeNodeView(
+ NodeInfo<C> nodeInfo, Element childElem, C childValue, Object viewData) {
return new CellTreeNodeView<C>(tree, this, nodeInfo, childElem, childValue);
}
/**
* Fire an event to the {@link com.google.gwt.cell.client.AbstractCell}.
- *
+ *
* @param event the native event
* @return true if the cell consumes the event, false if not
*/
@@ -638,8 +644,9 @@
if (parentNodeInfo != null) {
Element cellParent = getCellParent();
Cell<T> parentCell = parentNodeInfo.getCell();
- parentCell.onBrowserEvent(cellParent, value, null, event,
- parentNodeInfo.getValueUpdater());
+ Object key = getValueKey();
+ parentCell.onBrowserEvent(
+ cellParent, value, key, event, parentNodeInfo.getValueUpdater());
return parentCell.consumesEvents();
}
return false;
@@ -654,7 +661,7 @@
/**
* Returns the element corresponding to the open/close image.
- *
+ *
* @return the open/close image element
*/
protected Element getImageElement() {
@@ -671,14 +678,14 @@
/**
* Set up the node when it is opened.
- *
+ *
* @param nodeInfo the {@link NodeInfo} that provides information about the
* child values
* @param <C> the child data type of the node
*/
protected <C> void onOpen(final NodeInfo<C> nodeInfo) {
- NodeCellList<C> view = new NodeCellList<C>(nodeInfo, this,
- tree.getDefaultNodeSize());
+ NodeCellList<C> view = new NodeCellList<C>(
+ nodeInfo, this, tree.getDefaultNodeSize());
listView = view;
view.setSelectionModel(nodeInfo.getSelectionModel());
nodeInfo.setView(view);
@@ -686,7 +693,7 @@
/**
* Ensure that the animation frame exists and return it.
- *
+ *
* @return the animation frame
*/
Element ensureAnimationFrame() {
@@ -702,7 +709,7 @@
/**
* Ensure that the child container exists and return it.
- *
+ *
* @return the child container
*/
Element ensureChildContainer() {
@@ -715,7 +722,7 @@
/**
* Ensure that the content container exists and return it.
- *
+ *
* @return the content container
*/
Element ensureContentContainer() {
@@ -746,7 +753,7 @@
/**
* Check if this node is a root node.
- *
+ *
* @return true if a root node
*/
boolean isRootNode() {
@@ -756,7 +763,8 @@
void showFewer() {
Range range = listView.getRange();
int defaultPageSize = listView.getDefaultPageSize();
- int maxSize = Math.max(defaultPageSize, range.getLength() - defaultPageSize);
+ int maxSize = Math.max(
+ defaultPageSize, range.getLength() - defaultPageSize);
listView.setRange(range.getStart(), maxSize);
}
@@ -769,7 +777,7 @@
/**
* Update the image based on the current state.
- *
+ *
* @param isLoading true if still loading data
*/
private void updateImage(boolean isLoading) {
@@ -782,8 +790,8 @@
boolean isTopLevel = parentNode.isRootNode();
String html = tree.getClosedImageHtml(isTopLevel);
if (open) {
- html = isLoading ? tree.getLoadingImageHtml()
- : tree.getOpenImageHtml(isTopLevel);
+ html = isLoading ? tree.getLoadingImageHtml() : tree.getOpenImageHtml(
+ isTopLevel);
}
if (nodeInfoLoaded && nodeInfo == null) {
html = LEAF_IMAGE;
diff --git a/user/src/com/google/gwt/user/cellview/client/Column.java b/user/src/com/google/gwt/user/cellview/client/Column.java
index 1a51504..0f5d27a 100644
--- a/user/src/com/google/gwt/user/cellview/client/Column.java
+++ b/user/src/com/google/gwt/user/cellview/client/Column.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -21,68 +21,23 @@
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
-import com.google.gwt.view.client.HasViewData;
import com.google.gwt.view.client.ProvidesKey;
-import java.util.HashMap;
-import java.util.Map;
-
/**
* A representation of a column in a table. The column may maintain view data
* for each cell on demand. New view data, if needed, is created by the cell's
* onBrowserEvent method, stored in the Column, and passed to future calls to
* Cell's {@link Cell#onBrowserEvent} and @link{Cell#render} methods.
- *
+ *
* @param <T> the row type
* @param <C> the column type
*/
-// TODO - when can we get rid of a view data object?
-// TODO - should viewData implement some interface? (e.g., with
-// commit/rollback/dispose)
-// TODO - have a ViewDataColumn superclass / SimpleColumn subclass
-public abstract class Column<T, C> implements HasViewData, HasCell<T, C> {
-
- /**
- * A {@link ValueUpdater} used by the {@link Column} to delay the field update
- * until after the view data has been set. After the view data has been set,
- * the delay is revoked and we pass updates directly to the
- * {@link FieldUpdater}.
- */
- private class DelayedValueUpdater implements ValueUpdater<C> {
-
- private boolean hasNewValue;
- private boolean isDelayed = true;
- private C newValue;
- private final int rowIndex;
- private final T rowObject;
-
- public DelayedValueUpdater(int rowIndex, T rowObject) {
- this.rowIndex = rowIndex;
- this.rowObject = rowObject;
- }
-
- public void flush() {
- isDelayed = false;
- if (hasNewValue && fieldUpdater != null) {
- fieldUpdater.update(rowIndex, rowObject, newValue);
- }
- }
-
- public void update(C value) {
- hasNewValue = true;
- newValue = value;
- if (!isDelayed) {
- flush();
- }
- }
- }
+public abstract class Column<T, C> implements HasCell<T, C> {
protected final Cell<C> cell;
protected FieldUpdater<T, C> fieldUpdater;
- protected Map<Object, Object> viewDataMap = new HashMap<Object, Object>();
-
public Column(Cell<C> cell) {
this.cell = cell;
}
@@ -110,10 +65,6 @@
public abstract C getValue(T object);
- public Object getViewData(Object key) {
- return viewDataMap.get(key);
- }
-
/**
* @param providesKey an instance of ProvidesKey<T>, or null if the record
* object should act as its own key.
@@ -121,53 +72,35 @@
public void onBrowserEvent(Element elem, final int index, final T object,
NativeEvent event, ProvidesKey<T> providesKey) {
Object key = getKey(object, providesKey);
- Object viewData = getViewData(key);
- DelayedValueUpdater valueUpdater = (fieldUpdater == null) ? null
- : new DelayedValueUpdater(index, object);
- Object newViewData = cell.onBrowserEvent(elem, getValue(object), viewData,
- event, valueUpdater);
-
- // We have to save the view data before calling the field updater, or the
- // view data will not be available.
- // TODO(jlabanca): This is a squirrelly.
- if (newViewData != viewData) {
- setViewData(key, newViewData);
- }
-
- // Call the FieldUpdater after setting the view data.
- if (valueUpdater != null) {
- valueUpdater.flush();
- }
+ ValueUpdater<C> valueUpdater = (fieldUpdater == null)
+ ? null : new ValueUpdater<C>() {
+ public void update(C value) {
+ fieldUpdater.update(index, object, value);
+ }
+ };
+ cell.onBrowserEvent(elem, getValue(object), key, event, valueUpdater);
}
/**
* Render the object into the cell.
- *
+ *
* @param object the object to render
* @param keyProvider the {@link ProvidesKey} for the object
* @param sb the buffer to render into
*/
public void render(T object, ProvidesKey<T> keyProvider, StringBuilder sb) {
Object key = getKey(object, keyProvider);
- cell.render(getValue(object), getViewData(key), sb);
+ cell.render(getValue(object), key, sb);
}
public void setFieldUpdater(FieldUpdater<T, C> fieldUpdater) {
this.fieldUpdater = fieldUpdater;
}
- public void setViewData(Object key, Object viewData) {
- if (viewData == null) {
- viewDataMap.remove(key);
- } else {
- viewDataMap.put(key, viewData);
- }
- }
-
/**
* Get the view keu for the object given the {@link ProvidesKey}. If the
* {@link ProvidesKey} is null, the object is used as the key.
- *
+ *
* @param object the row object
* @param keyProvider the {@link ProvidesKey}
* @return the key for the object
diff --git a/user/src/com/google/gwt/user/cellview/client/Header.java b/user/src/com/google/gwt/user/cellview/client/Header.java
index b51d265..f3d6e3c 100644
--- a/user/src/com/google/gwt/user/cellview/client/Header.java
+++ b/user/src/com/google/gwt/user/cellview/client/Header.java
@@ -42,7 +42,8 @@
public abstract H getValue();
public void onBrowserEvent(Element elem, NativeEvent event) {
- cell.onBrowserEvent(elem, getValue(), null, event, updater);
+ H value = getValue();
+ cell.onBrowserEvent(elem, value, getKey(), event, updater);
}
public void render(StringBuilder sb) {
@@ -52,4 +53,14 @@
public void setUpdater(ValueUpdater<H> updater) {
this.updater = updater;
}
+
+ /**
+ * Get the key for the header value. By default, the key is the same as the
+ * value. Override this method to return a custom key.
+ *
+ * @return the key associated with the value
+ */
+ protected Object getKey() {
+ return getValue();
+ }
}
diff --git a/user/src/com/google/gwt/view/client/HasKeyProvider.java b/user/src/com/google/gwt/view/client/HasKeyProvider.java
new file mode 100644
index 0000000..e568037
--- /dev/null
+++ b/user/src/com/google/gwt/view/client/HasKeyProvider.java
@@ -0,0 +1,46 @@
+/*
+ * 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.view.client;
+
+/**
+ * Interface for classes that have a {@link ProvidesKey}. Must be implemented by
+ * {@link com.google.gwt.cell.client.Cell} containers.
+ *
+ * <p>
+ * Note: This class is new and its interface subject to change.
+ * </p>
+ *
+ * @param <T> the data type
+ */
+public interface HasKeyProvider<T> {
+
+ /**
+ * Get the key provider.
+ *
+ * @return the {@link ProvidesKey}
+ */
+ ProvidesKey<T> getKeyProvider();
+
+ /**
+ * Sets the {@link ProvidesKey} instance that will be used to generate keys
+ * for each record object as needed.
+ *
+ * @param keyProvider an instance of {@link ProvidesKey} used to generate keys
+ * for record objects.
+ */
+ // TODO(jlabanca) - Do we rehash the view data if it changes?
+ void setKeyProvider(ProvidesKey<T> keyProvider);
+}
diff --git a/user/src/com/google/gwt/view/client/HasViewData.java b/user/src/com/google/gwt/view/client/HasViewData.java
deleted file mode 100644
index 2961091..0000000
--- a/user/src/com/google/gwt/view/client/HasViewData.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.view.client;
-
-/**
- * Interface that must be implemented by {@link com.google.gwt.cell.client.Cell}
- * containers.
- *
- * <p>
- * Note: This class is new and its interface subject to change.
- * </p>
- */
-public interface HasViewData {
-
- /**
- * Gets the view data associated with the given item.
- *
- * @param key the key of the item whose view data is desired
- * @return the view data
- */
- Object getViewData(Object key);
-
- /**
- * Sets the view data associated with the given item.
- *
- * @param key the key of the item whose view data will be set
- * @param viewData the view data
- */
- void setViewData(Object key, Object viewData);
-}
diff --git a/user/test/com/google/gwt/cell/CellSuite.java b/user/test/com/google/gwt/cell/CellSuite.java
new file mode 100644
index 0000000..e780b2e
--- /dev/null
+++ b/user/test/com/google/gwt/cell/CellSuite.java
@@ -0,0 +1,59 @@
+/*
+ * 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.cell;
+
+import com.google.gwt.cell.client.AbstractCellTest;
+import com.google.gwt.cell.client.ActionCellTest;
+import com.google.gwt.cell.client.ButtonCellTest;
+import com.google.gwt.cell.client.CheckboxCellTest;
+import com.google.gwt.cell.client.ClickableTextCellTest;
+import com.google.gwt.cell.client.CompositeCellTest;
+import com.google.gwt.cell.client.DateCellTest;
+import com.google.gwt.cell.client.DatePickerCellTest;
+import com.google.gwt.cell.client.EditTextCellTest;
+import com.google.gwt.cell.client.IconCellDecoratorTest;
+import com.google.gwt.cell.client.NumberCellTest;
+import com.google.gwt.cell.client.SelectionCellTest;
+import com.google.gwt.cell.client.TextCellTest;
+import com.google.gwt.cell.client.TextInputCellTest;
+import com.google.gwt.junit.tools.GWTTestSuite;
+
+import junit.framework.Test;
+
+/**
+ * Tests of the cell package.
+ */
+public class CellSuite {
+ public static Test suite() {
+ GWTTestSuite suite = new GWTTestSuite("Test suite for all cell classes");
+
+ suite.addTestSuite(AbstractCellTest.class);
+ suite.addTestSuite(ActionCellTest.class);
+ suite.addTestSuite(ButtonCellTest.class);
+ suite.addTestSuite(CheckboxCellTest.class);
+ suite.addTestSuite(ClickableTextCellTest.class);
+ suite.addTestSuite(CompositeCellTest.class);
+ suite.addTestSuite(DateCellTest.class);
+ suite.addTestSuite(DatePickerCellTest.class);
+ suite.addTestSuite(EditTextCellTest.class);
+ suite.addTestSuite(IconCellDecoratorTest.class);
+ suite.addTestSuite(NumberCellTest.class);
+ suite.addTestSuite(SelectionCellTest.class);
+ suite.addTestSuite(TextCellTest.class);
+ suite.addTestSuite(TextInputCellTest.class);
+ return suite;
+ }
+}
diff --git a/user/test/com/google/gwt/cell/client/ActionCellTest.java b/user/test/com/google/gwt/cell/client/ActionCellTest.java
index 52f5bb2..15587e7 100644
--- a/user/test/com/google/gwt/cell/client/ActionCellTest.java
+++ b/user/test/com/google/gwt/cell/client/ActionCellTest.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -27,7 +27,7 @@
/**
* A mock {@link Delegate} used for testing.
- *
+ *
* @param <T> the value type
*/
private static class MockDelegate<T> implements Delegate<T> {
@@ -47,9 +47,9 @@
MockDelegate<String> delegate = new MockDelegate<String>();
ActionCell<String> cell = new ActionCell<String>("hello", delegate);
Element parent = Document.get().createDivElement();
- NativeEvent event = Document.get().createClickEvent(0, 0, 0, 0, 0, false,
- false, false, false);
- assertNull(cell.onBrowserEvent(parent, "test", null, event, null));
+ NativeEvent event = Document.get().createClickEvent(
+ 0, 0, 0, 0, 0, false, false, false, false);
+ cell.onBrowserEvent(parent, "test", DEFAULT_KEY, event, null);
delegate.assertLastObject("test");
}
diff --git a/user/test/com/google/gwt/cell/client/ButtonCellTest.java b/user/test/com/google/gwt/cell/client/ButtonCellTest.java
index d12935d..32e5656 100644
--- a/user/test/com/google/gwt/cell/client/ButtonCellTest.java
+++ b/user/test/com/google/gwt/cell/client/ButtonCellTest.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -24,10 +24,9 @@
public class ButtonCellTest extends CellTestBase<String> {
public void testOnBrowserEvent() {
- NativeEvent event = Document.get().createMouseUpEvent(0, 0, 0, 0, 0, false,
- false, false, false, NativeEvent.BUTTON_LEFT);
- testOnBrowserEvent(getExpectedInnerHtml(), event, null, "clickme",
- "clickme");
+ NativeEvent event = Document.get().createMouseUpEvent(
+ 0, 0, 0, 0, 0, false, false, false, false, NativeEvent.BUTTON_LEFT);
+ testOnBrowserEvent(getExpectedInnerHtml(), event, "clickme", "clickme");
}
@Override
diff --git a/user/test/com/google/gwt/cell/client/CellTestBase.java b/user/test/com/google/gwt/cell/client/CellTestBase.java
index 970f189..b9122c9 100644
--- a/user/test/com/google/gwt/cell/client/CellTestBase.java
+++ b/user/test/com/google/gwt/cell/client/CellTestBase.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -22,14 +22,19 @@
/**
* Base class for testing {@link Cell}.
- *
+ *
* @param <T> the cell type
*/
public abstract class CellTestBase<T> extends GWTTestCase {
/**
+ * The default row value key used for all tests.
+ */
+ protected static final Object DEFAULT_KEY = new Object();
+
+ /**
* A mock cell used for testing.
- *
+ *
* @param <T> the cell type
*/
static class MockCell<T> extends AbstractCell<T> {
@@ -39,8 +44,8 @@
private T lastEventValue;
private final T updateValue;
- public MockCell(boolean consumesEvents, boolean dependsOnSelection,
- T updateValue) {
+ public MockCell(
+ boolean consumesEvents, boolean dependsOnSelection, T updateValue) {
this.consumesEvents = consumesEvents;
this.dependsOnSelection = dependsOnSelection;
this.updateValue = updateValue;
@@ -61,17 +66,16 @@
}
@Override
- public Object onBrowserEvent(Element parent, T value, Object viewData,
+ public void onBrowserEvent(Element parent, T value, Object key,
NativeEvent event, ValueUpdater<T> valueUpdater) {
lastEventValue = value;
if (valueUpdater != null) {
valueUpdater.update(updateValue);
}
- return null;
}
@Override
- public void render(T value, Object viewData, StringBuilder sb) {
+ public void render(T value, Object key, StringBuilder sb) {
if (value != null) {
sb.append(value);
}
@@ -113,15 +117,18 @@
public void testOnBrowserEventNullValueUpdater() {
Cell<T> cell = createCell();
T value = createCellValue();
- NativeEvent event = Document.get().createClickEvent(0, 0, 0, 0, 0, false,
- false, false, false);
+ NativeEvent event = Document.get().createClickEvent(
+ 0, 0, 0, 0, 0, false, false, false, false);
Element parent = Document.get().createDivElement();
parent.setInnerHTML(getExpectedInnerHtml());
- cell.onBrowserEvent(parent, value, null, event, null);
+ cell.onBrowserEvent(parent, value, DEFAULT_KEY, event, null);
// Make sure that no exceptions occur.
}
+ /**
+ * Test rendering the cell with a valid value and no view data.
+ */
public void testRender() {
Cell<T> cell = createCell();
T value = createCellValue();
@@ -130,6 +137,9 @@
assertEquals(getExpectedInnerHtml(), sb.toString());
}
+ /**
+ * Test rendering the cell with a null value and no view data.
+ */
public void testRenderNull() {
Cell<T> cell = createCell();
StringBuilder sb = new StringBuilder();
@@ -139,35 +149,35 @@
/**
* Does the cell type consume events? Default to false.
- *
+ *
* @return true expected value of consumesEvents
*/
protected abstract boolean consumesEvents();
/**
* Create a new cell to test.
- *
+ *
* @return the new cell
*/
protected abstract Cell<T> createCell();
/**
* Create a value to test.
- *
+ *
* @return the cell value
*/
protected abstract T createCellValue();
/**
* Does the cell type depend on selection? Default to false.
- *
+ *
* @return true expected value of dependsOnSelection
*/
protected abstract boolean dependsOnSelection();
/**
* Get the expected inner HTML value of the rendered cell.
- *
+ *
* @return the expected string
*/
protected abstract String getExpectedInnerHtml();
@@ -175,33 +185,31 @@
/**
* Get the expected inner HTML value of the rendered cell when null is passed
* as the cell value.
- *
+ *
* @return the expected string
*/
protected abstract String getExpectedInnerHtmlNull();
/**
- * Test
- * {@link Cell#onBrowserEvent(Element, Object, Object, NativeEvent, ValueUpdater)}
- * with the specified conditions.
- *
+ * Test {@link Cell#onBrowserEvent(Element, Object, Object, NativeEvent,
+ * ValueUpdater)} with the specified conditions.
+ *
* @param startHtml the innerHTML of the cell before the test starts
* @param event the event to fire
- * @param viewData the view data to pass to the cell
* @param value the cell value
* @param expectedValue the expected value passed to the value updater, or
* null if none expected
* @return the parent element
*/
- protected Element testOnBrowserEvent(String startHtml, NativeEvent event,
- Object viewData, T value, T expectedValue) {
+ protected Element testOnBrowserEvent(
+ String startHtml, NativeEvent event, T value, T expectedValue) {
// Setup the parent element.
Element parent = Document.get().createDivElement();
parent.setInnerHTML(startHtml);
// Pass the event to the cell.
MockValueUpdater updater = new MockValueUpdater();
- createCell().onBrowserEvent(parent, value, viewData, event, updater);
+ createCell().onBrowserEvent(parent, value, DEFAULT_KEY, event, updater);
updater.assertLastValue(expectedValue);
return parent;
diff --git a/user/test/com/google/gwt/cell/client/CheckboxCellTest.java b/user/test/com/google/gwt/cell/client/CheckboxCellTest.java
index 2b28bb4..bf38e1f 100644
--- a/user/test/com/google/gwt/cell/client/CheckboxCellTest.java
+++ b/user/test/com/google/gwt/cell/client/CheckboxCellTest.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -21,17 +21,18 @@
/**
* Tests for {@link CheckboxCell}.
*/
-public class CheckboxCellTest extends CellTestBase<Boolean> {
+public class CheckboxCellTest extends EditableCellTestBase<Boolean, Boolean> {
public void testOnBrowserEventChecked() {
NativeEvent event = Document.get().createChangeEvent();
- testOnBrowserEvent("<input type=\"checkbox\" checked/>", event, null,
- false, true);
+ testOnBrowserEvent("<input type=\"checkbox\" checked/>", event, false, null,
+ Boolean.TRUE, true);
}
public void testOnBrowserEventUnchecked() {
NativeEvent event = Document.get().createChangeEvent();
- testOnBrowserEvent("<input type=\"checkbox\"/>", event, null, true, false);
+ testOnBrowserEvent(
+ "<input type=\"checkbox\"/>", event, true, null, Boolean.FALSE, false);
}
@Override
@@ -40,7 +41,7 @@
}
@Override
- protected Cell<Boolean> createCell() {
+ protected CheckboxCell createCell() {
return new CheckboxCell();
}
@@ -50,6 +51,11 @@
}
@Override
+ protected Boolean createCellViewData() {
+ return false;
+ }
+
+ @Override
protected boolean dependsOnSelection() {
return false;
}
@@ -63,4 +69,9 @@
protected String getExpectedInnerHtmlNull() {
return "<input type=\"checkbox\"/>";
}
+
+ @Override
+ protected String getExpectedInnerHtmlViewData() {
+ return "<input type=\"checkbox\"/>";
+ }
}
diff --git a/user/test/com/google/gwt/cell/client/ClickableTextCellTest.java b/user/test/com/google/gwt/cell/client/ClickableTextCellTest.java
index 6f057ce..efb62bd 100644
--- a/user/test/com/google/gwt/cell/client/ClickableTextCellTest.java
+++ b/user/test/com/google/gwt/cell/client/ClickableTextCellTest.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -24,9 +24,9 @@
public class ClickableTextCellTest extends CellTestBase<String> {
public void testOnBrowserEvent() {
- NativeEvent event = Document.get().createClickEvent(0, 0, 0, 0, 0, false,
- false, false, false);
- testOnBrowserEvent(getExpectedInnerHtml(), event, null, "value", "value");
+ NativeEvent event = Document.get().createClickEvent(
+ 0, 0, 0, 0, 0, false, false, false, false);
+ testOnBrowserEvent(getExpectedInnerHtml(), event, "value", "value");
}
@Override
diff --git a/user/test/com/google/gwt/cell/client/CompositeCellTest.java b/user/test/com/google/gwt/cell/client/CompositeCellTest.java
index 08be019..1046ad5 100644
--- a/user/test/com/google/gwt/cell/client/CompositeCellTest.java
+++ b/user/test/com/google/gwt/cell/client/CompositeCellTest.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -85,7 +85,7 @@
*/
public void testOnBrowserEventNoCell() {
NativeEvent event = Document.get().createChangeEvent();
- testOnBrowserEvent(getExpectedInnerHtml(), event, null, "test", null);
+ testOnBrowserEvent(getExpectedInnerHtml(), event, "test", null);
}
/**
@@ -106,15 +106,15 @@
// Add an event listener.
EventListener listener = new EventListener() {
public void onBrowserEvent(Event event) {
- cell.onBrowserEvent(parent, "test", null, event, null);
+ cell.onBrowserEvent(parent, "test", DEFAULT_KEY, event, null);
}
};
DOM.sinkEvents(parent, Event.ONCLICK);
DOM.setEventListener(parent, listener);
// Fire the event on one of the inner cells.
- NativeEvent event = Document.get().createClickEvent(0, 0, 0, 0, 0, false,
- false, false, false);
+ NativeEvent event = Document.get().createClickEvent(
+ 0, 0, 0, 0, 0, false, false, false, false);
Element.as(parent.getChild(1)).dispatchEvent(event);
innerCell.assertLastEventValue("test-1");
@@ -167,7 +167,7 @@
/**
* Create an array of {@link HasCell}.
- *
+ *
* @param count the number of cells to create
* @return the list of cells
*/
@@ -175,8 +175,8 @@
List<HasCell<String, ?>> cells = new ArrayList<HasCell<String, ?>>();
for (int i = 0; i < count; i++) {
final int index = i;
- final MockCell<String> inner = new MockCell<String>(false, false,
- "fromCell" + i);
+ final MockCell<String> inner = new MockCell<String>(
+ false, false, "fromCell" + i);
cells.add(new HasCell<String, String>() {
public Cell<String> getCell() {
return inner;
diff --git a/user/test/com/google/gwt/cell/client/DateCellTest.java b/user/test/com/google/gwt/cell/client/DateCellTest.java
index 5cb2d44..7e35b69 100644
--- a/user/test/com/google/gwt/cell/client/DateCellTest.java
+++ b/user/test/com/google/gwt/cell/client/DateCellTest.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -16,6 +16,7 @@
package com.google.gwt.cell.client;
import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
import java.util.Date;
@@ -31,7 +32,7 @@
@Override
protected Cell<Date> createCell() {
- return new DateCell(DateTimeFormat.getMediumDateFormat());
+ return new DateCell(DateTimeFormat.getFormat(PredefinedFormat.DATE_MEDIUM));
}
@Override
diff --git a/user/test/com/google/gwt/cell/client/DatePickerCellTest.java b/user/test/com/google/gwt/cell/client/DatePickerCellTest.java
new file mode 100644
index 0000000..2f91499
--- /dev/null
+++ b/user/test/com/google/gwt/cell/client/DatePickerCellTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.cell.client;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
+
+import java.util.Date;
+
+/**
+ * Tests for {@link DatePickerCell}.
+ */
+public class DatePickerCellTest extends EditableCellTestBase<Date, Date> {
+
+ @Override
+ protected boolean consumesEvents() {
+ return true;
+ }
+
+ @Override
+ protected DatePickerCell createCell() {
+ return new DatePickerCell(
+ DateTimeFormat.getFormat(PredefinedFormat.DATE_MEDIUM));
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected Date createCellValue() {
+ return new Date(2010 - 1900, 0, 1);
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected Date createCellViewData() {
+ return new Date(2010 - 1900, 0, 3);
+ }
+
+ @Override
+ protected boolean dependsOnSelection() {
+ return false;
+ }
+
+ @Override
+ protected String getExpectedInnerHtml() {
+ return "Jan 1, 2010";
+ }
+
+ @Override
+ protected String getExpectedInnerHtmlNull() {
+ return "";
+ }
+
+ @Override
+ protected String getExpectedInnerHtmlViewData() {
+ return "Jan 3, 2010";
+ }
+}
diff --git a/user/test/com/google/gwt/cell/client/EditTextCellTest.java b/user/test/com/google/gwt/cell/client/EditTextCellTest.java
index 1d76c81..0f5ca84 100644
--- a/user/test/com/google/gwt/cell/client/EditTextCellTest.java
+++ b/user/test/com/google/gwt/cell/client/EditTextCellTest.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -15,6 +15,7 @@
*/
package com.google.gwt.cell.client;
+import com.google.gwt.cell.client.EditTextCell.ViewData;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.InputElement;
@@ -24,51 +25,77 @@
/**
* Tests for {@link EditTextCell}.
*/
-public class EditTextCellTest extends CellTestBase<String> {
-
- public void testRenderViewData() {
- Cell<String> cell = createCell();
- StringBuilder sb = new StringBuilder();
- cell.render("test", "editing", sb);
- assertEquals("<input type='text' value='editing'></input>", sb.toString());
- }
+public class EditTextCellTest extends EditableCellTestBase<String, ViewData> {
public void testEdit() {
EditTextCell cell = createCell();
Element parent = Document.get().createDivElement();
parent.setInnerHTML("<input type='text' value='editing'></input>");
- cell.edit(parent, "editing");
+ ViewData viewData = new ViewData("originalValue");
+ viewData.setText("newValue");
+ cell.setViewData(DEFAULT_KEY, viewData);
+ cell.edit(parent, "originalValue", DEFAULT_KEY);
// Verify the input element.
Element child = parent.getFirstChildElement();
assertTrue(InputElement.is(child));
InputElement input = child.cast();
- assertEquals("editing", input.getValue());
+ assertEquals("newValue", input.getValue());
}
/**
* Cancel and switch to read only mode.
*/
public void testOnBrowserEventCancel() {
- NativeEvent event = Document.get().createKeyDownEvent(false, false, false,
- false, KeyCodes.KEY_ESCAPE);
+ NativeEvent event = Document.get().createKeyDownEvent(
+ false, false, false, false, KeyCodes.KEY_ESCAPE);
+ ViewData viewData = new ViewData("originalValue");
+ viewData.setText("newValue");
Element parent = testOnBrowserEvent(
"<input type='text' value='newValue'></input>", event, "originalValue",
- "originalValue", null);
+ viewData, null, null);
// Verify the input element is gone.
assertEquals("originalValue", parent.getInnerHTML());
}
/**
+ * Cancel and switch to read only mode after committing once.
+ */
+ public void testOnBrowserEventCancelSecondEdit() {
+ NativeEvent event = Document.get().createKeyDownEvent(
+ false, false, false, false, KeyCodes.KEY_ESCAPE);
+ ViewData viewData = new ViewData("originalValue");
+ viewData.setText("newValue");
+ viewData.setEditing(false); // commit.
+ viewData.setEditing(true);
+ assertEquals("newValue", viewData.getOriginal());
+ assertEquals("newValue", viewData.getText());
+ viewData.setText("newValue2");
+ Element parent = testOnBrowserEvent(
+ "<input type='text' value='newValue2'></input>", event, "originalValue",
+ viewData, null, viewData);
+ assertEquals("newValue", viewData.getOriginal());
+ assertEquals("newValue", viewData.getText());
+ assertFalse(viewData.isEditing());
+
+ // Verify the input element is gone.
+ assertEquals("newValue", parent.getInnerHTML());
+ }
+
+ /**
* Commit and switch to read only mode.
*/
public void testOnBrowserEventCommit() {
- NativeEvent event = Document.get().createKeyDownEvent(false, false, false,
- false, KeyCodes.KEY_ENTER);
+ NativeEvent event = Document.get().createKeyDownEvent(
+ false, false, false, false, KeyCodes.KEY_ENTER);
+ ViewData viewData = new ViewData("originalValue");
+ viewData.setText("newValue");
+ assertTrue(viewData.isEditing());
Element parent = testOnBrowserEvent(
"<input type='text' value='newValue'></input>", event, "originalValue",
- "originalValue", "newValue");
+ viewData, "newValue", viewData);
+ assertFalse(viewData.isEditing());
// Verify the input element is gone.
assertEquals("newValue", parent.getInnerHTML());
@@ -78,10 +105,11 @@
* Test switching into edit mode from onBrowserEvent.
*/
public void testOnBrowserEventEdit() {
- NativeEvent event = Document.get().createClickEvent(0, 0, 0, 0, 0, false,
- false, false, false);
- Element parent = testOnBrowserEvent("helloworld", event, null, "editing",
- null);
+ NativeEvent event = Document.get().createClickEvent(
+ 0, 0, 0, 0, 0, false, false, false, false);
+ ViewData expectedViewData = new ViewData("editing");
+ Element parent = testOnBrowserEvent(
+ "helloWorld", event, "editing", null, null, expectedViewData);
// Verify the input element.
Element child = parent.getFirstChildElement();
@@ -90,6 +118,51 @@
assertEquals("editing", input.getValue());
}
+ /**
+ * Test rendering the cell with a valid value and view data, but without
+ * editing.
+ */
+ public void testRenderViewDataDoneEditing() {
+ EditTextCell cell = createCell();
+ ViewData viewData = new ViewData("originalValue");
+ viewData.setText("newValue");
+ viewData.setEditing(false);
+ cell.setViewData(DEFAULT_KEY, viewData);
+ StringBuilder sb = new StringBuilder();
+ cell.render("originalValue", DEFAULT_KEY, sb);
+ assertEquals("newValue", sb.toString());
+ }
+
+ public void testViewData() {
+ // Start in edit mode.
+ ViewData viewData = new ViewData("originalValue");
+ assertEquals("originalValue", viewData.getOriginal());
+ assertEquals("originalValue", viewData.getText());
+ assertTrue(viewData.isEditing());
+ assertFalse(viewData.isEditingAgain());
+
+ // Change the text.
+ viewData.setText("newValue");
+ assertEquals("originalValue", viewData.getOriginal());
+ assertEquals("newValue", viewData.getText());
+ assertTrue(viewData.isEditing());
+ assertFalse(viewData.isEditingAgain());
+
+ // Stop editing.
+ viewData.setEditing(false);
+ assertEquals("originalValue", viewData.getOriginal());
+ assertEquals("newValue", viewData.getText());
+ assertFalse(viewData.isEditing());
+ assertFalse(viewData.isEditingAgain());
+
+ // Edit again.
+ viewData.setEditing(true);
+ assertEquals("newValue", viewData.getOriginal());
+ assertEquals("newValue", viewData.getText());
+ assertTrue(viewData.isEditing());
+ assertTrue(viewData.isEditingAgain());
+ }
+
@Override
protected boolean consumesEvents() {
return true;
@@ -106,6 +179,11 @@
}
@Override
+ protected ViewData createCellViewData() {
+ return new ViewData("newValue");
+ }
+
+ @Override
protected boolean dependsOnSelection() {
return false;
}
@@ -119,4 +197,9 @@
protected String getExpectedInnerHtmlNull() {
return "";
}
+
+ @Override
+ protected String getExpectedInnerHtmlViewData() {
+ return "<input type='text' value='newValue'></input>";
+ }
}
diff --git a/user/test/com/google/gwt/cell/client/EditableCellTestBase.java b/user/test/com/google/gwt/cell/client/EditableCellTestBase.java
new file mode 100644
index 0000000..19fe41c
--- /dev/null
+++ b/user/test/com/google/gwt/cell/client/EditableCellTestBase.java
@@ -0,0 +1,89 @@
+/*
+ * 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.cell.client;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+
+/**
+ * Base class for testing {@link AbstractEditableCell}s that can be modified.
+ *
+ * @param <T> the cell type
+ * @param <V> the view data type
+ */
+public abstract class EditableCellTestBase<T, V> extends CellTestBase<T> {
+
+ /**
+ * Test rendering the cell with a valid value and view data.
+ */
+ public void testRenderViewData() {
+ AbstractEditableCell<T, V> cell = createCell();
+ T value = createCellValue();
+ cell.setViewData(DEFAULT_KEY, createCellViewData());
+ StringBuilder sb = new StringBuilder();
+ cell.render(value, DEFAULT_KEY, sb);
+ assertEquals(getExpectedInnerHtmlViewData(), sb.toString());
+ }
+
+ @Override
+ protected abstract AbstractEditableCell<T, V> createCell();
+
+ /**
+ * Create a view data to test.
+ *
+ * @return the cell view data
+ */
+ protected abstract V createCellViewData();
+
+ /**
+ * Get the expected inner HTML value of the rendered cell when view data is
+ * present.
+ *
+ * @return the expected string
+ */
+ protected abstract String getExpectedInnerHtmlViewData();
+
+ /**
+ * Test {@link Cell#onBrowserEvent(Element, Object, Object, NativeEvent,
+ * ValueUpdater)} with the specified conditions.
+ *
+ * @param startHtml the innerHTML of the cell before the test starts
+ * @param event the event to fire
+ * @param value the cell value
+ * @param viewData the initial view data
+ * @param expectedValue the expected value passed to the value updater, or
+ * null if none expected
+ * @param expectedViewData the expected value of the view data after the event
+ * @return the parent element
+ */
+ protected Element testOnBrowserEvent(String startHtml, NativeEvent event,
+ T value, V viewData, T expectedValue, V expectedViewData) {
+ // Setup the parent element.
+ Element parent = Document.get().createDivElement();
+ parent.setInnerHTML(startHtml);
+
+ // Pass the event to the cell.
+ MockValueUpdater valueUpdater = new MockValueUpdater();
+ AbstractEditableCell<T, V> cell = createCell();
+ cell.setViewData(DEFAULT_KEY, viewData);
+ cell.onBrowserEvent(parent, value, DEFAULT_KEY, event, valueUpdater);
+ assertEquals(expectedViewData, cell.getViewData(DEFAULT_KEY));
+ valueUpdater.assertLastValue(expectedValue);
+
+ return parent;
+ }
+}
diff --git a/user/test/com/google/gwt/cell/client/IconCellDecoratorTest.java b/user/test/com/google/gwt/cell/client/IconCellDecoratorTest.java
index 882deb0..a506eab 100644
--- a/user/test/com/google/gwt/cell/client/IconCellDecoratorTest.java
+++ b/user/test/com/google/gwt/cell/client/IconCellDecoratorTest.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -42,14 +42,14 @@
*/
public void testOnBrowserEvent() {
NativeEvent event = Document.get().createChangeEvent();
- testOnBrowserEvent(getExpectedInnerHtml(), event, null, "helloworld",
- "newValueFromInnerCell");
+ testOnBrowserEvent(
+ getExpectedInnerHtml(), event, "helloworld", "newValueFromInnerCell");
}
public void testRenderNoImage() {
Images images = getImages();
- MockCell<String> innerCell = new MockCell<String>(true, true,
- "newValueFromInnerCell");
+ MockCell<String> innerCell = new MockCell<String>(
+ true, true, "newValueFromInnerCell");
IconCellDecorator<String> cell = new IconCellDecorator<String>(
images.prettyPiccy(), innerCell) {
@Override
@@ -64,8 +64,8 @@
// Compare the expected render string.
String expected = "<div style='position:relative;padding-left:64px;'>";
- expected += cell.getImageHtml(images.prettyPiccy(),
- HasVerticalAlignment.ALIGN_MIDDLE, true);
+ expected += cell.getImageHtml(
+ images.prettyPiccy(), HasVerticalAlignment.ALIGN_MIDDLE, true);
expected += "<div>helloworld</div>";
expected += "</div>";
assertEquals(expected, sb.toString());
@@ -75,8 +75,8 @@
Cell<String> cell = createCell();
Element parent = Document.get().createDivElement();
parent.setInnerHTML(getExpectedInnerHtml());
- assertEquals("helloworld", Element.as(
- parent.getFirstChildElement().getChild(1)).getInnerHTML());
+ assertEquals("helloworld",
+ Element.as(parent.getFirstChildElement().getChild(1)).getInnerHTML());
cell.setValue(parent, "test", null);
assertEquals("test",
Element.as(parent.getFirstChildElement().getChild(1)).getInnerHTML());
@@ -89,8 +89,8 @@
@Override
protected IconCellDecorator<String> createCell() {
- MockCell<String> innerCell = new MockCell<String>(true, true,
- "newValueFromInnerCell");
+ MockCell<String> innerCell = new MockCell<String>(
+ true, true, "newValueFromInnerCell");
IconCellDecorator<String> iconCell = new IconCellDecorator<String>(
getImages().prettyPiccy(), innerCell);
return iconCell;
diff --git a/user/test/com/google/gwt/cell/client/SelectionCellTest.java b/user/test/com/google/gwt/cell/client/SelectionCellTest.java
new file mode 100644
index 0000000..903c5eb
--- /dev/null
+++ b/user/test/com/google/gwt/cell/client/SelectionCellTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.cell.client;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.NativeEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link SelectionCell}.
+ */
+public class SelectionCellTest extends EditableCellTestBase<String, String> {
+
+ public void testOnBrowser() {
+ NativeEvent event = Document.get().createChangeEvent();
+ testOnBrowserEvent(getExpectedInnerHtml(), event, "option 0", null,
+ "option 1", "option 1");
+ }
+
+ @Override
+ protected boolean consumesEvents() {
+ return true;
+ }
+
+ @Override
+ protected SelectionCell createCell() {
+ List<String> options = new ArrayList<String>();
+ for (int i = 0; i < 3; i++) {
+ options.add("option " + i);
+ }
+ return new SelectionCell(options);
+ }
+
+ @Override
+ protected String createCellValue() {
+ return "option 1";
+ }
+
+ @Override
+ protected String createCellViewData() {
+ return "option 2";
+ }
+
+ @Override
+ protected boolean dependsOnSelection() {
+ return false;
+ }
+
+ @Override
+ protected String getExpectedInnerHtml() {
+ return "<select><option>option 0</option><option selected='selected'>option 1</option><option>option 2</option></select>";
+ }
+
+ @Override
+ protected String getExpectedInnerHtmlNull() {
+ return "<select><option>option 0</option><option>option 1</option><option>option 2</option></select>";
+ }
+
+ @Override
+ protected String getExpectedInnerHtmlViewData() {
+ return "<select><option>option 0</option><option>option 1</option><option selected='selected'>option 2</option></select>";
+ }
+}
diff --git a/user/test/com/google/gwt/cell/client/TextInputCellTest.java b/user/test/com/google/gwt/cell/client/TextInputCellTest.java
index 7cb2f84..03bd531 100644
--- a/user/test/com/google/gwt/cell/client/TextInputCellTest.java
+++ b/user/test/com/google/gwt/cell/client/TextInputCellTest.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -21,11 +21,19 @@
/**
* Tests for {@link TextInputCell}.
*/
-public class TextInputCellTest extends CellTestBase<String> {
+public class TextInputCellTest extends EditableCellTestBase<String, String> {
- public void testOnBrowserEvent() {
+ public void testOnBrowserEventChange() {
NativeEvent event = Document.get().createChangeEvent();
- testOnBrowserEvent(getExpectedInnerHtml(), event, null, "oldValue", "hello");
+ testOnBrowserEvent(
+ getExpectedInnerHtml(), event, "oldValue", null, "hello", "hello");
+ }
+
+ public void testOnBrowserEventKeyUp() {
+ NativeEvent event = Document.get().createKeyUpEvent(
+ false, false, false, false, 0);
+ testOnBrowserEvent(
+ getExpectedInnerHtml(), event, "oldValue", null, null, "hello");
}
@Override
@@ -34,7 +42,7 @@
}
@Override
- protected Cell<String> createCell() {
+ protected TextInputCell createCell() {
return new TextInputCell();
}
@@ -44,6 +52,11 @@
}
@Override
+ protected String createCellViewData() {
+ return "newValue";
+ }
+
+ @Override
protected boolean dependsOnSelection() {
return false;
}
@@ -57,4 +70,9 @@
protected String getExpectedInnerHtmlNull() {
return "<input type='text'></input>";
}
+
+ @Override
+ protected String getExpectedInnerHtmlViewData() {
+ return "<input type='text' value='newValue'></input>";
+ }
}
diff --git a/user/test/com/google/gwt/user/cellview/CellViewSuite.java b/user/test/com/google/gwt/user/cellview/CellViewSuite.java
index ec2a040..8031505 100644
--- a/user/test/com/google/gwt/user/cellview/CellViewSuite.java
+++ b/user/test/com/google/gwt/user/cellview/CellViewSuite.java
@@ -17,6 +17,7 @@
import com.google.gwt.junit.tools.GWTTestSuite;
import com.google.gwt.user.cellview.client.AbstractPagerTest;
+import com.google.gwt.user.cellview.client.ColumnTest;
import com.google.gwt.user.cellview.client.PagingListViewPresenterTest;
import com.google.gwt.user.cellview.client.SimplePagerTest;
@@ -30,6 +31,7 @@
GWTTestSuite suite = new GWTTestSuite("Test suite for all cellview classes");
suite.addTestSuite(AbstractPagerTest.class);
+ suite.addTestSuite(ColumnTest.class);
suite.addTestSuite(PagingListViewPresenterTest.class);
suite.addTestSuite(SimplePagerTest.class);
return suite;
diff --git a/user/test/com/google/gwt/user/cellview/client/ColumnTest.java b/user/test/com/google/gwt/user/cellview/client/ColumnTest.java
new file mode 100644
index 0000000..2549d85
--- /dev/null
+++ b/user/test/com/google/gwt/user/cellview/client/ColumnTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.FieldUpdater;
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.cell.client.TextInputCell;
+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.junit.client.GWTTestCase;
+import com.google.gwt.user.client.Timer;
+
+/**
+ * Tests for {@link Column}.
+ */
+public class ColumnTest extends GWTTestCase {
+
+ /**
+ * A mock {@link FieldUpdater} used for testing.
+ *
+ * @param <T> the field type
+ * @param <C> the value type
+ */
+ private static class MockFieldUpdater<T, C> implements FieldUpdater<T, C> {
+
+ private int index;
+ private T object;
+ private boolean updateCalled;
+ private C value;
+
+ public void assertIndex(int expected) {
+ assertEquals(expected, index);
+ }
+
+ public void assertObject(T expected) {
+ assertEquals(expected, object);
+ }
+
+ public void assertUpdateCalled(boolean expected) {
+ assertEquals(expected, updateCalled);
+ }
+
+ public void assertValue(C expected) {
+ assertEquals(expected, value);
+ }
+
+ public void update(int index, T object, C value) {
+ assertFalse("Update called twice", updateCalled);
+ this.updateCalled = true;
+ this.index = index;
+ this.object = object;
+ this.value = value;
+ }
+ }
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.cellview.CellView";
+ }
+
+ public void testConsumesEvents() {
+ TextCell cell = new TextCell() {
+ @Override
+ public boolean consumesEvents() {
+ return true;
+ }
+ };
+ Column<String, String> column = new IdentityColumn<String>(cell);
+ assertTrue(column.consumesEvents());
+ }
+
+ /**
+ * Test that a cell can hold onto the {@link ValueUpdater} and update it
+ * later.
+ */
+ public void testDelayedValueUpdaer() {
+ final Element theElem = Document.get().createDivElement();
+ final NativeEvent theEvent = Document.get().createClickEvent(
+ 0, 0, 0, 0, 0, false, false, false, false);
+ final TextInputCell cell = new TextInputCell() {
+ @Override
+ public void onBrowserEvent(Element parent, String value, Object key,
+ NativeEvent event, final ValueUpdater<String> valueUpdater) {
+ setViewData("test", "newViewData");
+ new Timer() {
+ @Override
+ public void run() {
+ valueUpdater.update("newValue");
+ }
+ }.schedule(200);
+ }
+ };
+ final Column<String, String> column = new IdentityColumn<String>(cell);
+ final MockFieldUpdater<String, String> fieldUpdater = new MockFieldUpdater<
+ String, String>() {
+ @Override
+ public void update(int index, String object, String value) {
+ assertEquals("newViewData", cell.getViewData("test"));
+ super.update(index, object, value);
+ finishTest();
+ }
+ };
+ column.setFieldUpdater(fieldUpdater);
+
+ // Fire the event to the cell.
+ delayTestFinish(5000);
+ cell.setViewData("test", "oldViewData");
+ column.onBrowserEvent(theElem, 3, "test", theEvent, null);
+ }
+
+ public void testGetCell() {
+ TextCell cell = new TextCell();
+ Column<String, String> column = new IdentityColumn<String>(cell);
+ assertEquals(cell, column.getCell());
+ }
+
+ public void testOnBrowserEventWithFieldUpdater() {
+ final Element theElem = Document.get().createDivElement();
+ final NativeEvent theEvent = Document.get().createClickEvent(
+ 0, 0, 0, 0, 0, false, false, false, false);
+ final TextInputCell cell = new TextInputCell() {
+ @Override
+ public void onBrowserEvent(Element parent, String value, Object key,
+ NativeEvent event, ValueUpdater<String> valueUpdater) {
+ assertEquals(theElem, parent);
+ assertEquals("test", value);
+ assertEquals("oldViewData", getViewData("test"));
+ assertEquals(theEvent, event);
+ assertNotNull(valueUpdater);
+ setViewData("test", "newViewData");
+ valueUpdater.update("newValue");
+ }
+ };
+ final Column<String, String> column = new IdentityColumn<String>(cell);
+ final MockFieldUpdater<String, String> fieldUpdater = new MockFieldUpdater<
+ String, String>() {
+ @Override
+ public void update(int index, String object, String value) {
+ // The new view data should already be set.
+ assertEquals("newViewData", cell.getViewData("test"));
+ super.update(index, object, value);
+ }
+ };
+ column.setFieldUpdater(fieldUpdater);
+
+ cell.setViewData("test", "oldViewData");
+ column.onBrowserEvent(theElem, 3, "test", theEvent, null);
+
+ fieldUpdater.assertUpdateCalled(true);
+ fieldUpdater.assertIndex(3);
+ fieldUpdater.assertObject("test");
+ fieldUpdater.assertValue("newValue");
+ }
+
+ public void testOnBrowserEventWithoutFieldUpdater() {
+ final Element theElem = Document.get().createDivElement();
+ final NativeEvent theEvent = Document.get().createClickEvent(
+ 0, 0, 0, 0, 0, false, false, false, false);
+ final TextInputCell cell = new TextInputCell() {
+ @Override
+ public void onBrowserEvent(Element parent, String value, Object key,
+ NativeEvent event, ValueUpdater<String> valueUpdater) {
+ assertEquals(theElem, parent);
+ assertEquals("test", value);
+ assertEquals("oldViewData", getViewData("test"));
+ assertEquals(theEvent, event);
+ assertNull(valueUpdater);
+ setViewData("test", "newViewData");
+ }
+ };
+ Column<String, String> column = new IdentityColumn<String>(cell);
+
+ cell.setViewData("test", "oldViewData");
+ column.onBrowserEvent(theElem, 3, "test", theEvent, null);
+ }
+
+ public void testRender() {
+ TextCell cell = new TextCell();
+ Column<String, String> column = new IdentityColumn<String>(cell);
+
+ StringBuilder sb = new StringBuilder();
+ column.render("test", null, sb);
+ assertEquals("test", sb.toString());
+ }
+}