Revision: 7718
Author: gwt.mirror...@gmail.com
Date: Fri Mar 12 11:14:43 2010
Log: Adding list of top players to the game.

http://code.google.com/p/google-web-toolkit/source/detail?r=7718

Added:
/trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/PlayerScoresWidget.java /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/PlayerScoresWidget.ui.xml /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/PlayerInfo.java
Modified:
 /trunk/bikeshed/.classpath
 /trunk/bikeshed/.project
/trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.ui.xml
 /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/common.css
/trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/PlayerStatus.java /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/StockServiceImpl.java /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockResponse.java
 /trunk/bikeshed/war/Stocks.css
 /trunk/bikeshed/war/WEB-INF/web.xml

=======================================
--- /dev/null
+++ /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/PlayerScoresWidget.java Fri Mar 12 11:14:43 2010
@@ -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.bikeshed.sample.stocks.client;
+
+import com.google.gwt.bikeshed.cells.client.Cell;
+import com.google.gwt.bikeshed.list.client.SimpleCellList;
+import com.google.gwt.bikeshed.list.shared.ListModel;
+import com.google.gwt.bikeshed.sample.stocks.shared.PlayerInfo;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiFactory;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Widget to display player scores.
+ */
+public class PlayerScoresWidget extends Composite {
+
+  interface Binder extends UiBinder<Widget, PlayerScoresWidget> {
+  }
+
+  private static final Binder binder = GWT.create(Binder.class);
+
+  /**
+   * A {...@link Cell} that displays the status of a single player.
+   */
+  private static final class PlayerInfoCell extends Cell<PlayerInfo> {
+    @Override
+    public void render(PlayerInfo value, StringBuilder sb) {
+      sb.append("<div class='playerScoreBox'>");
+      sb.append("<b>Name: </b>");
+      sb.append(value.getDisplayName());
+      sb.append("<br><b>Net Worth: </b>");
+      sb.append(StockSample.getFormattedPrice(value.getNetWorth()));
+      sb.append("<br><b>Cash: </b>");
+      sb.append(StockSample.getFormattedPrice(value.getCash()));
+      sb.append("</div>");
+    }
+  }
+
+  @UiField
+  SimpleCellList<PlayerInfo> listView;
+
+  private final ListModel<PlayerInfo> model;
+
+  public PlayerScoresWidget(ListModel<PlayerInfo> model) {
+    this.model = model;
+    initWidget(binder.createAndBindUi(this));
+  }
+
+  @UiFactory
+  SimpleCellList<PlayerInfo> createListView() {
+    return new SimpleCellList<PlayerInfo>(model, new PlayerInfoCell());
+  }
+}
=======================================
--- /dev/null
+++ /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/PlayerScoresWidget.ui.xml Fri Mar 12 11:14:43 2010
@@ -0,0 +1,21 @@
+<ui:UiBinder
+  xmlns:ui='urn:ui:com.google.gwt.uibinder'
+  xmlns:g='urn:import:com.google.gwt.user.client.ui'
+  xmlns:l='urn:import:com.google.gwt.bikeshed.list.client'
+  xmlns:t='urn:import:com.google.gwt.bikeshed.tree.client'
+  xmlns:s='urn:import:com.google.gwt.bikeshed.sample.stocks.client'>
+
+  <ui:style field='common' src='common.css'/>
+
+  <g:DockLayoutPanel unit='EM'>
+    <g:north size='2'>
+      <g:Label styleName='{common.header}'>Everyone Else</g:Label>
+    </g:north>
+
+    <g:center>
+      <g:ScrollPanel styleName="{common.padded}">
+        <l:SimpleCellList ui:field='listView'/>
+      </g:ScrollPanel>
+    </g:center>
+  </g:DockLayoutPanel>
+</ui:UiBinder>
=======================================
--- /dev/null
+++ /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/PlayerInfo.java Fri Mar 12 11:14:43 2010
@@ -0,0 +1,129 @@
+/*
+ * 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.shared;
+
+import java.io.Serializable;
+
+/**
+ * Information about a single player.
+ */
+public class PlayerInfo implements Serializable {
+
+  /**
+   * The initial amount of cash that the player starts with, in cents.
+   */
+  private static final int INITIAL_CASH = 10000 * 100;
+
+  /**
+   * The net worth of the player in cents.
+   */
+  private int cash = INITIAL_CASH;
+
+  /**
+   * The players name.
+   */
+  private String name;
+
+  /**
+   * The net worth of the player in cents.
+   */
+  private int stockValue;
+
+  public PlayerInfo(String name) {
+    this.name = name;
+  }
+
+  /**
+   * Visible for RPC.
+   */
+  PlayerInfo() {
+  }
+
+  public PlayerInfo copy() {
+    PlayerInfo copy = new PlayerInfo(name);
+    copy.setCash(cash);
+    copy.setStockValue(stockValue);
+    return copy;
+  }
+
+  /**
+   * Get the player's current cash amount.
+   *
+   * @return the cash amount
+   */
+  public int getCash() {
+    return cash;
+  }
+
+  /**
+   * Get the player's display name, which excludes domain information.
+   *
+   * @return the display name of the player.
+   */
+  public String getDisplayName() {
+    String displayName = name;
+    int domain = displayName.indexOf('@');
+    if (domain > 0) {
+      displayName = displayName.substring(0, domain);
+    }
+    return displayName;
+  }
+
+  /**
+   * Get the player's name.
+   *
+   * @return the name of the player.
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * Get the players net worth, including cash and stock value.
+   *
+   * @return the net worth in cents
+   */
+  public int getNetWorth() {
+    return cash + stockValue;
+  }
+
+  /**
+   * Get the value of this player's stock.
+   *
+   * @return the value of the stock in cents
+   */
+  public int getStockValue() {
+    return stockValue;
+  }
+
+  /**
+   * Set the amount of cash that the user has.
+   *
+   * @param cash the user's cash in cents
+   */
+  protected void setCash(int cash) {
+    this.cash = cash;
+  }
+
+  /**
+   * Set the value of this player's stock.
+   *
+   * @param value the stock value in cents
+   */
+  protected void setStockValue(int value) {
+    this.stockValue = value;
+  }
+}
=======================================
--- /trunk/bikeshed/.classpath  Thu Mar 11 09:45:33 2010
+++ /trunk/bikeshed/.classpath  Fri Mar 12 11:14:43 2010
@@ -6,6 +6,7 @@
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/> <classpathentry kind="var" path="GWT_TOOLS/redist/json/r2_20080312/json.jar" sourcepath="/GWT_TOOLS/redist/json/r2_20080312/json-src.jar"/>
        <classpathentry kind="lib" path="war/WEB-INF/lib/gwt-servlet.jar"/>
