summaryrefslogtreecommitdiffstats
path: root/src/dm/systems/Qt3DSDMTransactions.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/dm/systems/Qt3DSDMTransactions.h')
-rw-r--r--src/dm/systems/Qt3DSDMTransactions.h244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/dm/systems/Qt3DSDMTransactions.h b/src/dm/systems/Qt3DSDMTransactions.h
new file mode 100644
index 0000000..f6ed3da
--- /dev/null
+++ b/src/dm/systems/Qt3DSDMTransactions.h
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** Copyright (C) 1993-2009 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#ifndef QT3DSDM_TRANSACTIONS_H
+#define QT3DSDM_TRANSACTIONS_H
+#include "Qt3DSDMDataTypes.h"
+#include "StandardExtensions.h"
+#include <functional>
+
+namespace qt3dsdm {
+
+/**
+ * Transaction is some small entity that changes data. A transaction consumer is expected to
+ *execute
+ * a list of these either forward on a "redo" command or backwards on an "undo" command.
+ *
+ * Transactions merely change data. There are two other lists on consumers for "do"
+ *notifications
+ * and "undo" notifications. These lists control the events sent out to the UI about what
+ *actually
+ * changed in the model. Note that undo/do notifications may be more clever than simple
+ *send-signal
+ * commands in that they may check if an object is alive or not before sending a notification
+ *and may
+ * decline to send a notification if the target object is not currently alive.
+ *
+ * Currently the undo/redo system first executes all of the transactions and then sends the
+ *appropriate
+ * notifications. This means that when the UI receives any notification, the model is in its
+ *most-updated
+ * state.
+ */
+class ITransaction
+{
+public:
+ const char *m_File;
+ int m_Line;
+
+ ITransaction(const char *inFile, int inLine)
+ : m_File(inFile)
+ , m_Line(inLine)
+ {
+ }
+ virtual ~ITransaction() {}
+ virtual void Do() = 0;
+ virtual void Undo() = 0;
+};
+
+/**
+ * Merging allows us to efficient handle situations where the users are continuously
+ * modifying an object (or set of objects). These are referred to as live-update
+ * scenarios. Dragging an object in the 3d view or dragging keyframes in the timeline
+ * would be an example of live-update scenarios.
+ */
+template <typename TValueType>
+class IMergeableTransaction
+{
+public:
+ virtual ~IMergeableTransaction() {}
+ // Called when a new value has arrived and we would rather update
+ // an existing representation rather than create a new one.
+ virtual void Update(const TValueType &inValue) = 0;
+};
+
+/**
+ * A consumer is an object that records the transaction. This interface keeps the
+ * base producer objects from binding to how the transaction or the notifications
+ * are stored.
+ */
+class ITransactionConsumer
+{
+public:
+ virtual ~ITransactionConsumer() {}
+ virtual void OnTransaction(std::shared_ptr<ITransaction> inTransaction) = 0;
+ // Notifications to be sent for undo/redo These are used to
+ // notify clients that something is different.
+ virtual void OnDoNotification(std::function<void()> inNotification) = 0;
+ virtual void OnUndoNotification(std::function<void()> inNotification) = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Implementation of helper objects and functions.
+///////////////////////////////////////////////////////////////////////////////
+
+typedef std::vector<std::function<void()>> TVoidFunctionList;
+
+typedef std::shared_ptr<ITransactionConsumer> TTransactionConsumerPtr;
+
+class ITransactionProducer
+{
+public:
+ virtual ~ITransactionProducer() {}
+ virtual void SetConsumer(TTransactionConsumerPtr inConsumer) = 0;
+};
+
+template <typename TDoTransaction, typename TUndoTransaction>
+class CGenericTransaction : public ITransaction
+{
+ Q_DISABLE_COPY(CGenericTransaction)
+
+ TUndoTransaction m_UndoTransaction;
+ TDoTransaction m_DoTransaction;
+
+public:
+ CGenericTransaction(const char *inFile, int inLine, TDoTransaction inDo,
+ TUndoTransaction inUndo)
+ : ITransaction(inFile, inLine)
+ , m_UndoTransaction(inUndo)
+ , m_DoTransaction(inDo)
+ {
+ }
+ void Do() override { m_DoTransaction(); }
+ void Undo() override { m_UndoTransaction(); }
+};
+
+template <typename TDoTransaction, typename TUndoTransaction>
+ITransaction *DoCreateGenericTransaction(const char *inFile, int inLine, TDoTransaction inDo,
+ TUndoTransaction inUndo)
+{
+ return static_cast<ITransaction *>(
+ new CGenericTransaction<TDoTransaction, TUndoTransaction>(inFile, inLine, inDo, inUndo));
+}
+
+#define CREATE_GENERIC_TRANSACTION(inDo, inUndo) \
+ DoCreateGenericTransaction(__FILE__, __LINE__, inDo, inUndo)
+
+typedef std::shared_ptr<ITransaction> TTransactionPtr;
+typedef std::vector<TTransactionPtr> TTransactionPtrList;
+
+struct CTransactionConsumer : public ITransactionConsumer
+{
+ TTransactionPtrList m_TransactionList;
+ TVoidFunctionList m_DoNotifications;
+ TVoidFunctionList m_UndoNotifications;
+ void OnTransaction(TTransactionPtr inTransaction) override
+ {
+ m_TransactionList.push_back(inTransaction);
+ }
+ void OnDoNotification(std::function<void()> inNotification) override
+ {
+ m_DoNotifications.push_back(inNotification);
+ }
+ void OnUndoNotification(std::function<void()> inNotification) override
+ {
+ m_UndoNotifications.push_back(inNotification);
+ }
+
+ // Merge with another CTransactionConsumer
+ virtual void Merge(const ITransactionConsumer *inConsumer)
+ {
+ const CTransactionConsumer *theConsumer =
+ static_cast<const CTransactionConsumer *>(inConsumer);
+ m_TransactionList.insert(m_TransactionList.begin(), theConsumer->m_TransactionList.begin(),
+ theConsumer->m_TransactionList.end());
+ }
+ void Reset()
+ {
+ m_TransactionList.clear();
+ m_DoNotifications.clear();
+ m_UndoNotifications.clear();
+ }
+};
+
+template <typename TTransactionType>
+inline void RunWithConsumer(TTransactionConsumerPtr inConsumer, TTransactionType inTransaction)
+{
+ if (inConsumer)
+ inTransaction(inConsumer);
+}
+
+template <typename TDoTransaction, typename TUndoTransaction>
+inline void CreateGenericTransactionWithConsumer(const char *inFile, int inLine,
+ TTransactionConsumerPtr inConsumer,
+ TDoTransaction inDoTransaction,
+ TUndoTransaction inUndoTransaction)
+{
+ if (inConsumer)
+ inConsumer->OnTransaction(TTransactionPtr(
+ DoCreateGenericTransaction(inFile, inLine, inDoTransaction, inUndoTransaction)));
+}
+
+template <typename TItemType>
+inline void DoSetConsumer(TTransactionConsumerPtr inConsumer,
+ std::shared_ptr<TItemType> inTypePtr)
+{
+ ITransactionProducer *theProducer = dynamic_cast<ITransactionProducer *>(inTypePtr.get());
+ if (theProducer)
+ theProducer->SetConsumer(inConsumer);
+}
+
+template <typename TContainer>
+inline void Undo(TContainer &inTransactions)
+{
+ std::for_each(inTransactions.rbegin(), inTransactions.rend(), std::bind(&ITransaction::Undo,
+ std::placeholders::_1));
+}
+
+template <typename TContainer>
+inline void Redo(TContainer &inTransactions)
+{
+ do_all(inTransactions, std::bind(&ITransaction::Do, std::placeholders::_1));
+}
+
+template <typename TItemType>
+void Notify(std::vector<TItemType> &inNotifications)
+{
+ do_all(inNotifications, std::bind(&TItemType::operator(), std::placeholders::_1));
+}
+
+template <typename TItemType>
+void NotifyReverse(std::vector<TItemType> &inNotifications)
+{
+ std::for_each(inNotifications.rbegin(), inNotifications.rend(),
+ std::bind(&TItemType::operator(), std::placeholders::_1));
+}
+}
+
+#endif