Have a look at the code shown below. When I add two rows to the table and afterwards try to perform an undo operation I get a java.lang.ArrayIndexOutOfBoundsException: 11 >= 11
. Can anyone please tell me what is wrong with the code?
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import javax.swing.text.TabExpander;
import javax.swing.undo.*;
public class UndoTable
{
public static void main(String[] args)
{
Object data[][] = {
{"AMZN", "Amazon", 41.28, "BUY"},
{"EBAY", "eBay", 41.57, "BUY"},
{"GOOG", "Google", 388.33, "SELL"},
{"MSFT", "Microsoft", 26.56, "SELL"},
{"NOK", "Nokia Corp", 17.13, "BUY"},
{"ORCL", "Oracle Corp.", 12.52, "BUY"},
{"SUNW", "Sun Microsystems", 3.86, "BUY"},
{"TWX", "Time Warner", 17.66, "SELL"},
{"VOD", "Vodafone Group", 26.02, "SELL"},
{"YHOO", "Yahoo!", 37.69, "BUY"}
};
String columns[] = {"Symbol", "Name", "Price", "Guidance"};
final JvUndoableTableModel tableModel = new JvUndoableTableModel(data, columns);
final JTable table = new JTable(tableModel);
JScrollPane pane = new JScrollPane(table);
JvUndoManager undoManager = new JvUndoManager();
tableModel.addUndoableEditListener(undoManager);
JMenu editMenu = new JMenu("Edit");
Action addrowaction = new AbstractAction("Add Row") {
private static final long serialVersionUID = 1433684360133156145L;
public void actionPerformed(ActionEvent e) {
tableModel.insertRow(table.getRowCount(), new Object[]{"YHOO", "Yahoo!", 37.69, "BUY"});
}
};
editMenu.add(undoManager.getUndoAction());
//editMenu.add(undoManager.getRedoAction());
JMenuBar menuBar = new JMenuBar();
menuBar.add(editMenu);
editMenu.add(addrowaction);
JFrame frame = new JFrame("Undoable JTable");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setJMenuBar(menuBar);
frame.add(pane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setLocation(200, 300);
frame.setVisible(true);
}
}
class JvUndoableTableModel extends DefaultTableModel
{
public JvUndoableTableModel(Object[][] data, Object[] columnNames)
{
super(data, columnNames);
}
public Class getColumnClass(int column)
{
if (column >= 0 && column < getColumnCount())
return getValueAt(0, column).getClass();
return Object.class;
}
@Override
public void setValueAt(Object value, int row, int column)
{
setValueAt(value, row, column, true);
}
public void setValueAt(Object value, int row, int column, boolean undoable)
{
UndoableEditListener listeners[] = getListeners(UndoableEditListener.class);
if (undoable == false || listeners == null)
{
super.setValueAt(value, row, column);
return;
}
Object oldValue = getValueAt(row, column);
super.setValueAt(value, row, column);
JvCellEdit cellEdit = new JvCellEdit(this, oldValue, value, row, column);
UndoableEditEvent editEvent = new UndoableEditEvent(this, cellEdit);
for (UndoableEditListener listener : listeners)
listener.undoableEditHappened(editEvent);
}
//adding new cell to the table
public void insertRow(int row, Object[] rowData){
insertRow(row, rowData, true);
}
public void insertRow(int row,
Object[] rowData,boolean undoable){
UndoableEditListener listeners[] = getListeners(UndoableEditListener.class);
if (undoable == false || listeners == null)
{
super.insertRow(row, rowData);
return;
}
super.insertRow(row, rowData);
JvCellNew cellNew = new JvCellNew(this, rowData, row);
UndoableEditEvent editEvent = new UndoableEditEvent(this, cellNew);
for (UndoableEditListener listener : listeners)
listener.undoableEditHappened(editEvent);
}
//removing row from the table
public void removeRow(int row){
removeRow(row, true);
}
public void removeRow(int row, boolean undoable){
UndoableEditListener listeners[] = getListeners(UndoableEditListener.class);
if (undoable == false || listeners == null)
{
super.removeRow(row);
return;
}
super.removeRow(row);
JvCellNew cellNew = new JvCellNew(this, row);
UndoableEditEvent editEvent = new UndoableEditEvent(this, cellNew);
for (UndoableEditListener listener : listeners)
listener.undoableEditHappened(editEvent);
}
public void addUndoableEditListener(UndoableEditListener listener)
{
listenerList.add(UndoableEditListener.class, listener);
}
}
class JvCellEdit extends AbstractUndoableEdit
{
protected JvUndoableTableModel tableModel;
protected Object oldValue;
protected Object newValue;
protected int row;
protected int column;
public JvCellEdit(JvUndoableTableModel tableModel, Object oldValue, Object newValue, int row, int column)
{
this.tableModel = tableModel;
this.oldValue = oldValue;
this.newValue = newValue;
this.row = row;
this.column = column;
}
@Override
public String getPresentationName()
{
return "Cell Edit";
}
@Override
public void undo() throws CannotUndoException
{
super.undo();
tableModel.setValueAt(oldValue, row, column, false);
}
}
class JvCellNew extends AbstractUndoableEdit
{
/**
*
*/
private static final long serialVersionUID = 1L;
protected JvUndoableTableModel tableModel;
protected Object[] rowData;
protected int row;
public JvCellNew(JvUndoableTableModel tableModel, Object[] rowData, int row)
{
this.tableModel = tableModel;
this.rowData = rowData;
this.row = row;
}
public JvCellNew(JvUndoableTableModel tableModel, int row)
{
this.tableModel = tableModel;
this.row = row;
}
@Override
public String getPresentationName()
{
return "Cell New";
}
public void undo() throws CannotUndoException
{
super.undo();
tableModel.removeRow(row);
}
}
class JvUndoManager extends UndoManager
{
protected Action undoAction;
// protected Action redoAction;
public JvUndoManager()
{
this.undoAction = new JvUndoAction(this);
synchronizeActions(); // to set initial names
}
public Action getUndoAction()
{
return undoAction;
}
@Override
public boolean addEdit(UndoableEdit anEdit)
{
try
{
return super.addEdit(anEdit);
}
finally
{
synchronizeActions();
}
}
@Override
protected void undoTo(UndoableEdit edit) throws CannotUndoException
{
try
{
super.undoTo(edit);
}
finally
{
synchronizeActions();
}
}
protected void synchronizeActions()
{
undoAction.setEnabled(canUndo());
undoAction.putValue(Action.NAME, getUndoPresentationName());
}
}
class JvUndoAction extends AbstractAction
{
protected final UndoManager manager;
public JvUndoAction(UndoManager manager)
{
this.manager = manager;
}
public void actionPerformed(ActionEvent e)
{
try
{
manager.undo();
}
catch (CannotUndoException ex)
{
ex.printStackTrace();
}
}
}
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 11 >= 11 at java.util.Vector.removeElementAt(Unknown Source) at javax.swing.table.DefaultTableModel.removeRow(Unknown Source) at JvUndoableTableModel.removeRow(UndoTable.java:151) at JvUndoableTableModel.removeRow(UndoTable.java:142) at JvCellNew.undo(UndoTable.java:233) at javax.swing.undo.UndoManager.undoTo(Unknown Source) at JvUndoManager.undoTo(UndoTable.java:279) at javax.swing.undo.UndoManager.undo(Unknown Source) at JvUndoAction.actionPerformed(UndoTable.java:311) at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.setPressed(Unknown Source) at javax.swing.AbstractButton.doClick(Unknown Source) at javax.swing.plaf.basic.BasicMenuItemUI.doClick(Unknown Source) at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) at javax.swing.JComponent.processMouseEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Window.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.EventQueue.dispatchEventImpl(Unknown Source) at java.awt.EventQueue.access$200(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue$4.run(Unknown Source) at java.awt.EventQueue$4.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source)