- <classpathentry kind="con" path="com.google.gwt.eclipse.core.GWT_CONTAINER/Local"/> + <classpathentry kind="con" path="com.google.gwt.eclipse.core.GWT_CONTAINER/trunk"/> + <classpathentry kind="con" path="com.google.appengine.eclipse.core.GAE_CONTAINER"/>
        <classpathentry kind="output" path="war/WEB-INF/classes"/>
 </classpath>
=======================================
--- /trunk/bikeshed/.project    Thu Mar  4 12:59:01 2010
+++ /trunk/bikeshed/.project    Fri Mar 12 11:14:43 2010
@@ -28,6 +28,16 @@
                <buildCommand>
                        
<name>com.atlassw.tools.eclipse.checkstyle.CheckstyleBuilder</name>
                        <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       
<name>com.google.appengine.eclipse.core.enhancerbuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       
<name>com.google.appengine.eclipse.core.projectValidator</name>
+                       <arguments>
                        </arguments>
                </buildCommand>
        </buildSpec>
@@ -37,5 +47,6 @@
                <nature>com.google.gdt.eclipse.core.webAppNature</nature>
                
<nature>com.atlassw.tools.eclipse.checkstyle.CheckstyleNature</nature>
                
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+               <nature>com.google.appengine.eclipse.core.gaeNature</nature>
        </natures>
 </projectDescription>
