Skip to content

Instantly share code, notes, and snippets.

@scottferg
Created August 7, 2009 20:30
Show Gist options
  • Save scottferg/164150 to your computer and use it in GitHub Desktop.
Save scottferg/164150 to your computer and use it in GitHub Desktop.
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