Adds details place to scaffold app, and deletes unused
EntityPlaceVisitor, EntityPlaceFilter.

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

Review by: amitmanjhi@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7781 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/bikeshed/src/com/google/gwt/app/place/GoToPlaceCommand.java b/bikeshed/src/com/google/gwt/app/place/GoToPlaceCommand.java
new file mode 100644
index 0000000..9042609
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/place/GoToPlaceCommand.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.app.place;
+
+import com.google.gwt.user.client.Command;
+
+/**
+ * Command to change the app location.
+ * 
+ * @param <P> the type of place managed by the {@link PlaceController}
+ */
+public class GoToPlaceCommand<P extends Place> implements Command {
+  private final P place;
+  private final PlaceController<? super P> placeController;
+
+  /**
+   * @param place
+   * @param placeController
+   */
+  public GoToPlaceCommand(P place, PlaceController<? super P> placeController) {
+    this.place = place;
+    this.placeController = placeController;
+  }
+
+  public void execute() {
+    placeController.goTo(place);
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/app/place/PlacePicker.java b/bikeshed/src/com/google/gwt/app/place/PlacePicker.java
index c14765b..6ec118c 100644
--- a/bikeshed/src/com/google/gwt/app/place/PlacePicker.java
+++ b/bikeshed/src/com/google/gwt/app/place/PlacePicker.java
@@ -15,7 +15,10 @@
  */
 package com.google.gwt.app.place;
 
-import java.util.Map;
+import com.google.gwt.user.client.ui.Renderer;
+
+import java.util.LinkedHashMap;
+import java.util.List;
 
 /**
  * Presenter that goes to {@link Place}s the user picks.
@@ -25,19 +28,27 @@
 public class PlacePicker<P extends Place> implements
     PlacePickerView.Listener<P> {
   private final PlacePickerView<P> view;
-  private final PlaceController<P> placeController;
+  private final PlaceController<? super P> placeController;
+  private final Renderer<P> renderer;
 
-  public PlacePicker(PlacePickerView<P> view, PlaceController<P> placeController) {
+  public PlacePicker(PlacePickerView<P> view,
+      PlaceController<? super P> placeController, Renderer<P> renderer) {
+    // ? super P to allow us to pick subtypes of the PlaceController's type
     this.view = view;
     this.placeController = placeController;
     this.view.setListener(this);
+    this.renderer = renderer;
   }
 
   public void placePicked(P place) {
     placeController.goTo(place);
   }
 
-  public void setPlaces(Map<? extends P, String> places) {
-    view.setValues(places);
+  public void setPlaces(List<? extends P> places) {
+    LinkedHashMap<P, String> map = new LinkedHashMap<P, String>();
+    for (P place : places) {
+      map.put(place, renderer.render(place));
+    }
+    view.setValues(map);
   }
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/DetailsRequester.java b/bikeshed/src/com/google/gwt/sample/expenses/client/DetailsRequester.java
new file mode 100644
index 0000000..734d994
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/DetailsRequester.java
@@ -0,0 +1,109 @@
+/*
+ * 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.client;
+
+import com.google.gwt.app.place.PlaceChanged;
+import com.google.gwt.sample.expenses.client.place.EntityDetailsPlace;
+import com.google.gwt.sample.expenses.shared.EmployeeKey;
+import com.google.gwt.sample.expenses.shared.ExpensesEntityKey;
+import com.google.gwt.sample.expenses.shared.ExpensesEntityVisitor;
+import com.google.gwt.sample.expenses.shared.ReportKey;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.valuestore.shared.Values;
+
+/**
+ * In charge of requesting and displaying all info when the user goes to an
+ * {@link EntityDetailsPlace}.
+ */
+public final class DetailsRequester implements PlaceChanged.Handler {
+
+  private final EntityNameRenderer entityNamer;
+  private final SimplePanel panel;
+  private final HTML detailsView;
+
+  public DetailsRequester(EntityNameRenderer entityNamer,
+      SimplePanel simplePanel, HTML detailsView) {
+    this.entityNamer = entityNamer;
+    this.panel = simplePanel;
+    this.detailsView = detailsView;
+  }
+
+  public void onPlaceChanged(PlaceChanged event) {
+    if (!(event.getNewPlace() instanceof EntityDetailsPlace)) {
+      return;
+    }
+    EntityDetailsPlace newPlace = (EntityDetailsPlace) event.getNewPlace();
+    final Values<? extends ExpensesEntityKey<?>> entity = newPlace.getEntity();
+    ExpensesEntityKey<?> key = entity.getEntityKey();
+
+    // TODO make a pretty uibinder page, not least because we're rendering
+    // user strings here, which is dangerous
+
+    final String title = new StringBuilder("<h1>").append(
+        entityNamer.render(key)).append("</h1>").toString();
+
+    final StringBuilder list = new StringBuilder();
+
+    // 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.
+
+    key.accept(new ExpensesEntityVisitor() {
+
+      @SuppressWarnings("unchecked")
+      public void visit(EmployeeKey employeeKey) {
+        // wow, this cast is nasty. Perhaps visitor should actually
+        // be on the Values themselves? 
+        Values<EmployeeKey> eValues = (Values<EmployeeKey>) entity;
+        String user = eValues.get(EmployeeKey.get().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 = eValues.get(EmployeeKey.get().getDisplayName());
+        list.append("<label>").append("Display Name: ").append("</label>");
+        list.append("<span>").append(display).append("</span>");
+        list.append("</div>");
+      }
+
+      @SuppressWarnings("unchecked")
+      public void visit(ReportKey reportKey) {
+        Values<ReportKey> rValues = (Values<ReportKey>) entity;
+        String purpose = rValues.get(ReportKey.get().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 = rValues.get(ReportKey.get().getCreated()).toString();
+        list.append("<label>").append("Created: ").append("</label>");
+        list.append("<span>").append(created).append("</span>");
+        list.append("</div>");
+      }
+    });
+
+    detailsView.setHTML(title + list.toString());
+
+    if (detailsView.getParent() == null) {
+      panel.clear();
+      panel.add(detailsView);
+    }
+  }
+}
\ No newline at end of file
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/EntityList.java b/bikeshed/src/com/google/gwt/sample/expenses/client/EntityList.java
deleted file mode 100644
index 8b60eb8..0000000
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/EntityList.java
+++ /dev/null
@@ -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.client;
-
-import com.google.gwt.requestfactory.shared.EntityKey;
-import com.google.gwt.user.client.ui.HasValueList;
-import com.google.gwt.valuestore.shared.Property;
-import com.google.gwt.valuestore.shared.Values;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Base class for showing a list of entities.
- * 
- * @param <E> the type of entity listed
- */
-public class EntityList<E extends EntityKey<E>> implements
-    HasValueList<Values<E>> {
-  protected final EntityListView view;
-  protected final List<Property<E, ?>> properties;
-
-  public EntityList(String heading, EntityListView view, List<Property<E, ?>> properties) {
-    this.view = view;
-    view.setHeading(heading);
-    this.properties = properties;
-
-    List<String> names = new ArrayList<String>();
-    for (Property<E, ?> property : properties) {
-      names.add(property.getName());
-    }
-    this.view.setColumnNames(names);
-  }
-
-  public void editValueList(boolean replace, int index,
-      List<Values<E>> newValues) {
-    throw new UnsupportedOperationException();
-  }
-
-  public void setValueList(List<Values<E>> newValues) {
-    List<List<String>> strings = new ArrayList<List<String>>();
-
-    for (Values<E> values : newValues) {
-      List<String> row = new ArrayList<String>();
-      for (Property<E, ?> property : properties) {
-        row.add(values.get(property).toString());
-      }
-      strings.add(row);
-    }
-
-    view.setValues(strings);
-  }
-
-  public void setValueListSize(int size, boolean exact) {
-    throw new UnsupportedOperationException();
-  }
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/EntityListPresenter.java b/bikeshed/src/com/google/gwt/sample/expenses/client/EntityListPresenter.java
new file mode 100644
index 0000000..aa1a088
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/EntityListPresenter.java
@@ -0,0 +1,91 @@
+/*
+ * 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.client;
+
+import com.google.gwt.sample.expenses.client.place.Places;
+import com.google.gwt.sample.expenses.shared.ExpensesEntityKey;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.HasValueList;
+import com.google.gwt.valuestore.shared.Property;
+import com.google.gwt.valuestore.shared.Values;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Presenter that shows a list of entities and provides "edit" and "show"
+ * commands for them.
+ * 
+ * @param <E> the type of entity listed
+ */
+public class EntityListPresenter<E extends ExpensesEntityKey<?>> implements
+    HasValueList<Values<E>> {
+  private final EntityListView view;
+  private final List<Property<E, ?>> properties;
+  private final Places places;
+
+  public EntityListPresenter(String heading, EntityListView view,
+      List<Property<E, ?>> properties, Places places) {
+    this.view = view;
+    view.setHeading(heading);
+    this.properties = properties;
+    this.places = places;
+
+    List<String> names = new ArrayList<String>();
+    for (Property<E, ?> property : properties) {
+      names.add(property.getName());
+    }
+    this.view.setColumnNames(names);
+  }
+
+  public void editValueList(boolean replace, int index,
+      List<Values<E>> newValues) {
+    throw new UnsupportedOperationException();
+  }
+
+  public void setValueList(List<Values<E>> newValues) {
+    List<EntityListView.Row> rows = new ArrayList<EntityListView.Row>();
+
+    for (final Values<E> values : newValues) {
+      final List<String> strings = new ArrayList<String>();
+      for (Property<E, ?> property : properties) {
+        strings.add(values.get(property).toString());
+      }
+      EntityListView.Row row = new EntityListView.Row() {
+
+        public Command getEditCommand() {
+          return places.getGoToEditFor(values);
+        }
+
+        public Command getShowDetailsCommand() {
+          return places.getGoToDetailsFor(values);
+        }
+
+        public List<String> getValues() {
+          return strings;
+        }
+
+      };
+      rows.add(row);
+    }
+
+    view.setRowData(rows);
+  }
+
+  public void setValueListSize(int size, boolean exact) {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/EntityListView.java b/bikeshed/src/com/google/gwt/sample/expenses/client/EntityListView.java
index e4f0242..457eaba 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/EntityListView.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/EntityListView.java
@@ -15,15 +15,38 @@
  */
 package com.google.gwt.sample.expenses.client;
 
+import com.google.gwt.user.client.Command;
+
 import java.util.List;
 
 /**
  * Simple display of a list of entities.
  */
 public interface EntityListView {
-  void setHeading(String text);
+
+  /**
+   * Interface implemented by a row of data to display.
+   */
+  interface Row {
+    /**
+     * @return command to edit this row
+     */
+    Command getEditCommand();
+    
+    /**
+     * @return command to show the details for this row
+     */
+    Command getShowDetailsCommand();
+    
+    /**
+     * @return the strings to render for this row
+     */
+    List<String> getValues();
+  }
   
   void setColumnNames(List<String> names);
   
-  void setValues(List<List<String>> values);
+  void setHeading(String text);
+  
+  void setRowData(List<Row> rows);
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/EntityNameRenderer.java b/bikeshed/src/com/google/gwt/sample/expenses/client/EntityNameRenderer.java
new file mode 100644
index 0000000..b99320a
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/EntityNameRenderer.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.sample.expenses.client;
+
+import com.google.gwt.sample.expenses.shared.EmployeeKey;
+import com.google.gwt.sample.expenses.shared.ExpensesEntityKey;
+import com.google.gwt.sample.expenses.shared.ExpensesEntityFilter;
+import com.google.gwt.sample.expenses.shared.ReportKey;
+import com.google.gwt.user.client.ui.Renderer;
+
+/**
+ * Renders the name of {@link ExpensesEntityKey}s.
+ */
+//TODO i18n
+public class EntityNameRenderer implements Renderer<ExpensesEntityKey<?>> {
+  private final ExpensesEntityFilter<String> filter = new ExpensesEntityFilter<String>() {
+    public String filter(EmployeeKey employeeKey) {
+      return "Employees";
+    }
+
+    public String filter(ReportKey reportKey) {
+      return "Reports";
+    }
+  };
+
+  public String render(ExpensesEntityKey<?> entity) {
+    return entity.accept(filter);
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffold.java b/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffold.java
index 180f746..bd0cc29 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffold.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffold.java
@@ -23,9 +23,11 @@
 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.client.place.ExpensesScaffoldPlace;
+import com.google.gwt.sample.expenses.client.place.EntityListPlace;
+import com.google.gwt.sample.expenses.client.place.AbstractExpensesPlace;
 import com.google.gwt.sample.expenses.client.place.Places;
 import com.google.gwt.sample.expenses.shared.ExpenseRequestFactory;
+import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.RootLayoutPanel;
 
 /**
@@ -34,23 +36,38 @@
 public class ExpensesScaffold implements EntryPoint {
 
   public void onModuleLoad() {
+
+    // App controllers and services
     final ExpenseRequestFactory requests = GWT.create(ExpenseRequestFactory.class);
     final HandlerManager eventBus = new HandlerManager(null);
-    final PlaceController<ExpensesScaffoldPlace> placeController = new PlaceController<ExpensesScaffoldPlace>(
+    final PlaceController<AbstractExpensesPlace> placeController = new PlaceController<AbstractExpensesPlace>(
         eventBus);
+    final Places places = new Places(placeController);
 
+    // Renderers
+    final EntityNameRenderer entityNamer = new EntityNameRenderer();
+    final ListPlaceRenderer listPlaceNamer = new ListPlaceRenderer(entityNamer);
+    
+    // Top level UI
     final ExpensesScaffoldShell shell = new ExpensesScaffoldShell();
 
-    PlacePicker<ExpensesScaffoldPlace> placePicker = new PlacePicker<ExpensesScaffoldPlace>(
-        shell.getPlacesBox(), placeController);
-    placePicker.setPlaces(Places.getListPlacesAndNames());
+    // Left side
+    PlacePicker<EntityListPlace> placePicker = new PlacePicker<EntityListPlace>(
+        shell.getPlacesBox(), placeController, listPlaceNamer);
+    placePicker.setPlaces(places.getListPlaces());
 
-    // TODO Shouldn't create this until it's actually needed
+    // Shared view for entity lists. Perhaps real app would have
+    // a separate view per type?
     final TableEntityListView entitiesView = new TableEntityListView();
+    eventBus.addHandler(PlaceChanged.TYPE, new ListRequester(places,
+        shell.getBody(), entitiesView, requests, listPlaceNamer));
+    
+    // Shared view for entity details. Again, perhaps real app should not share
+    final HTML detailsView = new HTML();
+    eventBus.addHandler(PlaceChanged.TYPE, new DetailsRequester(entityNamer,
+        shell.getBody(), detailsView));
 
-    eventBus.addHandler(PlaceChanged.TYPE, new ListRequester(shell.getBody(),
-        entitiesView, requests));
-
+    // Hide the loading method
     Element loading = Document.get().getElementById("loading");
     loading.getParentElement().removeChild(loading);
 
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffoldShell.java b/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffoldShell.java
index 31b687e..9555b5e 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffoldShell.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffoldShell.java
@@ -18,7 +18,7 @@
 import com.google.gwt.app.client.ListBoxPlacePickerView;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.DivElement;
-import com.google.gwt.sample.expenses.client.place.ExpensesScaffoldPlace;
+import com.google.gwt.sample.expenses.client.place.EntityListPlace;
 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<ExpensesScaffoldPlace> placesBox;
+  @UiField ListBoxPlacePickerView<EntityListPlace> placesBox;
   @UiField DivElement error;
   
   public ExpensesScaffoldShell() {
@@ -51,7 +51,7 @@
   /**
    * @return the banner
    */
-  public ListBoxPlacePickerView<ExpensesScaffoldPlace> getPlacesBox() {
+  public ListBoxPlacePickerView<EntityListPlace> getPlacesBox() {
     return placesBox;
   }
 
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/ListPlaceRenderer.java b/bikeshed/src/com/google/gwt/sample/expenses/client/ListPlaceRenderer.java
new file mode 100644
index 0000000..155af25
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/ListPlaceRenderer.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.client;
+
+import com.google.gwt.sample.expenses.client.place.EntityListPlace;
+import com.google.gwt.sample.expenses.shared.ExpensesEntityKey;
+import com.google.gwt.user.client.ui.Renderer;
+
+/**
+ * Renders {@link EntityListPlace}s for display to users.
+ */
+public class ListPlaceRenderer implements Renderer<EntityListPlace> {
+
+  private final Renderer<ExpensesEntityKey<?>> entityRenderer;
+
+  /**
+   * @param entityRenderer
+   */
+  public ListPlaceRenderer(Renderer<ExpensesEntityKey<?>> entityRenderer) {
+    this.entityRenderer = entityRenderer;
+  }
+
+  public String render(EntityListPlace object) {
+    return entityRenderer.render(object.getKey());
+  }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/ListRequester.java b/bikeshed/src/com/google/gwt/sample/expenses/client/ListRequester.java
index 1556bd0..3bb724c 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/ListRequester.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/ListRequester.java
@@ -15,13 +15,15 @@
  */
 package com.google.gwt.sample.expenses.client;
 
-import com.google.gwt.app.place.Place;
 import com.google.gwt.app.place.PlaceChanged;
 import com.google.gwt.sample.expenses.client.place.EntityListPlace;
 import com.google.gwt.sample.expenses.client.place.Places;
 import com.google.gwt.sample.expenses.shared.EmployeeKey;
 import com.google.gwt.sample.expenses.shared.ExpenseRequestFactory;
+import com.google.gwt.sample.expenses.shared.ExpensesEntityKey;
+import com.google.gwt.sample.expenses.shared.ExpensesEntityVisitor;
 import com.google.gwt.sample.expenses.shared.ReportKey;
+import com.google.gwt.user.client.ui.Renderer;
 import com.google.gwt.user.client.ui.SimplePanel;
 import com.google.gwt.valuestore.shared.Property;
 
@@ -29,60 +31,73 @@
 import java.util.List;
 
 /**
- * In charge of requesting and displaying the appropriate entity lists
- * when the user goes to an {@link EntityListPlace}.
+ * In charge of requesting and displaying the appropriate entity lists when the
+ * user goes to an {@link EntityListPlace}.
  */
 public final class ListRequester implements PlaceChanged.Handler {
 
   private final SimplePanel panel;
   private final TableEntityListView entitiesView;
-  private final List<Property<ReportKey, ?>> reportColumns;
   private final ExpenseRequestFactory requests;
-  private final List<Property<EmployeeKey, ?>> employeeColumns;
+  private final Renderer<EntityListPlace> listNameFilter;
+  private final Places places;
 
-  /**
-   * @param shell
-   * @param entitiesView
-   * @param requests
-   */
-  public ListRequester(SimplePanel panel, TableEntityListView entitiesView,
-      ExpenseRequestFactory requests) {
+  public ListRequester(Places places, SimplePanel panel,
+      TableEntityListView entitiesView, ExpenseRequestFactory requests,
+      Renderer<EntityListPlace> renderer) {
+    this.places = places;
     this.panel = panel;
     this.entitiesView = entitiesView;
     this.requests = requests;
-
-    employeeColumns = new ArrayList<Property<EmployeeKey, ?>>();
-    employeeColumns.add(EmployeeKey.get().getUserName());
-    employeeColumns.add(EmployeeKey.get().getDisplayName());
-
-    reportColumns = new ArrayList<Property<ReportKey, ?>>();
-    reportColumns.add(ReportKey.get().getCreated());
-    reportColumns.add(ReportKey.get().getPurpose());
+    this.listNameFilter = renderer;
   }
 
   public void onPlaceChanged(PlaceChanged event) {
-    // TODO all this "instanceof" and "if else" stuff is not so great
-
-    Place newPlace = event.getNewPlace();
-    if (!(newPlace instanceof EntityListPlace)) {
+    if (!(event.getNewPlace() instanceof EntityListPlace)) {
       return;
     }
+    EntityListPlace newPlace = (EntityListPlace) event.getNewPlace();
+    final String name = listNameFilter.render(newPlace);
+
+    final ExpensesEntityKey<?> key = newPlace.getKey();
+
+    // TODO Would be simpler if every entity key knew its find method
+    key.accept(new ExpensesEntityVisitor() {
+
+      public void visit(EmployeeKey employeeKey) {
+        List<Property<EmployeeKey, ?>> columns = getEmployeeColumns();
+        EntityListPresenter<EmployeeKey> presenter = new EntityListPresenter<EmployeeKey>(
+            name, entitiesView, columns, places);
+        requests.employeeRequest().findAllEmployees().forProperties(columns).to(
+            presenter).fire();
+      }
+
+      public void visit(ReportKey reportKey) {
+        List<Property<ReportKey, ?>> columns = getReportColumns();
+        EntityListPresenter<ReportKey> presenter = new EntityListPresenter<ReportKey>(
+            name, entitiesView, columns, places);
+        requests.reportRequest().findAllReports().forProperties(columns).to(
+            presenter).fire();
+      }
+    });
 
     if (entitiesView.getParent() == null) {
       panel.clear();
       panel.add(entitiesView);
     }
+  }
 
-    if (newPlace == Places.EMPLOYEE_LIST) {
-      EntityList<EmployeeKey> list = new EntityList<EmployeeKey>("Employees",
-          entitiesView, employeeColumns);
-      requests.employeeRequest().findAllEmployees().forProperties(
-          employeeColumns).to(list).fire();
-    } else if (newPlace == Places.REPORT_LIST) {
-      EntityList<ReportKey> list = new EntityList<ReportKey>("Reports",
-          entitiesView, reportColumns);
-      requests.reportRequest().findAllReports().forProperties(reportColumns).to(
-          list).fire();
-    }
+  private List<Property<EmployeeKey, ?>> getEmployeeColumns() {
+    List<Property<EmployeeKey, ?>> columns = new ArrayList<Property<EmployeeKey, ?>>();
+    columns.add(EmployeeKey.get().getUserName());
+    columns.add(EmployeeKey.get().getDisplayName());
+    return columns;
+  }
+
+  private List<Property<ReportKey, ?>> getReportColumns() {
+    List<Property<ReportKey, ?>> columns = new ArrayList<Property<ReportKey, ?>>();
+    columns.add(ReportKey.get().getCreated());
+    columns.add(ReportKey.get().getPurpose());
+    return columns;
   }
 }
\ No newline at end of file
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/TableEntityListView.java b/bikeshed/src/com/google/gwt/sample/expenses/client/TableEntityListView.java
index 27244da..5ac6c93 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/TableEntityListView.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/TableEntityListView.java
@@ -18,12 +18,15 @@
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.EventTarget;
 import com.google.gwt.dom.client.HeadingElement;
 import com.google.gwt.dom.client.NodeList;
 import com.google.gwt.dom.client.TableCellElement;
 import com.google.gwt.dom.client.TableColElement;
 import com.google.gwt.dom.client.TableElement;
 import com.google.gwt.dom.client.TableRowElement;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiField;
 import com.google.gwt.user.client.ui.Widget;
@@ -31,7 +34,8 @@
 import java.util.List;
 
 /**
- * Interim table based implementation of {@link EntityListView}.
+ * Interim table based implementation of {@link EntityListView}. Will be replaced
+ * by some descendant of {@link com.google.gwt.bikeshed.list.client.PagingTableListView<}
  */
 public class TableEntityListView extends Widget implements EntityListView {
   interface Binder extends UiBinder<Element, TableEntityListView> {
@@ -44,8 +48,27 @@
   @UiField TableRowElement header;
   @UiField TableElement table;
 
+  private List<Row> values;
+
   public TableEntityListView() {
     setElement(BINDER.createAndBindUi(this));
+    addDomHandler(new ClickHandler() {
+
+      public void onClick(ClickEvent event) {
+        EventTarget target = event.getNativeEvent().getEventTarget();
+        if (Element.is(target)) {
+          Element e = Element.as(target);
+          String tagName = e.getTagName().toLowerCase();
+          if ("td".equals(tagName)) {
+            TableCellElement cell = TableCellElement.as(e);
+            int rowIndex = TableRowElement.as(cell.getParentElement()).getRowIndex();
+//            int cellIndex = cell.getCellIndex();
+            values.get(rowIndex - 1).getShowDetailsCommand().execute(); 
+          }
+        }
+      }
+      
+    }, ClickEvent.getType());
   }
 
   public void setColumnNames(List<String> names) {
@@ -59,12 +82,13 @@
     heading.setInnerText(text);
   }
 
-  public void setValues(List<List<String>> newValues) {
+  public void setRowData(List<Row> newValues) {
+    this.values = newValues;
     int r = 1; // skip header
     NodeList<TableRowElement> tableRows = table.getRows();
 
     for (int i = 0; i < newValues.size(); i++) {
-      List<String> valueRow = newValues.get(i);
+      List<String> valueRow = newValues.get(i).getValues();
 
       if (r < tableRows.getLength()) {
         reuseRow(r, tableRows, valueRow);
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/AbstractExpensesPlace.java
similarity index 78%
rename from bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java
rename to bikeshed/src/com/google/gwt/sample/expenses/client/place/AbstractExpensesPlace.java
index bf19125..4401c56 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/AbstractExpensesPlace.java
@@ -20,8 +20,6 @@
 /**
  * Base type of places for the Expenses Scaffold app.
  */
-public abstract class ExpensesScaffoldPlace extends Place {
-  public abstract void accept(ExpensesScaffoldPlaceVisitor visitor);
-
-  public abstract <T> T accept(ExpensesScaffoldPlaceFilter<T> filter);
+public abstract class AbstractExpensesPlace extends Place {
+  // TODO is there actual value in this base class?
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EditEntityPlace.java
similarity index 68%
copy from bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java
copy to bikeshed/src/com/google/gwt/sample/expenses/client/place/EditEntityPlace.java
index bf19125..23bf521 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EditEntityPlace.java
@@ -15,13 +15,15 @@
  */
 package com.google.gwt.sample.expenses.client.place;
 
-import com.google.gwt.app.place.Place;
+import com.google.gwt.sample.expenses.shared.ExpensesEntityKey;
+import com.google.gwt.valuestore.shared.Values;
 
 /**
- * Base type of places for the Expenses Scaffold app.
+ * Place in the app to edit an entity.
  */
-public abstract class ExpensesScaffoldPlace extends Place {
-  public abstract void accept(ExpensesScaffoldPlaceVisitor visitor);
+public class EditEntityPlace extends ExpenseEntityPlace {
 
-  public abstract <T> T accept(ExpensesScaffoldPlaceFilter<T> filter);
+  public EditEntityPlace(Values<? extends ExpensesEntityKey<?>> entity) {
+    super(entity);
+  }
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityDetailsPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityDetailsPlace.java
new file mode 100644
index 0000000..ee91140
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityDetailsPlace.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.sample.expenses.client.place;
+
+import com.google.gwt.sample.expenses.shared.ExpensesEntityKey;
+import com.google.gwt.valuestore.shared.Values;
+
+/**
+ * Place in the app to see details of an entity.
+ */
+public class EntityDetailsPlace extends ExpenseEntityPlace {
+
+  /**
+   * @param e
+   */
+  public EntityDetailsPlace(Values<? extends ExpensesEntityKey<?>> 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/client/place/EntityListPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityListPlace.java
index 4b3a6dd..5575542 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityListPlace.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityListPlace.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,16 +15,22 @@
  */
 package com.google.gwt.sample.expenses.client.place;
 
+import com.google.gwt.sample.expenses.shared.ExpensesEntityKey;
+
 /**
  * Place in the app that lists all Entities of a type.
  */
-public class EntityListPlace extends ExpensesScaffoldPlace {
+public class EntityListPlace extends AbstractExpensesPlace {
+  private final ExpensesEntityKey<?> key;
 
-  public void accept(ExpensesScaffoldPlaceVisitor visitor) {
-    visitor.visit(this);
+  /**
+   * @param key the schema of the entities at this place
+   */
+  public EntityListPlace(ExpensesEntityKey<?> key) {
+    this.key = key;
   }
-
-  public <T> T accept(ExpensesScaffoldPlaceFilter<T> filter) {
-    return filter.filter(this);
+  
+  public ExpensesEntityKey<?> getKey() {
+    return key;
   }
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpenseEntityPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpenseEntityPlace.java
new file mode 100644
index 0000000..57436d3
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpenseEntityPlace.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.client.place;
+
+import com.google.gwt.sample.expenses.shared.ExpensesEntityKey;
+import com.google.gwt.valuestore.shared.Values;
+
+/**
+ * A place in the app focused on a particular entity.
+ */
+public abstract class ExpenseEntityPlace extends AbstractExpensesPlace {
+
+  private final Values<? extends ExpensesEntityKey<?>> entity;
+
+  /**
+   * @param entity
+   */
+  public ExpenseEntityPlace(Values<? extends ExpensesEntityKey<?>> entity) {
+
+    this.entity = entity;
+  }
+
+  /**
+   * @return the entity
+   */
+  public Values<? extends ExpensesEntityKey<?>> getEntity() {
+    return entity;
+  }
+
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceFilter.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceFilter.java
deleted file mode 100644
index 0b59ab1..0000000
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceFilter.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.sample.expenses.client.place;
-
-/**
- * Implemented by filters of {@link ExpensesScaffoldPlace}.
- * 
- * @param <T> the type to filter to
- */
-public interface ExpensesScaffoldPlaceFilter<T> {
-
-//  /**
-//   * @param editEntityPlace
-//   * @return
-//   */
-//  T filter(EditEntityPlace editEntityPlace);
-//
-//  /**
-//   * @param entityDetailsPlace
-//   * @return
-//   */
-//  T filter(EntityDetailsPlace entityDetailsPlace);
-
-  /**
-   * @param entityListPlace
-   * @return
-   */
-  T filter(EntityListPlace entityListPlace);
-
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceVisitor.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceVisitor.java
deleted file mode 100644
index 55e4108..0000000
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceVisitor.java
+++ /dev/null
@@ -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.client.place;
-
-/**
- * 
- */
-public interface ExpensesScaffoldPlaceVisitor {
-
-//  /**
-//   * @param editEntityPlace
-//   */
-//  void visit(EditEntityPlace editEntityPlace);
-//
-//  /**
-//   * @param entityDetailsPlace
-//   */
-//  void visit(EntityDetailsPlace entityDetailsPlace);
-
-  /**
-   * @param entityListPlace
-   */
-  void visit(EntityListPlace entityListPlace);
-
-}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/Places.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/Places.java
index e7ee68d..f4a5ff1 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/Places.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/Places.java
@@ -15,34 +15,43 @@
  */
 package com.google.gwt.sample.expenses.client.place;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
+import com.google.gwt.app.place.GoToPlaceCommand;
+import com.google.gwt.app.place.PlaceController;
+import com.google.gwt.sample.expenses.shared.EmployeeKey;
+import com.google.gwt.sample.expenses.shared.ExpensesEntityKey;
+import com.google.gwt.sample.expenses.shared.ReportKey;
+import com.google.gwt.valuestore.shared.Values;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /**
- * The places of the ExpensesScaffold app.
+ * Object with knowledge of the places of the ExpensesScaffold app.
  */
 public class Places {
-  public static final EntityListPlace EMPLOYEE_LIST = new EntityListPlace();
-  public static final EntityListPlace REPORT_LIST = new EntityListPlace();
+  private final PlaceController<AbstractExpensesPlace> controller;
+  
+  private final List<EntityListPlace> listPlaces;
+  
+  public Places(PlaceController<AbstractExpensesPlace> controller) {
+    this.controller = controller;
 
-  /**
-   * @return the set of places to see lists of entities, and their localized
-   *         names
-   */
-  public static Map<EntityListPlace, String> getListPlacesAndNames() {
-    // TODO: i18n, get the Strings from a Messages interface. Really, names don't belong
-    // in this class at all.
-    Map<EntityListPlace, String> navPlaces = new LinkedHashMap<EntityListPlace, String>();
-    navPlaces.put(EMPLOYEE_LIST, "Employees");
-    navPlaces.put(REPORT_LIST, "Reports");
-    return navPlaces;
+    ArrayList<EntityListPlace> places = new ArrayList<EntityListPlace>();
+    places.add(new EntityListPlace(EmployeeKey.get()));
+    places.add(new EntityListPlace(ReportKey.get()));
+    listPlaces = Collections.unmodifiableList(places);
+  }
+  
+  public GoToPlaceCommand<EntityDetailsPlace> getGoToDetailsFor(Values<? extends ExpensesEntityKey<?>> e) {
+    return new GoToPlaceCommand<EntityDetailsPlace>(new EntityDetailsPlace(e), controller);
   }
 
-//  public EntityDetailsPlace getDetailsPlaceFor(ExpensesEntity<?> e) {
-//    return new EntityDetailsPlace(e);
-//  }
-//
-//  public EditEntityPlace getEditPlaceFor(ExpensesEntity<?> e) {
-//    return new EditEntityPlace(e);
-//  }
+  public GoToPlaceCommand<EditEntityPlace> getGoToEditFor(Values<? extends ExpensesEntityKey<?>> e) {
+    return new GoToPlaceCommand<EditEntityPlace>(new EditEntityPlace(e), controller);
+  }
+
+  public List<EntityListPlace> getListPlaces() {
+    return listPlaces;
+  }
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeKey.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeKey.java
index a7de62d..3be8455 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeKey.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeKey.java
@@ -15,7 +15,6 @@
  */
 package com.google.gwt.sample.expenses.shared;
 
-import com.google.gwt.requestfactory.shared.EntityKey;
 import com.google.gwt.requestfactory.shared.Id;
 import com.google.gwt.requestfactory.shared.LongString;
 import com.google.gwt.requestfactory.shared.Version;
@@ -32,7 +31,8 @@
  * IRL this class will be generated by a JPA-savvy tool run before
  * compilation.
  */
-public class EmployeeKey implements EntityKey<EmployeeKey> {
+
+public class EmployeeKey implements ExpensesEntityKey<EmployeeKey> {
   private static EmployeeKey instance;
 
   public static EmployeeKey get() {
@@ -67,6 +67,14 @@
     properties.add(version);
   }
 
+  public <T> T accept(ExpensesEntityFilter<T> filter) {
+    return filter.filter(this);
+  }
+
+  public void accept(ExpensesEntityVisitor visitor) {
+    visitor.visit(this);
+  }
+
   public Property<EmployeeKey, String> getDisplayName() {
     return displayName;
   }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityFilter.java
similarity index 61%
copy from bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java
copy to bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityFilter.java
index bf19125..771bea9 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityFilter.java
@@ -13,15 +13,17 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.expenses.client.place;
-
-import com.google.gwt.app.place.Place;
+package com.google.gwt.sample.expenses.shared;
 
 /**
- * Base type of places for the Expenses Scaffold app.
+ * "API Generated" base interface implemented by filters of {@link ExpensesEntityKey}.
+ * <p>
+ * IRL this class will be generated by a JPA-savvy tool run before compilation.
+ * 
+ * @param <T> the type to filter to
  */
-public abstract class ExpensesScaffoldPlace extends Place {
-  public abstract void accept(ExpensesScaffoldPlaceVisitor visitor);
+public interface ExpensesEntityFilter<T> {
+  T filter(EmployeeKey employeeKey);
 
-  public abstract <T> T accept(ExpensesScaffoldPlaceFilter<T> filter);
+  T filter(ReportKey reportKey);
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityKey.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityKey.java
new file mode 100644
index 0000000..2d036b4
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityKey.java
@@ -0,0 +1,33 @@
+/*
+ * 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.shared;
+
+import com.google.gwt.requestfactory.shared.EntityKey;
+
+/**
+ * "API Generated" base interface for proxy keys to
+ * {@link com.google.gwt.valuestore.shared.Values Values} of
+ * {@link com.google.gwt.sample.expenses.server.domain}.
+ * <p>
+ * IRL this class will be generated by a JPA-savvy tool run before compilation.
+ * 
+ * @param <K> this entity type
+ */
+public interface ExpensesEntityKey<K extends EntityKey<K>> extends EntityKey<K> {
+  public abstract void accept(ExpensesEntityVisitor visitor);
+
+  public abstract <T> T accept(ExpensesEntityFilter<T> filter);
+}
\ No newline at end of file
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityVisitor.java
similarity index 63%
copy from bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java
copy to bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityVisitor.java
index bf19125..ecd260e 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityVisitor.java
@@ -13,15 +13,14 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.expenses.client.place;
-
-import com.google.gwt.app.place.Place;
+package com.google.gwt.sample.expenses.shared;
 
 /**
- * Base type of places for the Expenses Scaffold app.
+ * "API Generated" base interface implemented by visitors of {@link ExpensesEntityKey}.
+ * <p>
+ * IRL this class will be generated by a JPA-savvy tool run before compilation.
  */
-public abstract class ExpensesScaffoldPlace extends Place {
-  public abstract void accept(ExpensesScaffoldPlaceVisitor visitor);
-
-  public abstract <T> T accept(ExpensesScaffoldPlaceFilter<T> filter);
+public interface ExpensesEntityVisitor {
+  void visit(EmployeeKey employeeKey);
+  void visit(ReportKey reportKey);
 }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportKey.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportKey.java
index 202b78a..0f03717 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportKey.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportKey.java
@@ -15,7 +15,6 @@
  */
 package com.google.gwt.sample.expenses.shared;
 
-import com.google.gwt.requestfactory.shared.EntityKey;
 import com.google.gwt.requestfactory.shared.Id;
 import com.google.gwt.requestfactory.shared.LongString;
 import com.google.gwt.requestfactory.shared.Version;
@@ -33,7 +32,8 @@
  * IRL this class will be generated by a JPA-savvy tool run before
  * compilation.
  */
-public class ReportKey implements EntityKey<ReportKey> {
+
+public class ReportKey implements ExpensesEntityKey<ReportKey> {
   private static ReportKey instance;
 
   public static ReportKey get() {
@@ -64,6 +64,14 @@
     properties.add(purpose);
   }
 
+  public <T> T accept(ExpensesEntityFilter<T> filter) {
+    return filter.filter(this);
+  }
+
+  public void accept(ExpensesEntityVisitor visitor) {
+    visitor.visit(this);
+  }
+
   public Property<ReportKey, Date> getCreated() {
     return created;
   }
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java b/bikeshed/src/com/google/gwt/user/client/ui/Renderer.java
similarity index 63%
copy from bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java
copy to bikeshed/src/com/google/gwt/user/client/ui/Renderer.java
index bf19125..b3dc9bf 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java
+++ b/bikeshed/src/com/google/gwt/user/client/ui/Renderer.java
@@ -13,15 +13,17 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.google.gwt.sample.expenses.client.place;
-
-import com.google.gwt.app.place.Place;
+package com.google.gwt.user.client.ui;
 
 /**
- * Base type of places for the Expenses Scaffold app.
+ * An object that can render other objects of a particular type into plain-text
+ * form.
+ * 
+ * @param <T> the type to render
  */
-public abstract class ExpensesScaffoldPlace extends Place {
-  public abstract void accept(ExpensesScaffoldPlaceVisitor visitor);
-
-  public abstract <T> T accept(ExpensesScaffoldPlaceFilter<T> filter);
+public interface Renderer<T> {
+  /**
+   * Renders {@code object} as plain text.
+   */
+  String render(T object);
 }
diff --git a/bikeshed/src/com/google/gwt/valuestore/client/ValuesImpl.java b/bikeshed/src/com/google/gwt/valuestore/client/ValuesImpl.java
index 33131bf..8f2b1db 100644
--- a/bikeshed/src/com/google/gwt/valuestore/client/ValuesImpl.java
+++ b/bikeshed/src/com/google/gwt/valuestore/client/ValuesImpl.java
@@ -61,7 +61,7 @@
     return nativeGet(property);
   }
 
-  public native T getPropertyHolder() /*-{
+  public native T getEntityKey() /*-{
     return this['__key'];
   }-*/;
 
diff --git a/bikeshed/src/com/google/gwt/valuestore/shared/Values.java b/bikeshed/src/com/google/gwt/valuestore/shared/Values.java
index d3d7827..6ac34af 100644
--- a/bikeshed/src/com/google/gwt/valuestore/shared/Values.java
+++ b/bikeshed/src/com/google/gwt/valuestore/shared/Values.java
@@ -21,9 +21,7 @@
  * @param <T> value type.
  */
 public interface Values<T> {
-  // TODO At the moment this isn't actually used. If it stays unused
-  // once ValueStore is in place, delete it
-  T getPropertyHolder();
+  T getEntityKey();
 
   <V, P extends Property<T, V>> V get(P property);