| // SPDX-License-Identifier: LGPL-2.1-or-later | |
| /*************************************************************************** | |
| * Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> * | |
| * * | |
| * This file is part of the FreeCAD CAx development system. * | |
| * * | |
| * This library is free software; you can redistribute it and/or * | |
| * modify it under the terms of the GNU Library General Public * | |
| * License as published by the Free Software Foundation; either * | |
| * version 2 of the License, or (at your option) any later version. * | |
| * * | |
| * This library is distributed in the hope that it will be useful, * | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
| * GNU Library General Public License for more details. * | |
| * * | |
| * You should have received a copy of the GNU Library General Public * | |
| * License along with this library; see the file COPYING.LIB. If not, * | |
| * write to the Free Software Foundation, Inc., 59 Temple Place, * | |
| * Suite 330, Boston, MA 02111-1307, USA * | |
| * * | |
| ***************************************************************************/ | |
| namespace Base | |
| { | |
| class Writer; | |
| } | |
| namespace App | |
| { | |
| enum class AddObjectOption | |
| { | |
| None = 0, | |
| SetNewStatus = 1, | |
| SetPartialStatus = 2, | |
| UnsetPartialStatus = 4, | |
| DoSetup = 8, | |
| ActivateObject = 16 | |
| }; | |
| using AddObjectOptions = Base::Flags<AddObjectOption>; | |
| enum class RemoveObjectOption | |
| { | |
| None = 0, | |
| MayRemoveWhileRecomputing = 1, | |
| MayDestroyOutOfTransaction = 2, | |
| DestroyOnRollback = 4, | |
| PreserveChildrenVisibility = 8 | |
| }; | |
| using RemoveObjectOptions = Base::Flags<RemoveObjectOption>; | |
| } | |
| ENABLE_BITMASK_OPERATORS(App::AddObjectOption) | |
| ENABLE_BITMASK_OPERATORS(App::RemoveObjectOption) | |
| namespace App | |
| { | |
| class TransactionalObject; | |
| class DocumentObject; | |
| class DocumentObjectExecReturn; | |
| class Document; | |
| class DocumentPy; | |
| class Application; | |
| class Transaction; | |
| class StringHasher; | |
| using StringHasherRef = Base::Reference<StringHasher>; | |
| /** | |
| * @brief The document class | |
| * @ingroup DocumentGroup | |
| * @details For a more high-level discussion see the topic @ref DocumentGroup "Document". | |
| */ | |
| class AppExport Document: public PropertyContainer | |
| { | |
| PROPERTY_HEADER_WITH_OVERRIDE(App::Document); | |
| public: | |
| // clang-format off | |
| enum Status | |
| { | |
| SkipRecompute = 0, | |
| KeepTrailingDigits = 1, | |
| Closable = 2, | |
| Restoring = 3, | |
| Recomputing = 4, | |
| PartialRestore = 5, | |
| Importing = 6, | |
| PartialDoc = 7, | |
| AllowPartialRecompute = 8, // allow recomputing editing object if SkipRecompute is set | |
| TempDoc = 9, // Mark as temporary document without prompt for save | |
| RestoreError = 10, | |
| LinkStampChanged = 11, // Indicates during restore time if any linked document's time stamp has changed | |
| IgnoreErrorOnRecompute = 12, // Don't report errors if the recompute failed | |
| RecomputeOnRestore = 13, // Mark pending recompute on restore for migration purposes | |
| MigrateLCS = 14 // Migrate local coordinate system of older versions | |
| }; | |
| // clang-format on | |
| // NOLINTBEGIN | |
| /** @name Properties */ | |
| //@{ | |
| /// holds the long name of the document (utf-8 coded) | |
| PropertyString Label; | |
| /// full qualified (with path) file name (utf-8 coded) | |
| PropertyString FileName; | |
| /// creators name (utf-8) | |
| PropertyString CreatedBy; | |
| PropertyString CreationDate; | |
| /// user last modified the document | |
| PropertyString LastModifiedBy; | |
| PropertyString LastModifiedDate; | |
| /// company name UTF8(optional) | |
| PropertyString Company; | |
| /// Unit System | |
| PropertyEnumeration UnitSystem; | |
| /// long comment or description (UTF8 with line breaks) | |
| PropertyString Comment; | |
| /// Id e.g. Part number | |
| PropertyString Id; | |
| /// unique identifier of the document | |
| PropertyUUID Uid; | |
| /// Full name of the licence e.g. "Creative Commons Attribution". See https://spdx.org/licenses/ | |
| PropertyString License; | |
| /// License description/contract URL | |
| PropertyString LicenseURL; | |
| /// Meta descriptions | |
| PropertyMap Meta; | |
| /// Material descriptions, used and defined in the Material module. | |
| PropertyMap Material; | |
| /// read-only name of the temp dir created when the document is opened | |
| PropertyString TransientDir; | |
| /// Tip object of the document (if any) | |
| PropertyLink Tip; | |
| /// Tip object of the document (if any) | |
| PropertyString TipName; | |
| /// Whether to show hidden items in TreeView | |
| PropertyBool ShowHidden; | |
| /// Whether to use hasher on topological naming | |
| PropertyBool UseHasher; | |
| //@} | |
| /** @name Signals of the document */ | |
| //@{ | |
| // clang-format off | |
| /// signal before changing an doc property | |
| fastsignals::signal<void(const Document&, const Property&)> signalBeforeChange; | |
| /// signal on changed doc property | |
| fastsignals::signal<void(const Document&, const Property&)> signalChanged; | |
| /// signal on new Object | |
| fastsignals::signal<void(const DocumentObject&)> signalNewObject; | |
| /// signal on deleted Object | |
| fastsignals::signal<void(const DocumentObject&)> signalDeletedObject; | |
| /// signal before changing an Object | |
| fastsignals::signal<void(const DocumentObject&, const Property&)> signalBeforeChangeObject; | |
| /// signal on changed Object | |
| fastsignals::signal<void(const DocumentObject&, const Property&)> signalChangedObject; | |
| /// signal on manually called DocumentObject::touch() | |
| fastsignals::signal<void(const DocumentObject&)> signalTouchedObject; | |
| /// signal on relabeled Object | |
| fastsignals::signal<void(const DocumentObject&)> signalRelabelObject; | |
| /// signal on activated Object | |
| fastsignals::signal<void(const DocumentObject&)> signalActivatedObject; | |
| /// signal on created object | |
| fastsignals::signal<void(const DocumentObject&, Transaction*)> signalTransactionAppend; | |
| /// signal on removed object | |
| fastsignals::signal<void(const DocumentObject&, Transaction*)> signalTransactionRemove; | |
| /// signal on undo | |
| fastsignals::signal<void(const Document&)> signalUndo; | |
| /// signal on redo | |
| fastsignals::signal<void(const Document&)> signalRedo; | |
| /** signal on load/save document | |
| * this signal is given when the document gets streamed. | |
| * you can use this hook to write additional information in | |
| * the file (like the Gui::Document does). | |
| */ | |
| fastsignals::signal<void(Base::Writer&)> signalSaveDocument; | |
| fastsignals::signal<void(Base::XMLReader&)> signalRestoreDocument; | |
| fastsignals::signal<void(const std::vector<DocumentObject*>&, Base::Writer&)> signalExportObjects; | |
| fastsignals::signal<void(const std::vector<DocumentObject*>&, Base::Writer&)> signalExportViewObjects; | |
| fastsignals::signal<void(const std::vector<DocumentObject*>&, Base::XMLReader&)> signalImportObjects; | |
| fastsignals::signal<void(const std::vector<DocumentObject*>&, Base::Reader&, | |
| const std::map<std::string, std::string>&)> signalImportViewObjects; | |
| fastsignals::signal<void(const std::vector<DocumentObject*>&)> signalFinishImportObjects; | |
| // signal starting a save action to a file | |
| fastsignals::signal<void(const Document&, const std::string&)> signalStartSave; | |
| // signal finishing a save action to a file | |
| fastsignals::signal<void(const Document&, const std::string&)> signalFinishSave; | |
| fastsignals::signal<void(const Document&)> signalBeforeRecompute; | |
| fastsignals::signal<void(const Document&, const std::vector<DocumentObject*>&)> signalRecomputed; | |
| fastsignals::signal<void(const DocumentObject&)> signalRecomputedObject; | |
| // signal a new opened transaction | |
| fastsignals::signal<void(const Document&, std::string)> signalOpenTransaction; | |
| // signal a committed transaction | |
| fastsignals::signal<void(const Document&)> signalCommitTransaction; | |
| // signal an aborted transaction | |
| fastsignals::signal<void(const Document&)> signalAbortTransaction; | |
| fastsignals::signal<void(const Document&, const std::vector<DocumentObject*>&)> signalSkipRecompute; | |
| fastsignals::signal<void(const DocumentObject&)> signalFinishRestoreObject; | |
| fastsignals::signal<void(const Document&, const Property&)> signalChangePropertyEditor; | |
| fastsignals::signal<void(std::string)> signalLinkXsetValue; | |
| // clang-format on | |
| //@} | |
| // NOLINTEND | |
| using PreRecomputeHook = std::function<void()>; | |
| void setPreRecomputeHook(const PreRecomputeHook& hook); | |
| void clearDocument(); | |
| /** @name File handling of the document */ | |
| //@{ | |
| /// Save the Document under a new Name | |
| // void saveAs (const char* Name); | |
| /// Save the document to the file in Property Path | |
| bool save(); | |
| bool saveAs(const char* file); | |
| bool saveCopy(const char* file) const; | |
| /// Restore the document from the file in Property Path | |
| void restore(const char* filename = nullptr, | |
| bool delaySignal = false, | |
| const std::vector<std::string>& objNames = {}); | |
| bool afterRestore(bool checkPartial = false); | |
| bool afterRestore(const std::vector<DocumentObject*>&, bool checkPartial = false); | |
| enum ExportStatus | |
| { | |
| NotExporting, | |
| Exporting, | |
| }; | |
| ExportStatus isExporting(const DocumentObject* obj) const; | |
| ExportInfo exportInfo() const; | |
| void setExportInfo(const ExportInfo& info); | |
| void exportObjects(const std::vector<DocumentObject*>&, std::ostream&); | |
| void exportGraphviz(std::ostream&) const; | |
| std::vector<DocumentObject*> importObjects(Base::XMLReader& reader); | |
| /** Import any externally linked objects | |
| * | |
| * @param objs: input list of objects. Only objects belonging to this document will | |
| * be checked for external links. And all found external linked object will be imported | |
| * to this document. Link type properties of those input objects will be automatically | |
| * reassigned to the imported objects. Note that the link properties of other objects | |
| * in the document but not included in the input list, will not be affected even if they | |
| * point to some object beining imported. To import all objects, simply pass in all objects | |
| * of this document. | |
| * | |
| * @return the list of imported objects | |
| */ | |
| std::vector<DocumentObject*> | |
| importLinks(const std::vector<DocumentObject*>& objs = {}); | |
| /// Opens the document from its file name | |
| // void open (void); | |
| /// Is the document already saved to a file? | |
| bool isSaved() const; | |
| /// Get the document name | |
| const char* getName() const; | |
| /// Get program version the project file was created with | |
| const char* getProgramVersion() const; | |
| /** Returned filename | |
| * | |
| * For saved document, this will be the content stored in property | |
| * 'Filename'. For unsaved temporary file, this will be the content of | |
| * property 'TransientDir'. | |
| */ | |
| const char* getFileName() const; | |
| //@} | |
| void Save(Base::Writer& writer) const override; | |
| void Restore(Base::XMLReader& reader) override; | |
| /// returns the complete document memory consumption, including all managed DocObjects and Undo | |
| /// Redo. | |
| unsigned int getMemSize() const override; | |
| /** @name Object handling */ | |
| //@{ | |
| /** Add a feature of sType with sName (ASCII) to this document and set it active. | |
| * Unicode names are set through the Label property. | |
| * @param sType the type of created object | |
| * @param pObjectName if nonNULL use that name otherwise generate a new unique name based on the | |
| * \a sType | |
| * @param isNew if false don't call the \c DocumentObject::setupObject() callback (default | |
| * is true) | |
| * @param viewType override object's view provider name | |
| * @param isPartial indicate if this object is meant to be partially loaded | |
| */ | |
| DocumentObject* addObject(const char* sType, | |
| const char* pObjectName = nullptr, | |
| bool isNew = true, | |
| const char* viewType = nullptr, | |
| bool isPartial = false); | |
| //@{ | |
| /** Add a feature of T type with sName (ASCII) to this document and set it active. | |
| * Unicode names are set through the Label property. | |
| * @param pObjectName if nonNULL use that name otherwise generate a new unique name based on the | |
| * \a sType | |
| * @param isNew if false don't call the \c DocumentObject::setupObject() callback (default | |
| * is true) | |
| * @param viewType override object's view provider name | |
| * @param isPartial indicate if this object is meant to be partially loaded | |
| */ | |
| template<typename T> | |
| T* addObject(const char* pObjectName = nullptr, | |
| bool isNew = true, | |
| const char* viewType = nullptr, | |
| bool isPartial = false); | |
| /** Add an array of features of the given types and names. | |
| * Unicode names are set through the Label property. | |
| * @param sType The type of created object | |
| * @param objectNames A list of object names | |
| * @param isNew If false don't call the \c DocumentObject::setupObject() callback (default | |
| * is true) | |
| */ | |
| std::vector<DocumentObject*> | |
| addObjects(const char* sType, const std::vector<std::string>& objectNames, bool isNew = true); | |
| /// Remove a feature out of the document | |
| void removeObject(const char* sName); | |
| /** Add an existing feature with sName (ASCII) to this document and set it active. | |
| * Unicode names are set through the Label property. | |
| * This is an overloaded function of the function above and can be used to create | |
| * a feature outside and add it to the document afterwards. | |
| * \note The passed feature must not yet be added to a document, otherwise an exception | |
| * is raised. | |
| */ | |
| void addObject(DocumentObject*, const char* pObjectName = nullptr); | |
| /// returns whether this is actually contains the DocumentObject. | |
| /// Testing the DocumentObject's pDoc pointer is not sufficient because the object | |
| /// removeObject and _removeObject leave _pDoc unchanged | |
| bool containsObject(const DocumentObject*) const; | |
| /** Copy objects from another document to this document | |
| * | |
| * @param objs | |
| * @param recursive: if true, then all objects this object depends on are | |
| * copied as well. By default \a recursive is false. | |
| * | |
| * @param returnAll: if true, return all copied objects including those | |
| * auto included by recursive searching. If false, then only return the | |
| * copied object corresponding to the input objects. | |
| * | |
| * @return Returns the list of objects copied. | |
| */ | |
| std::vector<DocumentObject*> copyObject(const std::vector<DocumentObject*>& objs, | |
| bool recursive = false, | |
| bool returnAll = false); | |
| /** Move an object from another document to this document | |
| * If \a recursive is true then all objects this object depends on | |
| * are moved as well. By default \a recursive is false. | |
| * Returns the moved object itself or 0 if the object is already part of this | |
| * document.. | |
| */ | |
| DocumentObject* moveObject(DocumentObject* obj, bool recursive = false); | |
| /// Returns the active Object of this document | |
| DocumentObject* getActiveObject() const; | |
| /// Returns a Object of this document | |
| DocumentObject* getObject(const char* Name) const; | |
| /// Returns a Object of this document by its id | |
| DocumentObject* getObjectByID(long id) const; | |
| /// Returns true if the DocumentObject is contained in this document | |
| bool isIn(const DocumentObject* pFeat) const; | |
| /// Returns a Name of an Object or 0 | |
| const char *getObjectName(const DocumentObject* pFeat) const; | |
| /// Returns a Name for a new Object or empty if proposedName is null or empty. | |
| std::string getUniqueObjectName(const char* proposedName) const; | |
| /// Returns a name different from any of the Labels of any objects in this document, based on the given modelName. | |
| std::string getStandardObjectLabel(const char* modelName, int d) const; | |
| /// Determine if a given DocumentObject Name and a proposed Label are based on the same base name | |
| bool haveSameBaseName(const std::string& name, const std::string& label); | |
| /// Returns a list of document's objects including the dependencies | |
| std::vector<DocumentObject*> getDependingObjects() const; | |
| /// Returns a list of all Objects | |
| const std::vector<DocumentObject*>& getObjects() const; | |
| std::vector<DocumentObject*> getObjectsOfType(const Base::Type& typeId) const; | |
| std::vector<DocumentObject*> getObjectsOfType(const std::vector<Base::Type>& types) const; | |
| /// Returns all object with given extensions. If derived=true also all objects with extensions | |
| /// derived from the given one | |
| std::vector<DocumentObject*> getObjectsWithExtension(const Base::Type& typeId, | |
| bool derived = true) const; | |
| std::vector<DocumentObject*> | |
| findObjects(const Base::Type& typeId, const char* objname, const char* label) const; | |
| /// Returns an array with the correct types already. | |
| template<typename T> | |
| inline std::vector<T*> getObjectsOfType() const; | |
| template<typename T> | |
| inline int countObjectsOfType() const; | |
| int countObjectsOfType(const char* typeName) const; | |
| /// get the number of objects in the document | |
| int countObjects() const; | |
| //@} | |
| /** @name methods for modification and state handling | |
| */ | |
| //@{ | |
| /// Remove all modifications. After this call The document becomes Valid again. | |
| void purgeTouched(); | |
| /// check if there is any touched object in this document | |
| bool isTouched() const; | |
| /// check if there is any object must execute in this document | |
| bool mustExecute() const; | |
| /// returns all touched objects | |
| std::vector<DocumentObject*> getTouched() const; | |
| /// set the document to be closable, this is on by default. | |
| void setClosable(bool); | |
| /// check whether the document can be closed | |
| bool isClosable() const; | |
| /// set the document to autoCreated, this is off by default. | |
| void setAutoCreated(bool); | |
| /// check whether the document is autoCreated. | |
| bool isAutoCreated() const; | |
| /** Recompute touched features and return the number of recalculated features | |
| * | |
| * @param objs: specify a sub set of objects to recompute. If empty, then | |
| * all object in this document is checked for recompute | |
| * @param force | |
| * @param hasError | |
| * @param options | |
| */ | |
| int recompute(const std::vector<DocumentObject*>& objs = {}, | |
| bool force = false, | |
| bool* hasError = nullptr, | |
| int options = 0); | |
| /// Recompute only one feature | |
| bool recomputeFeature(DocumentObject* Feat, bool recursive = false); | |
| /// get the text of the error of a specified object | |
| const char* getErrorDescription(const DocumentObject*) const; | |
| /// return the status bits | |
| bool testStatus(Status pos) const; | |
| /// set the status bits | |
| void setStatus(Status pos, bool on); | |
| //@} | |
| /** @name methods for the UNDO REDO and Transaction handling | |
| * | |
| * Introduce a new concept of transaction ID. Each transaction must be | |
| * unique inside the document. Multiple transactions from different | |
| * documents can be grouped together with the same transaction ID. | |
| * | |
| * When undo, Gui component can query getAvailableUndo(id) to see if it is | |
| * possible to undo with a given ID. If there more than one undo | |
| * transactions, meaning that there are other transactions before the given | |
| * ID. The Gui component shall ask user if they want to undo multiple steps. | |
| * And if the user agrees, call undo(id) to unroll all transaction before | |
| * and including the one with the given ID. Same applies for redo. | |
| * | |
| * The new transaction ID describe here is fully backward compatible. | |
| * Calling the APIs with a default id=0 gives the original behavior. | |
| */ | |
| //@{ | |
| /// switch the level of Undo/Redo | |
| void setUndoMode(int iMode); | |
| /// switch the level of Undo/Redo | |
| int getUndoMode() const; | |
| /// switch the transaction mode | |
| void setTransactionMode(int iMode); | |
| /** Open a new command Undo/Redo, an UTF-8 name can be specified | |
| * | |
| * @param name: transaction name | |
| * | |
| * This function calls Application::setActiveTransaction(name) instead | |
| * to setup a potential transaction which will only be created if there is | |
| * actual changes. | |
| */ | |
| void openTransaction(const char* name = nullptr); | |
| /// Rename the current transaction if the id matches | |
| void renameTransaction(const char* name, int id) const; | |
| /// Commit the Command transaction. Do nothing If there is no Command transaction open. | |
| void commitTransaction(); | |
| /// Abort the actually running transaction. | |
| void abortTransaction() const; | |
| /// Check if a transaction is open | |
| bool hasPendingTransaction() const; | |
| /// Return the undo/redo transaction ID starting from the back | |
| int getTransactionID(bool undo, unsigned pos = 0) const; | |
| /// Check if a transaction is open and its list is empty. | |
| /// If no transaction is open true is returned. | |
| bool isTransactionEmpty() const; | |
| /// Set the Undo limit in Byte! | |
| void setUndoLimit(unsigned int UndoMemSize = 0); | |
| /// Returns the actual memory consumption of the Undo redo stuff. | |
| unsigned int getUndoMemSize() const; | |
| /// Set the Undo limit as stack size | |
| void setMaxUndoStackSize(unsigned int UndoMaxStackSize = 20); // NOLINT | |
| /// Set the Undo limit as stack size | |
| unsigned int getMaxUndoStackSize() const; | |
| /// Remove all stored Undos and Redos | |
| void clearUndos(); | |
| /// Returns the number of stored Undos. If greater than 0 Undo will be effective. | |
| int getAvailableUndos(int id = 0) const; | |
| /// Returns a list of the Undo names | |
| std::vector<std::string> getAvailableUndoNames() const; | |
| /// Will UNDO one step, returns False if no undo was done (Undos == 0). | |
| bool undo(int id = 0); | |
| /// Returns the number of stored Redos. If greater than 0 Redo will be effective. | |
| int getAvailableRedos(int id = 0) const; | |
| /// Returns a list of the Redo names. | |
| std::vector<std::string> getAvailableRedoNames() const; | |
| /// Will REDO one step, returns False if no redo was done (Redos == 0). | |
| bool redo(int id = 0); | |
| /// returns true if the document is in an Transaction phase, e.g. currently performing a | |
| /// redo/undo or rollback | |
| bool isPerformingTransaction() const; | |
| /// \internal add or remove property from a transactional object | |
| void addOrRemovePropertyOfObject(TransactionalObject*, const Property* prop, bool add); | |
| void renamePropertyOfObject(TransactionalObject*, const Property* prop, const char* newName); | |
| //@} | |
| /** @name dependency stuff */ | |
| //@{ | |
| /// write GraphViz file | |
| void writeDependencyGraphViz(std::ostream& out); | |
| /// checks if the graph is directed and has no cycles | |
| static bool checkOnCycle(); | |
| /// get a list of all objects linking to the given object | |
| std::vector<DocumentObject*> getInList(const DocumentObject* me) const; | |
| /// Option bit flags used by getDepenencyList() | |
| enum DependencyOption | |
| { | |
| /// Return topological sorted list | |
| DepSort = 1, | |
| /// Do no include object linked by PropertyXLink, as it can handle external link | |
| DepNoXLinked = 2, | |
| /// Raise exception on cycles | |
| DepNoCycle = 4, | |
| }; | |
| /** Get a complete list of all objects the given objects depend on. | |
| * | |
| * This function is defined as static because it accepts objects from | |
| * different documents, and the returned list will contain dependent | |
| * objects from all relevant documents | |
| * | |
| * @param objs: input objects to query for dependency. | |
| * @param options: See DependencyOption | |
| */ | |
| static std::vector<DocumentObject*> | |
| getDependencyList(const std::vector<DocumentObject*>& objs, int options = 0); | |
| std::vector<Document*> getDependentDocuments(bool sort = true); | |
| static std::vector<Document*> getDependentDocuments(std::vector<Document*> docs, | |
| bool sort); | |
| // set Changed | |
| // void setChanged(DocumentObject* change); | |
| /// get a list of topological sorted objects (https://en.wikipedia.org/wiki/Topological_sorting) | |
| std::vector<DocumentObject*> topologicalSort() const; | |
| /// get all root objects (objects no other one reference too) | |
| std::vector<DocumentObject*> getRootObjects() const; | |
| /// get all tree root objects (objects that are at the root of the object tree) | |
| std::vector<DocumentObject*> getRootObjectsIgnoreLinks() const; | |
| /// get all possible paths from one object to another following the OutList | |
| std::vector<std::list<DocumentObject*>> | |
| getPathsByOutList(const DocumentObject* from, const DocumentObject* to) const; | |
| //@} | |
| /** Called by a property during save to store its StringHasher | |
| * | |
| * @param hasher: the input hasher | |
| * @return Returns a pair<bool,int>. The boolean indicates if the | |
| * StringHasher has been added before. The integer is the hasher index. | |
| * | |
| * The StringHasher object is designed to be shared among multiple objects. | |
| * We must not save duplicate copies of the same hasher, and must be | |
| * able to restore with the same sharing relationship. This function returns | |
| * whether the hasher has been added before by other objects, and the index | |
| * of the hasher. If the hasher has not been added before, the object must | |
| * save the hasher by calling StringHasher::Save | |
| */ | |
| std::pair<bool, int> addStringHasher(const StringHasherRef& hasher) const; | |
| /** Called by property to restore its StringHasher | |
| * | |
| * @param index: the index previously returned by calling addStringHasher() | |
| * during save. Or if is negative, then return document's own string hasher. | |
| * | |
| * @return Return the resulting string hasher. | |
| * | |
| * The caller is responsible for restoring the hasher if the caller is the first | |
| * owner of the hasher, i.e. if addStringHasher() returns true during save. | |
| */ | |
| StringHasherRef getStringHasher(int index = -1) const; | |
| /** Return the links to a given object | |
| * | |
| * @param links: holds the links found | |
| * @param obj: the linked object. If NULL, then all links are returned. | |
| * @param options: @sa GetLinkOption | |
| * @param maxCount: limit the number of links returned, 0 means no limit | |
| * @param objs: optional objects to search for, if empty, then all objects | |
| * of this document are searched. | |
| */ | |
| void getLinksTo(std::set<DocumentObject*>& links, | |
| const DocumentObject* obj, | |
| int options, | |
| int maxCount = 0, | |
| const std::vector<DocumentObject*>& objs = {}) const; | |
| /// Check if there is any link to the given object | |
| bool hasLinksTo(const DocumentObject* obj) const; | |
| /// Called by objects during restore to ask for recompute | |
| void addRecomputeObject(DocumentObject* obj); | |
| const std::string& getOldLabel() const | |
| { | |
| return oldLabel; | |
| } | |
| /// Function called to signal that an object identifier has been renamed | |
| void renameObjectIdentifiers( | |
| const std::map<ObjectIdentifier, ObjectIdentifier>& paths, | |
| const std::function<bool(const DocumentObject*)>& selector = | |
| [](const DocumentObject*) { | |
| return true; | |
| }); | |
| PyObject* getPyObject() override; | |
| std::string getFullName() const override; | |
| /// Indicate if there is any document restoring/importing | |
| static bool isAnyRestoring(); | |
| void registerLabel(const std ::string& newLabel); | |
| void unregisterLabel(const std::string& oldLabel); | |
| bool containsLabel(const std::string& label); | |
| std::string makeUniqueLabel(const std::string& modelLabel); | |
| friend class Application; | |
| /// because of transaction handling | |
| friend class TransactionalObject; | |
| friend class DocumentObject; | |
| friend class Transaction; | |
| friend class TransactionDocumentObject; | |
| /// Destruction | |
| ~Document() override; | |
| protected: | |
| /// Construction | |
| explicit Document(const char* documentName = ""); | |
| void _removeObject(DocumentObject* pcObject, RemoveObjectOptions options = RemoveObjectOption::DestroyOnRollback | RemoveObjectOption::PreserveChildrenVisibility); | |
| void _addObject(DocumentObject* pcObject, const char* pObjectName, AddObjectOptions options = AddObjectOption::ActivateObject, const char* viewType = nullptr); | |
| /// checks if a valid transaction is open | |
| void _checkTransaction(DocumentObject* pcDelObj, const Property* What, int line); | |
| void breakDependency(DocumentObject* pcObject, bool clear); | |
| std::vector<DocumentObject*> readObjects(Base::XMLReader& reader); | |
| void writeObjects(const std::vector<DocumentObject*>&, Base::Writer& writer) const; | |
| bool saveToFile(const char* filename) const; | |
| int countObjectsOfType(const Base::Type& typeId) const; | |
| void onBeforeChange(const Property* prop) override; | |
| void onChanged(const Property* prop) override; | |
| /// callback from the Document objects before property will be changed | |
| void onBeforeChangeProperty(const TransactionalObject* Who, const Property* What); | |
| /// callback from the Document objects after property was changed | |
| void onChangedProperty(const DocumentObject* Who, const Property* What); | |
| /// helper which Recompute only this feature | |
| /// @return 0 if succeeded, 1 if failed, -1 if aborted by user. | |
| int _recomputeFeature(DocumentObject* Feat); | |
| void _clearRedos(); | |
| /// refresh the internal dependency graph | |
| void _rebuildDependencyList( | |
| const std::vector<DocumentObject*>& objs = std::vector<DocumentObject*>()); | |
| std::string getTransientDirectoryName(const std::string& uuid, | |
| const std::string& filename) const; | |
| /** Open a new command Undo/Redo, an UTF-8 name can be specified | |
| * | |
| * @param name: transaction name | |
| * @param id: transaction ID, if 0 then the ID is auto generated. | |
| * | |
| * @return: Return the ID of the new transaction. | |
| * | |
| * This function creates an actual transaction regardless of Application | |
| * AutoTransaction setting. | |
| */ | |
| int _openTransaction(const char* name = nullptr, int id = 0); | |
| /// Internally called by Application to commit the Command transaction. | |
| void _commitTransaction(bool notify = false); | |
| /// Internally called by Application to abort the running transaction. | |
| void _abortTransaction(); | |
| private: | |
| void changePropertyOfObject(TransactionalObject* obj, const Property* prop, | |
| const std::function<void()>& changeFunc); | |
| private: | |
| // # Data Member of the document | |
| // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| std::list<Transaction*> mUndoTransactions; | |
| std::map<int, Transaction*> mUndoMap; | |
| std::list<Transaction*> mRedoTransactions; | |
| std::map<int, Transaction*> mRedoMap; | |
| struct DocumentP* d; | |
| std::string oldLabel; | |
| std::string myName; | |
| bool autoCreated; // Flag to know if the document was automatically created at startup | |
| }; | |
| template<typename T> | |
| inline std::vector<T*> Document::getObjectsOfType() const | |
| { | |
| std::vector<T*> type; | |
| const std::vector<DocumentObject*> obj = this->getObjectsOfType(T::getClassTypeId()); | |
| type.reserve(obj.size()); | |
| for (auto it : obj) { | |
| type.push_back(static_cast<T*>(it)); | |
| } | |
| return type; | |
| } | |
| template<typename T> | |
| inline int Document::countObjectsOfType() const | |
| { | |
| static_assert(std::is_base_of_v<DocumentObject, T>, | |
| "T must be derived from App::DocumentObject"); | |
| return this->countObjectsOfType(T::getClassTypeId()); | |
| } | |
| template<typename T> | |
| T* Document::addObject(const char* pObjectName, bool isNew, const char* viewType, bool isPartial) | |
| { | |
| static_assert(std::is_base_of<DocumentObject, T>::value, "T must be derived from DocumentObject"); | |
| return static_cast<T*>(addObject(T::getClassName(), pObjectName, isNew, viewType, isPartial)); | |
| } | |
| } // namespace App | |