=======================================
--- /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java Thu Mar 11 11:11:10 2010 +++ /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java Fri Mar 12 07:16:19 2010
@@ -1,12 +1,12 @@
 /*
  * Copyright 2010 Google Inc.
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
  * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -21,6 +21,7 @@
 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.PlayerInfo;
 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;
@@ -69,6 +70,7 @@

   @UiField FavoritesWidget favoritesWidget;
   @UiField Label netWorthLabel;
+  @UiField PlayerScoresWidget playerScoresWidget;
   @UiField StockQueryWidget queryWidget;
   @UiField SideBySideTreeView transactionTree;

@@ -79,6 +81,7 @@
private final StockServiceAsync dataService = GWT.create(StockService.class);

   private AsyncListModel<StockQuote> favoritesListModel;
+  private AsyncListModel<PlayerInfo> playerScoresListModel;
   private AsyncListModel<StockQuote> searchListModel;
private Map<String, ListListModel<Transaction>> transactionListListModelsByTicker =
     new HashMap<String, ListListModel<Transaction>>();
@@ -122,8 +125,15 @@
           }
         });

-    treeModel = new TransactionTreeViewModel(this,
-        favoritesListModel, transactionListListModelsByTicker);
+    playerScoresListModel = new AsyncListModel<PlayerInfo>(
+        new DataSource<PlayerInfo>() {
+          public void requestData(AsyncListModel<PlayerInfo> listModel) {
+            // Player cannot request data from this view.
+          }
+        });
+
+    treeModel = new TransactionTreeViewModel(this, favoritesListModel,
+        transactionListListModelsByTicker);

     transactionListModel = new ListListModel<Transaction>();
     transactions = transactionListModel.getList();
@@ -164,7 +174,7 @@

   /**
    * Process the {...@link StockResponse} from the server.
-   *
+   *
    * @param response the stock response
    */
   public void processStockResponse(StockResponse response) {
@@ -178,6 +188,12 @@
     updateFavorites(response);
     updateSector(response);

+    // Update the player scores.
+    List<PlayerInfo> playerScores = response.getPlayers();
+    int numPlayers = playerScores.size();
+    playerScoresListModel.updateDataSize(numPlayers, true);
+    playerScoresListModel.updateViewData(0, numPlayers, playerScores);
+
     // Update available cash.
     int cash = response.getCash();
     int netWorth = response.getNetWorth();
@@ -196,7 +212,7 @@

   /**
    * Set or unset a ticker symbol as a 'favorite'.
-   *
+   *
    * @param ticker the ticker symbol
    * @param favorite if true, make the stock a favorite
    */
@@ -204,28 +220,28 @@
     if (favorite) {
       dataService.addFavorite(ticker, favoritesListModel.getRanges()[0],
           new AsyncCallback<StockResponse>() {
-        public void onFailure(Throwable caught) {
-          Window.alert("Error adding favorite");
-        }
-
-        public void onSuccess(StockResponse response) {
-          updateFavorites(response);
-        }
-      });
+            public void onFailure(Throwable caught) {
+              handleRpcError(caught, "Error adding favorite");
+            }
+
+            public void onSuccess(StockResponse response) {
+              updateFavorites(response);
+            }
+          });
     } else {
       dataService.removeFavorite(ticker, favoritesListModel.getRanges()[0],
           new AsyncCallback<StockResponse>() {
-        public void onFailure(Throwable caught) {
-          Window.alert("Error removing favorite");
-        }
-
-        public void onSuccess(StockResponse response) {
-          updateFavorites(response);
-        }
-      });
+            public void onFailure(Throwable caught) {
+              handleRpcError(caught, "Error removing favorite");
+            }
+
+            public void onSuccess(StockResponse response) {
+              updateFavorites(response);
+            }
+          });
     }
   }
