Commit 21f7c023 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implement an ability for an undo command to be annihilated when merged with another command

Basically, when the user changes visibility to and fro, the undo step
should be removed.

parent ef6de07c
......@@ -339,6 +339,29 @@ bool KUndo2Command::timedMergeWith(KUndo2Command *other)
return false;
return true;
Attempts to merge this command with \a command and checks if the two commands
compensate each other. If the function returns true, both commands are removed
from the stack.
If this function returns true, calling this command's redo() followed by
\p other redo() must have no effect.
The function itself shouln't do any changes to the command, because
after returning true, the command will be deleted as a "noop"
KUndo2QStack will only try to merge two commands if they have the same id, and
the id is not -1.
The default implementation returns false.
\sa id() KUndo2QStack::push()
bool KUndo2Command::annihilateWith(const KUndo2Command *other)
return false;
void KUndo2Command::setTime()
m_timeOfCreation = QTime::currentTime();
......@@ -823,7 +846,27 @@ void KUndo2QStack::push(KUndo2Command *cmd)
m_index = m_command_list.size();
if (try_merge && cur->mergeWith(cmd)) {
if (try_merge && !macro && cur->annihilateWith(cmd)) {
delete cmd;
if (!macro) {
// this condition must be ruled out by try_merge check
// otherwise we would have to do cleanup for the clean state
Q_ASSERT(m_clean_index != m_index);
delete m_command_list.takeLast();
emit indexChanged(m_index);
emit canUndoChanged(canUndo());
emit undoTextChanged(undoText());
emit canRedoChanged(canRedo());
emit redoTextChanged(redoText());
} else {
delete m_macro_stack.takeLast();
} else if (try_merge && cur->mergeWith(cmd)) {
delete cmd;
if (!macro) {
emit indexChanged(m_index);
......@@ -104,6 +104,8 @@ public:
virtual bool mergeWith(const KUndo2Command *other);
virtual bool timedMergeWith(KUndo2Command *other);
virtual bool annihilateWith(const KUndo2Command *other);
int childCount() const;
const KUndo2Command *child(int index) const;
......@@ -117,6 +117,15 @@ bool KisNodePropertyListCommand::canMergeWith(const KUndo2Command *command) cons
changedProperties(other->m_oldPropertyList, other->m_newPropertyList));
bool KisNodePropertyListCommand::annihilateWith(const KUndo2Command *command)
const KisNodePropertyListCommand *other =
dynamic_cast<const KisNodePropertyListCommand*>(command);
return other && other->m_node == m_node &&
changedProperties(m_oldPropertyList, other->m_newPropertyList).isEmpty();
bool checkOnionSkinChanged(const KisBaseNode::PropertyList &oldPropertyList,
const KisBaseNode::PropertyList &newPropertyList)
......@@ -30,6 +30,7 @@ public:
int id() const override;
bool mergeWith(const KUndo2Command *command) override;
bool canMergeWith(const KUndo2Command *command) const override;
bool annihilateWith(const KUndo2Command *other) override;
typedef KisBaseNode::PropertyList PropertyList;
static void setNodePropertiesAutoUndo(KisNodeSP node, KisImageSP image, PropertyList proplist);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment