diff --git a/src/App/AutoTransaction.h b/src/App/AutoTransaction.h index 6318d5c7cf..747374eff5 100644 --- a/src/App/AutoTransaction.h +++ b/src/App/AutoTransaction.h @@ -31,31 +31,38 @@ namespace App class Application; -/// Helper class to manager transaction (i.e. undo/redo) +/** + * @brief A helper class to manage transactions (i.e. undo/redo). + * + * An AutoTransaction object is meant to be allocated on the stack and governs + * the transactions in that scope. + */ class AppExport AutoTransaction { public: - /// Private new operator to prevent heap allocation + /// Delete the new operator to prevent heap allocation. void* operator new(std::size_t) = delete; public: - /** Constructor + /** + * @brief Construct an auto transaction. * - * @param name: optional new transaction name on construction - * @param tmpName: if true and a new transaction is setup, the name given is + * @param[in] name: optional new transaction name on construction + * @param[in] tmpName: if true and a new transaction is setup, the name given is * considered as temporary, and subsequent construction of this class (or * calling Application::setActiveTransaction()) can override the transaction * name. * * The constructor increments an internal counter * (Application::_activeTransactionGuard). The counter prevents any new - * active transaction being setup. It also prevents close (i.e. commits) the - * current active transaction until it reaches zero. It does not have any - * effect on aborting transaction, though. + * active transactions being setup. It also prevents to close + * (i.e. commits) the current active transaction until it reaches zero. It + * does not have any effect on aborting transactions though. */ AutoTransaction(const char* name = nullptr, bool tmpName = false); - /** Destructor + /** + * @brief Destruct an auto transaction. * * This destructor decrease an internal counter * (Application::_activeTransactionGuard), and will commit any current @@ -63,15 +70,19 @@ public: */ ~AutoTransaction(); - /** Close or abort the transaction + /** + * @brief Close or abort the transaction. * * This function can be used to explicitly close (i.e. commit) the * transaction, if the current transaction ID matches the one created inside - * the constructor. For aborting, it will abort any current transaction + * the constructor. For aborting, it will abort any current transaction. + * + * @param[in] abort: if true, abort the transaction; otherwise, commit it. */ void close(bool abort = false); - /** Enable/Disable any AutoTransaction instance in the current stack + /** + * @brief Enable/Disable any AutoTransaction instance on the current stack. * * Once disabled, any empty temporary named transaction is closed. If there * are non-empty or non-temporary named active transaction, it will not be @@ -79,6 +90,8 @@ public: * * This function may be used in, for example, Gui::Document::setEdit() to * allow a transaction live past any command scope. + * + * @param[in] enable: if true, enable the AutoTransaction; otherwise, disable it. */ static void setEnable(bool enable); @@ -87,47 +100,55 @@ private: }; -/** Helper class to lock a transaction from being closed or aborted. +/** + * @brief Helper class to lock a transaction from being closed or aborted. * - * The helper class is used to protect some critical transaction from being + * The helper class is used to protect some critical transactions from being * closed prematurely, e.g. when deleting some object. */ class AppExport TransactionLocker { public: - /** Constructor - * @param lock: whether to activate the lock + + /** + * @brief Construct a transaction locker. + * + * @param[in] lock: whether to activate the lock */ TransactionLocker(bool lock = true); - /** Destructor - * Unlock the transaction is this locker is active + /** + * @brief Destruct a transaction locker. + * + * Unlock the transaction if this locker is active */ ~TransactionLocker(); - /** Activate or deactivate this locker - * @param enable: whether to activate the locker + /** + * @brief Activate or deactivate this locker. * * An internal counter is used to support recursive locker. When activated, * the current active transaction cannot be closed or aborted. But the * closing call (Application::closeActiveTransaction()) will be remembered, * and performed when the internal lock counter reaches zero. + * + * @param enable: whether to activate the locker */ void activate(bool enable); - /// Check if the locker is active + /// Check if the locker is active. bool isActive() const { return active; } - /// Check if transaction is being locked + /// Check if transaction is being locked. static bool isLocked(); friend class Application; public: - /// Private new operator to prevent heap allocation + /// Delete the new operator to prevent heap allocation. void* operator new(std::size_t) = delete; private: diff --git a/src/App/TransactionalObject.h b/src/App/TransactionalObject.h index dd4c86fdef..34832d9384 100644 --- a/src/App/TransactionalObject.h +++ b/src/App/TransactionalObject.h @@ -32,20 +32,40 @@ namespace App class Document; class TransactionObject; -/** Base class of transactional objects +/** + * @brief Base class of transactional objects. + * + * A transactional object provides functionality that is inherited by its + * children to ensure that these children objects can be targeted by a + * transaction. */ class AppExport TransactionalObject: public App::ExtensionContainer { PROPERTY_HEADER_WITH_OVERRIDE(App::TransactionalObject); public: - /// Constructor TransactionalObject(); ~TransactionalObject() override; + + /// Check if this object is attached to a document. virtual bool isAttachedToDocument() const; + + /** + * @brief Deteach this object from the document. + * + * @return the name of the document this object was attached to. + */ virtual const char* detachFromDocument(); protected: + /** + * @brief Notify the document that a property is about to be changed. + * + * This function is called before the property is changed. + * + * @param[in,out] doc the document this object is attached to. + * @param[in] prop the property that is about to be changed. + */ void onBeforeChangeProperty(Document* doc, const Property* prop); }; diff --git a/src/App/Transactions.cpp b/src/App/Transactions.cpp index ee4d944f04..aa6f989ae4 100644 --- a/src/App/Transactions.cpp +++ b/src/App/Transactions.cpp @@ -52,10 +52,6 @@ Transaction::Transaction(int id) transID = id; } -/** - * A destructor. - * A more elaborate description of the destructor. - */ Transaction::~Transaction() { auto& index = _Objects.get<0>(); @@ -291,16 +287,8 @@ TYPESYSTEM_SOURCE_ABSTRACT(App::TransactionObject, Base::Persistence) //************************************************************************** // Construction/Destruction -/** - * A constructor. - * A more elaborate description of the constructor. - */ TransactionObject::TransactionObject() = default; -/** - * A destructor. - * A more elaborate description of the destructor. - */ TransactionObject::~TransactionObject() { for (auto& v : _PropChangeMap) { @@ -344,7 +332,7 @@ void TransactionObject::applyChn(Document& /*Doc*/, TransactionalObject* pcObj, } // getPropertyName() is specially coded to be safe even if prop has - // been destroies. We must prepare for the case where user removed + // been destroyed. We must prepare for the case where user removed // a dynamic property but does not recordered as transaction. auto name = pcObj->getPropertyName(prop); if (!name || (!data.name.empty() && data.name != name) diff --git a/src/App/Transactions.h b/src/App/Transactions.h index eb57f2f888..967330b0b9 100644 --- a/src/App/Transactions.h +++ b/src/App/Transactions.h @@ -40,52 +40,105 @@ class TransactionObject; class TransactionalObject; -/** Represents a atomic transaction of the document +/** + * @brief A class that represents an atomic transaction of the document. + * + * A transaction can contain multiple actions. These actions are represented + * by TransactionObject objects. Actions can be on objects: adding one, + * removing one, or changing one. It can also be on properties: adding one or + * removing one. */ class AppExport Transaction: public Base::Persistence { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: - /** Construction + /** + * @brief Construct a transaction. * - * @param id: transaction id. If zero, then it will be generated + * @param[in] id: The transaction id. If zero, then it will be generated * automatically as a monotonically increasing index across the entire - * application. User can pass in a transaction id to group multiple - * transactions from different document, so that they can be undo/redo + * application. Users can pass in a transaction id to group multiple + * transactions from different document, so that they can be undone/redone * together. */ explicit Transaction(int id = 0); - /// Construction + ~Transaction() override; - /// apply the content to the document + /** + * @brief Apply the content of this transaction to the document. + * + * @param[in] Doc The document to apply the transaction to. + * @param[in] forward If true, apply the transaction; otherwise, undo it. + */ void apply(Document& Doc, bool forward); - // the utf-8 name of the transaction + /// The UTF-8 name of the transaction std::string Name; unsigned int getMemSize() const override; void Save(Base::Writer& writer) const override; - /// This method is used to restore properties from an XML document. void Restore(Base::XMLReader& reader) override; - /// Return the transaction ID + /// Get the transaction ID of this transaction. int getID() const; - /// Generate a new unique transaction ID + /// Generate a new unique transaction ID. static int getNewID(); + + /// Get the last transaction ID. static int getLastID(); - /// Returns true if the transaction list is empty; otherwise returns false. + /// Check if the transaction list is empty. bool isEmpty() const; - /// check if this object is used in a transaction + + /** + * @brief Check if this object is used in a transaction. + * + * @param[in] Obj The object to check. + * @return true if the object is used in a transaction; otherwise false. + */ bool hasObject(const TransactionalObject* Obj) const; + + /** + * @brief Record renaming a property. + * + * @param[in] Obj The object of which the property to rename. + * @param[in] pcProp The property with a new name. + * @param[in] oldName The old name of the property. + */ void renameProperty(TransactionalObject* Obj, const Property* pcProp, const char* oldName); + + /** + * @brief Record adding or removing a property from an object. + * + * @param[in] Obj The object to add or remove the property from. + * @param[in] pcProp The property to add or remove. + * @param[in] add If true, add the property; otherwise, remove it. + */ void addOrRemoveProperty(TransactionalObject* Obj, const Property* pcProp, bool add); + /** + * @brief Record adding a new object to the transaction. + * + * @param[in] Obj The object to add. + */ void addObjectNew(TransactionalObject* Obj); + + /** + * @brief Record removing an object from the transaction. + * + * @param[in] Obj The object to remove. + */ void addObjectDel(const TransactionalObject* Obj); + + /** + *@brief Record changing an object in the transaction. + * + * @param[in] Obj The object to change. + * @param[in] Prop The property that is changed. + */ void addObjectChange(const TransactionalObject* Obj, const Property* Prop); private: @@ -103,41 +156,87 @@ private: _Objects; }; -/** Represents an entry for an object in a Transaction +/** + * @brief Class that represents an entry for an object in a Transaction. + * + * This class is used to store the information about the object and its + * properties. It should not be confused with the TransactionalObject class + * that is a base class that contains functionality for a DocumentObject + * regarding transactions. */ class AppExport TransactionObject: public Base::Persistence { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: - /// Construction TransactionObject(); - /// Destruction + ~TransactionObject() override; - virtual void applyNew(Document& Doc, TransactionalObject* pcObj); - virtual void applyDel(Document& Doc, TransactionalObject* pcObj); - virtual void applyChn(Document& Doc, TransactionalObject* pcObj, bool Forward); + /** + * @brief Apply the transaction that adds a new object to the document. + * + * @param[in,out] doc The document to apply the transaction to. + * @param[in,out] obj The object that is added in the transaction. + */ + virtual void applyNew(Document& doc, TransactionalObject* obj); - void setProperty(const Property* pcProp); - void renameProperty(const Property* pcProp, const char* newName); - void addOrRemoveProperty(const Property* pcProp, bool add); + /** + * @brief Apply the transaction that removes an object from the document. + * + * @param[in,out] doc The document to apply the transaction to. + * @param[in,out] obj The object that is removed in the transaction. + */ + virtual void applyDel(Document& doc, TransactionalObject* obj); + + /** + * @brief Apply the transaction that changes an object in the document. + * + * @param[in,out] doc The document to apply the transaction to. + * @param[in,out] obj The object that is changed in the transaction. + * @param[in] forward If true, apply the transaction; otherwise, undo it. + */ + virtual void applyChn(Document& doc, TransactionalObject* obj, bool forward); + + /** + * @brief Set the property of the object that is affected by the transaction. + * + * @param[in] prop The property that is affected by the transaction. + */ + void setProperty(const Property* prop); + + /** + * @brief Rename a property. + * + * @param[in] pcProp The property with the new name. + * @param[in] oldName The old name of the property. + */ + void renameProperty(const Property* pcProp, const char* oldName); + + /** + * @brief Add or remove a property from the object. + * + * @param[in] prop The property to add or remove. + * @param[in] add If true, add the property; otherwise, remove it. + */ + void addOrRemoveProperty(const Property* prop, bool add); unsigned int getMemSize() const override; void Save(Base::Writer& writer) const override; - /// This method is used to restore properties from an XML document. void Restore(Base::XMLReader& reader) override; friend class Transaction; protected: + /// The status of the transaction object. enum Status { - New, - Del, - Chn + New, ///< A new object is added to the document. + Del, ///< An object is deleted from the document. + Chn ///< An object is changed in the document. } status {New}; + /// Struct to maintain property information. struct PropData: DynamicProperty::PropData { Base::Type propertyType; @@ -145,34 +244,59 @@ protected: // for property renaming std::string nameOrig; }; + + /// A map to maintain the properties of the object. std::unordered_map _PropChangeMap; + /// The name of the object in the document. std::string _NameInDocument; }; -/** Represents an entry for a document object in a transaction +/** + * @brief Class that represents an entry for a document object in a transaction. */ class AppExport TransactionDocumentObject: public TransactionObject { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: - /// Construction TransactionDocumentObject(); - /// Destruction + ~TransactionDocumentObject() override; void applyNew(Document& Doc, TransactionalObject* pcObj) override; void applyDel(Document& Doc, TransactionalObject* pcObj) override; }; +/** + * @brief Class that represents a factory for creating transaction objects. + * + * This class is used to create transaction objects for different types of + * transactions. + */ class AppExport TransactionFactory { public: + /// Get the singleton instance of the TransactionFactory. static TransactionFactory& instance(); + + /// Destruct the singleton instance of the TransactionFactory. static void destruct(); + /** + * @brief Create a transaction object for the given type. + * + * @param[in] type The type of the transaction object to create. + * @return A pointer to the created transaction object. + */ TransactionObject* createTransaction(const Base::Type& type) const; + + /** + * @brief Add a producer for a transaction object. + * + * @param[in] type The type id of the transaction object. + * @param[in,out] producer The producer to add. + */ void addProducer(const Base::Type& type, Base::AbstractProducer* producer); private: @@ -183,10 +307,20 @@ private: ~TransactionFactory() = default; }; +/** + * @brief Class that represents a producer for creating transaction objects. + * + * @tparam CLASS The class of the transaction object to produce. + */ template class TransactionProducer: public Base::AbstractProducer { public: + /** + * @brief Construct a transaction producer. + * + * @param[in] type The type of the transaction object. + */ explicit TransactionProducer(const Base::Type& type) { TransactionFactory::instance().addProducer(type, this); @@ -194,9 +328,7 @@ public: ~TransactionProducer() override = default; - /** - * Creates an instance of the specified transaction object. - */ + /// Creates an instance of the specified transaction object. void* Produce() const override { return (new CLASS);