Checkpoint work on Stock demo
Review by: jgw@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7691 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/bikeshed/src/com/google/gwt/bikeshed/list/shared/AsyncListModel.java b/bikeshed/src/com/google/gwt/bikeshed/list/shared/AsyncListModel.java
index 903041e..7631110 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/list/shared/AsyncListModel.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/list/shared/AsyncListModel.java
@@ -30,6 +30,7 @@
* @param <T> the data type
*/
public static interface DataSource<T> {
+
/**
* Request that the data source pushes new data to the client. The data
* source should call {@link #updateViewData} and/or {@link #updateDataSize}
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/Columns.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/Columns.java
new file mode 100644
index 0000000..8f743ba
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/Columns.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.bikeshed.sample.stocks.client;
+
+import com.google.gwt.bikeshed.cells.client.ButtonCell;
+import com.google.gwt.bikeshed.cells.client.CheckboxCell;
+import com.google.gwt.bikeshed.cells.client.CurrencyCell;
+import com.google.gwt.bikeshed.cells.client.TextCell;
+import com.google.gwt.bikeshed.list.client.Column;
+import com.google.gwt.bikeshed.sample.stocks.shared.StockQuote;
+import com.google.gwt.bikeshed.sample.stocks.shared.Transaction;
+
+/**
+ * Column definitions for the stock demo.
+ */
+public class Columns {
+
+ static Column<StockQuote, String> buyColumn = new Column<StockQuote, String>(
+ new ButtonCell()) {
+ @Override
+ protected String getValue(StockQuote object) {
+ return "Buy";
+ }
+ };
+
+ static Column<StockQuote, Integer> dollarsColumn =
+ new Column<StockQuote, Integer>(new CurrencyCell()) {
+ @Override
+ protected Integer getValue(StockQuote object) {
+ return object.getPrice() * object.getSharesOwned();
+ }
+ };
+
+ static Column<StockQuote, Boolean> favoriteColumn =
+ new Column<StockQuote, Boolean>(new CheckboxCell()) {
+ @Override
+ protected Boolean getValue(StockQuote object) {
+ return object.isFavorite();
+ }
+ };
+
+ static Column<StockQuote, String> nameColumn =
+ new Column<StockQuote, String>(new TextCell()) {
+ @Override
+ protected String getValue(StockQuote object) {
+ return object.getName();
+ }
+ };
+
+ static Column<StockQuote, Integer> priceColumn =
+ new Column<StockQuote, Integer>(new CurrencyCell()) {
+ @Override
+ protected Integer getValue(StockQuote object) {
+ return object.getPrice();
+ }
+ };
+
+ static Column<StockQuote, String> sellColumn =
+ new Column<StockQuote, String>(new ButtonCell()) {
+ @Override
+ protected String getValue(StockQuote object) {
+ return "Sell";
+ }
+ };
+
+ static Column<StockQuote, String> sharesColumn =
+ new Column<StockQuote, String>(new TextCell()) {
+ @Override
+ protected String getValue(StockQuote object) {
+ return "" + object.getSharesOwned();
+ }
+ };
+
+ static Column<Transaction, String> subtotalColumn =
+ new Column<Transaction, String>(new TextCell()) {
+ @Override
+ protected String getValue(Transaction object) {
+ int price = object.getActualPrice() * object.getQuantity();
+ return (object.isBuy() ? " (" : " ") + StockSample.getFormattedPrice(price) +
+ (object.isBuy() ? ")" : "");
+ }
+ };
+
+ static Column<StockQuote, String> tickerColumn =
+ new Column<StockQuote, String>(new TextCell()) {
+ @Override
+ protected String getValue(StockQuote object) {
+ return object.getTicker();
+ }
+ };
+
+ static Column<Transaction, String> transactionColumn =
+ new Column<Transaction, String>(new TextCell()) {
+ @Override
+ protected String getValue(Transaction object) {
+ return object.toString();
+ }
+ };
+}
\ No newline at end of file
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockQueryWidget.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockQueryWidget.java
new file mode 100644
index 0000000..13f44e0
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockQueryWidget.java
@@ -0,0 +1,74 @@
+/*
+ * 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.bikeshed.sample.stocks.client;
+
+import com.google.gwt.bikeshed.list.client.PagingTableListView;
+import com.google.gwt.bikeshed.list.shared.ListModel;
+import com.google.gwt.bikeshed.sample.stocks.shared.StockQuote;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.event.dom.client.KeyUpEvent;
+import com.google.gwt.event.dom.client.KeyUpHandler;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.DockLayoutPanel;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.ScrollPanel;
+import com.google.gwt.user.client.ui.TextBox;
+
+/**
+ * A widget containing a search box and a results table.
+ */
+public class StockQueryWidget extends Composite {
+
+ private final TextBox queryField = new TextBox();
+ private PagingTableListView<StockQuote> resultsTable;
+
+ public StockQueryWidget(ListModel<StockQuote> searchListModel, final Updater updater) {
+ // Create the results table.
+ resultsTable = new PagingTableListView<StockQuote>(searchListModel, 10);
+ resultsTable.addColumn(Columns.favoriteColumn);
+ resultsTable.addColumn(Columns.tickerColumn);
+ resultsTable.addColumn(Columns.nameColumn);
+ resultsTable.addColumn(Columns.priceColumn);
+ resultsTable.addColumn(Columns.buyColumn);
+
+ // Focus the cursor on the name field when the app loads
+ queryField.setFocus(true);
+ queryField.selectAll();
+ queryField.setText("G");
+
+ // Add a handler to send the name to the server
+ queryField.addKeyUpHandler(new KeyUpHandler() {
+ public void onKeyUp(KeyUpEvent event) {
+ updater.update();
+ }
+ });
+
+ DockLayoutPanel layoutPanel = new DockLayoutPanel(Unit.EM);
+
+ HorizontalPanel panel = new HorizontalPanel();
+ panel.add(new Label("Enter query: "));
+ panel.add(queryField);
+ layoutPanel.addNorth(panel, 2.0);
+ layoutPanel.add(new ScrollPanel(resultsTable));
+
+ initWidget(layoutPanel);
+ }
+
+ public String getSearchQuery() {
+ return queryField.getText();
+ }
+}
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java
index d74790a..b02bea5 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java
@@ -15,40 +15,36 @@
*/
package com.google.gwt.bikeshed.sample.stocks.client;
-import com.google.gwt.bikeshed.cells.client.ButtonCell;
-import com.google.gwt.bikeshed.cells.client.CheckboxCell;
-import com.google.gwt.bikeshed.cells.client.CurrencyCell;
import com.google.gwt.bikeshed.cells.client.FieldUpdater;
-import com.google.gwt.bikeshed.cells.client.TextCell;
-import com.google.gwt.bikeshed.list.client.Column;
import com.google.gwt.bikeshed.list.client.PagingTableListView;
import com.google.gwt.bikeshed.list.shared.AsyncListModel;
import com.google.gwt.bikeshed.list.shared.ListListModel;
import com.google.gwt.bikeshed.list.shared.Range;
import com.google.gwt.bikeshed.list.shared.AsyncListModel.DataSource;
+import com.google.gwt.bikeshed.sample.stocks.client.TransactionTreeViewModel.SectorListModel;
import com.google.gwt.bikeshed.sample.stocks.shared.StockQuote;
import com.google.gwt.bikeshed.sample.stocks.shared.StockQuoteList;
import com.google.gwt.bikeshed.sample.stocks.shared.StockRequest;
import com.google.gwt.bikeshed.sample.stocks.shared.StockResponse;
import com.google.gwt.bikeshed.sample.stocks.shared.Transaction;
import com.google.gwt.bikeshed.tree.client.SideBySideTreeView;
-import com.google.gwt.bikeshed.tree.client.StandardTreeView;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
-import com.google.gwt.event.dom.client.KeyUpEvent;
-import com.google.gwt.event.dom.client.KeyUpHandler;
+import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwt.user.client.ui.RootPanel;
-import com.google.gwt.user.client.ui.TextBox;
+import com.google.gwt.user.client.ui.RootLayoutPanel;
+import com.google.gwt.user.client.ui.ScrollPanel;
+import com.google.gwt.user.client.ui.Widget;
import java.util.HashMap;
import java.util.List;
@@ -57,91 +53,14 @@
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
-public class StockSample implements EntryPoint {
+public class StockSample implements EntryPoint, Updater {
- static class Columns {
-
- private static Column<StockQuote, String> buyColumn = new Column<StockQuote, String>(
- new ButtonCell()) {
- @Override
- protected String getValue(StockQuote object) {
- return "Buy";
- }
- };
-
- private static Column<StockQuote, Boolean> favoriteColumn =
- new Column<StockQuote, Boolean>(new CheckboxCell()) {
- @Override
- protected Boolean getValue(StockQuote object) {
- return object.isFavorite();
- }
- };
-
- private static Column<StockQuote, String> nameColumn =
- new Column<StockQuote, String>(new TextCell()) {
- @Override
- protected String getValue(StockQuote object) {
- return object.getName();
- }
- };
-
- private static Column<StockQuote, Integer> priceColumn =
- new Column<StockQuote, Integer>(new CurrencyCell()) {
- @Override
- protected Integer getValue(StockQuote object) {
- return object.getPrice();
- }
- };
-
- private static Column<StockQuote, String> sellColumn =
- new Column<StockQuote, String>(new ButtonCell()) {
- @Override
- protected String getValue(StockQuote object) {
- return "Sell";
- }
- };
-
- private static Column<StockQuote, String> sharesColumn =
- new Column<StockQuote, String>(new TextCell()) {
- @Override
- protected String getValue(StockQuote object) {
- return "" + object.getSharesOwned();
- }
- };
-
- private static Column<Transaction, String> subtotalColumn =
- new Column<Transaction, String>(new TextCell()) {
- @Override
- protected String getValue(Transaction object) {
- int price = object.getActualPrice() * object.getQuantity();
- return (object.isBuy() ? " (" : " ") + getFormattedPrice(price) +
- (object.isBuy() ? ")" : "");
- }
- };
-
- private static Column<StockQuote, String> tickerColumn =
- new Column<StockQuote, String>(new TextCell()) {
- @Override
- protected String getValue(StockQuote object) {
- return object.getTicker();
- }
- };
-
- private static Column<Transaction, String> transactionColumn =
- new Column<Transaction, String>(new TextCell()) {
- @Override
- protected String getValue(Transaction object) {
- return object.toString();
- }
- };
- }
-
/**
* The delay between updates in milliseconds.
*/
private static final int UPDATE_DELAY = 5000;
- private static String getFormattedPrice(int price) {
+ static String getFormattedPrice(int price) {
return NumberFormat.getCurrencyFormat("USD").format(price / 100.0);
}
@@ -157,30 +76,27 @@
*/
private final StockServiceAsync dataService = GWT.create(StockService.class);
- private final Label errorLabel = new Label();
-
private AsyncListModel<StockQuote> favoritesListModel;
private PagingTableListView<StockQuote> favoritesTable;
- private final TextBox queryField = new TextBox();
-
- private PagingTableListView<StockQuote> resultsTable;
+ private final Label netWorthLabel = new Label();
+ private StockQueryWidget queryWidget;
+
private AsyncListModel<StockQuote> searchListModel;
private Map<String, ListListModel<Transaction>> transactionListListModelsByTicker =
new HashMap<String, ListListModel<Transaction>>();
-
+
private ListListModel<Transaction> transactionListModel;
private List<Transaction> transactions;
-
- private PagingTableListView<Transaction> transactionTable;
-
- private StandardTreeView transactionTree1;
- private SideBySideTreeView transactionTree2;
+ private PagingTableListView<Transaction> transactionTable;
+
+ private SideBySideTreeView transactionTree;
+
/**
* The timer used to update the stock quotes.
*/
@@ -191,20 +107,12 @@
}
};
+ private TransactionTreeViewModel treeModel;
+
/**
* This is the entry point method.
*/
public void onModuleLoad() {
- queryField.setText("G");
-
- // Add the nameField and sendButton to the RootPanel
- // Use RootPanel.get() to get the entire body element
- RootPanel.get("queryFieldContainer").add(queryField);
- RootPanel.get("errorLabelContainer").add(errorLabel);
-
- // Focus the cursor on the name field when the app loads
- queryField.setFocus(true);
- queryField.selectAll();
// Create the list models
searchListModel = new AsyncListModel<StockQuote>(
@@ -224,19 +132,12 @@
transactionListModel = new ListListModel<Transaction>();
transactions = transactionListModel.getList();
- // Create the results table.
- resultsTable = new PagingTableListView<StockQuote>(searchListModel, 10);
- resultsTable.addColumn(Columns.favoriteColumn);
- resultsTable.addColumn(Columns.tickerColumn);
- resultsTable.addColumn(Columns.nameColumn);
- resultsTable.addColumn(Columns.priceColumn);
- resultsTable.addColumn(Columns.buyColumn);
-
// Create the favorites table.
favoritesTable = new PagingTableListView<StockQuote>(favoritesListModel, 10);
favoritesTable.addColumn(Columns.tickerColumn);
favoritesTable.addColumn(Columns.priceColumn);
favoritesTable.addColumn(Columns.sharesColumn);
+ favoritesTable.addColumn(Columns.dollarsColumn);
favoritesTable.addColumn(Columns.buyColumn);
favoritesTable.addColumn(Columns.sellColumn);
@@ -245,14 +146,9 @@
transactionTable.addColumn(Columns.transactionColumn);
transactionTable.addColumn(Columns.subtotalColumn);
- // Create the transactions tree.
- transactionTree1 = new StandardTreeView(new TransactionTreeViewModel(favoritesListModel,
- transactionListListModelsByTicker), null);
- transactionTree1.setAnimationEnabled(true);
-
- // Create the transactions tree.
- transactionTree2 = new SideBySideTreeView(new TransactionTreeViewModel(favoritesListModel,
- transactionListListModelsByTicker), null, 200, 200);
+ treeModel = new TransactionTreeViewModel(this,
+ favoritesListModel, transactionListListModelsByTicker);
+ transactionTree = new SideBySideTreeView(treeModel, null, 200, 200);
Columns.favoriteColumn.setFieldUpdater(new FieldUpdater<StockQuote, Boolean>() {
public void update(StockQuote object, Boolean value) {
@@ -309,32 +205,42 @@
t.getList().add(result);
}
});
- }
+ }
}
});
// Add components to the page.
- HorizontalPanel hPanel = new HorizontalPanel();
- hPanel.add(new HTML("<b>Available cash:</b>"));
- hPanel.add(cashLabel);
- RootPanel.get().add(hPanel);
+
+ Widget headerWidget = new HTML("<b>Stock Game</b>");
+
+ HorizontalPanel cashPanel = new HorizontalPanel();
+ cashPanel.add(new HTML("<b>Available cash:</b>"));
+ cashPanel.add(cashLabel);
+
+ HorizontalPanel netWorthPanel = new HorizontalPanel();
+ netWorthPanel.add(new HTML("<b>Net worth:</b>"));
+ netWorthPanel.add(netWorthLabel);
+
+ DockLayoutPanel footerPanel = new DockLayoutPanel(Unit.PCT);
+ footerPanel.addWest(cashPanel, 50.0);
+ footerPanel.add(netWorthPanel);
+
+ DockLayoutPanel layoutPanel = new DockLayoutPanel(Unit.EM);
+ layoutPanel.addNorth(headerWidget, 4.0);
+ layoutPanel.addSouth(footerPanel, 2.0);
+ layoutPanel.addNorth(transactionTree, 18.0);
+
+ DockLayoutPanel innerLayoutPanel = new DockLayoutPanel(Unit.PCT);
+ this.queryWidget = new StockQueryWidget(searchListModel, this);
+ innerLayoutPanel.addWest(queryWidget, 50.0);
+
+ DockLayoutPanel favoritesLayoutPanel = new DockLayoutPanel(Unit.EM);
+ favoritesLayoutPanel.addNorth(new Label("Portfolio / Favorites"), 2.0);
+ favoritesLayoutPanel.add(new ScrollPanel(favoritesTable));
+ innerLayoutPanel.add(favoritesLayoutPanel);
+ layoutPanel.add(innerLayoutPanel);
- RootPanel.get().add(resultsTable);
- RootPanel.get().add(new HTML("<hr>"));
- RootPanel.get().add(favoritesTable);
- RootPanel.get().add(new HTML("<hr>"));
- RootPanel.get().add(transactionTable);
- RootPanel.get().add(new HTML("<hr>"));
- RootPanel.get().add(transactionTree1);
- RootPanel.get().add(new HTML("<hr>"));
- RootPanel.get().add(transactionTree2);
-
- // Add a handler to send the name to the server
- queryField.addKeyUpHandler(new KeyUpHandler() {
- public void onKeyUp(KeyUpEvent event) {
- update();
- }
- });
+ RootLayoutPanel.get().add(layoutPanel);
update();
}
@@ -347,29 +253,75 @@
*/
public void setFavorite(String ticker, boolean favorite) {
if (favorite) {
- dataService.addFavorite(ticker, new AsyncCallback<Void>() {
+ dataService.addFavorite(ticker, favoritesListModel.getRanges()[0],
+ new AsyncCallback<StockResponse>() {
public void onFailure(Throwable caught) {
Window.alert("Error adding favorite");
}
- public void onSuccess(Void result) {
- // do nothing
+ public void onSuccess(StockResponse response) {
+ updateFavorites(response);
}
});
} else {
- dataService.removeFavorite(ticker, new AsyncCallback<Void>() {
+ dataService.removeFavorite(ticker, favoritesListModel.getRanges()[0],
+ new AsyncCallback<StockResponse>() {
public void onFailure(Throwable caught) {
Window.alert("Error removing favorite");
}
- public void onSuccess(Void result) {
- // do nothing
+ public void onSuccess(StockResponse response) {
+ updateFavorites(response);
}
});
}
}
/**
+ * Request data from the server using the last query string.
+ */
+ public void update() {
+ if (queryWidget == null) {
+ return;
+ }
+
+ updateTimer.cancel();
+
+ Range[] searchRanges = searchListModel.getRanges();
+ Range[] favoritesRanges = favoritesListModel.getRanges();
+ SectorListModel sectorListModel = treeModel.getSectorListModel();
+ Range[] sectorRanges = sectorListModel == null ? null : sectorListModel.getRanges();
+
+ if (searchRanges == null || searchRanges.length == 0
+ || favoritesRanges == null || favoritesRanges.length == 0) {
+ return;
+ }
+
+ String searchQuery = queryWidget.getSearchQuery();
+ StockRequest request = new StockRequest(searchQuery,
+ sectorListModel != null ? sectorListModel.getSector() : null,
+ searchRanges[0],
+ favoritesRanges[0],
+ sectorRanges != null && sectorRanges.length > 0 ? sectorRanges[0] : null);
+ dataService.getStockQuotes(request, new AsyncCallback<StockResponse>() {
+ public void onFailure(Throwable caught) {
+ String message = caught.getMessage();
+ if (message.contains("Not logged in")) {
+ // Force the user to login.
+ Window.Location.reload();
+ } else {
+ Window.alert("ERROR: " + caught.getMessage());
+ updateTimer.schedule(UPDATE_DELAY);
+ }
+ }
+
+ public void onSuccess(StockResponse result) {
+ processStockResponse(result);
+ }
+ });
+ }
+
+ /**
* Process the {@link StockResponse} from the server.
*
* @param response the stock response
@@ -382,52 +334,36 @@
searchResults.size(), searchResults);
// Update the favorites list.
- StockQuoteList favorites = response.getFavorites();
- favoritesListModel.updateDataSize(response.getNumFavorites(), true);
- favoritesListModel.updateViewData(favorites.getStartIndex(),
- favorites.size(), favorites);
+ updateFavorites(response);
+ updateSector(response);
// Update available cash.
int cash = response.getCash();
+ int netWorth = response.getNetWorth();
cashLabel.setText(getFormattedPrice(cash));
+ netWorthLabel.setText(getFormattedPrice(netWorth));
buySellPopup.setAvailableCash(cash);
// Restart the update timer.
updateTimer.schedule(UPDATE_DELAY);
}
- /**
- * Request data from the server using the last query string.
- */
- private void update() {
- updateTimer.cancel();
+ private void updateFavorites(StockResponse response) {
+ // Update the favorites list.
+ StockQuoteList favorites = response.getFavorites();
+ favoritesListModel.updateDataSize(response.getNumFavorites(), true);
+ favoritesListModel.updateViewData(favorites.getStartIndex(),
+ favorites.size(), favorites);
+ }
- Range[] searchRanges = searchListModel.getRanges();
- Range[] favoritesRanges = favoritesListModel.getRanges();
-
- if (searchRanges == null || searchRanges.length == 0
- || favoritesRanges == null || favoritesRanges.length == 0) {
- return;
+ private void updateSector(StockResponse response) {
+ // Update the sector list.
+ StockQuoteList sectorList = response.getSector();
+ if (sectorList != null) {
+ SectorListModel sectorListModel = treeModel.getSectorListModel();
+ sectorListModel.updateDataSize(response.getNumSector(), true);
+ sectorListModel.updateViewData(sectorList.getStartIndex(),
+ sectorList.size(), sectorList);
}
-
- String searchQuery = queryField.getText();
- StockRequest request = new StockRequest(searchQuery, searchRanges[0],
- favoritesRanges[0]);
- dataService.getStockQuotes(request, new AsyncCallback<StockResponse>() {
- public void onFailure(Throwable caught) {
- String message = caught.getMessage();
- if (message.contains("Not logged in")) {
- // Force the user to login.
- Window.Location.reload();
- } else {
- Window.alert("ERROR: " + caught.getMessage());
- updateTimer.schedule(UPDATE_DELAY);
- }
- }
-
- public void onSuccess(StockResponse result) {
- processStockResponse(result);
- }
- });
}
}
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockService.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockService.java
index 7589ca88..c9b3578 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockService.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockService.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.bikeshed.sample.stocks.client;
+import com.google.gwt.bikeshed.list.shared.Range;
import com.google.gwt.bikeshed.sample.stocks.shared.StockRequest;
import com.google.gwt.bikeshed.sample.stocks.shared.StockResponse;
import com.google.gwt.bikeshed.sample.stocks.shared.Transaction;
@@ -30,9 +31,9 @@
StockResponse getStockQuotes(StockRequest request)
throws IllegalArgumentException;
- void addFavorite(String ticker);
+ StockResponse addFavorite(String ticker, Range favoritesRange);
- void removeFavorite(String ticker);
+ StockResponse removeFavorite(String ticker, Range favoritesRange);
Transaction transact(Transaction transaction) throws IllegalArgumentException;
}
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockServiceAsync.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockServiceAsync.java
index 88a6b56..f57eeb5 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockServiceAsync.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockServiceAsync.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.bikeshed.sample.stocks.client;
+import com.google.gwt.bikeshed.list.shared.Range;
import com.google.gwt.bikeshed.sample.stocks.shared.StockRequest;
import com.google.gwt.bikeshed.sample.stocks.shared.StockResponse;
import com.google.gwt.bikeshed.sample.stocks.shared.Transaction;
@@ -27,9 +28,9 @@
void getStockQuotes(StockRequest request,
AsyncCallback<StockResponse> callback);
- void addFavorite(String ticker, AsyncCallback<Void> callback);
+ void addFavorite(String ticker, Range favoritesRange, AsyncCallback<StockResponse> callback);
- void removeFavorite(String ticker, AsyncCallback<Void> callback);
+ void removeFavorite(String ticker, Range favoritesRange, AsyncCallback<StockResponse> callback);
void transact(Transaction transaction, AsyncCallback<Transaction> callback);
}
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/TransactionTreeViewModel.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/TransactionTreeViewModel.java
index a44d1d4..7589158 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/TransactionTreeViewModel.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/TransactionTreeViewModel.java
@@ -16,13 +16,17 @@
package com.google.gwt.bikeshed.sample.stocks.client;
import com.google.gwt.bikeshed.cells.client.Cell;
+import com.google.gwt.bikeshed.cells.client.TextCell;
+import com.google.gwt.bikeshed.list.shared.AsyncListModel;
import com.google.gwt.bikeshed.list.shared.ListListModel;
import com.google.gwt.bikeshed.list.shared.ListModel;
import com.google.gwt.bikeshed.sample.stocks.shared.StockQuote;
import com.google.gwt.bikeshed.sample.stocks.shared.Transaction;
import com.google.gwt.bikeshed.tree.client.TreeNode;
import com.google.gwt.bikeshed.tree.client.TreeViewModel;
+import com.google.gwt.bikeshed.tree.client.TreeViewModel.DefaultNodeInfo;
+import java.util.List;
import java.util.Map;
/**
@@ -32,6 +36,24 @@
*/
class TransactionTreeViewModel implements TreeViewModel {
+ class SectorListModel extends AsyncListModel<StockQuote> {
+
+ String sector;
+
+ public SectorListModel(final Updater updater, String sector) {
+ super(new DataSource<StockQuote>() {
+ public void requestData(AsyncListModel<StockQuote> listModel) {
+ updater.update();
+ }
+ });
+ this.sector = sector;
+ }
+
+ public String getSector() {
+ return sector;
+ }
+ }
+
static class TransactionCell extends Cell<Transaction> {
@Override
public void render(Transaction value, StringBuilder sb) {
@@ -49,18 +71,32 @@
private static final Cell<Transaction> TRANSACTION_CELL =
new TransactionCell();
+ private SectorListModel sectorListModel;
private ListModel<StockQuote> stockQuoteListModel;
+ private ListListModel<String> topLevelListListModel =
+ new ListListModel<String>();
private Map<String, ListListModel<Transaction>> transactionListListModelsByTicker;
- public TransactionTreeViewModel(ListModel<StockQuote> stockQuoteListModel,
+ private Updater updater;
+
+ public TransactionTreeViewModel(Updater updater, ListModel<StockQuote> stockQuoteListModel,
Map<String, ListListModel<Transaction>> transactionListListModelsByTicker) {
+ this.updater = updater;
this.stockQuoteListModel = stockQuoteListModel;
+ List<String> topLevelList = topLevelListListModel.getList();
+ topLevelList.add("Favorites");
+ topLevelList.add("Internet");
+ topLevelList.add("Energy");
+ topLevelList.add("Networking");
this.transactionListListModelsByTicker = transactionListListModelsByTicker;
}
@SuppressWarnings("unused")
public <T> NodeInfo<?> getNodeInfo(T value, TreeNode<T> treeNode) {
if (value == null) {
+ return new TreeViewModel.DefaultNodeInfo<String>(topLevelListListModel,
+ new TextCell());
+ } else if ("Favorites".equals(value)) {
return new TreeViewModel.DefaultNodeInfo<StockQuote>(stockQuoteListModel,
STOCK_QUOTE_CELL) {
@Override
@@ -68,6 +104,14 @@
return value.getTicker();
}
};
+ } else if (value instanceof String) {
+ sectorListModel = new SectorListModel(updater, (String) value);
+ return new TreeViewModel.DefaultNodeInfo<StockQuote>(sectorListModel, STOCK_QUOTE_CELL) {
+ @Override
+ public Object getKey(StockQuote value) {
+ return value.getTicker();
+ }
+ };
} else if (value instanceof StockQuote) {
String ticker = ((StockQuote) value).getTicker();
ListListModel<Transaction> listModel = transactionListListModelsByTicker.get(ticker);
@@ -82,6 +126,10 @@
throw new IllegalArgumentException(value.toString());
}
+ public SectorListModel getSectorListModel() {
+ return sectorListModel;
+ }
+
public boolean isLeaf(Object value) {
return value instanceof Transaction;
}
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/Updater.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/Updater.java
new file mode 100644
index 0000000..02562bc
--- /dev/null
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/Updater.java
@@ -0,0 +1,30 @@
+/*
+ * 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.bikeshed.sample.stocks.client;
+
+/**
+ * Bridge between StockSample and StockQueryWidget.
+ */
+public interface Updater {
+
+ /**
+ * Update the widget.
+ *
+ * TODO - refactor this
+ */
+ void update();
+
+}
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/NasdaqStocks.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/NasdaqStocks.java
index f1c9022..da176aa 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/NasdaqStocks.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/NasdaqStocks.java
@@ -182,11 +182,9 @@
"ANGN", "Angeion Corporation",
"ANGO", "AngioDynamics, Inc.",
"ANIK", "Anika Therapeutics Inc.",
- "ANLY", "Analysts International Corporation",
"ANNB", "Annapolis Bancorp Inc.",
"ANPI", "Angiotech Pharmaceuticals, Inc.",
"ANSS", "ANSYS, Inc.",
- "ANSV", "Anesiva, Inc.",
"ANSW", "Answers Corporation",
"ANTP", "PHAZAR CORP", "AONE", "A123 Systems, Inc.",
"APAB", "Appalachian Bancshares, Inc. (GA)",
@@ -252,7 +250,6 @@
"ASTE", "Astec Industries, Inc.",
"ASTI", "Ascent Solar Technologies, Inc.",
"ASTIZ", "Ascent Solar Technologies, Inc.",
- "ASTM", "Aastrom Biosciences, Inc.",
"ASUR", "Forgent Networks Inc",
"ASYS", "Amtech Systems, Inc.",
"ATAC", "ATC Technology Corporation",
@@ -441,7 +438,6 @@
"CALI", "China Auto Logistics Inc.",
"CALM", "Cal-Maine Foods, Inc.",
"CALP", "Caliper Life Sciences Inc",
- "CAMD", "California Micro Devices Corporation",
"CAMP", "CalAmp Corp.",
"CAMT", "Camtek Ltd.",
"CAPS", "Orthologic Corp.",
@@ -715,7 +711,6 @@
"CWBS", "Commonwealth Bankshares, Inc.",
"CWCO", "Consolidated Water Co. Ltd.",
"CWEI", "Clayton Williams Energy, Inc.",
- "CWLZ", "Cowlitz Bancorporation",
"CWST", "Casella Waste Systems, Inc.",
"CWTR", "Coldwater Creek, Inc.",
"CYAN", "Cyanotech Corporation",
@@ -1055,7 +1050,6 @@
"FXCB", "Fox Chase Bancorp, Inc.",
"FXEN", "FX Energy, Inc.",
"GABC", "German American Bancorp, Inc.",
- "GAI", "Global-Tech Advanced Innovations Inc.",
"GAIA", "Gaiam, Inc.",
"GAIN", "Gladstone Investment Corporation",
"GAME", "Shanda Games Limited",
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/StockServiceImpl.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/StockServiceImpl.java
index 8ee31cc..f1f0598 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/StockServiceImpl.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/StockServiceImpl.java
@@ -67,6 +67,9 @@
private static final int MAX_RESULTS_TO_RETURN = 10000;
+ private static final HashMap<String,String> sectorQueries =
+ new HashMap<String,String>();
+
static {
int num = NasdaqStocks.SYMBOLS.length;
for (int i = 0; i < num - 1; i += 2) {
@@ -78,13 +81,31 @@
}
}
+ static {
+ sectorQueries.put("INTERNET", "GOOG|YHOO|MSFT");
+ sectorQueries.put("ENERGY", "GASS|GLRP");
+ sectorQueries.put("NETWORKING", "GLBC|CSCO");
+ }
+
/**
* A mapping of usernames to {@link PlayerStatus}.
*/
private Map<String, PlayerStatus> players = new HashMap<String, PlayerStatus>();
-
- public void addFavorite(String ticker) {
- ensurePlayer().addFavorite(ticker);
+
+ public StockResponse addFavorite(String ticker, Range favoritesRange) {
+ PlayerStatus player = ensurePlayer();
+ player.addFavorite(ticker);
+ Result favorites = query(player.getFavoritesQuery(), favoritesRange);
+ return new StockResponse(null, favorites.quotes, null,
+ 0, favorites.numRows, 0, player.getCash());
+ }
+
+ public Result getSectorQuotes(String sector, Range sectorRange) {
+ String sectorQuery = sectorQueries.get(sector.toUpperCase());
+ if (sectorQuery == null) {
+ return null;
+ }
+ return query(sectorQuery, sectorRange);
}
public StockResponse getStockQuotes(StockRequest request)
@@ -96,17 +117,28 @@
}
Range searchRange = request.getSearchRange();
Range favoritesRange = request.getFavoritesRange();
-
+ Range sectorRange = request.getSectorRange();
+
PlayerStatus player = ensurePlayer();
Result searchResults = query(query, searchRange);
Result favorites = query(player.getFavoritesQuery(), favoritesRange);
+ Result sector = sectorRange != null ? getSectorQuotes(request.getSector(), sectorRange) : null;
- return new StockResponse(searchResults.quotes, favorites.quotes,
- searchResults.numRows, favorites.numRows, player.getCash());
+ return new StockResponse(searchResults.quotes,
+ favorites.quotes,
+ sector != null ? sector.quotes : null,
+ searchResults.numRows,
+ favorites.numRows,
+ sector != null ? sector.numRows : 0,
+ player.getCash());
}
- public void removeFavorite(String ticker) {
- ensurePlayer().removeFavorite(ticker);
+ public StockResponse removeFavorite(String ticker, Range favoritesRange) {
+ PlayerStatus player = ensurePlayer();
+ player.removeFavorite(ticker);
+ Result favorites = query(player.getFavoritesQuery(), favoritesRange);
+ return new StockResponse(null, favorites.quotes, null,
+ 0, favorites.numRows, 0, player.getCash());
}
public Transaction transact(Transaction transaction)
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockQuoteList.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockQuoteList.java
index 7fa900a..85974ca 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockQuoteList.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockQuoteList.java
@@ -38,5 +38,16 @@
public int getStartIndex() {
return start;
}
+
+ /**
+ * Returns the sum of stock prices times shares owned, in pennies.
+ */
+ public int getValue() {
+ int value = 0;
+ for (StockQuote q : this) {
+ value += q.getPrice() * q.getSharesOwned();
+ }
+ return value;
+ }
}
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockRequest.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockRequest.java
index d7724b3..c612728 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockRequest.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockRequest.java
@@ -24,15 +24,18 @@
*/
public class StockRequest implements Serializable {
+ Range favoritesRange;
String searchQuery;
Range searchRange;
- Range favoritesRange;
-
- public StockRequest(String searchQuery, Range searchRange,
- Range favoritesRange) {
+ String sector;
+ Range sectorRange;
+ public StockRequest(String searchQuery, String sector, Range searchRange,
+ Range favoritesRange, Range sectorRange) {
this.searchQuery = searchQuery;
+ this.sector = sector;
this.searchRange = searchRange;
this.favoritesRange = favoritesRange;
+ this.sectorRange = sectorRange;
}
/**
@@ -52,4 +55,12 @@
public Range getSearchRange() {
return searchRange;
}
+
+ public String getSector() {
+ return sector;
+ }
+
+ public Range getSectorRange() {
+ return sectorRange;
+ }
}
diff --git a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockResponse.java b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockResponse.java
index 1df16ab..428a7fc 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockResponse.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockResponse.java
@@ -22,15 +22,27 @@
*/
public class StockResponse implements Serializable {
- private StockQuoteList searchResults;
- private StockQuoteList favorites;
- private int numSearchResults;
- private int numFavorites;
-
/**
* The amount of available cash in pennies.
*/
private int cash;
+ private StockQuoteList favorites;
+ private int numFavorites;
+ private int numSearchResults;
+ private int numSector;
+ private StockQuoteList searchResults;
+ private StockQuoteList sector;
+
+ public StockResponse(StockQuoteList searchResults, StockQuoteList favorites,
+ StockQuoteList sector, int numSearchResults, int numFavorites, int numSector, int cash) {
+ this.searchResults = searchResults;
+ this.favorites = favorites;
+ this.sector = sector;
+ this.numSearchResults = numSearchResults;
+ this.numFavorites = numFavorites;
+ this.numSector = numSector;
+ this.cash = cash;
+ }
/**
* Used for RPC.
@@ -38,15 +50,6 @@
StockResponse() {
}
- public StockResponse(StockQuoteList searchResults, StockQuoteList favorites,
- int numSearchResults, int numFavorites, int cash) {
- this.searchResults = searchResults;
- this.favorites = favorites;
- this.numSearchResults = numSearchResults;
- this.numFavorites = numFavorites;
- this.cash = cash;
- }
-
public int getCash() {
return cash;
}
@@ -54,6 +57,13 @@
public StockQuoteList getFavorites() {
return favorites;
}
+
+ /**
+ * The sum of cash available and portfolio value.
+ */
+ public int getNetWorth() {
+ return cash + favorites.getValue();
+ }
public int getNumFavorites() {
return numFavorites;
@@ -63,7 +73,15 @@
return numSearchResults;
}
+ public int getNumSector() {
+ return numSector;
+ }
+
public StockQuoteList getSearchResults() {
return searchResults;
}
+
+ public StockQuoteList getSector() {
+ return sector;
+ }
}
diff --git a/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeNodeView.java b/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeNodeView.java
index 87211c6..38c9cbe 100644
--- a/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeNodeView.java
+++ b/bikeshed/src/com/google/gwt/bikeshed/tree/client/TreeNodeView.java
@@ -27,7 +27,7 @@
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.UIObject;
import java.util.ArrayList;
import java.util.HashMap;
@@ -39,7 +39,7 @@
*
* @param <T> the type that this {@link TreeNodeView} contains
*/
-public abstract class TreeNodeView<T> extends Composite implements TreeNode<T> {
+public abstract class TreeNodeView<T> extends UIObject implements TreeNode<T> {
/**
* The element used in place of an image when a node has no children.
diff --git a/bikeshed/war/Stocks.html b/bikeshed/war/Stocks.html
index 5ad342e..0b3e56c 100644
--- a/bikeshed/war/Stocks.html
+++ b/bikeshed/war/Stocks.html
@@ -15,18 +15,5 @@
in order for this application to display correctly.
</div>
</noscript>
-
- <h1>Data Backed Widgets Sample</h1>
- <table align="center">
- <tr>
- <td colspan="2" style="font-weight:bold;">Enter a search query:</td>
- </tr>
- <tr>
- <td id="queryFieldContainer"></td>
- </tr>
- <tr>
- <td colspan="2" style="color:red;" id="errorLabelContainer"></td>
- </tr>
- </table>
</body>
</html>