summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/widgets/util/qundostack.cpp156
-rw-r--r--src/widgets/util/qundostack.h3
-rw-r--r--src/widgets/util/qundostack_p.h3
-rw-r--r--tests/auto/widgets/util/qundostack/tst_qundostack.cpp765
4 files changed, 912 insertions, 15 deletions
diff --git a/src/widgets/util/qundostack.cpp b/src/widgets/util/qundostack.cpp
index 59d517e77b..cfca5787cb 100644
--- a/src/widgets/util/qundostack.cpp
+++ b/src/widgets/util/qundostack.cpp
@@ -145,6 +145,36 @@ QUndoCommand::~QUndoCommand()
}
/*!
+ \since 5.9
+
+ Returns whether the command is obsolete.
+
+ The boolean is used for the automatic removal of commands that are not necessary in the
+ stack anymore. The isObsolete function is checked in the functions QUndoStack::push(),
+ QUndoStack::undo(), QUndoStack::redo(), and QUndoStack::setIndex().
+
+ \sa setObsolete(), mergeWith(), QUndoStack::push(), QUndoStack::undo(), QUndoStack::redo()
+*/
+
+bool QUndoCommand::isObsolete() const
+{
+ return d->obsolete;
+}
+
+/*!
+ \since 5.9
+
+ Sets whether the command is obsolete.
+
+ \sa isObsolete(), mergeWith(), QUndoStack::push(), QUndoStack::undo(), QUndoStack::redo()
+*/
+
+void QUndoCommand::setObsolete(bool obsolete)
+{
+ d->obsolete = obsolete;
+}
+
+/*!
Returns the ID of this command.
A command ID is used in command compression. It must be an integer unique to
@@ -390,6 +420,28 @@ const QUndoCommand *QUndoCommand::child(int index) const
and to update the document's title to reflect that it contains unsaved
changes.
+ \section1 Obsolete Commands
+
+ QUndoStack is able to delete commands from the stack if the command is no
+ longer needed. One example may be to delete a command when two commands are
+ merged together in such a way that the merged command has no function. This
+ can be seen with move commands where the user moves their mouse to one part
+ of the screen and then moves it to the original position. The merged command
+ results in a mouse movement of 0. This command can be deleted since it serves
+ no purpose. Another example is with networking commands that fail due to connection
+ issues. In this case, the command is to be removed from the stack because the redo()
+ and undo() functions have no function since there was connection issues.
+
+ A command can be marked obsolete with the QUndoCommand::setObsolete() function.
+ The QUndoCommand::isObsolete() flag is checked in QUndoStack::push(),
+ QUndoStack::undo(), QUndoStack::redo(), and QUndoStack::setIndex() after calling
+ QUndoCommand::undo(), QUndoCommand::redo() and QUndoCommand:mergeWith() where
+ applicable.
+
+ If a command is set obsolete and the clean index is greater than or equal to the
+ current command index, then the clean index will be reset when the command is
+ deleted from the stack.
+
\sa QUndoCommand, QUndoView
*/
@@ -563,6 +615,11 @@ void QUndoStack::clear()
commands by calling QUndoCommand::mergeWith() on the most recently executed
command. If QUndoCommand::mergeWith() returns \c true, \a cmd is deleted.
+ After calling QUndoCommand::redo() and, if applicable, QUndoCommand::mergeWith(),
+ QUndoCommand::isObsolete() will be called for \a cmd or the merged command.
+ If QUndoCommand::isObsolete() returns \c true, then \a cmd or the merged command
+ will be deleted from the stack.
+
In all other cases \a cmd is simply pushed on the stack.
If commands were undone before \a cmd was pushed, the current command and
@@ -580,7 +637,8 @@ void QUndoStack::clear()
void QUndoStack::push(QUndoCommand *cmd)
{
Q_D(QUndoStack);
- cmd->redo();
+ if (!cmd->isObsolete())
+ cmd->redo();
bool macro = !d->macro_stack.isEmpty();
@@ -605,13 +663,25 @@ void QUndoStack::push(QUndoCommand *cmd)
if (try_merge && cur->mergeWith(cmd)) {
delete cmd;
- if (!macro) {
- emit indexChanged(d->index);
- emit canUndoChanged(canUndo());
- emit undoTextChanged(undoText());
- emit canRedoChanged(canRedo());
- emit redoTextChanged(redoText());
+
+ if (macro) {
+ if (cur->isObsolete())
+ delete d->macro_stack.constLast()->d->child_list.takeLast();
+ } else {
+ if (cur->isObsolete()) {
+ delete d->command_list.takeLast();
+
+ d->setIndex(d->index - 1, false);
+ } else {
+ emit indexChanged(d->index);
+ emit canUndoChanged(canUndo());
+ emit undoTextChanged(undoText());
+ emit canRedoChanged(canRedo());
+ emit redoTextChanged(redoText());
+ }
}
+ } else if (cmd->isObsolete()) {
+ delete cmd; // command should be deleted and NOT added to the stack
} else {
if (macro) {
d->macro_stack.constLast()->d->child_list.append(cmd);
@@ -710,6 +780,11 @@ int QUndoStack::cleanIndex() const
If the stack is empty, or if the bottom command on the stack has already been
undone, this function does nothing.
+ After the command is undone, if QUndoCommand::isObsolete() returns \c true,
+ then the command will be deleted from the stack. Additionally, if the clean
+ index is greater than or equal to the current command index, then the clean
+ index is reset.
+
\sa redo(), index()
*/
@@ -725,7 +800,18 @@ void QUndoStack::undo()
}
int idx = d->index - 1;
- d->command_list.at(idx)->undo();
+ QUndoCommand *cmd = d->command_list.at(idx);
+
+ if (!cmd->isObsolete())
+ cmd->undo();
+
+ if (cmd->isObsolete()) { // A separate check is done b/c the undo command may set obsolete flag
+ delete d->command_list.takeAt(idx);
+
+ if (d->clean_index > idx)
+ resetClean();
+ }
+
d->setIndex(idx, false);
}
@@ -736,6 +822,11 @@ void QUndoStack::undo()
If the stack is empty, or if the top command on the stack has already been
redone, this function does nothing.
+ If QUndoCommand::isObsolete() returns true for the current command, then
+ the command will be deleted from the stack. Additionally, if the clean
+ index is greater than or equal to the current command index, then the clean
+ index is reset.
+
\sa undo(), index()
*/
@@ -750,8 +841,20 @@ void QUndoStack::redo()
return;
}
- d->command_list.at(d->index)->redo();
- d->setIndex(d->index + 1, false);
+ int idx = d->index;
+ QUndoCommand *cmd = d->command_list.at(idx);
+
+ if (!cmd->isObsolete())
+ cmd->redo(); // A separate check is done b/c the undo command may set obsolete flag
+
+ if (cmd->isObsolete()) {
+ delete d->command_list.takeAt(idx);
+
+ if (d->clean_index > idx)
+ resetClean();
+ } else {
+ d->setIndex(d->index + 1, false);
+ }
}
/*!
@@ -803,10 +906,35 @@ void QUndoStack::setIndex(int idx)
idx = d->command_list.size();
int i = d->index;
- while (i < idx)
- d->command_list.at(i++)->redo();
- while (i > idx)
- d->command_list.at(--i)->undo();
+ while (i < idx) {
+ QUndoCommand *cmd = d->command_list.at(i);
+
+ if (!cmd->isObsolete())
+ cmd->redo(); // A separate check is done b/c the undo command may set obsolete flag
+
+ if (cmd->isObsolete()) {
+ delete d->command_list.takeAt(i);
+
+ if (d->clean_index > i)
+ resetClean();
+
+ idx--; // Subtract from idx because we removed a command
+ } else {
+ i++;
+ }
+ }
+
+ while (i > idx) {
+ QUndoCommand *cmd = d->command_list.at(--i);
+
+ cmd->undo();
+ if (cmd->isObsolete()) {
+ delete d->command_list.takeAt(i);
+
+ if (d->clean_index > i)
+ resetClean();
+ }
+ }
d->setIndex(idx, false);
}
diff --git a/src/widgets/util/qundostack.h b/src/widgets/util/qundostack.h
index ca918b0618..2a8f4decb6 100644
--- a/src/widgets/util/qundostack.h
+++ b/src/widgets/util/qundostack.h
@@ -69,6 +69,9 @@ public:
QString actionText() const;
void setText(const QString &text);
+ bool isObsolete() const;
+ void setObsolete(bool obsolete);
+
virtual int id() const;
virtual bool mergeWith(const QUndoCommand *other);
diff --git a/src/widgets/util/qundostack_p.h b/src/widgets/util/qundostack_p.h
index 1bfe992426..e92a1fe620 100644
--- a/src/widgets/util/qundostack_p.h
+++ b/src/widgets/util/qundostack_p.h
@@ -66,11 +66,12 @@ class QUndoGroup;
class QUndoCommandPrivate
{
public:
- QUndoCommandPrivate() : id(-1) {}
+ QUndoCommandPrivate() : id(-1), obsolete(false) {}
QList<QUndoCommand*> child_list;
QString text;
QString actionText;
int id;
+ bool obsolete;
};
#ifndef QT_NO_UNDOSTACK
diff --git a/tests/auto/widgets/util/qundostack/tst_qundostack.cpp b/tests/auto/widgets/util/qundostack/tst_qundostack.cpp
index 8576e237ec..11a29b808c 100644
--- a/tests/auto/widgets/util/qundostack/tst_qundostack.cpp
+++ b/tests/auto/widgets/util/qundostack/tst_qundostack.cpp
@@ -95,6 +95,23 @@ public:
virtual void redo();
};
+class MoveMouseCommand : public QUndoCommand
+{
+public:
+ MoveMouseCommand(QPoint *mouse, QPoint oldPoint, QPoint newPoint, QUndoCommand *parent = 0);
+ ~MoveMouseCommand();
+
+ virtual void undo();
+ virtual void redo();
+ virtual int id() const;
+ virtual bool mergeWith(const QUndoCommand *other);
+
+private:
+ QPoint *m_mouse;
+ QPoint m_oldPoint;
+ QPoint m_newPoint;
+};
+
InsertCommand::InsertCommand(QString *str, int idx, const QString &text,
QUndoCommand *parent)
: QUndoCommand(parent)
@@ -215,6 +232,48 @@ void IdleCommand::undo()
{
}
+MoveMouseCommand::MoveMouseCommand(QPoint *mouse, QPoint oldPoint, QPoint newPoint, QUndoCommand *parent)
+ : QUndoCommand(parent)
+{
+ setText("move mouse");
+
+ m_mouse = mouse;
+ m_oldPoint = oldPoint;
+ m_newPoint = newPoint;
+
+ if (m_oldPoint == m_newPoint)
+ setObsolete(true);
+}
+
+MoveMouseCommand::~MoveMouseCommand()
+{
+}
+
+void MoveMouseCommand::redo()
+{
+ *m_mouse = m_newPoint;
+}
+
+void MoveMouseCommand::undo()
+{
+ *m_mouse = m_oldPoint;
+}
+
+int MoveMouseCommand::id() const
+{
+ return 2;
+}
+
+bool MoveMouseCommand::mergeWith(const QUndoCommand *other)
+{
+ m_newPoint = static_cast<const MoveMouseCommand*>(other)->m_newPoint;
+
+ if (m_newPoint == m_oldPoint)
+ setObsolete(true);
+
+ return true;
+}
+
/******************************************************************************
** tst_QUndoStack
*/
@@ -233,6 +292,7 @@ private slots:
void childCommand();
void macroBeginEnd();
void compression();
+ void obsolete();
void undoLimit();
void commandTextFormat();
void separateUndoText();
@@ -2563,6 +2623,711 @@ void tst_QUndoStack::compression()
true); // redoChanged
}
+void tst_QUndoStack::obsolete()
+{
+ QUndoStack stack;
+ const QScopedPointer<QAction> undoAction(stack.createUndoAction(0, QString("foo")));
+ const QScopedPointer<QAction> redoAction(stack.createRedoAction(0, QString("bar")));
+ QSignalSpy indexChangedSpy(&stack, &QUndoStack::indexChanged);
+ QSignalSpy cleanChangedSpy(&stack, &QUndoStack::cleanChanged);
+ QSignalSpy canUndoChangedSpy(&stack, &QUndoStack::canUndoChanged);
+ QSignalSpy undoTextChangedSpy(&stack, &QUndoStack::undoTextChanged);
+ QSignalSpy canRedoChangedSpy(&stack, &QUndoStack::canRedoChanged);
+ QSignalSpy redoTextChangedSpy(&stack, &QUndoStack::redoTextChanged);
+ QPoint mouse(0, 0);
+ QString str;
+ MoveMouseCommand *cmd1 = 0;
+ MoveMouseCommand *cmd2 = 0;
+
+ stack.resetClean();
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 0, // count
+ 0, // index
+ false, // canUndo
+ "", // undoText
+ false, // canRedo
+ "", // redoText
+ true, // cleanChanged
+ false, // indexChanged
+ false, // undoChanged
+ false); // redoChanged
+
+ stack.push(new MoveMouseCommand(&mouse, mouse, QPoint(0, 0))); // #1 should not merge but will be deleted (b/c oldPoint == newPoint)
+ QCOMPARE(mouse, QPoint(0, 0));
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 0, // count
+ 0, // index
+ false, // canUndo
+ "", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ false, // indexChanged
+ false, // undoChanged
+ false); // redoChanged
+
+ stack.push(new MoveMouseCommand(&mouse, mouse, QPoint(12, 0))); // #2 should not merge or be deleted (b/c oldPoint != newPoint)
+ QCOMPARE(mouse, QPoint(12, 0));
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 1, // count
+ 1, // index
+ true, // canUndo
+ "move mouse", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+ stack.push(new MoveMouseCommand(&mouse, mouse, QPoint(8, 2))); // #3 should merge and not be deleted (b/c oldPoint != newPoint)
+ QCOMPARE(mouse, QPoint(8, 2));
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 1, // count
+ 1, // index
+ true, // canUndo
+ "move mouse", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+ stack.push(new MoveMouseCommand(&mouse, mouse, QPoint(0, 0))); // #4 should merge and be deleted (b/c oldPoint == newPoint)
+ QCOMPARE(mouse, QPoint(0, 0));
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 0, // count
+ 0, // index
+ false, // canUndo
+ "", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+
+
+
+ stack.push(new InsertCommand(&str, 0, "ene")); // #5 should not merge or be deleted
+ QCOMPARE(str, QString("ene"));
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 1, // count
+ 1, // index
+ true, // canUndo
+ "insert", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+ cmd1 = new MoveMouseCommand(&mouse, mouse, QPoint(6, 5));
+ stack.push(cmd1); // #6 should not merge or be deleted (b/c oldPoint != newPoint)
+ QCOMPARE(mouse, QPoint(6, 5));
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 2, // count
+ 2, // index
+ true, // canUndo
+ "move mouse", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+ stack.push(new InsertCommand(&str, 3, "ma")); // #7 should not merge or be deleted
+ QCOMPARE(str, QString("enema"));
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 3, // count
+ 3, // index
+ true, // canUndo
+ "insert", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+ cmd2 = new MoveMouseCommand(&mouse, mouse, QPoint(12, 4));
+ stack.push(cmd2); // #8 should not merge or be deleted (b/c oldPoint != newPoint)
+ QCOMPARE(mouse, QPoint(12, 4));
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 4, // count
+ 4, // index
+ true, // canUndo
+ "move mouse", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+ stack.setClean();
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ true, // clean
+ 4, // count
+ 4, // index
+ true, // canUndo
+ "move mouse", // undoText
+ false, // canRedo
+ "", // redoText
+ true, // cleanChanged
+ false, // indexChanged
+ false, // undoChanged
+ false); // redoChanged
+ QCOMPARE(stack.cleanIndex(), 4);
+
+ cmd2->setObsolete(true);
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ true, // clean
+ 4, // count
+ 4, // index
+ true, // canUndo
+ "move mouse", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ false, // indexChanged
+ false, // undoChanged
+ false); // redoChanged
+
+ stack.undo();
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 3, // count
+ 3, // index
+ true, // canUndo
+ "insert", // undoText
+ false, // canRedo
+ "", // redoText
+ true, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+ QCOMPARE(stack.cleanIndex(), -1);
+
+ stack.undo();
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 3, // count
+ 2, // index
+ true, // canUndo
+ "move mouse", // undoText
+ true, // canRedo
+ "insert", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+ stack.setClean();
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ true, // clean
+ 3, // count
+ 2, // index
+ true, // canUndo
+ "move mouse", // undoText
+ true, // canRedo
+ "insert", // redoText
+ true, // cleanChanged
+ false, // indexChanged
+ false, // undoChanged
+ false); // redoChanged
+ QCOMPARE(stack.cleanIndex(), 2);
+
+ stack.undo();
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 3, // count
+ 1, // index
+ true, // canUndo
+ "insert", // undoText
+ true, // canRedo
+ "move mouse", // redoText
+ true, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+ cmd1->setObsolete(true);
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 3, // count
+ 1, // index
+ true, // canUndo
+ "insert", // undoText
+ true, // canRedo
+ "move mouse", // redoText
+ false, // cleanChanged
+ false, // indexChanged
+ false, // undoChanged
+ false); // redoChanged
+
+ stack.redo();
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 2, // count
+ 1, // index
+ true, // canUndo
+ "insert", // undoText
+ true, // canRedo
+ "insert", // redoText
+ false, // cleanChanged
+ false, // indexChanged
+ false, // undoChanged
+ false); // redoChanged
+ QCOMPARE(stack.cleanIndex(), -1);
+
+ stack.redo();
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 2, // count
+ 2, // index
+ true, // canUndo
+ "insert", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+ QCOMPARE(stack.cleanIndex(), -1);
+
+ cmd1 = new MoveMouseCommand(&mouse, mouse, QPoint(13, 2));
+ stack.push(cmd1); // #9 should not merge or be deleted (b/c oldPoint != newPoint)
+ QCOMPARE(mouse, QPoint(13, 2));
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 3, // count
+ 3, // index
+ true, // canUndo
+ "move mouse", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+ stack.push(new InsertCommand(&str, 3, "ma")); // #10 should not merge or be deleted
+ QCOMPARE(str, QString("enemama"));
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 4, // count
+ 4, // index
+ true, // canUndo
+ "insert", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+ cmd2 = new MoveMouseCommand(&mouse, mouse, QPoint(6, 20));
+ stack.push(cmd2); // #11 should not merge or be deleted (b/c oldPoint != newPoint)
+ QCOMPARE(mouse, QPoint(6, 20));
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 5, // count
+ 5, // index
+ true, // canUndo
+ "move mouse", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+ cmd1->setObsolete(true);
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 5, // count
+ 5, // index
+ true, // canUndo
+ "move mouse", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ false, // indexChanged
+ false, // undoChanged
+ false); // redoChanged
+
+ stack.setClean();
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ true, // clean
+ 5, // count
+ 5, // index
+ true, // canUndo
+ "move mouse", // undoText
+ false, // canRedo
+ "", // redoText
+ true, // cleanChanged
+ false, // indexChanged
+ false, // undoChanged
+ false); // redoChanged
+ QCOMPARE(stack.cleanIndex(), 5);
+
+ stack.setIndex(0);
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 4, // count
+ 0, // index
+ false, // canUndo
+ "", // undoText
+ true, // canRedo
+ "insert", // redoText
+ true, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+ QCOMPARE(stack.cleanIndex(), -1);
+
+ cmd2->setObsolete(true);
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 4, // count
+ 0, // index
+ false, // canUndo
+ "", // undoText
+ true, // canRedo
+ "insert", // redoText
+ false, // cleanChanged
+ false, // indexChanged
+ false, // undoChanged
+ false); // redoChanged
+
+ stack.setIndex(stack.count());
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 3, // count
+ 3, // index
+ true, // canUndo
+ "insert", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+ mouse = QPoint(0, 0); // Reset mouse position
+ stack.beginMacro("ding");
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 4, // count
+ 3, // index
+ false, // canUndo
+ "", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ false, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+
+ stack.push(new MoveMouseCommand(&mouse, mouse, QPoint(7, 7))); // #12 should not merge or be deleted (b/c oldPoint != newPoint & in macro)
+ QCOMPARE(mouse, QPoint(7, 7));
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 4, // count
+ 3, // index
+ false, // canUndo
+ "", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ false, // indexChanged
+ false, // undoChanged
+ false); // redoChanged
+
+ stack.push(new MoveMouseCommand(&mouse, mouse, QPoint(0, 0))); // #13 should merge and be deleted (b/c oldPoint = newPoint)
+ QCOMPARE(mouse, QPoint(0, 0));
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 4, // count
+ 3, // index
+ false, // canUndo
+ "", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ false, // indexChanged
+ false, // undoChanged
+ false); // redoChanged
+
+ stack.endMacro();
+ checkState(redoTextChangedSpy,
+ canRedoChangedSpy,
+ undoTextChangedSpy,
+ redoAction,
+ undoAction,
+ canUndoChangedSpy,
+ cleanChangedSpy,
+ indexChangedSpy,
+ stack,
+ false, // clean
+ 4, // count
+ 4, // index
+ true, // canUndo
+ "ding", // undoText
+ false, // canRedo
+ "", // redoText
+ false, // cleanChanged
+ true, // indexChanged
+ true, // undoChanged
+ true); // redoChanged
+}
+
void tst_QUndoStack::undoLimit()
{
QUndoStack stack;