Inital commit

This commit is contained in:
Tilman
2011-10-26 09:44:02 +02:00
commit 5971f4b417
1813 changed files with 737837 additions and 0 deletions
@@ -0,0 +1,234 @@
/* Copyright (c) 2008 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 sample.spreadsheet;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.SpreadsheetQuery;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.client.spreadsheet.WorksheetQuery;
import com.google.gdata.data.Link;
import com.google.gdata.data.spreadsheet.CellEntry;
import com.google.gdata.data.spreadsheet.CellFeed;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.data.spreadsheet.WorksheetEntry;
import com.google.gdata.data.spreadsheet.WorksheetFeed;
import java.io.BufferedReader;
import java.io.FileReader;
import java.net.URL;
import java.util.List;
import java.util.regex.Pattern;
/**
* An application that serves as a sample to show how the SpreadsheetService
* can be used to import delimited text file to a spreadsheet.
*
*
*/
public class ImportClient {
private SpreadsheetService service;
private FeedURLFactory factory;
public ImportClient() throws Exception {
factory = FeedURLFactory.getDefault();
service = new SpreadsheetService("gdata-sample-spreadsheetimport");
}
/**
* Creates a client object for which the provided username and password
* produces a valid authentication.
*
* @param username the Google service user name
* @param password the corresponding password for the user name
* @throws Exception if error is encountered, such as invalid username and
* password pair
*/
public ImportClient(String username, String password) throws Exception {
this();
service.setUserCredentials(username, password);
}
/**
* Gets the SpreadsheetEntry for the first spreadsheet with that name
* retrieved in the feed.
*
* @param spreadsheet the name of the spreadsheet
* @return the first SpreadsheetEntry in the returned feed, so latest
* spreadsheet with the specified name
* @throws Exception if error is encountered, such as no spreadsheets with the
* name
*/
public SpreadsheetEntry getSpreadsheet(String spreadsheet)
throws Exception {
SpreadsheetQuery spreadsheetQuery
= new SpreadsheetQuery(factory.getSpreadsheetsFeedUrl());
spreadsheetQuery.setTitleQuery(spreadsheet);
SpreadsheetFeed spreadsheetFeed = service.query(spreadsheetQuery,
SpreadsheetFeed.class);
List<SpreadsheetEntry> spreadsheets = spreadsheetFeed.getEntries();
if (spreadsheets.isEmpty()) {
throw new Exception("No spreadsheets with that name");
}
return spreadsheets.get(0);
}
/**
* Get the WorksheetEntry for the worksheet in the spreadsheet with the
* specified name.
*
* @param spreadsheet the name of the spreadsheet
* @param worksheet the name of the worksheet in the spreadsheet
* @return worksheet with the specified name in the spreadsheet with the
* specified name
* @throws Exception if error is encountered, such as no spreadsheets with the
* name, or no worksheet wiht the name in the spreadsheet
*/
public WorksheetEntry getWorksheet(String spreadsheet, String worksheet)
throws Exception {
SpreadsheetEntry spreadsheetEntry = getSpreadsheet(spreadsheet);
WorksheetQuery worksheetQuery
= new WorksheetQuery(spreadsheetEntry.getWorksheetFeedUrl());
worksheetQuery.setTitleQuery(worksheet);
WorksheetFeed worksheetFeed = service.query(worksheetQuery,
WorksheetFeed.class);
List<WorksheetEntry> worksheets = worksheetFeed.getEntries();
if (worksheets.isEmpty()) {
throw new Exception("No worksheets with that name in spreadhsheet "
+ spreadsheetEntry.getTitle().getPlainText());
}
return worksheets.get(0);
}
/**
* Clears all the cell entries in the worksheet.
*
* @param spreadsheet the name of the spreadsheet
* @param worksheet the name of the worksheet
* @throws Exception if error is encountered, such as bad permissions
*/
public void purgeWorksheet(String spreadsheet, String worksheet)
throws Exception {
WorksheetEntry worksheetEntry = getWorksheet(spreadsheet, worksheet);
CellFeed cellFeed = service.getFeed(worksheetEntry.getCellFeedUrl(),
CellFeed.class);
List<CellEntry> cells = cellFeed.getEntries();
for (CellEntry cell : cells) {
Link editLink = cell.getEditLink();
service.delete(new URL(editLink.getHref()));
}
}
/**
* Inserts a cell entry in the worksheet.
*
* @param spreadsheet the name of the spreadsheet
* @param worksheet the name of the worksheet
* @param row the index of the row
* @param column the index of the column
* @param input the input string for the cell
* @throws Exception if error is encountered, such as bad permissions
*/
public void insertCellEntry(String spreadsheet, String worksheet,
int row, int column, String input) throws Exception {
URL cellFeedUrl = getWorksheet(spreadsheet, worksheet).getCellFeedUrl();
CellEntry newEntry = new CellEntry(row, column, input);
service.insert(cellFeedUrl, newEntry);
}
/**
* Prints the usage of this application.
*/
private static void usage() {
System.out.println("Usage: java ImportClient --username [user] "
+ "--password [pass] --filename [file] --spreadsheet [name] "
+ "--worksheet [name] --delimiter [regex]");
System.out.println("\nA simple application that uses the provided Google\n"
+ "Account username and password to locate the\n"
+ "spreadsheet and worksheet in user's Google\n"
+ "Spreadsheet account, and import the provided\n"
+ "delimited text file into the worksheet.");
}
/**
* Main entry point. Parses arguments and creates and invokes the
* ImportClient.
*/
public static void main(String[] args) throws Exception {
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
String username = parser.getValue("username", "user", "u");
String password = parser.getValue("password", "pass", "passwd", "pw", "p");
String filename = parser.getValue("filename", "file", "f");
String spreadsheet = parser.getValue("spreadsheet", "s");
String worksheet = parser.getValue("worksheet", "w");
String delimiter = parser.getValue("delimiter", "delimit", "d");
boolean help = parser.containsKey("help", "h");
if (help || (username == null) || (password == null)
|| (spreadsheet == null) || (worksheet == null)
|| (delimiter == null)) {
usage();
System.exit(1);
}
ImportClient client = new ImportClient(username, password);
client.purgeWorksheet(spreadsheet, worksheet);
Pattern delim = Pattern.compile(delimiter);
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(filename));
String line = reader.readLine();
int row = 0;
while (line != null) {
// Break up the line by the delimiter and insert the cells
String[] cells = delim.split(line, -1);
for (int col = 0; col < cells.length; col++) {
client.insertCellEntry(spreadsheet, worksheet,
row + 1, col + 1, cells[col]);
}
// Advance the loop
line = reader.readLine();
row++;
}
} catch (Exception e) {
throw e;
} finally {
if (reader != null) {
reader.close();
}
}
}
}
@@ -0,0 +1,190 @@
/* Copyright (c) 2008 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 sample.spreadsheet;
import com.google.gdata.data.Person;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.CellQuery;
import com.google.gdata.data.Feed;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.data.spreadsheet.CellFeed;
import com.google.gdata.data.Entry;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.WorksheetEntry;
import com.google.gdata.data.spreadsheet.CellEntry;
import com.google.gdata.data.spreadsheet.Cell;
import sample.util.SimpleCommandLineParser;
import java.net.URL;
import java.util.List;
import java.util.ArrayList;
/**
* An application that serves as a sample to show how the SpreadhseetService
* can be used to obtain an index of spreadsheets with author and worksheets.
*
*
*/
public class IndexClient {
private SpreadsheetService service;
private FeedURLFactory factory;
/**
* Creates a client object for which the provided username and password
* produces a valid authentication.
*
* @param username the Google service user name
* @param password the corresponding password for the user name
* @throws Exception if error is encountered, such as invalid username and
* password pair
*/
public IndexClient(String username, String password) throws Exception {
factory = FeedURLFactory.getDefault();
service = new SpreadsheetService("gdata-sample-spreadhsheetindex");
service.setUserCredentials(username, password);
}
/**
* Retrieves the spreadsheets that the authenticated user has access to.
*
* @return a list of spreadsheet entries
* @throws Exception if error in retrieving the spreadsheet information
*/
public List<SpreadsheetEntry> getSpreadsheetEntries() throws Exception {
SpreadsheetFeed feed = service.getFeed(
factory.getSpreadsheetsFeedUrl(), SpreadsheetFeed.class);
return feed.getEntries();
}
/**
* Retrieves the worksheet entries from a spreadsheet entry.
*
* @param spreadsheet the spreadsheet entry containing the worksheet entries
* @return a list of worksheet entries
* @throws Exception if error in retrieving the spreadsheet information
*/
public List<WorksheetEntry> getWorksheetEntries(SpreadsheetEntry spreadsheet)
throws Exception {
return spreadsheet.getWorksheets();
}
/**
* Retrieves the columns headers from the cell feed of the worksheet
* entry.
*
* @param worksheet worksheet entry containing the cell feed in question
* @return a list of column headers
* @throws Exception if error in retrieving the spreadsheet information
*/
public List<String> getColumnHeaders(WorksheetEntry worksheet)
throws Exception {
List<String> headers = new ArrayList<String>();
// Get the appropriate URL for a cell feed
URL cellFeedUrl = worksheet.getCellFeedUrl();
// Create a query for the top row of cells only (1-based)
CellQuery cellQuery = new CellQuery(cellFeedUrl);
cellQuery.setMaximumRow(1);
// Get the cell feed matching the query
CellFeed topRowCellFeed = service.query(cellQuery, CellFeed.class);
// Get the cell entries fromt he feed
List<CellEntry> cellEntries = topRowCellFeed.getEntries();
for (CellEntry entry : cellEntries) {
// Get the cell element from the entry
Cell cell = entry.getCell();
headers.add(cell.getValue());
}
return headers;
}
/**
* Prints the usage of this application.
*/
private static void usage() {
System.out.println("Usage: java IndexClient --username [user] " +
"--password [pass] [--authors] [--worksheets] [--headers]");
System.out.println("\nA simple application that uses the provided Google\n"
+ "Account username and password to create\n"
+ "an index of the user's spreadsheets against\n"
+ "the user's Google Spreadsheet account.\n");
}
/**
* Main entry point. Parses arguments and creates and invokes the
* IndexClient.
*/
public static void main(String[] args) throws Exception {
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
String username = parser.getValue("username", "user", "u");
String password = parser.getValue("password", "pass", "passwd", "pw", "p");
boolean help = parser.containsKey("help", "h");
if (help || (username == null) || (password == null)) {
usage();
System.exit(1);
}
boolean author = parser.containsKey("author", "a");
boolean columns = parser.containsKey("headers", "header", "h");
boolean worksheets = parser.containsKey("worksheets", "worksheet", "w");
IndexClient client = new IndexClient(username, password);
for (SpreadsheetEntry spreadsheet : client.getSpreadsheetEntries()) {
System.out.print(spreadsheet.getTitle().getPlainText());
if (author) {
for (Person person : spreadsheet.getAuthors()) {
System.out.println(" - " + person.getName());
}
} else {
System.out.println();
} //authors (or not)
if (worksheets || columns) {
List<WorksheetEntry> entries = client.getWorksheetEntries(spreadsheet);
for (WorksheetEntry worksheet : entries) {
System.out.println("\t" + worksheet.getTitle().getPlainText());
if (columns) {
List<String> headers = client.getColumnHeaders(worksheet);
for (String header : headers) {
System.out.println("\t\t" + header);
}
} // columns
}
} // worksheets
} // spreadsheets
}
}
+16
View File
@@ -0,0 +1,16 @@
Google Spreadsheets data API Java Sample - README.txt
-----------------------------------------------------
Google Spreadsheets has multiple ways of access, and thus we have
multiple sample applications.
In cells/, there is a small sample application that shows
demonstrates positional getting and setting of formulas and values.
In list/, there is a small sample application where you can modify
your spreadsheet data almost like a database.
Finally, in gui/, there is a sample that you can use to see potential
ways that Google Spreadsheets Data API could be used to develop a
real, full-featured application.
@@ -0,0 +1,511 @@
/* Copyright (c) 2008 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 sample.spreadsheet.cell;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.client.spreadsheet.CellQuery;
import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.Link;
import com.google.gdata.data.batch.BatchOperationType;
import com.google.gdata.data.batch.BatchStatus;
import com.google.gdata.data.batch.BatchUtils;
import com.google.gdata.data.spreadsheet.CellEntry;
import com.google.gdata.data.spreadsheet.CellFeed;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.data.spreadsheet.WorksheetEntry;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URL;
import java.util.List;
/**
* Using this demo, you can see how GData can read and write to individual cells
* based on their position or send a batch of update commands in one HTTP
* request.
*
* Usage: java CellDemo --username [user] --password [pass]
*/
public class CellDemo {
/** The message for displaying the usage parameters. */
private static final String[] USAGE_MESSAGE = {
"Usage: java CellDemo --username [user] --password [pass] ", ""};
/** Welcome message, introducing the program. */
private static final String[] WELCOME_MESSAGE = {
"This is a demo of the cells feed!", "",
"Using this interface, you can read/write to your spreadsheet's cells.",
""};
/** Help on all available commands. */
private static final String[] COMMAND_HELP_MESSAGE = {
"Commands:",
" load "
+ "[[select a spreadsheet and worksheet]]",
" list [[shows all cells]]",
" range minRow maxRow minCol maxCol [[rectangle]]",
" set row# col# formula [[sets a cell]]",
" example: set 1 3 =R1C2+1",
" search adam [[full text query]]",
" batch [[batch request]]",
" exit"};
/** Our view of Google Spreadsheets as an authenticated Google user. */
private SpreadsheetService service;
/** The URL of the cells feed. */
private URL cellFeedUrl;
/** The output stream. */
private PrintStream out;
/** A factory that generates the appropriate feed URLs. */
private FeedURLFactory factory;
/**
* Constructs a cell demo from the specified spreadsheet service, which is
* used to authenticate to and access Google Spreadsheets.
*
* @param service the connection to the Google Spradsheets service.
* @param outputStream a handle for stdout.
*/
public CellDemo(SpreadsheetService service, PrintStream outputStream) {
this.service = service;
this.out = outputStream;
this.factory = FeedURLFactory.getDefault();
}
/**
* Log in to Google, under the Google Spreadsheets account.
*
* @param username name of user to authenticate (e.g. yourname@gmail.com)
* @param password password to use for authentication
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public void login(String username, String password)
throws AuthenticationException {
// Authenticate
service.setUserCredentials(username, password);
}
/**
* Displays the given list of entries and prompts the user to select the index
* of one of the entries. NOTE: The displayed index is 1-based and is
* converted to 0-based before being returned.
*
* @param reader to read input from the keyboard
* @param entries the list of entries to display
* @param type describes the type of things the list contains
* @return the 0-based index of the user's selection
* @throws IOException if an I/O error occurs while getting input from user
*/
private int getIndexFromUser(BufferedReader reader, List entries, String type)
throws IOException {
for (int i = 0; i < entries.size(); i++) {
BaseEntry entry = (BaseEntry) entries.get(i);
System.out.println("\t(" + (i + 1) + ") "
+ entry.getTitle().getPlainText());
}
int index = -1;
while (true) {
out.print("Enter the number of the spreadsheet to load: ");
String userInput = reader.readLine();
try {
index = Integer.parseInt(userInput);
if (index < 1 || index > entries.size()) {
throw new NumberFormatException();
}
break;
} catch (NumberFormatException e) {
System.out.println("Please enter a valid number for your selection.");
}
}
return index - 1;
}
/**
* Uses the user's credentials to get a list of spreadsheets. Then asks the
* user which spreadsheet to load. If the selected spreadsheet has multiple
* worksheets then the user will also be prompted to select what sheet to use.
*
* @param reader to read input from the keyboard
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*
*/
public void loadSheet(BufferedReader reader) throws IOException,
ServiceException {
// Get the spreadsheet to load
SpreadsheetFeed feed = service.getFeed(factory.getSpreadsheetsFeedUrl(),
SpreadsheetFeed.class);
List spreadsheets = feed.getEntries();
int spreadsheetIndex = getIndexFromUser(reader, spreadsheets,
"spreadsheet");
SpreadsheetEntry spreadsheet = feed.getEntries().get(spreadsheetIndex);
// Get the worksheet to load
if (spreadsheet.getWorksheets().size() == 1) {
cellFeedUrl = spreadsheet.getWorksheets().get(0).getCellFeedUrl();
} else {
List worksheets = spreadsheet.getWorksheets();
int worksheetIndex = getIndexFromUser(reader, worksheets, "worksheet");
WorksheetEntry worksheet = (WorksheetEntry) worksheets
.get(worksheetIndex);
cellFeedUrl = worksheet.getCellFeedUrl();
}
System.out.println("Sheet loaded.");
}
/**
* Sets the particular cell at row, col to the specified formula or value.
*
* @param row the row number, starting with 1
* @param col the column number, starting with 1
* @param formulaOrValue the value if it doesn't start with an '=' sign; if it
* is a formula, be careful that cells are specified in R1C1 format
* instead of A1 format.
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void setCell(int row, int col, String formulaOrValue)
throws IOException, ServiceException {
CellEntry newEntry = new CellEntry(row, col, formulaOrValue);
service.insert(cellFeedUrl, newEntry);
out.println("Added!");
}
/**
* Prints out the specified cell.
*
* @param cell the cell to print
*/
public void printCell(CellEntry cell) {
String shortId = cell.getId().substring(cell.getId().lastIndexOf('/') + 1);
out.println(" -- Cell(" + shortId + "/" + cell.getTitle().getPlainText()
+ ") formula(" + cell.getCell().getInputValue() + ") numeric("
+ cell.getCell().getNumericValue() + ") value("
+ cell.getCell().getValue() + ")");
}
/**
* Shows all cells that are in the spreadsheet.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void showAllCells() throws IOException, ServiceException {
CellFeed feed = service.getFeed(cellFeedUrl, CellFeed.class);
for (CellEntry entry : feed.getEntries()) {
printCell(entry);
}
}
/**
* Shows a particular range of cells, limited by minimum/maximum rows and
* columns.
*
* @param minRow the minimum row, inclusive, 1-based
* @param maxRow the maximum row, inclusive, 1-based
* @param minCol the minimum column, inclusive, 1-based
* @param maxCol the maximum column, inclusive, 1-based
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void showRange(int minRow, int maxRow, int minCol, int maxCol)
throws IOException, ServiceException {
CellQuery query = new CellQuery(cellFeedUrl);
query.setMinimumRow(minRow);
query.setMaximumRow(maxRow);
query.setMinimumCol(minCol);
query.setMaximumCol(maxCol);
CellFeed feed = service.query(query, CellFeed.class);
for (CellEntry entry : feed.getEntries()) {
printCell(entry);
}
}
/**
* Performs a full-text search on cells.
*
* @param fullTextSearchString a full text search string, with space-separated
* keywords
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void search(String fullTextSearchString) throws IOException,
ServiceException {
CellQuery query = new CellQuery(cellFeedUrl);
query.setFullTextQuery(fullTextSearchString);
CellFeed feed = service.query(query, CellFeed.class);
out.println("Results for [" + fullTextSearchString + "]");
for (CellEntry entry : feed.getEntries()) {
printCell(entry);
}
}
/**
* Writes (to stdout) a list of the entries in the batch request in a human
* readable format.
*
* @param batchRequest the CellFeed containing entries to display.
*/
private void printBatchRequest(CellFeed batchRequest) {
System.out.println("Current operations in batch");
for (CellEntry entry : batchRequest.getEntries()) {
String msg = "\tID: " + BatchUtils.getBatchId(entry) + " - "
+ BatchUtils.getBatchOperationType(entry) + " row: "
+ entry.getCell().getRow() + " col: " + entry.getCell().getCol()
+ " value: " + entry.getCell().getInputValue();
System.out.println(msg);
}
}
/**
* Returns a CellEntry with batch id and operation type that will tell the
* server to update the specified cell with the given value. The entry is
* fetched from the server in order to get the current edit link (for
* optimistic concurrency).
*
* @param row the row number of the cell to operate on
* @param col the column number of the cell to operate on
* @param value the value to set in case of an update the cell to operate on
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
private CellEntry createUpdateOperation(int row, int col, String value)
throws ServiceException, IOException {
String batchId = "R" + row + "C" + col;
URL entryUrl = new URL(cellFeedUrl.toString() + "/" + batchId);
CellEntry entry = service.getEntry(entryUrl, CellEntry.class);
entry.changeInputValueLocal(value);
BatchUtils.setBatchId(entry, batchId);
BatchUtils.setBatchOperationType(entry, BatchOperationType.UPDATE);
return entry;
}
/**
* Prompts the user for a set of operations and submits them in a batch
* request.
*
* @param reader to read input from the keyboard.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void processBatchRequest(BufferedReader reader)
throws IOException, ServiceException {
final String BATCH_PROMPT = "Enter set operations one by one, "
+ "then enter submit to send the batch request:\n"
+ " set row# col# value [[add a set operation]]\n"
+ " submit [[submit the request]]";
CellFeed batchRequest = new CellFeed();
// Prompt user for operation
System.out.println(BATCH_PROMPT);
String operation = reader.readLine();
while (!operation.startsWith("submit")) {
String[] s = operation.split(" ", 4);
if (s.length != 4 || !s[0].equals("set")) {
System.out.println("Invalid command: " + operation);
operation = reader.readLine();
continue;
}
// Create a new cell entry and add it to the batch request.
int row = Integer.parseInt(s[1]);
int col = Integer.parseInt(s[2]);
String value = s[3];
CellEntry batchOperation = createUpdateOperation(row, col, value);
batchRequest.getEntries().add(batchOperation);
// Display the current entries in the batch request.
printBatchRequest(batchRequest);
// Prompt for another operation.
System.out.println(BATCH_PROMPT);
operation = reader.readLine();
}
// Get the batch feed URL and submit the batch request
CellFeed feed = service.getFeed(cellFeedUrl, CellFeed.class);
Link batchLink = feed.getLink(Link.Rel.FEED_BATCH, Link.Type.ATOM);
URL batchUrl = new URL(batchLink.getHref());
CellFeed batchResponse = service.batch(batchUrl, batchRequest);
// Print any errors that may have happened.
boolean isSuccess = true;
for (CellEntry entry : batchResponse.getEntries()) {
String batchId = BatchUtils.getBatchId(entry);
if (!BatchUtils.isSuccess(entry)) {
isSuccess = false;
BatchStatus status = BatchUtils.getBatchStatus(entry);
System.out.println("\n" + batchId + " failed (" + status.getReason()
+ ") " + status.getContent());
}
}
if (isSuccess) {
System.out.println("Batch operations successful.");
}
}
/**
* Reads and executes one command.
*
* @param reader to read input from the keyboard
* @return false if the user quits, true on exception
*/
public boolean executeCommand(BufferedReader reader) {
for (String s : COMMAND_HELP_MESSAGE) {
out.println(s);
}
System.err.print("Command: ");
try {
String command = reader.readLine();
String[] parts = command.trim().split(" ", 2);
String name = parts[0];
String parameters = parts.length > 1 ? parts[1] : "";
if (name.equals("list")) {
showAllCells();
} else if (name.equals("load")) {
loadSheet(reader);
} else if (name.equals("search")) {
search(parameters);
} else if (name.equals("range")) {
String[] s = parameters.split(" ", 4);
showRange(Integer.parseInt(s[0]), Integer.parseInt(s[1]), Integer
.parseInt(s[2]), Integer.parseInt(s[3]));
} else if (name.equals("set")) {
String[] s = parameters.split(" ", 3);
setCell(Integer.parseInt(s[0]), Integer.parseInt(s[1]), s[2]);
} else if (name.equals("batch")) {
processBatchRequest(reader);
} else if (name.startsWith("q") || name.startsWith("exit")) {
return false;
} else {
out.println("Unknown command.");
}
} catch (Exception e) {
// Show *exactly* what went wrong.
e.printStackTrace();
}
return true;
}
/**
* Starts up the demo and prompts for commands.
*
* @param username name of user to authenticate (e.g. yourname@gmail.com)
* @param password password to use for authentication
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public void run(String username, String password)
throws AuthenticationException {
for (String s : WELCOME_MESSAGE) {
out.println(s);
}
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
// Login and prompt the user to pick a sheet to use.
login(username, password);
try {
loadSheet(reader);
} catch (IOException e) {
e.printStackTrace();
} catch (ServiceException e) {
e.printStackTrace();
}
while (executeCommand(reader)) {
}
}
/**
* Runs the demo.
*
* @param args the command-line arguments
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public static void main(String[] args) throws AuthenticationException {
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
String username = parser.getValue("username", "user", "u");
String password = parser.getValue("password", "pass", "p");
boolean help = parser.containsKey("help", "h");
if (help || username == null || password == null) {
usage();
System.exit(1);
}
CellDemo demo = new CellDemo(new SpreadsheetService("Cell Demo"),
System.out);
demo.run(username, password);
}
/**
* Prints out the usage.
*/
private static void usage() {
for (String s : USAGE_MESSAGE) {
System.out.println(s);
}
for (String s : WELCOME_MESSAGE) {
System.out.println(s);
}
}
}
@@ -0,0 +1,23 @@
Google Spreadsheets data API Java Sample - README.txt
-----------------------------------------------------
This is a very simple Java example of reading and writing to cells on the
spreadsheet. Using it, you can fully experiment with setting cells,
using both formulas, and values.
This can be built an run with Ant:
1. Edit gdata/java/build-samples/build.properties with your Google Account
username, password, and a URL to your Google spreadsheet
(in the format ....spreadsheets.google.com/ccc?id=...)
2. Run the Ant rule:
ant -f gdata/java/build-samples.xml sample.spreadsheet.celldemo.run
Alternately, you can compile and run it from the command line:
java sample.spreadsheet.cell.CellDemo
--username [user]
--password [pass]
@@ -0,0 +1,263 @@
/* Copyright (c) 2008 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 sample.spreadsheet.gui;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.spreadsheet.CellEntry;
import com.google.gdata.data.spreadsheet.CellFeed;
import com.google.gdata.util.ServiceException;
import java.awt.BorderLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
/**
* Widget for displaying and editing a spreadsheet.
*
* This is just for demonstrative purposes, it is not very featureful.
*
*
*/
public class CellBasedSpreadsheetPanel extends JPanel {
/** The underlying Google Spreadsheets service. */
private SpreadsheetService service;
/** The URL of the cell feed. */
private URL cellFeedUrl;
private SpreadsheetTableModel model;
private JTable table;
private JButton refreshButton;
/**
* Creates the cell-based spreadsheet widget.
*
* @param service the Google Spreadsheets service to connect to
* @param cellFeedUrl the URL of the cell feed
*/
public CellBasedSpreadsheetPanel(
SpreadsheetService service, URL cellFeedUrl) {
this.service = service;
this.cellFeedUrl = cellFeedUrl;
model = new SpreadsheetTableModel();
initializeGui();
}
/**
* Sets a cell at the specified row and column.
*
* @return the newly set cell, returned back from the server
*/
private CellEntry actuallySetCell(int row, int col, String valueOrFormula) {
try {
// This method ignores collisions. Use update() if you are afraid
// of overwriting other users' data.
CellEntry entry = new CellEntry(row, col, valueOrFormula);
return service.insert(cellFeedUrl, entry);
} catch (IOException ioe) {
SpreadsheetApiDemo.showErrorBox(ioe);
return null;
} catch (ServiceException se) {
SpreadsheetApiDemo.showErrorBox(se);
return null;
}
}
/**
* Gets a list of all cells.
*
* This just calls the method getAllCells in cellFellFeedHelper.
*/
private CellFeed getCellFeed() {
try {
return service.getFeed(cellFeedUrl, CellFeed.class);
} catch (IOException ioe) {
SpreadsheetApiDemo.showErrorBox(ioe);
return null;
} catch (ServiceException se) {
SpreadsheetApiDemo.showErrorBox(se);
return null;
}
}
// -- Mostly GUI code from here on down --
/**
* The Swing model for the spreadsheet.
*
* This is mostly GUI code.
*/
private class SpreadsheetTableModel extends AbstractTableModel {
/** All the cells indexed for easy display purposes. */
private Map<Point, CellEntry> cells = new HashMap<Point, CellEntry>();
/** The last row to display (1-based). */
private int maxRow;
/** The last column to display (1-based). */
private int maxCol;
public SpreadsheetTableModel() {
refresh();
}
/**
* Load all the cells from Google Spreadsheets.
*/
public synchronized void refresh() {
cells.clear();
CellFeed cellFeed = getCellFeed();
if (cellFeed != null) {
for (CellEntry entry : cellFeed.getEntries()) {
doAddCell(entry);
}
}
int oldMaxRow = maxRow;
int oldMaxCol = maxCol;
maxRow = cellFeed.getRowCount();
maxCol = cellFeed.getColCount();
fireTableDataChanged();
if (maxRow != oldMaxRow || maxCol != oldMaxCol) {
fireTableStructureChanged();
}
}
/**
* Implements the Swing method for handling cell edits.
*/
public void setValueAt(Object value, int screenRow, int screenCol) {
int row = screenRow + 1; // account for the fact Swing is 0-indexed
int col = screenCol + 1;
// Pop up a little window to indicate that this is busy.
JFrame statusIndicatorFrame = new JFrame();
statusIndicatorFrame.getContentPane().add(new JButton("Updating..."));
statusIndicatorFrame.setVisible(true);
statusIndicatorFrame.setSize(200, 100);
CellEntry entry = actuallySetCell(row, col, value.toString());
if (entry != null) {
doAddCell(entry);
}
statusIndicatorFrame.dispose();
fireTableDataChanged();
}
/** Tells Swing how many rows are in this table. */
public int getRowCount() {
return maxRow; // Allow user to insert up to two rows
}
/** Tells Swing how many columns are in this table. */
public int getColumnCount() {
return maxCol;
}
/** Gets the cached version of the specified cell. */
public CellEntry getCell(int row, int col) {
return cells.get(new Point(row, col));
}
/** Tells Swing the value at a particular location. */
public Object getValueAt(int screenRow, int screenCol) {
CellEntry cell = getCell(screenRow + 1, screenCol + 1);
if (cell == null) {
return null;
} else {
return cell.getCell().getValue();
}
}
public void addCell(CellEntry entry) {
doAddCell(entry);
}
private void doAddCell(CellEntry entry) {
int row = entry.getCell().getRow();
int col = entry.getCell().getCol();
cells.put(new Point(row, col), entry);
}
/** Tells Swing whether the cell is editable. */
public boolean isCellEditable(int screenRow, int screenCol) {
CellEntry cell = getCell(screenRow + 1, screenCol + 1);
if (cell == null) {
// Although this can be wrong, assume editable unless told otherwise.
return true;
} else {
return cell.getEditLink() != null;
}
}
}
public static JFrame createWindow(
SpreadsheetService service, URL cellFeedUrl) {
JFrame frame = new JFrame();
frame.setSize(600, 480);
frame.getContentPane().add(new CellBasedSpreadsheetPanel(
service, cellFeedUrl));
frame.setVisible(true);
frame.setTitle("Cells Demo - Positional Editing");
return frame;
}
private void initializeGui() {
table = new JTable(model);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
JScrollPane scrollpane = new JScrollPane(table);
setLayout(new BorderLayout());
add(scrollpane, BorderLayout.CENTER);
refreshButton = new JButton("Refresh");
refreshButton.addActionListener(new ActionHandler());
add(refreshButton, BorderLayout.SOUTH);
}
private class ActionHandler implements ActionListener {
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == refreshButton) {
model.refresh();
}
}
}
}
@@ -0,0 +1,365 @@
/* Copyright (c) 2008 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 sample.spreadsheet.gui;
import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.data.spreadsheet.WorksheetEntry;
import com.google.gdata.data.spreadsheet.WorksheetFeed;
import com.google.gdata.util.ServiceException;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
/**
* Window for selecting a spreadsheet.
*
* This is a little bit of a complicated class, but the main GData
* parts to know are:
*
* - populateSpreadsheetList just makes a few calls in order to
* get a list of spreadsheets
* - populateWorksheetList will get a list of worksheets within
* that spreadsheet
*
*
*/
public class ChooseSpreadsheetFrame extends JFrame {
/** The Google Spreadsheets GData service. */
private SpreadsheetService service;
private FeedURLFactory factory;
private List<SpreadsheetEntry> spreadsheetEntries;
private JList spreadsheetListBox;
private List<WorksheetEntry> worksheetEntries;
private JList worksheetListBox;
private JTextField ajaxLinkField;
private JTextField worksheetsFeedUrlField;
private JTextField cellsFeedUrlField;
private JTextField listFeedUrlField;
private JButton viewWorksheetsButton;
private JButton submitCellsButton;
private JButton submitListButton;
/** Starts the selection off with a spreadsheet feed helper. */
public ChooseSpreadsheetFrame(SpreadsheetService spreadsheetService) {
service = spreadsheetService;
factory = FeedURLFactory.getDefault();
initializeGui();
}
/**
* Gets the list of spreadsheets, and fills the list box.
*/
private void populateSpreadsheetList() {
if (retrieveSpreadsheetList()) {
fillSpreadsheetListBox();
}
}
/**
* Asks Google Spreadsheets for a list of all the spreadsheets
* the user has access to.
* @return true if successful
*/
private boolean retrieveSpreadsheetList() {
SpreadsheetFeed feed;
try {
feed = service.getFeed(
factory.getSpreadsheetsFeedUrl(), SpreadsheetFeed.class);
} catch (IOException e) {
SpreadsheetApiDemo.showErrorBox(e);
return false;
} catch (ServiceException e) {
SpreadsheetApiDemo.showErrorBox(e);
return false;
}
this.spreadsheetEntries = feed.getEntries();
return true;
}
/**
* Fills up the list-box of spreadsheets with the already-computed entries.
*/
private void fillSpreadsheetListBox() {
String[] stringsForListbox = new String[spreadsheetEntries.size()];
for (int i = 0; i < spreadsheetEntries.size(); i++) {
SpreadsheetEntry entry = spreadsheetEntries.get(i);
// Title of Spreadsheet (author, updated 2006-6-20 7:30PM)
stringsForListbox[i] =
entry.getTitle().getPlainText()
+ " (" + entry.getAuthors().get(0).getEmail()
+ ", updated " + entry.getUpdated().toUiString()
+ ")";
}
spreadsheetListBox.setListData(stringsForListbox);
}
/**
* Gets the list of worksheets in the specified spreadsheet,
* and fills the list box.
* @param spreadsheet the selected spreadsheet
*/
private void populateWorksheetList(SpreadsheetEntry spreadsheet) {
if (retrieveWorksheetList(spreadsheet)) {
fillWorksheetListBox(spreadsheet.getTitle().getPlainText());
}
}
/**
* Gets the list of worksheets from Google Spreadsheets.
* @param spreadsheet the spreadsheet to get a list of worksheets for
* @return true if successful
*/
private boolean retrieveWorksheetList(SpreadsheetEntry spreadsheet) {
WorksheetFeed feed;
try {
feed = service.getFeed(
spreadsheet.getWorksheetFeedUrl(), WorksheetFeed.class);
} catch (IOException e) {
SpreadsheetApiDemo.showErrorBox(e);
return false;
} catch (ServiceException e) {
SpreadsheetApiDemo.showErrorBox(e);
return false;
}
this.worksheetEntries = feed.getEntries();
return true;
}
/**
* Fills up the list-box of worksheets with the already computed entries.
*/
private void fillWorksheetListBox(String spreadsheetTitle) {
String[] stringsForListbox = new String[worksheetEntries.size()];
for (int i = 0; i < worksheetEntries.size(); i++) {
WorksheetEntry entry = worksheetEntries.get(i);
// Title Of Worksheet (T)
stringsForListbox[i] = entry.getTitle().getPlainText()
+ " (in " + spreadsheetTitle + ")";
}
worksheetListBox.setListData(stringsForListbox);
}
/**
* Handles when a user presses the "View Worksheets" button.
*
*/
private void handleViewWorksheetsButton() {
int selected = spreadsheetListBox.getSelectedIndex();
if (spreadsheetEntries != null && selected >= 0) {
populateWorksheetList(spreadsheetEntries.get(selected));
}
}
/**
* Handles when a user presses a "View Cells Demo" button.
*/
private void handleSubmitCellsButton() {
int selected = worksheetListBox.getSelectedIndex();
if (worksheetEntries != null && selected >= 0) {
CellBasedSpreadsheetPanel.createWindow(
service, worksheetEntries.get(selected).getCellFeedUrl());
}
}
/**
* Handles when a user presses a "View List Demo" button.
*/
private void handleSubmitListButton() {
int selected = worksheetListBox.getSelectedIndex();
if (worksheetEntries != null && selected >= 0) {
ListBasedSpreadsheetPanel.createWindow(service,
worksheetEntries.get(selected).getListFeedUrl());
}
}
/**
* Shows the feed URL's as you select spreadsheets.
*/
private void handleSpreadsheetSelection() {
int selected = spreadsheetListBox.getSelectedIndex();
if (spreadsheetEntries != null && selected >= 0) {
SpreadsheetEntry entry = spreadsheetEntries.get(selected);
ajaxLinkField.setText(
entry.getHtmlLink().getHref());
worksheetsFeedUrlField.setText(
entry.getWorksheetFeedUrl().toExternalForm());
}
}
/**
* Shows the feed URL's as you select worksheets within a spreadsheets.
*/
private void handleWorksheetSelection() {
int selected = worksheetListBox.getSelectedIndex();
if (worksheetEntries != null && selected >= 0) {
WorksheetEntry entry = worksheetEntries.get(selected);
cellsFeedUrlField.setText(entry.getCellFeedUrl().toExternalForm());
listFeedUrlField.setText(entry.getListFeedUrl().toExternalForm());
}
}
// ---- GUI code from here on down ----------------------------------------
private void initializeGui() {
setTitle("Choose your Spreadsheet");
Container panel = getContentPane();
panel.setLayout(new GridLayout(2, 1));
// Top part - choose a spreadsheet
JPanel spreadsheetPanel = new JPanel();
spreadsheetPanel.setLayout(new BorderLayout());
spreadsheetListBox = new JList();
spreadsheetPanel.add(new JScrollPane(spreadsheetListBox),
BorderLayout.CENTER);
spreadsheetListBox.addListSelectionListener(new ActionHandler());
Container topButtonsPanel = new JPanel();
topButtonsPanel.setLayout(new GridLayout(3, 1));
viewWorksheetsButton = new JButton("View Worksheets");
viewWorksheetsButton.addActionListener(new ActionHandler());
topButtonsPanel.add(viewWorksheetsButton);
panel.add(spreadsheetPanel);
ajaxLinkField = new JTextField();
ajaxLinkField.setEditable(false);
topButtonsPanel.add(ajaxLinkField);
worksheetsFeedUrlField = new JTextField();
worksheetsFeedUrlField.setEditable(false);
topButtonsPanel.add(worksheetsFeedUrlField);
spreadsheetPanel.add(topButtonsPanel, BorderLayout.SOUTH);
panel.add(spreadsheetPanel);
// Bottom part - choose a worksheet
JPanel worksheetPanel = new JPanel();
worksheetPanel.setLayout(new BorderLayout());
worksheetListBox = new JList(
new String[] { "[Please click 'View Worksheets' for a list.]" });
worksheetPanel.add(new JScrollPane(worksheetListBox), BorderLayout.CENTER);
worksheetListBox.addListSelectionListener(new ActionHandler());
Container bottomButtonsPanel = new JPanel();
bottomButtonsPanel.setLayout(new GridLayout(4, 1));
submitCellsButton = new JButton("Cells Demo");
submitCellsButton.addActionListener(new ActionHandler());
bottomButtonsPanel.add(submitCellsButton);
cellsFeedUrlField = new JTextField();
cellsFeedUrlField.setEditable(false);
bottomButtonsPanel.add(cellsFeedUrlField);
submitListButton = new JButton("List Demo");
submitListButton.addActionListener(new ActionHandler());
bottomButtonsPanel.add(submitListButton);
listFeedUrlField = new JTextField();
listFeedUrlField.setEditable(false);
bottomButtonsPanel.add(listFeedUrlField);
worksheetPanel.add(bottomButtonsPanel, BorderLayout.SOUTH);
panel.add(worksheetPanel);
populateSpreadsheetList();
pack();
setSize(700, 600);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private class ActionHandler
implements ActionListener, ListSelectionListener {
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == viewWorksheetsButton) {
handleViewWorksheetsButton();
} else if (ae.getSource() == submitCellsButton) {
handleSubmitCellsButton();
} else if (ae.getSource() == submitListButton) {
handleSubmitListButton();
}
}
public void valueChanged(ListSelectionEvent e) {
if (e.getSource() == spreadsheetListBox) {
handleSpreadsheetSelection();
} else if (e.getSource() == worksheetListBox) {
handleWorksheetSelection();
}
}
}
}
@@ -0,0 +1,530 @@
/* Copyright (c) 2008 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 sample.spreadsheet.gui;
import com.google.gdata.client.spreadsheet.ListQuery;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.TextContent;
import com.google.gdata.data.spreadsheet.CustomElementCollection;
import com.google.gdata.data.spreadsheet.ListEntry;
import com.google.gdata.data.spreadsheet.ListFeed;
import com.google.gdata.util.ServiceException;
import com.google.gdata.util.VersionConflictException;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.AbstractTableModel;
/**
* Widget for displaying and editing a spreadsheet.
*
* This is just for demonstrative purposes, it is not very featureful.
*
*
*/
public class ListBasedSpreadsheetPanel extends JPanel {
/** The Google Spreadsheets service. */
private SpreadsheetService service;
/** The list feed URL. */
private URL listFeedUrl;
/** The model that Swing uses to represent the table. */
private ListTableModel model;
/** The table widget. */
private JTable table;
private JButton refreshButton;
private JButton deleteOneButton;
private JButton revertOneButton;
private JButton commitOneButton;
private JButton commitAllButton;
private JTextField fulltextField;
private JTextField spreadsheetQueryField;
private JTextField orderbyField;
/**
* Creates a list-based spreadsheet editing panel.
* @param service the spreadsheet service
* @param listFeedUrl the URL of the list feed
*/
public ListBasedSpreadsheetPanel(
SpreadsheetService service, URL listFeedUrl) {
this.service = service;
this.listFeedUrl = listFeedUrl;
model = new ListTableModel();
initializeGui();
}
/**
* Refreshes the contents of the table, applying any queries the user
* specifies.
*/
private void refreshFromServer() {
try {
ListQuery query = new ListQuery(listFeedUrl);
if (!fulltextField.getText().equals("")) {
query.setFullTextQuery(fulltextField.getText());
}
if (!spreadsheetQueryField.getText().equals("")) {
query.setSpreadsheetQuery(spreadsheetQueryField.getText());
}
if (!orderbyField.getText().equals("")) {
query.setOrderBy(orderbyField.getText());
}
ListFeed feed = service.query(query, ListFeed.class);
model.resetEntries(feed.getEntries());
} catch (ServiceException e) {
SpreadsheetApiDemo.showErrorBox(e);
} catch (IOException e) {
SpreadsheetApiDemo.showErrorBox(e);
}
}
/**
* This class models one particular row in the list, tracking both its old
* contents and its new contents.
*
* This is responsible for the "commit/revert/delete" behavior that you
* see in the GUI.
*/
private class ListEntryModel {
/**
* The original entry downloaded.
* If this is an entry to add, originalEntry will be null.
*/
private ListEntry originalEntry = null;
/**
* The new contents to add.
* If this is not being edited, this will be null.
*/
private CustomElementCollection newContents = null;
/** Makes an existing row to be edited. */
public ListEntryModel(ListEntry originalEntry) {
this.originalEntry = originalEntry;
}
/** Creates a blank row to be edited. */
public ListEntryModel() {
}
/** Gets the visible contents of a particular column. */
public String getContents(String column) {
String result = null;
if (newContents != null) {
result = newContents.getValue(column);
} else if (originalEntry != null) {
result = originalEntry.getCustomElements().getValue(column);
}
if (result == null) {
result = "";
}
return result;
}
/** Gets whether this row neither has data nor is being edited. */
public boolean isBlank() {
return originalEntry == null && newContents == null;
}
/** Gets whether this row is oepn for edit. */
public boolean isBeingEdited() {
return newContents != null;
}
/** Open the row up for editing. */
public void startEdit() {
newContents = new CustomElementCollection();
if (originalEntry != null) {
newContents.replaceWithLocal(originalEntry.getCustomElements());
}
}
/** Sets the contents of a particular cell. */
public void setContents(String column, String newText) {
if (!isBeingEdited()) {
startEdit();
}
newContents.setValueLocal(column, newText);
}
/** Loses all changes. */
public void revert() {
newContents = null;
}
/** Actually adds this new entry to the spreadsheet. */
private void doAddNew() throws ServiceException, IOException {
ListEntry newEntry = new ListEntry();
newEntry.getCustomElements().replaceWithLocal(newContents);
originalEntry = service.insert(listFeedUrl, newEntry);
newContents = null;
}
/** Actually updates an existing entry on the spreadsheet,
* checking for edit conflicts. */
private void doUpdateExisting() throws ServiceException, IOException {
try {
originalEntry.getCustomElements().replaceWithLocal(newContents);
originalEntry = originalEntry.update();
newContents = null;
} catch (VersionConflictException e) {
originalEntry = originalEntry.getSelf();
TextContent content = (TextContent) originalEntry.getContent();
JOptionPane.showMessageDialog(null,
"Someone has edited the row in the meantime to:\n"
+ originalEntry.getTitle().getPlainText()
+ " (" + content.getContent().getPlainText() + ")\n"
+ "Commit again to confirm.",
"Version Conflict",
JOptionPane.WARNING_MESSAGE);
}
}
/** Commits all changes. */
public void commit() {
if (isBeingEdited()) {
boolean success = false;
try {
if (originalEntry != null) {
doUpdateExisting();
} else {
doAddNew();
}
success = true;
} catch (ServiceException e) {
SpreadsheetApiDemo.showErrorBox(e);
} catch (IOException e) {
SpreadsheetApiDemo.showErrorBox(e);
}
}
}
/** Deletes this entry from the backend, but not from the list. */
public void delete() {
if (originalEntry != null) {
try {
originalEntry.delete();
} catch (ServiceException e) {
SpreadsheetApiDemo.showErrorBox(e);
} catch (IOException e) {
SpreadsheetApiDemo.showErrorBox(e);
}
}
originalEntry = null;
newContents = null;
}
}
/**
* The Swing model for the spreadsheet.
*
* This is mostly GUI code.
*/
private class ListTableModel extends AbstractTableModel {
/** The name of each column (in the XML). */
private List<String> columnNames = new ArrayList<String>();
/** All entries of the list. */
private List<ListEntryModel> list = new ArrayList<ListEntryModel>();
/**
* Resets all the entries from a new list.
*
* This also tries to figure out what the set of valid columns is.
*/
public synchronized void resetEntries(List<ListEntry> entries) {
TreeSet<String> columnSet = new TreeSet<String>();
list.clear();
columnNames.clear();
for (ListEntry entry : entries) {
list.add(new ListEntryModel(entry));
columnSet.addAll(entry.getCustomElements().getTags());
}
// Always have an empty row to edit.
list.add(new ListEntryModel());
columnNames.add("(Edit)");
columnNames.addAll(columnSet);
fireTableStructureChanged();
fireTableDataChanged();
}
/** Writes back all modified entries to the actual spreadsheet. */
public synchronized void commitAll() {
for (ListEntryModel entryModel : list) {
entryModel.commit();
}
fireTableDataChanged();
}
/** Reverts all entries, losing all changes. */
public synchronized void revertAll() {
for (ListEntryModel entryModel : list) {
entryModel.revert();
}
fireTableDataChanged();
}
/** Delete one entry by index. */
public synchronized void deleteOne(int row) {
if (!list.get(row).isBeingEdited()) {
list.get(row).delete();
list.remove(row);
fireTableRowsDeleted(row, row);
}
}
/** Commit one entry by index. */
public synchronized void commitOne(int row) {
if (row >= 0 && row < list.size()) {
if (list.get(row).isBeingEdited()) {
list.get(row).commit();
fireTableRowsUpdated(row, row);
}
}
}
/** Revert one entry by index. */
public synchronized void revertOne(int row) {
if (list.get(row).isBeingEdited()) {
list.get(row).revert();
fireTableRowsUpdated(row, row);
}
}
/** Gets whether this is the special column. */
private boolean isSpecialColumn(int col) {
return col == 0;
}
/**
* Implements the Swing method for handling cell edits.
*/
public synchronized void setValueAt(Object value, int row, int col) {
ListEntryModel entryModel = list.get(row);
if (isSpecialColumn(col)) {
setRowEditing(row, ((Boolean) value).booleanValue());
} else {
setRowEditing(row, true);
entryModel.setContents(columnNames.get(col), value.toString());
fireTableCellUpdated(row, col);
}
}
/** Sets whether a row is being edited. */
private void setRowEditing(int row, boolean edit) {
ListEntryModel entryModel = list.get(row);
if (edit && !entryModel.isBeingEdited()) {
if (entryModel.isBlank()) {
// Always have at least two blank rows.
list.add(new ListEntryModel());
fireTableRowsInserted(list.size() - 1, list.size() - 1);
}
entryModel.startEdit();
fireTableRowsUpdated(row, row);
} else if (!edit) {
commitOne(row);
}
}
/** Tells Swing the value at a particular location. */
public synchronized Object getValueAt(int row, int col) {
ListEntryModel entryModel = list.get(row);
if (isSpecialColumn(col)) {
return Boolean.valueOf(entryModel.isBeingEdited());
} else {
return entryModel.getContents(columnNames.get(col));
}
}
/** Tells Swing whether the cell is editable. */
public synchronized boolean isCellEditable(int row, int col) {
return true;
}
/** Gets the column name by index. */
public synchronized String getColumnName(int columnIndex) {
return columnNames.get(columnIndex);
}
/** Gets the column class for editing. */
public synchronized Class<?> getColumnClass(int columnIndex) {
if (isSpecialColumn(columnIndex)) {
return Boolean.class;
} else {
return String.class;
}
}
/** Tells Swing how many rows are in this table. */
public synchronized int getRowCount() {
return list.size();
}
/** Tells Swing how many columns are in this table. */
public synchronized int getColumnCount() {
return columnNames.size();
}
}
// GUI code
public static JFrame createWindow(SpreadsheetService service,
URL listFeedUrl) {
JFrame frame = new JFrame();
frame.setSize(600, 480);
frame.getContentPane().add(new ListBasedSpreadsheetPanel(
service, listFeedUrl));
frame.setVisible(true);
frame.setTitle("List Demo - Row-based Editing");
return frame;
}
private void initializeGui() {
table = new JTable(model);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
JScrollPane scrollpane = new JScrollPane(table);
setLayout(new BorderLayout());
add(scrollpane, BorderLayout.CENTER);
Container southPanel = new JPanel();
southPanel.setLayout(new GridBagLayout());
deleteOneButton = new JButton("Delete");
deleteOneButton.addActionListener(new ActionHandler());
southPanel.add(deleteOneButton, getTopConstraints(0));
revertOneButton = new JButton("Revert");
revertOneButton.addActionListener(new ActionHandler());
southPanel.add(revertOneButton, getTopConstraints(1));
commitOneButton = new JButton("Commit");
commitOneButton.addActionListener(new ActionHandler());
southPanel.add(commitOneButton, getTopConstraints(2));
commitAllButton = new JButton("Commit All");
commitAllButton.addActionListener(new ActionHandler());
southPanel.add(commitAllButton, getTopConstraints(3));
refreshButton = new JButton("Refresh");
refreshButton.addActionListener(new ActionHandler());
southPanel.add(refreshButton, getTopConstraints(4));
southPanel.add(new JLabel("Full text:"), getLeftConstraints(1));
fulltextField = new JTextField();
southPanel.add(fulltextField, getRightConstraints(1));
southPanel.add(new JLabel("Structured:"), getLeftConstraints(2));
spreadsheetQueryField = new JTextField();
southPanel.add(spreadsheetQueryField, getRightConstraints(2));
southPanel.add(new JLabel("Order By:"), getLeftConstraints(3));
orderbyField = new JTextField();
southPanel.add(orderbyField, getRightConstraints(3));
add(southPanel, BorderLayout.SOUTH);
refreshFromServer();
}
private GridBagConstraints getTopConstraints(int col) {
GridBagConstraints c = new GridBagConstraints();
c.gridy = 0;
c.gridx = col;
c.fill = GridBagConstraints.HORIZONTAL;
return c;
}
private GridBagConstraints getLeftConstraints(int row) {
GridBagConstraints c = new GridBagConstraints();
c.gridy = row;
c.gridx = 0;
c.fill = GridBagConstraints.HORIZONTAL;
return c;
}
private GridBagConstraints getRightConstraints(int row) {
GridBagConstraints c = new GridBagConstraints();
c.gridy = row;
c.gridx = 1;
c.gridwidth = 4;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1.0; // take up as much space as possible
return c;
}
private class ActionHandler implements ActionListener {
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == refreshButton) {
refreshFromServer();
} else if (ae.getSource() == deleteOneButton) {
model.deleteOne(table.getSelectedRow());
} else if (ae.getSource() == revertOneButton) {
model.revertOne(table.getSelectedRow());
} else if (ae.getSource() == commitOneButton) {
model.commitOne(table.getSelectedRow());
} else if (ae.getSource() == commitAllButton) {
model.commitAll();
}
}
}
}
@@ -0,0 +1,129 @@
/* Copyright (c) 2008 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 sample.spreadsheet.gui;
import com.google.gdata.client.spreadsheet.ListQuery;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.spreadsheet.ListEntry;
import com.google.gdata.data.spreadsheet.ListFeed;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.net.URL;
import java.util.List;
/**
* This class helps you access your spreadsheet like a list or like a
* database.
*
*
* In this model, each row is treated like a separate entry, with multiple
* fields. Each field is named based on the top row of your speradsheet.
*
*
*/
public class ListFeedHelper {
/** The SpreadsheetService to contact Google with. */
private SpreadsheetService service;
/** List feed URL. */
private URL feedUrl;
/**
* Creates a list feed helper for a particular URL.
*
* @param inService the SpreadsheetService to contact Google with
* @param inFeedUrl the URL of the list feed; to get this URL, you can
* use SpreadsheetFeedHelper, or if you have a WorksheetEntry
* you can use its method to get the list feed URL
*/
public ListFeedHelper(SpreadsheetService inService, URL inFeedUrl) {
service = inService;
feedUrl = inFeedUrl;
}
/**
* Adds a new list entry to the spreadsheet.
*
* @param entry the new entry
* @throws IOException if there was a problem contacting Google
* @throws ServiceException if there was an error processnig the request
*/
public ListEntry addListEntry(ListEntry entry)
throws IOException, ServiceException {
return service.insert(feedUrl, entry);
}
/**
* Gets a list of all the list entries.
*
* @return a list of all non-empty rows in the spreadsheet
* @throws IOException if there was a problem contacting Google
* @throws ServiceException if there was an error processnig the request
*/
public List<ListEntry> getAllListEntries()
throws IOException, ServiceException {
ListQuery query = new ListQuery(feedUrl);
ListFeed feed = service.query(query, ListFeed.class);
return feed.getEntries();
}
/**
* Gets a list of all entries that match a full-text search.
*
* Full-text searches look for the keywords you specify, that may
* occur in any order in the row. Right now only the simplest syntax
* is supported, as a convenience feature.
*
* @param search the search string like "adam technical writer"
* @return all matching entries
* @throws IOException if there was a problem contacting Google
* @throws ServiceException if there was an error processnig the request
*/
public List<ListEntry> getFullTextSearch(String search)
throws IOException, ServiceException {
ListQuery query = new ListQuery(feedUrl);
query.setFullTextQuery(search);
ListFeed feed = service.query(query, ListFeed.class);
return feed.getEntries();
}
/**
* Gets a list of all entries that match a structured query.
*
* Structured queries are in format:
* name = 'adam' and (job = 'technical writer' or job = 'artist')
*
* In short, it is case-insensitive, supporting both SQL-like and
* C-like syntaxes for all varieties of new and seasoned programmers.
*
* @param structuredQuery the search string
* @return all matching entries
* @throws IOException if there was a problem contacting Google
* @throws ServiceException if there was an error processnig the request
*/
public List<ListEntry> getStructuredQuery(
String structuredQuery)
throws IOException, ServiceException {
ListQuery query = new ListQuery(feedUrl);
query.setFullTextQuery(structuredQuery);
ListFeed feed = service.query(query, ListFeed.class);
return feed.getEntries();
}
}
@@ -0,0 +1,189 @@
/* Copyright (c) 2008 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 sample.spreadsheet.gui;
import com.google.gdata.client.GoogleService.CaptchaRequiredException;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.util.AuthenticationException;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
/**
* A Swing window for logging in to Google Spreadsheets.
*
*
*/
public class LoginFrame extends JFrame {
/** The spreadsheet service. */
private SpreadsheetService service;
/** Field for entering username. */
private JTextField usernameField;
/** Field for entering password. */
private JPasswordField passwordField;
/** Image to display as a CAPTCHA (distorted letters to verify human). */
private JLabel captchaImage;
/** Place where user types the captcha answer. */
private JTextField captchaAnswerField;
/** Button to log in. */
private JButton submitButton;
/**
* The captcha token that is issued,
* null if there was no CAPTCHA challenge.
*/
private String captchaToken = null;
/**
* Starts out the login window, for a particular service and
* feed root, with initial username and password (these can
* be blank strings).
*/
public LoginFrame(SpreadsheetService service,
String username, String password) {
this.service = service;
initializeGui();
usernameField.setText(username);
passwordField.setText(password);
}
/**
* Try authenticating the user with the provided username and
* password.
*/
private boolean authenticate(
String username, String password) {
try {
if (captchaToken == null) {
// No CAPTCHA challenge was presented.
// Proceed to the next step.
service.setUserCredentials(username, password);
} else {
// Use the CAPTCHA token and answer to help the
// authentication.
service.setUserCredentials(username, password, captchaToken,
captchaAnswerField.getText());
}
return true;
} catch (CaptchaRequiredException e) {
// Get the CAPTCHA token and display the image.
captchaToken = e.getCaptchaToken();
try {
captchaImage.setIcon(new ImageIcon(new URL(e.getCaptchaUrl())));
captchaAnswerField.setText("(Please write the above letters here)");
} catch (IOException ioe) {
captchaImage.setText("(Error parsing captcha image URL)");
}
return false;
} catch (AuthenticationException e) {
SpreadsheetApiDemo.showErrorBox(e);
return false;
}
}
/**
* Handles the submit button being pressed.
*/
private void handleSubmitButton() {
String username = usernameField.getText();
String password = new String(passwordField.getPassword());
if (authenticate(username, password)) {
new ChooseSpreadsheetFrame(service);
dispose();
}
}
// ---- GUI code from here on down ----------------------------------------
/**
* Handles all clicks.
*/
private class ActionHandler implements ActionListener {
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == submitButton) {
handleSubmitButton();
}
}
}
/**
* Initializes all the GUI widgets.
*/
private void initializeGui() {
setTitle("Log in to Google Spreadsheets");
Container panel = getContentPane();
panel.setLayout(new BorderLayout());
JPanel topPanel = new JPanel();
topPanel.setLayout(new GridLayout(4, 1));
topPanel.add(new JLabel("Log in to Google Spreadsheets!"));
usernameField = new JTextField();
topPanel.add(usernameField);
passwordField = new JPasswordField();
topPanel.add(passwordField);
submitButton = new JButton("Log in!");
submitButton.addActionListener(new ActionHandler());
topPanel.add(submitButton);
panel.add(topPanel, BorderLayout.NORTH);
captchaImage = new JLabel("(A CAPTCHA may appear here)",
SwingConstants.CENTER);
panel.add(captchaImage, BorderLayout.CENTER);
captchaAnswerField = new JTextField();
captchaAnswerField.setText("(type captcha answer here)");
panel.add(captchaAnswerField, BorderLayout.SOUTH);
setSize(300, 240);
setVisible(true);
}
}
@@ -0,0 +1,24 @@
Google Spreadsheets data API Java Sample - README.txt
-----------------------------------------------------
This is a fairly complete example that shows a possible application of the
Google Spreadsheets Data API. This example shows how to handle the login
process (including CAPTCHA), how to select a spreadsheet and/or worksheet,
and a possible interface for manipulating the spreadsheet.
This example might be good for experimenting, but is harder to understand.
For a more down-to-earth example, see the cell or list demo.
This can be built an run with Ant:
1. Edit gdata/java/build-samples/build.properties with your Google Account
username, password, and a URL to your Google spreadsheet
(in the format ....spreadsheets.google.com/ccc?id=...)
2. Run the Ant rule:
ant -f gdata/java/build-samples.xml sample.spreadsheet.guidemo.run
Alternately, you can compile and run it from the command line:
java sample.spreadsheet.gui.GuiDemo
@@ -0,0 +1,74 @@
/* Copyright (c) 2008 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 sample.spreadsheet.gui;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import javax.swing.JOptionPane;
/**
* Runs the spreadsheets GUI API demo.
*/
public final class SpreadsheetApiDemo {
/** Prevents instantiation. */
private SpreadsheetApiDemo() {
}
/**
* Runs the demo.
*
* @param args IGNORED
*/
public static void main(String[] args) {
new LoginFrame(new SpreadsheetService("SpreadsheetApiDemo-1"),
"(username)", "");
}
/**
* Shows a pop-up dialog box alerting the user of an error.
*
* @param e the exception
*/
public static void showErrorBox(Exception e) {
if (e instanceof IOException) {
JOptionPane.showMessageDialog(null,
"There was an error contacting Google: " + e.getMessage(),
"Error contacting Google",
JOptionPane.ERROR_MESSAGE);
} else if (e instanceof AuthenticationException) {
JOptionPane.showMessageDialog(null,
"Your username and/or password were rejected: " + e.getMessage(),
"Authentication Error",
JOptionPane.ERROR_MESSAGE);
} else if (e instanceof ServiceException) {
JOptionPane.showMessageDialog(null,
"Google returned the error: " + e.getMessage(),
"Google had an error processing the request",
JOptionPane.ERROR_MESSAGE);
} else {
JOptionPane.showMessageDialog(null,
"There was an unexpected error: " + e.getMessage(),
"Unexpected error",
JOptionPane.ERROR_MESSAGE);
}
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,554 @@
/* Copyright (c) 2008 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 sample.spreadsheet.list;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.ListQuery;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.spreadsheet.ListEntry;
import com.google.gdata.data.spreadsheet.ListFeed;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.data.spreadsheet.WorksheetEntry;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* An application to show the basic operations of the List feed.
*
*
*/
public class ListDemo {
/** The message for displaying the usage parameters. */
private static final String[] USAGE_MESSAGE = {
"Usage: java ListDemo --username [user] --password [pass] ", ""};
/** Help on setting up this demo. */
private static final String[] WELCOME_MESSAGE = {
"Using this demo, you can see how rows can be conveniently inserted,",
"queried, and deleted, almost like a user-friendly database.", "",
"Before starting this demo, make sure you create a spreadsheet. In the",
"top row, put headers, such as 'Name', 'Day', 'Address', or any other",
"important piece of information. A good example might be:", "",
" Name Day Phone", " Rosa Tue 555-1212",
" Vladimir Wed 555-3137", " Sanjay Thu 555-2127",
" Ejike Fri 555-4444", "",
"It is best practices to freeze the top row, in the 'Sorting' tab.",
"This way, sorting will make sure the top row stays intact. We",
"suggest you leave your browser open while trying this out.", "",
"It is important to know each row is identified by GData by a",
"random-looking string like 'czhdp', which stays the same forever,",
"even if the row is moved or changed. This type of identifier",
"is used throughout this demo. ", ""};
/** Help on all available commands. */
private static final String[] COMMAND_HELP_MESSAGE = {
"Commands:",
" load [[select a spreadsheet and worksheet]]",
" list [[shows all entries]]",
" reverse [[shows all entries in reverse order]]",
" add name=Rosie,day=Tue [[adds an entry]]",
" delete <id> [[deletes; use 'list' first]]",
" update <id> day=Wed [[modifies]",
" search Rosie Tue [[full-text search]]",
" query name = 'Rosie' [[structured query]]",
" exit"};
/** Our view of Google Spreadsheets as an authenticated Google user. */
private SpreadsheetService service;
/** The URL of the list feed for the selected spreadsheet. */
private URL listFeedUrl;
/** A factory that generates the appropriate feed URLs. */
private FeedURLFactory factory;
/** The output stream to use. */
private PrintStream out;
/**
* Caches entries.
*
* In this example, every entry we display to the user is cached. We do this
* because Google Data has a feature where if an entry is updated between the
* time you download it and update or delete it, you will be alerted of the
* edit. For example:
*
* 1. In this sample app, I look at the row for Rosie, with age 26. 2. Someone
* editing the spreadsheet changes Rosie's age to 29 3. In this sample app, I
* try to change Rosie's age to 24
*
* By caching the entry and updating the last entry, I am telling the server
* that I am updating the age from 26 to 24. The server now has enough
* information to tell me that the age has already been changed, because the
* version ID that I am sending was the version ID for age 26.
*
* If you do not wish to cache entries, an alternative is to fetch the proper
* entry ID from Google Data, update that fresh entry, and post. In that case,
* no caching is necessary, and a version conflict is less likely. On the
* other hand, you won't get alerted if someone else has changed the entry in
* the meantime.
*
* This would be achieved by getting an entry: ListEntry freshEntry=
* service.getEntry( new URL(listFeedUrl.toString() + "/" + id),
* ListEntry.class) (update freshEntry's fields) freshEntry.update();
*/
private Map<String, ListEntry> entriesCached;
/**
* Starts up the demo with the specified service.
*
* @param service the connection to the Google Spradsheets service.
* @param outputStream a handle for stdout.
*/
public ListDemo(SpreadsheetService service, PrintStream outputStream) {
this.out = outputStream;
this.service = service;
this.factory = FeedURLFactory.getDefault();
this.entriesCached = new HashMap<String, ListEntry>();
}
/**
* Log in to Google, under a Google Spreadsheets account.
*
* @param username name of user to authenticate (e.g. yourname@gmail.com)
* @param password password to use for authentication
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public void login(String username, String password)
throws AuthenticationException {
// Authenticate
service.setUserCredentials(username, password);
}
/**
* Parses a list of the format "name=Fred,age=20,friend=Wilma", and sets the
* corresponding values in the list entry.
*
* Values that are not specified are left alone. That is, if the entry already
* contains "haircolor=black", then setting name, age, and friend will retain
* the haircolor as black.
*
* @param entryToChange the entry to change based on the parameters
* @param nameValuePairs the list of name/value pairs, containing the name of
* the title (in lowercase with all invalid characters removed), .
*/
public void setEntryContentsFromString(ListEntry entryToChange,
String nameValuePairs) {
// Split first by the commas between the different fields.
for (String nameValuePair : nameValuePairs.split(",")) {
// Then, split by the equal sign.
String[] parts = nameValuePair.split("=", 2);
String tag = parts[0]; // such as "name"
String value = parts[1]; // such as "Fred"
entryToChange.getCustomElements().setValueLocal(tag, value);
}
}
/**
* Adds a new list entry, based on the user-specified name value pairs.
*
* @param nameValuePairs pairs such as "name=Rosa,phone=555-1212"
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void addNewEntry(String nameValuePairs) throws IOException,
ServiceException {
ListEntry newEntry = new ListEntry();
setEntryContentsFromString(newEntry, nameValuePairs);
service.insert(listFeedUrl, newEntry);
out.println("Added!");
}
/**
* Prints the entire list entry, in a way that mildly resembles what the
* actual XML looks like.
*
* In addition, all printed entries are cached here. This way, they can be
* updated or deleted, without having to retrieve the version identifier again
* from the server.
*
* @param entry the list entry to print
*/
public void printAndCacheEntry(ListEntry entry) {
// We only care about the entry id, chop off the leftmost part.
// I.E., this turns http://spreadsheets.google.com/..../cpzh6 into cpzh6.
String id = entry.getId().substring(entry.getId().lastIndexOf('/') + 1);
// Cache all displayed entries so that they can be updated later.
entriesCached.put(id, entry);
out.println("-- id: " + id + " title: " + entry.getTitle().getPlainText());
for (String tag : entry.getCustomElements().getTags()) {
out.println(" <gsx:" + tag + ">"
+ entry.getCustomElements().getValue(tag) + "</gsx:" + tag + ">");
}
}
/**
* Displays the given list of entries and prompts the user to select the index
* of one of the entries. NOTE: The displayed index is 1-based and is
* converted to 0-based before being returned.
*
* @param reader to read input from the keyboard
* @param entries the list of entries to display
* @param type describes the tyoe of things the list contains
* @return the 0-based index of the user's selection
* @throws IOException if an I/O error occurs while getting input from user
*/
private int getIndexFromUser(BufferedReader reader, List entries, String type)
throws IOException {
for (int i = 0; i < entries.size(); i++) {
BaseEntry entry = (BaseEntry) entries.get(i);
System.out.println("\t(" + (i + 1) + ") "
+ entry.getTitle().getPlainText());
}
int index = -1;
while (true) {
out.print("Enter the number of the spreadsheet to load: ");
String userInput = reader.readLine();
try {
index = Integer.parseInt(userInput);
if (index < 1 || index > entries.size()) {
throw new NumberFormatException();
}
break;
} catch (NumberFormatException e) {
System.out.println("Please enter a valid number for your selection.");
}
}
return index - 1;
}
/**
* Uses the user's creadentials to get a list of spreadsheets. Then asks the
* user which spreadsheet to load. If the selected spreadsheet has multiple
* worksheets then the user will also be prompted to select what sheet to use.
*
* @param reader to read input from the keyboard
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*
*/
public void loadSheet(BufferedReader reader) throws IOException,
ServiceException {
// Get the spreadsheet to load
SpreadsheetFeed feed = service.getFeed(factory.getSpreadsheetsFeedUrl(),
SpreadsheetFeed.class);
List spreadsheets = feed.getEntries();
int spreadsheetIndex = getIndexFromUser(reader, spreadsheets,
"spreadsheet");
SpreadsheetEntry spreadsheet = (SpreadsheetEntry) spreadsheets
.get(spreadsheetIndex);
// Get the worksheet to load
if (spreadsheet.getWorksheets().size() == 1) {
listFeedUrl = spreadsheet.getWorksheets().get(0).getListFeedUrl();
} else {
List worksheets = spreadsheet.getWorksheets();
int worksheetIndex = getIndexFromUser(reader, worksheets, "worksheet");
WorksheetEntry worksheet = (WorksheetEntry) worksheets
.get(worksheetIndex);
listFeedUrl = worksheet.getListFeedUrl();
}
System.out.println("Sheet loaded.");
}
/**
* Lists all rows in the spreadsheet.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void listAllEntries() throws IOException, ServiceException {
ListFeed feed = service.getFeed(listFeedUrl, ListFeed.class);
for (ListEntry entry : feed.getEntries()) {
printAndCacheEntry(entry);
}
}
/**
* Lists all rows in the spreadsheet in reverse order.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void reverseAllEntries() throws IOException, ServiceException {
ListQuery query = new ListQuery(listFeedUrl);
query.setReverse(true);
ListFeed feed = service.query(query, ListFeed.class);
for (ListEntry entry : feed.getEntries()) {
printAndCacheEntry(entry);
}
}
/**
* Searches rows with a full text search string, finding any rows that match
* all the given words.
*
* @param fullTextSearchString a string like "Rosa 555" will look for the
* substrings Rosa and 555 to appear anywhere in the row
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void search(String fullTextSearchString) throws IOException,
ServiceException {
ListQuery query = new ListQuery(listFeedUrl);
query.setFullTextQuery(fullTextSearchString);
ListFeed feed = service.query(query, ListFeed.class);
out.println("Results for [" + fullTextSearchString + "]");
for (ListEntry entry : feed.getEntries()) {
printAndCacheEntry(entry);
}
}
/**
* Performs a full database-like query on the rows.
*
* @param structuredQuery a query like: name = "Bob" and phone != "555-1212"
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void query(String structuredQuery) throws IOException,
ServiceException {
ListQuery query = new ListQuery(listFeedUrl);
query.setSpreadsheetQuery(structuredQuery);
ListFeed feed = service.query(query, ListFeed.class);
out.println("Results for [" + structuredQuery + "]");
for (ListEntry entry : feed.getEntries()) {
printAndCacheEntry(entry);
}
}
/**
* Deletes an entry by the ID.
*
* This looks up the old cached row so that the version ID is known. A version
* ID is used by GData to avoid edit collisions, so that you know if someone
* has changed the row before you delete it.
*
* For this reason, the cached version of the row, as you last saw it, is
* kept, instead of querying the entry anew.
*
* @param idToDelete the ID of the row to delete such as "cph6n"
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void delete(String idToDelete) throws IOException, ServiceException {
ListEntry entry = entriesCached.get(idToDelete); // Find the entry to
// delete
if (entry != null) {
entry.delete(); // This deletes the existing entry.
out.println("Deleted!");
} else {
out.println("I don't know that ID.");
out.println("In GData, you must get an entry before deleting it,");
out.println("so that you have the version ID.");
out.println("You might have to 'list' first.");
}
}
/**
* Updates an existing entry.
*
* See the comment in {@code delete} for why the entry is cached in a hash
* map.
*
* @param id the ID of the row to update
* @param nameValuePairs the name value pairs, such as "name=Rosa" to change
* the row's name field to Rosa
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void update(String id, String nameValuePairs) throws IOException,
ServiceException {
// The next line of code finds the entry to update.
// See the javadoc on entriesCached.
ListEntry entry = entriesCached.get(id);
setEntryContentsFromString(entry, nameValuePairs);
if (entry != null) {
entry.update(); // This updates the existing entry.
out.println("Updated!");
} else {
out.println("I don't know that ID.");
out.println("In GData, you must get an entry before deleting it.");
out.println("You might have to 'list' first.");
}
}
/**
* Parses and executes a command.
*
* @param reader to read input from the keyboard
* @return false if the user quits, true on exception
*/
public boolean executeCommand(BufferedReader reader) {
for (String s : COMMAND_HELP_MESSAGE) {
out.println(s);
}
System.err.print("Command: ");
try {
String command = reader.readLine();
String[] parts = command.trim().split(" ", 2);
String name = parts[0];
String parameters = parts.length > 1 ? parts[1] : "";
if (name.equals("add")) {
addNewEntry(parameters);
} else if (name.equals("load")) {
loadSheet(reader);
} else if (name.equals("list")) {
listAllEntries();
} else if (name.equals("reverse")) {
reverseAllEntries();
} else if (name.equals("search")) {
search(parameters);
} else if (name.equals("query")) {
query(parameters);
} else if (name.equals("delete")) {
delete(parameters);
} else if (name.equals("update")) {
String[] split = parameters.split(" ", 2);
update(split[0], split[1]);
} else if (name.startsWith("q") || name.startsWith("exit")) {
return false;
} else {
out.println("Unknown command.");
}
} catch (ServiceException se) {
// Show *exactly* what went wrong.
se.printStackTrace();
} catch (IOException ioe) {
// Show *exactly* what went wrong.
ioe.printStackTrace();
}
return true;
}
/**
* Starts up the demo and prompts for commands.
*
* @param username name of user to authenticate (e.g. yourname@gmail.com)
* @param password password to use for authentication
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public void run(String username, String password)
throws AuthenticationException {
for (String s : WELCOME_MESSAGE) {
out.println(s);
}
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
// Login and prompt the user to pick a sheet to use.
login(username, password);
try {
loadSheet(reader);
} catch (Exception e) {
e.printStackTrace();
}
while (executeCommand(reader)) {
}
}
/**
* Runs the demo.
*
* @param args the command-line arguments
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public static void main(String[] args) throws AuthenticationException {
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
String username = parser.getValue("username", "user", "u");
String password = parser.getValue("password", "pass", "p");
boolean help = parser.containsKey("help", "h");
if (help || username == null || password == null) {
usage();
System.exit(1);
}
ListDemo demo = new ListDemo(new SpreadsheetService("List Demo"),
System.out);
demo.run(username, password);
}
/**
* Prints out the usage.
*/
private static void usage() {
for (String s : USAGE_MESSAGE) {
System.out.println(s);
}
for (String s : WELCOME_MESSAGE) {
System.out.println(s);
}
}
}
@@ -0,0 +1,36 @@
Google Spreadsheets data API Java Sample - README.txt
-----------------------------------------------------
This is a very simple Java example of how the API can be used on a
Google spreadsheet to add, remove, and modify rows like a data table.
Before starting this demo, make sure you create a spreadsheet. In
the top row, put headers, such as 'Name', 'Day', 'Address', or any
other important piece of information. A good example might be:
Name Day Phone
Rosa Tue 555-1212
Vladimir Wed 555-3137
Sanjay Thu 555-2127
Ejike Fri 555-4444
It is best practices to freeze the top row, in the 'Sorting' tab.
This way, sorting will make sure the top row stays intact. We
suggest you leave your browser open while trying this out.
This can be built an run with Ant:
1. Edit gdata/java/build-samples/build.properties with your Google Account
username, password, and a URL to your Google spreadsheet.
(in the format ....spreadsheets.google.com/ccc?id=...)
2. Run the Ant rule:
ant -f gdata/java/build-samples.xml sample.spreadsheet.list.run
Alternately, you can compile and run it from the command line:
java sample.list.ListDemo
--username [user]
--password [pass]
@@ -0,0 +1,38 @@
Google Spreadsheets data API Java Sample - README.txt
-----------------------------------------------------
This is a very simple Java example of how the API can be used on a
Google spreadsheet to create record objects and add them to a table object.
The records can be updated, deleted and queried based on their contents.
Before starting this demo, make sure you create a spreadsheet with a table.
You can create a table object using the TableDemo. The demo will prompt you
to choose a table to add records to.
An example table might look like:
Name Day Phone
Example records might look like:
Rosa Tue 555-1212,
Vladimir Wed 555-3137,
Sanjay Thu 555-2127,
Ejike Fri 555-4444.
We suggest you leave your browser open while trying this out.
This can be built and run with Ant:
// TODO down here.
1. Edit gdata/java/build-samples/build.properties with your Google Account
username and password.
2. Run the Ant rule:
ant -f gdata/java/build-samples.xml sample.spreadsheet.list.run
Alternately, you can compile and run it from the command line:
java sample.list.RecordDemo
--username [user]
--password [pass]
@@ -0,0 +1,644 @@
/* Copyright (c) 2008 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 sample.spreadsheet.record;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.RecordQuery;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.spreadsheet.Column;
import com.google.gdata.data.spreadsheet.Data;
import com.google.gdata.data.spreadsheet.Field;
import com.google.gdata.data.spreadsheet.RecordEntry;
import com.google.gdata.data.spreadsheet.RecordFeed;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.data.spreadsheet.TableEntry;
import com.google.gdata.data.spreadsheet.TableFeed;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* An application to show the basic operations of the Record feed.
*
*
*/
public class RecordDemo {
/** The message for displaying the usage parameters. */
private static final String[] USAGE_MESSAGE = {
"Usage: java RecordDemo --username [user] --password [pass] ", ""};
/** Help on setting up this demo. */
private static final String[] WELCOME_MESSAGE = {
"Using this demo, you can see how records can be conveniently inserted,",
"queried, and deleted, into a table.", "",
"Before starting this demo, make sure you create a spreadsheet and add ",
"at least one table to it. You can create tables by using the ",
"TableDemo. ",
"This demo will help you create records and insert them into an ",
"existing table.",
"An example table might look like:", "",
" Name Day Phone", "",
"The example records might look like: ",
" Rosa Tue 555-1212",
" Vladimir Wed 555-3137",
" Sanjay Thu 555-2127",
" Ejike Fri 555-4444", "",
"We suggest you leave your browser open while trying this out.", "",
"It is important to know each record is identified by GData by a",
"random-looking string like 'czhdp', which stays the same forever,",
"even if the row is moved or changed. This type of identifier",
"is used throughout this demo. ", ""};
/** Help on all available commands. */
private static final String[] COMMAND_HELP_MESSAGE = {
"Commands:",
" load [[select a spreadsheet and worksheet]]",
" listtables [[list all tables in the sheet]] ",
" table <tableid> [[select a table to create a record feed from]]",
" list [[shows all entries]]",
" reverse [[shows all entries in reverse order]]",
" add name=Rosie,day=Tue [[adds an entry]]",
" delete <recordid> [[deletes; use 'list' first]]",
" update <recordid> day=Wed [[modifies]",
" search Rosie Tue [[full-text search]]",
" query name=Rosie [[structured query]]",
" exit"};
/** Our view of Google Spreadsheets as an authenticated Google user. */
private SpreadsheetService service;
/** The URL of the record feed for the selected spreadsheet. */
private URL recordsFeedUrl;
/** The URL of the table feed for the selected spreadsheet. */
private URL tablesFeedUrl;
/** Base url of the spreadsheet to use to construct the record feed url. */
private String baseUrl;
/** Spreadsheet key of the loaded sheet. */
private String spreadsheetKey;
/** Table id to use to construct the record feed. */
private int tableId;
/** A factory that generates the appropriate feed URLs. */
private FeedURLFactory factory;
/** The output stream to use. */
private PrintStream out;
/**
* Caches entries.
*
* In this example, every entry we display to the user is cached. We do this
* because Google Data has a feature where if an entry is updated between the
* time you download it and update or delete it, you will be alerted of the
* edit. For example:
*
* 1. In this sample app, I look at the row for Rosie, with age 26. 2. Someone
* editing the spreadsheet changes Rosie's age to 29 3. In this sample app, I
* try to change Rosie's age to 24
*
* By caching the entry and updating the last entry, I am telling the server
* that I am updating the age from 26 to 24. The server now has enough
* information to tell me that the age has already been changed, because the
* version ID that I am sending was the version ID for age 26.
*
* If you do not wish to cache entries, an alternative is to fetch the proper
* entry ID from Google Data, update that fresh entry, and post. In that case,
* no caching is necessary, and a version conflict is less likely. On the
* other hand, you won't get alerted if someone else has changed the entry in
* the meantime.
*
* This would be achieved by getting an entry: RecordEntry freshEntry=
* service.getEntry( new URL(recordsFeedUrl.toString() + "/" + id),
* RecordEntry.class) (update freshEntry's fields) freshEntry.update();
*/
private Map<String, RecordEntry> entriesCached;
/**
* Starts up the demo with the specified service.
*
* @param service the connection to the Google Spreadsheets service.
* @param outputStream a handle for stdout.
*/
public RecordDemo(SpreadsheetService service, PrintStream outputStream) {
this.out = outputStream;
this.service = service;
this.factory = FeedURLFactory.getDefault();
this.entriesCached = new HashMap<String, RecordEntry>();
}
/**
* Log in to Google, under a Google Spreadsheets account.
*
* @param username name of user to authenticate (e.g. yourname@gmail.com)
* @param password password to use for authentication
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public void login(String username, String password)
throws AuthenticationException {
// Authenticate
service.setUserCredentials(username, password);
}
/**
* Parses a list of the format "Name=Fred,Day=wed,Phone=123-4567", and sets
* the corresponding values in the record entry.
*
* Values that are not specified are left alone. That is, if the entry already
* contains "Day=wed", then setting name and phone will retain
* the day as wed.
*
* @param entryToChange the entry to change based on the parameters
* @param nameValuePairs the list of name/value pairs.
*/
public void setEntryContentsFromString(RecordEntry entryToChange,
String nameValuePairs) {
if (entryToChange == null) {
entryToChange = new RecordEntry();
}
// Split first by the commas between the different fields.
for (String nameValuePair : nameValuePairs.split(",")) {
// Then, split by the equal sign.
String[] parts = nameValuePair.split("=", 2);
String name = parts[0]; // such as "name"
String value = parts[1]; // such as "Fred"
entryToChange.addField(new Field(null, name, value));
}
}
/**
* Adds a new record entry, based on the user-specified name value pairs.
*
* @param nameValuePairs pairs such as "Name=Rosa,Phone=555-1212"
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void addNewEntry(String nameValuePairs) throws IOException,
ServiceException {
RecordEntry newEntry = new RecordEntry();
setEntryContentsFromString(newEntry, nameValuePairs);
service.insert(recordsFeedUrl, newEntry);
out.println("Added!");
}
/**
* Prints the entire record entry, in a way that mildly resembles what the
* actual XML looks like.
*
* In addition, all printed entries are cached here. This way, they can be
* updated or deleted, without having to retrieve the version identifier again
* from the server.
*
* @param entry the record entry to print
*/
public void printAndCacheEntry(RecordEntry entry) {
// We only care about the entry id, chop off the leftmost part.
// I.E., this turns http://spreadsheets.google.com/..../cpzh6 into cpzh6.
String id = entry.getId().substring(entry.getId().lastIndexOf('/') + 1);
// Cache all displayed entries so that they can be updated later.
entriesCached.put(id, entry);
out.println("-- id: " + id + " title: " + entry.getTitle().getPlainText());
for (Field field : entry.getFields()) {
out.println(" <field name=" + field.getName() + ">"
+ field.getValue() + "</field>");
}
}
/**
* Displays the given list of entries and prompts the user to select the index
* of one of the entries. NOTE: The displayed index is 1-based and is
* converted to 0-based before being returned.
*
* @param reader to read input from the keyboard
* @param entries the list of entries to display
* @param type describes the tyoe of things the list contains
* @return the 0-based index of the user's selection
* @throws IOException if an I/O error occurs while getting input from user
*/
private int getIndexFromUser(BufferedReader reader, List entries, String type)
throws IOException {
for (int i = 0; i < entries.size(); i++) {
BaseEntry entry = (BaseEntry) entries.get(i);
out.println("\t(" + (i + 1) + ") "
+ entry.getTitle().getPlainText());
}
int index = -1;
while (true) {
out.print("Enter the number of the spreadsheet to load: ");
String userInput = reader.readLine();
try {
index = Integer.parseInt(userInput);
if (index < 1 || index > entries.size()) {
throw new NumberFormatException();
}
break;
} catch (NumberFormatException e) {
System.out.println("Please enter a valid number for your selection.");
}
}
return index - 1;
}
/**
* Uses the user's credentials to get a list of spreadsheets. Then asks the
* user which spreadsheet to load. If the selected spreadsheet has multiple
* worksheets then the user will also be prompted to select what sheet to use.
*
* @param reader to read input from the keyboard
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*
*/
public void loadSheet(BufferedReader reader) throws IOException,
ServiceException {
// Get the spreadsheet to load
SpreadsheetFeed feed = service.getFeed(factory.getSpreadsheetsFeedUrl(),
SpreadsheetFeed.class);
List spreadsheets = feed.getEntries();
int spreadsheetIndex = getIndexFromUser(reader, spreadsheets,
"spreadsheet");
SpreadsheetEntry spreadsheet = (SpreadsheetEntry) spreadsheets
.get(spreadsheetIndex);
URL spreadsheetUrl =
new java.net.URL(spreadsheet.getSpreadsheetLink().getHref());
this.baseUrl = spreadsheetUrl.getProtocol() + "://"
+ spreadsheetUrl.getHost();
this.spreadsheetKey = spreadsheet.getKey();
tablesFeedUrl = new java.net.URL(this.baseUrl + "/feeds/"
+ spreadsheet.getKey() + "/tables");
out.println("Sheet loaded.");
}
/**
* Sets the table to use to construct the record feed.
*
* @param id the table to use to construct the record feed. A record
* feed is a feed of records from a table. A table can be constructed
* using the TableDemo.
*/
public void setTableId(String id) throws IOException {
this.tableId = Integer.parseInt(id);
this.recordsFeedUrl = new java.net.URL(this.baseUrl + "/feeds/" +
this.spreadsheetKey + "/records/" + tableId);
out.println("Set table id: " + this.tableId);
}
/**
* Lists the tables currently available in the sheet.
*/
public void listAllTables() throws IOException, ServiceException {
TableFeed feed = service.getFeed(tablesFeedUrl, TableFeed.class);
for (TableEntry entry : feed.getEntries()) {
printTable(entry);
}
if (feed.getEntries().size() == 0) {
out.println("No tables yet! Use the table demo to create one.");
}
}
/**
* Prints a table entry in a format that looks vaguely like the xml.
*
* @param table entry to print.
*/
public void printTable(TableEntry entry) {
out.println("-- id: " + entry.getId()
+ " title: " + entry.getTitle().getPlainText());
out.println("<title>" + entry.getTitle().getPlainText() + "</title>");
out.println("<summary>" + entry.getSummary().getPlainText() + "</summary>");
out.println("<worksheet>" + entry.getWorksheet().getName()
+ "</worksheet>");
out.println("<header>" + entry.getHeader().getRow() + "</header>");
Data data = entry.getData();
out.println("<data> insertionMode=" + data.getInsertionMode().name()
+ " startRow=" + data.getStartIndex()
+ " numRows=" + data.getNumberOfRows());
for (Column col: data.getColumns()) {
out.println(" <column>" + col.getIndex() + " " + col.getName()
+ "</column>");
}
out.println("</data>");
}
/**
* Lists all rows in the spreadsheet.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void listAllEntries() throws IOException, ServiceException {
RecordFeed feed = service.getFeed(recordsFeedUrl, RecordFeed.class);
for (RecordEntry entry : feed.getEntries()) {
printAndCacheEntry(entry);
}
if (feed.getEntries().size() == 0) {
out.println("No entries yet!");
}
}
/**
* Lists all rows in the spreadsheet in reverse order.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void reverseAllEntries() throws IOException, ServiceException {
RecordQuery query = new RecordQuery(recordsFeedUrl);
query.setReverse(true);
RecordFeed feed = service.query(query, RecordFeed.class);
for (RecordEntry entry : feed.getEntries()) {
printAndCacheEntry(entry);
}
}
/**
* Searches rows with a full text search string, finding any rows that match
* all the given words.
*
* @param fullTextSearchString a string like "Rosa 555" will look for the
* substrings Rosa and 555 to appear anywhere in the row
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void search(String fullTextSearchString) throws IOException,
ServiceException {
RecordQuery query = new RecordQuery(recordsFeedUrl);
query.setFullTextQuery(fullTextSearchString);
RecordFeed feed = service.query(query, RecordFeed.class);
out.println("Results for [" + fullTextSearchString + "]");
for (RecordEntry entry : feed.getEntries()) {
printAndCacheEntry(entry);
}
}
/**
* Performs a full database-like query on the records.
*
* @param structuredQuery a query like: name = "Bob" and phone != "555-1212"
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void query(String structuredQuery) throws IOException,
ServiceException {
RecordQuery query = new RecordQuery(recordsFeedUrl);
query.setSpreadsheetQuery(structuredQuery);
RecordFeed feed = service.query(query, RecordFeed.class);
out.println("Results for [" + structuredQuery + "]");
for (RecordEntry entry : feed.getEntries()) {
printAndCacheEntry(entry);
}
}
/**
* Deletes an entry by the ID.
*
* This looks up the old cached row so that the version ID is known. A version
* ID is used by GData to avoid edit collisions, so that you know if someone
* has changed the row before you delete it.
*
* For this reason, the cached version of the row, as you last saw it, is
* kept, instead of querying the entry anew.
*
* @param idToDelete the ID of the row to delete such as "cph6n"
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void delete(String idToDelete) throws IOException, ServiceException {
RecordEntry entry = entriesCached.get(idToDelete); // Find the entry to
// delete
if (entry != null) {
entry.delete(); // This deletes the existing entry.
out.println("Deleted!");
} else {
out.println("I don't know that ID.");
out.println("In GData, you must get an entry before deleting it,");
out.println("so that you have the version ID.");
out.println("You might have to 'list' first.");
}
}
/**
* Updates an existing entry.
*
* See the comment in {@code delete} for why the entry is cached in a hash
* map.
*
* @param id the ID of the row to update
* @param nameValuePairs the name value pairs, such as "name=Rosa" to change
* the row's name field to Rosa
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void update(String id, String nameValuePairs) throws IOException,
ServiceException {
// The next line of code finds the entry to update.
// See the javadoc on entriesCached.
RecordEntry entry = entriesCached.get(id);
setEntryContentsFromString(entry, nameValuePairs);
if (entry != null) {
entry.update(); // This updates the existing entry.
out.println("Updated!");
} else {
out.println("I don't know that ID.");
out.println("In GData, you must get an entry before deleting it.");
out.println("You might have to 'list' first.");
}
}
/**
* Parses and executes a command.
*
* @param reader to read input from the keyboard
* @return false if the user quits, true otherwise.
*/
public boolean executeCommand(BufferedReader reader) {
for (String s : COMMAND_HELP_MESSAGE) {
out.println(s);
}
System.err.print("Command: ");
try {
String command = reader.readLine();
String[] parts = command.trim().split(" ", 2);
String name = parts[0];
String parameters = parts.length > 1 ? parts[1] : "";
if (recordsFeedUrl == null && !name.equals("table")
&& !name.equals("listtables")
&& !name.equals("exit")) {
out.println("Please set the table to use first! "
+ " Use the 'table' command to choose a table. If there"
+ " are no tables in your sheet, create one using the"
+ " TableDemo.");
return true;
}
if (name.equals("add")) {
addNewEntry(parameters);
} else if (name.equals("load")) {
loadSheet(reader);
} else if (name.equals("list")) {
listAllEntries();
} else if (name.equals("listtables")) {
listAllTables();
} else if (name.equals("reverse")) {
reverseAllEntries();
} else if (name.equals("search")) {
search(parameters);
} else if (name.equals("query")) {
query(parameters);
} else if (name.equals("delete")) {
delete(parameters);
} else if (name.equals("update")) {
String[] split = parameters.split(" ", 2);
update(split[0], split[1]);
} else if (name.equals("table")) {
setTableId(parameters);
} else if (name.startsWith("q") || name.startsWith("exit")) {
return false;
} else {
out.println("Unknown command.");
}
} catch (ServiceException se) {
// Show *exactly* what went wrong.
se.printStackTrace();
} catch (IOException ioe) {
// Show *exactly* what went wrong.
ioe.printStackTrace();
}
return true;
}
/**
* Starts up the demo and prompts for commands.
*
* @param username name of user to authenticate (e.g. yourname@gmail.com)
* @param password password to use for authentication
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public void run(String username, String password)
throws AuthenticationException {
for (String s : WELCOME_MESSAGE) {
out.println(s);
}
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
// Login and prompt the user to pick a sheet to use.
login(username, password);
try {
loadSheet(reader);
} catch (Exception e) {
e.printStackTrace();
}
while (executeCommand(reader)) {
}
}
/**
* Runs the demo.
*
* @param args the command-line arguments
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public static void main(String[] args) throws AuthenticationException {
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
String username = parser.getValue("username", "user", "u");
String password = parser.getValue("password", "pass", "p");
boolean help = parser.containsKey("help", "h");
if (help || username == null || password == null) {
usage();
System.exit(1);
}
RecordDemo demo = new RecordDemo(new SpreadsheetService("Record Demo"),
System.out);
demo.run(username, password);
}
/**
* Prints out the usage.
*/
private static void usage() {
for (String s : USAGE_MESSAGE) {
System.out.println(s);
}
for (String s : WELCOME_MESSAGE) {
System.out.println(s);
}
}
}
@@ -0,0 +1,35 @@
Google Spreadsheets data API Java Sample - README.txt
-----------------------------------------------------
This is a very simple Java example of how the API can be used on a
Google spreadsheet to create a table object. This table object
can be updated, and deleted and you can query it based on
it's title. It can be placed anywhere on the grid. The
records in the table (see RecordDemo) can be sorted and queried
without modifying the position of the table headers and records.
Before starting this demo, make sure you create a spreadsheet.
The spreadsheet can be empty as you will be adding a table to it
that will contain column headers.
An example table might look like:
Name Day Phone
We suggest you leave your browser open while trying this out.
This can be built and run with Ant:
// TODO down here.
1. Edit gdata/java/build-samples/build.properties with your Google Account
username and password.
2. Run the Ant rule:
ant -f gdata/java/build-samples.xml sample.spreadsheet.list.run
Alternately, you can compile and run it from the command line:
java sample.list.TableDemo
--username [user]
--password [pass]
@@ -0,0 +1,614 @@
/* Copyright (c) 2008 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 sample.spreadsheet.table;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import sample.util.SimpleCommandLineParser;
import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.TableQuery;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.spreadsheet.Column;
import com.google.gdata.data.spreadsheet.Data;
import com.google.gdata.data.spreadsheet.Header;
import com.google.gdata.data.spreadsheet.Worksheet;
import com.google.gdata.data.spreadsheet.TableEntry;
import com.google.gdata.data.spreadsheet.TableFeed;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* An application to show the basic operations of the Table feed.
*
*
*/
public class TableDemo {
/** The message for displaying the usage parameters. */
private static final String[] USAGE_MESSAGE = {
"Usage: java TableDemo --username [user] --password [pass] ", ""};
/** Help on setting up this demo. */
private static final String[] WELCOME_MESSAGE = {
"Using this demo, you can see how tables can be conveniently created,",
"updated, queried, and deleted.", "",
"Before starting this demo, make sure you create a spreadsheet."};
/** Help on all available commands. */
private static final String[] COMMAND_HELP_MESSAGE = {
"Commands:",
" load [[select a spreadsheet]]",
" list [[shows all entries]]",
" add title=Table1, summary=Test Table, worksheet=Sheet1, header=1, "
+ "startrow=2, numrows=5, columns=a:Name;b:Phone;c:Address "
+ "[[adds a table]]",
" update <tableid> title=AwesomeTable [[updates a table]]",
" delete <tableid> [[deletes; use 'list' first]]",
" search AwesomeTable [[title search]]", // add title exact.
" exit"};
/** Our view of Google Spreadsheets as an authenticated Google user. */
private SpreadsheetService service;
/** The URL of the table feed for the selected spreadsheet. */
private URL tablesFeedUrl;
/** A factory that generates the appropriate feed URLs. */
private FeedURLFactory factory;
/** The output stream to use. */
private PrintStream out;
/**
* Caches entries.
*
* In this example, every entry we display to the user is cached. We do this
* because Google Data has a feature where if an entry is updated between the
* time you download it and update or delete it, you will be alerted of the
* edit. For example:
*
* 1. In this sample app, I look at the table with title Table1. 2. Someone
* editing the spreadsheet changes the title to UpdatedTable1.
* In this sample app, I try to change the title to Table2.
*
* By caching the entry and updating the last entry, I am telling the server
* that I am updating the age from Table1 to Table2. The server now has enough
* information to tell me that the age has already been changed, because the
* version ID that I am sending was the version ID for Table 1.
*
* If you do not wish to cache entries, an alternative is to fetch the proper
* entry ID from Google Data, update that fresh entry, and post. In that case,
* no caching is necessary, and a version conflict is less likely. On the
* other hand, you won't get alerted if someone else has changed the entry in
* the meantime.
*
* This would be achieved by getting an entry: TableEntry freshEntry=
* service.getEntry( new URL(tablesFeedUrl.toString() + "/" + id),
* TableEntry.class) (update freshEntry's fields) freshEntry.update();
*/
private Map<String, TableEntry> entriesCached;
/**
* Starts up the demo with the specified service.
*
* @param service the connection to the Google Spradsheets service.
* @param outputStream a handle for stdout.
*/
public TableDemo(SpreadsheetService service, PrintStream outputStream) {
this.out = outputStream;
this.service = service;
this.factory = FeedURLFactory.getDefault();
this.entriesCached = new HashMap<String, TableEntry>();
}
/**
* Set the user credentials for theg given user name and password.
*
* @param username the username of the user toauthenticate
* (e.g. yourname@gmail.com)
@ @param password the password of the user to authenticate.
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public void login(String username, String password)
throws AuthenticationException {
// Authenticate
service.setUserCredentials(username, password);
}
/**
* Parses the command line arguments given in the format
* "title=Table1,summary=This is a test", and sets the corresponding values
* on the given TableEntry.
*
* Values that are not specified are left alone. That is, if the entry already
* contains "title=Table1", then setting summary will retain
* the title as Table1.
*
* @param entryToUpdate the entry to change based on the parameters
* @param nameValuePairs the list of name/value pairs, containing the name of
* the title.
*/
public TableEntry setEntryContentsFromString(TableEntry entryToUpdate,
String nameValuePairs) {
Map<String, String> dataParams = Maps.newHashMap();
Map<String, String> dataCols = Maps.newHashMap();
// Split first by the commas between the different fields.
for (String nameValuePair : nameValuePairs.split(",")) {
// Then, split by the equal sign. Attributes are specified as key=value.
String[] parts = nameValuePair.split("=", 2);
if (parts.length < 2) {
System.out.println("Attributes are specified as key=value, "
+ "for example, title=Table1");
}
String tag = parts[0].trim(); // such as "name"
String value = parts[1].trim(); // such as "Fred"
if (tag.equals("title")) {
entryToUpdate.setTitle(new PlainTextConstruct(value));
} else if (tag.equals("summary")) {
entryToUpdate.setSummary(new PlainTextConstruct(value));
} else if (tag.equals("worksheet")) {
entryToUpdate.setWorksheet(new Worksheet(value));
} else if (tag.equals("header")) {
entryToUpdate.setHeader(new Header(Integer.parseInt(value)));
} else if (tag.equals("startrow") || tag.equals("insertionmode")
|| tag.equals("numrows")) {
dataParams.put(tag, value);
} else if (tag.equals("columns")) {
String[] columns = value.split(";");
for (int i = 0; i < columns.length; i++) {
String[] colInfo = columns[i].split(":");
if (colInfo.length < 2) {
System.out.println("Columns are specified as column:value, for "
+ " example, B:UpdatedPhone");
}
String index = colInfo[0];
String name = colInfo[1];
dataCols.put(index, name);
}
}
}
// Update table data.
Data data = getDataFromParams(
entryToUpdate.getData(), dataParams, dataCols);
entryToUpdate.setData(data);
return entryToUpdate;
}
/**
* Create a new data object from any data params that were specified.
* Data params are numrows, startrow, insertionmode and columns.
* Any attributes that are not specified are left alone. So, if data already
* has insertionmode=insert, specifying numrows=4 and startrow=12 will leave
* insertionmode as insert.
*
* @param data original data object.
* @param dataParams new data params to use to update the original
* data object.
* @param columnMap map of column index to value used to update the column
* headers of the table.
*/
public Data getDataFromParams(Data data,
Map<String, String> dataParams, Map<String, String> columnMap) {
Data newData = new Data();
if (data == null) {
data = new Data();
}
if (dataParams.get("numrows") != null) {
newData.setNumberOfRows(Integer.parseInt(dataParams.get("numrows")));
} else {
newData.setNumberOfRows(data.getNumberOfRows());
}
if (dataParams.get("startrow") != null) {
newData.setStartIndex(Integer.parseInt(dataParams.get("startrow")));
} else {
newData.setStartIndex(data.getStartIndex());
}
String insertionMode = dataParams.get("insertionmode");
if (insertionMode != null && insertionMode.equals("insert")) {
newData.setInsertionMode(Data.InsertionMode.INSERT);
}
List<Column> existing = data.getColumns();
// Add existing column data to column map.
for (Column existingCol : existing) {
String index = existingCol.getIndex();
String name = existingCol.getName();
// If column is being updated, set value, else add a new one.
if (columnMap.get(index) == null) {
columnMap.put(index, name);
}
}
// Set columns on new data object.
for (String key : columnMap.keySet()) {
newData.addColumn(new Column(key, columnMap.get(key)));
}
return newData;
}
/**
* Adds a new table entry, based on the user-specified name value pairs.
* Note that the following parameters must be specified:
* title, startrow, numrows, columns.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void addNewEntry(String nameValuePairs) throws IOException,
ServiceException {
TableEntry newEntry = setEntryContentsFromString(new TableEntry(),
nameValuePairs);
service.insert(tablesFeedUrl, newEntry);
out.println("Added table!");
}
/**
* Prints the entire table entry, in a way that mildly resembles what the
* actual XML looks like.
*
* In addition, all printed entries are cached here. This way, they can be
* updated or deleted, without having to retrieve the version identifier again
* from the server.
*
* @param entry the list entry to print
*/
public void printAndCacheEntry(TableEntry entry) {
// We only care about the entry id, chop off the leftmost part.
// I.E., this turns http://spreadsheets.google.com/..../cpzh6 into cpzh6.
String id = entry.getId().substring(entry.getId().lastIndexOf('/') + 1);
// Cache all displayed entries so that they can be updated later.
entriesCached.put(id, entry);
out.println("-- id: " + id + " title: " + entry.getTitle().getPlainText());
out.println("<title>" + entry.getTitle().getPlainText() + "</title>");
out.println("<summary>" + entry.getSummary().getPlainText() + "</summary>");
out.println("<worksheet>" + entry.getWorksheet().getName()
+ "</worksheet>");
out.println("<header>" + entry.getHeader().getRow() + "</header>");
Data data = entry.getData();
out.println("<data> insertionMode=" + data.getInsertionMode().name()
+ " startRow=" + data.getStartIndex()
+ " numRows=" + data.getNumberOfRows());
for (Column col: data.getColumns()) {
out.println(" <column>" + col.getIndex() + " " + col.getName()
+ "</column>");
}
out.println("</data>");
}
/**
* Displays the given list of entries and prompts the user to select the index
* of one of the entries. NOTE: The displayed index is 1-based and is
* converted to 0-based before being returned.
*
* @param reader to read input from the keyboard
* @param entries the list of entries to display
* @param type describes the tyoe of things the list contains
* @return the 0-based index of the user's selection
* @throws IOException if an I/O error occurs while getting input from user
*/
private int getIndexFromUser(BufferedReader reader, List entries, String type)
throws IOException {
for (int i = 0; i < entries.size(); i++) {
BaseEntry entry = (BaseEntry) entries.get(i);
System.out.println("\t(" + (i + 1) + ") "
+ entry.getTitle().getPlainText());
}
int index = -1;
while (true) {
out.print("Enter the number of the spreadsheet to load: ");
String userInput = reader.readLine();
try {
index = Integer.parseInt(userInput);
if (index < 1 || index > entries.size()) {
throw new NumberFormatException();
}
break;
} catch (NumberFormatException e) {
System.out.println("Please enter a valid number for your selection.");
}
}
return index - 1;
}
/**
* Uses the user's credentials to get a list of spreadsheets. Then asks the
* user which spreadsheet to load. If the selected spreadsheet has multiple
* worksheets then the user will also be prompted to select what sheet to use.
*
* @param reader to read input from the keyboard
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*
*/
public void loadSheet(BufferedReader reader) throws IOException,
ServiceException {
// Get the spreadsheet to load
SpreadsheetFeed feed = service.getFeed(factory.getSpreadsheetsFeedUrl(),
SpreadsheetFeed.class);
List spreadsheets = feed.getEntries();
int spreadsheetIndex = getIndexFromUser(reader, spreadsheets,
"spreadsheet");
SpreadsheetEntry spreadsheet = (SpreadsheetEntry) spreadsheets
.get(spreadsheetIndex);
URL spreadsheetUrl = new java.net.URL(
spreadsheet.getSpreadsheetLink().getHref());
String baseUrl = new java.net.URL(spreadsheetUrl.getProtocol() + "://"
+ spreadsheetUrl.getHost()).toString();
tablesFeedUrl = new java.net.URL(baseUrl + "/feeds/" + spreadsheet.getKey()
+ "/tables");
System.out.println("Sheet loaded.");
}
/**
* Lists all tables in the spreadsheet.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void listAllEntries() throws IOException, ServiceException {
TableFeed feed = service.getFeed(tablesFeedUrl, TableFeed.class);
for (TableEntry entry : feed.getEntries()) {
printAndCacheEntry(entry);
}
if (feed.getEntries().size() == 0) {
System.out.println("No entries yet!");
}
}
/**
* Searches titles of tables with a text search string, finds tables that
* match the given title and prints those entries out.
*
* @param titleSearchString a string like "Table 2" will look for the
* string "Table 2" in the title of all tables available on the sheet.
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void search(String titleSearchString) throws IOException,
ServiceException {
TableQuery query = new TableQuery(tablesFeedUrl);
query.setTitleQuery(titleSearchString);
TableFeed feed = service.query(query, TableFeed.class);
out.println("Results for [" + titleSearchString + "]");
for (TableEntry entry : feed.getEntries()) {
printAndCacheEntry(entry);
}
}
/**
* Deletes an entry by the ID.
*
* This looks up the old cached row so that the version ID is known. A version
* ID is used by GData to avoid edit collisions, so that you know if someone
* has changed the row before you delete it.
*
* For this reason, the cached version of the row, as you last saw it, is
* kept, instead of querying the entry anew.
*
* @param idToDelete the ID of the table to delete such as "0"
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void delete(String idToDelete) throws IOException, ServiceException {
TableEntry entry = entriesCached.get(idToDelete); // Find the entry to
// delete
if (entry != null) {
entry.delete(); // This deletes the existing entry.
out.println("Deleted!");
} else {
out.println("I don't know that ID.");
out.println("In GData, you must get an entry before deleting it,");
out.println("so that you have the version ID.");
out.println("You might have to 'list' first.");
}
}
/**
* Updates an existing entry.
*
* See the comment in {@code delete} for why the entry is cached in a hash
* map.
*
* @param id the ID of the row to update
* @param nameValuePairs the name value pairs, such as "title=UpdatedTitle"
* to change
* the table's title to UpdatedTitle
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
public void update(String id, String nameValuePairs) throws IOException,
ServiceException {
// The next line of code finds the entry to update.
// See the javadoc on entriesCached.
TableEntry entry = entriesCached.get(id);
setEntryContentsFromString(entry, nameValuePairs);
if (entry != null) {
entry.update(); // This updates the existing entry.
out.println("Updated!");
} else {
out.println("I don't know that ID.");
out.println("In GData, you must get an entry before deleting it.");
out.println("You might have to 'list' first.");
}
}
/**
* Parses and executes a command.
*
* @param reader to read input from the keyboard
* @return false if the user quits, true on exception
*/
public boolean executeCommand(BufferedReader reader) {
for (String s : COMMAND_HELP_MESSAGE) {
out.println(s);
}
System.err.print("Command: ");
try {
String command = reader.readLine();
String[] parts = command.trim().split(" ", 2);
String name = parts[0];
String parameters = parts.length > 1 ? parts[1] : "";
if (name.equals("add")) {
addNewEntry(parameters);
} else if (name.equals("load")) {
loadSheet(reader);
} else if (name.equals("list")) {
listAllEntries();
} else if (name.equals("search")) {
search(parameters);
} else if (name.equals("delete")) {
delete(parameters);
} else if (name.equals("update")) {
String[] split = parameters.split(" ", 2);
if (split.length < 2) {
out.println("insufficient number of params for update.");
}
update(split[0], split[1]);
} else if (name.startsWith("q") || name.startsWith("exit")) {
return false;
} else {
out.println("Unknown command.");
}
} catch (ServiceException se) {
// Show *exactly* what went wrong.
se.printStackTrace();
} catch (IOException ioe) {
// Show *exactly* what went wrong.
ioe.printStackTrace();
}
return true;
}
/**
* Starts up the demo and prompts for commands.
*
* @param username name of user to authenticate (e.g. yourname@gmail.com)
* @param password password to use for authentication
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public void run(String username, String password)
throws AuthenticationException {
for (String s : WELCOME_MESSAGE) {
out.println(s);
}
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
// Login and prompt the user to pick a sheet to use.
login(username, password);
try {
loadSheet(reader);
} catch (Exception e) {
e.printStackTrace();
}
while (executeCommand(reader)) {
}
}
/**
* Runs the demo.
*
* @param args the command-line arguments
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public static void main(String[] args) throws AuthenticationException {
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
String username = parser.getValue("username", "user", "u");
String password = parser.getValue("password", "pass", "p");
boolean help = parser.containsKey("help", "h");
if (help || username == null || password == null) {
usage();
System.exit(1);
}
TableDemo demo = new TableDemo(new SpreadsheetService("Table Demo"),
System.out);
demo.run(username, password);
}
/**
* Prints out the usage.
*/
private static void usage() {
for (String s : USAGE_MESSAGE) {
System.out.println(s);
}
for (String s : WELCOME_MESSAGE) {
System.out.println(s);
}
}
}
@@ -0,0 +1,24 @@
Google Spreadsheets data API Java Sample - README.txt
-----------------------------------------------------
This is a very simple Java example of reading and writing to worksheets in
a spreadsheet. Using it, you can fully experiment with creating, listing,
updating, and deleting worksheets.
This can be built an run with Ant:
1. Edit gdata/java/build-samples/build.properties with your Google Account
username, password, and a URL to your Google spreadsheet
(in the format ....spreadsheets.google.com/ccc?id=...)
2. Run the Ant rule:
ant -f gdata/java/build-samples/spreadsheet.xml sample.spreadsheet.worksheetdemo.run
Alternately, you can compile and run it from the command line:
java sample.spreadsheet.worksheet.WorksheetDemo
--username [user]
--password [pass]
@@ -0,0 +1,396 @@
/* Copyright (c) 2008 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 sample.spreadsheet.worksheet;
import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.data.spreadsheet.WorksheetEntry;
import com.google.gdata.data.spreadsheet.WorksheetFeed;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import sample.util.SimpleCommandLineParser;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URL;
import java.util.List;
/**
* Demo of the CRUD operation on the worksheets feed.
*
* Using this demo, you can see how the Google data API can you can manage the
* worksheets in your spreadsheets.
*
* Usage: java WorksheetDemo --username [username] --password [password]
*
*
*/
public class WorksheetDemo {
/** The message for displaying the usage parameters. */
private static final String[] USAGE_MESSAGE = {
"Usage: java WorksheetDemo --username [user] --password [pass] ", ""};
/** Welcome message, introducing the program. */
private static final String[] WELCOME_MESSAGE = {
"This is a demo of the worksheets feed!",
"",
"Using this interface, you can manage the worksheets in your "
+ "spreadsheet.", ""};
/** Help on all available commands. */
private static final String[] COMMAND_HELP_MESSAGE = {
"Commands:",
" load [[load a spreadsheet]]",
" list [[show all worksheets]]",
" create title, #rows, #cols [[create a new worksheet]]",
" update oldTitle, newTitle, #rows, #cols "
+ "[[update the title and size of a worksheet]]",
" delete title [[delete a worksheet]]",
" quit or q [[quit demo]]"};
/** Our view of Google Spreadsheets as an authenticated Google user. */
private SpreadsheetService service;
/** The URL of the worksheet feed. */
private URL worksheetFeedUrl;
/** The output stream. */
private PrintStream out;
/** A factory that generates the appropriate feed URLs. */
private FeedURLFactory factory;
/**
* Constructs a worksheet demo using the given spreadsheet service and output
* stream. The spreadsheet service is used to authenticate to and access
* Google Spreadsheets.
*
* @param service the connection to the Google Spreadsheets service.
* @param outputStream a handle for stdout.
*/
public WorksheetDemo(SpreadsheetService service, PrintStream outputStream) {
this.service = service;
this.out = outputStream;
this.factory = FeedURLFactory.getDefault();
}
/**
* Log in to Google, under the Google Spreadsheets account.
*
* @param username name of user to authenticate (e.g. yourname@gmail.com)
* @param password password to use for authentication
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public void login(String username, String password)
throws AuthenticationException {
// Authenticate
service.setUserCredentials(username, password);
}
/**
* Displays the given list of entries and prompts the user to select the index
* of one of the entries. NOTE: The displayed index is 1-based and is
* converted to 0-based before being returned.
*
* @param reader to read input from the keyboard
* @param entries the list of entries to display
* @param type describes the type of things the list contains
* @return the 0-based index of the user's selection
* @throws IOException if an I/O error occurs while getting input from user
*/
private int getIndexFromUser(BufferedReader reader, List entries, String type)
throws IOException {
for (int i = 0; i < entries.size(); i++) {
BaseEntry entry = (BaseEntry) entries.get(i);
System.out.println("\t(" + (i + 1) + ") "
+ entry.getTitle().getPlainText());
}
int index = -1;
while (true) {
out.print("Enter the number of the spreadsheet to load: ");
String userInput = reader.readLine();
try {
index = Integer.parseInt(userInput);
if (index < 1 || index > entries.size()) {
throw new NumberFormatException();
}
break;
} catch (NumberFormatException e) {
System.out.println("Please enter a valid number for your selection.");
}
}
return index - 1;
}
/**
* Uses the user's credentials to get a list of spreadsheets. Then asks the
* user which spreadsheet to load. If the selected spreadsheet has multiple
* worksheets then the user will also be prompted to select what sheet to use.
*
* @param reader to read input from the keyboard
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*
*/
public void loadSheet(BufferedReader reader) throws IOException,
ServiceException {
SpreadsheetFeed feed = service.getFeed(factory.getSpreadsheetsFeedUrl(),
SpreadsheetFeed.class);
List<SpreadsheetEntry> spreadsheets = feed.getEntries();
int spreadsheetIndex = getIndexFromUser(reader, spreadsheets, "spreadsheet");
SpreadsheetEntry spreadsheet = feed.getEntries().get(spreadsheetIndex);
worksheetFeedUrl = spreadsheet.getWorksheetFeedUrl();
System.out.println("Spreadsheet loaded.");
}
/**
* Lists all the worksheets in the loaded spreadsheet.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
private void listAllWorksheets() throws IOException, ServiceException {
WorksheetFeed worksheetFeed = service.getFeed(worksheetFeedUrl,
WorksheetFeed.class);
for (WorksheetEntry worksheet : worksheetFeed.getEntries()) {
String title = worksheet.getTitle().getPlainText();
int rowCount = worksheet.getRowCount();
int colCount = worksheet.getColCount();
System.out.println("\t" + title + " - rows:" + rowCount + " cols: "
+ colCount);
}
}
/**
* Creates a new worksheet in the loaded spreadsheets, using the title and
* sizes given.
*
* @param title a String containing a name for the new worksheet.
* @param rowCount the number of rows the new worksheet should have.
* @param colCount the number of columns the new worksheet should have.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
private void createWorksheet(String title, int rowCount, int colCount)
throws IOException, ServiceException {
WorksheetEntry worksheet = new WorksheetEntry();
worksheet.setTitle(new PlainTextConstruct(title));
worksheet.setRowCount(rowCount);
worksheet.setColCount(colCount);
service.insert(worksheetFeedUrl, worksheet);
}
/**
* Updates the worksheet specified by the oldTitle parameter, with the given
* title and sizes. Note that worksheet titles are not unique, so this method
* just updates the first worksheet it finds. Hey, it's just sample code - no
* refunds!
*
* @param oldTitle a String specifying the worksheet to update.
* @param newTitle a String containing the new name for the worksheet.
* @param rowCount the number of rows the new worksheet should have.
* @param colCount the number of columns the new worksheet should have.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
private void updateWorksheet(String oldTitle, String newTitle, int rowCount,
int colCount) throws IOException, ServiceException {
WorksheetFeed worksheetFeed = service.getFeed(worksheetFeedUrl,
WorksheetFeed.class);
for (WorksheetEntry worksheet : worksheetFeed.getEntries()) {
String currTitle = worksheet.getTitle().getPlainText();
if (currTitle.equals(oldTitle)) {
worksheet.setTitle(new PlainTextConstruct(newTitle));
worksheet.setRowCount(rowCount);
worksheet.setColCount(colCount);
worksheet.update();
System.out.println("Worksheet updated.");
return;
}
}
// If it got this far, the worksheet wasn't found.
System.out.println("Worksheet not found: " + oldTitle);
}
/**
* Deletes the worksheet specified by the title parameter. Note that worksheet
* titles are not unique, so this method just updates the first worksheet it
* finds.
*
* @param title a String containing the name of the worksheet to delete.
*
* @throws ServiceException when the request causes an error in the Google
* Spreadsheets service.
* @throws IOException when an error occurs in communication with the Google
* Spreadsheets service.
*/
private void deleteWorksheet(String title) throws IOException,
ServiceException {
WorksheetFeed worksheetFeed = service.getFeed(worksheetFeedUrl,
WorksheetFeed.class);
for (WorksheetEntry worksheet : worksheetFeed.getEntries()) {
String currTitle = worksheet.getTitle().getPlainText();
if (currTitle.equals(title)) {
worksheet.delete();
System.out.println("Worksheet deleted.");
return;
}
}
// If it got this far, the worksheet wasn't found.
System.out.println("Worksheet not found: " + title);
}
/**
* Parses and executes a command.
*
* @param reader to read input from the keyboard
* @return false if the user quits, true on exception
*/
public boolean executeCommand(BufferedReader reader) {
for (String s : COMMAND_HELP_MESSAGE) {
out.println(s);
}
System.err.print("Command: ");
try {
String command = reader.readLine();
String[] parts = command.trim().split(" ", 2);
String name = parts[0];
String parameters = parts.length > 1 ? parts[1] : "";
if (name.equals("load")) {
loadSheet(reader);
} else if (name.equals("list")) {
listAllWorksheets();
} else if (name.equals("create")) {
String[] split = parameters.split(" ", 3);
createWorksheet(split[0], Integer.parseInt(split[1]), Integer
.parseInt(split[2]));
} else if (name.equals("update")) {
String[] split = parameters.split(" ", 4);
updateWorksheet(split[0], split[1], Integer.parseInt(split[2]), Integer
.parseInt(split[3]));
} else if (name.equals("delete")) {
deleteWorksheet(parameters);
} else if (name.equals("q") || name.equals("quit")) {
return false;
} else {
out.println("Unknown command.");
}
} catch (ServiceException se) {
// Show *exactly* what went wrong.
se.printStackTrace();
} catch (IOException ioe) {
// Show *exactly* what went wrong.
ioe.printStackTrace();
}
return true;
}
/**
* Starts up the demo and prompts for commands.
*
* @param username name of user to authenticate (e.g. yourname@gmail.com)
* @param password password to use for authentication
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public void run(String username, String password)
throws AuthenticationException {
for (String s : WELCOME_MESSAGE) {
out.println(s);
}
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
// Login and prompt the user to pick a sheet to use.
login(username, password);
try {
loadSheet(reader);
} catch (ServiceException se) {
// Show *exactly* what went wrong.
se.printStackTrace();
} catch (IOException ioe) {
// Show *exactly* what went wrong.
ioe.printStackTrace();
}
while (executeCommand(reader)) {
}
}
/**
* Runs the demo.
*
* @param args the command-line arguments
* @throws AuthenticationException if the service is unable to validate the
* username and password.
*/
public static void main(String[] args) throws AuthenticationException {
SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
String username = parser.getValue("username", "user", "u");
String password = parser.getValue("password", "pass", "p");
boolean help = parser.containsKey("help", "h");
if (help || username == null || password == null) {
usage();
System.exit(1);
}
final String appName = "sampleCo-WorksheetDemo-0.9";
WorksheetDemo demo = new WorksheetDemo(new SpreadsheetService(appName),
System.out);
demo.run(username, password);
}
/**
* Prints out the usage.
*/
private static void usage() {
for (String s : USAGE_MESSAGE) {
System.out.println(s);
}
for (String s : WELCOME_MESSAGE) {
System.out.println(s);
}
}
}