Utils: Add Undo facilities for aspects

Change-Id: I2a8acfa23b3a4303414be21af224b08c13561666
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Marcus Tillmanns
2023-09-12 07:34:53 +02:00
parent 8bcec807d9
commit 66c8eda943
2 changed files with 99 additions and 0 deletions

View File

@@ -31,6 +31,7 @@
#include <QSettings>
#include <QSpinBox>
#include <QTextEdit>
#include <QUndoStack>
using namespace Layouting;
@@ -84,6 +85,8 @@ public:
BaseAspect::DataCreator m_dataCreator;
BaseAspect::DataCloner m_dataCloner;
QList<BaseAspect::DataExtractor> m_dataExtractors;
QUndoStack *m_undoStack = nullptr;
};
/*!
@@ -302,6 +305,29 @@ void BaseAspect::setToolTip(const QString &tooltip)
}
}
void BaseAspect::setUndoStack(QUndoStack *undoStack)
{
d->m_undoStack = undoStack;
}
QUndoStack *BaseAspect::undoStack() const
{
return d->m_undoStack;
}
void BaseAspect::pushUndo(QUndoCommand *cmd)
{
if (!cmd)
return;
if (d->m_undoStack)
d->m_undoStack->push(cmd);
else {
cmd->redo();
delete cmd;
}
}
bool BaseAspect::isEnabled() const
{
return d->m_enabled;
@@ -2645,6 +2671,14 @@ bool AspectContainer::isDirty()
return false;
}
void AspectContainer::setUndoStack(QUndoStack *undoStack)
{
BaseAspect::setUndoStack(undoStack);
for (BaseAspect *aspect : std::as_const(d->m_items))
aspect->setUndoStack(undoStack);
}
bool AspectContainer::equals(const AspectContainer &other) const
{
// FIXME: Expensive, but should not really be needed in a fully aspectified world.

View File

@@ -15,9 +15,12 @@
#include <memory>
#include <optional>
#include <QUndoCommand>
QT_BEGIN_NAMESPACE
class QAction;
class QSettings;
class QUndoStack;
QT_END_NAMESPACE
namespace Layouting { class LayoutItem; }
@@ -81,6 +84,10 @@ public:
bool isAutoApply() const;
virtual void setAutoApply(bool on);
virtual void setUndoStack(QUndoStack *undoStack);
QUndoStack *undoStack() const;
void pushUndo(QUndoCommand *cmd);
bool isEnabled() const;
void setEnabled(bool enabled);
void setEnabler(BoolAspect *checker);
@@ -862,6 +869,7 @@ public:
void copyFrom(const AspectContainer &other);
void setAutoApply(bool on) override;
bool isDirty() override;
void setUndoStack(QUndoStack *undoStack) override;
template <typename T> T *aspect() const
{
@@ -900,4 +908,61 @@ private:
std::unique_ptr<Internal::AspectContainerPrivate> d;
};
// Because QObject cannot be a template
class QTCREATOR_UTILS_EXPORT UndoSignaller : public QObject
{
Q_OBJECT
public:
void emitChanged() { emit changed(); }
signals:
void changed();
};
template<class T>
class QTCREATOR_UTILS_EXPORT UndoableValue
{
public:
class UndoCmd : public QUndoCommand
{
public:
UndoCmd(UndoableValue<T> *value, const T &oldValue, const T &newValue)
: m_value(value)
, m_oldValue(oldValue)
, m_newValue(newValue)
{}
void undo() override { m_value->setInternal(m_oldValue); }
void redo() override { m_value->setInternal(m_newValue); }
private:
UndoableValue<T> *m_value;
T m_oldValue;
T m_newValue;
};
QUndoCommand *set(const T &value)
{
if (m_value == value)
return nullptr;
return new UndoCmd(this, m_value, value);
}
void setSilently(const T &value) { m_value = value; }
T get() const { return m_value; }
UndoSignaller m_signal;
private:
void setInternal(const T &value)
{
m_value = value;
m_signal.emitChanged();
}
private:
T m_value;
};
} // namespace Utils