The use of UndoManager
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O'Reilly
*/
// UndoableToggleApp3.java
//A sample app showing the use of UndoManager.
//
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JToggleButton;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
public class UndoableToggleApp3 extends JFrame {
private UndoManager manager = new UndoManager();
private JButton undoButton;
private JButton redoButton;
// Create the main frame and everything in it.
public UndoableToggleApp3() {
// Create some toggle buttons.
UndoableJToggleButton tog1 = new UndoableJToggleButton("One");
UndoableJToggleButton tog2 = new UndoableJToggleButton("Two");
UndoableJToggleButton tog3 = new UndoableJToggleButton("Three");
// Add our listener to each toggle button.
SimpleUEListener sl = new SimpleUEListener();
tog1.addUndoableEditListener(sl);
tog2.addUndoableEditListener(sl);
tog3.addUndoableEditListener(sl);
// Lay out the buttons.
Box buttonBox = new Box(BoxLayout.Y_AXIS);
buttonBox.add(tog1);
buttonBox.add(tog2);
buttonBox.add(tog3);
// Create undo and redo buttons (initially disabled).
undoButton = new JButton("Undo");
redoButton = new JButton("Redo");
undoButton.setEnabled(false);
redoButton.setEnabled(false);
// Add a listener to the undo button. It attempts to call undo() on the
// UndoManager, then enables/disables the undo/redo buttons as
// appropriate.
undoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
try {
manager.undo();
} catch (CannotUndoException ex) {
ex.printStackTrace();
} finally {
updateButtons();
}
}
});
// Add a redo listener: just like the undo listener.
redoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
try {
manager.redo();
} catch (CannotRedoException ex) {
ex.printStackTrace();
} finally {
updateButtons();
}
}
});
// Lay out the undo/redo buttons.
Box undoRedoBox = new Box(BoxLayout.X_AXIS);
undoRedoBox.add(Box.createGlue());
undoRedoBox.add(undoButton);
undoRedoBox.add(Box.createHorizontalStrut(2));
undoRedoBox.add(redoButton);
undoRedoBox.add(Box.createGlue());
// Lay out the main frame.
getContentPane().setLayout(new BorderLayout());
getContentPane().add(buttonBox, BorderLayout.CENTER);
getContentPane().add(undoRedoBox, BorderLayout.SOUTH);
setSize(400, 150);
}
public class SimpleUEListener implements UndoableEditListener {
// When an UndoableEditEvent is generated (each time one of the buttons
// is pressed), we add it to the UndoManager and then get the manager's
// undo/redo names and set the undo/redo button labels. Finally, we
// enable/disable these buttons by asking the manager what we are
// allowed to do.
public void undoableEditHappened(UndoableEditEvent ev) {
manager.addEdit(ev.getEdit());
updateButtons();
}
}
// Method to set the text and state of the undo/redo buttons.
protected void updateButtons() {
undoButton.setText(manager.getUndoPresentationName());
redoButton.setText(manager.getRedoPresentationName());
undoButton.getParent().validate();
undoButton.setEnabled(manager.canUndo());
redoButton.setEnabled(manager.canRedo());
}
// Main program just creates the frame and displays it.
public static void main(String[] args) {
JFrame f = new UndoableToggleApp3();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
//UndoableJToggleButton.java
//Sample undoable toggle button class. Supports only a single listener to
//simplify the code.
//
class UndoableJToggleButton extends JToggleButton {
private UndoableEditListener listener;
// For this example, we'll just provide one constructor . . .
public UndoableJToggleButton(String txt) {
super(txt);
}
// Set the UndoableEditListener.
public void addUndoableEditListener(UndoableEditListener l) {
listener = l; // Should ideally throw an exception if listener != null
}
// Remove the UndoableEditListener.
public void removeUndoableEditListener(UndoableEditListener l) {
listener = null;
}
// We override this method to call the super implementation first (to fire
// the
// action event) and then fire a new UndoableEditEvent to our listener.
protected void fireActionPerformed(ActionEvent ev) {
// Fire the ActionEvent as usual.
super.fireActionPerformed(ev);
if (listener != null) {
listener.undoableEditHappened(new UndoableEditEvent(this,
new UndoableToggleEdit(this)));
}
}
}
//UndoableToggleEdit.java
//An UndoableEdit used to undo the pressing of a JToggleButton.
//
class UndoableToggleEdit extends AbstractUndoableEdit {
private JToggleButton button;
private boolean selected;
// Create a new edit for a JToggleButton that has just been toggled.
public UndoableToggleEdit(JToggleButton button) {
this.button = button;
selected = button.isSelected();
}
// Return a reasonable name for this edit.
public String getPresentationName() {
return "Toggle " + button.getText() + " " + (selected ? "on" : "off");
}
// Redo by setting the button state as it was initially.
public void redo() throws CannotRedoException {
super.redo();
button.setSelected(selected);
}
// Undo by setting the button state to the opposite value.
public void undo() throws CannotUndoException {
super.undo();
button.setSelected(!selected);
}
}
Related examples in the same category