Created
August 7, 2009 20:30
-
-
Save scottferg/164150 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.google.gwt.sample.stockwatcher.client; | |
import com.google.gwt.core.client.GWT; | |
import com.google.gwt.core.client.EntryPoint; | |
import com.google.gwt.core.client.JsArray; | |
import com.google.gwt.http.client.URL; | |
import com.google.gwt.http.client.Request; | |
import com.google.gwt.http.client.RequestBuilder; | |
import com.google.gwt.http.client.RequestCallback; | |
import com.google.gwt.http.client.RequestException; | |
import com.google.gwt.http.client.Response; | |
import com.google.code.gwt.storage.client.Storage; | |
import com.google.code.gwt.storage.client.StorageEvent; | |
import com.google.code.gwt.storage.client.StorageEventHandler; | |
import com.google.gwt.event.dom.client.ClickEvent; | |
import com.google.gwt.event.dom.client.ClickHandler; | |
import com.google.gwt.event.dom.client.KeyCodes; | |
import com.google.gwt.event.dom.client.KeyPressEvent; | |
import com.google.gwt.event.dom.client.KeyPressHandler; | |
import com.google.gwt.user.client.Window; | |
import com.google.gwt.user.client.Timer; | |
import com.google.gwt.user.client.Random; | |
import com.google.gwt.user.client.ui.Button; | |
import com.google.gwt.user.client.ui.FlexTable; | |
import com.google.gwt.user.client.ui.HorizontalPanel; | |
import com.google.gwt.user.client.ui.Label; | |
import com.google.gwt.user.client.ui.TextBox; | |
import com.google.gwt.user.client.ui.VerticalPanel; | |
import com.google.gwt.user.client.ui.RootPanel; | |
import com.google.gwt.i18n.client.NumberFormat; | |
import com.google.gwt.i18n.client.DateTimeFormat; | |
import java.util.ArrayList; | |
import java.util.Date; | |
import java.util.Iterator; | |
public class StockWatcher implements EntryPoint { | |
private static final int REFRESH_INTERVAL = 5000; // ms | |
// Should be able to use GWT.getModuleBaseURL() but that returns a 404 | |
private static final String JSON_URL = "http://localhost/StockWatcher/war/stockPrices.php?q="; | |
private VerticalPanel main_panel = new VerticalPanel(); | |
private FlexTable stocks_flex_table = new FlexTable(); | |
private HorizontalPanel add_panel = new HorizontalPanel(); | |
private TextBox new_symbol_text_box = new TextBox(); | |
private Button add_stock_button = new Button("Add"); | |
private Label last_updated_label = new Label(); | |
private ArrayList<String> stocks = new ArrayList<String>(); | |
private Storage local_storage = Storage.getLocalStorage(); | |
private Label error_msg_label = new Label(); | |
/** | |
* Entry point method | |
*/ | |
public void onModuleLoad() | |
{ | |
// Create table for stock data | |
stocks_flex_table.setText(0, 0, "Symbol"); | |
stocks_flex_table.setText(0, 1, "Price"); | |
stocks_flex_table.setText(0, 2, "Change"); | |
stocks_flex_table.setText(0, 3, "Remove"); | |
// Add styles to elements in the stock list table | |
stocks_flex_table.setCellPadding(6); | |
stocks_flex_table.getRowFormatter().addStyleName(0, "watchListHeader"); | |
stocks_flex_table.addStyleName("watchList"); | |
stocks_flex_table.getCellFormatter().addStyleName(0, 1, "watchListNumericColumn"); | |
stocks_flex_table.getCellFormatter().addStyleName(0, 2, "watchListNumericColumn"); | |
stocks_flex_table.getCellFormatter().addStyleName(0, 3, "watchListRemoveColumn"); | |
// Assemble Add Stock panel | |
add_panel.add(new_symbol_text_box); | |
add_panel.add(add_stock_button); | |
add_panel.addStyleName("addPanel"); | |
// Assemble Main panel | |
error_msg_label.setStyleName("errorMessage"); | |
error_msg_label.setVisible(false); | |
main_panel.add(error_msg_label); | |
main_panel.add(stocks_flex_table); | |
main_panel.add(add_panel); | |
main_panel.add(last_updated_label); | |
// Associate the Main panel with the HTML host page | |
RootPanel.get("stockList").add(main_panel); | |
// Move cursor focus to the input box | |
new_symbol_text_box.setFocus(true); | |
// Setup timer to refresh list automatically | |
Timer refresh_timer = new Timer() { | |
@Override | |
public void run() | |
{ | |
refreshWatchList(); | |
} | |
}; | |
refresh_timer.scheduleRepeating(REFRESH_INTERVAL); | |
// Listen for click events on the "Add" button | |
add_stock_button.addClickHandler(new ClickHandler() | |
{ | |
public void onClick(ClickEvent event) | |
{ | |
addStock(); | |
} | |
}); | |
// Listen for keyboard events in the input box | |
new_symbol_text_box.addKeyPressHandler(new KeyPressHandler() | |
{ | |
public void onKeyPress(KeyPressEvent event) | |
{ | |
if (event.getCharCode() == KeyCodes.KEY_ENTER) | |
{ | |
addStock(); | |
} | |
} | |
}); | |
readLocalStorage(); | |
} | |
private void addStock() | |
{ | |
final String symbol = new_symbol_text_box.getText().toUpperCase().trim(); | |
if (this.validateStock(symbol)) | |
{ | |
addStock(symbol, true); | |
} | |
} | |
private void addStock(final String symbol, | |
boolean write_local_storage) | |
{ | |
new_symbol_text_box.setFocus(true); | |
new_symbol_text_box.setText(""); | |
// Add the stock to the table | |
int row = stocks_flex_table.getRowCount(); | |
stocks.add(symbol); | |
stocks_flex_table.setText(row, 0, symbol); | |
stocks_flex_table.setWidget(row, 2, new Label()); | |
stocks_flex_table.getCellFormatter().addStyleName(0, 1, "watchListNumericColumn"); | |
stocks_flex_table.getCellFormatter().addStyleName(0, 2, "watchListNumericColumn"); | |
stocks_flex_table.getCellFormatter().addStyleName(0, 3, "watchListRemoveColumn"); | |
// Add the stock to localStorage | |
if (!(local_storage == null)) | |
{ | |
if (write_local_storage) | |
local_storage.setItem("row-" + (new Integer(row).toString()), symbol); | |
} | |
// Add a button to remove this stock from the table | |
Button remove_stock_button = new Button("X"); | |
remove_stock_button.addStyleDependentName("remove"); | |
remove_stock_button.addClickHandler(new ClickHandler() | |
{ | |
public void onClick(ClickEvent event) | |
{ | |
int removed_index = stocks.indexOf(symbol); | |
stocks.remove(removed_index); | |
stocks_flex_table.removeRow(removed_index + 1); | |
} | |
}); | |
stocks_flex_table.setWidget(row, 3, remove_stock_button); | |
// Get the stock price | |
refreshWatchList(); | |
} | |
private boolean validateStock(final String symbol) | |
{ | |
// Stock code must be between 1 and 10 characters that are | |
// numbers, letters, or dots. | |
if (!symbol.matches("^[0-9A-Z\\.]{1,10}$")) | |
{ | |
Window.alert("'" + symbol + "' is not a valid symbol."); | |
new_symbol_text_box.selectAll(); | |
return false; | |
} | |
// Don't add the stock if it's already in the table | |
if (stocks.contains(symbol)) | |
return false; | |
return true; | |
} | |
// Refresh prices on list of stocks | |
private void refreshWatchList() | |
{ | |
if (stocks.size() == 0) | |
{ | |
return; | |
} | |
String url = JSON_URL; | |
// Append watch list stock symbols to query URL | |
Iterator iter = stocks.iterator(); | |
while (iter.hasNext()) | |
{ | |
url += iter.next(); | |
if (iter.hasNext()) | |
{ | |
url += "+"; | |
} | |
} | |
url = URL.encode(url); | |
// Send request to server and handle errors | |
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url); | |
try { | |
Request request = builder.sendRequest(null, new RequestCallback() | |
{ | |
public void onError(Request request, Throwable exception) | |
{ | |
displayError("Couldn't retrieve JSON"); | |
} | |
public void onResponseReceived(Request request, Response response) | |
{ | |
if (200 == response.getStatusCode()) | |
{ | |
updateTable(asArrayOfStockData(response.getText())); | |
} else { | |
displayError("Couldn't retrieve JSON (" + response.getStatusText() + ")"); | |
} | |
} | |
}); | |
} catch (RequestException e) { | |
displayError("Couldn't retrieve JSON"); | |
} | |
} | |
/** | |
* Update the Price and Change for all fields in the stock table | |
* | |
* @param prices Stock data for all rows | |
*/ | |
private void updateTable(JsArray<StockData> prices) | |
{ | |
for (int i = 0; i < prices.length(); i++) | |
{ | |
updateTable(prices.get(i)); | |
} | |
// Display timestamp showing last refresh | |
last_updated_label.setText("Last update: " | |
+ DateTimeFormat.getMediumDateTimeFormat().format(new Date())); | |
// Clear any errors | |
error_msg_label.setVisible(false); | |
} | |
/** | |
* Update a single row in the stock table | |
* | |
* @param price Stock data for a single row | |
*/ | |
private void updateTable(StockData price) | |
{ | |
// Make sure the stock is still in the stock table | |
if (!stocks.contains(price.getSymbol())) | |
{ | |
return; | |
} | |
int row = stocks.indexOf(price.getSymbol()) + 1; | |
// Format the data in the Price and Change fields | |
String price_text = NumberFormat.getFormat("#,##0.00").format( | |
price.getPrice()); | |
NumberFormat change_format = NumberFormat.getFormat("+#,##0.00;-#,##0.00"); | |
String change_text = change_format.format(price.getChange()); | |
String change_percent_text = change_format.format(price.getChangePercent()); | |
// Populate the Price and Change fields with new data | |
stocks_flex_table.setText(row, 1, price_text); | |
Label change_widget = (Label)stocks_flex_table.getWidget(row, 2); | |
change_widget.setText(change_text + " (" + change_percent_text + "%)"); | |
// Change color of text in the Change field based on it's value | |
String change_style_name = "noChange"; | |
if (price.getChangePercent() < -0.1f) | |
{ | |
change_style_name = "negativeChange"; | |
} else if (price.getChangePercent() > 0.1f) { | |
change_style_name = "positiveChange"; | |
} | |
change_widget.setStyleName(change_style_name); | |
} | |
/** | |
* Read localStorage for row-N keys and push each out to the | |
* stocks list | |
*/ | |
private void readLocalStorage() | |
{ | |
for (int i = 0; i < local_storage.getLength(); i++) | |
{ | |
String current_key = local_storage.key(i); | |
final String symbol = local_storage.getItem(current_key); | |
if (this.validateStock(symbol)) | |
this.addStock(symbol, false); | |
} | |
} | |
/** | |
* If can't get JSON, display error message | |
* | |
* @param error | |
*/ | |
private void displayError(String error) | |
{ | |
error_msg_label.setText("Error: " + error); | |
error_msg_label.setVisible(true); | |
} | |
/** | |
* Convert the string of JSON into JavaScript object | |
*/ | |
private final native JsArray<StockData> asArrayOfStockData(String json) /*-{ return eval(json); }-*/; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment