Dmitry Kurgansky
Dmitry Kurgansky

Reputation: 96

Using children/parent of QUndoCommand to push several commands to undo stack at once

I am implementing editable tree with undo stack, using QUndoStack. Remove node requires removing all it's offsprings. I am using child QUndoCommand for this:

Header:

class RemoveNodeCommand : QUndoCommand
{
public:
    RemoveNodeCommand(NodesContainer *cont, int node_id, QUndoCommand *parent = 0);
    void undo();
    void redo();

private:
    NodeParams mParams;
    NodesContainer *mCont;
};

Command implementation:

RemoveNodeCommand::RemoveNodeCommand(NodesContainer *cont, int node_id, QUndoCommand *parent)
{
    QList<int> offsprings_ids;
    QUndoCommand *tmpcomm;

    //Keep params of deleted notes to use in Undo if necessary
    mParams = cont->getNogeParams();
    mCont = cont;

    //List all offsprings of node to be deleted
    cont->getOffspringsIds(&offsprings_ids);

    for(int co = 0; co < basket.size(); co++)
    {
        tmpcomm = new RemoveNodeCommand(cont, offsprings_ids.at(co), this);
    }
}

void RemoveNodeCommand::redo()
{
    mCont->deleteNode(mParams);
}

Slot in tree editing class:

RemoveNodeSlot(int id)
{
     mUndoStack->push( new RemoveNodeCommand(mContainer, id));
}

In QUndoStack documentation it is indicated that
If parent is not 0, this command is appended to parent's child list.,
and it's true, child_list of parent command is increased each time new child command created. However, pushing parent does not lead to pushing all it's children. redo() is called only for parent node.
What I'm doing wrong? Do I need to push all children manually? And, as I need all this commands inside single undo step, I'll need to use beginMacro and endMacro? But this way, holding pointers to children commands in QUndoCommand is senseless. I guess t is not QT fault, but my misunderstanding of undo stack conception. How to use child commands mechanism correctly?

Upvotes: 4

Views: 1197

Answers (2)

wolpers
wolpers

Reputation: 131

The child command constructor needs to pass the parent argument to the QUndoCommand constructor:

RemoveNodeCommand::RemoveNodeCommand(NodesContainer *cont, int node_id, QUndoCommand *parent) 
: QUndoCommand(parent) {
// ...
}

Because you use a single class for parent and child you also need to call through to the parent's undo+redo methods as explained by Dmitry Kurgansky

Upvotes: 1

Dmitry Kurgansky
Dmitry Kurgansky

Reputation: 96

It is necessary to call default implementation of QUndoCommand::undo() and QUndoCommand::redo() in nested implementations. In redo() default implementation must be added before processing data, and in undo() - after all tree data proceed.

void RemoveNodeCommand::redo()
{
    QUndoCommand::redo();
    mCont->deleteNode(mParams);
}

Upvotes: 4

Related Questions