QUndoStack is quite cool.

QUndoStack sounds simple enough. It is a Qt class that is used to implement ,,Undo'' functionality in your programs. A stack of objects that implement QUndoCommand subclass. QUndoCommand interface is made of two methods: undo() and redo(). What can be simpler?

I've tried to use QUndoStack in the magazynier, a sokoban game for KDE4 I'm writing. I must say it proved to be way more useful than I thought.

At first I planned to implement a subclass of QUndoCommand for each move combination possible in the game: move from a goal or an empty place to another goal or empty place, possibly pushing a box. Each such object would know how to move one or two game objects on the board.

It worked OK, but seemed to be overly complicated. I wasn't satisfied with this set of boilerplate QUndoCommand subclasses and a messy factory method implementing bulk of the game logic.

The solution I discovered (with great help from people on #qt on irc.freenode.net) is that QUndoCommands can be composed together into trees. QUndoCommand constructor accepts an optional parent parameter. You can create one top-level command object and then attach multiple sub-commands to it to create more complex macro-commands.

Walking this tree is as simple as it gets — QUndoCommand undo() and redo() methods do exactly that. In the subclass you can overload redo() method with a method that does whatever your application needs to do and then calls base implementation of QUndoCommand::redo(). The command's sub-commands will be executed automatically. The same for undo() method.

The design I've come up with is that I've derived 5 QUndoCommand subclasses. There's macro-command root which is used to increment/decrement move counters, and there are 4 subclasses that move objects on the board. The factory method that puts together those trees is still quite messy with lots of nested if-statements, but once you create a command it's execution is very straightforward.

Niels Slot implemented mouse navigation in magazynier. I'm quite confident that it will be very easy to put all the moves found by the pathfinder in a single command and execute it in one go.