summaryrefslogtreecommitdiffstats
path: root/src/widgets/util
diff options
context:
space:
mode:
authorAddison Elliott <addison.elliott@gmail.com>2016-12-02 12:17:07 -0600
committerAddison Elliott <addison.elliott@gmail.com>2017-01-02 13:31:25 +0000
commit00ad7bd5a492ff5bce306c53024714670e59039e (patch)
treeda6451c9ea3d6743039edb4f948f01bdc90860fb /src/widgets/util
parentafda26ce5d0534d85219a2fe858aa0e05037cf09 (diff)
Added isObsolete and setObsolete functions in QUndoStack
Added isObsolete and setObsolete functions to QUndoCommand that signifies a command is not functional. This is useful for when two commands are merged in such a way that the merged command does nothing. Another particular use is with networking commands in which the command fails due to connection issues. The command is considered obsolete because the undo/redo functions do nothing since the connection failed. This property is checked in QUndoStack::push(), QUndoStack::undo(), QUndoStack::redo(), and QUndoStack::setIndex(). The obsolete flag is checked after QUndoCommand::undo(), QUndoCommand::redo(), and QUndoCommand::mergeWith() is called where applicable. This allows the user to set the obsolete flag within the QUndoCommand class and it will be deleted directly afterwards. Task-number: QTBUG-54970 Change-Id: Ia8e962ff3aa16515e8f9e2180aee5e1d726d5ba3 Reviewed-by: David Faure <david.faure@kdab.com>
Diffstat (limited to 'src/widgets/util')
-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
3 files changed, 147 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