Archive for the ‘Programming’ Category

Challenges in implementing the Undo Redo functionality

Here are some of the points to be noted

  • Undo/Redo is an EDIT operation

Operation1 + Undo(on Operation1) = 2 Edit operations.

This will mean that the state of the object(lastModified) is changed even though there is no change in the content.

Hence any mechanism to know whether there are any changes made to the ObjectModel state must be based on the difference in the content and cannot just be based on its lastModified info.

  • Maintaining the edits in a Stack(FirstInLastOut behaviour) will enforce the undo/redo implementation to be sequential in the reverse order in which the operations were performed. It cannot offer the flexibility to offer the undo/redo functionality for the edits which need not correspond to the latest edit operation.
  • Each edit must implement the CanUndo() and CanRedo() to validate the undo/redo operation. This is very essential to ensure that the object model on which edit operation is performed via the undo/redo implementation does not push the underlying object model to an Invalid state.

Each edit might have a cached object instance associated with it when the edit is initialized. When trying to perform the Undo/Redo operation using the cached object, validation is must to ensure that using the cached object doesnt push the underlying object model to an Invalid State, resulting in a total disaster.

  • Each edit must implement Dispose() to ensure that objects cached in the edit are disposed and they don’t eat up the memory.

In addition to all these, for a robust implementation of undo/redo here are some tips

1. Undo Redo for an edit operation on the objectModel should only be dependent on the objects in the objectModel. It should never be dependent on the objects used in the UI which are used for displaying the content of the objectModel.

2.  Always update the object model before updating the UI, so that the UI displayed will always truly represents the object model.

3. The undo/redo implementation will deal with cached instance of the object model but working with caching instances of the UI objects should be avoided and instead the UI objects which represent the object model must be retreived at run time.

Implementing Undo/Redo

Here is a code snippet for implementing the Undo/Redo.

Sample Code

</pre>
//interface defining the edit
 <strong> public interface IUndoableEdit</strong>
 {

//Perform the Undo operation
 bool Undo();

//Perform the Redo operation
 bool Redo();

//validates whether Undo operation can be performed on this edit   //in the current context
 bool CanUndo();

//validates whether Redo operation can be performed on this edit   //in the current context
 bool CanRedo();

void Dispose();

}

//Class providing the infrastructure for manging the IUndoableEdits
 <strong> public class UndoStack</strong>
 {
 //stack is used to store the edits..First In Last Out

private Stack undoStack;
 private Stack redoStack;

public UndoStack()
 {
 //initialize the stack
 redoStack = new Stack(100);
 undoStack = new Stack(100);
 }

public void AddEdit(IUndoableEdit  edit)
 {
 //validate input arguments
 undoStack.Push(edit);
 }

//Clear all the edits stored in the Stack.
 public void ClearAll()
 {
 undoStack.Clear();
 redoStack.Clear();
 }

public void Undo()
 {
 if(undoStack.Count == 0)
 {
 Console.Beep();
 return;
 }

IUndoableEdit edit = undoStack.Pop();

if(edit.CanUndo() && edit.Undo())
 {
 if(edit.CanRedo() )
 {
 redoStack.Push(edit)
 }
 }
 else
 {
 edit.Dispose();
 }

}

public void Redo()
 {
 if(redoStack.Count == 0)
 {
 Console.Beep();
 return;
 }

IUndoableEdit edit = redoStack.Pop();

if(edit.CanRedo() && edit.Redo())
 {
 if(edit.CanUndo() )
 {
 undoStack.Push(edit)
 }
 }
 else
 {
 edit.Dispose();
 }

}

}
<pre>

Explore the Undo/Redo – Part II

Here is the list of the types and variations of the Undo/Redo functionalty.

1.Blind Undo/Redo

The Undo/Redo functionality without specifying the operation which will be performed.

2.Instructional Undo/Redo

