import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.undo.*;

/**
  Application-wide undo manager for Mozart.
  This class contains everything Mozart needs to use in order
  to have undo/redo capabilities. It's important to note that 
  the developer must call the instantiated undoManager inorder
  to get the correct actions. <BR>
  I.e. mozart.getUndoManager().getUndoAction();<BR>
  <br><a href="../source/MozartUndoManager.java">View Source File</a>
*/
public class MozartUndoManager implements UndoableEditListener {
  protected UndoAction undoAction;
  protected RedoAction redoAction;
  protected UndoManager undo;

  /** Creates a new UndoAction, RedoAction and UndoManager */
  public MozartUndoManager() {
    undoAction = new UndoAction();
    redoAction = new RedoAction();
    undo = new UndoManager();
  }

  /** 
    The Action used in menus and toolbars.
    This abstract action knows when the application can
    be undoed.
  */
  class UndoAction extends AbstractAction {
    public UndoAction() {
      super("Undo");
      setEnabled(false);
    }
    
    public void actionPerformed(ActionEvent e) {
      try {
	undo.undo();
      } catch (CannotUndoException ex) {
	System.out.println("Unable to undo: " + ex);
      }
      undoAction.update();
      redoAction.update();
    }
    
    protected void update() {
      if (undo.canUndo()) {
	setEnabled(true);
	putValue(Action.NAME, undo.getUndoPresentationName());
      } else {
	setEnabled(false);
	putValue(Action.NAME, "Undo");
      }
    }      
  }
  
  /** 
    RedoAction used in menus and toolbars.
    This abstract action knows when the application can
    be undoed.
  */
  class RedoAction extends AbstractAction {
    public RedoAction() {
      super("Redo");
      setEnabled(false);
    }
    
    public void actionPerformed(ActionEvent e) {
      try {
	undo.redo();
      } catch (CannotRedoException ex) {
	System.out.println("Unable to redo: " + ex);
	ex.printStackTrace();
      }
      undoAction.update();
      redoAction.update();
    }
    
    protected void update() {
      if (undo.canRedo()) {
	setEnabled(true);
	putValue(Action.NAME, undo.getRedoPresentationName());
      } else {
	setEnabled(false);
	putValue(Action.NAME, "Redo");
      }
    }
  }    
  

  /**
    This method listens for edits that can be undone.
    If the developer makes this class the UndoableEventListener
    for any new document added to the application, then the
    undos and redos will be taken care of.
  */
  public void undoableEditHappened(UndoableEditEvent e) {
    //Remember the edit and update the menus
    undo.addEdit(e.getEdit());
    undoAction.update();
    redoAction.update();
  }

  /** Returns the UndoAction associated with this object. */
  public Action getUndoAction() {
    return undoAction;
  }

  /** Returns the RedoAction associated with this object. */
  public Action getRedoAction() {
    return redoAction;
  }
}
