Introduces expenses scaffolding app, ExpensesScaffold, complete with
event bus and places.
Creates (in bikeshed only, don't panic) new com.google.gwt.app
package, where app framework classes should accumulate. So far that
includes PlaceController et al. PlaceController doesn't yet do history
management.
Also introduces HasValueMap and ValueListBox, first attempt to make ListBox play in the HasValue world.
Review at http://gwt-code-reviews.appspot.com/209802
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7743 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/bikeshed/src/com/google/gwt/app/App.gwt.xml b/bikeshed/src/com/google/gwt/app/App.gwt.xml
new file mode 100644
index 0000000..58b1263
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/App.gwt.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Could not determine the version of your GWT SDK; using the module DTD from GWT 1.6.4. You may want to change this. -->
+<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.6.4//EN" "http://google-web-toolkit.googlecode.com/svn/tags/1.6.4/distro-source/core/src/gwt-module.dtd">
+<module>
+ <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
new file mode 100644
index 0000000..6a96e0e
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/client/ListBoxPlacePickerView.java
@@ -0,0 +1,50 @@
+/*
+ * 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.client;
+
+import com.google.gwt.app.place.Place;
+import com.google.gwt.app.place.PlacePickerView;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.ValueListBox;
+
+/**
+ * Hacky ValueListBox based implementation of PlacePickerView, to be replaced by
+ * new data widget, or at least something less ugly.
+ *
+ * @param <P> the type of places listed
+ */
+public class ListBoxPlacePickerView<P extends Place> extends ValueListBox<P>
+ implements PlacePickerView<P> {
+ private HandlerRegistration handlerRegistration;
+
+ /**
+ * Set the listener.
+ */
+ public void setListener(final PlacePickerView.Listener<P> listener) {
+ if (handlerRegistration != null) {
+ handlerRegistration.removeHandler();
+ handlerRegistration = null;
+ }
+
+ handlerRegistration = addValueChangeHandler(new ValueChangeHandler<P>() {
+ public void onValueChange(ValueChangeEvent<P> event) {
+ listener.placePicked(event.getValue());
+ }
+ });
+ }
+}
diff --git a/bikeshed/src/com/google/gwt/app/place/Place.java b/bikeshed/src/com/google/gwt/app/place/Place.java
new file mode 100644
index 0000000..95ef693
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/place/Place.java
@@ -0,0 +1,23 @@
+/*
+ * 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;
+
+/**
+ * Represents a bookmarkable location in an app.
+ */
+public abstract class Place {
+
+}
diff --git a/bikeshed/src/com/google/gwt/app/place/PlaceChanged.java b/bikeshed/src/com/google/gwt/app/place/PlaceChanged.java
new file mode 100644
index 0000000..7c5d07a
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/place/PlaceChanged.java
@@ -0,0 +1,54 @@
+/*
+ * 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
new file mode 100644
index 0000000..ae7178f
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/place/PlaceController.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.place;
+
+import com.google.gwt.event.shared.HandlerManager;
+
+/**
+ * In charge of the user's location in the app.
+ *
+ * @param <P> the type of places managed
+ */
+public class PlaceController<P extends Place> {
+ private final HandlerManager eventBus;
+
+ private P where;
+
+ public PlaceController(HandlerManager eventBus) {
+ this.eventBus = eventBus;
+ }
+
+ public P getWhere() {
+ return where;
+ }
+
+ public void goTo(P newPlace) {
+ where = newPlace;
+ eventBus.fireEvent(new PlaceChanged(newPlace));
+ }
+}
diff --git a/bikeshed/src/com/google/gwt/app/place/PlacePicker.java b/bikeshed/src/com/google/gwt/app/place/PlacePicker.java
new file mode 100644
index 0000000..c14765b
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/place/PlacePicker.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.place;
+
+import java.util.Map;
+
+/**
+ * Presenter that goes to {@link Place}s the user picks.
+ *
+ * @param <P> the type of places listed
+ */
+public class PlacePicker<P extends Place> implements
+ PlacePickerView.Listener<P> {
+ private final PlacePickerView<P> view;
+ private final PlaceController<P> placeController;
+
+ public PlacePicker(PlacePickerView<P> view, PlaceController<P> placeController) {
+ this.view = view;
+ this.placeController = placeController;
+ this.view.setListener(this);
+ }
+
+ public void placePicked(P place) {
+ placeController.goTo(place);
+ }
+
+ public void setPlaces(Map<? extends P, String> places) {
+ view.setValues(places);
+ }
+}
diff --git a/bikeshed/src/com/google/gwt/app/place/PlacePickerView.java b/bikeshed/src/com/google/gwt/app/place/PlacePickerView.java
new file mode 100644
index 0000000..dd3820b
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/app/place/PlacePickerView.java
@@ -0,0 +1,35 @@
+/*
+ * 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.HasValueMap;
+
+/**
+ * View for a {@link PlacePicker}.
+ *
+ * @param <P> the type of place displayed
+ */
+public interface PlacePickerView<P extends Place> extends HasValueMap<P> {
+
+ /**
+ * Implemented by the presenter currently using this view.
+ */
+ interface Listener<P> {
+ void placePicked(P place);
+ }
+
+ void setListener(Listener<P> listener);
+}
diff --git a/bikeshed/src/com/google/gwt/requestfactory/shared/EntityListRequest.java b/bikeshed/src/com/google/gwt/requestfactory/shared/EntityListRequest.java
index 19ead9c..85cda13 100644
--- a/bikeshed/src/com/google/gwt/requestfactory/shared/EntityListRequest.java
+++ b/bikeshed/src/com/google/gwt/requestfactory/shared/EntityListRequest.java
@@ -19,6 +19,8 @@
import com.google.gwt.valuestore.shared.Property;
import com.google.gwt.valuestore.shared.Values;
+import java.util.Collection;
+
/**
* Implemented by RequestObjects for service methods that return list
* properties.
@@ -28,6 +30,8 @@
public interface EntityListRequest<E> {
void fire();
+ EntityListRequest<E> forProperties(Collection<Property<E, ?>> properties);
+
EntityListRequest<E> forProperty(Property<E, ?> property);
EntityListRequest<E> to(HasValueList<Values<E>> watcher);
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/Expenses.gwt.xml b/bikeshed/src/com/google/gwt/sample/expenses/Expenses.gwt.xml
index 0d663ad..1122451 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/Expenses.gwt.xml
+++ b/bikeshed/src/com/google/gwt/sample/expenses/Expenses.gwt.xml
@@ -7,7 +7,6 @@
<!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
<!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> -->
- <inherits name='com.google.gwt.user.theme.standard.Standard'/>
<inherits name='com.google.gwt.requestfactory.RequestFactory'/>
<!-- Specify the app entry point class. -->
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/ExpensesScaffold.gwt.xml b/bikeshed/src/com/google/gwt/sample/expenses/ExpensesScaffold.gwt.xml
new file mode 100644
index 0000000..4f5173c
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/ExpensesScaffold.gwt.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Could not determine the version of your GWT SDK; using the module DTD from GWT 1.6.4. You may want to change this. -->
+<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.6.4//EN" "http://google-web-toolkit.googlecode.com/svn/tags/1.6.4/distro-source/core/src/gwt-module.dtd">
+<module rename-to='expensesScaffold'>
+ <inherits name='com.google.gwt.user.User' />
+ <inherits name='com.google.gwt.app.App' />
+ <inherits name='com.google.gwt.user.theme.standard.Standard' />
+
+ <inherits name="com.google.gwt.requestfactory.RequestFactory" />
+
+ <source path='client' />
+ <source path='shared' />
+ <source path='gen' />
+ <entry-point
+ class="com.google.gwt.sample.expenses.client.ExpensesScaffold" />
+
+ <!-- TODO: generate-with -->
+ <replace-with class='com.google.gwt.sample.expenses.gen.ExpenseRequestFactoryImpl'>
+ <when-type-is class='com.google.gwt.sample.expenses.shared.ExpenseRequestFactory'/>
+ </replace-with>
+
+</module>
\ 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
new file mode 100644
index 0000000..baa6faf
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/EntityList.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.client;
+
+import com.google.gwt.requestfactory.shared.EntityRef;
+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 EntityRef<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/EntityListView.java b/bikeshed/src/com/google/gwt/sample/expenses/client/EntityListView.java
new file mode 100644
index 0000000..07e5038
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/EntityListView.java
@@ -0,0 +1,29 @@
+/*
+ * 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 java.util.List;
+
+/**
+ * Simple display of a list of entities
+ */
+public interface EntityListView {
+ void setHeading(String text);
+
+ void setColumnNames(List<String> names);
+
+ void setValues(List<List<String>> values);
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffold.java b/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffold.java
new file mode 100644
index 0000000..c8b7d06
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffold.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.sample.expenses.client;
+
+import com.google.gwt.app.place.PlaceChanged;
+import com.google.gwt.app.place.PlaceController;
+import com.google.gwt.app.place.PlacePicker;
+import com.google.gwt.core.client.EntryPoint;
+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.event.shared.HandlerManager;
+import com.google.gwt.sample.expenses.client.place.ExpensesScaffoldPlace;
+import com.google.gwt.sample.expenses.client.place.Places;
+import com.google.gwt.sample.expenses.shared.ExpenseRequestFactory;
+import com.google.gwt.user.client.ui.RootLayoutPanel;
+
+
+/**
+ * Application for browsing the entities of the Expenses app.
+ */
+public class ExpensesScaffold implements EntryPoint {
+
+ public void onModuleLoad() {
+ final ExpenseRequestFactory requests = GWT.create(ExpenseRequestFactory.class);
+ final HandlerManager eventBus = new HandlerManager(null);
+ final PlaceController<ExpensesScaffoldPlace> placeController = new PlaceController<ExpensesScaffoldPlace>(
+ eventBus);
+
+ final ExpensesScaffoldShell shell = new ExpensesScaffoldShell();
+
+ PlacePicker<ExpensesScaffoldPlace> placePicker = new PlacePicker<ExpensesScaffoldPlace>(
+ shell.getPlacesBox(), placeController);
+ placePicker.setPlaces(Places.getListPlacesAndNames());
+
+ // TODO Shouldn't create this until it's actually needed
+ final TableEntityListView entitiesView = new TableEntityListView();
+
+ eventBus.addHandler(PlaceChanged.TYPE, new ListRequester(shell.getBody(),
+ entitiesView, requests));
+
+ Element loading = Document.get().getElementById("loading");
+ loading.getParentElement().removeChild(loading);
+
+ RootLayoutPanel.get().add(shell);
+ }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffoldShell.java b/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffoldShell.java
new file mode 100644
index 0000000..31b687e
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffoldShell.java
@@ -0,0 +1,64 @@
+/*
+ * 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.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.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.SimplePanel;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * The outermost UI for the scaffold app.
+ */
+public class ExpensesScaffoldShell extends Composite {
+ interface Binder extends UiBinder<Widget, ExpensesScaffoldShell> {
+ }
+ private static final Binder BINDER = GWT.create(Binder.class);
+
+ @UiField SimplePanel body;
+ @UiField ListBoxPlacePickerView<ExpensesScaffoldPlace> placesBox;
+ @UiField DivElement error;
+
+ public ExpensesScaffoldShell() {
+ initWidget(BINDER.createAndBindUi(this));
+ }
+
+ /**
+ * @return the body
+ */
+ public SimplePanel getBody() {
+ return body;
+ }
+
+ /**
+ * @return the banner
+ */
+ public ListBoxPlacePickerView<ExpensesScaffoldPlace> getPlacesBox() {
+ return placesBox;
+ }
+
+ /**
+ * @param string
+ */
+ public void setError(String string) {
+ error.setInnerText(string);
+ }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffoldShell.ui.xml b/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffoldShell.ui.xml
new file mode 100644
index 0000000..d7a63fa
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/ExpensesScaffoldShell.ui.xml
@@ -0,0 +1,54 @@
+<!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:a='urn:import:com.google.gwt.app.client'>
+
+ <ui:style>
+ .disabled {
+ color: gray;
+ }
+
+ .banner {
+ background-color: wheat;
+ }
+
+ .title {
+ text-align: left;
+ margin-left: 1em;
+ }
+
+ .error {
+ position: absolute;
+ left: 12%;
+ right: 12%;
+ text-align: center;
+ background-color: red;
+ }
+
+ .users {
+ position: absolute;
+ right: 0;
+ }
+ </ui:style>
+
+ <g:DockLayoutPanel unit='EM'>
+ <g:north size='4.5'>
+ <g:HTML styleName='{style.banner}'>
+ <div class='{style.error}' ui:field='error'></div>
+ <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>
+
+ <g:center>
+ <g:SimplePanel ui:field='body'>
+ <g:HTML>
+ <h3>Welcome to Expenses</h3>
+ <p>Choose an entity set from the list on the left to get started</p>
+ </g:HTML>
+ </g:SimplePanel>
+ </g:center>
+ </g:DockLayoutPanel>
+</ui:UiBinder>
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/ListRequester.java b/bikeshed/src/com/google/gwt/sample/expenses/client/ListRequester.java
new file mode 100644
index 0000000..6ce367f
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/ListRequester.java
@@ -0,0 +1,88 @@
+/*
+ * 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.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.EmployeeRef;
+import com.google.gwt.sample.expenses.shared.ExpenseRequestFactory;
+import com.google.gwt.sample.expenses.shared.ReportRef;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.valuestore.shared.Property;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 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<ReportRef, ?>> reportColumns;
+ private final ExpenseRequestFactory requests;
+ private final List<Property<EmployeeRef, ?>> employeeColumns;
+
+ /**
+ * @param shell
+ * @param entitiesView
+ * @param requests
+ */
+ public ListRequester(SimplePanel panel, TableEntityListView entitiesView,
+ ExpenseRequestFactory requests) {
+ this.panel = panel;
+ this.entitiesView = entitiesView;
+ this.requests = requests;
+
+ employeeColumns = new ArrayList<Property<EmployeeRef, ?>>();
+ employeeColumns.add(EmployeeRef.USER_NAME);
+ employeeColumns.add(EmployeeRef.DISPLAY_NAME);
+
+ reportColumns = new ArrayList<Property<ReportRef, ?>>();
+ reportColumns.add(ReportRef.CREATED);
+ reportColumns.add(ReportRef.PURPOSE);
+ }
+
+ 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)) {
+ return;
+ }
+
+ if (entitiesView.getParent() == null) {
+ panel.clear();
+ panel.add(entitiesView);
+ }
+
+ if (newPlace == Places.EMPLOYEE_LIST) {
+ EntityList<EmployeeRef> list = new EntityList<EmployeeRef>("Employees",
+ entitiesView, employeeColumns);
+ requests.employeeRequest().findAllEmployees().forProperties(
+ employeeColumns).to(list).fire();
+ } else if (newPlace == Places.REPORT_LIST) {
+ EntityList<ReportRef> list = new EntityList<ReportRef>("Reports",
+ entitiesView, reportColumns);
+ requests.reportRequest().findAllReports().forProperties(reportColumns).to(
+ list).fire();
+ }
+ }
+}
\ 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
new file mode 100644
index 0000000..27244da
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/TableEntityListView.java
@@ -0,0 +1,96 @@
+/*
+ * 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.core.client.GWT;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+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.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Widget;
+
+import java.util.List;
+
+/**
+ * Interim table based implementation of {@link EntityListView}.
+ */
+public class TableEntityListView extends Widget implements EntityListView {
+ interface Binder extends UiBinder<Element, TableEntityListView> {
+ }
+
+ private static final Binder BINDER = GWT.create(Binder.class);
+
+ @UiField HeadingElement heading;
+ @UiField TableColElement narrowColumns;
+ @UiField TableRowElement header;
+ @UiField TableElement table;
+
+ public TableEntityListView() {
+ setElement(BINDER.createAndBindUi(this));
+ }
+
+ public void setColumnNames(List<String> names) {
+ NodeList<TableCellElement> cells = header.getCells();
+ for (int i = 0; i < names.size(); i++) {
+ cells.getItem(i).setInnerText(names.get(i));
+ }
+ }
+
+ public void setHeading(String text) {
+ heading.setInnerText(text);
+ }
+
+ public void setValues(List<List<String>> 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);
+
+ if (r < tableRows.getLength()) {
+ reuseRow(r, tableRows, valueRow);
+ } else {
+ TableRowElement tableRow = Document.get().createTRElement();
+ for (String s : valueRow) {
+ TableCellElement tableCell = Document.get().createTDElement();
+ tableCell.setInnerText(s);
+ tableRow.appendChild(tableCell);
+ }
+ table.appendChild(tableRow);
+ }
+ r++;
+ }
+ while (r < tableRows.getLength()) {
+ table.removeChild(tableRows.getItem(r));
+ }
+ }
+
+ private void reuseRow(int r, NodeList<TableRowElement> tableRows,
+ List<String> valueRow) {
+ TableRowElement tableRow = tableRows.getItem(r);
+ NodeList<TableCellElement> tableCells = tableRow.getCells();
+
+ for (int i = 0; i < valueRow.size(); i++) {
+ tableCells.getItem(i).setInnerText(valueRow.get(i));
+ }
+ }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/TableEntityListView.ui.xml b/bikeshed/src/com/google/gwt/sample/expenses/client/TableEntityListView.ui.xml
new file mode 100644
index 0000000..8df3c5b
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/TableEntityListView.ui.xml
@@ -0,0 +1,22 @@
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'>
+ <ui:style>
+ table.reports td {
+ border-width: 1px;
+ padding: 1px;
+ border-style: solid;
+ background-color: white;
+ }
+ </ui:style>
+ <div>
+ <h3 ui:field='heading'/>
+ <table ui:field='table' class='{style.reports}' width='100%'>
+ <col ui:field='narrowColumns' width='0%'></col>
+ <col width='100%'></col>
+ <tr ui:field='header'>
+ <th></th>
+ <th align='left'></th>
+ </tr>
+ </table>
+ </div>
+</ui:UiBinder>
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/EditEntityPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EditEntityPlace.java
new file mode 100644
index 0000000..33961f0
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EditEntityPlace.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.place;
+
+import com.google.gwt.sample.expenses.shared.ExpensesEntity;
+
+/**
+ *
+ */
+public class EditEntityPlace extends EntityPlace {
+
+ /**
+ * @param entityRef The entity to edit
+ */
+ public EditEntityPlace(ExpensesEntity<?> entityRef) {
+ super(entityRef);
+ }
+
+ public void accept(ExpensesScaffoldPlaceVisitor visitor) {
+ visitor.visit(this);
+ }
+
+ public <T> T accept(ExpensesScaffoldPlaceFilter<T> filter) {
+ return filter.filter(this);
+ }
+}
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..d54128b
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityDetailsPlace.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.place;
+
+import com.google.gwt.sample.expenses.shared.ExpensesEntity;
+
+/**
+ *
+ */
+public class EntityDetailsPlace extends EntityPlace {
+
+ /**
+ * @param entityRef The entity to edit
+ */
+ public EntityDetailsPlace(ExpensesEntity<?> entityRef) {
+ super(entityRef);
+ }
+
+ public void accept(ExpensesScaffoldPlaceVisitor visitor) {
+ visitor.visit(this);
+ }
+
+ public <T> T accept(ExpensesScaffoldPlaceFilter<T> filter) {
+ return filter.filter(this);
+ }
+}
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
new file mode 100644
index 0000000..0ffca69
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityListPlace.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.client.place;
+
+
+/**
+ * Place in the app that lists all Entities of a type.
+ */
+public class EntityListPlace extends ExpensesScaffoldPlace {
+
+ public void accept(ExpensesScaffoldPlaceVisitor visitor) {
+ visitor.visit(this);
+ }
+
+ public <T> T accept(ExpensesScaffoldPlaceFilter<T> filter) {
+ return filter.filter(this);
+ }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityPlace.java
new file mode 100644
index 0000000..011b37c
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/EntityPlace.java
@@ -0,0 +1,54 @@
+/*
+ * 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.ExpensesEntity;
+
+/**
+ * A place in the app focused on a particular {@link ExpensesEntity}
+ */
+public abstract class EntityPlace extends ExpensesScaffoldPlace {
+ private final ExpensesEntity<?> entityRef;
+
+ public EntityPlace(ExpensesEntity<?> entityRef) {
+ assert null != entityRef;
+ this.entityRef = entityRef;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ EntityPlace other = (EntityPlace) obj;
+ return entityRef.getId().equals(other.entityRef.getId());
+ }
+
+ public ExpensesEntity<?> getEntity() {
+ return entityRef;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + entityRef.getId().hashCode();
+ return result;
+ }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java b/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.java
new file mode 100644
index 0000000..bf19125
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlace.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.client.place;
+
+import com.google.gwt.app.place.Place;
+
+/**
+ * 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);
+}
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
new file mode 100644
index 0000000..15849da
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceFilter.java
@@ -0,0 +1,44 @@
+/*
+ * 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
new file mode 100644
index 0000000..096c2e2
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/ExpensesScaffoldPlaceVisitor.java
@@ -0,0 +1,38 @@
+/*
+ * 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
new file mode 100644
index 0000000..c1e44c1
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/client/place/Places.java
@@ -0,0 +1,50 @@
+/*
+ * 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.ExpensesEntity;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * 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();
+
+ /**
+ * @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;
+ }
+
+ public EntityDetailsPlace getDetailsPlaceFor(ExpensesEntity<?> e) {
+ return new EntityDetailsPlace(e);
+ }
+
+ public EditEntityPlace getEditPlaceFor(ExpensesEntity<?> e) {
+ return new EditEntityPlace(e);
+ }
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gen/EmployeeRequestImpl.java b/bikeshed/src/com/google/gwt/sample/expenses/gen/EmployeeRequestImpl.java
index d9ffb1d..a464655 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gen/EmployeeRequestImpl.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gen/EmployeeRequestImpl.java
@@ -31,6 +31,7 @@
import com.google.gwt.valuestore.shared.Values;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
@@ -91,6 +92,14 @@
// values.subscribe(watcher, future, properties);
}
+ public EntityListRequest<EmployeeRef> forProperties(
+ Collection<Property<EmployeeRef, ?>> properties) {
+ for (Property<EmployeeRef, ?> property : properties) {
+ forProperty(property);
+ }
+ return this;
+ }
+
public EntityListRequest<EmployeeRef> forProperty(
Property<EmployeeRef, ?> property) {
return this;
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gen/MethodName.java b/bikeshed/src/com/google/gwt/sample/expenses/gen/MethodName.java
index 662287e..bb40955 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gen/MethodName.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gen/MethodName.java
@@ -19,5 +19,5 @@
* Represents the MethodName.
*/
public enum MethodName {
- FIND_ALL_EMPLOYEES, FIND_EMPLOYEE, FIND_REPORTS_BY_EMPLOYEE, SYNC,
+ FIND_ALL_EMPLOYEES, FIND_ALL_REPORTS, FIND_EMPLOYEE, FIND_REPORTS_BY_EMPLOYEE, SYNC,
}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/gen/ReportRequestImpl.java b/bikeshed/src/com/google/gwt/sample/expenses/gen/ReportRequestImpl.java
index 84cbf5d..528dd1c 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/gen/ReportRequestImpl.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/gen/ReportRequestImpl.java
@@ -33,6 +33,7 @@
import com.google.gwt.valuestore.shared.Values;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -101,15 +102,94 @@
// values.subscribe(watcher, future, properties);
}
+ public EntityListRequest<ReportRef> forProperties(
+ Collection<Property<ReportRef, ?>> properties) {
+ for (Property<ReportRef, ?> property : properties) {
+ forProperty(property);
+ }
+ return this;
+ }
+
public EntityListRequest<ReportRef> forProperty(Property<ReportRef, ?> property) {
properties.add(property);
return this;
}
+
public EntityListRequest<ReportRef> to(HasValueList<Values<ReportRef>> watcher) {
this.watcher = watcher;
return this;
}
};
}
+
+ public EntityListRequest<ReportRef> findAllReports() {
+ return new EntityListRequest<ReportRef>() {
+ private HasValueList<Values<ReportRef>> watcher;
+
+ public void fire() {
+
+ // TODO: need someway to track that this request has been issued so that
+ // we don't issue another request that arrives while we are waiting for
+ // the response.
+ RequestBuilder builder = new RequestBuilder(RequestBuilder.GET,
+ "/expenses/data?methodName=" + MethodName.FIND_ALL_REPORTS.name());
+ builder.setCallback(new RequestCallback() {
+
+ public void onError(Request request, Throwable exception) {
+ // shell.error.setInnerText(SERVER_ERROR);
+ }
+
+ public void onResponseReceived(Request request, Response response) {
+ if (200 == response.getStatusCode()) {
+ String text = response.getText();
+ JsArray<ValuesImpl<ReportRef>> valueArray = ValuesImpl.arrayFromJson(text);
+ // Handy for FireBug snooping
+// Document.get().getBody().setPropertyJSO("foo", valueArray);
+ List<Values<ReportRef>> valueList = new ArrayList<Values<ReportRef>>(
+ valueArray.length());
+ for (int i = 0; i < valueArray.length(); i++) {
+ ValuesImpl<ReportRef> values = valueArray.get(i);
+ values.setPropertyHolder(new ReportRef(values.get(ReportRef.ID),
+ values.get(ReportRef.VERSION)));
+ valueList.add(values);
+ }
+ watcher.setValueList(valueList);
+ } else {
+ // shell.error.setInnerText(SERVER_ERROR + " ("
+ // + response.getStatusText() + ")");
+ }
+ }
+ });
+
+ try {
+ builder.send();
+ } catch (RequestException e) {
+ // shell.error.setInnerText(SERVER_ERROR + " (" + e.getMessage() +
+ // ")");
+ }
+
+ // values.subscribe(watcher, future, properties);
+ }
+
+ public EntityListRequest<ReportRef> forProperties(
+ Collection<Property<ReportRef, ?>> properties) {
+ for (Property<ReportRef, ?> property : properties) {
+ forProperty(property);
+ }
+ return this;
+ }
+
+ public EntityListRequest<ReportRef> forProperty(
+ Property<ReportRef, ?> property) {
+ return this;
+ }
+
+ public EntityListRequest<ReportRef> to(
+ HasValueList<Values<ReportRef>> watcher) {
+ this.watcher = watcher;
+ return this;
+ }
+ };
+ }
}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/server/ExpensesDataServlet.java b/bikeshed/src/com/google/gwt/sample/expenses/server/ExpensesDataServlet.java
index f4ea982..9d67502 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/server/ExpensesDataServlet.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/server/ExpensesDataServlet.java
@@ -18,11 +18,13 @@
import com.google.gwt.sample.expenses.gen.MethodName;
import com.google.gwt.sample.expenses.server.domain.Employee;
import com.google.gwt.sample.expenses.server.domain.Report;
+import com.google.gwt.sample.expenses.server.domain.Storage;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.PrintWriter;
@@ -47,12 +49,36 @@
case FIND_ALL_EMPLOYEES:
findAllEmployees(writer);
break;
+ case FIND_ALL_REPORTS:
+ findAllReports(writer);
+ break;
case FIND_EMPLOYEE:
// TODO
break;
case FIND_REPORTS_BY_EMPLOYEE:
findReportsByEmployee(request, writer);
break;
+ default:
+ System.err.println("Unknown method " + methodName);
+ break;
+ }
+ writer.flush();
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws IOException {
+
+ response.setStatus(HttpServletResponse.SC_OK);
+ MethodName methodName = getMethodName(request.getParameter("methodName"));
+ PrintWriter writer = response.getWriter();
+ switch (methodName) {
+ case SYNC:
+ sync(request, writer);
+ break;
+ default:
+ System.err.println("POST: unknown method " + methodName);
+ break;
}
writer.flush();
}
@@ -84,31 +110,20 @@
writer.print(jsonArray.toString());
}
+ private void findAllReports(PrintWriter writer) {
+ JSONArray jsonArray = new JSONArray();
+ for (Report r : Report.findAllReports()) {
+ reportToJson(jsonArray, r);
+ }
+ writer.print(jsonArray.toString());
+ }
+
private void findReportsByEmployee(HttpServletRequest request,
PrintWriter writer) {
JSONArray jsonArray = new JSONArray();
Long id = Long.valueOf(request.getParameter("id"));
for (Report r : Report.findReportsByEmployee(id)) {
- try {
- // TODO should only be getting requested properties
- // TODO clearly there should be centralized code for these conversions
- JSONObject jsonObject = new JSONObject();
- jsonObject.put(
- com.google.gwt.sample.expenses.shared.EmployeeRef.ID.getName(),
- Long.toString(r.getId()));
- jsonObject.put(
- com.google.gwt.sample.expenses.shared.ReportRef.VERSION.getName(),
- r.getVersion().intValue());
- jsonObject.put(
- com.google.gwt.sample.expenses.shared.ReportRef.CREATED.getName(),
- Double.valueOf(r.getCreated().getTime()));
- jsonObject.put(
- com.google.gwt.sample.expenses.shared.ReportRef.PURPOSE.getName(),
- r.getPurpose());
- jsonArray.put(jsonObject);
- } catch (JSONException ex) {
- System.err.println("Unable to create a JSON object " + ex);
- }
+ reportToJson(jsonArray, r);
}
writer.print(jsonArray.toString());
}
@@ -126,4 +141,69 @@
throw new IllegalArgumentException("unknown methodName: " + methodString);
}
+ /**
+ * @param jsonArray
+ * @param r
+ */
+ private void reportToJson(JSONArray jsonArray, Report r) {
+ try {
+ // TODO should only be getting requested properties
+ // TODO clearly there should be centralized code for these conversions
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put(
+ com.google.gwt.sample.expenses.shared.EmployeeRef.ID.getName(),
+ Long.toString(r.getId()));
+ jsonObject.put(
+ com.google.gwt.sample.expenses.shared.ReportRef.VERSION.getName(),
+ r.getVersion().intValue());
+ jsonObject.put(
+ com.google.gwt.sample.expenses.shared.ReportRef.CREATED.getName(),
+ Double.valueOf(r.getCreated().getTime()));
+ jsonObject.put(
+ com.google.gwt.sample.expenses.shared.ReportRef.PURPOSE.getName(),
+ r.getPurpose());
+ jsonArray.put(jsonObject);
+ } catch (JSONException ex) {
+ System.err.println("Unable to create a JSON object " + ex);
+ }
+ }
+
+ /**
+ * @param request
+ * @param writer
+ * @throws IOException
+ */
+ private void sync(HttpServletRequest request, PrintWriter writer)
+ throws IOException {
+ int contentLength = request.getContentLength();
+ byte contentBytes[] = new byte[contentLength];
+ BufferedInputStream bis = new BufferedInputStream(request.getInputStream());
+ int readBytes = 0;
+ while (bis.read(contentBytes, readBytes, contentLength - readBytes) > 0) {
+ // read the contents
+ }
+ // TODO: encoding issues?
+ String content = new String(contentBytes);
+ try {
+ JSONArray reportArray = new JSONArray(content);
+ int length = reportArray.length();
+ if (length > 0) {
+ JSONObject report = reportArray.getJSONObject(0);
+ Report r = Report.findReport(report.getLong(com.google.gwt.sample.expenses.shared.ReportRef.ID.getName()));
+ r.setPurpose(report.getString(com.google.gwt.sample.expenses.shared.ReportRef.PURPOSE.getName()));
+ r = Storage.INSTANCE.persist(r);
+ report.put(
+ com.google.gwt.sample.expenses.shared.ReportRef.VERSION.getName(),
+ r.getVersion());
+ JSONArray returnArray = new JSONArray();
+ // TODO: don't echo back everything.
+ returnArray.put(report);
+ writer.print(returnArray.toString());
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ // TODO: return an error.
+ }
+ return;
+ }
}
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 870003f..a87c719 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
@@ -15,7 +15,6 @@
*/
package com.google.gwt.sample.expenses.server.domain;
-
import java.util.Date;
import java.util.List;
@@ -24,12 +23,24 @@
*/
// @javax.persistence.Entity
public class Report implements Entity {
+
+ /**
+ * @return
+ */
+ public static List<Report> findAllReports() {
+ return Storage.INSTANCE.findAllReports();
+ }
+
+ public static Report findReport(Long id) {
+ return Storage.INSTANCE.findReport(id);
+ }
+
public static List<Report> findReportsByEmployee(long id) {
return Storage.INSTANCE.findReportsByEmployee(id);
}
-
private final Long id;
- private final Integer version;
+
+private final Integer version;
// @javax.validation.constraints.NotNull
// @javax.validation.constraints.Past
@@ -46,13 +57,13 @@
// @javax.persistence.JoinColumn
private Employee reporter;
-// @javax.validation.constraints.Size(min = 3, max = 100)
- private String purpose;
-
// @javax.persistence.OneToMany(cascade = javax.persistence.CascadeType.ALL,
// mappedBy = "report")
// private Set<ReportItem> items = new HashSet<ReportItem>();
+ // @javax.validation.constraints.Size(min = 3, max = 100)
+ private String purpose;
+
// @javax.persistence.ManyToOne(targetEntity =
// com.google.io.expenses.server.domain.Employee.class)
// @javax.persistence.JoinColumn
@@ -120,14 +131,14 @@
public Integer getVersion() {
return version;
}
-
+
/**
* @param approvedSupervisor the approved_supervisor to set
*/
public void setApprovedSupervisor(Employee approvedSupervisor) {
this.approvedSupervisor = approvedSupervisor;
}
-
+
public void setCreated(Date date) {
this.created = date;
}
@@ -138,14 +149,14 @@
public void setPurpose(String purpose) {
this.purpose = purpose;
}
-
+
/**
* @param reporter the reporter to set
*/
public void setReporter(Employee reporter) {
this.reporter = reporter;
}
-
+
/**
* @param status the status to set
*/
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Storage.java b/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Storage.java
index 6772419..8a8beaa 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Storage.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/server/domain/Storage.java
@@ -15,7 +15,6 @@
*/
package com.google.gwt.sample.expenses.server.domain;
-
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@@ -29,8 +28,8 @@
* Pretend pool of domain objects, trying to act more or less like persistence
* frameworks do. For goodness sake don't imitate this for production code.
*/
-class Storage {
- static final Storage INSTANCE;
+public class Storage {
+ public static final Storage INSTANCE;
static {
INSTANCE = new Storage();
fill(INSTANCE);
@@ -134,6 +133,39 @@
private int getDepth = 0;
private long serial = 0;
+ public synchronized <E extends Entity> E persist(final E delta) {
+ E next = null;
+ E previous = null;
+
+ if (delta.getId() == null) {
+ next = delta.accept(new CreationVisitor<E>(++serial, 0));
+ delta.accept(new NullFieldFiller(next));
+ } else {
+ previous = get(delta);
+ if (!previous.getVersion().equals(delta.getVersion())) {
+ throw new IllegalArgumentException(String.format(
+ "Version mismatch of %s. Cannot update %d from %d", delta,
+ previous.getVersion(), delta.getVersion()));
+ }
+
+ next = previous.accept(new CreationVisitor<E>(previous.getId(),
+ previous.getVersion() + 1));
+
+ NullFieldFiller filler = new NullFieldFiller(next);
+ // Copy the changed fields into the new version
+ delta.accept(filler);
+ // And copy the old fields into any null fields remaining on the new
+ // version
+ previous.accept(filler);
+ }
+
+ next.accept(new RelationshipValidationVisitor());
+
+ updateIndices(previous, next);
+ soup.put(next.getId(), next);
+ return get(next);
+ }
+
synchronized List<Employee> findAllEmployees() {
List<Employee> rtn = new ArrayList<Employee>();
for (Map.Entry<String, Long> entry : employeeUserNameIndex.entrySet()) {
@@ -141,10 +173,38 @@
}
return rtn;
}
+
+ synchronized List<Report> findAllReports() {
+ List<Report> rtn = new ArrayList<Report>();
+ for (Entity e : soup.values()) {
+ if (e instanceof Report) {
+ rtn.add(get((Report) e));
+ }
+ }
+ return rtn;
+ }
+
+ /**
+ * Returns Employee by id.
+ * @param id
+ * @return
+ */
+ synchronized Employee findEmployee(Long id) {
+ return get((Employee) rawGet(id));
+ }
synchronized Employee findEmployeeByUserName(String userName) {
Long id = employeeUserNameIndex.get(userName);
- return get((Employee) rawGet(id));
+ return findEmployee(id);
+ }
+
+ /**
+ * Returns report by id.
+ * @param id
+ * @return
+ */
+ synchronized Report findReport(Long id) {
+ return get((Report) rawGet(id));
}
synchronized List<Report> findReportsByEmployee(long id) {
@@ -200,39 +260,6 @@
}
}
- synchronized <E extends Entity> E persist(final E delta) {
- E next = null;
- E previous = null;
-
- if (delta.getId() == null) {
- next = delta.accept(new CreationVisitor<E>(++serial, 0));
- delta.accept(new NullFieldFiller(next));
- } else {
- previous = get(delta);
- if (!previous.getVersion().equals(delta.getVersion())) {
- throw new IllegalArgumentException(String.format(
- "Version mismatch of %s. Cannot update %d from %d", delta,
- previous.getVersion(), delta.getVersion()));
- }
-
- next = previous.accept(new CreationVisitor<E>(previous.getId(),
- previous.getVersion() + 1));
-
- NullFieldFiller filler = new NullFieldFiller(next);
- // Copy the changed fields into the new version
- delta.accept(filler);
- // And copy the old fields into any null fields remaining on the new
- // version
- previous.accept(filler);
- }
-
- next.accept(new RelationshipValidationVisitor());
-
- updateIndices(previous, next);
- soup.put(next.getId(), next);
- return get(next);
- }
-
/**
* @param original Entity to copy
* @return copy of original
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeRef.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeRef.java
index d013a85..3c844e0 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeRef.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/EmployeeRef.java
@@ -15,7 +15,6 @@
*/
package com.google.gwt.sample.expenses.shared;
-import com.google.gwt.requestfactory.shared.EntityRef;
import com.google.gwt.requestfactory.shared.FieldRef;
import com.google.gwt.requestfactory.shared.LongString;
import com.google.gwt.requestfactory.shared.ServerType;
@@ -26,7 +25,7 @@
* domain.Employee}.
*/
@ServerType(com.google.gwt.sample.expenses.server.domain.Employee.class)
-public class EmployeeRef implements EntityRef<EmployeeRef> {
+public class EmployeeRef implements ExpensesEntity<EmployeeRef> {
@LongString
public static final Property<EmployeeRef, String> ID = new Property<EmployeeRef, String>(
@@ -51,6 +50,14 @@
this.version = version;
}
+ public <T> T accept(ExpensesEntityFilter<T> filter) {
+ return filter.filter(this);
+ }
+
+ public void accept(ExpensesEntityVisitor visitor) {
+ visitor.visit(this);
+ }
+
public <V> FieldRef<EmployeeRef, V> getFieldRef(Property<EmployeeRef, V> property) {
return new FieldRef<EmployeeRef, V>(this, property);
}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpenseRequestFactory.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpenseRequestFactory.java
index b9b29e7..5de9fa7 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpenseRequestFactory.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpenseRequestFactory.java
@@ -48,6 +48,11 @@
*/
EntityListRequest<ReportRef> findReportsByEmployee(
@LongString FieldRef<EmployeeRef, String> id);
+
+ /**
+ * @return a request object
+ */
+ EntityListRequest<ReportRef> findAllReports();
}
/**
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntity.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntity.java
new file mode 100644
index 0000000..273455b
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntity.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.shared;
+
+import com.google.gwt.requestfactory.shared.EntityRef;
+
+/**
+ * Implemented by entities of the {@link ExpensesRequestFactory}.
+ *
+ * @param <E> the type of this entity
+ */
+public interface ExpensesEntity<E extends ExpensesEntity<E>>
+ extends EntityRef<E> {
+
+ void accept(ExpensesEntityVisitor visitor);
+
+ <T> T accept(ExpensesEntityFilter<T> filter);
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityFilter.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityFilter.java
new file mode 100644
index 0000000..e761285
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityFilter.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.shared;
+
+/**
+ * Implemented by filters of {@link ExpensesEntity}.
+ *
+ * @param <T> the type to filter to
+ */
+public interface ExpensesEntityFilter<T> {
+ T filter(EmployeeRef employeeRef);
+
+ T filter(ReportRef reportRef);
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityVisitor.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityVisitor.java
new file mode 100644
index 0000000..8ccbb7a
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/ExpensesEntityVisitor.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+/**
+ * Implemented by visitors of {@link ExpensesEntity}.
+ */
+public interface ExpensesEntityVisitor {
+ void visit(EmployeeRef employeeRef);
+ void visit(ReportRef reportRef);
+}
diff --git a/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportRef.java b/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportRef.java
index dcf9020..907a489 100644
--- a/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportRef.java
+++ b/bikeshed/src/com/google/gwt/sample/expenses/shared/ReportRef.java
@@ -15,7 +15,6 @@
*/
package com.google.gwt.sample.expenses.shared;
-import com.google.gwt.requestfactory.shared.EntityRef;
import com.google.gwt.requestfactory.shared.FieldRef;
import com.google.gwt.requestfactory.shared.LongString;
import com.google.gwt.requestfactory.shared.ServerType;
@@ -28,7 +27,7 @@
* {@link com.google.gwt.sample.expenses.server.domain.Report domain.Report}.
*/
@ServerType(com.google.gwt.sample.expenses.server.domain.Report.class)
-public class ReportRef implements EntityRef<ReportRef> {
+public class ReportRef implements ExpensesEntity<ReportRef> {
@LongString
public static final Property<ReportRef, String> ID = new Property<ReportRef, String>(
@@ -51,6 +50,14 @@
this.version = version;
}
+ public <T> T accept(ExpensesEntityFilter<T> filter) {
+ return filter.filter(this);
+ }
+
+ public void accept(ExpensesEntityVisitor visitor) {
+ visitor.visit(this);
+ }
+
public <V> FieldRef<ReportRef, V> getFieldRef(Property<ReportRef, V> property) {
return new FieldRef<ReportRef, V>(this, property);
}
diff --git a/bikeshed/src/com/google/gwt/user/client/ui/HasValueMap.java b/bikeshed/src/com/google/gwt/user/client/ui/HasValueMap.java
new file mode 100644
index 0000000..ee33e3a
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/user/client/ui/HasValueMap.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.user.client.ui;
+
+import java.util.Map;
+
+/**
+ * Implemented by widgets that let the user pick from a set
+ * of values.
+ *
+ * @param <T> the value type
+ */
+public interface HasValueMap<T> {
+ /**
+ * @param values A map of acceptable values and their display strings
+ */
+ public void setValues(Map<? extends T, String> values);
+}
diff --git a/bikeshed/src/com/google/gwt/user/client/ui/ValueListBox.java b/bikeshed/src/com/google/gwt/user/client/ui/ValueListBox.java
new file mode 100644
index 0000000..ddb0ebf
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/user/client/ui/ValueListBox.java
@@ -0,0 +1,113 @@
+/*
+ * 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;
+
+import com.google.gwt.event.dom.client.ChangeEvent;
+import com.google.gwt.event.dom.client.ChangeHandler;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A {@link HasValue} variation on {@link ListBox}.
+ *
+ * @param <T> the value type
+ */
+public class ValueListBox<T> extends Composite implements HasValue<T>,
+ HasValueMap<T> {
+
+ 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));
+ }
+
+ public HandlerRegistration addValueChangeHandler(ValueChangeHandler<T> handler) {
+ return addHandler(handler, ValueChangeEvent.getType());
+ }
+
+ public T getValue() {
+ int selectedIndex = getListBox().getSelectedIndex();
+ if (selectedIndex > -1) {
+ return indexToValue.get(selectedIndex);
+ }
+
+ return null;
+ }
+
+ public void setValue(T value) {
+ setValue(value, false);
+ }
+
+ /**
+ * Set the value, or clear it if the given value is not in the value map.
+ */
+ public void setValue(T value, boolean fireEvents) {
+ T oldValue = getValue();
+ ListBox listBox = getListBox();
+ Integer index = valueToIndex.get(value);
+ if (index == null) {
+ listBox.setSelectedIndex(-1);
+ }
+ listBox.setSelectedIndex(index);
+ if (fireEvents) {
+ ValueChangeEvent.fireIfNotEqual(this, oldValue, value);
+ }
+ }
+
+ public void setValues(Map<? extends T, String> values) {
+ ListBox listBox = getListBox();
+
+ indexToValue.clear();
+ valueToIndex.clear();
+ listBox.clear();
+ int i = 0;
+ for (T key : values.keySet()) {
+ indexToValue.add(key);
+ valueToIndex.put(key, i++);
+ listBox.addItem(values.get(key));
+ }
+ }
+
+ public void setVisibleItemCount(int size) {
+ getListBox().setVisibleItemCount(size);
+ }
+
+ @Override
+ protected void initWidget(Widget widget) {
+ super.initWidget(widget);
+ getListBox().addChangeHandler(new ChangeHandler() {
+ public void onChange(ChangeEvent event) {
+ ValueChangeEvent.fire(ValueListBox.this, getValue());
+ }
+ });
+ }
+
+ /**
+ * @return
+ */
+ private ListBox getListBox() {
+ return (ListBox) getWidget();
+ }
+}
diff --git a/bikeshed/war/ExpensesScaffold.html b/bikeshed/war/ExpensesScaffold.html
new file mode 100644
index 0000000..ff55275
--- /dev/null
+++ b/bikeshed/war/ExpensesScaffold.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title>Expenses Entity Browser</title>
+ <script type="text/javascript" language="javascript" src="expensesScaffold/expensesScaffold.nocache.js"></script>
+ </head>
+
+ <body>
+ <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
+ <span id='loading'><i>…loading…</i></span>
+ </body>
+</html>
\ No newline at end of file
diff --git a/bikeshed/war/WEB-INF/logging.properties b/bikeshed/war/WEB-INF/logging.properties
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bikeshed/war/WEB-INF/logging.properties
diff --git a/user/src/com/google/gwt/uibinder/rebind/XMLElement.java b/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
index 9996f9f..b9b9377 100644
--- a/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
+++ b/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
@@ -244,7 +244,11 @@
return defaultValue;
}
String value = attribute.consumeRawValue();
- return getParser(attribute, types).parse(value);
+ AttributeParser parser = getParser(attribute, types);
+ if (parser == null) {
+ logger.die("In %s, no such attribute %s", this, name);
+ }
+ return parser.parse(value);
}
/**