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,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);
}
}
}