Cherry picking r9328 into release branch for issue #5622.


git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/2.1@9331 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportDetails.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportDetails.java
index 455e0cf..d4c02c7 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportDetails.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportDetails.java
@@ -23,6 +23,7 @@
 import com.google.gwt.cell.client.NumberCell;
 import com.google.gwt.cell.client.TextCell;
 import com.google.gwt.cell.client.ValueUpdater;
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
@@ -46,7 +47,6 @@
 import com.google.gwt.requestfactory.ui.client.EntityProxyKeyProvider;
 import com.google.gwt.resources.client.ImageResource;
 import com.google.gwt.safehtml.client.SafeHtmlTemplates;
-import com.google.gwt.safehtml.client.SafeHtmlTemplates.Template;
 import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
 import com.google.gwt.safehtml.shared.SafeHtmlUtils;
@@ -183,15 +183,16 @@
     }
 
     @Override
-    public boolean isEditing(Element parent, String value, Object key) {
-      return super.isEditing(parent, value, key) || denialPopup.isShowing();
+    public boolean isEditing(Context context, Element parent, String value) {
+      return super.isEditing(context, parent, value) || denialPopup.isShowing();
     }
 
     @Override
-    public void onBrowserEvent(Element parent, String value, Object key,
+    public void onBrowserEvent(Context context, Element parent, String value,
         NativeEvent event, ValueUpdater<String> valueUpdater) {
-      super.onBrowserEvent(parent, value, key, event, valueUpdater);
+      super.onBrowserEvent(context, parent, value, event, valueUpdater);
 
+      Object key = context.getKey();
       String type = event.getType();
       ApprovalViewData viewData = getViewData(key);
       if ("change".equals(type)) {
@@ -235,8 +236,9 @@
     }
 
     @Override
-    public void render(String value, Object key, SafeHtmlBuilder sb) {
+    public void render(Context context, String value, SafeHtmlBuilder sb) {
       // Get the view data.
+      Object key = context.getKey();
       ApprovalViewData viewData = getViewData(key);
       if (viewData != null && viewData.getPendingApproval().equals(value)) {
         clearViewData(key);
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportList.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportList.java
index bb40add..2df0dbf 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportList.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportList.java
@@ -163,7 +163,7 @@
     private static final String replaceString = "<span style='color:red;font-weight:bold;'>$1</span>";
 
     @Override
-    public void render(String value, Object viewData, SafeHtmlBuilder sb) {
+    public void render(Context context, String value, SafeHtmlBuilder sb) {
       if (value != null) {
         if (searchRegExp != null) {
           // The search regex has already been html-escaped
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseTree.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseTree.java
index 49d29be..db78b4d 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseTree.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseTree.java
@@ -19,13 +19,13 @@
 import com.google.gwt.cell.client.Cell;
 import com.google.gwt.cell.client.IconCellDecorator;
 import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Style.Overflow;
 import com.google.gwt.requestfactory.shared.EntityProxyId;
 import com.google.gwt.requestfactory.shared.Receiver;
 import com.google.gwt.requestfactory.ui.client.EntityProxyKeyProvider;
 import com.google.gwt.safehtml.client.SafeHtmlTemplates;
-import com.google.gwt.safehtml.client.SafeHtmlTemplates.Template;
 import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
 import com.google.gwt.sample.expenses.client.style.Styles;
@@ -85,7 +85,7 @@
         }
 
         @Override
-        public void render(EmployeeProxy value, Object viewData,
+        public void render(Context context, EmployeeProxy value,
             SafeHtmlBuilder sb) {
           if (value != null) {
             StringBuilder classesBuilder = new StringBuilder(usernameStyle);
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileExpenseList.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileExpenseList.java
index df44ef9..db184f7 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileExpenseList.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileExpenseList.java
@@ -81,7 +81,7 @@
     }
 
     @Override
-    public void render(ExpenseProxy value, Object viewData, SafeHtmlBuilder sb) {
+    public void render(Context context, ExpenseProxy value, SafeHtmlBuilder sb) {
       String approval = value.getApproval();
       SafeHtml approvalIcon;
       if (approvedText.equals(approval)) {
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileReportList.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileReportList.java
index 4ef274c..80466d8 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileReportList.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileReportList.java
@@ -76,8 +76,7 @@
 
     reportList = new CellList<ReportProxy>(new AbstractCell<ReportProxy>() {
       @Override
-      public void render(
-          ReportProxy value, Object viewData, SafeHtmlBuilder sb) {
+      public void render(Context context, ReportProxy value, SafeHtmlBuilder sb) {
         sb.appendHtmlConstant("<div class='item'>");
         sb.appendEscaped(value.getPurpose());
         sb.appendHtmlConstant("</div>");
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/SortableHeader.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/SortableHeader.java
index 5df24a5..3ab78bf 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/SortableHeader.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/SortableHeader.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.sample.expenses.client;
 
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.cell.client.ClickableTextCell;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.resources.client.ClientBundle;
@@ -89,7 +90,7 @@
   }
 
   @Override
-  public void render(SafeHtmlBuilder sb) {
+  public void render(Context context, SafeHtmlBuilder sb) {
     if (sorted) {
       sb.append(template.sorted(IMAGE_WIDTH, reverseSort ? DOWN_ARROW : UP_ARROW, text));
     } else {
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/MainMenuTreeViewModel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/MainMenuTreeViewModel.java
index 3c47105..f5f16fc 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/MainMenuTreeViewModel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/MainMenuTreeViewModel.java
@@ -109,7 +109,7 @@
    */
   private static class CategoryCell extends AbstractCell<Category> {
     @Override
-    public void render(Category value, Object key, SafeHtmlBuilder sb) {
+    public void render(Context context, Category value, SafeHtmlBuilder sb) {
       if (value != null) {
         sb.appendEscaped(value.getName());
       }
@@ -121,7 +121,8 @@
    */
   private static class ContentWidgetCell extends AbstractCell<ContentWidget> {
     @Override
-    public void render(ContentWidget value, Object key, SafeHtmlBuilder sb) {
+    public void render(Context context, ContentWidget value,
+        SafeHtmlBuilder sb) {
       if (value != null) {
         sb.appendEscaped(value.getName());
       }
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/ContactTreeViewModel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/ContactTreeViewModel.java
index 3a2248d..b18ff11 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/ContactTreeViewModel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/ContactTreeViewModel.java
@@ -69,7 +69,7 @@
     }
 
     @Override
-    public void render(Category value, Object key, SafeHtmlBuilder sb) {
+    public void render(Context context, Category value, SafeHtmlBuilder sb) {
       if (value != null) {
         sb.appendHtmlConstant(imageHtml).appendEscaped(" ");
         sb.appendEscaped(value.getDisplayName());
@@ -126,7 +126,7 @@
   private static class LetterCountCell extends AbstractCell<LetterCount> {
 
     @Override
-    public void render(LetterCount value, Object key, SafeHtmlBuilder sb) {
+    public void render(Context context, LetterCount value, SafeHtmlBuilder sb) {
       if (value != null) {
         sb.appendEscaped(value.firstLetter + " (" + value.count + ")");
       }
@@ -193,9 +193,9 @@
     });
     contactCell = new CompositeCell<ContactInfo>(hasCells) {
       @Override
-      public void render(ContactInfo value, Object key, SafeHtmlBuilder sb) {
+      public void render(Context context, ContactInfo value, SafeHtmlBuilder sb) {
         sb.appendHtmlConstant("<table><tbody><tr>");
-        super.render(value, key, sb);
+        super.render(context, value, sb);
         sb.appendHtmlConstant("</tr></tbody></table>");
       }
 
@@ -206,11 +206,11 @@
       }
 
       @Override
-      protected <X> void render(ContactInfo value, Object key,
+      protected <X> void render(Context context, ContactInfo value,
           SafeHtmlBuilder sb, HasCell<ContactInfo, X> hasCell) {
         Cell<X> cell = hasCell.getCell();
         sb.appendHtmlConstant("<td>");
-        cell.render(hasCell.getValue(value), key, sb);
+        cell.render(context, hasCell.getValue(value), sb);
         sb.appendHtmlConstant("</td>");
       }
     };
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellList.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellList.java
index 956e31d..4e55af7 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellList.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellList.java
@@ -90,7 +90,7 @@
     }
 
     @Override
-    public void render(ContactInfo value, Object key, SafeHtmlBuilder sb) {
+    public void render(Context context, ContactInfo value, SafeHtmlBuilder sb) {
       // Value can be null, so do a null check..
       if (value == null) {
         return;
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellValidation.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellValidation.java
index 97c9be7..bd4c872 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellValidation.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellValidation.java
@@ -85,9 +85,9 @@
     }
 
     @Override
-    public void onBrowserEvent(Element parent, String value, Object key,
+    public void onBrowserEvent(Context context, Element parent, String value,
         NativeEvent event, ValueUpdater<String> valueUpdater) {
-      super.onBrowserEvent(parent, value, key, event, valueUpdater);
+      super.onBrowserEvent(context, parent, value, event, valueUpdater);
 
       // Ignore events that don't target the input.
       Element target = event.getEventTarget().cast();
@@ -95,6 +95,7 @@
         return;
       }
 
+      Object key = context.getKey();
       ValidationData viewData = getViewData(key);
       String eventType = event.getType();
       if ("change".equals(eventType)) {
@@ -120,8 +121,9 @@
     }
 
     @Override
-    public void render(String value, Object key, SafeHtmlBuilder sb) {
+    public void render(Context context, String value, SafeHtmlBuilder sb) {
       // Get the view data.
+      Object key = context.getKey();
       ValidationData viewData = getViewData(key);
       if (viewData != null && viewData.getValue().equals(value)) {
         // Clear the view data if the value is the same as the current value.
@@ -148,13 +150,13 @@
     }
 
     @Override
-    protected void onEnterKeyDown(Element parent, String value, Object key,
+    protected void onEnterKeyDown(Context context, Element parent, String value,
         NativeEvent event, ValueUpdater<String> valueUpdater) {
       Element target = event.getEventTarget().cast();
       if (getInputElement(parent).isOrHasChild(target)) {
-        finishEditing(parent, value, key, valueUpdater);
+        finishEditing(parent, value, context.getKey(), valueUpdater);
       } else {
-        super.onEnterKeyDown(parent, value, key, event, valueUpdater);
+        super.onEnterKeyDown(context, parent, value, event, valueUpdater);
       }
     }
   }
diff --git a/tools/api-checker/config/gwt21_22userApi.conf b/tools/api-checker/config/gwt21_22userApi.conf
index 405ee8d..9664ee9 100644
--- a/tools/api-checker/config/gwt21_22userApi.conf
+++ b/tools/api-checker/config/gwt21_22userApi.conf
@@ -143,3 +143,124 @@
 com.google.gwt.user.cellview.client.Column::cell MISSING
 com.google.gwt.user.cellview.client.Column::fieldUpdater MISSING
 
+# Passing a Context to Cell methods instead of passing a bunch of different args.
+com.google.gwt.cell.client.AbstractCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.AbstractCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.AbstractCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.AbstractCell::render(Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.AbstractCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.AbstractCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.AbstractEditableCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.AbstractInputCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.AbstractInputCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.AbstractInputCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.AbstractInputCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.AbstractSafeHtmlCell::render(Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.AbstractSafeHtmlCell::render(Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ActionCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ActionCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ActionCell::render(Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ButtonCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ButtonCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ButtonCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ButtonCell::render(Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ButtonCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ButtonCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ButtonCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.CheckboxCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/Boolean;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.CheckboxCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Boolean;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.CheckboxCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/Boolean;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.CheckboxCell::render(Ljava/lang/Boolean;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.CheckboxCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/Boolean;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.CheckboxCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/Boolean;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::render(Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.CompositeCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.CompositeCell::render(Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.CompositeCell::render(Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;Lcom/google/gwt/cell/client/HasCell;) MISSING
+com.google.gwt.cell.client.CompositeCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.CompositeCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.DateCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.DateCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.DateCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.DateCell::render(Ljava/util/Date;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.DateCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.DateCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.DatePickerCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.DatePickerCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.DatePickerCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.DatePickerCell::render(Ljava/util/Date;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.DatePickerCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.DatePickerCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.EditTextCell::edit(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.EditTextCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.EditTextCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.EditTextCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.EditTextCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.EditTextCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.EditTextCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.IconCellDecorator::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.IconCellDecorator::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.IconCellDecorator::render(Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.IconCellDecorator::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.IconCellDecorator::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ImageCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ImageCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ImageCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageLoadingCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageLoadingCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ImageLoadingCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ImageLoadingCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ImageLoadingCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageLoadingCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageResourceCell::isEditing(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/resources/client/ImageResource;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageResourceCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/resources/client/ImageResource;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ImageResourceCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/resources/client/ImageResource;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ImageResourceCell::render(Lcom/google/gwt/resources/client/ImageResource;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ImageResourceCell::resetFocus(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/resources/client/ImageResource;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageResourceCell::setValue(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/resources/client/ImageResource;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.NumberCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/Number;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.NumberCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Number;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.NumberCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/Number;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.NumberCell::render(Ljava/lang/Number;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.NumberCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/Number;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.NumberCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/Number;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.SafeHtmlCell::isEditing(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.SafeHtmlCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.SafeHtmlCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.SafeHtmlCell::render(Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.SafeHtmlCell::resetFocus(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.SafeHtmlCell::setValue(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.SelectionCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.SelectionCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.SelectionCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.SelectionCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.SelectionCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.SelectionCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.TextCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.TextCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.TextCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.TextCell::render(Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.TextCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.TextCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.TextCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.TextInputCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.TextInputCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.TextInputCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.TextInputCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.TextInputCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.TextInputCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.user.cellview.client.CellList::fireEventToCell(Lcom/google/gwt/user/client/Event;Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;) MISSING
+com.google.gwt.user.cellview.client.Column::render(Ljava/lang/Object;Lcom/google/gwt/view/client/ProvidesKey;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.user.cellview.client.Column::onBrowserEvent(Lcom/google/gwt/dom/client/Element;ILjava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/view/client/ProvidesKey;) MISSING
+com.google.gwt.user.cellview.client.Header::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/dom/client/NativeEvent;) MISSING
+com.google.gwt.user.cellview.client.Header::render(Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+
diff --git a/user/javadoc/com/google/gwt/examples/cell/CellExample.java b/user/javadoc/com/google/gwt/examples/cell/CellExample.java
index 2c8317c..524889d 100644
--- a/user/javadoc/com/google/gwt/examples/cell/CellExample.java
+++ b/user/javadoc/com/google/gwt/examples/cell/CellExample.java
@@ -39,7 +39,7 @@
   private static class ColorCell extends AbstractCell<String> {
 
     @Override
-    public void render(String value, Object key, SafeHtmlBuilder sb) {
+    public void render(Context context, String value, SafeHtmlBuilder sb) {
       /*
        * Always do a null check on the value. Cell widgets can pass null to
        * cells if the underlying data contains a null, or if the data arrives
diff --git a/user/javadoc/com/google/gwt/examples/cell/EditableCellExample.java b/user/javadoc/com/google/gwt/examples/cell/EditableCellExample.java
index 024a01b..73aacf2 100644
--- a/user/javadoc/com/google/gwt/examples/cell/EditableCellExample.java
+++ b/user/javadoc/com/google/gwt/examples/cell/EditableCellExample.java
@@ -67,7 +67,7 @@
     }
 
     @Override
-    public void onBrowserEvent(Element parent, Contact value, Object key,
+    public void onBrowserEvent(Context context, Element parent, Contact value,
         NativeEvent event, ValueUpdater<Contact> valueUpdater) {
       // Check that the value is not null.
       if (value == null) {
@@ -75,7 +75,7 @@
       }
 
       // Call the super handler, which handlers the enter key.
-      super.onBrowserEvent(parent, value, key, event, valueUpdater);
+      super.onBrowserEvent(context, parent, value, event, valueUpdater);
 
       // Handle click events.
       if ("change".equals(event.getType())) {
@@ -85,7 +85,7 @@
     }
 
     @Override
-    public void render(Contact value, Object key, SafeHtmlBuilder sb) {
+    public void render(Context context, Contact value, SafeHtmlBuilder sb) {
       /*
        * Always do a null check on the value. Cell widgets can pass null to
        * cells if the underlying data contains a null, or if the data arrives
@@ -123,8 +123,8 @@
      * navigation in the widget. Our cell will toggle the checkbox on Enter.
      */
     @Override
-    protected void onEnterKeyDown(Element parent, Contact value, Object key,
-        NativeEvent event, ValueUpdater<Contact> valueUpdater) {
+    protected void onEnterKeyDown(Context context, Element parent,
+        Contact value, NativeEvent event, ValueUpdater<Contact> valueUpdater) {
       // Toggle the checkbox.
       InputElement input = getInputElement(parent);
       input.setChecked(!input.isChecked());
diff --git a/user/javadoc/com/google/gwt/examples/cell/InteractionCellExample.java b/user/javadoc/com/google/gwt/examples/cell/InteractionCellExample.java
index ceaa7a3..70c7001 100644
--- a/user/javadoc/com/google/gwt/examples/cell/InteractionCellExample.java
+++ b/user/javadoc/com/google/gwt/examples/cell/InteractionCellExample.java
@@ -78,7 +78,7 @@
     }
 
     @Override
-    public void onBrowserEvent(Element parent, Contact value, Object key,
+    public void onBrowserEvent(Context context, Element parent, Contact value,
         NativeEvent event, ValueUpdater<Contact> valueUpdater) {
       // Check that the value is not null.
       if (value == null) {
@@ -86,16 +86,16 @@
       }
 
       // Call the super handler, which handlers the enter key.
-      super.onBrowserEvent(parent, value, key, event, valueUpdater);
+      super.onBrowserEvent(context, parent, value, event, valueUpdater);
 
       // On click, perform the same action that we perform on enter.
       if ("click".equals(event.getType())) {
-        this.onEnterKeyDown(parent, value, key, event, valueUpdater);
+        this.onEnterKeyDown(context, parent, value, event, valueUpdater);
       }
     }
 
     @Override
-    public void render(Contact value, Object key, SafeHtmlBuilder sb) {
+    public void render(Context context, Contact value, SafeHtmlBuilder sb) {
       /*
        * Always do a null check on the value. Cell widgets can pass null to
        * cells if the underlying data contains a null, or if the data arrives
@@ -128,8 +128,8 @@
      * navigation in the widget.
      */
     @Override
-    protected void onEnterKeyDown(Element parent, Contact value, Object key,
-        NativeEvent event, ValueUpdater<Contact> valueUpdater) {
+    protected void onEnterKeyDown(Context context, Element parent,
+        Contact value, NativeEvent event, ValueUpdater<Contact> valueUpdater) {
       Window.alert("You clicked " + value.name);
     }
   }
diff --git a/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample2.java b/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample2.java
index 013db42..5aa5173 100644
--- a/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample2.java
+++ b/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample2.java
@@ -209,7 +209,7 @@
         // Create a cell to display a composer.
         Cell<Composer> cell = new AbstractCell<Composer>() {
           @Override
-          public void render(Composer value, Object key, SafeHtmlBuilder sb) {
+          public void render(Context context, Composer value, SafeHtmlBuilder sb) {
             if (value != null) {
               sb.appendEscaped(value.getName());
             }
@@ -225,7 +225,7 @@
             ((Composer) value).getPlaylists());
         Cell<Playlist> cell = new AbstractCell<Playlist>() {
           @Override
-          public void render(Playlist value, Object key, SafeHtmlBuilder sb) {
+          public void render(Context context, Playlist value, SafeHtmlBuilder sb) {
             if (value != null) {
               sb.appendEscaped(value.getName());
             }
diff --git a/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample2.java b/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample2.java
index 6c713f8..6825e76 100644
--- a/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample2.java
+++ b/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample2.java
@@ -210,7 +210,7 @@
         // Create a cell to display a composer.
         Cell<Composer> cell = new AbstractCell<Composer>() {
           @Override
-          public void render(Composer value, Object key, SafeHtmlBuilder sb) {
+          public void render(Context context, Composer value, SafeHtmlBuilder sb) {
             if (value != null) {
               sb.appendEscaped(value.getName());
             }
@@ -226,7 +226,7 @@
             ((Composer) value).getPlaylists());
         Cell<Playlist> cell = new AbstractCell<Playlist>() {
           @Override
-          public void render(Playlist value, Object key, SafeHtmlBuilder sb) {
+          public void render(Context context, Playlist value, SafeHtmlBuilder sb) {
             if (value != null) {
               sb.appendEscaped(value.getName());
             }
diff --git a/user/javadoc/com/google/gwt/examples/view/KeyProviderExample.java b/user/javadoc/com/google/gwt/examples/view/KeyProviderExample.java
index f3cfc89..434019e 100644
--- a/user/javadoc/com/google/gwt/examples/view/KeyProviderExample.java
+++ b/user/javadoc/com/google/gwt/examples/view/KeyProviderExample.java
@@ -54,7 +54,7 @@
    */
   private static class ContactCell extends AbstractCell<Contact> {
     @Override
-    public void render(Contact value, Object key, SafeHtmlBuilder sb) {
+    public void render(Context context, Contact value, SafeHtmlBuilder sb) {
       if (value != null) {
         sb.appendEscaped(value.name);
       }
diff --git a/user/src/com/google/gwt/cell/client/AbstractCell.java b/user/src/com/google/gwt/cell/client/AbstractCell.java
index d47edee..e98f6af 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
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.cell.client;
 
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.event.dom.client.KeyCodes;
@@ -26,7 +27,7 @@
 
 /**
  * A default implementation of the {@link Cell} interface.
- *
+ * 
  * <p>
  * <h3>Examples</h3>
  * <dl>
@@ -38,7 +39,7 @@
  * <dd>{@example com.google.gwt.examples.cell.EditableCellExample}</dd>
  * </dl>
  * </p>
- *
+ * 
  * @param <C> the type that this Cell represents
  */
 public abstract class AbstractCell<C> implements Cell<C> {
@@ -51,7 +52,7 @@
   /**
    * Construct a new {@link AbstractCell} with the specified consumed events.
    * The input arguments are passed by copy.
-   *
+   * 
    * @param consumedEvents the events that this cell consumes
    */
   public AbstractCell(String... consumedEvents) {
@@ -67,7 +68,7 @@
 
   /**
    * Construct a new {@link AbstractCell} with the specified consumed events.
-   *
+   * 
    * @param consumedEvents the events that this cell consumes
    */
   public AbstractCell(Set<String> consumedEvents) {
@@ -90,45 +91,45 @@
    * Returns false. Subclasses that support editing should override this method
    * to return the current editing status.
    */
-  public boolean isEditing(Element parent, C value, Object key) {
+  public boolean isEditing(Context context, Element parent, C value) {
     return false;
   }
 
   /**
    * {@inheritDoc}
-   *
+   * 
    * <p>
    * If you override this method to add support for events, remember to pass the
    * event types that the cell expects into the constructor.
    * </p>
    */
-  public void onBrowserEvent(Element parent, C value, Object key,
+  public void onBrowserEvent(Context context, Element parent, C value,
       NativeEvent event, ValueUpdater<C> valueUpdater) {
     String eventType = event.getType();
     // Special case the ENTER key for a unified user experience.
     if ("keydown".equals(eventType) && event.getKeyCode() == KeyCodes.KEY_ENTER) {
-      onEnterKeyDown(parent, value, key, event, valueUpdater);
+      onEnterKeyDown(context, parent, value, event, valueUpdater);
     }
   }
 
-  public abstract void render(C value, Object key, SafeHtmlBuilder sb);
+  public abstract void render(Context context, C value, SafeHtmlBuilder sb);
 
   /**
    * {@inheritDoc}
-   *
+   * 
    * <p>
    * This method is a no-op and returns false. If your cell is editable or can
    * be focused by the user, override this method to reset focus when the
    * containing widget is refreshed.
    * </p>
    */
-  public boolean resetFocus(Element parent, C value, Object key) {
+  public boolean resetFocus(Context context, Element parent, C value) {
     return false;
   }
 
-  public void setValue(Element parent, C value, Object key) {
+  public void setValue(Context context, Element parent, C value) {
     SafeHtmlBuilder sb = new SafeHtmlBuilder();
-    render(value, key, sb);
+    render(context, value, sb);
     parent.setInnerHTML(sb.toSafeHtml().asString());
   }
 
@@ -138,20 +139,20 @@
    * should override this method to provide a consistent user experience. Your
    * widget must consume <code>keydown</code> events for this method to be
    * called.
-   *
+   * 
+   * @param context the {@link Context} of the cell
    * @param parent the parent Element
    * @param value the value associated with the cell
-   * @param key the unique key associated with the row object
    * @param event the native browser event
    * @param valueUpdater a {@link ValueUpdater}, or null if not specified
    */
-  protected void onEnterKeyDown(Element parent, C value, Object key,
+  protected void onEnterKeyDown(Context context, Element parent, C value,
       NativeEvent event, ValueUpdater<C> valueUpdater) {
   }
 
   /**
    * Initialize the cell.
-   *
+   * 
    * @param consumedEvents the events that the cell consumes
    */
   private void init(Set<String> consumedEvents) {
diff --git a/user/src/com/google/gwt/cell/client/AbstractEditableCell.java b/user/src/com/google/gwt/cell/client/AbstractEditableCell.java
index a99eb8f..66a4bcb 100644
--- a/user/src/com/google/gwt/cell/client/AbstractEditableCell.java
+++ b/user/src/com/google/gwt/cell/client/AbstractEditableCell.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.cell.client;
 
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.dom.client.Element;
 
 import java.util.HashMap;
@@ -76,7 +77,7 @@
    *
    * @param key the key identifying the row object
    * @return the view data, or null if none has been set
-   * @see #setViewData(Object, Object)V
+   * @see #setViewData(Object, Object)
    */
   public V getViewData(Object key) {
     return (key == null) ? null : viewDataMap.get(key);
@@ -87,14 +88,14 @@
    * given element and key. While a cell is editing, widgets containing the cell
    * may choose to pass keystrokes directly to the cell rather than using them
    * for navigation purposes.
-   *
+   * 
+   * @param context the {@link Context} of the cell
    * @param parent the parent Element
    * @param value the value associated with the cell
-   * @param key the unique key associated with the row object
    * @return true if the cell is in edit mode
    */
   @Override
-  public abstract boolean isEditing(Element parent, C value, Object key);
+  public abstract boolean isEditing(Context context, Element parent, C value);
 
   /**
    * Associate view data with the specified key. If the key is null, the view
diff --git a/user/src/com/google/gwt/cell/client/AbstractInputCell.java b/user/src/com/google/gwt/cell/client/AbstractInputCell.java
index e67ccf5..b9719fc 100644
--- a/user/src/com/google/gwt/cell/client/AbstractInputCell.java
+++ b/user/src/com/google/gwt/cell/client/AbstractInputCell.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,7 +23,7 @@
 
 /**
  * An {@link AbstractCell} used to render input elements that can receive focus.
- *
+ * 
  * @param <C> the type that this Cell represents
  * @param <V> the data type of the view data state
  */
@@ -32,7 +32,7 @@
 
   /**
    * Get the events consumed by the input cell.
-   *
+   * 
    * @param userEvents the events consumed by the subclass
    * @return the events
    */
@@ -49,7 +49,7 @@
 
   /**
    * Get the events consumed by the input cell.
-   *
+   * 
    * @param userEvents the events consumed by the subclass
    * @return the events
    */
@@ -71,7 +71,7 @@
   /**
    * Construct a new {@link AbstractInputCell} with the specified consumed
    * events.
-   *
+   * 
    * @param consumedEvents the events that this cell consumes
    */
   public AbstractInputCell(String... consumedEvents) {
@@ -81,7 +81,7 @@
   /**
    * Construct a new {@link AbstractInputCell} with the specified consumed
    * events.
-   *
+   * 
    * @param consumedEvents the events that this cell consumes
    */
   public AbstractInputCell(Set<String> consumedEvents) {
@@ -89,14 +89,14 @@
   }
 
   @Override
-  public boolean isEditing(Element parent, C value, Object key) {
-    return focusedKey != null && focusedKey.equals(key);
+  public boolean isEditing(Context context, Element parent, C value) {
+    return focusedKey != null && focusedKey.equals(context.getKey());
   }
 
   @Override
-  public void onBrowserEvent(Element parent, C value, Object key,
+  public void onBrowserEvent(Context context, Element parent, C value,
       NativeEvent event, ValueUpdater<C> valueUpdater) {
-    super.onBrowserEvent(parent, value, key, event, valueUpdater);
+    super.onBrowserEvent(context, parent, value, event, valueUpdater);
 
     // Ignore events that don't target the input.
     Element target = event.getEventTarget().cast();
@@ -106,15 +106,15 @@
 
     String eventType = event.getType();
     if ("focus".equals(eventType)) {
-      focusedKey = key;
+      focusedKey = context.getKey();
     } else if ("blur".equals(eventType)) {
       focusedKey = null;
     }
   }
 
   @Override
-  public boolean resetFocus(Element parent, C value, Object key) {
-    if (isEditing(parent, value, key)) {
+  public boolean resetFocus(Context context, Element parent, C value) {
+    if (isEditing(context, parent, value)) {
       getInputElement(parent).focus();
       return true;
     }
@@ -123,7 +123,7 @@
 
   /**
    * Call this method when editing is complete.
-   *
+   * 
    * @param parent the parent Element
    * @param value the value associated with the cell
    * @param key the unique key associated with the row object
@@ -137,7 +137,7 @@
 
   /**
    * Get the input element.
-   *
+   * 
    * @param parent the cell parent element
    * @return the input element
    */
@@ -146,10 +146,11 @@
   }
 
   @Override
-  protected void onEnterKeyDown(Element parent, C value, Object key,
+  protected void onEnterKeyDown(Context context, Element parent, C value,
       NativeEvent event, ValueUpdater<C> valueUpdater) {
     Element input = getInputElement(parent);
     Element target = event.getEventTarget().cast();
+    Object key = context.getKey();
     if (getInputElement(parent).isOrHasChild(target)) {
       finishEditing(parent, value, key, valueUpdater);
     } else {
diff --git a/user/src/com/google/gwt/cell/client/AbstractSafeHtmlCell.java b/user/src/com/google/gwt/cell/client/AbstractSafeHtmlCell.java
index 4d7bc32..73f7ac7 100644
--- a/user/src/com/google/gwt/cell/client/AbstractSafeHtmlCell.java
+++ b/user/src/com/google/gwt/cell/client/AbstractSafeHtmlCell.java
@@ -73,11 +73,11 @@
   }
 
   @Override
-  public void render(C data, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, C data, SafeHtmlBuilder sb) {
     if (data == null) {
-      render((SafeHtml) null, key, sb);
+      render(context, (SafeHtml) null, sb);
     } else {
-      render(renderer.render(data), key, sb);
+      render(context, renderer.render(data), sb);
     }
   }
 
@@ -85,9 +85,10 @@
    * Render the cell contents after they have been converted to {@link SafeHtml}
    * form.
    * 
+   * @param context the original context to render
    * @param data a {@link SafeHtml} string
-   * @param key the unique key associated with the row object
    * @param sb the {@link SafeHtmlBuilder} to be written to
    */
-  protected abstract void render(SafeHtml data, Object key, SafeHtmlBuilder sb);
+  protected abstract void render(Context context, SafeHtml data,
+      SafeHtmlBuilder sb);
 }
diff --git a/user/src/com/google/gwt/cell/client/ActionCell.java b/user/src/com/google/gwt/cell/client/ActionCell.java
index 0003118..c72c63d 100644
--- a/user/src/com/google/gwt/cell/client/ActionCell.java
+++ b/user/src/com/google/gwt/cell/client/ActionCell.java
@@ -72,21 +72,21 @@
   }
 
   @Override
-  public void onBrowserEvent(Element parent, C value, Object key,
+  public void onBrowserEvent(Context context, Element parent, C value,
       NativeEvent event, ValueUpdater<C> valueUpdater) {
-    super.onBrowserEvent(parent, value, key, event, valueUpdater);
+    super.onBrowserEvent(context, parent, value, event, valueUpdater);
     if ("click".equals(event.getType())) {
-      onEnterKeyDown(parent, value, key, event, valueUpdater);
+      onEnterKeyDown(context, parent, value, event, valueUpdater);
     }
   }
 
   @Override
-  public void render(C value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, C value, SafeHtmlBuilder sb) {
     sb.append(html);
   }
 
   @Override
-  protected void onEnterKeyDown(Element parent, C value, Object key,
+  protected void onEnterKeyDown(Context context, Element parent, C value,
       NativeEvent event, ValueUpdater<C> valueUpdater) {
     delegate.execute(value);
   }
diff --git a/user/src/com/google/gwt/cell/client/ButtonCell.java b/user/src/com/google/gwt/cell/client/ButtonCell.java
index d8caa83..cabd39e 100644
--- a/user/src/com/google/gwt/cell/client/ButtonCell.java
+++ b/user/src/com/google/gwt/cell/client/ButtonCell.java
@@ -44,16 +44,16 @@
   }
 
   @Override
-  public void onBrowserEvent(Element parent, String value, Object key,
+  public void onBrowserEvent(Context context, Element parent, String value,
       NativeEvent event, ValueUpdater<String> valueUpdater) {
-    super.onBrowserEvent(parent, value, key, event, valueUpdater);
+    super.onBrowserEvent(context, parent, value, event, valueUpdater);
     if ("click".equals(event.getType())) {
-      onEnterKeyDown(parent, value, key, event, valueUpdater);
+      onEnterKeyDown(context, parent, value, event, valueUpdater);
     }
   }
 
   @Override
-  public void render(SafeHtml data, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, SafeHtml data, SafeHtmlBuilder sb) {
     sb.appendHtmlConstant("<button type=\"button\" tabindex=\"-1\">");
     if (data != null) {
       sb.append(data);
@@ -62,7 +62,7 @@
   }
 
   @Override
-  protected void onEnterKeyDown(Element parent, String value, Object key,
+  protected void onEnterKeyDown(Context context, Element parent, String value,
       NativeEvent event, ValueUpdater<String> valueUpdater) {
     if (valueUpdater != null) {
       valueUpdater.update(value);
diff --git a/user/src/com/google/gwt/cell/client/Cell.java b/user/src/com/google/gwt/cell/client/Cell.java
index 217217f..2f32358 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
@@ -23,19 +23,70 @@
 
 /**
  * A light weight representation of a renderable object.
- *
+ * 
  * <p>
  * <h3>Example</h3>
  * {@example com.google.gwt.examples.cell.CellExample}
  * </p>
- *
+ * 
  * @param <C> the type that this Cell represents
  */
 public interface Cell<C> {
 
   /**
+   * Contains information about the context of the Cell.
+   */
+  public static class Context {
+
+    private final int column;
+    private final int index;
+    private final Object key;
+
+    /**
+     * Create a new {@link Context}.
+     * 
+     * @param index the absolute index of the value
+     * @param column the column index of the cell, or 0
+     * @param key the unique key that represents the row value
+     */
+    public Context(int index, int column, Object key) {
+      this.index = index;
+      this.column = column;
+      this.key = key;
+    }
+
+    /**
+     * Get the column index of the cell. If the view only contains a single
+     * column, this method returns 0.
+     * 
+     * @return the column index of the cell
+     */
+    public int getColumn() {
+      return column;
+    }
+
+    /**
+     * Get the absolute index of the value.
+     * 
+     * @return the index
+     */
+    public int getIndex() {
+      return index;
+    }
+
+    /**
+     * Get the key that uniquely identifies the row object.
+     * 
+     * @return the unique key
+     */
+    public Object getKey() {
+      return key;
+    }
+  }
+
+  /**
    * Check if this cell depends on the selection state.
-   *
+   * 
    * @return true if dependent on selection, false if not
    */
   boolean dependsOnSelection();
@@ -43,13 +94,14 @@
   /**
    * Get the set of events that this cell consumes. The container that uses this
    * cell should only pass these events to
-   * {@link #onBrowserEvent(Element, Object, Object, NativeEvent, ValueUpdater)}.
-   *
+   * {@link #onBrowserEvent(Context, Element, Object, NativeEvent, ValueUpdater))}
+   * when the event occurs.
+   * 
    * <p>
    * The returned value should not be modified, and may be an unmodifiable set.
    * Changes to the return value may not be reflected in the cell.
    * </p>
-   *
+   * 
    * @return the consumed events, or null if no events are consumed
    */
   Set<String> getConsumedEvents();
@@ -57,7 +109,7 @@
   /**
    * Check if this cell handles selection. If the cell handles selection, then
    * its container should not automatically handle selection.
-   *
+   * 
    * @return true if the cell handles selection, false if not
    */
   boolean handlesSelection();
@@ -65,32 +117,32 @@
   /**
    * Returns true if the cell is currently editing the data identified by the
    * given element and key. While a cell is editing, widgets containing the cell
-   * may chooses to pass keystrokes directly to the cell rather than using them
+   * may choose to pass keystrokes directly to the cell rather than using them
    * for navigation purposes.
-   *
+   * 
+   * @param context the {@link Context} of the cell
    * @param parent the parent Element
    * @param value the value associated with the cell
-   * @param key the unique key associated with the row object
    * @return true if the cell is in edit mode
    */
-  boolean isEditing(Element parent, C value, Object key);
+  boolean isEditing(Context context, Element parent, C value);
 
   /**
    * Handle a browser event that took place within the cell. The default
    * implementation returns null.
-   *
+   * 
+   * @param context the {@link Context} of the cell
    * @param parent the parent Element
    * @param value the value associated with the cell
-   * @param key the unique key associated with the row object
    * @param event the native browser event
    * @param valueUpdater a {@link ValueUpdater}, or null if not specified
    */
-  void onBrowserEvent(Element parent, C value, Object key, NativeEvent event,
-      ValueUpdater<C> valueUpdater);
+  void onBrowserEvent(Context context, Element parent, C value,
+      NativeEvent event, ValueUpdater<C> valueUpdater);
 
   /**
    * Render a cell as HTML into a {@link SafeHtmlBuilder}, suitable for passing
-   * to {@link Element#setInnerHTML} on a container element.
+   * to {@link Element#setInnerHTML(String)} on a container element.
    * 
    * <p>
    * Note: If your cell contains natively focusable elements, such as buttons or
@@ -98,33 +150,32 @@
    * focus away from the containing widget.
    * </p>
    * 
+   * @param context the {@link Context} of the cell
    * @param value the cell value to be rendered
-   * @param key the unique key associated with the row object
    * @param sb the {@link SafeHtmlBuilder} to be written to
    */
-  void render(C value, Object key, SafeHtmlBuilder sb);
+  void render(Context context, C value, SafeHtmlBuilder sb);
 
   /**
    * Reset focus on the Cell. This method is called if the cell has focus when
    * it is refreshed.
-   *
+   * 
+   * @param context the {@link Context} of the cell
    * @param parent the parent Element
    * @param value the value associated with the cell
-   * @param key the unique key associated with the row object
-   *
    * @return true if focus is taken, false if not
    */
-  boolean resetFocus(Element parent, C value, Object key);
+  boolean resetFocus(Context context, Element parent, C value);
 
   /**
    * 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, SafeHtmlBuilder)}.
-   *
+   * {@link AbstractCell#setValue(Context)} for a default implementation that
+   * uses {@link #render(Context, SafeHtmlBuilder))}.
+   * 
+   * @param context the {@link Context} of the cell
    * @param parent the parent Element
    * @param value the value associated with the cell
-   * @param key the unique key associated with the row object
    */
-  void setValue(Element parent, C value, Object key);
+  void setValue(Context context, Element parent, C value);
 }
diff --git a/user/src/com/google/gwt/cell/client/CheckboxCell.java b/user/src/com/google/gwt/cell/client/CheckboxCell.java
index 1f51a1d..e0eae00 100644
--- a/user/src/com/google/gwt/cell/client/CheckboxCell.java
+++ b/user/src/com/google/gwt/cell/client/CheckboxCell.java
@@ -83,14 +83,14 @@
   }
 
   @Override
-  public boolean isEditing(Element parent, Boolean value, Object key) {
+  public boolean isEditing(Context context, Element parent, Boolean value) {
     // A checkbox is never in "edit mode". There is no intermediate state
     // between checked and unchecked.
     return false;
   }
 
   @Override
-  public void onBrowserEvent(Element parent, Boolean value, Object key,
+  public void onBrowserEvent(Context context, Element parent, Boolean value, 
       NativeEvent event, ValueUpdater<Boolean> valueUpdater) {
     String type = event.getType();
 
@@ -117,9 +117,9 @@
        * do not save the value because we can get into an inconsistent state.
        */
       if (value != isChecked && !dependsOnSelection()) {
-        setViewData(key, isChecked);
+        setViewData(context.getKey(), isChecked);
       } else {
-        clearViewData(key);
+        clearViewData(context.getKey());
       }
 
       if (valueUpdater != null) {
@@ -129,8 +129,9 @@
   }
 
   @Override
-  public void render(Boolean value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, Boolean value, SafeHtmlBuilder sb) {
     // Get the view data.
+    Object key = context.getKey();
     Boolean viewData = getViewData(key);
     if (viewData != null && viewData.equals(value)) {
       clearViewData(key);
diff --git a/user/src/com/google/gwt/cell/client/ClickableTextCell.java b/user/src/com/google/gwt/cell/client/ClickableTextCell.java
index 16fbe38..a3a41d7 100644
--- a/user/src/com/google/gwt/cell/client/ClickableTextCell.java
+++ b/user/src/com/google/gwt/cell/client/ClickableTextCell.java
@@ -47,16 +47,16 @@
   }
 
   @Override
-  public void onBrowserEvent(Element parent, String value, Object key,
+  public void onBrowserEvent(Context context, Element parent, String value,
       NativeEvent event, ValueUpdater<String> valueUpdater) {
-    super.onBrowserEvent(parent, value, key, event, valueUpdater);
+    super.onBrowserEvent(context, parent, value, event, valueUpdater);
     if ("click".equals(event.getType())) {
-      onEnterKeyDown(parent, value, key, event, valueUpdater);
+      onEnterKeyDown(context, parent, value, event, valueUpdater);
     }
   }
 
   @Override
-  protected void onEnterKeyDown(Element parent, String value, Object key,
+  protected void onEnterKeyDown(Context context, Element parent, String value,
       NativeEvent event, ValueUpdater<String> valueUpdater) {
     if (valueUpdater != null) {
       valueUpdater.update(value);
@@ -64,7 +64,7 @@
   }
 
   @Override
-  protected void render(SafeHtml value, Object key, SafeHtmlBuilder sb) {
+  protected void render(Context context, SafeHtml value, SafeHtmlBuilder 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 6013d46..c1328b6 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
@@ -30,13 +30,13 @@
  * <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>
- *
+ * 
  * @param <C> the type that this Cell represents
  */
 public class CompositeCell<C> extends AbstractCell<C> {
@@ -58,7 +58,7 @@
 
   /**
    * The cells that compose this {@link 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.
@@ -67,7 +67,7 @@
 
   /**
    * Construct a new {@link CompositeCell}.
-   *
+   * 
    * @param hasCells the cells that makeup the composite
    */
   public CompositeCell(List<HasCell<C, ?>> hasCells) {
@@ -113,7 +113,7 @@
   }
 
   @Override
-  public void onBrowserEvent(Element parent, C value, Object key,
+  public void onBrowserEvent(Context context, Element parent, C value,
       NativeEvent event, ValueUpdater<C> valueUpdater) {
     int index = 0;
     EventTarget eventTarget = event.getEventTarget();
@@ -123,7 +123,7 @@
       Element wrapper = container.getFirstChildElement();
       while (wrapper != null) {
         if (wrapper.isOrHasChild(target)) {
-          onBrowserEventImpl(wrapper, value, key, event, valueUpdater,
+          onBrowserEventImpl(context, wrapper, value, event, valueUpdater,
               hasCells.get(index));
         }
 
@@ -134,19 +134,19 @@
   }
 
   @Override
-  public void render(C value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, C value, SafeHtmlBuilder sb) {
     for (HasCell<C, ?> hasCell : hasCells) {
-      render(value, key, sb, hasCell);
+      render(context, value, sb, hasCell);
     }
   }
 
   @Override
-  public boolean resetFocus(Element parent, C value, Object key) {
+  public boolean resetFocus(Context context, Element parent, C value) {
     Element curChild = getContainerElement(parent).getFirstChildElement();
     for (HasCell<C, ?> hasCell : hasCells) {
       // The first child that takes focus wins. Only one child should ever be in
       // edit mode, so this is safe.
-      if (resetFocusImpl(curChild, value, key, hasCell)) {
+      if (resetFocusImpl(context, curChild, value, hasCell)) {
         return true;
       }
       curChild = curChild.getNextSiblingElement();
@@ -155,10 +155,10 @@
   }
 
   @Override
-  public void setValue(Element parent, C object, Object key) {
+  public void setValue(Context context, Element parent, C object) {
     Element curChild = getContainerElement(parent).getFirstChildElement();
     for (HasCell<C, ?> hasCell : hasCells) {
-      setValueImpl(curChild, object, key, hasCell);
+      setValueImpl(context, curChild, object, hasCell);
       curChild = curChild.getNextSiblingElement();
     }
   }
@@ -167,7 +167,7 @@
    * Get the element that acts as the container for all children. If children
    * are added directly to the parent, the parent is the container. If children
    * are added in a table row, the row is the parent.
-   *
+   * 
    * @param parent the parent element of the cell
    * @return the container element
    */
@@ -185,22 +185,22 @@
    * focus away from the containing widget.
    * </p>
    * 
+   * @param context the {@link Context} of the cell
    * @param value the cell value to be rendered
-   * @param key the unique key associated with the row object
    * @param sb the {@link SafeHtmlBuilder} to be written to
    * @param hasCell a {@link HasCell} instance containing the cells to be
    *          rendered within this cell
    */
-  protected <X> void render(C value, Object key, SafeHtmlBuilder sb,
-      HasCell<C, X> hasCell) {
+  protected <X> void render(Context context, C value,
+      SafeHtmlBuilder sb, HasCell<C, X> hasCell) {
     Cell<X> cell = hasCell.getCell();
     sb.appendHtmlConstant("<span>");
-    cell.render(hasCell.getValue(value), key, sb);
+    cell.render(context, hasCell.getValue(value), sb);
     sb.appendHtmlConstant("</span>");
   }
 
-  private <X> void onBrowserEventImpl(Element parent, final C object,
-      Object key, NativeEvent event, final ValueUpdater<C> valueUpdater,
+  private <X> void onBrowserEventImpl(Context context, Element parent,
+      final C object, NativeEvent event, final ValueUpdater<C> valueUpdater,
       final HasCell<C, X> hasCell) {
     ValueUpdater<X> tempUpdater = null;
     final FieldUpdater<C, X> fieldUpdater = hasCell.getFieldUpdater();
@@ -215,18 +215,18 @@
       };
     }
     Cell<X> cell = hasCell.getCell();
-    cell.onBrowserEvent(parent, hasCell.getValue(object), key, event,
+    cell.onBrowserEvent(context, parent, hasCell.getValue(object), event,
         tempUpdater);
   }
 
-  private <X> boolean resetFocusImpl(Element cellParent, C value, Object key,
-      HasCell<C, X> hasCell) {
+  private <X> boolean resetFocusImpl(Context context, Element cellParent,
+      C value, HasCell<C, X> hasCell) {
     X cellValue = hasCell.getValue(value);
-    return hasCell.getCell().resetFocus(cellParent, cellValue, key);
+    return hasCell.getCell().resetFocus(context, cellParent, cellValue);
   }
 
-  private <X> void setValueImpl(Element cellParent, C object, Object key,
+  private <X> void setValueImpl(Context context, Element cellParent, C object,
       HasCell<C, X> hasCell) {
-    hasCell.getCell().setValue(cellParent, hasCell.getValue(object), key);
-  }
+    hasCell.getCell().setValue(context, cellParent, hasCell.getValue(object));
+  }  
 }
diff --git a/user/src/com/google/gwt/cell/client/DateCell.java b/user/src/com/google/gwt/cell/client/DateCell.java
index bfab2af..bed5b8b 100644
--- a/user/src/com/google/gwt/cell/client/DateCell.java
+++ b/user/src/com/google/gwt/cell/client/DateCell.java
@@ -82,7 +82,7 @@
   }
 
   @Override
-  public void render(Date value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, Date value, SafeHtmlBuilder sb) {
     if (value != null) {
       sb.append(renderer.render(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 49df900..4b1252b 100644
--- a/user/src/com/google/gwt/cell/client/DatePickerCell.java
+++ b/user/src/com/google/gwt/cell/client/DatePickerCell.java
@@ -61,6 +61,8 @@
   private int offsetY = 10;
   private Object lastKey;
   private Element lastParent;
+  private int lastIndex;
+  private int lastColumn;
   private Date lastValue;
   private PopupPanel panel;
   private final SafeHtmlRenderer<String> renderer;
@@ -131,6 +133,8 @@
       public void onClose(CloseEvent<PopupPanel> event) {
         lastKey = null;
         lastValue = null;
+        lastIndex = -1;
+        lastColumn = -1;
         if (lastParent != null && !event.isAutoClosed()) {
           // Refocus on the containing cell after the user selects a value, but
           // not if the popup is auto closed.
@@ -148,12 +152,14 @@
         Element cellParent = lastParent;
         Date oldValue = lastValue;
         Object key = lastKey;
+        int index = lastIndex;
+        int column = lastColumn;
         panel.hide();
 
         // Update the cell and value updater.
         Date date = event.getValue();
         setViewData(key, date);
-        setValue(cellParent, oldValue, key);
+        setValue(new Context(index, column, key), cellParent, oldValue);
         if (valueUpdater != null) {
           valueUpdater.update(date);
         }
@@ -162,22 +168,23 @@
   }
 
   @Override
-  public boolean isEditing(Element parent, Date value, Object key) {
-    return lastKey != null && lastKey.equals(key);
+  public boolean isEditing(Context context, Element parent, Date value) {
+    return lastKey != null && lastKey.equals(context.getKey());
   }
 
   @Override
-  public void onBrowserEvent(Element parent, Date value, Object key,
+  public void onBrowserEvent(Context context, Element parent, Date value,
       NativeEvent event, ValueUpdater<Date> valueUpdater) {
-    super.onBrowserEvent(parent, value, key, event, valueUpdater);
+    super.onBrowserEvent(context, parent, value, event, valueUpdater);
     if ("click".equals(event.getType())) {
-      onEnterKeyDown(parent, value, key, event, valueUpdater);
+      onEnterKeyDown(context, parent, value, event, valueUpdater);
     }
   }
 
   @Override
-  public void render(Date value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, Date value, SafeHtmlBuilder sb) {
     // Get the view data.
+    Object key = context.getKey();
     Date viewData = getViewData(key);
     if (viewData != null && viewData.equals(value)) {
       clearViewData(key);
@@ -196,21 +203,23 @@
   }
 
   @Override
-  protected void onEnterKeyDown(final Element parent, Date value, Object key,
+  protected void onEnterKeyDown(Context context, Element parent, Date value,
       NativeEvent event, ValueUpdater<Date> valueUpdater) {
-    this.lastKey = key;
+    this.lastKey = context.getKey();
     this.lastParent = parent;
     this.lastValue = value;
+    this.lastIndex = context.getIndex();
+    this.lastColumn = context.getColumn();
     this.valueUpdater = valueUpdater;
 
-    Date viewData = getViewData(key);
-    Date date = (viewData == null) ? value : viewData;
+    Date viewData = getViewData(lastKey);
+    Date date = (viewData == null) ? lastValue : viewData;
     datePicker.setCurrentMonth(date);
     datePicker.setValue(date);
     panel.setPopupPositionAndShow(new PositionCallback() {
       public void setPosition(int offsetWidth, int offsetHeight) {
-        panel.setPopupPosition(parent.getAbsoluteLeft() + offsetX,
-            parent.getAbsoluteTop() + offsetY);
+        panel.setPopupPosition(lastParent.getAbsoluteLeft() + offsetX,
+            lastParent.getAbsoluteTop() + offsetY);
       }
     });
   }
diff --git a/user/src/com/google/gwt/cell/client/EditTextCell.java b/user/src/com/google/gwt/cell/client/EditTextCell.java
index 57f214f..e180a69 100644
--- a/user/src/com/google/gwt/cell/client/EditTextCell.java
+++ b/user/src/com/google/gwt/cell/client/EditTextCell.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.cell.client;
 
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.EventTarget;
@@ -161,18 +162,19 @@
   }
 
   @Override
-  public boolean isEditing(Element element, String value, Object key) {
-    ViewData viewData = getViewData(key);
+  public boolean isEditing(Context context, Element parent, String value) {
+    ViewData viewData = getViewData(context.getKey());
     return viewData == null ? false : viewData.isEditing();
   }
 
   @Override
-  public void onBrowserEvent(Element parent, String value, Object key,
+  public void onBrowserEvent(Context context, Element parent, String value,
       NativeEvent event, ValueUpdater<String> valueUpdater) {
+    Object key = context.getKey();
     ViewData viewData = getViewData(key);
     if (viewData != null && viewData.isEditing()) {
       // Handle the edit event.
-      editEvent(parent, key, viewData, event, valueUpdater);
+      editEvent(context, parent, value, viewData, event, valueUpdater);
     } else {
       String type = event.getType();
       int keyCode = event.getKeyCode();
@@ -186,14 +188,15 @@
         } else {
           viewData.setEditing(true);
         }
-        edit(parent, value, key);
+        edit(context, parent, value);
       }
     }
   }
 
   @Override
-  public void render(String value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, String value, SafeHtmlBuilder sb) {
     // Get the view data.
+    Object key = context.getKey();
     ViewData viewData = getViewData(key);
     if (viewData != null && !viewData.isEditing() && value != null
         && value.equals(viewData.getText())) {
@@ -218,8 +221,8 @@
   }
 
   @Override
-  public boolean resetFocus(Element parent, String value, Object key) {
-    if (isEditing(parent, value, key)) {
+  public boolean resetFocus(Context context, Element parent, String value) {
+    if (isEditing(context, parent, value)) {
       getInputElement(parent).focus();
       return true;
     }
@@ -229,12 +232,12 @@
   /**
    * Convert the cell to edit mode.
    *
+   * @param context the {@link Context} of the cell
    * @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);
+  protected void edit(Context context, Element parent, String value) {
+    setValue(context, parent, value);
     InputElement input = getInputElement(parent);
     input.focus();
     input.select();
@@ -242,13 +245,14 @@
 
   /**
    * Convert the cell to non-edit mode.
-   *
-   * @param parent the parent element
-   * @param value the current value
+   * 
+   * @param context the context of the cell
+   * @param parent the parent Element
+   * @param value the value associated with the cell
    */
-  private void cancel(Element parent, String value) {
+  private void cancel(Context context, Element parent, String value) {
     clearInput(getInputElement(parent));
-    setValue(parent, value, null);
+    setValue(context, parent, value);
   }
 
   /**
@@ -267,23 +271,24 @@
 
   /**
    * Commit the current value.
-   *
-   * @param parent the parent element
+   * 
+   * @param context the context of the cell
+   * @param parent the parent Element
    * @param viewData the {@link ViewData} object
    * @param valueUpdater the {@link ValueUpdater}
    */
-  private void commit(Element parent, ViewData viewData,
+  private void commit(Context context, Element parent, ViewData viewData,
       ValueUpdater<String> valueUpdater) {
     String value = updateViewData(parent, viewData, false);
     clearInput(getInputElement(parent));
-    setValue(parent, value, viewData);
+    setValue(context, parent, viewData.getOriginal());
     if (valueUpdater != null) {
       valueUpdater.update(value);
     }
   }
 
-  private void editEvent(Element parent, Object key, ViewData viewData,
-      NativeEvent event, ValueUpdater<String> valueUpdater) {
+  private void editEvent(Context context, Element parent, String value,
+      ViewData viewData, NativeEvent event, ValueUpdater<String> valueUpdater) {
     String type = event.getType();
     boolean keyUp = "keyup".equals(type);
     boolean keyDown = "keydown".equals(type);
@@ -291,7 +296,7 @@
       int keyCode = event.getKeyCode();
       if (keyUp && keyCode == KeyCodes.KEY_ENTER) {
         // Commit the change.
-        commit(parent, viewData, valueUpdater);
+        commit(context, parent, viewData, valueUpdater);
       } else if (keyUp && keyCode == KeyCodes.KEY_ESCAPE) {
         // Cancel edit mode.
         String originalText = viewData.getOriginal();
@@ -299,9 +304,9 @@
           viewData.setText(originalText);
           viewData.setEditing(false);
         } else {
-          setViewData(key, null);
+          setViewData(context.getKey(), null);
         }
-        cancel(parent, originalText);
+        cancel(context, parent, value);
       } else {
         // Update the text in the view data on each key.
         updateViewData(parent, viewData, true);
@@ -313,7 +318,7 @@
       if (Element.is(eventTarget)) {
         Element target = Element.as(eventTarget);
         if ("input".equals(target.getTagName().toLowerCase())) {
-          commit(parent, viewData, valueUpdater);
+          commit(context, parent, viewData, valueUpdater);
         }
       }
     }
diff --git a/user/src/com/google/gwt/cell/client/IconCellDecorator.java b/user/src/com/google/gwt/cell/client/IconCellDecorator.java
index 496ac3c..3e0c7da 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
@@ -32,7 +32,7 @@
 
 /**
  * A {@link Cell} decorator that adds an icon to another {@link Cell}.
- *
+ * 
  * @param <C> the type that this Cell represents
  */
 public class IconCellDecorator<C> implements Cell<C> {
@@ -83,7 +83,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
    */
@@ -93,7 +93,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
@@ -122,35 +122,36 @@
     return cell.handlesSelection();
   }
 
-  public boolean isEditing(Element element, C value, Object key) {
-    return cell.isEditing(element, value, key);
+  public boolean isEditing(Context context, Element parent, C value) {
+    return cell.isEditing(context, getCellParent(parent), value);
   }
 
-  public void onBrowserEvent(Element parent, C value, Object key,
+  public void onBrowserEvent(Context context, Element parent, C value,
       NativeEvent event, ValueUpdater<C> valueUpdater) {
-    cell.onBrowserEvent(getCellParent(parent), value, key, event, valueUpdater);
+    cell.onBrowserEvent(context, getCellParent(parent), value, event,
+        valueUpdater);
   }
 
-  public void render(C value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, C value, SafeHtmlBuilder sb) {
     SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();
-    cell.render(value, key, cellBuilder);
+    cell.render(context, value, cellBuilder);
 
     sb.append(template.outerDiv(direction, imageWidth, isIconUsed(value)
         ? getIconHtml(value) : placeHolderHtml, cellBuilder.toSafeHtml()));
   }
 
-  public boolean resetFocus(Element parent, C value, Object key) {
-    return cell.resetFocus(getCellParent(parent), value, key);
+  public boolean resetFocus(Context context, Element parent, C value) {
+    return cell.resetFocus(context, getCellParent(parent), value);
   }
 
-  public void setValue(Element parent, C value, Object key) {
-    cell.setValue(getCellParent(parent), value, key);
+  public void setValue(Context context, Element parent, C value) {
+    cell.setValue(context, getCellParent(parent), value);
   }
 
   /**
    * Get the safe 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
    */
@@ -162,7 +163,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
    */
@@ -172,7 +173,7 @@
 
   /**
    * 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
@@ -203,7 +204,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/ImageCell.java b/user/src/com/google/gwt/cell/client/ImageCell.java
index 25f173d..18ea3c8 100644
--- a/user/src/com/google/gwt/cell/client/ImageCell.java
+++ b/user/src/com/google/gwt/cell/client/ImageCell.java
@@ -51,7 +51,7 @@
   }
 
   @Override
-  public void render(String value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, String value, SafeHtmlBuilder sb) {
     if (value != null) {
       // The template will sanitize the URI.
       sb.append(template.img(value));
diff --git a/user/src/com/google/gwt/cell/client/ImageLoadingCell.java b/user/src/com/google/gwt/cell/client/ImageLoadingCell.java
index 67a3e23..e72e7a4 100644
--- a/user/src/com/google/gwt/cell/client/ImageLoadingCell.java
+++ b/user/src/com/google/gwt/cell/client/ImageLoadingCell.java
@@ -179,7 +179,7 @@
   }
 
   @Override
-  public void onBrowserEvent(Element parent, String value, Object key,
+  public void onBrowserEvent(Context context, Element parent, String value,
       NativeEvent event, ValueUpdater<String> valueUpdater) {
     // The loading indicator can fire its own load or error event, so we check
     // that the event actually occurred on the main image.
@@ -201,7 +201,7 @@
   }
 
   @Override
-  public void render(String value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, String value, SafeHtmlBuilder sb) {
     // We can't use ViewData because we don't know the caching policy of the
     // browser. The browser may fetch the image every time we render.
     if (value != null) {
diff --git a/user/src/com/google/gwt/cell/client/ImageResourceCell.java b/user/src/com/google/gwt/cell/client/ImageResourceCell.java
index ce9fb37..c2a0c8c 100644
--- a/user/src/com/google/gwt/cell/client/ImageResourceCell.java
+++ b/user/src/com/google/gwt/cell/client/ImageResourceCell.java
@@ -40,7 +40,7 @@
   }
 
   @Override
-  public void render(ImageResource value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, ImageResource value, SafeHtmlBuilder sb) {
     if (value != null) {
       SafeHtml html = SafeHtmlUtils.fromTrustedString(AbstractImagePrototype.create(
           value).getHTML());
diff --git a/user/src/com/google/gwt/cell/client/NumberCell.java b/user/src/com/google/gwt/cell/client/NumberCell.java
index 14b301b..cdf0201 100644
--- a/user/src/com/google/gwt/cell/client/NumberCell.java
+++ b/user/src/com/google/gwt/cell/client/NumberCell.java
@@ -84,7 +84,7 @@
   }
 
   @Override
-  public void render(Number value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, Number value, SafeHtmlBuilder sb) {
     if (value != null) {
       sb.append(renderer.render(format.format(value)));
     }
diff --git a/user/src/com/google/gwt/cell/client/SafeHtmlCell.java b/user/src/com/google/gwt/cell/client/SafeHtmlCell.java
index 69f46ed..bb4109b 100644
--- a/user/src/com/google/gwt/cell/client/SafeHtmlCell.java
+++ b/user/src/com/google/gwt/cell/client/SafeHtmlCell.java
@@ -30,7 +30,7 @@
   }
 
   @Override
-  public void render(SafeHtml value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, SafeHtml value, SafeHtmlBuilder sb) {
     if (value != null) {
       sb.append(value);
     }
diff --git a/user/src/com/google/gwt/cell/client/SelectionCell.java b/user/src/com/google/gwt/cell/client/SelectionCell.java
index 79c9b76..1695d19 100644
--- a/user/src/com/google/gwt/cell/client/SelectionCell.java
+++ b/user/src/com/google/gwt/cell/client/SelectionCell.java
@@ -64,11 +64,12 @@
   }
 
   @Override
-  public void onBrowserEvent(Element parent, String value, Object key,
+  public void onBrowserEvent(Context context, Element parent, String value,
       NativeEvent event, ValueUpdater<String> valueUpdater) {
-    super.onBrowserEvent(parent, value, key, event, valueUpdater);
+    super.onBrowserEvent(context, parent, value, event, valueUpdater);
     String type = event.getType();
     if ("change".equals(type)) {
+      Object key = context.getKey();
       SelectElement select = parent.getFirstChild().cast();
       String newValue = options.get(select.getSelectedIndex());
       setViewData(key, newValue);
@@ -80,8 +81,9 @@
   }
 
   @Override
-  public void render(String value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, String value, SafeHtmlBuilder sb) {
     // Get the view data.
+    Object key = context.getKey();
     String viewData = getViewData(key);
     if (viewData != null && viewData.equals(value)) {
       clearViewData(key);
diff --git a/user/src/com/google/gwt/cell/client/TextCell.java b/user/src/com/google/gwt/cell/client/TextCell.java
index 48db9eb..2df83ec 100644
--- a/user/src/com/google/gwt/cell/client/TextCell.java
+++ b/user/src/com/google/gwt/cell/client/TextCell.java
@@ -44,7 +44,7 @@
   }
 
   @Override
-  public void render(SafeHtml value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, SafeHtml value, SafeHtmlBuilder 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 be1f7d5..e90d295 100644
--- a/user/src/com/google/gwt/cell/client/TextInputCell.java
+++ b/user/src/com/google/gwt/cell/client/TextInputCell.java
@@ -156,9 +156,9 @@
   }
 
   @Override
-  public void onBrowserEvent(Element parent, String value, Object key,
+  public void onBrowserEvent(Context context, Element parent, String value,
       NativeEvent event, ValueUpdater<String> valueUpdater) {
-    super.onBrowserEvent(parent, value, key, event, valueUpdater);
+    super.onBrowserEvent(context, parent, value, event, valueUpdater);
 
     // Ignore events that don't target the input.
     InputElement input = getInputElement(parent);
@@ -168,6 +168,7 @@
     }
 
     String eventType = event.getType();
+    Object key = context.getKey();
     if ("change".equals(eventType)) {
       finishEditing(parent, value, key, valueUpdater);
     } else if ("keyup".equals(eventType)) {
@@ -182,8 +183,9 @@
   }
 
   @Override
-  public void render(String value, Object key, SafeHtmlBuilder sb) {
+  public void render(Context context, String value, SafeHtmlBuilder sb) {
     // Get the view data.
+    Object key = context.getKey();
     ViewData viewData = getViewData(key);
     if (viewData != null && viewData.getCurrentValue().equals(value)) {
       clearViewData(key);
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 1776e45..d92b913 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
@@ -17,6 +17,7 @@
 
 import com.google.gwt.animation.client.Animation;
 import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
@@ -300,7 +301,8 @@
         }
 
         SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();
-        cell.render(value, getValueKey(value), cellBuilder);
+        Context context = new Context(i, 0, getValueKey(value));
+        cell.render(context, value, cellBuilder);
 
         // Figure out which image to use.
         SafeHtml image;
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 9034ae3..2c557d5 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellList.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellList.java
@@ -16,6 +16,7 @@
 package com.google.gwt.user.cellview.client;
 
 import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.cell.client.ValueUpdater;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.Scheduler;
@@ -289,18 +290,19 @@
 
   /**
    * Fire an event to the cell.
-   *
+   * 
+   * @param context the {@link Context} of the cell
    * @param event the event that was fired
    * @param parent the parent of the cell
    * @param value the value of the cell
    */
-  protected void fireEventToCell(Event event, Element parent, T value) {
+  protected void fireEventToCell(Context context, Event event, Element parent,
+      T value) {
     Set<String> consumedEvents = cell.getConsumedEvents();
     if (consumedEvents != null && consumedEvents.contains(event.getType())) {
-      Object key = getValueKey(value);
-      boolean cellWasEditing = cell.isEditing(parent, value, key);
-      cell.onBrowserEvent(parent, value, key, event, valueUpdater);
-      cellIsEditing = cell.isEditing(parent, value, key);
+      boolean cellWasEditing = cell.isEditing(context, parent, value);
+      cell.onBrowserEvent(context, parent, value, event, valueUpdater);
+      cellIsEditing = cell.isEditing(context, parent, value);
       if (cellWasEditing && !cellIsEditing) {
         CellBasedWidgetImpl.get().resetFocus(new Scheduler.ScheduledCommand() {
           public void execute() {
@@ -393,8 +395,9 @@
           || KeyboardSelectionPolicy.BOUND_TO_SELECTION == getKeyboardSelectionPolicy();
       Element cellParent = getCellParent(cellTarget);
       T value = getVisibleItem(indexOnPage);
+      Context context = new Context(idx, 0, getValueKey(value));
       CellPreviewEvent<T> previewEvent = CellPreviewEvent.fire(this, event,
-          this, indexOnPage, value, cellIsEditing, isSelectionHandled);
+          this, context, value, cellIsEditing, isSelectionHandled);
       if (isClick && !cellIsEditing && !isSelectionHandled) {
         doSelection(event, value, indexOnPage);
       }
@@ -412,7 +415,7 @@
 
       // Fire the event to the cell if the list has not been refreshed.
       if (!previewEvent.isCanceled()) {
-        fireEventToCell(event, cellParent, value);
+        fireEventToCell(context, event, cellParent, value);
       }
     }
   }
@@ -448,7 +451,8 @@
       }
 
       SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();
-      cell.render(value, getValueKey(value), cellBuilder);
+      Context context = new Context(i, 0, getValueKey(value));
+      cell.render(context, value, cellBuilder);
 
       if (i == keyboardSelectedRow) {
         // This is the focused item.
@@ -477,8 +481,8 @@
       Element rowElem = getKeyboardSelectedElement();
       Element cellParent = getCellParent(rowElem);
       T value = getVisibleItem(row);
-      Object key = getValueKey(value);
-      return cell.resetFocus(cellParent, value, key);
+      Context context = new Context(row + getPageStart(), 0, getValueKey(value));
+      return cell.resetFocus(context, cellParent, value);
     }
     return false;
   }
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 31517bd..0c5e6a6 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellTable.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellTable.java
@@ -16,18 +16,19 @@
 package com.google.gwt.user.cellview.client;
 
 import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.EventTarget;
 import com.google.gwt.dom.client.NodeList;
+import com.google.gwt.dom.client.Style.Display;
 import com.google.gwt.dom.client.TableCellElement;
 import com.google.gwt.dom.client.TableColElement;
 import com.google.gwt.dom.client.TableElement;
 import com.google.gwt.dom.client.TableRowElement;
 import com.google.gwt.dom.client.TableSectionElement;
-import com.google.gwt.dom.client.Style.Display;
 import com.google.gwt.event.dom.client.KeyCodes;
 import com.google.gwt.i18n.client.LocaleInfo;
 import com.google.gwt.resources.client.ClientBundle;
@@ -292,7 +293,6 @@
 
     @Template("<td class=\"{0}\" align=\"{1}\" valign=\"{2}\">{3}</td>")
     SafeHtml tdBothAlign(String classes, String hAlign, String vAlign,
-
         SafeHtml contents);
 
     @Template("<td class=\"{0}\" align=\"{1}\">{2}</td>")
@@ -939,12 +939,14 @@
     if (section == thead) {
       Header<?> header = headers.get(col);
       if (header != null && cellConsumesEventType(header.getCell(), eventType)) {
-        header.onBrowserEvent(tableCell, event);
+        Context context = new Context(0, col, header.getKey());
+        header.onBrowserEvent(context, tableCell, event);
       }
     } else if (section == tfoot) {
       Header<?> footer = footers.get(col);
       if (footer != null && cellConsumesEventType(footer.getCell(), eventType)) {
-        footer.onBrowserEvent(tableCell, event);
+        Context context = new Context(0, col, footer.getKey());
+        footer.onBrowserEvent(context, tableCell, event);
       }
     } else if (section == tbody) {
       // Update the hover state.
@@ -964,8 +966,7 @@
             style.cellTableHoveredRowCell(), false);
         hoveringRow = null;
       } else if (isClick
-          && ((getPresenter().getKeyboardSelectedRowInView() != row)
-              || (keyboardSelectedColumn != col))) {
+          && ((getPresenter().getKeyboardSelectedRowInView() != row) || (keyboardSelectedColumn != col))) {
         // Move keyboard focus. Since the user clicked, allow focus to go to a
         // non-interactive column.
         boolean isFocusable = CellBasedWidgetImpl.get().isFocusable(target);
@@ -984,14 +985,17 @@
       boolean isSelectionHandled = handlesSelection
           || KeyboardSelectionPolicy.BOUND_TO_SELECTION == getKeyboardSelectionPolicy();
       T value = getVisibleItem(row);
+      Context context = new Context(row + getPageStart(), col,
+          getValueKey(value));
       CellPreviewEvent<T> previewEvent = CellPreviewEvent.fire(this, event,
-          this, row, col, value, cellIsEditing, isSelectionHandled);
+          this, context, value, cellIsEditing, isSelectionHandled);
       if (isClick && !cellIsEditing && !isSelectionHandled) {
         doSelection(event, value, row, col);
       }
 
+      // Pass the event to the cell.
       if (!previewEvent.isCanceled()) {
-        fireEventToCell(event, eventType, tableCell, value, row,
+        fireEventToCell(event, eventType, tableCell, value, context,
             columns.get(col));
       }
     }
@@ -1015,7 +1019,6 @@
     createHeadersAndFooters();
 
     int keyboardSelectedRow = getKeyboardSelectedRow() + getPageStart();
-    ProvidesKey<T> keyProvider = getKeyProvider();
     String evenRowStyle = style.cellTableEvenRow();
     String oddRowStyle = style.cellTableOddRow();
     String cellStyle = style.cellTableCell();
@@ -1075,7 +1078,8 @@
 
         SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();
         if (value != null) {
-          column.render(value, keyProvider, cellBuilder);
+          Context context = new Context(i, curColumn, getValueKey(value));
+          column.render(context, value, cellBuilder);
         }
 
         // Build the contents.
@@ -1132,7 +1136,7 @@
     int row = getKeyboardSelectedRow();
     if (isRowWithinBounds(row) && columns.size() > 0) {
       Column<T, ?> column = columns.get(keyboardSelectedColumn);
-      return resetFocusOnCellImpl(row, column);
+      return resetFocusOnCellImpl(row, keyboardSelectedColumn, column);
     }
     return false;
   }
@@ -1218,7 +1222,8 @@
           : style.cellTableFirstColumnHeader());
 
       // Loop through all column headers.
-      for (int curColumn = 1; curColumn < columnCount; curColumn++) {
+      int curColumn;
+      for (curColumn = 1; curColumn < columnCount; curColumn++) {
         Header<?> header = theHeaders.get(curColumn);
 
         if (header != prevHeader) {
@@ -1226,7 +1231,9 @@
           SafeHtmlBuilder headerBuilder = new SafeHtmlBuilder();
           if (prevHeader != null) {
             hasHeader = true;
-            prevHeader.render(headerBuilder);
+            Context context = new Context(0, curColumn - prevColspan,
+                prevHeader.getKey());
+            prevHeader.render(context, headerBuilder);
           }
           sb.append(template.th(prevColspan, classesBuilder.toString(),
               headerBuilder.toSafeHtml()));
@@ -1245,7 +1252,9 @@
       SafeHtmlBuilder headerBuilder = new SafeHtmlBuilder();
       if (prevHeader != null) {
         hasHeader = true;
-        prevHeader.render(headerBuilder);
+        Context context = new Context(0, curColumn - prevColspan,
+            prevHeader.getKey());
+        prevHeader.render(context, headerBuilder);
       }
 
       // The first and last columns could be the same column.
@@ -1348,17 +1357,15 @@
    * Fire an event to the Cell within the specified {@link TableCellElement}.
    */
   private <C> void fireEventToCell(Event event, String eventType,
-      TableCellElement tableCell, T value, int row, Column<T, C> column) {
+      TableCellElement tableCell, T value, Context context,
+      Column<T, C> column) {
     Cell<C> cell = column.getCell();
     if (cellConsumesEventType(cell, eventType)) {
       C cellValue = column.getValue(value);
-      ProvidesKey<T> providesKey = getKeyProvider();
-      Object key = getValueKey(value);
       Element parentElem = getCellParent(tableCell);
-      boolean cellWasEditing = cell.isEditing(parentElem, cellValue, key);
-      column.onBrowserEvent(parentElem, getPageStart() + row, value, event,
-          providesKey);
-      cellIsEditing = cell.isEditing(parentElem, cellValue, key);
+      boolean cellWasEditing = cell.isEditing(context, parentElem, cellValue);
+      column.onBrowserEvent(context, parentElem, value, event);
+      cellIsEditing = cell.isEditing(context, parentElem, cellValue);
       if (cellWasEditing && !cellIsEditing) {
         CellBasedWidgetImpl.get().resetFocus(new Scheduler.ScheduledCommand() {
           public void execute() {
@@ -1438,13 +1445,14 @@
     return consumedEvents != null && consumedEvents.size() > 0;
   }
 
-  private <C> boolean resetFocusOnCellImpl(int row, Column<T, C> column) {
+  private <C> boolean resetFocusOnCellImpl(int row, int col, Column<T, C> column) {
     Element parent = getKeyboardSelectedElement();
     T value = getVisibleItem(row);
     Object key = getValueKey(value);
     C cellValue = column.getValue(value);
     Cell<C> cell = column.getCell();
-    return cell.resetFocus(parent, cellValue, key);
+    Context context = new Context(row + getPageStart(), col, key);
+    return cell.resetFocus(context, parent, cellValue);
   }
 
   /**
@@ -1505,4 +1513,3 @@
     }
   }
 }
-
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 5598364..22c0938 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java
@@ -16,6 +16,7 @@
 package com.google.gwt.user.cellview.client;
 
 import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.dom.client.AnchorElement;
@@ -63,6 +64,7 @@
  *
  * @param <T> the type that this view contains
  */
+// TODO(jlabanca): Convert this to be the type of the child and create lazily.
 class CellTreeNodeView<T> extends UIObject {
 
   interface Template extends SafeHtmlTemplates {
@@ -138,7 +140,8 @@
         // Render the child nodes.
         ProvidesKey<C> keyProvider = nodeInfo.getProvidesKey();
         TreeViewModel model = nodeView.tree.getTreeViewModel();
-        for (C value : values) {
+        for (int i = start; i < end; i++) {
+          C value = values.get(i - start);
           Object key = keyProvider.getKey(value);
           boolean isOpen = openNodes.contains(key);
 
@@ -171,7 +174,8 @@
           }
           // Render cell contents
           SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();
-          cell.render(value, key, cellBuilder);
+          Context context = new Context(i, 0, key);
+          cell.render(context, value, cellBuilder);
 
           SafeHtml innerDiv = template.innerDiv(paddingDirection, imageWidth,
               innerClasses.toString(), image, itemValueStyle,
@@ -397,7 +401,6 @@
     }
 
     private final Cell<C> cell;
-
     private final int defaultPageSize;
     private HandlerManager handlerManger = new HandlerManager(this);
     private final NodeInfo<C> nodeInfo;
@@ -999,14 +1002,15 @@
     String eventType = event.getType();
     Element cellParent = getCellParent();
     Object key = getValueKey();
-    boolean cellWasEditing = parentCell.isEditing(cellParent, value, key);
+    Context context = new Context(getIndex(), 0, key);
+    boolean cellWasEditing = parentCell.isEditing(context, cellParent, value);
 
     // Update selection.
     boolean isSelectionHandled = parentCell.handlesSelection()
         || KeyboardSelectionPolicy.BOUND_TO_SELECTION == tree.getKeyboardSelectionPolicy();
     HasData<T> display = (HasData<T>) parentNode.listView;
     CellPreviewEvent<T> previewEvent = CellPreviewEvent.fire(display, event,
-        display, getIndex(), value, cellWasEditing, isSelectionHandled);
+        display, context, value, cellWasEditing, isSelectionHandled);
 
     // Forward the event to the cell.
     if (previewEvent.isCanceled()
@@ -1015,9 +1019,9 @@
     }
     Set<String> consumedEvents = parentCell.getConsumedEvents();
     if (consumedEvents != null && consumedEvents.contains(eventType)) {
-      parentCell.onBrowserEvent(cellParent, value, key, event,
+      parentCell.onBrowserEvent(context, cellParent, value, event,
           parentNodeInfo.getValueUpdater());
-      tree.cellIsEditing = parentCell.isEditing(cellParent, value, key);
+      tree.cellIsEditing = parentCell.isEditing(context, cellParent, value);
       if (cellWasEditing && !tree.cellIsEditing) {
         CellBasedWidgetImpl.get().resetFocus(new Scheduler.ScheduledCommand() {
           public void execute() {
@@ -1198,13 +1202,14 @@
 
   /**
    * Reset focus on this node.
-   *
+   * 
    * @return true of the cell takes focus, false if not
    */
   boolean resetFocusOnCell() {
     if (parentNodeInfo != null) {
+      Context context = new Context(getIndex(), 0, getValueKey());
       Cell<T> cell = parentNodeInfo.getCell();
-      return cell.resetFocus(getCellParent(), value, getValueKey());
+      return cell.resetFocus(context, getCellParent(), value);
     }
     return false;
   }
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 0ad4215..f74f5da 100644
--- a/user/src/com/google/gwt/user/cellview/client/Column.java
+++ b/user/src/com/google/gwt/user/cellview/client/Column.java
@@ -16,6 +16,7 @@
 package com.google.gwt.user.cellview.client;
 
 import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.cell.client.FieldUpdater;
 import com.google.gwt.cell.client.HasCell;
 import com.google.gwt.cell.client.ValueUpdater;
@@ -23,7 +24,6 @@
 import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
 import com.google.gwt.user.client.ui.HasAlignment;
-import com.google.gwt.view.client.ProvidesKey;
 
 /**
  * A representation of a column in a table. The column may maintain view data
@@ -93,35 +93,32 @@
   /**
    * Handle a browser event that took place within the column.
    * 
+   * @param context the cell context
    * @param elem the parent Element
-   * @param index the current row index of the object
    * @param object the base object to be updated
    * @param event the native browser event
-   * @param keyProvider an instance of ProvidesKey<T>, or null if the record
-   *          object should act as its own key.
    */
-  public void onBrowserEvent(Element elem, final int index, final T object,
-      NativeEvent event, ProvidesKey<T> keyProvider) {
-    Object key = getKey(object, keyProvider);
+  public void onBrowserEvent(Context context, Element elem, final T object,
+      NativeEvent event) {
+    final int index = context.getIndex();
     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);
+    cell.onBrowserEvent(context, elem, getValue(object), event, valueUpdater);
   }
 
   /**
    * Render the object into the cell.
    * 
+   * @param context the cell context
    * @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, SafeHtmlBuilder sb) {
-    Object key = getKey(object, keyProvider);
-    cell.render(getValue(object), key, sb);
+  public void render(Context context, T object, SafeHtmlBuilder sb) {
+    cell.render(context, getValue(object), sb);
   }
 
   /**
@@ -156,16 +153,4 @@
   public void setVerticalAlignment(VerticalAlignmentConstant align) {
     this.vAlign = align;
   }
-
-  /**
-   * Get the view key 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
-   */
-  private Object getKey(T object, ProvidesKey<T> keyProvider) {
-    return keyProvider == null ? object : keyProvider.getKey(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 3739fc3..c38ad35 100644
--- a/user/src/com/google/gwt/user/cellview/client/Header.java
+++ b/user/src/com/google/gwt/user/cellview/client/Header.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.user.cellview.client;
 
 import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.cell.client.ValueUpdater;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.NativeEvent;
@@ -23,7 +24,7 @@
 
 /**
  * A table column header or footer.
- *
+ * 
  * @param <H> the {@link Cell} type
  */
 public abstract class Header<H> {
@@ -43,7 +44,7 @@
 
   /**
    * Return the {@link Cell} responsible for rendering items in the header.
-   *
+   * 
    * @return the header Cell
    */
   public Cell<H> getCell() {
@@ -51,30 +52,41 @@
   }
 
   /**
+   * 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
+   */
+  public Object getKey() {
+    return getValue();
+  }
+
+  /**
    * Return the header value.
-   *
+   * 
    * @return the header value
    */
   public abstract H getValue();
 
   /**
    * Handle a browser event that took place within the header.
-   *
+   * 
+   * @param context the context of the header
    * @param elem the parent Element
    * @param event the native browser event
    */
-  public void onBrowserEvent(Element elem, NativeEvent event) {
-    H value = getValue();
-    cell.onBrowserEvent(elem, value, getKey(), event, updater);
+  public void onBrowserEvent(Context context, Element elem, NativeEvent event) {
+    cell.onBrowserEvent(context, elem, getValue(), event, updater);
   }
 
   /**
    * Render the header.
    * 
+   * @param context the context of the header
    * @param sb a {@link SafeHtmlBuilder} to render into
    */
-  public void render(SafeHtmlBuilder sb) {
-    cell.render(getValue(), getKey(), sb);
+  public void render(Context context, SafeHtmlBuilder sb) {
+    cell.render(context, getValue(), sb);
   }
 
   /**
@@ -85,14 +97,4 @@
   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/user/client/ui/ValuePicker.java b/user/src/com/google/gwt/user/client/ui/ValuePicker.java
index 7ec9259..45ced21 100644
--- a/user/src/com/google/gwt/user/client/ui/ValuePicker.java
+++ b/user/src/com/google/gwt/user/client/ui/ValuePicker.java
@@ -47,7 +47,7 @@
     }
 
     @Override
-    public void render(T value, Object viewData, SafeHtmlBuilder sb) {
+    public void render(Context context, T value, SafeHtmlBuilder sb) {
       sb.appendEscaped(renderer.render(value));
     }
   }
diff --git a/user/src/com/google/gwt/view/client/CellPreviewEvent.java b/user/src/com/google/gwt/view/client/CellPreviewEvent.java
index d2fcc06..aa486a2 100644
--- a/user/src/com/google/gwt/view/client/CellPreviewEvent.java
+++ b/user/src/com/google/gwt/view/client/CellPreviewEvent.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.view.client;
 
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.event.shared.EventHandler;
 import com.google.gwt.event.shared.GwtEvent;
@@ -55,39 +56,17 @@
    * @param source the source of the handlers
    * @param nativeEvent the event to preview
    * @param display the {@link HasData} source of the event
-   * @param index the index of the value where the event occurred
+   * @param context the Cell {@link Context}
    * @param value the value where the event occurred
    * @param isCellEditing indicates whether or not the cell is being edited
    * @param isSelectionHandled indicates whether or not selection is handled
    * @return the {@link CellPreviewEvent} that was fired
    */
   public static <T> CellPreviewEvent<T> fire(HasCellPreviewHandlers<T> source,
-      NativeEvent nativeEvent, HasData<T> display, int index, T value,
+      NativeEvent nativeEvent, HasData<T> display, Context context, T value,
       boolean isCellEditing, boolean isSelectionHandled) {
-    return fire(source, nativeEvent, display, index, 0, value, isCellEditing,
-        isSelectionHandled);
-  }
-
-  /**
-   * Fires a cell preview event on all registered handlers in the handler
-   * manager. If no such handlers exist, this implementation will do nothing.
-   * 
-   * @param <T> the old value type
-   * @param source the source of the handlers
-   * @param nativeEvent the event to preview
-   * @param display the {@link HasData} source of the event
-   * @param index the index of the value where the event occurred
-   * @param column the column index
-   * @param value the value where the event occurred
-   * @param isCellEditing indicates whether or not the cell is being edited
-   * @param isSelectionHandled indicates whether or not selection is handled
-   * @return the {@link CellPreviewEvent} that was fired
-   */
-  public static <T> CellPreviewEvent<T> fire(HasCellPreviewHandlers<T> source,
-      NativeEvent nativeEvent, HasData<T> display, int index, int column,
-      T value, boolean isCellEditing, boolean isSelectionHandled) {
     CellPreviewEvent<T> event = new CellPreviewEvent<T>(nativeEvent, display,
-        index, column, value, isCellEditing, isSelectionHandled);
+        context, value, isCellEditing, isSelectionHandled);
     if (TYPE != null) {
       source.fireEvent(event);
     }
@@ -106,9 +85,8 @@
     return TYPE;
   }
 
-  private final int column;
+  private final Context context;
   private final HasData<T> display;
-  private final int index;
   private boolean isCanceled = false;
   private final boolean isCellEditing;
   private final boolean isSelectionHandled;
@@ -120,18 +98,17 @@
    * 
    * @param nativeEvent the event to preview
    * @param display the {@link HasData} source of the event
-   * @param index the index of the value where the event occurred
+   * @param context the Cell {@link Context}
    * @param value the value where the event occurred
    * @param isCellEditing indicates whether or not the cell is being edited
    * @param isSelectionHandled indicates whether or not selection is handled
    */
   protected CellPreviewEvent(NativeEvent nativeEvent, HasData<T> display,
-      int index, int column, T value, boolean isCellEditing,
+      Context context, T value, boolean isCellEditing,
       boolean isSelectionHandled) {
     this.nativeEvent = nativeEvent;
     this.display = display;
-    this.index = index;
-    this.column = column;
+    this.context = context;
     this.value = value;
     this.isCellEditing = isCellEditing;
     this.isSelectionHandled = isSelectionHandled;
@@ -152,7 +129,16 @@
    * @return the column index, or 0 if there is only one column
    */
   public int getColumn() {
-    return column;
+    return context.getColumn();
+  }
+
+  /**
+   * Get the cell {@link Context}.
+   * 
+   * @return the cell {@link Context}
+   */
+  public Context getContext() {
+    return context;
   }
 
   /**
@@ -166,7 +152,7 @@
    * Get the index of the value where the event occurred.
    */
   public int getIndex() {
-    return index;
+    return context.getIndex();
   }
 
   /**
diff --git a/user/test/com/google/gwt/cell/client/AbstractCellTest.java b/user/test/com/google/gwt/cell/client/AbstractCellTest.java
index 1414369..5520e79 100644
--- a/user/test/com/google/gwt/cell/client/AbstractCellTest.java
+++ b/user/test/com/google/gwt/cell/client/AbstractCellTest.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.cell.client;
 
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 
@@ -27,7 +28,8 @@
     Cell<String> cell = createCell();
     String value = createCellValue();
     Element parent = Document.get().createDivElement();
-    cell.setValue(parent, value, null);
+    Context context = new Context(0, 0, null);
+    cell.setValue(context, parent, value);
     assertEquals(getExpectedInnerHtml(), parent.getInnerHTML());
   }
 
diff --git a/user/test/com/google/gwt/cell/client/ActionCellTest.java b/user/test/com/google/gwt/cell/client/ActionCellTest.java
index b8cdfa7..474375e 100644
--- a/user/test/com/google/gwt/cell/client/ActionCellTest.java
+++ b/user/test/com/google/gwt/cell/client/ActionCellTest.java
@@ -16,6 +16,7 @@
 package com.google.gwt.cell.client;
 
 import com.google.gwt.cell.client.ActionCell.Delegate;
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.NativeEvent;
@@ -49,7 +50,8 @@
     Element parent = Document.get().createDivElement();
     NativeEvent event = Document.get().createClickEvent(0, 0, 0, 0, 0, false,
         false, false, false);
-    cell.onBrowserEvent(parent, "test", DEFAULT_KEY, event, null);
+    Context context = new Context(0, 0, DEFAULT_KEY);
+    cell.onBrowserEvent(context, parent, "test", event, null);
     delegate.assertLastObject("test");
   }
 
diff --git a/user/test/com/google/gwt/cell/client/CellTestBase.java b/user/test/com/google/gwt/cell/client/CellTestBase.java
index cdbee13..733b1e5 100644
--- a/user/test/com/google/gwt/cell/client/CellTestBase.java
+++ b/user/test/com/google/gwt/cell/client/CellTestBase.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.cell.client;
 
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.NativeEvent;
@@ -41,7 +42,9 @@
   static class MockCell<T> extends AbstractCell<T> {
 
     private final boolean isSelectable;
+    private Context lastContext;
     private T lastEventValue;
+    private Element lastParentElement;
     private final T updateValue;
 
     public MockCell(boolean isSelectable, T updateValue,
@@ -55,19 +58,30 @@
       assertEquals(expected, lastEventValue);
     }
 
+    public void assertLastParentElement(Element expected) {
+      assertEquals(expected, lastParentElement);
+    }
+
+    
     @Override
     public boolean dependsOnSelection() {
       return isSelectable;
     }
 
+    public Context getLastContext() {
+      return lastContext;
+    }
+
     @Override
     public boolean handlesSelection() {
       return isSelectable;
     }
 
     @Override
-    public void onBrowserEvent(Element parent, T value, Object key,
+    public void onBrowserEvent(Context context, Element parent, T value,
         NativeEvent event, ValueUpdater<T> valueUpdater) {
+      lastContext = context;
+      lastParentElement = parent;
       lastEventValue = value;
       if (valueUpdater != null) {
         valueUpdater.update(updateValue);
@@ -75,7 +89,8 @@
     }
 
     @Override
-    public void render(T value, Object key, SafeHtmlBuilder sb) {
+    public void render(Context context, T value, SafeHtmlBuilder sb) {
+      lastContext = context;
       if (value != null) {
         sb.appendEscaped(String.valueOf(value));
       }
@@ -139,7 +154,20 @@
     Cell<T> cell = createCell();
     T value = createCellValue();
     SafeHtmlBuilder sb = new SafeHtmlBuilder();
-    cell.render(value, null, sb);
+    Context context = new Context(0, 0, null);
+    cell.render(context, value, sb);
+    assertEquals(getExpectedInnerHtml(), sb.toSafeHtml().asString());
+  }
+
+  /**
+   * Test rendering the cell with a negative index is handled.
+   */
+  public void testRenderNegativeIndex() {
+    Cell<T> cell = createCell();
+    T value = createCellValue();
+    SafeHtmlBuilder sb = new SafeHtmlBuilder();
+    Context context = new Context(-1, -1, null);
+    cell.render(context, value, sb);
     assertEquals(getExpectedInnerHtml(), sb.toSafeHtml().asString());
   }
 
@@ -149,7 +177,8 @@
   public void testRenderNull() {
     Cell<T> cell = createCell();
     SafeHtmlBuilder sb = new SafeHtmlBuilder();
-    cell.render(null, null, sb);
+    Context context = new Context(0, 0, null);
+    cell.render(context, null, sb);
     assertEquals(getExpectedInnerHtmlNull(), sb.toSafeHtml().asString());
   }
 
@@ -225,7 +254,8 @@
       public void onBrowserEvent(Event event) {
         try {
           DOM.setEventListener(parent, null);
-          createCell().onBrowserEvent(parent, value, DEFAULT_KEY, event,
+          Context context = new Context(0, 0, DEFAULT_KEY);
+          createCell().onBrowserEvent(context, parent, value, event,
               valueUpdater);
           parent.removeFromParent();
         } catch (Exception e) {
diff --git a/user/test/com/google/gwt/cell/client/CompositeCellTest.java b/user/test/com/google/gwt/cell/client/CompositeCellTest.java
index a56e6ef..a40461c 100644
--- a/user/test/com/google/gwt/cell/client/CompositeCellTest.java
+++ b/user/test/com/google/gwt/cell/client/CompositeCellTest.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.cell.client;
 
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.NativeEvent;
@@ -109,7 +110,8 @@
     // Add an event listener.
     EventListener listener = new EventListener() {
       public void onBrowserEvent(Event event) {
-        cell.onBrowserEvent(parent, "test", DEFAULT_KEY, event, null);
+        Context context = new Context(3, 4, "key");
+        cell.onBrowserEvent(context, parent, "test", event, null);
       }
     };
     DOM.sinkEvents(parent, Event.ONCLICK);
@@ -120,6 +122,11 @@
         false, false, false);
     Element.as(parent.getChild(1)).dispatchEvent(event);
     innerCell.assertLastEventValue("test-1");
+    innerCell.assertLastParentElement(Element.as(parent.getChild(1)));
+    Context innerContext = innerCell.getLastContext();
+    assertEquals("key", innerContext.getKey());
+    assertEquals(3, innerContext.getIndex());
+    assertEquals(4, innerContext.getColumn());
 
     // Remove the element and event listener.
     DOM.setEventListener(parent, null);
@@ -130,7 +137,8 @@
     Cell<String> cell = createCell();
     Element parent = Document.get().createDivElement();
     parent.setInnerHTML(getExpectedInnerHtml());
-    cell.setValue(parent, "test", null);
+    Context context = new Context( 0, 0, null);
+    cell.setValue(context, parent, "test");
 
     assertEquals(3, parent.getChildCount());
     assertEquals("test-0", Element.as(parent.getChild(0)).getInnerHTML());
diff --git a/user/test/com/google/gwt/cell/client/EditTextCellTest.java b/user/test/com/google/gwt/cell/client/EditTextCellTest.java
index 8925a5d..c088c71 100644
--- a/user/test/com/google/gwt/cell/client/EditTextCellTest.java
+++ b/user/test/com/google/gwt/cell/client/EditTextCellTest.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.cell.client;
 
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.cell.client.EditTextCell.ViewData;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
@@ -35,7 +36,8 @@
     ViewData viewData = new ViewData("originalValue");
     viewData.setText("newValue");
     cell.setViewData(DEFAULT_KEY, viewData);
-    cell.edit(parent, "originalValue", DEFAULT_KEY);
+    Context context = new Context(0, 0, DEFAULT_KEY);
+    cell.edit(context, parent, "originalValue");
 
     // Verify the input element.
     Element child = parent.getFirstChildElement();
@@ -130,7 +132,8 @@
     viewData.setEditing(false);
     cell.setViewData(DEFAULT_KEY, viewData);
     SafeHtmlBuilder sb = new SafeHtmlBuilder();
-    cell.render("originalValue", DEFAULT_KEY, sb);
+    Context context = new Context(0, 0, DEFAULT_KEY);
+    cell.render(context, "originalValue", sb);
     assertEquals("newValue", sb.toSafeHtml().asString());
   }
 
diff --git a/user/test/com/google/gwt/cell/client/EditableCellTestBase.java b/user/test/com/google/gwt/cell/client/EditableCellTestBase.java
index 1eddda7..f1c6230 100644
--- a/user/test/com/google/gwt/cell/client/EditableCellTestBase.java
+++ b/user/test/com/google/gwt/cell/client/EditableCellTestBase.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.cell.client;
 
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.NativeEvent;
@@ -39,7 +40,8 @@
     T value = createCellValue();
     cell.setViewData(DEFAULT_KEY, createCellViewData());
     SafeHtmlBuilder sb = new SafeHtmlBuilder();
-    cell.render(value, DEFAULT_KEY, sb);
+    Context context = new Context(0, 0, DEFAULT_KEY);
+    cell.render(context, value, sb);
     String expectedInnerHtmlViewData = getExpectedInnerHtmlViewData();
     String asString = sb.toSafeHtml().asString();
     assertEquals(expectedInnerHtmlViewData, asString);
@@ -96,7 +98,8 @@
       public void onBrowserEvent(Event event) {
         try {
           DOM.setEventListener(parent, null);
-          cell.onBrowserEvent(parent, value, DEFAULT_KEY, event, valueUpdater);
+          Context context = new Context(0, 0, DEFAULT_KEY);
+          cell.onBrowserEvent(context, parent, value, event, valueUpdater);
           parent.removeFromParent();
         } catch (Exception e) {
           // We are in an event loop, so events may not propagate out to JUnit.
diff --git a/user/test/com/google/gwt/cell/client/IconCellDecoratorTest.java b/user/test/com/google/gwt/cell/client/IconCellDecoratorTest.java
index 79c656a..054b751 100644
--- a/user/test/com/google/gwt/cell/client/IconCellDecoratorTest.java
+++ b/user/test/com/google/gwt/cell/client/IconCellDecoratorTest.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.cell.client;
 
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
@@ -62,7 +63,8 @@
 
     // Render the cell.
     SafeHtmlBuilder sb = new SafeHtmlBuilder();
-    cell.render("helloworld", null, sb);
+    Context context = new Context(0, 0, null);
+    cell.render(context, "helloworld", sb);
 
     // Compare the expected render string.
     String expected = "<div style=\"position:relative;padding-left:64px;\">";
@@ -88,7 +90,8 @@
     parent.setInnerHTML(getExpectedInnerHtml());
     assertEquals("helloworld",
         Element.as(parent.getFirstChildElement().getChild(1)).getInnerHTML());
-    cell.setValue(parent, "test", null);
+    Context context = new Context(0, 0, null);
+    cell.setValue(context, parent, "test");
     assertEquals("test",
         Element.as(parent.getFirstChildElement().getChild(1)).getInnerHTML());
   }
diff --git a/user/test/com/google/gwt/cell/client/ImageLoadingCellTest.java b/user/test/com/google/gwt/cell/client/ImageLoadingCellTest.java
index 8d0d606..87d7beb 100644
--- a/user/test/com/google/gwt/cell/client/ImageLoadingCellTest.java
+++ b/user/test/com/google/gwt/cell/client/ImageLoadingCellTest.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.cell.client;
 
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.ImageElement;
@@ -30,7 +31,8 @@
     Cell<String> cell = createCell();
     String value = createCellValue();
     SafeHtmlBuilder sb = new SafeHtmlBuilder();
-    cell.render(value, null, sb);
+    Context context = new Context(0, 0, null);
+    cell.render(context, value, sb);
 
     // Render the html.
     Element elem = Document.get().createDivElement();
@@ -45,6 +47,26 @@
   }
 
   @Override
+  public void testRenderNegativeIndex() {
+    Cell<String> cell = createCell();
+    String value = createCellValue();
+    SafeHtmlBuilder sb = new SafeHtmlBuilder();
+    Context context = new Context(-1, -1, null);
+    cell.render(context, value, sb);
+ 
+    // Render the html.
+    Element elem = Document.get().createDivElement();
+    elem.setInnerHTML(sb.toSafeHtml().asString());
+
+    // Verify the image.
+    assertEquals(2, elem.getChildCount());
+    Element imgWrapper = elem.getChild(1).cast();
+    ImageElement img = imgWrapper.getFirstChildElement().cast();
+    assertEquals("img", img.getTagName().toLowerCase());
+    assertTrue(img.getSrc().toLowerCase().endsWith("test.png"));
+  }
+
+  @Override
   protected Cell<String> createCell() {
     return new ImageLoadingCell();
   }
diff --git a/user/test/com/google/gwt/user/cellview/client/AbstractCellTreeTestBase.java b/user/test/com/google/gwt/user/cellview/client/AbstractCellTreeTestBase.java
index 8dbc539..574c596 100644
--- a/user/test/com/google/gwt/user/cellview/client/AbstractCellTreeTestBase.java
+++ b/user/test/com/google/gwt/user/cellview/client/AbstractCellTreeTestBase.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.user.cellview.client;
 
+import com.google.gwt.user.cellview.client.AbstractHasDataTestBase.IndexCell;
 import com.google.gwt.cell.client.Cell;
 import com.google.gwt.cell.client.TextCell;
 import com.google.gwt.core.client.Scheduler;
@@ -56,8 +57,7 @@
     /**
      * The root data provider.
      */
-    private final ListDataProvider<String> rootDataProvider =
-        createDataProvider("");
+    private final ListDataProvider<String> rootDataProvider = createDataProvider("");
 
     public <T> NodeInfo<?> getNodeInfo(T value) {
       if (value == ROOT_VALUE) {
@@ -93,7 +93,7 @@
 
     /**
      * Create a data provider that extends the prefix by one letter.
-     *
+     * 
      * @param prefix the prefix string
      * @return a data provider
      */
@@ -163,7 +163,7 @@
 
   /**
    * Construct a new {@link AbstractCellTreeTestBase}.
-   *
+   * 
    * @param singlePathOnly true if the tree only supports a single open path
    */
   public AbstractCellTreeTestBase(boolean singlePathOnly) {
@@ -199,14 +199,16 @@
   public void testRenderWithKeyProvider() {
     // Create a cell that verifies the render args.
     final List<String> rendered = new ArrayList<String>();
-    final Cell<String> cell = new TextCell() {
+    final IndexCell<String> cell = new IndexCell<String>() {
       @Override
-      public void render(String data, Object key, SafeHtmlBuilder sb) {
-        int call = rendered.size(); 
+      public void render(Context context, String data, SafeHtmlBuilder sb) {
+        super.render(context, data, sb);
+        int call = rendered.size();
         rendered.add(data);
         assertTrue("render() called more than thrice", rendered.size() < 4);
 
         assertEquals(call + "value", data);
+        Object key = context.getKey();
         assertTrue(key instanceof Integer);
         assertEquals(call, key);
       }
@@ -241,11 +243,12 @@
       public void execute() {
         assertEquals("Cell#render() should be called exactly thrice", 3,
             rendered.size());
+        cell.assertLastRenderIndex(2);
         finishTest();
       }
     });
   }
-  
+
   /**
    * Test that opening a sibling node works.
    */
@@ -565,7 +568,7 @@
 
   /**
    * Create an {@link AbstractCellTree} to test.
-   *
+   * 
    * @param <T> the data type of the root value
    * @param model the {@link TreeViewModel} that backs the tree
    * @param rootValue the root value
@@ -588,7 +591,7 @@
 
   /**
    * Test the state of a {@link TreeNode}.
-   *
+   * 
    * @param node the node to test
    * @param parent the expected parent
    * @param index the expected index within the parent
diff --git a/user/test/com/google/gwt/user/cellview/client/AbstractHasDataTestBase.java b/user/test/com/google/gwt/user/cellview/client/AbstractHasDataTestBase.java
index e3427bf..d56a3f5 100644
--- a/user/test/com/google/gwt/user/cellview/client/AbstractHasDataTestBase.java
+++ b/user/test/com/google/gwt/user/cellview/client/AbstractHasDataTestBase.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,9 +15,16 @@
  */
 package com.google.gwt.user.cellview.client;
 
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.TextCell;
+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.junit.client.GWTTestCase;
 import com.google.gwt.regexp.shared.MatchResult;
 import com.google.gwt.regexp.shared.RegExp;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.view.client.ListDataProvider;
 import com.google.gwt.view.client.Range;
@@ -30,13 +37,69 @@
  */
 public abstract class AbstractHasDataTestBase extends GWTTestCase {
 
+  /**
+   * A mock cell that tests the index specified in each method.
+   * 
+   * @param <C> the cell type
+   */
+  protected static class IndexCell<C> extends AbstractCell<C> {
+    private int lastBrowserEventIndex = -1;
+    private int lastEditingIndex = -1;
+    private int lastRenderIndex = -1;
+    private int lastResetFocusIndex = -1;
+
+    public IndexCell(String... consumedEvents) {
+      super(consumedEvents);
+    }
+
+    public void assertLastBrowserEventIndex(int expected) {
+      assertEquals(expected, lastBrowserEventIndex);
+    }
+
+    public void assertLastEditingIndex(int expected) {
+      assertEquals(expected, lastEditingIndex);
+    }
+
+    public void assertLastRenderIndex(int expected) {
+      assertEquals(expected, lastRenderIndex);
+    }
+
+    public void assertLastResetFocusIndex(int expected) {
+      assertEquals(expected, lastResetFocusIndex);
+    }
+
+    @Override
+    public boolean isEditing(Context context, Element parent, C value) {
+      this.lastEditingIndex = context.getIndex();
+      return false;
+    }
+
+    @Override
+    public void onBrowserEvent(Context context, Element parent, C value,
+        NativeEvent event, ValueUpdater<C> valueUpdater) {
+      this.lastBrowserEventIndex = context.getIndex();
+    }
+
+    @Override
+    public void render(Context context, C value, SafeHtmlBuilder sb) {
+      this.lastRenderIndex = context.getIndex();
+      sb.appendEscaped("index " + this.lastRenderIndex);
+    }
+
+    @Override
+    public boolean resetFocus(Context context, Element parent, C value) {
+      this.lastResetFocusIndex = context.getIndex();
+      return false;
+    }
+  }
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.user.cellview.CellView";
   }
 
   public void testGetVisibleItem() {
-    AbstractHasData<String> display = createAbstractHasData();
+    AbstractHasData<String> display = createAbstractHasData(new TextCell());
     ListDataProvider<String> provider = new ListDataProvider<String>(
         createData(0, 13));
     provider.addDataDisplay(display);
@@ -65,7 +128,7 @@
   }
 
   public void testGetVisibleItems() {
-    AbstractHasData<String> display = createAbstractHasData();
+    AbstractHasData<String> display = createAbstractHasData(new TextCell());
     ListDataProvider<String> provider = new ListDataProvider<String>();
     provider.addDataDisplay(display);
     display.setVisibleRange(10, 3);
@@ -82,8 +145,21 @@
     assertEquals("test 12", items.get(2));
   }
 
+  public void testResetFocus() {
+    IndexCell<String> cell = new IndexCell<String>();
+    AbstractHasData<String> display = createAbstractHasData(cell);
+    display.setRowData(createData(0, 10));
+    display.getPresenter().flush();
+
+    cell.assertLastResetFocusIndex(-1);
+    display.getPresenter().setKeyboardSelectedRow(5, false, false);
+    display.resetFocusOnCell();
+    cell.assertLastResetFocusIndex(5);
+  }
+
   public void testSetRowData() {
-    AbstractHasData<String> display = createAbstractHasData();
+    IndexCell<String> cell = new IndexCell<String>();
+    AbstractHasData<String> display = createAbstractHasData(cell);
 
     // Set exact data.
     List<String> values = createData(0, 62);
@@ -110,6 +186,13 @@
     assertTrue(display.isRowCountExact());
     assertEquals(values, display.getVisibleItems());
     assertEquals(new Range(0, 62), display.getVisibleRange());
+    display.getPresenter().flush();
+
+    // Render one row and verify the index.
+    display.setRowData(5, createData(100, 1));
+    display.getPresenter().flush();
+    assertEquals("test 100", display.getVisibleItem(5));
+    cell.assertLastRenderIndex(5);
   }
 
   public void testSetTabIndex() {
@@ -123,7 +206,7 @@
       }
     }
 
-    AbstractHasData<String> display = createAbstractHasData();
+    AbstractHasData<String> display = createAbstractHasData(new TextCell());
     ListDataProvider<String> provider = new ListDataProvider<String>(
         createData(0, 10));
     provider.addDataDisplay(display);
@@ -147,14 +230,16 @@
 
   /**
    * Create an {@link AbstractHasData} to test.
-   *
+   * 
+   * @param cell the cell to use
    * @return the widget to test
    */
-  protected abstract AbstractHasData<String> createAbstractHasData();
+  protected abstract AbstractHasData<String> createAbstractHasData(
+      Cell<String> cell);
 
   /**
    * Create a list of data for testing.
-   *
+   * 
    * @param start the start index
    * @param length the length
    * @return a list of data
diff --git a/user/test/com/google/gwt/user/cellview/client/CellListTest.java b/user/test/com/google/gwt/user/cellview/client/CellListTest.java
index de16617..cc42e22 100644
--- a/user/test/com/google/gwt/user/cellview/client/CellListTest.java
+++ b/user/test/com/google/gwt/user/cellview/client/CellListTest.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,7 +17,11 @@
 
 import com.google.gwt.cell.client.Cell;
 import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.user.client.ui.RootPanel;
 import com.google.gwt.view.client.ProvidesKey;
 
 import java.util.ArrayList;
@@ -29,13 +33,30 @@
 public class CellListTest extends AbstractHasDataTestBase {
 
   public void testGetRowElement() {
-    CellList<String> list = createAbstractHasData();
+    CellList<String> list = createAbstractHasData(new TextCell());
     list.setRowData(0, createData(0, 10));
 
     // Ensure that calling getRowElement() flushes all pending changes.
     assertNotNull(list.getRowElement(9));
   }
 
+  public void testCellEvent() {
+    IndexCell<String> cell = new IndexCell<String>("click");
+    CellList<String> list = createAbstractHasData(cell);
+    RootPanel.get().add(list);
+    list.setRowData(createData(0, 10));
+    list.getPresenter().flush();
+
+    // Trigger an event at index 5.
+    NativeEvent event = Document.get().createClickEvent(0, 0, 0, 0, 0, false,
+        false, false, false);
+    list.getRowElement(5).dispatchEvent(event);
+    cell.assertLastBrowserEventIndex(5);
+    cell.assertLastEditingIndex(5);
+
+    RootPanel.get().remove(list);
+  }
+
   /**
    * Test that the correct values are sent to the Cell to be rendered.
    */
@@ -44,12 +65,13 @@
     final List<String> rendered = new ArrayList<String>();
     final Cell<String> cell = new TextCell() {
       @Override
-      public void render(String data, Object key, SafeHtmlBuilder sb) {
+      public void render(Context context, SafeHtml data, SafeHtmlBuilder sb) {
         int call = rendered.size();
-        rendered.add(data);
+        rendered.add(data.asString());
         assertTrue("render() called more than ten times", rendered.size() < 11);
 
-        assertEquals("test " + call, data);
+        Object key = context.getKey();
+        assertEquals("test " + call, data.asString());
         assertTrue(key instanceof Integer);
         assertEquals(call, key);
       }
@@ -68,7 +90,7 @@
   }
 
   @Override
-  protected CellList<String> createAbstractHasData() {
-    return new CellList<String>(new TextCell());
+  protected CellList<String> createAbstractHasData(Cell<String> cell) {
+    return new CellList<String>(cell);
   }
 }
diff --git a/user/test/com/google/gwt/user/cellview/client/CellTableTest.java b/user/test/com/google/gwt/user/cellview/client/CellTableTest.java
index d47d9c4..535bcd8 100644
--- a/user/test/com/google/gwt/user/cellview/client/CellTableTest.java
+++ b/user/test/com/google/gwt/user/cellview/client/CellTableTest.java
@@ -15,8 +15,11 @@
  */
 package com.google.gwt.user.cellview.client;
 
+import com.google.gwt.cell.client.Cell;
 import com.google.gwt.cell.client.TextCell;
 import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.dom.client.TableCellElement;
 import com.google.gwt.dom.client.TableElement;
 import com.google.gwt.dom.client.TableRowElement;
@@ -26,6 +29,7 @@
 import com.google.gwt.user.cellview.client.CellTable.Style;
 import com.google.gwt.user.client.ui.HasHorizontalAlignment;
 import com.google.gwt.user.client.ui.HasVerticalAlignment;
+import com.google.gwt.user.client.ui.RootPanel;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -64,7 +68,7 @@
   }
 
   public void testCellAlignment() {
-    CellTable<String> table = createAbstractHasData();
+    CellTable<String> table = createAbstractHasData(new TextCell());
     Column<String, String> column = new Column<String, String>(new TextCell()) {
       @Override
       public String getValue(String object) {
@@ -117,8 +121,25 @@
     assertTrue("bottom".equals(vAlign));
   }
 
+  public void testCellEvent() {
+    IndexCell<String> cell = new IndexCell<String>("click");
+    CellTable<String> table = createAbstractHasData(cell);
+    RootPanel.get().add(table);
+    table.setRowData(createData(0, 10));
+    table.getPresenter().flush();
+
+    // Trigger an event at index 5.
+    NativeEvent event = Document.get().createClickEvent(0, 0, 0, 0, 0, false,
+        false, false, false);
+    table.getRowElement(5).getCells().getItem(0).dispatchEvent(event);
+    cell.assertLastBrowserEventIndex(5);
+    cell.assertLastEditingIndex(5);
+
+    RootPanel.get().remove(table);
+  }
+
   public void testGetRowElement() {
-    CellTable<String> table = createAbstractHasData();
+    CellTable<String> table = createAbstractHasData(new TextCell());
     table.setRowData(0, createData(0, 10));
 
     // Ensure that calling getRowElement() flushes all pending changes.
@@ -238,9 +259,9 @@
   }
 
   @Override
-  protected CellTable<String> createAbstractHasData() {
+  protected CellTable<String> createAbstractHasData(Cell<String> cell) {
     CellTable<String> table = new CellTable<String>();
-    table.addColumn(new Column<String, String>(new TextCell()) {
+    table.addColumn(new Column<String, String>(cell) {
       @Override
       public String getValue(String object) {
         return object;
diff --git a/user/test/com/google/gwt/user/cellview/client/ColumnTest.java b/user/test/com/google/gwt/user/cellview/client/ColumnTest.java
index c96a0a7..6190c90 100644
--- a/user/test/com/google/gwt/user/cellview/client/ColumnTest.java
+++ b/user/test/com/google/gwt/user/cellview/client/ColumnTest.java
@@ -19,6 +19,7 @@
 import com.google.gwt.cell.client.FieldUpdater;
 import com.google.gwt.cell.client.TextCell;
 import com.google.gwt.cell.client.ValueUpdater;
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.NativeEvent;
@@ -38,12 +39,12 @@
       AbstractEditableCell<String, String> {
 
     @Override
-    public boolean isEditing(Element parent, String value, Object key) {
+    public boolean isEditing(Context context, Element parent, String value) {
       return false;
     }
 
     @Override
-    public void render(String value, Object key, SafeHtmlBuilder sb) {
+    public void render(Context context, String value, SafeHtmlBuilder sb) {
       sb.appendEscaped(value);
     }
   }
@@ -101,7 +102,7 @@
         false, false, false, false);
     final MockEditableCell cell = new MockEditableCell() {
       @Override
-      public void onBrowserEvent(Element parent, String value, Object key,
+      public void onBrowserEvent(Context context, Element parent, String value,
           NativeEvent event, final ValueUpdater<String> valueUpdater) {
         setViewData("test", "newViewData");
         new Timer() {
@@ -126,7 +127,8 @@
     // Fire the event to the cell.
     delayTestFinish(5000);
     cell.setViewData("test", "oldViewData");
-    column.onBrowserEvent(theElem, 3, "test", theEvent, null);
+    Context context = new Context(3, 0, null);
+    column.onBrowserEvent(context, theElem, "test", theEvent);
   }
 
   public void testGetCell() {
@@ -141,7 +143,7 @@
         false, false, false, false);
     final MockEditableCell cell = new MockEditableCell() {
       @Override
-      public void onBrowserEvent(Element parent, String value, Object key,
+      public void onBrowserEvent(Context context, Element parent, String value,
           NativeEvent event, ValueUpdater<String> valueUpdater) {
         assertEquals(theElem, parent);
         assertEquals("test", value);
@@ -164,7 +166,8 @@
     column.setFieldUpdater(fieldUpdater);
 
     cell.setViewData("test", "oldViewData");
-    column.onBrowserEvent(theElem, 3, "test", theEvent, null);
+    Context context = new Context(3, 0, null);
+    column.onBrowserEvent(context, theElem, "test", theEvent);
 
     fieldUpdater.assertUpdateCalled(true);
     fieldUpdater.assertIndex(3);
@@ -178,7 +181,7 @@
         false, false, false, false);
     final MockEditableCell cell = new MockEditableCell() {
       @Override
-      public void onBrowserEvent(Element parent, String value, Object key,
+      public void onBrowserEvent(Context context, Element parent, String value,
           NativeEvent event, ValueUpdater<String> valueUpdater) {
         assertEquals(theElem, parent);
         assertEquals("test", value);
@@ -191,7 +194,8 @@
     Column<String, String> column = new IdentityColumn<String>(cell);
 
     cell.setViewData("test", "oldViewData");
-    column.onBrowserEvent(theElem, 3, "test", theEvent, null);
+    Context context = new Context(3, 0, null);
+    column.onBrowserEvent(context, theElem, "test", theEvent);
   }
 
   public void testRender() {
@@ -199,7 +203,8 @@
     Column<String, String> column = new IdentityColumn<String>(cell);
 
     SafeHtmlBuilder sb = new SafeHtmlBuilder();
-    column.render("test", null, sb);
+    Context context = new Context(0, 0, null);
+    column.render(context, "test", sb);
     assertEquals("test", sb.toSafeHtml().asString());
   }
 }
diff --git a/user/test/com/google/gwt/view/client/DefaultSelectionEventManagerTest.java b/user/test/com/google/gwt/view/client/DefaultSelectionEventManagerTest.java
index 7ab159c..c1cec44 100644
--- a/user/test/com/google/gwt/view/client/DefaultSelectionEventManagerTest.java
+++ b/user/test/com/google/gwt/view/client/DefaultSelectionEventManagerTest.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.view.client;
 
+import com.google.gwt.cell.client.Cell.Context;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.junit.client.GWTTestCase;
@@ -215,7 +216,7 @@
     NativeEvent nativeEvent = Document.get().createClickEvent(0, 0, 0, 0, 0,
         false, false, false, false);
     CellPreviewEvent<String> event = new CellPreviewEvent<String>(nativeEvent,
-        display, 1, 0, "test 1", false, false);
+        display, new Context(1, 0, null), "test 1", false, false);
     manager.handleSelectionEvent(event, null, model);
     assertEquals("test 1", model.getSelectedObject());
 
@@ -226,16 +227,16 @@
     // Ctrl+Select the same value.
     nativeEvent = Document.get().createClickEvent(0, 0, 0, 0, 0, true, false,
         false, true);
-    event = new CellPreviewEvent<String>(nativeEvent, display, 1, 0, "test 1",
-        false, false);
+    event = new CellPreviewEvent<String>(nativeEvent, display, new Context(1,
+        0, null), "test 1", false, false);
     manager.handleSelectionEvent(event, null, model);
     assertNull(model.getSelectedObject());
 
     // Spacebar a different value.
     nativeEvent = Document.get().createKeyUpEvent(false, false, false, false,
         32);
-    event = new CellPreviewEvent<String>(nativeEvent, display, 2, 0, "test 2",
-        false, false);
+    event = new CellPreviewEvent<String>(nativeEvent, display, new Context(2,
+        0, null), "test 2", false, false);
     manager.handleSelectionEvent(event, null, model);
     assertEquals("test 2", model.getSelectedObject());
 
@@ -253,13 +254,13 @@
     NativeEvent nativeEvent = Document.get().createClickEvent(0, 0, 0, 0, 0,
         false, false, false, false);
     CellPreviewEvent<String> event = new CellPreviewEvent<String>(nativeEvent,
-        display, 1, 0, "test 1", false, false);
+        display, new Context(1, 0, null), "test 1", false, false);
     manager.handleSelectionEvent(event, SelectAction.DESELECT, model);
     assertEquals("test 0", model.getSelectedObject());
 
     // Deselect the same value.
-    event = new CellPreviewEvent<String>(nativeEvent, display, 0, 0, "test 0",
-        false, false);
+    event = new CellPreviewEvent<String>(nativeEvent, display, new Context(0,
+        0, null), "test 0", false, false);
     manager.handleSelectionEvent(event, SelectAction.DESELECT, model);
     assertNull(model.getSelectedObject());
   }
@@ -272,7 +273,7 @@
     NativeEvent nativeEvent = Document.get().createClickEvent(0, 0, 0, 0, 0,
         false, false, false, false);
     CellPreviewEvent<String> event = new CellPreviewEvent<String>(nativeEvent,
-        display, 3, 0, "test 3", false, false);
+        display, new Context(3, 0, null), "test 3", false, false);
     manager.handleSelectionEvent(event, SelectAction.IGNORE, model);
     assertEquals("test 0", model.getSelectedObject());
   }
@@ -286,13 +287,13 @@
     NativeEvent nativeEvent = Document.get().createClickEvent(0, 0, 0, 0, 0,
         false, false, false, false);
     CellPreviewEvent<String> event = new CellPreviewEvent<String>(nativeEvent,
-        display, 0, 0, "test 0", false, false);
+        display, new Context(0, 0, null), "test 0", false, false);
     manager.handleSelectionEvent(event, SelectAction.SELECT, model);
     assertEquals("test 0", model.getSelectedObject());
 
     // Select a different value.
-    event = new CellPreviewEvent<String>(nativeEvent, display, 1, 0, "test 1",
-        false, false);
+    event = new CellPreviewEvent<String>(nativeEvent, display, new Context(1,
+        0, null), "test 1", false, false);
     manager.handleSelectionEvent(event, SelectAction.SELECT, model);
     assertEquals("test 1", model.getSelectedObject());
   }
@@ -306,7 +307,7 @@
     NativeEvent nativeEvent = Document.get().createClickEvent(0, 0, 0, 0, 0,
         false, false, false, false);
     CellPreviewEvent<String> event = new CellPreviewEvent<String>(nativeEvent,
-        display, 1, 0, "test 1", false, false);
+        display, new Context(1, 0, null), "test 1", false, false);
     manager.handleSelectionEvent(event, SelectAction.TOGGLE, model);
     assertEquals("test 1", model.getSelectedObject());