Draw beautiful diagram effortlessly on ipad. Click here to know more..

Sunday, April 1, 2012

How to implement UndoManager (with example in Java on Android)

Undo-redo is a must-to-have feature in editing programs. This blog post describes how to implement undo-redo in your program. The example taken here is in Java but the concept is very simple and can be implemented easily in any language. 
Here is idea to implement the undo-redo. First of all you need these: UndoManager - a class that implements undo-redo features. UserAction - an abstract base class for all user actions.
The operations in the UndoManager are: undo, redo, canUndo, canRedo, addAction And the operations in UserAction are: perform, undo
As said above, the UserAction abstracts user actions which user can undo. For example in text editing program, inserting a character at a particular cursor location is an action which user can undo. So you need to implement this abstract class for all type of user's undo-able actions. 
Lets start with some real code. The code here is taken from an Android app "Scratchpad" 
This is a simple drawing program using touch. User can draw on the screen using touch dragging on Android tablet screen. So the user action,in this case, is draw a stroke on canvas. A stroke is defined as the drawing done between users actions of starting touch drag and stopping touch drag. Here is UndoManager class:
import java.util.*;
public class UndoManager {
 private UndoManager(){
  undoActions = new Stack();
  redoActions = new Stack();
 }
 public boolean canUndo(){
  return undoActions.size() > 0;
 }
 public boolean canRedo(){
  return redoActions.size() > 0;
 }
 public void undo(){
  if(canUndo()){
   UserAction act = this.undoActions.pop();
   act.undo();
   redoActions.push(act);
  }
 }
 public void redo(){
  if(canRedo()){
   UserAction act = this.redoActions.pop();
   act.perform();
   undoActions.add(act);
  }
 }
 public void add(UserAction action){
  this.undoActions.push(action);
  this.redoActions.clear();
 }
 private Stack undoActions;
 private Stack redoActions;
}

The code for UserAction
public abstract class UserAction {
 public abstract void perform();
 public abstract void undo();
}
Here is code for StrokeAction
public class StrokeAction extends UserAction{
 public StrokeAction(DrawingStroke ds){
  this.stroke = ds;
 }
 @Override
 public void perform(){
  ObjectStore.instance.addObject(stroke);
 }
 @Override
 public void undo(){
  ObjectStore.instance.removeObject(stroke);
 }
 private DrawingStroke stroke;
}

Whenever the user completes a drawing stroke in Scratchpad, an object of DrawingAction is created. The ObjectManager in the code above contains the all stroke objects. Whenever user performs a drawing, we add the stroke to object manager. The drawing of all available objects are managed ObjectManager. And when user wants to undo, we simply remove the stroke from object manager. For simplicity and readability, I am not adding the code of ObjectManager here. 

The code of UndoManager and UserAction is very generic and can be used any application. UserActions has to be implemented for for each undo-able user action type. This implementation will be application dependent.