-
+
   public void transact(Transaction t) {
     dataService.transact(t, new AsyncCallback<Transaction>() {
       public void onFailure(Throwable caught) {
@@ -238,19 +254,17 @@
       }

       /**
-       * Update transactions (list of all transactions),
-       * transactionTickers (set of all tickers involved in
-       * transactions), and transactionsByTicker (map from
-       * ticker to lists of transactions for that ticker).
+ * Update transactions (list of all transactions), transactionTickers (set + * of all tickers involved in transactions), and transactionsByTicker (map
+       * from ticker to lists of transactions for that ticker).
        */
       private void recordTransaction(Transaction result) {
         transactions.add(0, result);
         String ticker = result.getTicker();
-
+
         // Update the next level of the transaction tree
         // for the given ticker
-        ListListModel<Transaction> t =
-          transactionListListModelsByTicker.get(ticker);
+ ListListModel<Transaction> t = transactionListListModelsByTicker.get(ticker);
         if (t == null) {
           t = new ListListModel<Transaction>();
           transactionListListModelsByTicker.put(ticker, t);
@@ -272,10 +286,12 @@

     Range[] searchRanges = searchListModel.getRanges();
     Range[] favoritesRanges = favoritesListModel.getRanges();
-
+
     String sectorName = getSectorName();
- SectorListModel sectorListModel = sectorName != null ? treeModel.getSectorListModel(sectorName) : null; - Range[] sectorRanges = sectorListModel == null ? null : sectorListModel.getRanges();
+    SectorListModel sectorListModel = sectorName != null
+        ? treeModel.getSectorListModel(sectorName) : null;
+    Range[] sectorRanges = sectorListModel == null ? null
+        : sectorListModel.getRanges();

     if (searchRanges == null || searchRanges.length == 0
         || favoritesRanges == null || favoritesRanges.length == 0) {
@@ -283,20 +299,14 @@
     }

     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);
+        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());
+        if (handleRpcError(caught, null)) {
           updateTimer.schedule(UPDATE_DELAY);
         }
       }
@@ -332,6 +342,11 @@
   FavoritesWidget createFavoritesWidget() {
     return new FavoritesWidget(favoritesListModel);
   }
+
+  @UiFactory
+  PlayerScoresWidget createPlayerScoresWidget() {
+    return new PlayerScoresWidget(playerScoresListModel);
+  }

   @UiFactory
   StockQueryWidget createQueryWidget() {
@@ -352,7 +367,30 @@
         return (String) childNode.getValue();
       }
     }
-
+
     return null;
   }
-}
+
+  /**
+   * Display a message to the user when an RPC call fails.
+   *
+   * @param caught the exception
+   * @param displayMessage the message to display to the user, or null to
+   *          display a default message
+   * @return true if recoverable, false if not
+   */
+  private boolean handleRpcError(Throwable caught, String displayMessage) {
+    String message = caught.getMessage();
+    if (message.contains("Not logged in")) {
+      // Force the user to login.
+      Window.Location.reload();
+      return false;
+    }
+
+    if (displayMessage == null) {
+      displayMessage = "ERROR: " + caught.getMessage();
+    }
+    Window.alert(displayMessage);
+    return true;
+  }
+}
=======================================
--- /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.ui.xml Thu Mar 11 08:39:56 2010 +++ /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.ui.xml Fri Mar 12 07:16:19 2010
@@ -25,16 +25,7 @@
         </g:north>

         <g:center>
-          <g:ScrollPanel styleName='{common.bg}'>
-            <g:HTMLPanel>
-              <div class='{common.header}'>Everyone Else</div>
-              <table>
-                <tr><td>Dan Rice</td><td>$10000</td></tr>
-                <tr><td>Joel Webber</td><td>$10000</td></tr>
-                <tr><td>John Labanca</td><td>$10000</td></tr>
-              </table>
-            </g:HTMLPanel>
-          </g:ScrollPanel>
+ <s:PlayerScoresWidget styleName='{common.bg}' ui:field='playerScoresWidget'/>
         </g:center>
       </g:DockLayoutPanel>
     </g:west>
=======================================
--- /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/common.css Thu Mar 11 10:09:28 2010 +++ /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/common.css Fri Mar 12 07:16:19 2010
@@ -45,3 +45,7 @@
 .table tfoot th {
   border-width: 0px;
 }
+
+.padded {
+  padding: 5px;
+}
=======================================
--- /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/PlayerStatus.java Thu Mar 11 03:44:25 2010 +++ /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/PlayerStatus.java Fri Mar 12 07:16:19 2010
@@ -15,6 +15,8 @@
  */
 package com.google.gwt.bikeshed.sample.stocks.server;

+import com.google.gwt.bikeshed.sample.stocks.shared.PlayerInfo;
+
 import java.util.HashMap;
 import java.util.TreeSet;
 import java.util.regex.Pattern;
@@ -22,28 +24,18 @@
 /**
  * Game state for a single player.
  */
-public class PlayerStatus {
-
-  /**
-   * The initial amount of cash that the player starts with, in cents.
-   */
-  private static final int INITIAL_CASH = 10000 * 100;
+public class PlayerStatus extends PlayerInfo {

   /**
    * An impossible stock ticker.
    */
   private static final String IMPOSSIBLE_TICKER_SYMBOL = "XXXXXXXXXX";

-  /**
-   * The amount of cash that the player has.
-   */
-  private int cash = INITIAL_CASH;
-
   /**
    * This players favorite stocks.
    */
   private TreeSet<String> favorites = new TreeSet<String>();
-
+
   /**
    * A precompiled version of the favorites query.
    */
@@ -58,13 +50,14 @@
    * The number of shares owned for each symbol.
    */
private HashMap<String, Integer> sharesOwnedBySymbol = new HashMap<String, Integer>();
-
+
   /**
    * The total amount paid for each symbol.
    */
private HashMap<String, Double> averagePriceBySymbol = new HashMap<String, Double>();

-  public PlayerStatus() {
+  public PlayerStatus(String name) {
+    super(name);
     generateFavoritesQuery();
   }

@@ -89,6 +82,7 @@
   public void buy(String ticker, int quantity, int price)
       throws IllegalArgumentException {
     // Verify that the player can afford the stock.
+    int cash = getCash();
     int totalPrice = price * quantity;
     if (cash < totalPrice) {
throw new IllegalArgumentException("You cannot afford that much stock");
@@ -98,16 +92,16 @@
     int current = getSharesOwned(ticker);
     double averagePrice = getAveragePrice(ticker);
     double totalPaid = averagePrice * current + totalPrice;
-
+
     // Update case and shares owned
     current += quantity;
-    cash -= totalPrice;
+    setCash(cash - totalPrice);
     sharesOwnedBySymbol.put(ticker, current);
-
+
     // Update average price
     averagePrice = totalPaid / current;
     averagePriceBySymbol.put(ticker, averagePrice);
-
+
     // Add this stock to the favorites list.
     addFavorite(ticker);
   }
@@ -115,7 +109,7 @@
   /**
* Returns the total cost of the currently owned shared, using an average cost
    * basis method.
-   *
+   *
    * @param ticker the stock ticker
    */
   public int getAverageCostBasis(String ticker) {
@@ -126,15 +120,6 @@
     Double current = averagePriceBySymbol.get(ticker);
     return current == null ? 0.0 : current;
   }
-
-  /**
-   * Get the player's current cash amount.
-   *
-   * @return the cash amount
-   */
-  public int getCash() {
-    return cash;
-  }

   /**
    * Get this players favorite pattern.
@@ -164,7 +149,7 @@
     Integer current = sharesOwnedBySymbol.get(ticker);
     return current == null ? 0 : current;
   }
-
+
   /**
    * Check if the stock ticker is in the favorites list.
    *
@@ -204,16 +189,22 @@

     // Perform the transaction.
     int totalPrice = price * quantity;
-    cash += totalPrice;
+    setCash(getCash() + totalPrice);
+
     current -= quantity;
     sharesOwnedBySymbol.put(ticker, current);
-
+
     if (current == 0) {
       sharesOwnedBySymbol.remove(ticker);
       averagePriceBySymbol.remove(ticker);
       removeFavorite(ticker);
     }
   }
+
+  @Override
+  public void setStockValue(int value) {
+    super.setStockValue(value);
+  }

   /**
    * Regenerate the favorites query.
=======================================
--- /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/StockServiceImpl.java Fri Mar 12 06:22:00 2010 +++ /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/server/StockServiceImpl.java Fri Mar 12 07:16:19 2010
@@ -15,9 +15,13 @@
  */
 package com.google.gwt.bikeshed.sample.stocks.server;

+import com.google.appengine.api.users.User;
+import com.google.appengine.api.users.UserService;
+import com.google.appengine.api.users.UserServiceFactory;
 import com.google.gwt.bikeshed.list.shared.Range;
 import com.google.gwt.bikeshed.list.shared.AbstractListModel.DefaultRange;
 import com.google.gwt.bikeshed.sample.stocks.client.StockService;
+import com.google.gwt.bikeshed.sample.stocks.shared.PlayerInfo;
 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;
@@ -25,7 +29,11 @@
 import com.google.gwt.bikeshed.sample.stocks.shared.Transaction;
 import com.google.gwt.user.server.rpc.RemoteServiceServlet;

+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
@@ -46,7 +54,7 @@
     String change;
     long createdTime;
     int price;
-
+
     public Quote(int price, String change) {
       this.price = price;
       this.change = change;
@@ -65,7 +73,7 @@
       return price;
     }
   }
-
+
   /**
* The result of a query to the remote service that provides stock quotes.
    */
@@ -127,7 +135,7 @@
         "ZMH");

     // Precompile each regex
-    for (Map.Entry<String,String> entry : sectorQueries.entrySet()) {
+    for (Map.Entry<String, String> entry : sectorQueries.entrySet()) {
       sectorPatterns.put(entry.getKey(), compile(entry.getValue()));
     }
   }
@@ -150,8 +158,7 @@
     PlayerStatus player = ensurePlayer();
     player.addFavorite(ticker);
     Result favorites = queryFavorites(favoritesRange);
-    return new StockResponse(null, favorites.quotes, null, null,
-        0, favorites.numRows, 0, player.getCash());
+    return createStockResponse(player, null, favorites, null, null);
   }

   public Result getSectorQuotes(String sector, Range sectorRange) {
@@ -182,22 +189,15 @@
     Result sector = sectorRange != null ?
         getSectorQuotes(sectorName, sectorRange) : null;

-    return new StockResponse(searchResults.quotes,
-        favorites.quotes,
-        sector != null ? sectorName : null,
-        sector != null ? sector.quotes : null,
-        searchResults.numRows,
-        favorites.numRows,
-        sector != null ? sector.numRows : 0,
-        player.getCash());
-  }
-
+ return createStockResponse(player, searchResults, favorites, sectorName,
+        sector);
+  }
+
public StockResponse removeFavorite(String ticker, Range favoritesRange) {
     PlayerStatus player = ensurePlayer();
     player.removeFavorite(ticker);
     Result favorites = queryFavorites(favoritesRange);
-    return new StockResponse(null, favorites.quotes, null, null,
-        0, favorites.numRows, 0, player.getCash());
+    return createStockResponse(player, null, favorites, null, null);
   }

   public Transaction transact(Transaction transaction)
