Project: sikuli
package org.sikuli.guide;
/*
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(300150); 
    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); 
  } 
}