diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 26eb97cf491..f1559b77167 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -31,6 +31,7 @@ #include #include #include +#include using namespace Layouting; @@ -84,6 +85,8 @@ public: BaseAspect::DataCreator m_dataCreator; BaseAspect::DataCloner m_dataCloner; QList 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. diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 793dcbb7bbd..35773ce7d25 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -15,9 +15,12 @@ #include #include +#include + 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 T *aspect() const { @@ -900,4 +908,61 @@ private: std::unique_ptr 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 QTCREATOR_UTILS_EXPORT UndoableValue +{ +public: + class UndoCmd : public QUndoCommand + { + public: + UndoCmd(UndoableValue *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 *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