UndoManager.java
/*
* @(#)UndoManager.java
*
* Project: JHotdraw - a GUI framework for technical drawings
* http://www.jhotdraw.org
* http://jhotdraw.sourceforge.net
* Copyright: © by the original author(s) and all contributors
* License: Lesser GNU Public License (LGPL)
* http://www.opensource.org/licenses/lgpl-license.html
*/
package CH.ifa.draw.util;
import CH.ifa.draw.framework.*;
import java.util.*;
/**
* This class manages all the undoable commands. It keeps track of all
* the modifications done through user interactions.
*
* @version <$CURRENT_VERSION$>
*/
public class UndoManager {
/**
* Maximum default buffer size for undo and redo stack
*/
public static final int DEFAULT_BUFFER_SIZE = 20;
/**
* Collection of undo activities
*/
private Vector redoStack;
/**
* Collection of undo activities
*/
private Vector undoStack;
private int maxStackCapacity;
public UndoManager() {
this(DEFAULT_BUFFER_SIZE);
}
public UndoManager(int newUndoStackSize) {
maxStackCapacity = newUndoStackSize;
undoStack = new Vector(maxStackCapacity);
redoStack = new Vector(maxStackCapacity);
}
public void pushUndo(Undoable undoActivity) {
if (undoActivity.isUndoable()) {
// If buffersize exceeds, remove the oldest command
if (getUndoSize() >= maxStackCapacity) {
undoStack.removeElementAt(0);
}
undoStack.addElement(undoActivity);
}
else {
// a not undoable activity clears the stack because
// the last activity does not correspond with the
// last undo activity
undoStack = new Vector(maxStackCapacity);
}
}
public void pushRedo(Undoable redoActivity) {
if (redoActivity.isRedoable()) {
// If buffersize exceeds, remove the oldest command
if (getRedoSize() >= maxStackCapacity) {
redoStack.removeElementAt(0);
}
// add redo activity only if it is not already the last
// one in the buffer
if ((getRedoSize() == 0) || (peekRedo() != redoActivity)) {
redoStack.addElement(redoActivity);
}
}
else {
// a not undoable activity clears the tack because
// the last activity does not correspond with the
// last undo activity
redoStack = new Vector(maxStackCapacity);
}
}
public boolean isUndoable() {
if (getUndoSize() > 0) {
return ((Undoable)undoStack.lastElement()).isUndoable();
}
else {
return false;
}
}
public boolean isRedoable() {
if (getRedoSize() > 0) {
return ((Undoable)redoStack.lastElement()).isRedoable();
}
else {
return false;
}
}
protected Undoable peekUndo() {
if (getUndoSize() > 0) {
return (Undoable) undoStack.lastElement();
}
else {
return null;
}
}
protected Undoable peekRedo() {
if (getRedoSize() > 0) {
return (Undoable) redoStack.lastElement();
}
else {
return null;
}
}
/**
* Returns the current size of undo buffer.
*/
public int getUndoSize() {
return undoStack.size();
}
/**
* Returns the current size of redo buffer.
*/
public int getRedoSize() {
return redoStack.size();
}
/**
* Throw NoSuchElementException if there is none
*/
public Undoable popUndo() {
// Get the last element - throw NoSuchElementException if there is none
Undoable lastUndoable = peekUndo();
// Remove it from undo collection
undoStack.removeElementAt(getUndoSize() - 1);
return lastUndoable;
}
/**
* Throw NoSuchElementException if there is none
*/
public Undoable popRedo() {
// Get the last element - throw NoSuchElementException if there is none
Undoable lastUndoable = peekRedo();
// Remove it from undo collection
redoStack.removeElementAt(getRedoSize() - 1);
return lastUndoable;
}
public void clearUndos() {
clearStack(undoStack);
}
public void clearRedos() {
clearStack(redoStack);
}
protected void clearStack(Vector clearStack) {
clearStack.removeAllElements();
}
}