/*
Definitive Guide to Swing for Java 2, Second Edition
By John Zukowski
ISBN: 1-893115-78-X
Publisher: APress
*/
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JToolBar;
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;
import javax.swing.undo.UndoableEditSupport;
public class UndoDrawing {
public static void main(String args[]) {
JFrame frame = new JFrame("Drawing Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
UndoableDrawingPanel drawingPanel = new UndoableDrawingPanel();
UndoManager manager = new UndoManager();
drawingPanel.addUndoableEditListener(manager);
JToolBar toolbar = new JToolBar();
toolbar.add(UndoManagerHelper.getUndoAction(manager));
toolbar.add(UndoManagerHelper.getRedoAction(manager));
Container content = frame.getContentPane();
content.add(toolbar, BorderLayout.NORTH);
content.add(drawingPanel, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
class UndoableDrawingPanel extends JPanel {
UndoableEditSupport undoableEditSupport = new UndoableEditSupport(this);
Polygon polygon = new Polygon();
public UndoableDrawingPanel() {
MouseListener mouseListener = new MouseAdapter() {
public void mouseReleased(MouseEvent mouseEvent) {
undoableEditSupport.postEdit(new UndoableDrawEdit(
UndoableDrawingPanel.this));
polygon.addPoint(mouseEvent.getX(), mouseEvent.getY());
repaint();
}
};
addMouseListener(mouseListener);
}
public void addUndoableEditListener(
UndoableEditListener undoableEditListener) {
undoableEditSupport.addUndoableEditListener(undoableEditListener);
}
public void removeUndoableEditListener(
UndoableEditListener undoableEditListener) {
undoableEditSupport.removeUndoableEditListener(undoableEditListener);
}
public void setPolygon(Polygon newValue) {
polygon = newValue;
repaint();
}
public Polygon getPolygon() {
Polygon returnValue;
if (polygon.npoints == 0) {
returnValue = new Polygon();
} else {
returnValue = new Polygon(polygon.xpoints, polygon.ypoints,
polygon.npoints);
}
return returnValue;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawPolygon(polygon);
}
}
class UndoManagerHelper {
public static Action getUndoAction(UndoManager manager, String label) {
return new UndoAction(manager, label);
}
public static Action getUndoAction(UndoManager manager) {
return new UndoAction(manager, "Undo");
}
public static Action getRedoAction(UndoManager manager, String label) {
return new RedoAction(manager, label);
}
public static Action getRedoAction(UndoManager manager) {
return new RedoAction(manager, "Redo");
}
private abstract static class UndoRedoAction extends AbstractAction {
UndoManager undoManager = new UndoManager();
String errorMessage = "Cannot undo";
String errorTitle = "Undo Problem";
protected UndoRedoAction(UndoManager manager, String name) {
super(name);
undoManager = manager;
}
public void setErrorMessage(String newValue) {
errorMessage = newValue;
}
public void setErrorTitle(String newValue) {
errorTitle = newValue;
}
protected void showMessage(Object source) {
if (source instanceof Component) {
JOptionPane.showMessageDialog((Component) source, errorMessage,
errorTitle, JOptionPane.WARNING_MESSAGE);
} else {
System.err.println(errorMessage);
}
}
}
public static class UndoAction extends UndoRedoAction {
public UndoAction(UndoManager manager, String name) {
super(manager, name);
setErrorMessage("Cannot undo");
setErrorTitle("Undo Problem");
}
public void actionPerformed(ActionEvent actionEvent) {
try {
undoManager.undo();
} catch (CannotUndoException cannotUndoException) {
showMessage(actionEvent.getSource());
}
}
}
public static class RedoAction extends UndoRedoAction {
String errorMessage = "Cannot redo";
String errorTitle = "Redo Problem";
public RedoAction(UndoManager manager, String name) {
super(manager, name);
setErrorMessage("Cannot redo");
setErrorTitle("Redo Problem");
}
public void actionPerformed(ActionEvent actionEvent) {
try {
undoManager.redo();
} catch (CannotRedoException cannotRedoException) {
showMessage(actionEvent.getSource());
}
}
}
}
class UndoableDrawEdit extends AbstractUndoableEdit {
UndoableDrawingPanel panel;
Polygon polygon, savedPolygon;
public UndoableDrawEdit(UndoableDrawingPanel panel) {
this.panel = panel;
polygon = panel.getPolygon();
}
public String getPresentationName() {
return "Polygon of size " + polygon.npoints;
}
public void redo() throws CannotRedoException {
super.redo();
if (savedPolygon == null) {
// Should never get here, as super() doesn't permit redoing
throw new CannotRedoException();
} else {
panel.setPolygon(savedPolygon);
savedPolygon = null;
}
}
public void undo() throws CannotUndoException {
super.undo();
savedPolygon = panel.getPolygon();
panel.setPolygon(polygon);
}
}