Skip to content

Instantly share code, notes, and snippets.

@deyindra
Created June 4, 2017 06:32
Show Gist options
  • Save deyindra/5f4e7337fa8f70ad53664defca644770 to your computer and use it in GitHub Desktop.
Save deyindra/5f4e7337fa8f70ad53664defca644770 to your computer and use it in GitHub Desktop.
UndoRedoList
import java.util.List;
import java.util.Objects;
abstract class AbstractListCommand<T> {
protected final String opName;
protected final int index;
protected T newObject;
protected T oldObject;
protected AbstractListCommand(final int index, final String opName) {
this.index = index;
this.opName = opName;
}
protected void validate(List<T> list, boolean isSizeInclusive){
if(index<0 || (isSizeInclusive? index>=list.size() : index>list.size())){
throw new IllegalArgumentException("Invalid Index "+index);
}
}
protected abstract void undo(List<T> list);
protected abstract void redo(List<T> list);
@Override
public String toString() {
return String.format("Operation: %s, index: %s, " +
"newObject: %s, oldObject %s",
opName,index,
Objects.toString(newObject, "null"),
Objects.toString(oldObject, "null"));
}
}
import java.util.List;
public class AddCommand<T> extends AbstractListCommand<T> {
public AddCommand(final int index, T newObject) {
super(index, "ADD");
this.newObject = newObject;
}
@Override
protected void undo(List<T> list) {
validate(list,true);
this.newObject = list.remove(index);
}
@Override
protected void redo(List<T> list) {
validate(list,false);
list.add(index,newObject);
}
}
import java.util.List;
public class DeleteCommand<T> extends AbstractListCommand<T> {
public DeleteCommand(final int index) {
super(index, "DELETE");
}
@Override
protected void undo(List<T> list) {
validate(list,false);
list.add(index, newObject);
}
@Override
protected void redo(List<T> list) {
validate(list,true);
this.newObject = list.remove(index);
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class UndoRedoList<T> {
private List<T> list;
private Stack<AbstractListCommand<T>> undoStack;
private Stack<AbstractListCommand<T>> redoStack;
private AbstractListCommand<T> currentCommand;
public UndoRedoList() {
list = new ArrayList<>();
undoStack = new Stack<>();
redoStack = new Stack<>();
currentCommand = null;
}
private void execute(int index, T object, Operation op){
AbstractListCommand<T> prevCommand = currentCommand;
if(op == Operation.ADD){
currentCommand = new AddCommand<>(index,object);
}else if (op == Operation.UPDATE){
currentCommand = new UpdateCommand<>(index,object);
}else if(op == Operation.DELETE){
currentCommand = new DeleteCommand<>(index);
}
undoStack.push(prevCommand);
currentCommand.redo(list);
}
public void add(T object){
add(list.size(),object);
}
public void add(int index, T object){
execute(index,object, Operation.ADD);
}
public void remove(T object){
int index = list.indexOf(object);
remove(index);
}
public void remove(int index){
execute(index,null,Operation.DELETE);
}
public void update(int index, T object){
execute(index,object,Operation.UPDATE);
}
public void undo(){
if(!canUndo()){
throw new IllegalStateException("Can not undo!!");
}
currentCommand.undo(list);
redoStack.push(currentCommand);
currentCommand = undoStack.pop();
}
public void redo(){
if(!canRedo()){
throw new IllegalStateException("Can not redo!!");
}
AbstractListCommand<T> prevCommand = currentCommand;
undoStack.push(prevCommand);
currentCommand = redoStack.pop();
currentCommand.redo(list);
}
public boolean canUndo(){
return !undoStack.isEmpty();
}
public boolean canRedo(){
return !redoStack.isEmpty();
}
@Override
public String toString() {
return "UndoRedoList{" +
"list=" + list +
'}';
}
private enum Operation{
ADD, UPDATE, DELETE
}
}
import java.util.List;
public class UpdateCommand<T> extends AbstractListCommand<T> {
public UpdateCommand(final int index, T newObject) {
super(index, "UPDATE");
this.newObject = newObject;
}
@Override
protected void undo(List<T> list) {
validate(list,true);
this.newObject = list.set(index, oldObject);
}
@Override
protected void redo(List<T> list) {
validate(list,true);
this.oldObject = list.set(index, newObject);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment