Merging from the 2.1 I/O branch through r7982.

Review by: mmendez@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8219 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/bikeshed/eclipse.README b/bikeshed/eclipse.README
index 5425a63..a36dd98 100644
--- a/bikeshed/eclipse.README
+++ b/bikeshed/eclipse.README
@@ -31,8 +31,10 @@
   * Google > App Engine > Use Google App Engine
   * Google > App Engine > ORM
     * Remove src and test
-    * Add server and shared from src/com/google/gwt/sample/bikeshed/stocks
-    * Add com/google/gwt/sample/expenses/server/domain
+    * Add 
+      * src/com/google/gwt/sample/bikeshed/stocks/server
+      * src/com/google/gwt/sample/bikeshed/stocks/shared
+      * src/com/google/gwt/sample/expenses/server/domain
   * Java Build Path > Libraries > Add Variable > GWT_TOOLS, Extend > redist/json/r2_20080312/json.jar
 * Copy tools/redist/json/r2_20080312/json.jar to bikeshed/war/WEB_INF/lib
 * Right click on the bikeshed project and choose Run as > Web Application. Choose from the various .html files
diff --git a/bikeshed/src/com/google/gwt/app/App.gwt.xml b/bikeshed/src/com/google/gwt/app/App.gwt.xml
index b9337b7..f553b63 100644
--- a/bikeshed/src/com/google/gwt/app/App.gwt.xml
+++ b/bikeshed/src/com/google/gwt/app/App.gwt.xml
@@ -5,6 +5,7 @@
   <inherits name='com.google.gwt.user.User'/>
   <inherits name='com.google.gwt.valuestore.ValueStore'/>
 
+  <source path="misc"/>
   <source path="place"/>
   <source path="client"/>
 </module>
