Inital commit
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user