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 <QSettings>
#include <QSpinBox> #include <QSpinBox>
#include <QTextEdit> #include <QTextEdit>
#include <QUndoStack>
using namespace Layouting; using namespace Layouting;
@@ -84,6 +85,8 @@ public:
BaseAspect::DataCreator m_dataCreator; BaseAspect::DataCreator m_dataCreator;
BaseAspect::DataCloner m_dataCloner; BaseAspect::DataCloner m_dataCloner;
QList<BaseAspect::DataExtractor> m_dataExtractors; 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 bool BaseAspect::isEnabled() const
{ {
return d->m_enabled; return d->m_enabled;
@@ -2645,6 +2671,14 @@ bool AspectContainer::isDirty()
return false; 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 bool AspectContainer::equals(const AspectContainer &other) const
{ {
// FIXME: Expensive, but should not really be needed in a fully aspectified world. // FIXME: Expensive, but should not really be needed in a fully aspectified world.

View File

@@ -15,9 +15,12 @@
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <QUndoCommand>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QAction; class QAction;
class QSettings; class QSettings;
class QUndoStack;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace Layouting { class LayoutItem; } namespace Layouting { class LayoutItem; }
@@ -81,6 +84,10 @@ public:
bool isAutoApply() const; bool isAutoApply() const;
virtual void setAutoApply(bool on); virtual void setAutoApply(bool on);
virtual void setUndoStack(QUndoStack *undoStack);
QUndoStack *undoStack() const;
void pushUndo(QUndoCommand *cmd);
bool isEnabled() const; bool isEnabled() const;
void setEnabled(bool enabled); void setEnabled(bool enabled);
void setEnabler(BoolAspect *checker); void setEnabler(BoolAspect *checker);
@@ -862,6 +869,7 @@ public:
void copyFrom(const AspectContainer &other); void copyFrom(const AspectContainer &other);
void setAutoApply(bool on) override; void setAutoApply(bool on) override;
bool isDirty() override; bool isDirty() override;
void setUndoStack(QUndoStack *undoStack) override;
template <typename T> T *aspect() const template <typename T> T *aspect() const
{ {
@@ -900,4 +908,61 @@ private:
std::unique_ptr<Internal::AspectContainerPrivate> d; 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 } // namespace Utils