\ No newline at end of file
diff --git a/bikeshed/src/com/google/gwt/app/client/ListBoxPlacePickerView.java b/bikeshed/src/com/google/gwt/app/client/ListBoxPlacePickerView.java
index a1d1d21..204d0ea 100644
--- a/bikeshed/src/com/google/gwt/app/client/ListBoxPlacePickerView.java
+++ b/bikeshed/src/com/google/gwt/app/client/ListBoxPlacePickerView.java
@@ -33,6 +33,13 @@
   private HandlerRegistration handlerRegistration;
 
   /**
+   * @return this view
+   */
+  public ListBoxPlacePickerView<P> asWidget() {
+    return this;
+  }
+  
+  /**
    * Set the listener.
    */
   public void setListener(final PlacePickerView.Listener<P> listener) {
diff --git a/bikeshed/src/com/google/gwt/app/place/AbstractActivity.java b/bikeshed/src/com/google/gwt/app/place/AbstractActivity.java
new file mode 100644
index 0000000..2d9e5c7
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/place/AbstractActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.app.place;
+
+/**
+ * Simple Activity implementation that is always willing to stop,
+ * and does nothing onStop and onCancel
+ */
+public abstract class AbstractActivity implements Activity {
+
+  public void onCancel() {
+  }
+
+  public void onStop() {
+  }
+
+  public boolean willStop() {
+    return true;
+  }
+
+}
diff --git a/bikeshed/src/com/google/gwt/app/place/Activity.java b/bikeshed/src/com/google/gwt/app/place/Activity.java
new file mode 100644
index 0000000..4f171bc
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/place/Activity.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.app.place;
+
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Implemented by objects that control a piece of user interface,
+ * with a life cycle managed by an {@link ActivityManager}, in 
+ * response to {@link PlaceChangeEvent} events as the user
+ * navigates through the app. 
+ */
+public interface Activity {
+
+  /**
+   * Callback object used for asynchronous {@link Activity#start} requests,
+   * provides the widget this activity drives.
+   */
+  public interface Callback {
+    void onStarted(Widget widget);
+  }
+
+  /**
+   * Called when {@link #start} has not yet replied to its callback, but the
+   * user has lost interest.
+   */
+  public void onCancel();
+
+  /**
+   * Called when the Activity's widget has been removed from view.
+   */
+  public void onStop();
+
+  /**
+   * Called when the Activity should prepare its {@link Widget} to the user.
+   * 
+   * @param callback allows the widget to be presented asynchronously
+   */
+  public void start(Callback callback);
+
+  public boolean willStop();
+}
diff --git a/bikeshed/src/com/google/gwt/app/place/ActivityManager.java b/bikeshed/src/com/google/gwt/app/place/ActivityManager.java
new file mode 100644
index 0000000..eb5dee6
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/place/ActivityManager.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.app.place;
+
+import com.google.gwt.app.place.Activity.Callback;
+import com.google.gwt.event.shared.HandlerManager;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Manages {@link Activity} objects that should be kicked off in response to
+ * {@link PlaceChangeEvent} events. Each activity can start itself
+ * asynchronously, and provides a widget to be shown when it's ready to run.
+ * 
+ * @param <P> the type of {@link Place} objects that this ActivityManager can
+ *          map to Activities
+ */
+public class ActivityManager<P extends Place> implements
+    PlaceChangeEvent.Handler<P>, PlaceChangeRequestedEvent.Handler<P> {
+
+  /**
+   * Implemented by the view of an ActivityManager,
+   */
+  public interface View {
+    /**
+     * Displays widget, swapping out the previous.
+     * 
+     * @param widget the widget to display
+     */
+    void setWidget(Widget widget);
+  }
+
+  private final ActivityMapper<P> mapper;
+  private final HandlerManager eventBus;
+
+  private Activity currentActivity;
+  private View display;
+  private boolean startingNext = false;
+
+  /**
+   * Create an ActivityManager. Next call {@link #setDisplay} and
+   * {@link #activate}.
+   * 
+   * @param mapper finds the {@link Activity} for a given {@link Place}
+   * @param eventBus source of {@link PlaceChangeEvent} and
+   *          {@link PlaceChangeRequestedEvent} events.
+   */
+  public ActivityManager(ActivityMapper<P> mapper, HandlerManager eventBus) {
+    this.mapper = mapper;
+    this.eventBus = eventBus;
+  }
+
+  /**
+   * Deactive the current activity, find the next one from our ActivityMapper,
+   * and start it.
+   * 
+   * @see PlaceChangeEvent.Handler#onPlaceChange(PlaceChangeEvent)
+   */
+  public void onPlaceChange(PlaceChangeEvent<P> event) {
+    Activity nextActivity = mapper.getActivity(event.getNewPlace());
+
+    if (currentActivity != null) {
+      display.setWidget(null);
+      currentActivity.onStop();
+    }
+
+    if (startingNext) {
+      currentActivity.onCancel();
+      currentActivity = null;
+      startingNext = false;
+    }
+
+    if (nextActivity == null) {
+      display.setWidget(null);
+      currentActivity = null;
+      return;
+    }
+
+    currentActivity = nextActivity;
+    startingNext = true;
+    currentActivity.start(new Callback() {
+      public void onStarted(Widget widget) {
+        startingNext = false;
+        display.setWidget(widget);
+      }
+    });
+  }
+
+  /**
+   * Reject the place change if the current is not willing to stop.
+   * 
+   * @see PlaceChangeRequestedEvent.Handler#onPlaceChangeRequested(PlaceChangeRequestedEvent)
+   */
+  public void onPlaceChangeRequested(PlaceChangeRequestedEvent<P> event) {
+    if (!event.isRejected()) {
+
+      /*
+       * TODO Allow asynchronous willClose check? Could have the event object
+       * vend callbacks. Place change doesn't happen until they all vended
+       * callbacks, if any, reply with yes. Would likely need to add
+       * onPlaceChangeCanceled?
+       * 
+       * Complicated, but I really want to keep AM and PC isolated. Alternative
+       * is to mash them together and take place conversation off the event bus.
+       * And it's still complicated, just very slightly less so.
+       * 
+       * Let's see if a real use case pops up.
+       */
+      if (currentActivity != null && !currentActivity.willStop()) {
+        event.reject();
+      }
+    }
+  }
+
+  /**
+   * Sets the display for the receiver, and has the side effect of starting or
+   * stopping its monitoring the event bus for place change events.
+   * <p>
+   * If you are disposing of an ActivityManager, it is important to call
+   * setDisplay(null) to get it to deregister from the event bus, so that it can
+   * be garbage collected.
+   * 
+   * @param display
+   */
+  public void setDisplay(View display) {
+    boolean wasActive = (null != this.display);
+    boolean willBeActive = (null != display);
+    this.display = display;
+    if (wasActive != willBeActive) {
+      updateHandlers(willBeActive);
+    }
+  }
+
+  private void updateHandlers(boolean activate) {
+    if (activate) {
+      eventBus.addHandler(PlaceChangeEvent.TYPE, this);
+      eventBus.addHandler(PlaceChangeRequestedEvent.TYPE, this);
+    } else {
+      eventBus.removeHandler(PlaceChangeEvent.TYPE, this);
+      eventBus.removeHandler(PlaceChangeRequestedEvent.TYPE, this);
+    }
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/app/place/ActivityMapper.java b/bikeshed/src/com/google/gwt/app/place/ActivityMapper.java
new file mode 100644
index 0000000..f8c383b
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/place/ActivityMapper.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.app.place;
+
+/**
+ * Finds the activity to run for a given {@link Place}, used to configure
+ * an {@link ActivityManager}
+ * 
+ * @param <P> the type of place that can be mapped
+ */
+public interface ActivityMapper<P extends Place> {
+  Activity getActivity(P place);
+}
diff --git a/bikeshed/src/com/google/gwt/app/place/Place.java b/bikeshed/src/com/google/gwt/app/place/Place.java
index 95ef693..c315e38 100644
--- a/bikeshed/src/com/google/gwt/app/place/Place.java
+++ b/bikeshed/src/com/google/gwt/app/place/Place.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,7 +16,9 @@
 package com.google.gwt.app.place;
 
 /**
- * Represents a bookmarkable location in an app.
+ * Represents a bookmarkable location in an app. Implementations are expected to
+ * provide correct {@link Object#equals(Object)} and {@link Object#hashCode()}
+ * methods.
  */
 public abstract class Place {
 
diff --git a/bikeshed/src/com/google/gwt/app/place/PlaceChangeEvent.java b/bikeshed/src/com/google/gwt/app/place/PlaceChangeEvent.java
new file mode 100644
index 0000000..82d28e6
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/place/PlaceChangeEvent.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.app.place;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.GwtEvent;
+
+/**
+ * Event thrown when the user has reached a new location in the app.
+ * 
+ * @param <P> the type of the new place
+ */
+public class PlaceChangeEvent<P extends Place> extends
+    GwtEvent<PlaceChangeEvent.Handler<P>> {
+
+  /**
+   * Implemented by handlers of PlaceChangeEvent
+   * @param <P> the type of the new Place
+   */
+  public interface Handler<P extends Place> extends EventHandler {
+    void onPlaceChange(PlaceChangeEvent<P> event);
+  }
+
+  public static final Type<Handler<?>> TYPE = new Type<Handler<?>>();
+
+  private final P newPlace;
+
+  public PlaceChangeEvent(P newPlace) {
+    this.newPlace = newPlace;
+  }
+
+  // param type of static TYPE cannot be set
+  @SuppressWarnings("unchecked")
+  @Override
+  public Type<Handler<P>> getAssociatedType() {
+    return (Type) TYPE;
+  }
+
+  public P getNewPlace() {
+    return newPlace;
+  }
+
+  @Override
+  protected void dispatch(Handler<P> handler) {
+    handler.onPlaceChange(this);
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/app/place/PlaceChangeRequestedEvent.java b/bikeshed/src/com/google/gwt/app/place/PlaceChangeRequestedEvent.java
new file mode 100644
index 0000000..41a848e
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/place/PlaceChangeRequestedEvent.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.app.place;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.GwtEvent;
+
+/**
+ * Event thrown when the user may go to a new place in the app. May be rejected.
+ * 
+ * @param <P> the type of the requested place
+ */
+public class PlaceChangeRequestedEvent<P extends Place> extends
+    GwtEvent<PlaceChangeRequestedEvent.Handler<P>> {
+
+  /**
+   * Implemented by handlers of PlaceChangeRequestedEvent
+   * @param <P> the type of the requested Place
+   */
+  public interface Handler<P extends Place> extends EventHandler {
+    void onPlaceChangeRequested(PlaceChangeRequestedEvent<P> event);
+  }
+
+  public static final Type<Handler<?>> TYPE = new Type<Handler<?>>();
+
+  private boolean rejected = false;
+
+  private final P newPlace;
+
+  public PlaceChangeRequestedEvent(P newPlace) {
+    this.newPlace = newPlace;
+  }
+
+  // param type of static TYPE cannot be set
+  @SuppressWarnings("unchecked")
+  @Override
+  public Type<Handler<P>> getAssociatedType() {
+    return (Type) TYPE;
+  }
+
+  public P getNewPlace() {
+    return newPlace;
+  }
+
+  public boolean isRejected() {
+    return rejected;
+  }
+
+  public void reject() {
+    this.rejected = true;
+  }
+
+  @Override
+  protected void dispatch(Handler<P> handler) {
+    handler.onPlaceChangeRequested(this);
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/app/place/PlaceChanged.java b/bikeshed/src/com/google/gwt/app/place/PlaceChanged.java
index 79f2e79..e69de29 100644
--- a/bikeshed/src/com/google/gwt/app/place/PlaceChanged.java
+++ b/bikeshed/src/com/google/gwt/app/place/PlaceChanged.java
@@ -1,54 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.app.place;
-
-import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.event.shared.GwtEvent;
-
-/**
- * Event thrown when the user has reached a new location in the app.
- */
-public class PlaceChanged extends GwtEvent<PlaceChanged.Handler> {
-
-  /**
-   * Implemented by handlers of PlaceChanged events.
-   */
-  public interface Handler extends EventHandler {
-    void onPlaceChanged(PlaceChanged event);
-  }
-
-  public static Type<Handler> TYPE = new Type<Handler>();
-
-  private final Place newPlace;
-
-  public PlaceChanged(Place newPlace) {
-    this.newPlace = newPlace;
-  }
-
-  @Override
-  public GwtEvent.Type<Handler> getAssociatedType() {
-    return TYPE;
-  }
-
-  public Place getNewPlace() {
-    return newPlace;
-  }
-
-  @Override
-  protected void dispatch(Handler handler) {
-    handler.onPlaceChanged(this);
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/app/place/PlaceController.java b/bikeshed/src/com/google/gwt/app/place/PlaceController.java
index 9400006..ddc15b7 100644
--- a/bikeshed/src/com/google/gwt/app/place/PlaceController.java
+++ b/bikeshed/src/com/google/gwt/app/place/PlaceController.java
@@ -31,12 +31,16 @@
     this.eventBus = eventBus;
   }
 
-  public  P getWhere() {
+  public P getWhere() {
     return where;
   }
 
   public void goTo(P newPlace) {
-    where = newPlace;
-    eventBus.fireEvent(new PlaceChanged(newPlace));
+    PlaceChangeRequestedEvent<P> willChange = new PlaceChangeRequestedEvent<P>(newPlace);
+    eventBus.fireEvent(willChange);
+    if (!willChange.isRejected()) {
+      where = newPlace;
+      eventBus.fireEvent(new PlaceChangeEvent<P>(newPlace));
+    }
   }
 }
diff --git a/bikeshed/src/com/google/gwt/app/place/PlacePicker.java b/bikeshed/src/com/google/gwt/app/place/PlacePicker.java
index 6b75410..f964036 100644
--- a/bikeshed/src/com/google/gwt/app/place/PlacePicker.java
+++ b/bikeshed/src/com/google/gwt/app/place/PlacePicker.java
@@ -15,7 +15,7 @@
  */
 package com.google.gwt.app.place;
 
-import com.google.gwt.user.client.ui.Renderer;
+import com.google.gwt.app.util.Renderer;
 
 import java.util.LinkedHashMap;
 import java.util.List;
diff --git a/bikeshed/src/com/google/gwt/app/place/PlacePickerView.java b/bikeshed/src/com/google/gwt/app/place/PlacePickerView.java
index 31c36e3..7e9b338 100644
--- a/bikeshed/src/com/google/gwt/app/place/PlacePickerView.java
+++ b/bikeshed/src/com/google/gwt/app/place/PlacePickerView.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,21 +15,31 @@
  */
 package com.google.gwt.app.place;
 
+import com.google.gwt.app.util.IsWidget;
 import com.google.gwt.user.client.ui.HasValueMap;
+import com.google.gwt.user.client.ui.Widget;
 
 /**
  * View for a {@link PlacePicker}.
- *
+ * 
  * @param <P> the type of place displayed
  */
-public interface PlacePickerView<P extends Place> extends HasValueMap<P> {
+public interface PlacePickerView<P extends Place> extends IsWidget,
+    HasValueMap<P> {
 
-   /**
-    * Implemented by the presenter currently using this view.
-    */
+  /**
+   * Implemented by the presenter currently using this view.
+   */
   interface Listener<P> {
     void placePicked(P place);
   }
 
   void setListener(Listener<P> listener);
+
+  /**
+   * May throw {@link UnsupportedOperationException}, or return null.
+   * 
+   * @return the receiver as a Widget
+   */
+  Widget asWidget();
 }
diff --git a/bikeshed/src/com/google/gwt/app/util/DateTimeFormatRenderer.java b/bikeshed/src/com/google/gwt/app/util/DateTimeFormatRenderer.java
new file mode 100644
index 0000000..7abc353
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/util/DateTimeFormatRenderer.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.app.util;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.TimeZone;
+
+import java.util.Date;
+
+/**
+ * Renders {@link Date} objects with a {@link DateTimeFormat}.
+ */
+public class DateTimeFormatRenderer implements Renderer<Date> {
+  private final DateTimeFormat format;
+  private final TimeZone timeZone;
+
+  public DateTimeFormatRenderer(DateTimeFormat format) {
+    this(format, null);
+  }
+
+  public DateTimeFormatRenderer(DateTimeFormat format, TimeZone timeZone) {
+    this.format = format;
+    this.timeZone = timeZone;
+  }
+
+  public String render(Date object) {
+    return timeZone == null ? format.format(object) : format.format(object,
+        timeZone);
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/app/util/IsWidget.java b/bikeshed/src/com/google/gwt/app/util/IsWidget.java
new file mode 100644
index 0000000..d2f2d1d
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/util/IsWidget.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.app.util;
+
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Extended by View interfaces that are likely to be implemented by Widgets.
+ * Provides access to that widget, if it exists, without compromising the
+ * ability to provide mock view instance in JRE unit tests.
+ */
+public interface IsWidget {
+  Widget asWidget();
+}
diff --git a/bikeshed/src/com/google/gwt/app/util/PassthroughRenderer.java b/bikeshed/src/com/google/gwt/app/util/PassthroughRenderer.java
new file mode 100644
index 0000000..118088c
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/util/PassthroughRenderer.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.app.util;
+
+/**
+ * A no-op renderer.
+ */
+public class PassthroughRenderer implements Renderer<String> {
+
+  private static PassthroughRenderer INSTANCE;
+  
+  /**
+   * @return the instance of the no-op renderer
+   */
+  public static Renderer<String> instance() {
+    if (INSTANCE == null) {
+      INSTANCE = new PassthroughRenderer();
+    }
+    return INSTANCE;
+  }
+  
+  protected PassthroughRenderer() {
+  }
+
+  public String render(String object) {
+    return object;
+  }
+
+}
diff --git a/bikeshed/src/com/google/gwt/app/util/Renderer.java b/bikeshed/src/com/google/gwt/app/util/Renderer.java
new file mode 100644
index 0000000..12de40e
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/util/Renderer.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.app.util;
+
+/**
+ * An object that can render other objects of a particular type into plain-text
+ * form.
+ * <p>
+ * TODO: steal the slightly richer version from Guava
+ *
+ * @param <T> the type to render
+ */
+public interface Renderer<T> {
+  /**
+   * Renders {@code object} as plain text.
+   */
+  String render(T object);
+}
diff --git a/bikeshed/src/com/google/gwt/bikeshed/cells/client/ActionCell.java b/bikeshed/src/com/google/gwt/bikeshed/cells/client/ActionCell.java
index 8e40523..f8752e7 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/cells/client/ActionCell.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/cells/client/ActionCell.java
@@ -57,4 +57,4 @@
   public void render(C value, Void viewData, StringBuilder sb) {
     sb.append("<button>" + message + "</button>");
   }
-}
\ No newline at end of file
+}
diff --git a/bikeshed/src/com/google/gwt/collections/Collections.gwt.xml b/bikeshed/src/com/google/gwt/collections/Collections.gwt.xml
index a91449d..cf2b0f1 100644
--- a/bikeshed/src/com/google/gwt/collections/Collections.gwt.xml
+++ b/bikeshed/src/com/google/gwt/collections/Collections.gwt.xml
@@ -16,4 +16,5 @@
 <module>
   <inherits name='com.google.gwt.user.User'/>
   <source path="" />
+  <super-source path="super"/>
 </module>
diff --git a/bikeshed/src/com/google/gwt/collections/MutableArray.java b/bikeshed/src/com/google/gwt/collections/MutableArray.java
index c76cf48..547f2bf 100644
--- a/bikeshed/src/com/google/gwt/collections/MutableArray.java
+++ b/bikeshed/src/com/google/gwt/collections/MutableArray.java
@@ -115,7 +115,6 @@
     Assertions.assertNotFrozen(this);
     Assertions.assertIndexInRange(index, 0, size());
     if (elems != null && elems.length >= 1) {
-      // TODO: replace with splice using JSNI
       int oldLen = elems.length;
       E[] newElems = (E[]) new Object[oldLen - 1];
       System.arraycopy(elems, 0, newElems, 0, index);
diff --git a/bikeshed/src/com/google/gwt/collections/super/com/google/gwt/collections/ImmutableArrayImpl.java b/bikeshed/src/com/google/gwt/collections/super/com/google/gwt/collections/ImmutableArrayImpl.java
new file mode 100644
index 0000000..900ebf8
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/collections/super/com/google/gwt/collections/ImmutableArrayImpl.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.collections;
+
+import com.google.gwt.core.client.JsArray;
+
+/**
+ * The standard JSNI implementation of an immutable array.
+ * 
+ * @param <E> The type stored in the array elements
+ */
+public class ImmutableArrayImpl<E> extends ImmutableArray<E> {
+
+  final JsArray elems;
+
+  ImmutableArrayImpl(JsArray elems) {
+    Assertions.assertNotNull(elems);
+    this.elems = elems;
+  }
+
+  @Override
+  public E get(int index) {
+    Assertions.assertIndexInRange(index, 0, size());
+    return jsniGet(index);
+  }
+
+  @Override
+  public int size() {
+    return elems.length();
+  }
+
+  private native E jsniGet(int index) /*-{
+    return this.@com.google.gwt.collections.ImmutableArrayImpl::elems[index];
+  }-*/;
+
+}
diff --git a/bikeshed/src/com/google/gwt/collections/super/com/google/gwt/collections/MutableArray.java b/bikeshed/src/com/google/gwt/collections/super/com/google/gwt/collections/MutableArray.java
new file mode 100644
index 0000000..a23ee72
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/collections/super/com/google/gwt/collections/MutableArray.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.collections;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArray;
+
+/**
+ * An array whose content and length can change over time. This implementation
+ * is used in web mode.
+ * 
+ * @param <E> The type stored in the array elements
+ */
+public class MutableArray<E> extends Array<E> {
+
+  JsArray elems;
+
+  private boolean frozen;
+
+  /**
+   * Can only be constructed via {@link CollectionFactory}.
+   */
+  MutableArray() {
+    elems = (JsArray) JavaScriptObject.createArray();
+  }
+
+  @ConstantTime
+  public void add(E elem) {
+    Assertions.assertNotFrozen(this);
+    jsniAdd(elem);
+  }
+
+  @ConstantTime
+  public void clear() {
+    Assertions.assertNotFrozen(this);
+    elems.setLength(0);
+  }
+
+  /**
+   * Creates an immutable array based on this one. Also marks this object as
+   * read-only. After calling {@code freeze()}, only use methods from
+   * {@link Array} or the returned {@link ImmutableArray} should be to access
+   * the elements of the array is preferred.
+   */
+  public ImmutableArray<E> freeze() {
+    Assertions.markFrozen(this);
+    if (size() != 0) {
+      return new ImmutableArrayImpl(elems);
+    } else {
+      return ImmutableArray.getEmptyInstance();
+    }
+  }
+
+  @Override
+  @ConstantTime
+  public E get(int index) {
+    Assertions.assertIndexInRange(index, 0, size());
+    return jsniGet(index);
+  }
+
+  /**
+   * Inserts {@code element} before the element residing at {@code index}.
+   * 
+   * @param index in the range [0, this.size()], inclusive; if index is equal to
+   *          the array's current size, the result is equivalent to calling
+   *          {@link #add(Object)}
+   * @param elem the element to insert or {@code null}
+   */
+  @LinearTime
+  public void insert(int index, E elem) {
+    Assertions.assertNotFrozen(this);
+    Assertions.assertIndexInRange(index, 0, size() + 1);
+    jsniInsert(index, elem);
+  }
+
+  /**
+   * Removes the element at the specified index.
+   */
+  @LinearTime
+  public void remove(int index) {
+    Assertions.assertNotFrozen(this);
+    Assertions.assertIndexInRange(index, 0, size());
+    jsniRemove(index);
+  }
+
+  /**
+   * Replaces the element at the specified index.
+   * 
+   * @param index in the range [0, this.size()), exclusive
+   * @param elem the element to insert or {@code null}
+   */
+  @ConstantTime
+  public void set(int index, E elem) {
+    Assertions.assertNotFrozen(this);
+    Assertions.assertIndexInRange(index, 0, size());
+
+    jsniSet(index, elem);
+  }
+
+  /**
+   * Changes the array size. If {@code newSize} is less than the current size,
+   * the array is truncated. If {@code newSize} is greater than the current size
+   * the array is grown and the new elements of the array filled up with {@code
+   * fillValue}.
+   */
+  @LinearTime
+  public void setSize(int newSize, E fillValue) {
+    Assertions.assertNotFrozen(this);
+    jsniSetSize(newSize, fillValue);
+  }
+
+  @Override
+  @ConstantTime
+  public int size() {
+    return elems.length();
+  }
+
+  // Only meant to be called from within Assertions
+  boolean isFrozen() {
+    return frozen;
+  }
+
+  // Only meant to be called from within Assertions
+  void markFrozen() {
+    frozen = true;
+  }
+
+  private Object[] copyNativeArray(JsArray jsElems) {
+    if (jsElems == null) {
+      return null;
+    }
+
+    Object[] jreElems = new Object[jsElems.length()];
+
+    for (int i = 0; i < jsElems.length(); ++i) {
+      jreElems[i] = jsElems.get(i);
+    }
+    return jreElems;
+  }
+
+  @ConstantTime
+  private native void jsniAdd(E elem) /*-{
+    this.@com.google.gwt.collections.MutableArray::elems.push(elem);
+  }-*/;
+
+  @ConstantTime
+  private native E jsniGet(int index) /*-{
+    return this.@com.google.gwt.collections.MutableArray::elems[index];
+  }-*/;
+
+  /**
+   * Inserts {@code element} before the element residing at {@code index}.
+   * 
+   * @param index in the range [0, this.size()], inclusive; if index is equal to
+   *          the array's current size, the result is equivalent to calling
+   *          {@link #add(Object)}
+   * @param elem the element to insert or {@code null}
+   */
+  @LinearTime
+  private native void jsniInsert(int index, E elem) /*-{
+    this.@com.google.gwt.collections.MutableArray::elems.splice(index, 0, elem);
+  }-*/;
+
+  /**
+   * Removes the element at the specified index.
+   */
+  @LinearTime
+  private native void jsniRemove(int index) /*-{
+    this.@com.google.gwt.collections.MutableArray::elems.splice(index, 1);
+  }-*/;
+
+  /**
+   * Replaces the element at the specified index.
+   * 
+   * @param index in the range [0, this.size()), exclusive
+   * @param elem the element to insert or {@code null}
+   */
+  @ConstantTime
+  private native void jsniSet(int index, E elem) /*-{
+    this.@com.google.gwt.collections.MutableArray::elems[index] = elem;
+  }-*/;
+
+  /**
+   * Changes the array size. If {@code newSize} is less than the current size,
+   * the array is truncated. If {@code newSize} is greater than the current size
+   * the array is grown and the new elements of the array filled up with {@code
+   * fillValue}.
+   */
+  @LinearTime
+  private native void jsniSetSize(int newSize, E fillValue) /*-{
+    var fillStart;
+    var i;
+
+    fillStart = this.@com.google.gwt.collections.MutableArray::elems.length;
+
+    this.@com.google.gwt.collections.MutableArray::elems.length = newSize;
+
+    if (fillValue != null) {
+      for (i = fillStart; i < newSize; ++i) {
+        this.@com.google.gwt.collections.MutableArray::elems[i] = fillValue;
+      }
+    }
+  }-*/;
+
+}
diff --git a/bikeshed/src/com/google/gwt/requestfactory/client/gen/ClientRequestObject.java b/bikeshed/src/com/google/gwt/requestfactory/client/gen/ClientRequestObject.java
index 00211bf..e69de29 100644
--- a/bikeshed/src/com/google/gwt/requestfactory/client/gen/ClientRequestObject.java
+++ b/bikeshed/src/com/google/gwt/requestfactory/client/gen/ClientRequestObject.java
@@ -1,53 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.requestfactory.client.gen;
-
-import com.google.gwt.core.client.JavaScriptObject;
-
-import java.util.Map;
-
-/**
- * A convenience class to convert a Map<String, String> to a JSON string on the
- * client side.
- */
-public class ClientRequestObject {
-
-  private static class MyJSO extends JavaScriptObject {
-    static native MyJSO create() /*-{
-      return {};
-    }-*/;
-
-    @SuppressWarnings("unused")
-    protected MyJSO() {
-    }
-
-    private native void put(String key, String value)/*-{
-      this[key] = value;
-    }-*/;
-
-    private native String toJsonString()/*-{
-      return JSON.stringify(this);
-    }-*/;
-  }
-
-  public static String getRequestString(Map<String, String> requestData) {
-    MyJSO requestObject = MyJSO.create();
-    for (String key : requestData.keySet()) {
-      requestObject.put(key, requestData.get(key));
-    }
-    return requestObject.toJsonString();
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/requestfactory/client/impl/ClientRequestObject.java b/bikeshed/src/com/google/gwt/requestfactory/client/impl/ClientRequestObject.java
new file mode 100644
index 0000000..73ae76e
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/requestfactory/client/impl/ClientRequestObject.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.requestfactory.client.impl;
+
+import com.google.gwt.core.client.JavaScriptObject;
+
+import java.util.Map;
+
+/**
+ * A convenience class to convert a Map<String, String> to a JSON string on the
+ * client side.
+ */
+public class ClientRequestObject {
+
+  private static class MyJSO extends JavaScriptObject {
+    static native MyJSO create() /*-{
+      return {};
+    }-*/;
+
+    @SuppressWarnings("unused")
+    protected MyJSO() {
+    }
+
+    private native void put(String key, String value)/*-{
+      this[key] = value;
+    }-*/;
+
+    private native String toJsonString()/*-{
+      return JSON.stringify(this);
+    }-*/;
+  }
+
+  public static String getRequestString(Map<String, String> requestData) {
+    MyJSO requestObject = MyJSO.create();
+    for (String key : requestData.keySet()) {
+      requestObject.put(key, requestData.get(key));
+    }
+    return requestObject.toJsonString();
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java b/bikeshed/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java
index 2541c90..745e978 100644
--- a/bikeshed/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java
+++ b/bikeshed/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java
@@ -21,7 +21,6 @@
 import com.google.gwt.http.client.RequestCallback;
 import com.google.gwt.http.client.RequestException;
 import com.google.gwt.http.client.Response;
-import com.google.gwt.requestfactory.client.gen.ClientRequestObject;
 import com.google.gwt.requestfactory.shared.RequestFactory;
 import com.google.gwt.requestfactory.shared.SyncRequest;
 import com.google.gwt.requestfactory.shared.impl.RequestDataManager;
diff --git a/bikeshed/src/com/google/gwt/requestfactory/rebind/RequestFactoryGenerator.java b/bikeshed/src/com/google/gwt/requestfactory/rebind/RequestFactoryGenerator.java
index 4f2bf96..38974a1 100644
--- a/bikeshed/src/com/google/gwt/requestfactory/rebind/RequestFactoryGenerator.java
+++ b/bikeshed/src/com/google/gwt/requestfactory/rebind/RequestFactoryGenerator.java
@@ -27,8 +27,8 @@
 import com.google.gwt.core.ext.typeinfo.JType;
 import com.google.gwt.core.ext.typeinfo.NotFoundException;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.requestfactory.client.gen.ClientRequestObject;
 import com.google.gwt.requestfactory.client.impl.AbstractListJsonRequestObject;
+import com.google.gwt.requestfactory.client.impl.ClientRequestObject;
 import com.google.gwt.requestfactory.client.impl.RequestFactoryJsonImpl;
 import com.google.gwt.requestfactory.shared.ServerOperation;
 import com.google.gwt.requestfactory.shared.RequestFactory.WriteOperation;
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesDetailsPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesDetailsPlace.java
index 6bd5ab0..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesDetailsPlace.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesDetailsPlace.java
@@ -1,31 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.place;
-
-import com.google.gwt.valuestore.shared.Record;
-
-/**
- * Place in an app to see details of a particular
- * {@link com.google.gwt.valuestore.shared.ValueStore ValueStore} record.
- */
-public class ExpensesDetailsPlace extends ExpensesRecordPlace {
-
-  public ExpensesDetailsPlace(Record entity) {
-    // TODO it is bad to be passing the values rather than an id. Want
-    // to force UI code to request the data it needs
-    super(entity);
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesEditorPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesEditorPlace.java
index 4f3ba13..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesEditorPlace.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesEditorPlace.java
@@ -1,29 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.place;
-
-import com.google.gwt.valuestore.shared.Record;
-
-/**
- * Place in an app to edit the values of a particular
- * {@link com.google.gwt.valuestore.shared.ValueStore ValueStore} record.
- */
-public class ExpensesEditorPlace extends ExpensesRecordPlace {
-
-  public ExpensesEditorPlace(Record entity) {
-    super(entity);
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesListPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesListPlace.java
index 6d9c935..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesListPlace.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesListPlace.java
@@ -1,38 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.place;
-
-import com.google.gwt.valuestore.shared.Record;
-
-/**
- * Place in an app that lists
- * {@link com.google.gwt.valuestore.shared.ValueStore ValueStore} records of a
- * particular type.
- */
-public class ExpensesListPlace extends ExpensesPlace {
-  private final Class<? extends Record> key;
-
-  /**
-   * @param key the schema of the entities at this place
-   */
-  public ExpensesListPlace(Class<? extends Record> key) {
-    this.key = key;
-  }
-
-  public Class<? extends Record> getType() {
-    return key;
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesPlace.java
index 4f445b0..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesPlace.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesPlace.java
@@ -1,26 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.place;
-
-import com.google.gwt.app.place.Place;
-
-/**
- * Base type of places for an app.
- */
-public abstract class ExpensesPlace extends Place {
-  // TODO is there actual value in this base class? Yes, if visitors
-  // and fiters leave the keys and come back to places.
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesPlaces.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesPlaces.java
index 8547d2a..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesPlaces.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesPlaces.java
@@ -1,47 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.place;
-
-import com.google.gwt.app.place.PlaceController;
-import com.google.gwt.bikeshed.cells.client.ActionCell;
-import com.google.gwt.valuestore.shared.Record;
-
-/**
- * Object with knowledge of the places of an app.
- */
-public class ExpensesPlaces {
-  private final PlaceController<ExpensesPlace> controller;
-
-  public ExpensesPlaces(PlaceController<ExpensesPlace> controller) {
-    this.controller = controller;
-  }
-
-  public <R extends Record> ActionCell.Delegate<R> getDetailsGofer() {
-    return new ActionCell.Delegate<R>() {
-      public void execute(R object) {
-        controller.goTo(new ExpensesDetailsPlace(object));
-      }
-    };
-  }
-
-  public <R extends Record> ActionCell.Delegate<R> getEditorGofer() {
-    return new ActionCell.Delegate<R>() {
-      public void execute(R object) {
-        controller.goTo(new ExpensesEditorPlace(object));
-      }
-    };
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesRecordPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesRecordPlace.java
index 3a0d167..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesRecordPlace.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/place/ExpensesRecordPlace.java
@@ -1,43 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.place;
-
-import com.google.gwt.valuestore.shared.Record;
-
-/**
- * A place in the app focused on the {@link Values} of a particular type of
- * {@link com.google.gwt.valuestore.shared.ValueStore ValueStore} record.
- */
-public abstract class ExpensesRecordPlace extends ExpensesPlace {
-
-  private final Record record;
-
-  /**
-   * @param record
-   */
-  public ExpensesRecordPlace(Record record) {
-
-    this.record = record;
-  }
-
-  /**
-   * @return the entity
-   */
-  public Record getEntity() {
-    return record;
-  }
-
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/EmployeeRequest.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/EmployeeRequest.java
index 61c1ea7..2a46b8a 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/EmployeeRequest.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/EmployeeRequest.java
@@ -18,6 +18,7 @@
 import com.google.gwt.requestfactory.shared.EntityListRequest;
 import com.google.gwt.requestfactory.shared.RequestFactory;
 import com.google.gwt.requestfactory.shared.ServerOperation;
+import com.google.gwt.valuestore.shared.PropertyReference;
 import com.google.gwt.valuestore.shared.Record;
 
 /**
@@ -37,11 +38,17 @@
       public String getDomainMethodName() {
         return "findAllEmployees";
       }
+    },
 
-      public Class<? extends Record> getReturnType() {
-        return EmployeeRecord.class;
+    FIND_EMPLOYEE {
+      public String getDomainMethodName() {
+        return "findListOfOneEmployee";
       }
-    };
+
+      public Class<?>[] getParameterTypes() {
+        return new Class[] {java.lang.String.class};
+      }
+   };
 
     public String getDomainClassName() {
       return "com.google.gwt.sample.expenses.server.domain.Employee";
@@ -50,6 +57,10 @@
     public Class<?>[] getParameterTypes() {
       return null;
     }
+
+    public Class<? extends Record> getReturnType() {
+      return EmployeeRecord.class;
+    }
   }
 
   /**
@@ -57,4 +68,10 @@
    */
   @ServerOperation("FIND_ALL_EMPLOYEES")
   EntityListRequest<EmployeeRecord> findAllEmployees();
+
+  /**
+   * @return a request object
+   */
+  @ServerOperation("FIND_EMPLOYEE")
+  EntityListRequest<EmployeeRecord> findEmployee(PropertyReference<String> id);
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ExpensesEntityTypesProcessor.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ExpensesEntityTypesProcessor.java
index e2d2a12..7184ed4 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ExpensesEntityTypesProcessor.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ExpensesEntityTypesProcessor.java
@@ -29,7 +29,7 @@
 public class ExpensesEntityTypesProcessor {
 
   /**
-   * Implemented by objects interested in all {@link ExpensesKey} instances.
+   * Implemented by objects that need to process {@link Record} types.
    */
   public interface EntityTypesProcessor {
     void processType(Class<? extends Record> recordType);
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ReportRequest.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ReportRequest.java
index 98dfb80..7988cbd 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ReportRequest.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/request/ReportRequest.java
@@ -34,6 +34,22 @@
    * Defines the server operations that handle these requests.
    */
   public enum ServerOperations implements RequestFactory.RequestDefinition {
+    FIND_ALL_REPORTS {
+      public String getDomainMethodName() {
+        return "findAllReports";
+      }
+    },
+
+    FIND_REPORT {
+      public String getDomainMethodName() {
+        return "findListOfOneReport";
+      }
+
+      public Class<?>[] getParameterTypes() {
+        return new Class[] {java.lang.String.class};
+      }
+    },
+
     FIND_REPORTS_BY_EMPLOYEE {
       public String getDomainMethodName() {
         return "findReportsByEmployee";
@@ -42,20 +58,6 @@
       public Class<?>[] getParameterTypes() {
         return new Class[] {java.lang.String.class};
       }
-
-      public Class<? extends Record> getReturnType() {
-        return ReportRecord.class;
-      }
-    },
-
-    FIND_ALL_REPORTS {
-      public String getDomainMethodName() {
-        return "findAllReports";
-      }
-
-      public Class<? extends Record> getReturnType() {
-        return ReportRecord.class;
-      }
     };
 
     public String getDomainClassName() {
@@ -65,18 +67,28 @@
     public Class<?>[] getParameterTypes() {
       return null;
     }
+
+    public Class<? extends Record> getReturnType() {
+      return ReportRecord.class;
+    }
   }
 
   /**
    * @return a request object
    */
+  @ServerOperation("FIND_ALL_REPORTS")
+  EntityListRequest<ReportRecord> findAllReports();
+
+  /**
+   * @return a request object
+   */
+  @ServerOperation("FIND_REPORT")
+  EntityListRequest<ReportRecord> findReport(PropertyReference<String> id);
+
+  /**
+   * @return a request object
+   */
   @ServerOperation("FIND_REPORTS_BY_EMPLOYEE")
   EntityListRequest<ReportRecord> findReportsByEmployee(
       PropertyReference<String> id);
-
-  /**
-   * @return a request object
-   */
-  @ServerOperation("FIND_ALL_REPORTS")
-  EntityListRequest<ReportRecord> findAllReports();
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/EditorView.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/EditorView.java
new file mode 100644
index 0000000..de71e8a
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/EditorView.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.scaffold;
+
+import com.google.gwt.app.util.IsWidget;
+import com.google.gwt.user.client.ui.TakesValue;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.valuestore.shared.Record;
+
+/**
+ * Implemented by a widget that edit sthe properties of a bean-style object.
+ * 
+ * @param <T> the type of the object being edited
+ */
+public interface EditorView<T extends Record> extends IsWidget, TakesValue<T> {
+
+  Widget asWidget();
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/Scaffold.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/Scaffold.java
index 6f4c1ef..cd97352 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/Scaffold.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/Scaffold.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,7 +15,8 @@
  */
 package com.google.gwt.sample.expenses.gwt.scaffold;
 
-import com.google.gwt.app.place.PlaceChanged;
+import com.google.gwt.app.place.ActivityManager;
+import com.google.gwt.app.place.ActivityMapper;
 import com.google.gwt.app.place.PlaceController;
 import com.google.gwt.app.place.PlacePicker;
 import com.google.gwt.core.client.EntryPoint;
@@ -23,15 +24,13 @@
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.event.shared.HandlerManager;
-import com.google.gwt.sample.expenses.gwt.place.ExpensesListPlace;
-import com.google.gwt.sample.expenses.gwt.place.ExpensesPlace;
-import com.google.gwt.sample.expenses.gwt.place.ExpensesPlaces;
 import com.google.gwt.sample.expenses.gwt.request.ExpensesEntityTypesProcessor;
 import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
-import com.google.gwt.sample.expenses.gwt.ui.ExpensesKeyNameRenderer;
-import com.google.gwt.sample.expenses.gwt.ui.ListPlaceRenderer;
-import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ListScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.ui.ScaffoldListPlaceRenderer;
 import com.google.gwt.user.client.ui.RootLayoutPanel;
+import com.google.gwt.user.client.ui.Widget;
 import com.google.gwt.valuestore.shared.Record;
 
 import java.util.ArrayList;
@@ -45,53 +44,55 @@
 
   public void onModuleLoad() {
 
-    // App controllers and services
+    /* App controllers and services */
+    
     final HandlerManager eventBus = new HandlerManager(null);
     final ExpensesRequestFactory requestFactory = GWT.create(ExpensesRequestFactory.class);
     requestFactory.init(eventBus);
-
-    final PlaceController<ExpensesPlace> placeController = new PlaceController<ExpensesPlace>(
+    final PlaceController<ScaffoldPlace> placeController = new PlaceController<ScaffoldPlace>(
         eventBus);
-    final ExpensesPlaces places = new ExpensesPlaces(placeController);
 
-    // Renderers
-    final ExpensesKeyNameRenderer entityNamer = new ExpensesKeyNameRenderer();
-    final ListPlaceRenderer listPlaceNamer = new ListPlaceRenderer();
+    /* Top level UI */
 
-    // Top level UI
     final ScaffoldShell shell = new ScaffoldShell();
 
-    // Left side
-    PlacePicker<ExpensesListPlace> placePicker = new PlacePicker<ExpensesListPlace>(
-        shell.getPlacesBox(), placeController, listPlaceNamer);
-    List<ExpensesListPlace> topPlaces = getTopPlaces();
-    placePicker.setPlaces(topPlaces);
+    /* Left side lets us pick from all the types of entities */
 
-    // Shows entity lists
-    eventBus.addHandler(PlaceChanged.TYPE, new ScaffoldListRequester(
-        shell.getBody(), new ScaffoldListViewBuilder(places, requestFactory,
-            listPlaceNamer)));
+    PlacePicker<ListScaffoldPlace> placePicker = new PlacePicker<ListScaffoldPlace>(
+        shell.getPlacesBox(), placeController, new ScaffoldListPlaceRenderer());
+    placePicker.setPlaces(getTopPlaces());
 
-    // Shared view for entity details.
-    final HTML detailsView = new HTML(); // TODO Real app should not share?
+    /*
+     * The body is run by an ActivitManager that listens for PlaceChange events
+     * and finds the corresponding Activity to run
+     */
 
-    // Shows entity details
-    eventBus.addHandler(PlaceChanged.TYPE, new ScaffoldDetailsRequester(
-        entityNamer, shell.getBody(), detailsView,
-        new ScaffoldDetailsViewBuilder()));
+    final ActivityMapper<ScaffoldPlace> mapper = new ScaffoldActivities(
+        requestFactory, placeController);
+    final ActivityManager<ScaffoldPlace> activityManager = new ActivityManager<ScaffoldPlace>(
+        mapper, eventBus);
 
-    // Hide the loading message
+    activityManager.setDisplay(new ActivityManager.View() {
+      public void setWidget(Widget widget) {
+        shell.getBody().setWidget(widget);
+      }
+    });
+
+    /* Hide the loading message */
+
     Element loading = Document.get().getElementById("loading");
     loading.getParentElement().removeChild(loading);
 
+    /* And show the user the shell */
+    
     RootLayoutPanel.get().add(shell);
   }
 
-  private List<ExpensesListPlace> getTopPlaces() {
-    final List<ExpensesListPlace> rtn = new ArrayList<ExpensesListPlace>();
+  private List<ListScaffoldPlace> getTopPlaces() {
+    final List<ListScaffoldPlace> rtn = new ArrayList<ListScaffoldPlace>();
     ExpensesEntityTypesProcessor.processAll(new ExpensesEntityTypesProcessor.EntityTypesProcessor() {
       public void processType(Class<? extends Record> recordType) {
-        rtn.add(new ExpensesListPlace(recordType));
+        rtn.add(new ListScaffoldPlace(recordType));
       }
     });
     return Collections.unmodifiableList(rtn);
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldActivities.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldActivities.java
new file mode 100644
index 0000000..da47156
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldActivities.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.scaffold;
+
+import com.google.gwt.app.place.Activity;
+import com.google.gwt.app.place.ActivityMapper;
+import com.google.gwt.app.place.PlaceController;
+import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.EmployeeScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ListScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ReportScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ScaffoldPlaceFilter;
+import com.google.gwt.sample.expenses.gwt.ui.ListActivitiesMapper;
+import com.google.gwt.sample.expenses.gwt.ui.employee.EmployeeActivitiesMapper;
+import com.google.gwt.sample.expenses.gwt.ui.report.ReportActivitiesMapper;
+
+/**
+ * Finds the activity to run for a particular {@link ScaffoldPlace}.
+ */
+public final class ScaffoldActivities implements ActivityMapper<ScaffoldPlace> {
+
+  private final ActivityMapper<ListScaffoldPlace> listActivitiesBuilder;
+  private final ActivityMapper<EmployeeScaffoldPlace> employeeActivitiesBuilder;
+  private final ActivityMapper<ReportScaffoldPlace> reportActivitiesBuilder;
+
+  /**
+   * @param requestFactory
+   * @param placeController
+   */
+  public ScaffoldActivities(ExpensesRequestFactory requestFactory,
+      PlaceController<ScaffoldPlace> placeController) {
+    this.listActivitiesBuilder = new ListActivitiesMapper(requestFactory,
+        placeController);
+    this.employeeActivitiesBuilder = new EmployeeActivitiesMapper(
+        requestFactory, placeController);
+    this.reportActivitiesBuilder = new ReportActivitiesMapper(requestFactory,
+        placeController);
+  }
+
+  public Activity getActivity(ScaffoldPlace place) {
+    return place.acceptFilter(new ScaffoldPlaceFilter<Activity>() {
+
+      public Activity filter(EmployeeScaffoldPlace place) {
+        return employeeActivitiesBuilder.getActivity(place);
+      }
+
+      public Activity filter(ListScaffoldPlace place) {
+        return listActivitiesBuilder.getActivity(place);
+      }
+
+      public Activity filter(ReportScaffoldPlace place) {
+        return reportActivitiesBuilder.getActivity(place);
+      }
+    });
+  }
+}
\ No newline at end of file
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldDetailsRequester.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldDetailsRequester.java
index 0c7c841..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldDetailsRequester.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldDetailsRequester.java
@@ -1,69 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.scaffold;
-
-import com.google.gwt.app.place.PlaceChanged;
-import com.google.gwt.sample.expenses.gwt.place.ExpensesDetailsPlace;
-import com.google.gwt.sample.expenses.gwt.ui.ExpensesKeyNameRenderer;
-import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwt.valuestore.shared.Record;
-
-/**
- * In charge of requesting and displaying details of a particular record in the
- * appropriate view when the user goes to an {@link ExpensesDetailsPlace} in the
- * Scaffold app.
- */
-public final class ScaffoldDetailsRequester implements PlaceChanged.Handler {
-
-  private final ExpensesKeyNameRenderer entityNamer;
-  private final SimplePanel panel;
-  private final HTML detailsView;
-  private final ScaffoldDetailsViewBuilder detailsBuilder;
-
-  public ScaffoldDetailsRequester(ExpensesKeyNameRenderer entityNamer,
-      SimplePanel simplePanel, HTML detailsView,
-      ScaffoldDetailsViewBuilder detailsBuilder) {
-    this.entityNamer = entityNamer;
-    this.panel = simplePanel;
-    this.detailsView = detailsView;
-    this.detailsBuilder = detailsBuilder;
-  }
-
-  public void onPlaceChanged(PlaceChanged event) {
-    if (!(event.getNewPlace() instanceof ExpensesDetailsPlace)) {
-      return;
-    }
-
-    ExpensesDetailsPlace newPlace = (ExpensesDetailsPlace) event.getNewPlace();
-    final Record values = newPlace.getEntity();
-    final String title = new StringBuilder("<h1>").append(
-        entityNamer.render(values)).append("</h1>").toString();
-
-    // TODO would actually issue request to get details here, but
-    // at the moment we know we already have them, such as they are.
-    // And we haven't implemented the fake findEmployee call yet, ahem.
-
-    StringBuilder list = new StringBuilder();
-    detailsBuilder.appendHtmlDescription(list, values);
-    detailsView.setHTML(title + list.toString());
-
-    if (detailsView.getParent() == null) {
-      panel.clear();
-      panel.add(detailsView);
-    }
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldDetailsViewBuilder.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldDetailsViewBuilder.java
index 59ecc76..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldDetailsViewBuilder.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldDetailsViewBuilder.java
@@ -1,48 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.scaffold;
-
-import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
-import com.google.gwt.sample.expenses.gwt.request.ReportRecord;
-import com.google.gwt.sample.expenses.gwt.ui.employee.EmployeeDetailsBuilder;
-import com.google.gwt.sample.expenses.gwt.ui.report.ReportDetailsBuilder;
-import com.google.gwt.valuestore.shared.Record;
-
-/**
- * Builds the details view for a record.
- * <p>
- * TODO should instead be a finder of pretty uibinder-based widgets, not least
- * because we're rendering user strings here, which is dangerous
- */
-public class ScaffoldDetailsViewBuilder {
-  private final EmployeeDetailsBuilder employeeBuilder = new EmployeeDetailsBuilder();
-  private final ReportDetailsBuilder reportBuilder = new ReportDetailsBuilder();
-
-  public void appendHtmlDescription(final StringBuilder list,
-      final Record entity) {
-
-    // TODO These casts are nasty, but they probably wouldn't be necessary
-    // if we were listening for request reponses they way we're supposed to
-
-    if (entity instanceof EmployeeRecord) {
-      employeeBuilder.append(list, (EmployeeRecord) entity);
-    }
-
-    if (entity instanceof ReportRecord) {
-      reportBuilder.append(list, (ReportRecord) entity);
-    }
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldListRequester.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldListRequester.java
index eff73a6..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldListRequester.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldListRequester.java
@@ -1,56 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.scaffold;
-
-import com.google.gwt.app.place.PlaceChanged;
-import com.google.gwt.sample.expenses.gwt.place.ExpensesListPlace;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwt.user.client.ui.Widget;
-
-/**
- * In charge of requesting and displaying the appropriate record lists in the
- * appropriate view when the user goes to an {@link ExpensesListPlace} in the
- * Scaffold app.
- */
-public final class ScaffoldListRequester implements PlaceChanged.Handler {
-
-  private final SimplePanel panel;
-  private final ScaffoldListViewBuilder builder;
-
-  public ScaffoldListRequester(SimplePanel panel,
-      ScaffoldListViewBuilder builder) {
-    this.panel = panel;
-    this.builder = builder;
-  }
-
-  public void onPlaceChanged(PlaceChanged event) {
-    if (!(event.getNewPlace() instanceof ExpensesListPlace)) {
-      return;
-    }
-    final ExpensesListPlace newPlace = (ExpensesListPlace) event.getNewPlace();
-
-    Widget view = builder.getListView(newPlace).asWidget();
-
-    if (null == view) {
-      throw new RuntimeException("Unable to locate a view for " + newPlace);
-    }
-
-    if (view.getParent() == null) {
-      panel.clear();
-      panel.add(view);
-    }
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldListViewBuilder.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldListViewBuilder.java
index 7d63895..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldListViewBuilder.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldListViewBuilder.java
@@ -1,70 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.scaffold;
-
-import com.google.gwt.sample.expenses.gwt.place.ExpensesListPlace;
-import com.google.gwt.sample.expenses.gwt.place.ExpensesPlaces;
-import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
-import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
-import com.google.gwt.sample.expenses.gwt.request.ReportRecord;
-import com.google.gwt.sample.expenses.gwt.ui.employee.AllEmployeesRequester;
-import com.google.gwt.sample.expenses.gwt.ui.employee.EmployeeListView;
-import com.google.gwt.sample.expenses.gwt.ui.report.AllReportsRequester;
-import com.google.gwt.sample.expenses.gwt.ui.report.ReportListView;
-import com.google.gwt.user.client.ui.Renderer;
-import com.google.gwt.valuestore.client.ValuesListViewTable;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Returns the view instances for {@link ExpensesListPlace}s, paired with
- * objects to request all records of the appropriate type.
- */
-public class ScaffoldListViewBuilder {
-  private final ExpensesRequestFactory requests;
-  private final Renderer<ExpensesListPlace> placeRenderer;
-  private final ExpensesPlaces places;
-  private final Map<ExpensesListPlace, ValuesListViewTable<?>> viewMap = new HashMap<ExpensesListPlace, ValuesListViewTable<?>>();
-
-  public ScaffoldListViewBuilder(ExpensesPlaces places,
-      ExpensesRequestFactory requests, Renderer<ExpensesListPlace> renderer) {
-    this.places = places;
-    this.requests = requests;
-    this.placeRenderer = renderer;
-  }
-
-  public ValuesListViewTable<?> getListView(final ExpensesListPlace newPlace) {
-    // TODO Will these class references prevent customized apps that keep this
-    // view builder around from stripping unused entity types?
-    if (!viewMap.containsKey(newPlace)) {
-      if (newPlace.getType().equals(EmployeeRecord.class)) {
-        EmployeeListView newView = new EmployeeListView(
-            placeRenderer.render(newPlace), places);
-        newView.setDelegate(new AllEmployeesRequester(requests, newView));
-        viewMap.put(newPlace, newView);
-      }
-
-      if (newPlace.getType().equals(ReportRecord.class)) {
-        ReportListView newView = new ReportListView(
-            placeRenderer.render(newPlace), places);
-        newView.setDelegate(new AllReportsRequester(requests, newView));
-        viewMap.put(newPlace, newView);
-      }
-    }
-    return viewMap.get(newPlace);
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldShell.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldShell.java
index 739db9b..b5eb33f 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldShell.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldShell.java
@@ -15,10 +15,10 @@
  */
 package com.google.gwt.sample.expenses.gwt.scaffold;
 
-import com.google.gwt.app.client.ListBoxPlacePickerView;
+import com.google.gwt.app.place.PlacePickerView;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.DivElement;
-import com.google.gwt.sample.expenses.gwt.place.ExpensesListPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ListScaffoldPlace;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiField;
 import com.google.gwt.user.client.ui.Composite;
@@ -34,7 +34,7 @@
   private static final Binder BINDER = GWT.create(Binder.class);
 
   @UiField SimplePanel body;
-  @UiField ListBoxPlacePickerView<ExpensesListPlace> placesBox;
+  @UiField PlacePickerView<ListScaffoldPlace> placesBox;
   @UiField DivElement error;
 
   public ScaffoldShell() {
@@ -49,9 +49,9 @@
   }
 
   /**
-   * @return the banner
+   * @return the navigator
    */
-  public ListBoxPlacePickerView<ExpensesListPlace> getPlacesBox() {
+  public PlacePickerView<ListScaffoldPlace> getPlacesBox() {
     return placesBox;
   }
 
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldShell.ui.xml b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldShell.ui.xml
index 4f2c073..d75e07f 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldShell.ui.xml
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/ScaffoldShell.ui.xml
@@ -38,6 +38,7 @@
         <h2 class='{style.title}'>Expenses Entity Browser</h2>
       </g:HTML>
     </g:north>
+    
     <g:west size='15'>
       <a:ListBoxPlacePickerView width='90%' visibleItemCount='10' ui:field='placesBox'/>
     </g:west>
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/BaseScaffoldPlaceProcessor.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/BaseScaffoldPlaceProcessor.java
new file mode 100644
index 0000000..c12fd7f
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/BaseScaffoldPlaceProcessor.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.scaffold.place;
+
+/**
+ * A convenient base implementation of {@link ScaffoldPlaceProcessor}. Just
+ * override the methods for the types of places that you actually care about.
+ * <p>
+ * <strong>NB</strong>It is a bad idea to use this class if your code needs to
+ * be extended when new subclasses of {@link ScaffoldPlace} are added. If that's
+ * the case, implement ScaffoldPlaceVisitor yourself, so that the compiler will
+ * let you know to update your code.
+ */
+public class BaseScaffoldPlaceProcessor implements ScaffoldPlaceProcessor {
+
+  public void process(EmployeeScaffoldPlace employeePlace) {
+  }
+
+  public void process(ListScaffoldPlace listPlace) {
+  }
+
+  public void process(ReportScaffoldPlace reportPlace) {
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/EmployeeScaffoldPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/EmployeeScaffoldPlace.java
new file mode 100644
index 0000000..2e67c63
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/EmployeeScaffoldPlace.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.scaffold.place;
+
+import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
+
+/**
+ * A place in the scaffold app for working with an {@EmployeeRecord
+ * }.
+ */
+public class EmployeeScaffoldPlace extends ScaffoldRecordPlace {
+
+  public EmployeeScaffoldPlace(EmployeeRecord record, Operation operation) {
+    super(record.getId(), operation);
+  }
+
+  public EmployeeScaffoldPlace(String id, Operation operation) {
+    super(id, operation);
+  }
+
+  @Override
+  public void accept(ScaffoldPlaceProcessor visitor) {
+    visitor.process(this);
+  }
+
+  @Override
+  public <T> T acceptFilter(ScaffoldPlaceFilter<T> filter) {
+    return filter.filter(this);
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ListScaffoldPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ListScaffoldPlace.java
new file mode 100644
index 0000000..e2abdee
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ListScaffoldPlace.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.scaffold.place;
+
+import com.google.gwt.valuestore.shared.Record;
+
+/**
+ * Place in an app that lists
+ * {@link com.google.gwt.valuestore.shared.ValueStore ValueStore} records of a
+ * particular type.
+ */
+public class ListScaffoldPlace extends ScaffoldPlace {
+  private final Class<? extends Record> type;
+
+  /**
+   * @param key the schema of the entities at this place
+   */
+  public ListScaffoldPlace(Class<? extends Record> type) {
+    assert null != type;
+    this.type = type;
+  }
+
+  @Override
+  public void accept(ScaffoldPlaceProcessor visitor) {
+    visitor.process(this);
+  }
+
+  @Override
+  public <T> T acceptFilter(ScaffoldPlaceFilter<T> filter) {
+    return filter.filter(this);
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) {
+      return true;
+    }
+
+    if (getClass() != obj.getClass()) {
+      return false;
+    }
+    ListScaffoldPlace other = (ListScaffoldPlace) obj;
+
+    if (!type.equals(other.type)) {
+      return false;
+    }
+    
+    return true;
+  }
+
+  public Class<? extends Record> getType() {
+    return type;
+  }
+
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + ((type == null) ? 0 : type.hashCode());
+    return result;
+  }
+  
+  
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ReportScaffoldPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ReportScaffoldPlace.java
new file mode 100644
index 0000000..731e6b0
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ReportScaffoldPlace.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.scaffold.place;
+
+import com.google.gwt.sample.expenses.gwt.request.ReportRecord;
+
+/**
+ * A place in the scaffold app for working with an {@EmployeeRecord
+ * }.
+ */
+public class ReportScaffoldPlace extends ScaffoldRecordPlace {
+
+  public ReportScaffoldPlace(ReportRecord record, Operation operation) {
+    super(record.getId(), operation);
+  }
+
+  public ReportScaffoldPlace(String id, Operation operation) {
+    super(id, operation);
+  }
+
+  @Override
+  public void accept(ScaffoldPlaceProcessor visitor) {
+    visitor.process(this);
+  }
+
+  @Override
+  public <T> T acceptFilter(ScaffoldPlaceFilter<T> filter) {
+    return filter.filter(this);
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ScaffoldPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ScaffoldPlace.java
new file mode 100644
index 0000000..4cf866b
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ScaffoldPlace.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.scaffold.place;
+
+import com.google.gwt.app.place.Place;
+
+/**
+ * Base type of {@link Place}s for the Scaffold app.
+ */
+public abstract class ScaffoldPlace extends Place {
+  public abstract void accept(ScaffoldPlaceProcessor processor);
+  
+  public abstract <T> T acceptFilter(ScaffoldPlaceFilter<T> filter);
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ScaffoldPlaceFilter.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ScaffoldPlaceFilter.java
new file mode 100644
index 0000000..903a6fb
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ScaffoldPlaceFilter.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.scaffold.place;
+
+/**
+ * Implemented by objects that filter {@link ScaffoldPlace} subtypes to other
+ * objects.
+ * 
+ * @param <T> the type to filter to 
+ */
+public interface ScaffoldPlaceFilter<T> {
+  T filter(EmployeeScaffoldPlace place);
+  T filter(ListScaffoldPlace place);
+  T filter(ReportScaffoldPlace place);
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ScaffoldPlaceProcessor.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ScaffoldPlaceProcessor.java
new file mode 100644
index 0000000..3cc11d1
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ScaffoldPlaceProcessor.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.scaffold.place;
+
+/**
+ * Implemented by objects to allow them to process specific sub-types of
+ * {@link ScaffoldPlace} without resorting to instanceof checks.
+ */
+public interface ScaffoldPlaceProcessor {
+  void process(EmployeeScaffoldPlace place);
+
+  void process(ListScaffoldPlace place);
+
+  void process(ReportScaffoldPlace place);
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ScaffoldRecordPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ScaffoldRecordPlace.java
new file mode 100644
index 0000000..1fd97a5
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/scaffold/place/ScaffoldRecordPlace.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.scaffold.place;
+
+/**
+ * A place in the app focused on the {@link Values} of a particular type of
+ * {@link com.google.gwt.valuestore.shared.Record Record}.
+ */
+public abstract class ScaffoldRecordPlace extends ScaffoldPlace {
+
+  /**
+   * The things you do with a record, each of which is a different bookmarkable
+   * location in the scaffold app.
+   */
+  public enum Operation {
+    EDIT, DETAILS
+  }
+  private final String id;
+
+  private final Operation operation;
+
+  /**
+   * @param record
+   */
+  public ScaffoldRecordPlace(String id, Operation operation) {
+    assert null != id;
+    assert null != operation;
+
+    this.id = id;
+    this.operation = operation;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) {
+      return true;
+    }
+
+    if (obj == null) {
+      return false;
+    }
+
+    if (getClass() != obj.getClass()) {
+      return false;
+    }
+    ScaffoldRecordPlace other = (ScaffoldRecordPlace) obj;
+
+    if (!id.equals(other.id)) {
+      return false;
+    }
+
+    if (!operation.equals(other.operation)) {
+      return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * @return the id for this record
+   */
+  public String getId() {
+    return id;
+  }
+
+  /**
+   * @return what to do with the record here
+   */
+  public Operation getOperation() {
+    return operation;
+  }
+
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + id.hashCode();
+    result = prime * result + operation.hashCode();
+    return result;
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ExpensesKeyNameRenderer.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ExpensesKeyNameRenderer.java
index e80e17e..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ExpensesKeyNameRenderer.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ExpensesKeyNameRenderer.java
@@ -1,37 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.ui;
-
-import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
-import com.google.gwt.sample.expenses.gwt.request.ReportRecord;
-import com.google.gwt.user.client.ui.Renderer;
-import com.google.gwt.valuestore.shared.Record;
-
-/**
- * Renders the name of an {@link ExpensesKey}.
- */
-//TODO i18n
-public class ExpensesKeyNameRenderer implements Renderer<Record> {
-  public String render(Record record) {
-    if (record instanceof EmployeeRecord) {
-      return "Employees";
-    }
-    if (record instanceof ReportRecord) {
-      return "Reports";
-    }
-    throw new IllegalArgumentException("Unrecognized schema " + record);
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ListActivitiesMapper.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ListActivitiesMapper.java
new file mode 100644
index 0000000..09e6f4b
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ListActivitiesMapper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.ui;
+
+import com.google.gwt.app.place.Activity;
+import com.google.gwt.app.place.ActivityMapper;
+import com.google.gwt.app.place.PlaceController;
+import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
+import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
+import com.google.gwt.sample.expenses.gwt.request.ReportRecord;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ListScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.ui.employee.EmployeeListActivity;
+import com.google.gwt.sample.expenses.gwt.ui.report.ReportListActivity;
+
+/**
+ * The class that knows what {@link Activity} to run when the user goes to a
+ * particular {@link ListScaffoldPlace}.
+ * <p>
+ * To create a new list activity, copy one of the existing ones (and the
+ * corresponding view), and register it here.
+ */
+public class ListActivitiesMapper implements ActivityMapper<ListScaffoldPlace> {
+  private final ExpensesRequestFactory requests;
+  private final PlaceController<ScaffoldPlace> placeController;
+
+  public ListActivitiesMapper(ExpensesRequestFactory requests,
+      PlaceController<ScaffoldPlace> placeController) {
+    this.requests = requests;
+    this.placeController = placeController;
+  }
+
+  public Activity getActivity(ListScaffoldPlace place) {
+    if (place.getType().equals(EmployeeRecord.class)) {
+      return new EmployeeListActivity(requests, placeController);
+    }
+    if (place.getType().equals(ReportRecord.class)) {
+      return new ReportListActivity(requests, placeController);
+    }
+
+    throw new RuntimeException("Unable to locate a activity for " + place);
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ListPlaceRenderer.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ListPlaceRenderer.java
index 7b15630..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ListPlaceRenderer.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ListPlaceRenderer.java
@@ -1,42 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.ui;
-
-import com.google.gwt.sample.expenses.gwt.place.ExpensesListPlace;
-import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
-import com.google.gwt.sample.expenses.gwt.request.ReportRecord;
-import com.google.gwt.user.client.ui.Renderer;
-import com.google.gwt.valuestore.shared.Record;
-
-/**
- * Renders {@link ExpensesListPlace}s for display to users.
- */
-public class ListPlaceRenderer implements Renderer<ExpensesListPlace> {
-
-  public String render(ExpensesListPlace object) {
-    // TODO Will these class references prevent customized apps that keep this
-    // view builder around from stripping unsued entity types?
-   Class<? extends Record> type = object.getType();
-    if (type.equals(EmployeeRecord.class)) {
-      return "Employees";
-    }
-    if (type.equals(ReportRecord.class)) {
-      return "Reports";
-    }
-    
-    throw new IllegalArgumentException("Cannot render unknown type " + object);
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ScaffoldListPlaceRenderer.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ScaffoldListPlaceRenderer.java
new file mode 100644
index 0000000..0a5043d
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/ScaffoldListPlaceRenderer.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.ui;
+
+import com.google.gwt.app.util.Renderer;
+import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
+import com.google.gwt.sample.expenses.gwt.request.ReportRecord;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ListScaffoldPlace;
+import com.google.gwt.valuestore.shared.Record;
+
+/**
+ * Renders {@link ListScaffoldPlace}s for display to users.
+ */
+public class ScaffoldListPlaceRenderer implements Renderer<ListScaffoldPlace> {
+
+  public String render(ListScaffoldPlace object) {
+    // TODO These class comparisons are gross, find a cleaner way.
+    Class<? extends Record> type = object.getType();
+    if (type.equals(EmployeeRecord.class)) {
+      return "Employees";
+    }
+    if (type.equals(ReportRecord.class)) {
+      return "Reports";
+    }
+
+    throw new IllegalArgumentException("Cannot render unknown type " + object);
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/AllEmployeesRequester.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/AllEmployeesRequester.java
index 8c7b73b..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/AllEmployeesRequester.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/AllEmployeesRequester.java
@@ -1,42 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.ui.employee;
-
-import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
-import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
-import com.google.gwt.valuestore.client.ValuesListViewTable;
-import com.google.gwt.valuestore.shared.ValuesListView;
-
-/**
- * An implementation of {@link ValuesListView.Delegate} that requests all
- * {@link EmployeeKey} records.
- */
-public final class AllEmployeesRequester implements ValuesListView.Delegate {
-  private final ValuesListViewTable<EmployeeRecord> view;
-  private final ExpensesRequestFactory requests;
-
-  public AllEmployeesRequester(ExpensesRequestFactory requests,
-      ValuesListViewTable<EmployeeRecord> newView) {
-    this.view = newView;
-    this.requests = requests;
-  }
-
-  public void onRangeChanged(int start, int length) {
-    // TODO use start and length
-    requests.employeeRequest().findAllEmployees().forProperties(
-        view.getProperties()).to(view).fire();
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeActivitiesMapper.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeActivitiesMapper.java
new file mode 100644
index 0000000..c67d1d1
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeActivitiesMapper.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.ui.employee;
+
+import com.google.gwt.app.place.Activity;
+import com.google.gwt.app.place.ActivityMapper;
+import com.google.gwt.app.place.PlaceController;
+import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.EmployeeScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ScaffoldPlace;
+
+/**
+ * Maps {@link EmployeeScaffoldPlace} instances to the {@link Activity} to run.
+ */
+public class EmployeeActivitiesMapper implements
+    ActivityMapper<EmployeeScaffoldPlace> {
+  private final ExpensesRequestFactory requests;
+  private final PlaceController<ScaffoldPlace> placeController;
+
+  public EmployeeActivitiesMapper(ExpensesRequestFactory requests,
+      PlaceController<ScaffoldPlace> placeController) {
+    this.requests = requests;
+    this.placeController = placeController;
+  }
+
+  public Activity getActivity(EmployeeScaffoldPlace place) {
+    switch (place.getOperation()) {
+      case DETAILS:
+        return new EmployeeDetailsActivity(place.getId(), requests);
+
+      case EDIT:
+        return new EmployeeEditActivity(place.getId(), requests,
+            placeController);
+    }
+
+    throw new IllegalArgumentException("Unknown operation "
+        + place.getOperation());
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeDetailsActivity.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeDetailsActivity.java
new file mode 100644
index 0000000..68f1ea8
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeDetailsActivity.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.ui.employee;
+
+import com.google.gwt.app.place.AbstractActivity;
+import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
+import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.TakesValueList;
+import com.google.gwt.valuestore.shared.Value;
+
+import java.util.List;
+
+/**
+ * An {@link com.google.gwt.app.place.Activity Activity} that requests and displays detailed information on a
+ * given employee.
+ */
+public class EmployeeDetailsActivity extends AbstractActivity {
+  class RequestCallBack implements TakesValueList<EmployeeRecord> {
+    public void setValueList(List<EmployeeRecord> listOfOne) {
+      EmployeeRecord record = listOfOne.get(0);
+
+      StringBuilder list = new StringBuilder("<h3>Employee " + record.getId()
+          + "</h3>");
+
+      String user = record.getUserName();
+      list.append("<div>");
+      list.append("<label>").append("User Name: ").append("</label>");
+      list.append("<span>").append(user).append("</span>");
+      list.append("</div>");
+
+      list.append("<div>");
+      String display = record.getDisplayName();
+      list.append("<label>").append("Display Name: ").append("</label>");
+      list.append("<span>").append(display).append("</span>");
+      list.append("</div>");
+
+      callback.onStarted(new HTML(list.toString()));
+    }
+  }
+
+  private final ExpensesRequestFactory requests;
+
+  private String id;
+
+  private Callback callback;
+
+  public EmployeeDetailsActivity(String id, ExpensesRequestFactory requests) {
+    this.requests = requests;
+    this.id = id;
+  }
+
+  public void start(Callback callback) {
+    this.callback = callback;
+    requests.employeeRequest().findEmployee(Value.of(id)).to(
+        new RequestCallBack()).fire();
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeDetailsBuilder.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeDetailsBuilder.java
index b6cfa6f..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeDetailsBuilder.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeDetailsBuilder.java
@@ -1,38 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.ui.employee;
-
-import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
-
-/**
- * Renders report details to HTML.
- */
-public class EmployeeDetailsBuilder {
-
-  public void append(StringBuilder list, EmployeeRecord values) {
-    String user = values.getUserName();
-    list.append("<div>");
-    list.append("<label>").append("User Name: ").append("</label>");
-    list.append("<span>").append(user).append("</span>");
-    list.append("</div>");
-
-    list.append("<div>");
-    String display = values.getDisplayName();
-    list.append("<label>").append("Display Name: ").append("</label>");
-    list.append("<span>").append(display).append("</span>");
-    list.append("</div>");
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeEditActivity.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeEditActivity.java
new file mode 100644
index 0000000..64eda5d
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeEditActivity.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.ui.employee;
+
+import com.google.gwt.app.place.AbstractActivity;
+import com.google.gwt.app.place.PlaceController;
+import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
+import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ListScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ScaffoldPlace;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.TakesValueList;
+import com.google.gwt.valuestore.shared.DeltaValueStore;
+import com.google.gwt.valuestore.shared.Value;
+import com.google.gwt.valuestore.ui.RecordEditView;
+
+import java.util.List;
+
+/**
+ * An activity that requests all info on an employee, allows the user to  edit it,
+ * and persists the results. 
+ */
+public class EmployeeEditActivity extends AbstractActivity implements
+    RecordEditView.Delegate {
+  class RequestCallBack implements TakesValueList<EmployeeRecord> {
+    public void setValueList(List<EmployeeRecord> listOfOne) {
+      view.setEnabled(true);
+      EmployeeRecord record = listOfOne.get(0);
+      view.setValue(record);
+      callback.onStarted(view.asWidget());
+    }
+  }
+
+  private static RecordEditView<EmployeeRecord> defaultView;
+
+  private static RecordEditView<EmployeeRecord> getDefaultView() {
+    if (defaultView == null) {
+      defaultView = new EmployeeEditView();
+    }
+    return defaultView;
+  }
+
+  private final ExpensesRequestFactory requests;
+  private final RecordEditView<EmployeeRecord> view;
+  private final String id;
+  private final PlaceController<ScaffoldPlace> placeController;
+
+  private DeltaValueStore deltas;
+  private Callback callback;
+
+  /**
+   * Creates an activity that uses the default singleton view instance.
+   */
+  public EmployeeEditActivity(String id, ExpensesRequestFactory requests,
+      PlaceController<ScaffoldPlace> placeController) {
+    this(id, getDefaultView(), requests, placeController);
+  }
+
+  /**
+   * Creates an activity that uses its own view instance.
+   */
+  public EmployeeEditActivity(String id, RecordEditView<EmployeeRecord> view,
+      ExpensesRequestFactory requests,
+      PlaceController<ScaffoldPlace> placeController) {
+    this.requests = requests;
+    this.id = id;
+    this.view = view;
+    this.deltas = requests.getValueStore().spawnDeltaView();
+    this.placeController = placeController;
+    view.setDelegate(this);
+    view.setDeltaValueStore(deltas);
+  }
+
+  public void saveClicked() {
+    if (deltas.isChanged()) {
+      view.setEnabled(false);
+      DeltaValueStore toCommit = deltas;
+      deltas = null;
+      requests.syncRequest(toCommit).fire(); // TODO Need callback, idiot
+      placeController.goTo(new ListScaffoldPlace(EmployeeRecord.class));
+    }
+  }
+
+  public void start(Callback callback) {
+    this.callback = callback;
+    requests.employeeRequest().findEmployee(Value.of(id)).to(
+        new RequestCallBack()).fire();
+  }
+
+  @Override
+  public boolean willStop() {
+    return deltas == null || !deltas.isChanged()
+        || Window.confirm("Dude! Really drop your edits?");
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeEditView.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeEditView.java
new file mode 100644
index 0000000..f08842d
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeEditView.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.ui.employee;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.SpanElement;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.uibinder.client.UiHandler;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HTMLPanel;
+import com.google.gwt.user.client.ui.TextBox;
+import com.google.gwt.valuestore.shared.DeltaValueStore;
+import com.google.gwt.valuestore.shared.Property;
+import com.google.gwt.valuestore.ui.RecordEditView;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Edit view for employee records.
+ */
+public class EmployeeEditView extends Composite implements
+    RecordEditView<EmployeeRecord> {
+  interface Binder extends UiBinder<HTMLPanel, EmployeeEditView> {
+  }
+
+  private static final Binder BINDER = GWT.create(Binder.class);
+
+  @UiField
+  TextBox displayName;
+  @UiField
+  TextBox userName;
+  @UiField
+  Button save;
+  @UiField
+  SpanElement idSpan;
+
+  private Delegate delegate;
+  private DeltaValueStore deltas;
+  
+  private EmployeeRecord record;
+
+  public EmployeeEditView() {
+    initWidget(BINDER.createAndBindUi(this));
+  }
+
+  public EmployeeEditView asWidget() {
+    return this;
+  }
+
+  public Set<Property<?>> getProperties() {
+    Set<Property<?>> rtn = new HashSet<Property<?>>();
+    rtn.add(EmployeeRecord.userName);
+    rtn.add(EmployeeRecord.displayName);
+    return rtn;
+  }
+
+  public void setDelegate(Delegate delegate) {
+    this.delegate = delegate;
+  }
+
+  public void setDeltaValueStore(DeltaValueStore deltas) {
+    this.deltas = deltas;
+  }
+
+  public void setEnabled(boolean enabled) {
+    displayName.setEnabled(enabled);
+    userName.setEnabled(enabled);
+    save.setEnabled(enabled);
+  }
+
+  public void setValue(EmployeeRecord value) {
+    this.record = value;
+    displayName.setValue(record.getDisplayName());
+    userName.setValue(record.getUserName());
+    idSpan.setInnerText(record.getId());
+  }
+
+  @UiHandler("displayName")
+  void onDisplayNameChange(ValueChangeEvent<String> event) {
+    deltas.set(EmployeeRecord.displayName, record, event.getValue());
+  }
+
+  @UiHandler("save")
+  void onSave(@SuppressWarnings("unused") ClickEvent event) {
+    delegate.saveClicked();
+  }
+
+  @UiHandler("userName")
+  void onUserNameChange(ValueChangeEvent<String> event) {
+    deltas.set(EmployeeRecord.userName, record, event.getValue());
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeEditView.ui.xml b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeEditView.ui.xml
new file mode 100644
index 0000000..9847a45
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeEditView.ui.xml
@@ -0,0 +1,12 @@
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
+  xmlns:g='urn:import:com.google.gwt.user.client.ui' xmlns:b='urn:import:com.google.gwt.bikeshed.list.client'>
+  <g:HTMLPanel>
+    <h3><ui:msg>Edit Employee <span ui:field='idSpan' /></ui:msg></h3>
+
+    <span>Display Name:</span> <g:TextBox ui:field='displayName'></g:TextBox>
+    <span>User Name:</span> <g:TextBox ui:field='userName'></g:TextBox>
+
+    <g:Button ui:field='save'>Save</g:Button>
+  </g:HTMLPanel>
+</ui:UiBinder>
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeListActivity.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeListActivity.java
new file mode 100644
index 0000000..1277e26
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeListActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.ui.employee;
+
+import com.google.gwt.app.place.PlaceController;
+import com.google.gwt.requestfactory.shared.EntityListRequest;
+import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
+import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.EmployeeScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ScaffoldRecordPlace.Operation;
+import com.google.gwt.valuestore.ui.AbstractRecordListActivity;
+import com.google.gwt.valuestore.ui.RecordListView;
+
+/**
+ * Activity that requests and displays all {@EmployeeRecord}
+ * records.
+ */
+public class EmployeeListActivity extends
+    AbstractRecordListActivity<EmployeeRecord> {
+
+  private static RecordListView<EmployeeRecord> defaultView;
+
+  private static RecordListView<EmployeeRecord> getDefaultView() {
+    if (defaultView == null) {
+      defaultView = new EmployeeListView();
+    }
+    return defaultView;
+  }
+
+  private final ExpensesRequestFactory requests;
+  private final PlaceController<ScaffoldPlace> placeController;
+
+  /**
+   * Creates an activity that uses the default singleton view instance.
+   */
+  public EmployeeListActivity(ExpensesRequestFactory requests,
+      PlaceController<ScaffoldPlace> placeController) {
+    this(requests, getDefaultView(), placeController);
+  }
+
+  /**
+   * Creates an activity that uses its own view instance.
+   */
+  public EmployeeListActivity(ExpensesRequestFactory requests,
+      RecordListView<EmployeeRecord> view,
+      PlaceController<ScaffoldPlace> placeController) {
+    super(view);
+    this.requests = requests;
+    this.placeController = placeController;
+  }
+
+  public void edit(EmployeeRecord record) {
+    placeController.goTo(new EmployeeScaffoldPlace(record, Operation.EDIT));
+  }
+
+  public void showDetails(EmployeeRecord record) {
+    placeController.goTo(new EmployeeScaffoldPlace(record, Operation.DETAILS));
+  }
+
+  protected EntityListRequest<EmployeeRecord> createRequest() {
+    return requests.employeeRequest().findAllEmployees();
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeListView.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeListView.java
index c2c6f83..0d2ce87 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeListView.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeListView.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,77 +15,41 @@
  */
 package com.google.gwt.sample.expenses.gwt.ui.employee;
 
-import com.google.gwt.bikeshed.cells.client.ActionCell;
-import com.google.gwt.bikeshed.list.client.Column;
-import com.google.gwt.bikeshed.list.client.Header;
-import com.google.gwt.bikeshed.list.client.IdentityColumn;
-import com.google.gwt.bikeshed.list.client.TextColumn;
-import com.google.gwt.bikeshed.list.client.TextHeader;
-import com.google.gwt.sample.expenses.gwt.place.ExpensesPlaces;
+import com.google.gwt.bikeshed.list.client.PagingTableListView;
+import com.google.gwt.core.client.GWT;
 import com.google.gwt.sample.expenses.gwt.request.EmployeeRecord;
-import com.google.gwt.valuestore.client.ValuesListViewTable;
-import com.google.gwt.valuestore.shared.Property;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.HTMLPanel;
+import com.google.gwt.valuestore.ui.AbstractRecordListView;
+import com.google.gwt.valuestore.ui.PropertyColumn;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 
 /**
- * {@link ValuesListViewTable} specialized to {@link EmployeeKey} values.
- * <p>
- * TODO The bulk of this should be in a <g:table> in a ui.xml file
+ * {@link AbstractRecordListView} specialized to {@link EmployeeKey} values.
  */
-public class EmployeeListView extends ValuesListViewTable<EmployeeRecord> {
-  private static final List<Property<?>> properties;
-  static {
-    List<Property<?>> p = new ArrayList<Property<?>>();
-    p.add(EmployeeRecord.userName);
-    p.add(EmployeeRecord.displayName);
-    properties = Collections.unmodifiableList(p);
+public class EmployeeListView extends AbstractRecordListView<EmployeeRecord> {
+  interface Binder extends UiBinder<HTMLPanel, EmployeeListView> {
   }
 
-  private static List<Column<EmployeeRecord, ?, ?>> getColumns(
-      final ExpensesPlaces places) {
-    List<Column<EmployeeRecord, ?, ?>> columns = new ArrayList<Column<EmployeeRecord, ?, ?>>();
+  private static final Binder BINDER = GWT.create(Binder.class);
 
-    columns.add(new TextColumn<EmployeeRecord>() {
-      @Override
-      public String getValue(EmployeeRecord object) {
-        return object.getUserName();
-      }
-    });
+  @UiField PagingTableListView<EmployeeRecord> table;
 
-    columns.add(new TextColumn<EmployeeRecord>() {
-      @Override
-      public String getValue(EmployeeRecord object) {
-        return object.getDisplayName();
-      }
-    });
+  public EmployeeListView() {
+    init(BINDER.createAndBindUi(this), table, getColumns());
+  }
 
-    columns.add(new IdentityColumn<EmployeeRecord>(
-        new ActionCell<EmployeeRecord>("Show",
-            places.<EmployeeRecord> getDetailsGofer())));
+  protected List<PropertyColumn<EmployeeRecord, ?>> getColumns() {
+    // TODO These should be <g:col> elements in a <g:table> in the ui.xml file
 
-//    columns.add(new IdentityColumn<EmployeeRecord>(
-//        new ActionCell<EmployeeRecord>("Edit",
-//            places.<EmployeeRecord> getEditorGofer())));
+    List<PropertyColumn<EmployeeRecord, ?>> columns = new ArrayList<PropertyColumn<EmployeeRecord, ?>>();
+
+    columns.add(PropertyColumn.<EmployeeRecord> getStringPropertyColumn(EmployeeRecord.userName));
+    columns.add(PropertyColumn.<EmployeeRecord> getStringPropertyColumn(EmployeeRecord.displayName));
 
     return columns;
   }
-
-  private static List<Header<?>> getHeaders() {
-    List<Header<?>> headers = new ArrayList<Header<?>>();
-    for (final Property<?> property : properties) {
-      headers.add(new TextHeader(property.getName()));
-    }
-    return headers;
-  }
-
-  public EmployeeListView(String headingMessage, ExpensesPlaces places) {
-    super(headingMessage, getColumns(places), getHeaders());
-  }
-
-  public List<Property<?>> getProperties() {
-    return properties;
-  }
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeListView.ui.xml b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeListView.ui.xml
new file mode 100644
index 0000000..a9b3748
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/employee/EmployeeListView.ui.xml
@@ -0,0 +1,9 @@
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
+  xmlns:g='urn:import:com.google.gwt.user.client.ui'
+  xmlns:b='urn:import:com.google.gwt.bikeshed.list.client'>
+  <g:HTMLPanel>
+    <h3><ui:msg>Employees</ui:msg></h3>
+    <b:PagingTableListView ui:field='table'/>
+  </g:HTMLPanel>
+</ui:UiBinder>
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/AllReportsRequester.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/AllReportsRequester.java
index 8ae0359..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/AllReportsRequester.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/AllReportsRequester.java
@@ -1,42 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.ui.report;
-
-import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
-import com.google.gwt.sample.expenses.gwt.request.ReportRecord;
-import com.google.gwt.valuestore.client.ValuesListViewTable;
-import com.google.gwt.valuestore.shared.ValuesListView;
-
-/**
- * An implementation of {@link ValuesListView.Delegate} that requests all
- * {@link ReportKey} records.
- */
-public final class AllReportsRequester implements ValuesListView.Delegate {
-  private final ValuesListViewTable<ReportRecord> view;
-  private final ExpensesRequestFactory requests;
-
-  public AllReportsRequester(ExpensesRequestFactory requests,
-      ValuesListViewTable<ReportRecord> newView) {
-    this.view = newView;
-    this.requests = requests;
-  }
-
-  public void onRangeChanged(int start, int length) {
-    // TODO use start and length
-    requests.reportRequest().findAllReports().forProperties(
-        view.getProperties()).to(view).fire();
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportActivitiesMapper.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportActivitiesMapper.java
new file mode 100644
index 0000000..da3226a
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportActivitiesMapper.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.ui.report;
+
+import com.google.gwt.app.place.Activity;
+import com.google.gwt.app.place.ActivityMapper;
+import com.google.gwt.app.place.PlaceController;
+import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ReportScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ScaffoldPlace;
+
+/**
+ * Maps {@link ReportScaffoldPlace} instances to the {@link Activity} to run.
+ */
+public class ReportActivitiesMapper implements
+    ActivityMapper<ReportScaffoldPlace> {
+  private final ExpensesRequestFactory requests;
+  private final PlaceController<ScaffoldPlace> placeController;
+
+  public ReportActivitiesMapper(ExpensesRequestFactory requests, PlaceController<ScaffoldPlace> placeController) {
+    this.requests = requests;
+    this.placeController = placeController;
+  }
+
+  public Activity getActivity(ReportScaffoldPlace place) {
+    switch (place.getOperation()) {
+      case DETAILS:
+        return new ReportDetailsActivity(place.getId(), requests);
+      case EDIT:
+        return new ReportEditActivity(place.getId(), requests, placeController);
+    }
+
+    throw new IllegalArgumentException("Unknown operation "
+        + place.getOperation());
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportDetailsActivity.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportDetailsActivity.java
new file mode 100644
index 0000000..5a8cd42
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportDetailsActivity.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.ui.report;
+
+import com.google.gwt.app.place.AbstractActivity;
+import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
+import com.google.gwt.sample.expenses.gwt.request.ReportRecord;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.TakesValueList;
+import com.google.gwt.valuestore.shared.Value;
+
+import java.util.List;
+
+/**
+ * An {@link com.google.gwt.app.place.Activity Activity} that requests and
+ * displays detailed information on a given report.
+ */
+public class ReportDetailsActivity extends AbstractActivity {
+  class RequestCallBack implements TakesValueList<ReportRecord> {
+    public void setValueList(List<ReportRecord> listOfOne) {
+      ReportRecord record = listOfOne.get(0);
+
+      StringBuilder list = new StringBuilder("<h3>Employee " + record.getId()
+          + "</h3>");
+
+      String purpose = record.getPurpose();
+      list.append("<div>");
+      list.append("<label>").append("Purpose: ").append("</label>");
+      list.append("<span>").append(purpose).append("</span>");
+      list.append("</div>");
+
+      list.append("<div>");
+      String created = record.getCreated().toString();
+      list.append("<label>").append("Created: ").append("</label>");
+      list.append("<span>").append(created).append("</span>");
+      list.append("</div>");
+
+      callback.onStarted(new HTML(list.toString()));
+    }
+  }
+
+  private final ExpensesRequestFactory requests;
+
+  private String id;
+
+  private Callback callback;
+
+  public ReportDetailsActivity(String id, ExpensesRequestFactory requests) {
+    this.requests = requests;
+    this.id = id;
+  }
+
+  public void start(Callback callback) {
+    this.callback = callback;
+    requests.reportRequest().findReport(Value.of(id)).to(new RequestCallBack()).fire();
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportDetailsBuilder.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportDetailsBuilder.java
index 613316e..e69de29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportDetailsBuilder.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportDetailsBuilder.java
@@ -1,38 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.gwt.ui.report;
-
-import com.google.gwt.sample.expenses.gwt.request.ReportRecord;
-
-/**
- * Renders report details to HTML.
- */
-public class ReportDetailsBuilder {
-
-  public void append(StringBuilder list, ReportRecord values) {
-    String purpose = values.getPurpose();
-    list.append("<div>");
-    list.append("<label>").append("Purpose: ").append("</label>");
-    list.append("<span>").append(purpose).append("</span>");
-    list.append("</div>");
-
-    list.append("<div>");
-    String created = values.getCreated().toString();
-    list.append("<label>").append("Created: ").append("</label>");
-    list.append("<span>").append(created).append("</span>");
-    list.append("</div>");
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportEditActivity.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportEditActivity.java
new file mode 100644
index 0000000..10a9238
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportEditActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.ui.report;
+
+import com.google.gwt.app.place.AbstractActivity;
+import com.google.gwt.app.place.PlaceController;
+import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ScaffoldPlace;
+import com.google.gwt.user.client.ui.Label;
+
+/**
+ * An activity that requests all info on a report, allows the user to edit it,
+ * and persists the results.
+ */
+public class ReportEditActivity extends AbstractActivity {
+
+  public ReportEditActivity(String id, ExpensesRequestFactory requests,
+      PlaceController<ScaffoldPlace> placeController) {
+    // TODO Auto-generated constructor stub
+  }
+
+  public void start(Callback callback) {
+    callback.onStarted(new Label("tbd"));
+  }
+
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportListActivity.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportListActivity.java
new file mode 100644
index 0000000..4e2014e
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportListActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.sample.expenses.gwt.ui.report;
+
+import com.google.gwt.app.place.PlaceController;
+import com.google.gwt.requestfactory.shared.EntityListRequest;
+import com.google.gwt.sample.expenses.gwt.request.ExpensesRequestFactory;
+import com.google.gwt.sample.expenses.gwt.request.ReportRecord;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ReportScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ScaffoldPlace;
+import com.google.gwt.sample.expenses.gwt.scaffold.place.ScaffoldRecordPlace.Operation;
+import com.google.gwt.valuestore.ui.AbstractRecordListActivity;
+import com.google.gwt.valuestore.ui.RecordListView;
+
+/**
+ * Activity that requests and displays all {@ReportRecord}
+ * records.
+ */
+public final class ReportListActivity extends
+    AbstractRecordListActivity<ReportRecord> {
+
+  private static RecordListView<ReportRecord> defaultView;
+
+  private static RecordListView<ReportRecord> getDefaultView() {
+    if (defaultView == null) {
+      defaultView = new ReportListView();
+    }
+    return defaultView;
+  }
+
+  private final ExpensesRequestFactory requests;
+  private final PlaceController<ScaffoldPlace> placeController;
+
+  /**
+   * Creates an activity that uses the default singleton view instance.
+   */
+  public ReportListActivity(ExpensesRequestFactory requests,
+      PlaceController<ScaffoldPlace> placeController) {
+    this(requests, getDefaultView(), placeController);
+  }
+
+  /**
+   * Creates an activity that uses its own view instance.
+   */
+  public ReportListActivity(ExpensesRequestFactory requests,
+      RecordListView<ReportRecord> view,
+      PlaceController<ScaffoldPlace> placeController) {
+    super(view);
+    this.requests = requests;
+    this.placeController = placeController;
+  }
+
+  public void edit(ReportRecord record) {
+    placeController.goTo(new ReportScaffoldPlace(record, Operation.EDIT));
+  }
+
+  public void showDetails(ReportRecord record) {
+    placeController.goTo(new ReportScaffoldPlace(record, Operation.DETAILS));
+  }
+
+  protected EntityListRequest<ReportRecord> createRequest() {
+    return requests.reportRequest().findAllReports();
+  }
+}
\ No newline at end of file
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportListView.java b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportListView.java
index 860e7a8..13d9690 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportListView.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportListView.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,83 +15,48 @@
  */
 package com.google.gwt.sample.expenses.gwt.ui.report;
 
-import com.google.gwt.bikeshed.cells.client.ActionCell;
-import com.google.gwt.bikeshed.cells.client.DateCell;
-import com.google.gwt.bikeshed.list.client.Column;
-import com.google.gwt.bikeshed.list.client.Header;
-import com.google.gwt.bikeshed.list.client.IdentityColumn;
-import com.google.gwt.bikeshed.list.client.SimpleColumn;
-import com.google.gwt.bikeshed.list.client.TextColumn;
-import com.google.gwt.bikeshed.list.client.TextHeader;
+import com.google.gwt.app.util.DateTimeFormatRenderer;
+import com.google.gwt.bikeshed.list.client.PagingTableListView;
+import com.google.gwt.core.client.GWT;
 import com.google.gwt.i18n.client.DateTimeFormat;
-import com.google.gwt.sample.expenses.gwt.place.ExpensesPlaces;
 import com.google.gwt.sample.expenses.gwt.request.ReportRecord;
-import com.google.gwt.valuestore.client.ValuesListViewTable;
-import com.google.gwt.valuestore.shared.Property;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.HTMLPanel;
+import com.google.gwt.valuestore.ui.AbstractRecordListView;
+import com.google.gwt.valuestore.ui.PropertyColumn;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
 /**
- * {@link ValuesListViewTable} specialized to {@link ReportKey} values.
+ * {@link AbstractRecordListView} specialized to {@link EmployeeKey} values.
  * <p>
- * TODO The bulk of this should be in a <g:table> in a ui.xml file
+ * TODO This should be a <g:table> in a ui.xml file
  */
-public class ReportListView extends ValuesListViewTable<ReportRecord> {
-  private static final List<Property<?>> properties;
-  static {
-    List<Property<?>> p = new ArrayList<Property<?>>();
-    p.add(ReportRecord.created);
-    p.add(ReportRecord.purpose);
-    properties = Collections.unmodifiableList(p);
+public class ReportListView extends AbstractRecordListView<ReportRecord> {
+  interface Binder extends UiBinder<HTMLPanel, ReportListView> {
   }
 
-  private static List<Column<ReportRecord, ?, ?>> getColumns(
-      final ExpensesPlaces places) {
-    List<Column<ReportRecord, ?, ?>> columns = new ArrayList<Column<ReportRecord, ?, ?>>();
+  private static final Binder BINDER = GWT.create(Binder.class);
 
-    DateCell dateCell = new DateCell(DateTimeFormat.getShortDateFormat());
-    columns.add(new SimpleColumn<ReportRecord, Date>(dateCell) {
-      @Override
-      public Date getValue(ReportRecord object) {
-        return object.getCreated();
-      }
-    });
+  @UiField PagingTableListView<ReportRecord> table;
 
-    columns.add(new TextColumn<ReportRecord>() {
-      @Override
-      public String getValue(ReportRecord object) {
-        return object.getPurpose();
-      }
-    });
+  public ReportListView() {
+    init(BINDER.createAndBindUi(this), table, getColumns());
+  }
 
-    columns.add(new IdentityColumn<ReportRecord>(
-        new ActionCell<ReportRecord>("Show",
-            places.<ReportRecord> getDetailsGofer())));
 
-//    columns.add(new IdentityColumn<ReportRecord>(
-//        new ActionCell<ReportRecord>("Edit",
-//            places.<ReportRecord> getEditorGofer())));
+  protected List<PropertyColumn<ReportRecord, ?>> getColumns() {
+    // TODO These should be <g:col> elements in a <g:table> in the ui.xml file
+
+    List<PropertyColumn<ReportRecord, ?>> columns = new ArrayList<PropertyColumn<ReportRecord, ?>>();
+
+    columns.add(new PropertyColumn<ReportRecord, Date>(ReportRecord.created,
+        new DateTimeFormatRenderer(DateTimeFormat.getShortDateFormat())));
+    columns.add(PropertyColumn.<ReportRecord> getStringPropertyColumn(ReportRecord.purpose));
 
     return columns;
   }
-
-  private static List<Header<?>> getHeaders() {
-    List<Header<?>> headers = new ArrayList<Header<?>>();
-    for (final Property<?> property : properties) {
-      headers.add(new TextHeader(property.getName()));
-    }
-    return headers;
-  }
-
-  public ReportListView(String headingMessage, ExpensesPlaces places) {
-    super(headingMessage, getColumns(places), getHeaders());
-  }
-
-  public List<Property<?>> getProperties() {
-    return properties;
-  }
-
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportListView.ui.xml b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportListView.ui.xml
new file mode 100644
index 0000000..82ec73d
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gwt/ui/report/ReportListView.ui.xml
@@ -0,0 +1,9 @@
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
+  xmlns:g='urn:import:com.google.gwt.user.client.ui'
+  xmlns:b='urn:import:com.google.gwt.bikeshed.list.client'>
+  <g:HTMLPanel>
+    <h3><ui:msg>Reports</ui:msg></h3>
+    <b:PagingTableListView ui:field='table'/>
+  </g:HTMLPanel>
+</ui:UiBinder>
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Employee.java b/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Employee.java
index 9a5dfc4..5c96797 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Employee.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Employee.java
@@ -17,6 +17,7 @@
 
 import org.datanucleus.jpa.annotations.Extension;
 
+import java.util.Collections;
 import java.util.List;
 
 import javax.persistence.Column;
@@ -84,6 +85,10 @@
     }
   }
 
+  public static List<Employee> findListOfOneEmployee(String id) {
+    return Collections.singletonList(findEmployee(id));
+  }
+  
   private String userName;
 
   private String displayName;
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Report.java b/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Report.java
index d661122..a1f2b1c 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Report.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Report.java
@@ -17,6 +17,7 @@
 
 import org.datanucleus.jpa.annotations.Extension;
 
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
@@ -62,6 +63,10 @@
     }
   }
 
+  public static List<Report> findListOfOneReport(String id) {
+    return Collections.singletonList(findReport(id));
+  }
+  
   public static Report findReport(String id) {
     if (id == null) {
       return null;
@@ -73,7 +78,7 @@
       em.close();
     }
   }
-
+  
   @SuppressWarnings("unchecked")
   public static List<Report> findReportEntries(int firstResult, int maxResults) {
     EntityManager em = entityManager();
diff --git a/bikeshed/src/com/google/gwt/user/client/ui/HasErrors.java b/bikeshed/src/com/google/gwt/user/client/ui/HasErrors.java
index 811b091..e69de29 100644
--- a/bikeshed/src/com/google/gwt/user/client/ui/HasErrors.java
+++ b/bikeshed/src/com/google/gwt/user/client/ui/HasErrors.java
@@ -1,26 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.user.client.ui;
-
-/**
- * Implemented by input objects that can present validation
- * errors.
- */
-public interface HasErrors {
-  void addError(ValidationError e);
-
-  void resetErrors();
-}
diff --git a/bikeshed/src/com/google/gwt/user/client/ui/Renderer.java b/bikeshed/src/com/google/gwt/user/client/ui/Renderer.java
index 9c5a25f..e69de29 100644
--- a/bikeshed/src/com/google/gwt/user/client/ui/Renderer.java
+++ b/bikeshed/src/com/google/gwt/user/client/ui/Renderer.java
@@ -1,29 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.user.client.ui;
-
-/**
- * An object that can render other objects of a particular type into plain-text
- * form.
- *
- * @param <T> the type to render
- */
-public interface Renderer<T> {
-  /**
-   * Renders {@code object} as plain text.
-   */
-  String render(T object);
-}
diff --git a/bikeshed/src/com/google/gwt/user/client/ui/TakesValue.java b/bikeshed/src/com/google/gwt/user/client/ui/TakesValue.java
index c07ddb4..2b91a1b 100644
--- a/bikeshed/src/com/google/gwt/user/client/ui/TakesValue.java
+++ b/bikeshed/src/com/google/gwt/user/client/ui/TakesValue.java
@@ -16,7 +16,7 @@
 package com.google.gwt.user.client.ui;
 
 /**
- * Implemented by objects that want to be kept apprised of a value.
+ * Implemented by objects that hold a value.
  *
  * @param <V> value type
  */
diff --git a/bikeshed/src/com/google/gwt/user/client/ui/TakesValueList.java b/bikeshed/src/com/google/gwt/user/client/ui/TakesValueList.java
index f1ea31f..46883ee 100644
--- a/bikeshed/src/com/google/gwt/user/client/ui/TakesValueList.java
+++ b/bikeshed/src/com/google/gwt/user/client/ui/TakesValueList.java
@@ -18,7 +18,7 @@
 import java.util.List;
 
 /**
- * Implemented by objects that want to be kept apprised of a list of values.
+ * Implemented by objects that display a list of values.
  *
  * @param <V> value type
  */
diff --git a/bikeshed/src/com/google/gwt/user/client/ui/ValidationError.java b/bikeshed/src/com/google/gwt/user/client/ui/ValidationError.java
index c23f27d..e69de29 100644
--- a/bikeshed/src/com/google/gwt/user/client/ui/ValidationError.java
+++ b/bikeshed/src/com/google/gwt/user/client/ui/ValidationError.java
@@ -1,23 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.user.client.ui;
-
-/**
- *
- */
-public interface ValidationError {
-
-}
diff --git a/bikeshed/src/com/google/gwt/user/client/ui/ValueListBox.java b/bikeshed/src/com/google/gwt/user/client/ui/ValueListBox.java
index 50a93cf..54cec5f 100644
--- a/bikeshed/src/com/google/gwt/user/client/ui/ValueListBox.java
+++ b/bikeshed/src/com/google/gwt/user/client/ui/ValueListBox.java
@@ -36,9 +36,6 @@
   private ArrayList<T> indexToValue = new ArrayList<T>();
   private Map<T, Integer> valueToIndex = new HashMap<T, Integer>();
 
-  // TODO ValueSetListBox<T> extends Composite implements HasValue<Set<T>>,
-  // HasValueMap<T>
-
   public ValueListBox() {
     initWidget(new ListBox(false));
   }
diff --git a/bikeshed/src/com/google/gwt/valuestore/ValueStore.gwt.xml b/bikeshed/src/com/google/gwt/valuestore/ValueStore.gwt.xml
index 42a432c..bb7f5ed 100644
--- a/bikeshed/src/com/google/gwt/valuestore/ValueStore.gwt.xml
+++ b/bikeshed/src/com/google/gwt/valuestore/ValueStore.gwt.xml
@@ -19,5 +19,7 @@
   <inherits name='com.google.gwt.user.User'/>
 
   <source path="client"/>
+  <source path="shared"/>
+  <source path="ui"/>
   <source path="shared" excludes="ServerType" />
 </module>
diff --git a/bikeshed/src/com/google/gwt/valuestore/client/RecordKey.java b/bikeshed/src/com/google/gwt/valuestore/client/RecordKey.java
index 0f10975..8d365b3 100644
--- a/bikeshed/src/com/google/gwt/valuestore/client/RecordKey.java
+++ b/bikeshed/src/com/google/gwt/valuestore/client/RecordKey.java
@@ -19,6 +19,7 @@
 import com.google.gwt.valuestore.shared.impl.RecordJsoImpl;
 import com.google.gwt.valuestore.shared.impl.RecordSchema;
 
+
 /**
  * The key used to store {@link com.google.gwt.valuestore.shared.Record Record}s
  * in {@link com.google.gwt.valuestore.shared.ValueStore ValueStore}.
diff --git a/bikeshed/src/com/google/gwt/valuestore/client/ValueStoreListViewAdapter.java b/bikeshed/src/com/google/gwt/valuestore/client/ValueStoreListViewAdapter.java
index ba2ded5..e69de29 100644
--- a/bikeshed/src/com/google/gwt/valuestore/client/ValueStoreListViewAdapter.java
+++ b/bikeshed/src/com/google/gwt/valuestore/client/ValueStoreListViewAdapter.java
@@ -1,40 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.valuestore.client;
-
-import com.google.gwt.bikeshed.list.shared.AsyncListViewAdapter;
-import com.google.gwt.user.client.ui.TakesValueList;
-import com.google.gwt.valuestore.shared.Record;
-
-import java.util.List;
-
-/**
- * Simple adapter from a {@link com.google.gwt.valuestore.shared.ValueStore
- * ValueStore} to an {@link AsyncListViewAdapter}.
- * <p>
- * TODO: pay attention to the visible range info that subclasses receive via
- * {@link #onRangeChanged}
- *
- * @param <K> the ValuesKey of the records to display
- */
-public abstract class ValueStoreListViewAdapter<K extends Record> extends
-    AsyncListViewAdapter<K> implements TakesValueList<K> {
-
-  public void setValueList(List<K> newValues) {
-    updateDataSize(newValues.size(), true);
-    updateViewData(0, newValues.size(), newValues);
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/valuestore/client/ValuesListViewTable.java b/bikeshed/src/com/google/gwt/valuestore/client/ValuesListViewTable.java
index 118b8f0..e69de29 100644
--- a/bikeshed/src/com/google/gwt/valuestore/client/ValuesListViewTable.java
+++ b/bikeshed/src/com/google/gwt/valuestore/client/ValuesListViewTable.java
@@ -1,115 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.valuestore.client;
-
-import com.google.gwt.bikeshed.list.client.Column;
-import com.google.gwt.bikeshed.list.client.Header;
-import com.google.gwt.bikeshed.list.client.ListView;
-import com.google.gwt.bikeshed.list.client.PagingTableListView;
-import com.google.gwt.bikeshed.list.shared.Range;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.dom.client.HeadingElement;
-import com.google.gwt.uibinder.client.UiBinder;
-import com.google.gwt.uibinder.client.UiField;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.HTMLPanel;
-import com.google.gwt.valuestore.shared.Property;
-import com.google.gwt.valuestore.shared.Record;
-import com.google.gwt.valuestore.shared.ValuesListView;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * A widget that displays lists of {@link com.google.gwt.valuestore.shared.ValueStore
- * ValueStore} records in a {@link PagingTableListView}.
- *
- * @param <R> the type of the records
- */
-public abstract class ValuesListViewTable<R extends Record> extends
-    Composite implements ValuesListView<R> {
-  interface Binder extends UiBinder<HTMLPanel, ValuesListViewTable<?>> {
-  }
-
-  private static final Binder BINDER = GWT.create(Binder.class);
-
-  public ValuesListView.Delegate delegate;
-  public ValueStoreListViewAdapter<R> adapter;
-
-  @UiField(provided = true)
-  PagingTableListView<R> table;
-  @UiField
-  HeadingElement heading;
-
-  public ValuesListViewTable(String headingMessage,
-      List<Column<R, ?, ?>> columns, List<Header<?>> headers) {
-    adapter = createAdapter();
-    table = new PagingTableListView<R>(100);
-    adapter.addView(table);
-    final Iterator<Header<?>> nextHeader = headers.iterator();
-    for (Column<R, ?, ?> column : columns) {
-      if (nextHeader.hasNext()) {
-        table.addColumn(column, nextHeader.next());
-      } else {
-        table.addColumn(column);
-      }
-    }
-    initWidget(BINDER.createAndBindUi(this));
-
-    heading.setInnerText(headingMessage);
-  }
-
-  public ValuesListViewTable<R> asWidget() {
-    return this;
-  }
-
-  /**
-   * @return the delegate for this view, or null if there is none
-   */
-  public ValuesListView.Delegate getDelegate() {
-    return delegate;
-  }
-
-  public abstract Collection<Property<?>> getProperties();
-
-  /**
-   * @param delegate the new delegate for this view, may be null
-   */
-  public void setDelegate(ValuesListView.Delegate delegate) {
-    this.delegate = delegate;
-    if (delegate != null) {
-      delegate.onRangeChanged(0, table.getNumDisplayedItems());
-    }
-  }
-
-  public void setValueList(List<R> newValues) {
-    adapter.setValueList(newValues);
-  }
-
-  private ValueStoreListViewAdapter<R> createAdapter() {
-    return new ValueStoreListViewAdapter<R>() {
-      @Override
-      protected void onRangeChanged(ListView<R> view) {
-        Range range = view.getRange();
-        Delegate myDelegate = getDelegate();
-        if (myDelegate != null) {
-          myDelegate.onRangeChanged(range.getStart(), range.getLength());
-        }
-      }
-    };
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/valuestore/client/ValuesListViewTable.ui.xml b/bikeshed/src/com/google/gwt/valuestore/client/ValuesListViewTable.ui.xml
index 7fab0c5..e69de29 100644
--- a/bikeshed/src/com/google/gwt/valuestore/client/ValuesListViewTable.ui.xml
+++ b/bikeshed/src/com/google/gwt/valuestore/client/ValuesListViewTable.ui.xml
@@ -1,9 +0,0 @@
-<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
-<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
-  xmlns:g='urn:import:com.google.gwt.user.client.ui'
-  xmlns:b='urn:import:com.google.gwt.bikeshed.list.client'>
-  <g:HTMLPanel>
-    <h3 ui:field='heading'/>
-    <b:PagingTableListView ui:field='table'/>
-  </g:HTMLPanel>
-</ui:UiBinder>
diff --git a/bikeshed/src/com/google/gwt/valuestore/shared/PropertyReference.java b/bikeshed/src/com/google/gwt/valuestore/shared/PropertyReference.java
index 2c890ed..3166209 100644
--- a/bikeshed/src/com/google/gwt/valuestore/shared/PropertyReference.java
+++ b/bikeshed/src/com/google/gwt/valuestore/shared/PropertyReference.java
@@ -31,6 +31,11 @@
     this.record = record;
     this.property = property;
   }
+  
+  protected PropertyReference() {
+    this.record = null;
+    this.property = null;
+  }
 
   public V get() {
     return record.get(property);
diff --git a/bikeshed/src/com/google/gwt/valuestore/shared/Value.java b/bikeshed/src/com/google/gwt/valuestore/shared/Value.java
new file mode 100644
index 0000000..716f268
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/valuestore/shared/Value.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.valuestore.shared;
+
+/**
+ * @param <V> the type of the value
+ */
+public class Value<V> extends PropertyReference<V> {
+
+  public static <V> Value<V> of(V value) {
+    return new Value<V>(value);
+  }
+
+  private final V value;
+  
+  private Value(V value) {
+    this.value = value;
+  }
+
+  @Override
+  public V get() {
+    return value;
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/valuestore/shared/ValuesListView.java b/bikeshed/src/com/google/gwt/valuestore/shared/ValuesListView.java
index 5fe4111..e69de29 100644
--- a/bikeshed/src/com/google/gwt/valuestore/shared/ValuesListView.java
+++ b/bikeshed/src/com/google/gwt/valuestore/shared/ValuesListView.java
@@ -1,50 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.valuestore.shared;
-
-import com.google.gwt.user.client.ui.TakesValueList;
-import com.google.gwt.user.client.ui.Widget;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Implemented by widgets that display lists of records.
- *
- * @param <K> the type of the key of the records
- */
-public interface ValuesListView<K extends Record> extends
-    TakesValueList<K> {
-
-  /**
-   * Implemented by ValuesListView delegates, to keep informed when the visible
-   * range changes.
-   */
-  public interface Delegate {
-    void onRangeChanged(int start, int length);
-  }
-
-  Widget asWidget();
-
-  Collection<Property<?>> getProperties();
-
-  /**
-   * @param delegate the new delegate for this view, may be null
-   */
-  void setDelegate(ValuesListView.Delegate delegate);
-
-  void setValueList(List<K> newValues);
-}
diff --git a/bikeshed/src/com/google/gwt/valuestore/ui/AbstractRecordListActivity.java b/bikeshed/src/com/google/gwt/valuestore/ui/AbstractRecordListActivity.java
new file mode 100644
index 0000000..eef1fc3
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/valuestore/ui/AbstractRecordListActivity.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.valuestore.ui;
+
+import com.google.gwt.app.place.Activity;
+import com.google.gwt.bikeshed.list.client.ListView;
+import com.google.gwt.requestfactory.shared.EntityListRequest;
+import com.google.gwt.user.client.ui.TakesValueList;
+import com.google.gwt.valuestore.shared.Record;
+
+import java.util.List;
+
+/**
+ * Abstract activity for requesting and displaying a list of {@Record}.
+ * <p>
+ * Subclasses must:
+ * 
+ * <ul>
+ * <li>implement a method for creating request objects
+ * <li>provide a {@link RecordListView}
+ * <li>respond to "show" and "edit" requests
+ * </ul>
+ * 
+ * Only the properties required by the view will be requested.
+ * 
+ * @param <R> the type of {@link Record} listed
+ */
+public abstract class AbstractRecordListActivity<R extends Record> implements
+    Activity, RecordListView.Delegate<R>, TakesValueList<R> {
+  private RecordListView<R> view;
+  private Callback callback;
+
+  public AbstractRecordListActivity(RecordListView<R> view) {
+    this.view = view;
+    view.setDelegate(this);
+  }
+
+  public RecordListView<R> getView() {
+    return view;
+  }
+
+  public void onCancel() {
+    onStop();
+  }
+
+  /**
+   * Called by the table as it needs data.
+   */
+  public void onRangeChanged(ListView<R> listView) {
+    // TODO use listview.getRange()
+    getData();
+  }
+
+  public void onStop() {
+    view.setDelegate((RecordListView.Delegate<R>) null);
+  }
+
+  /**
+   * When the request returns it calls this method.
+   * <p>
+   * TODO this was supposed to be a convenience but it's just confusing. Get
+   * real callbacks into request factory
+   */
+  public void setValueList(List<R> values) {
+    getView().setDataSize(values.size(), true);
+    getView().setData(0, values.size(), values);
+    if (callback != null) {
+      callback.onStarted(getView().asWidget());
+    }
+  }
+
+  public void start(Callback callback) {
+    this.callback = callback;
+    getData();
+  }
+
+  public boolean willStop() {
+    return true;
+  }
+
+  protected abstract EntityListRequest<R> createRequest();
+
+  private void getData() {
+    createRequest().forProperties(getView().getProperties()).to(this).fire();
+  }
+
+}
diff --git a/bikeshed/src/com/google/gwt/valuestore/ui/AbstractRecordListView.java b/bikeshed/src/com/google/gwt/valuestore/ui/AbstractRecordListView.java
new file mode 100644
index 0000000..64ac28b
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/valuestore/ui/AbstractRecordListView.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.valuestore.ui;
+
+import com.google.gwt.bikeshed.cells.client.ActionCell;
+import com.google.gwt.bikeshed.list.client.IdentityColumn;
+import com.google.gwt.bikeshed.list.client.PagingTableListView;
+import com.google.gwt.bikeshed.list.shared.Range;
+import com.google.gwt.bikeshed.list.shared.SelectionModel;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.valuestore.shared.Property;
+import com.google.gwt.valuestore.shared.Record;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Abstract implementation of RecordListView. Subclasses must call {@link #init}
+ * with the root widget, its {@link PagingTableListView}, and a list of
+ * {@link PropertyColumn}.
+ * 
+ * @param <R> the type of the records
+ */
+public abstract class AbstractRecordListView<R extends Record> extends
+    Composite implements RecordListView<R> {
+
+  private PagingTableListView<R> table;
+  private Delegate<R> delegate;
+  private Set<Property<?>> properties = new HashSet<Property<?>>();
+
+  public AbstractRecordListView<R> asWidget() {
+    return this;
+  }
+
+  public Set<Property<?>> getProperties() {
+    return properties;
+  }
+
+  public Range getRange() {
+    return table.getRange();
+  }
+
+  public void setData(int start, int length, List<R> values) {
+    table.setData(start, length, values);
+  }
+
+  public void setDataSize(int size, boolean isExact) {
+    table.setDataSize(size, isExact);
+  }
+  
+  public void setDelegate(
+      com.google.gwt.bikeshed.list.client.ListView.Delegate<R> delegate) {
+    throw new UnsupportedOperationException(
+        "A RecordListView requires a RecordListView.Delegate");
+  }
+
+  public void setDelegate(Delegate<R> delegate) {
+    this.delegate = delegate;
+    table.setDelegate(delegate);
+  }
+
+  public void setSelectionModel(SelectionModel<? super R> selectionModel) {
+    table.setSelectionModel(selectionModel);
+  }
+
+  protected void init(Widget root, PagingTableListView<R> table,
+      List<PropertyColumn<R, ?>> columns) {
+    super.initWidget(root);
+    this.table = table;
+
+    for (PropertyColumn<R, ?> column : columns) {
+      table.addColumn(column, column.getProperty().getName());
+      properties.add(column.getProperty());
+    }
+
+    table.addColumn(new IdentityColumn<R>(new ActionCell<R>("Show",
+        new ActionCell.Delegate<R>() {
+          public void execute(R object) {
+            delegate.showDetails(object);
+          }
+        })));
+
+    table.addColumn(new IdentityColumn<R>(new ActionCell<R>("Edit",
+        new ActionCell.Delegate<R>() {
+          public void execute(R object) {
+            delegate.edit(object);
+          }
+        })));
+  }
+
+  @Override
+  protected void initWidget(Widget widget) {
+    throw new UnsupportedOperationException(
+        "AbstractRecordListView must be initialized via "
+            + "init(Widget PagingTableListView<R> List<PropertyColumn<R, ?>> ) ");
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/valuestore/ui/PropertyColumn.java b/bikeshed/src/com/google/gwt/valuestore/ui/PropertyColumn.java
new file mode 100644
index 0000000..723a183
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/valuestore/ui/PropertyColumn.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.valuestore.ui;
+
+import com.google.gwt.app.util.PassthroughRenderer;
+import com.google.gwt.app.util.Renderer;
+import com.google.gwt.bikeshed.list.client.TextColumn;
+import com.google.gwt.valuestore.shared.Property;
+import com.google.gwt.valuestore.shared.Record;
+
+/**
+ * A column that displays a record property as a string.
+ * 
+ * @param <R> the type of record in this table
+ * @param <T> value type of the property
+ */
+public class PropertyColumn<R extends Record, T> extends TextColumn<R> {
+  public static <R extends Record> PropertyColumn<R, String> getStringPropertyColumn(
+      Property<String> property) {
+    return new PropertyColumn<R, String>(property,
+        PassthroughRenderer.instance());
+  }
+  private final Renderer<T> renderer;
+
+  private final Property<T> property;
+
+  public PropertyColumn(Property<T> property, Renderer<T> renderer) {
+    this.property = property;
+    this.renderer = renderer;
+  }
+
+  public Property<T> getProperty() {
+    return property;
+  }
+
+  @Override
+  public String getValue(R object) {
+    return renderer.render(object.get(property));
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/valuestore/ui/PropertyView.java b/bikeshed/src/com/google/gwt/valuestore/ui/PropertyView.java
new file mode 100644
index 0000000..5f7a44f
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/valuestore/ui/PropertyView.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.valuestore.ui;
+
+import com.google.gwt.valuestore.shared.Property;
+import com.google.gwt.valuestore.shared.Record;
+
+import java.util.Set;
+
+/**
+ * A view that displays a set of {@link Property} values for a type of
+ * {@link Record}.
+ * 
+ * @param <R> the type of the record
+ */
+public interface PropertyView<R extends Record> {
+
+  /**
+   * @return the set of properties this view displays, which are guaranteed to
+   *         be properties of R
+   */
+  Set<Property<?>> getProperties();
+}
diff --git a/bikeshed/src/com/google/gwt/valuestore/ui/RecordEditView.java b/bikeshed/src/com/google/gwt/valuestore/ui/RecordEditView.java
new file mode 100644
index 0000000..4523efb
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/valuestore/ui/RecordEditView.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.valuestore.ui;
+
+import com.google.gwt.app.util.IsWidget;
+import com.google.gwt.user.client.ui.TakesValue;
+import com.google.gwt.valuestore.shared.DeltaValueStore;
+import com.google.gwt.valuestore.shared.Record;
+
+/**
+ * Implemented by views that edit {@link Record}s.
+ * 
+ * @param <R> the type of the record
+ */
+public interface RecordEditView<R extends Record> extends TakesValue<R>,
+    IsWidget, PropertyView<R> {
+  
+  /**
+   * Implemented by the owner of the view.
+   */
+  interface Delegate {
+    void saveClicked();
+  }
+  
+  void setDelegate(Delegate delegate);
+  void setDeltaValueStore(DeltaValueStore deltas);
+  void setEnabled(boolean b);
+}
diff --git a/bikeshed/src/com/google/gwt/valuestore/ui/RecordListView.java b/bikeshed/src/com/google/gwt/valuestore/ui/RecordListView.java
new file mode 100644
index 0000000..5c0246b
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/valuestore/ui/RecordListView.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.valuestore.ui;
+
+import com.google.gwt.app.util.IsWidget;
+import com.google.gwt.bikeshed.list.client.ListView;
+import com.google.gwt.valuestore.shared.Record;
+
+/**
+ * A view of a list of {@link Records}, which declares which properties it is
+ * able to display.
+ * <p>
+ * It is expected that such views will typically (eventually) be defined largely
+ * in ui.xml files which declare the properties of interest, which is why the
+ * view is a source of a property set rather than a receiver of one.
+ * 
+ * @param <R> the type of the records to display
+ */
+public interface RecordListView<R extends Record> extends ListView<R>,
+    IsWidget, PropertyView<R> {
+  /**
+   * Implemented by the owner of a RecordTableView.
+   * 
+   * @param<R> the type of the records to display
+   */
+  interface Delegate<R extends Record> extends ListView.Delegate<R> {
+    /**
+     * @param record the record the user wants to edit
+     */
+    void edit(R record);
+
+    /**
+     * @param record the record whose details the user wants to see
+     */
+    void showDetails(R record);
+  }
+
+  /**
+   * A RecordListView requires a RecordListView.Delegate.
+   */
+  void setDelegate(
+      com.google.gwt.bikeshed.list.client.ListView.Delegate<R> delegate)
+      throws UnsupportedOperationException;
+
+  /**
+   * Sets the delegate.
+   */
+  void setDelegate(Delegate<R> delegate);
+}
diff --git a/bikeshed/test/com/google/gwt/collections/ClientMutableArrayTest.java b/bikeshed/test/com/google/gwt/collections/ClientMutableArrayTest.java
index 162a41e..a62b26f 100644
--- a/bikeshed/test/com/google/gwt/collections/ClientMutableArrayTest.java
+++ b/bikeshed/test/com/google/gwt/collections/ClientMutableArrayTest.java
@@ -16,12 +16,12 @@
 package com.google.gwt.collections;
 
 /**
- * Re-run {@link ObjectArrayTest} tests under GWT.
+ * Re-run {@link MutableArrayTest} tests under GWT.
  */
-public class ClientMutableArrayTest extends ObjectArrayTest {
+public class ClientMutableArrayTest extends MutableArrayTest {
   @Override
   public String getModuleName() {
     return "com.google.gwt.collections.Collections";
   }
-
+  
 }
diff --git a/bikeshed/test/com/google/gwt/collections/CollectionsServerSideTestSuite.java b/bikeshed/test/com/google/gwt/collections/CollectionsServerSideTestSuite.java
new file mode 100644
index 0000000..7bd5b71
--- /dev/null
+++ b/bikeshed/test/com/google/gwt/collections/CollectionsServerSideTestSuite.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.collections;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * This suite collects all server-side Lightweight collections tests.
+ */
+public class CollectionsServerSideTestSuite extends TestSuite {
+  public static Test suite() {
+    TestSuite suite = 
+      new TestSuite("All Gwt Lightweight collections unit tests");
+
+    suite.addTestSuite(MutableArrayTest.class);
+    suite.addTestSuite(MutableArrayInternalTest.class);
+    suite.addTestSuite(ImmutableArrayTest.class);
+
+    return suite;
+  }
+}
diff --git a/bikeshed/test/com/google/gwt/collections/CollectionsTestSuite.java b/bikeshed/test/com/google/gwt/collections/CollectionsTestSuite.java
new file mode 100644
index 0000000..9baed5f
--- /dev/null
+++ b/bikeshed/test/com/google/gwt/collections/CollectionsTestSuite.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.collections;
+
+import com.google.gwt.junit.tools.GWTTestSuite;
+
+import junit.framework.Test;
+
+/**
+ * This suite collects all client-side Lightweight collections tests.
+ */
+public class CollectionsTestSuite extends GWTTestSuite {
+  public static Test suite() {
+    GWTTestSuite suite = new GWTTestSuite("All Gwt Lightwight collections unit tests");
+    
+    suite.addTestSuite(ClientMutableArrayTest.class);
+    suite.addTestSuite(GwtImmutableArrayTest.class);
+    
+    return suite;
+  }
+}
diff --git a/bikeshed/test/com/google/gwt/collections/ImmutableArrayTest.java b/bikeshed/test/com/google/gwt/collections/ImmutableArrayTest.java
index c12a415..0ce5628 100644
--- a/bikeshed/test/com/google/gwt/collections/ImmutableArrayTest.java
+++ b/bikeshed/test/com/google/gwt/collections/ImmutableArrayTest.java
@@ -111,6 +111,7 @@
     assertTrue(ia1.elems == ia2.elems);
   }
 
+  
   public void testModifyFrozenMutable() {    
     // Do not test undefined behavior with assertions disabled
     if (!assertionsEnabled) {
diff --git a/bikeshed/test/com/google/gwt/collections/MutableArrayBenchmarkTest.java b/bikeshed/test/com/google/gwt/collections/MutableArrayBenchmarkTest.java
index 9d59bfe..6ad9a11 100644
--- a/bikeshed/test/com/google/gwt/collections/MutableArrayBenchmarkTest.java
+++ b/bikeshed/test/com/google/gwt/collections/MutableArrayBenchmarkTest.java
@@ -20,22 +20,24 @@
 import com.google.gwt.benchmarks.client.Operator;
 import com.google.gwt.benchmarks.client.RangeField;
 
+import java.util.ArrayList;
+
 /**
  * Benchmarks the performance of various MutableArray methods.
  */
 public class MutableArrayBenchmarkTest extends Benchmark {
 
-  final IntRange elemRange = new IntRange(0, 5000, Operator.ADD, 100);
+  final IntRange elemRange = new IntRange(5, 30000, Operator.ADD, 500);
 
   @Override
   public String getModuleName() {
     return "com.google.gwt.collections.Collections";
   }
   
-  public void testAddGrowth() {    
+  public void testGwtCollectionsArrayAddGrowth() {    
   }
   
-  public void testAddGrowth(@RangeField("elemRange") Integer numElements) {
+  public void testGwtCollectionsArrayAddGrowth(@RangeField("elemRange") Integer numElements) {
     MutableArray<Integer> ma = CollectionFactory.createMutableArray();
     
     for (int i = 0; i < numElements; i++) {
@@ -43,10 +45,10 @@
     }
   }
   
-  public void testSetSizeGrowth() {  
+  public void testGwtCollectionsArraySetSizeGrowth() {  
   }
   
-  public void testSetSizeGrowth(@RangeField("elemRange") Integer numElements) {
+  public void testGwtCollectionsArraySetSizeGrowth(@RangeField("elemRange") Integer numElements) {
     MutableArray<Integer> ma = CollectionFactory.createMutableArray();
     
     ma.setSize(numElements, null);
@@ -54,5 +56,40 @@
       ma.set(i, i);
     }    
   }
+  
+  public void testGwtCollectionsArraySetSizeInitGrowth() {  
+  }
+  
+  public void testGwtCollectionsArraySetSizeInitGrowth(
+      @RangeField("elemRange") Integer numElements) {
+    MutableArray<Integer> ma = CollectionFactory.createMutableArray();
+    
+    ma.setSize(numElements, new Integer(0));
+    for (int i = 0; i < numElements; i++) {
+      ma.set(i, i);
+    }    
+  }
+  
+  public void testJavaArraySetGrowth() {
+  }
+  
+  public void testJavaArraySetGrowth(@RangeField("elemRange") Integer numElements) {
+    Integer[] ia = new Integer[numElements];
+    
+    for (int i = 0; i < numElements; i++) {
+      ia[i] = i;
+    }
+  }
+  
+  public void testJreArrayListAddGrowth() {
+  }
+  
+  public void testJreArrayListAddGrowth(@RangeField("elemRange") Integer numElements) {
+    ArrayList<Integer> al = new ArrayList<Integer>();
+    
+    for (int i = 0; i < numElements; i++) {
+      al.add(i);
+    }
+  }
 
 }
diff --git a/bikeshed/test/com/google/gwt/collections/MutableArrayInternalTest.java b/bikeshed/test/com/google/gwt/collections/MutableArrayInternalTest.java
new file mode 100644
index 0000000..25e05f3
--- /dev/null
+++ b/bikeshed/test/com/google/gwt/collections/MutableArrayInternalTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.collections;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests mutable array implementation internal details.
+ */
+public class MutableArrayInternalTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return null;
+  }
+
+  public void testSetSizeNullElems() {
+    MutableArray<String> b = CollectionFactory.createMutableArray();
+
+    b.setSize(1, "fillValue");
+    assertNotNull(b.elems);
+
+    b.setSize(0, null);
+    assertEquals(null, b.elems);
+  }
+
+}
diff --git a/bikeshed/test/com/google/gwt/collections/ObjectArrayTest.java b/bikeshed/test/com/google/gwt/collections/MutableArrayTest.java
similarity index 98%
rename from bikeshed/test/com/google/gwt/collections/ObjectArrayTest.java
rename to bikeshed/test/com/google/gwt/collections/MutableArrayTest.java
index 3b745e0..06cdc84 100644
--- a/bikeshed/test/com/google/gwt/collections/ObjectArrayTest.java
+++ b/bikeshed/test/com/google/gwt/collections/MutableArrayTest.java
@@ -22,7 +22,7 @@
 /**
  * Tests mutable arrays.
  */
-public class ObjectArrayTest extends GWTTestCase {
+public class MutableArrayTest extends GWTTestCase {
 
   boolean assertionsEnabled;
 
@@ -181,9 +181,8 @@
 
     b.setSize(0, null);
     assertEquals(0, b.size());
-    assertEquals(null, b.elems);
   }
-
+  
   public void testSingleElementAddAndRemove() {
       MutableArray<String> a = createMutableArray();
 
diff --git a/bikeshed/test/com/google/gwt/collections/super/com/google/gwt/collections/ImmutableArrayInternalTest.java b/bikeshed/test/com/google/gwt/collections/super/com/google/gwt/collections/ImmutableArrayInternalTest.java
new file mode 100644
index 0000000..7764d04
--- /dev/null
+++ b/bikeshed/test/com/google/gwt/collections/super/com/google/gwt/collections/ImmutableArrayInternalTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.collections;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests mutable array implementation internal details.
+ */
+public class ImmutableArrayInternalTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return null;
+  }
+
+  public void testImmutableNoCopy() {
+    // TODO: Test no copying is made
+  }
+
+}
diff --git a/bikeshed/test/com/google/gwt/collections/super/com/google/gwt/collections/MutableArrayInternalTest.java b/bikeshed/test/com/google/gwt/collections/super/com/google/gwt/collections/MutableArrayInternalTest.java
new file mode 100644
index 0000000..6f5fca2
--- /dev/null
+++ b/bikeshed/test/com/google/gwt/collections/super/com/google/gwt/collections/MutableArrayInternalTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.collections;
+
+import static com.google.gwt.collections.CollectionFactory.createMutableArray;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests mutable array implementation internal details.
+ */
+public class MutableArrayInternalTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return null;
+  }
+
+  public void testSetSizeNullElems() {
+    MutableArray<String> b = createMutableArray();
+    
+    b.setSize(1, "fillValue");
+    assertTrue(hasElems(b));
+
+    b.setSize(0, null);
+    assertFalse(hasElems(b));
+  }
+  
+  public native boolean hasElems(MutableArray ma) /*-{
+    return !(ma.elems === undefined) 
+  }-*/;
+
+}
diff --git a/user/test/com/google/gwt/uibinder/test/client/Specific.java b/user/test/com/google/gwt/uibinder/test/client/Specific.java
index dbeb021..705d748 100644
--- a/user/test/com/google/gwt/uibinder/test/client/Specific.java
+++ b/user/test/com/google/gwt/uibinder/test/client/Specific.java
@@ -18,9 +18,8 @@
 /**
  * A specific implementation of {@link Abstract}, used to test generics in
  * UiBinder. See {@link ParameterizedWidget}.
- * 
- * @param <T> a param type
+ *
+ * @param <T>
  */
 public class Specific<T> extends Abstract<T> {
-
 }