@@ -225,18 +225,65 @@

     return new Transaction(transaction.isBuy(), ticker, quantity, price);
   }
+
+  /**
+   * Create a stock response, updating the current user's net worth.
+   *
+   * @param player the player info
+   * @param searchResults the search results
+   * @param favorites the users favorites
+   * @param sectorName the name of the sector
+   * @param sectorResults the sector results
+   * @return a {...@link StockResponse}
+   */
+  private StockResponse createStockResponse(PlayerStatus player,
+      Result searchResults, Result favorites, String sectorName,
+      Result sectorResults) {
+    // Default to no search results.
+    if (searchResults == null) {
+      searchResults = new Result(null, 0);
+    }
+
+    // Default to no sector results.
+    if (sectorResults == null) {
+      sectorResults = new Result(null, 0);
+    }
+
+    // Store the new stock value.
+    player.setStockValue(favorites.quotes.getValue());
+
+    // Create a stock response.
+    List<PlayerInfo> playerScores = new ArrayList<PlayerInfo>();
+    for (PlayerStatus curPlayer : players.values()) {
+      playerScores.add(curPlayer.copy());
+    }
+    Collections.sort(playerScores, new Comparator<PlayerInfo>() {
+      public int compare(PlayerInfo o1, PlayerInfo o2) {
+        // Reverse sort so top player is first.
+        return o2.getNetWorth() - o1.getNetWorth();
+      }
+    });
+    StockResponse response = new StockResponse(player.copy(),
+ searchResults.quotes, favorites.quotes, sectorName != null ? sectorName
+            : null, sectorResults.quotes, searchResults.numRows,
+        favorites.numRows, sectorResults.numRows, playerScores);
+
+    return response;
+  }

   /**
* Ensure that a {...@link PlayerStatus} for the current player exists and return
    * it.
-   *
+   *
    * @return the {...@link PlayerStatus} for the current player
    */
   private PlayerStatus ensurePlayer() {
-    String userId = "I Am the User";
+    UserService userService = UserServiceFactory.getUserService();
+    User user = userService.getCurrentUser();
+    String userId = user.getUserId();
     PlayerStatus player = players.get(userId);
     if (player == null) {
-      player = new PlayerStatus();
+      player = new PlayerStatus(user.getNickname());
       players.put(userId, player);
     }
     return player;
@@ -245,11 +292,11 @@
   private Result getQuotes(SortedSet<String> symbols, Range range) {
     int start = range.getStart();
     int end = Math.min(start + range.getLength(), symbols.size());
-
+
     if (end <= start) {
       return new Result(new StockQuoteList(0), 0);
     }
-
+
     // Get the symbols that are in range.
     SortedSet<String> symbolsInRange = new TreeSet<String>();
     int idx = 0;
@@ -259,10 +306,10 @@
       }
       idx++;
     }
