Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm currently implementing an undo/redo mechanism using the Command Pattern. Everything works so far. My problem now is to implement the undo/redo functionality in a way that it is bound to a given context.

Assume the following situation:
You have win1 and win2. In win1 you execute action1; then you switch to win2 and you execute action2 and action3. You "undo-stack" would look as follows

  • action3
  • action2
  • action1

Now what happens if win1 gets closed/removed and you start performing undos. At action1 the program would probably crash as the context is has been executed against previously (i.e. win1) doesn't exist any more. As such, when win1 gets closed, all the corresponding actions should be removed from the "undo-stack".

My question is on whether there exist already implementations/best practices for implementing such scenario properly? Or do you have any ideas?

share|improve this question

2 Answers 2

What happens if win1 gets closed/removed? To answer this question, ask you another one: is the action reversible?

1. Case where the closing/removal action is reversible:

The closing/removal event is recorded in the undo stack, and when the user is performing undos, it un-does the closing/removal.

For example, when a user removes, through your application, a file win1, the app should not remove the file, but only mark it as a candidate for removal; then, a potential undo will un-mark the file.

2. Case of irreversible actions:

If you're talking about irreversible actions, given that the reversibility is not depending of your application, then deal with it, for example by disabling the corresponding undo elements.

For example, you're writing a tool which manages server farms, and at a given moment, the server win1 is materially unplugged from the network. In this case, your application can't replug the server, since it requires human intervention.

The application should then adapt its behavior in a more intuitive way: cancel or undos anterior to the irreversible one, skip the irreversible action, or something radically different and innovative. It's up to your interaction designer to come with the most intuitive way.

This is not much different from a case such as when your application tries to access a database, but the database is offline: you can't do anything about it, and the way you behave depends on the precise context.

Example:

Let's take an example from your comment: the removal of an Excel sheet. The successive actions are:

  1. Change the cell A1 in sheet 1,
  2. Change the cell A1 in sheet 2,
  3. Remove the sheet 1.

Two possible behaviors would be:

  1. The reversibility of sheet removal. Strangely, Excel team have chosen to not make it reversible. While this is probably motivated by some technical aspects I ignore, this behavior is totally wrong UX-wise. As a user, when by mistake I destroy a sheet, I expect to be able to get it back by pressing Ctrl+Z.

    Not being able to do that makes it risky to use Excel, since I can never know what could be reverted, and what could result in a loss of work. That's not nice at all.

  2. The impossibility to remove the sheet with the loss of "Change the cell A1 in sheet 1" step in the undo stack after the removal. Technically, it's not so difficult. Imagine the following structure:

    class undoEntry
    {
        string text; // Text which is displayed to the user in the undo history.
        sheet? correspondingSheet; // The sheet where the action happened, or null.
        undoAction action; // The action to undo.
    }
    

    With correspondingSheet property, you can then walk though the undo stack when a sheet is removed, and delete the entries you shouldn't display any longer.

share|improve this answer
    
Also, removing items from the middle of an undo/redo stack can be problematic because the state of the items around them will depend on those changes. –  GalacticCowboy Mar 8 '13 at 17:19
    
@GalacticCowboy: True. I haven't thought about that. –  MainMa Mar 8 '13 at 17:20
    
Hmm..I'm talking about a more practical example. Try it with Excel (just to mention a program). Add a value in sheet1, then go ahead to sheet2 and add other values. Take a look at the undo stack (arrow down of the undo button). Now remove sheet1; your action about writing in sheet1 is no more in the stack, it has been removed. Pratically, how would you implement such behavior in your program. I do not expect code, just implementation strategies. (Note, removing a sheet is also not reversible) –  Juri Mar 8 '13 at 17:35

Context is important from a programming/technical standpoint, as well as, usability. Your Excel comment is a good example. Several documents and then worksheets could be in the same instance of Excel and your undo would go across them (assuming you made recent actions on different ones), but this wouldn't happen in another instance of Excel or from Excel to Word.

Users may be able to provide the context where they see the line drawn with this functionality. Microsoft could have built this functionality in the context of all open Office applications. I wouldn't like it as a user eventhough it is technically possible.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.