I had the same problem and could not find a good approach to handle this (anyone did?).
My workaround to the problem was to filter the setXXX calls caused by focus changes based on a timestamp.
My code customized UndoManager class' code looks like this:
/**
* Time of last undoable edit<p>
* We use this as a workaround when undoing in the following case:
* - table cell was edited and
* - undo toolbar-button clicked
* this causes a stopEdit which in turn causes setValueAt and produces a new edit.
* If the last edit was created less then MINTIME far (ex. 0.2sec), we undo twice.
*/
private GregorianCalendar editTime;
public synchronized boolean addEdit(UndoableEdit anEdit) {
this.editTime = new GregorianCalendar();
editTime.add(Calendar.MILLISECOND, MIN_TIME); // only after this time, an xxxxxxxxxx
boolean success = super.addEdit(anEdit);
if (success) {
adjustMenuState();
}
return success;
}
@Override
public synchronized void undo() {
try
{
// filter out unwanted edits from focus changes
if(editTime.after(GregorianCalendar.getInstance())){
// timeout this one so we can undo it
editTime.set(Calendar.YEAR, 1900);
// undo it and kill the unwanted one
UndoableEdit e = this.editToBeUndone();
undo(); // undo the unwanted
if(e instanceof TableCellEdit) {
TableCellEdit tce = (TableCellEdit) e;
log.warn("Remove edit :" +tce.getPresentationName() + ", " + tce.toString());
}
e.die();
}
// do the undo
super.undo();
}
finally
{
// will call undoTo adjustMenuState();
}
}
I posted a full description of the Java Undo/Redo mechanism in my blog SNIPPED (without the timestamp mechanism).