-
+
     // If we already have a price that is less than 5 seconds old,
     // don't re-request the data from the server
-
+
     SortedSet<String> symbolsToQuery = new TreeSet<String>();
     long now = System.currentTimeMillis();
     for (String symbol : symbolsInRange) {
@@ -271,19 +318,20 @@
         symbolsToQuery.add(symbol);
         // System.out.println("retrieving new value of " + symbol);
       } else {
- // System.out.println("Using cached value of " + symbol + " (" + (now - quote.getCreatedTime()) + "ms old)"); + // System.out.println("Using cached value of " + symbol + " (" + (now -
+        // quote.getCreatedTime()) + "ms old)");
       }
     }
-
+
     if (symbolsToQuery.size() > 0) {
       GoogleFinance.queryServer(symbolsToQuery, QUOTES);
     }
-
+
     // Create and return a StockQuoteList containing the quotes
     StockQuoteList toRet = new StockQuoteList(start);
     for (String symbol : symbolsInRange) {
       Quote quote = QUOTES.get(symbol);
-
+
       if (quote == null) {
         System.out.println("Bad symbol " + symbol);
       } else {
@@ -292,44 +340,45 @@
         Integer sharesOwned = player.getSharesOwned(symbol);
         boolean favorite = player.isFavorite(symbol);
         int totalPaid = player.getAverageCostBasis(symbol);
-
+
         toRet.add(new StockQuote(symbol, name, quote.getPrice(),
- quote.getChange(), sharesOwned == null ? 0 : sharesOwned.intValue(),
-                favorite, totalPaid));
+            quote.getChange(),
+            sharesOwned == null ? 0 : sharesOwned.intValue(), favorite,
+            totalPaid));
       }
     }
-
+
     return new Result(toRet, toRet.size());
   }

   // If a query is alpha-only ([A-Za-z]+), return stocks for which:
-  //   1a) a prefix of the ticker symbol matches the query
-  //   2) any substring of the stock name matches the query
+  // 1a) a prefix of the ticker symbol matches the query
+  // 2) any substring of the stock name matches the query
   //
   // If a query is non-alpha, consider it as a regex and return stocks for
   // which:
-  //   1b) any portion of the stock symbol matches the regex
-  //   2) any portion of the stock name matches the regex
+  // 1b) any portion of the stock symbol matches the regex
+  // 2) any portion of the stock name matches the regex
   private Result getSearchQuotes(String query, Range searchRange) {
     SortedSet<String> symbols = new TreeSet<String>();
-
+
     boolean queryIsAlpha = true;
     for (int i = 0; i < query.length(); i++) {
       char c = query.charAt(i);
       if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z')) {
         queryIsAlpha = false;
         break;
-      }
+      }
     }

     // Canonicalize case
     query = query.toUpperCase(Locale.US);
-
+
     // (1a)
     if (queryIsAlpha) {
       getTickersByPrefix(query, symbols);
     }