The menu item offering the Undo/Redo functionality also displays the operation which will performed. This makes use of the DisplayName of the edit to be performed.

3.Single Undo/Redo

The typical notepad style supporting Undo/Redo only for the last operation performed.

4.Multiple Undo/Redo

Multiple Undo/Redo supports unlimited no of edits for all the opertaions performed.

5.Multiple Undo/Redo with the UI to choose the number of edits.

Its the typical MS word style. The UI(toolBar Button) shows the DisplayName of  all the edits in the Undo/Redo stack providing the option to choose the multiple edits to be performed. This provides the option of performing Undo on the last N opertaion at one shot.

More sophisticated implementation would be allow the user to choose the edit which need not correspond to the last edit operation.

For Eg:

Operation 1- Delete a line

OPeration2- Find Replace operation performed for a particular word

What if user wants to perform Undo for operation1 but NOT for operation2?

My next post will be on the Challenges that I faced in implementing Multiple (Instructional) Undo/Redo .

Explore the Undo/Redo – Part I

Imagine preparing your project report in MS Word without having to use Ctrl Z/Y. You will bulb for sure, its going to be very very painful.

That’s the power of Undo/Redo. We take it for granted in any standard, user-friendly software.

  • It acts as a Saviour, during the times of distress
  • It makes the learning process like a ride on a Highway.
  • It allows the users to explore the software with a confidence that he can always recover easily from the mistakes, during the learning process.

Q. But why does a computer application need the Undo/Redo functionality, when the underlying piece of code will never ever go wrong it its output. You run the same operation 1000 times with the same inputs you are guaranteed to get the same output every time?

Ans. The Undo/Redo is meant for the User and not the application itself. Yes the computer program never makes a mistake but humans do. They are by default error prone.

What the designed applications treats as an invalid input for an operation might be a perfectly valid input from the users side.

The role of Undo/Redo comes into picture when an error(s) is made and the user realises it and express a strong intent to recover from the mistake(s) made.

The application must always assume that the user is always right.

Let’s solve the Recursion

The code posted below is a very simple recursive code for performing the search operation. Reading the code will force you to follow a visually cyclic path but instead visualising the search operation as a traversal along the tree from the root node to the leaf node of the last top level node follows a straight visual path.

Most of the single recursive methods can be split into group of atomic methods .

//iterate the collection (this is where the recursion is imposed)

//validate the input object against the object of interest

——————————————————————–

//Finds the first treeNode encountered in the Hunt operation, which is tagged to the //specified object.

//Returns Null, if the search operation fails to find a node tagged to the object specified Or if the specified object/nodeCollection is Null.
private TreeNode FindNode(object taggedObject, TreeNodeCollection nodes)
{
//validate inputs
if (taggedObject == null || nodes == null)
{ return null; }

TreeNode nodeToReturn = null;
foreach (TreeNode node in nodes)
{
if (Equals(node.Tag, taggedObject))
{
return node;
}

//Now search in children of this node.
nodeToReturn = FindNode(taggedObject, node.Nodes);
if (nodeToReturn != null)
{
return nodeToReturn;
}
}
//no matching node found. Hence return null!!
return null;
}

Coding vs Programming

Coding is a mere typing exercise to express the logical sequence of steps in the form of a well indented paragraph. It is specific to syntax and the language.

Programming is problem solving exercise, which forces you think continuously. Its a two step process.

First and the most crucial step is to “Define the Problem Statement”. This is the most important and difficult step as all the use cases which needs to be satisfied must be clearly identified. The accuracy of the solution will depend on this step. This doesn’t depend on how you express. It could be a flow chart or diagrams depicting the problem statement.

Second step is to provide a logical sequence of the steps. The elegance, re-usability and scalability of the solution will depend on this step, as domain/technology specific knowledge is essential.

After some experience in using the msdn, I am confident that any software technology can be easily learnt by spending some time with a well documented API.

Hence a solid first step, is essential for a rock solid solution.