-
+
     // Use Unicode case-insensitive matching, allow matching of a substring
     Pattern pattern = compile("(?iu).*(" + query + ").*");
     if (pattern != null) {
@@ -337,7 +386,7 @@
       if (!queryIsAlpha) {
         getTickersBySymbolRegex(pattern, symbols);
       }
-
+
       // (2)
       if (query.length() > 2) {
         getTickersByNameRegex(pattern, symbols);
@@ -352,29 +401,29 @@
     if (pattern == null) {
       return;
     }
-
- for (Map.Entry<String,String> entry : Stocks.companyNamesBySymbol.entrySet()) {
+
+ for (Map.Entry<String, String> entry : Stocks.companyNamesBySymbol.entrySet()) {
       if (tickers.size() >= MAX_RESULTS_TO_RETURN) {
         return;
       }
-
+
       if (match(entry.getValue(), pattern)) {
         tickers.add(entry.getKey());
       }
     }
   }
-
+
   // Assume prefix is upper case
   private void getTickersByPrefix(String prefix, Set<String> tickers) {
     if (prefix == null || prefix.length() == 0) {
       return;
     }
-
+
     for (String ticker : Stocks.stockTickers) {
       if (tickers.size() >= MAX_RESULTS_TO_RETURN) {
         break;
       }
-
+
       if (ticker.startsWith(prefix)) {
         tickers.add(ticker);
       }
@@ -386,7 +435,7 @@
     if (pattern == null) {
       return;
     }
-
+
     for (String ticker : Stocks.stockTickers) {
       if (tickers.size() >= MAX_RESULTS_TO_RETURN) {
         return;
@@ -396,7 +445,7 @@
       }
     }
   }
-
+
   private boolean match(String symbol, Pattern pattern) {
     Matcher m = pattern.matcher(symbol);
     return m.matches();
@@ -416,7 +465,7 @@
     if (favoritesPattern != null) {
       getTickersBySymbolRegex(favoritesPattern, symbols);
     }
-
+
     return getQuotes(symbols, favoritesRange);
   }

=======================================
--- /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockResponse.java Thu Mar 11 03:44:25 2010 +++ /trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/shared/StockResponse.java Fri Mar 12 07:16:19 2010
@@ -16,6 +16,7 @@
 package com.google.gwt.bikeshed.sample.stocks.shared;

 import java.io.Serializable;
+import java.util.List;

 /**
  * A response to a request for stock data.
@@ -25,7 +26,6 @@
   /**
    * The amount of available cash in pennies.
    */
-  private int cash;
   private StockQuoteList favorites;
   private int numFavorites;
   private int numSearchResults;
@@ -33,9 +33,14 @@
   private StockQuoteList searchResults;
   private StockQuoteList sector;
   private String sectorName;
-
- public StockResponse(StockQuoteList searchResults, StockQuoteList favorites, - String sectorName, StockQuoteList sector, int numSearchResults, int numFavorites, int numSector, int cash) {
+  private PlayerInfo player;
+  private List<PlayerInfo> players;
+
+  public StockResponse(PlayerInfo player, StockQuoteList searchResults,
+      StockQuoteList favorites, String sectorName, StockQuoteList sector,
+      int numSearchResults, int numFavorites, int numSector,
+      List<PlayerInfo> players) {
+    this.player = player;
     this.searchResults = searchResults;
     this.favorites = favorites;
     this.sectorName = sectorName;
@@ -43,7 +48,7 @@
     this.numSearchResults = numSearchResults;
     this.numFavorites = numFavorites;
     this.numSector = numSector;
-    this.cash = cash;
+    this.players = players;
   }

   /**
@@ -53,18 +58,18 @@
   }

   public int getCash() {
-    return cash;
+    return player.getCash();
   }

   public StockQuoteList getFavorites() {
     return favorites;
   }
-
+
   /**
-   * The sum of cash available and portfolio value.
+   * The sum of cash available and portfolio value.
    */
   public int getNetWorth() {
-    return cash + favorites.getValue();
+    return player.getNetWorth();
   }

   public int getNumFavorites() {
@@ -78,6 +83,15 @@
   public int getNumSector() {
     return numSector;
   }
+
+  /**
+   * Get the list of all players and their scores.
+   *
+   * @return the ordered list of all players
+   */
+  public List<PlayerInfo> getPlayers() {
+    return players;
+  }

   public StockQuoteList getSearchResults() {
     return searchResults;
@@ -86,7 +100,7 @@
   public StockQuoteList getSector() {
     return sector;
   }
-
+
   public String getSectorName() {
     return sectorName;
   }
=======================================
--- /trunk/bikeshed/war/Stocks.css      Thu Mar 11 10:09:28 2010
+++ /trunk/bikeshed/war/Stocks.css      Fri Mar 12 07:16:19 2010
@@ -59,6 +59,13 @@
 .serverResponseLabelError {
   color: red;
 }
+
+.playerScoreBox {
+  border: 1px solid #777;
+  padding:3px;
+  background: #eee;
+  margin-bottom: 5px;
+}

 /** Set ids using widget.getElement().setId("idOfElement") */
 #closeButton {
=======================================
--- /trunk/bikeshed/war/WEB-INF/web.xml Thu Mar  4 12:59:01 2010
+++ /trunk/bikeshed/war/WEB-INF/web.xml Fri Mar 12 07:16:19 2010
@@ -41,4 +41,14 @@
     <welcome-file>Tree.html</welcome-file>
   </welcome-file-list>

+  <!-- Require login. -->
+  <security-constraint>
+    <web-resource-collection>
+      <url-pattern>/*</url-pattern>
+    </web-resource-collection>
+    <auth-constraint>
+      <role-name>*</role-name>
+    </auth-constraint>
+  </security-constraint>
+
 </web-app>

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to