Merge pull request #25195 from pieterhijma/doc-document
Doc: Improve the documentation of Document
This commit is contained in:
@@ -461,16 +461,18 @@ public:
|
||||
/** @name Link handling */
|
||||
//@{
|
||||
|
||||
/** Check for link recursion depth
|
||||
/**
|
||||
* @brief Check for link recursion depth.
|
||||
*
|
||||
* The function uses an internal count of all objects in all documents as
|
||||
* the limit of recursion depth. If the depth exceeds this limit, it means
|
||||
* that there is likely a cyclic reference in the links.
|
||||
*
|
||||
* @param depth: current depth
|
||||
* @param option: whether to throw exception, print an error message or quieten any output.
|
||||
* In the latter case the caller must check the returned value.
|
||||
*
|
||||
* @return Return the maximum remaining depth.
|
||||
*
|
||||
* The function uses an internal count of all objects in all documents as
|
||||
* the limit of recursion depth.
|
||||
*/
|
||||
int checkLinkDepth(int depth, MessageOption option = MessageOption::Error);
|
||||
|
||||
|
||||
@@ -1251,12 +1251,12 @@ constexpr auto fcAttrDepObjName {"Name"};
|
||||
constexpr auto fcAttrDepAllowPartial {"AllowPartial"};
|
||||
constexpr auto fcElementObjectDep {"Dep"};
|
||||
|
||||
void Document::writeObjects(const std::vector<DocumentObject*>& obj,
|
||||
void Document::writeObjects(const std::vector<DocumentObject*>& objs,
|
||||
Base::Writer& writer) const
|
||||
{
|
||||
// writing the features types
|
||||
writer.incInd(); // indentation for 'Objects count'
|
||||
writer.Stream() << writer.ind() << "<Objects Count=\"" << obj.size();
|
||||
writer.Stream() << writer.ind() << "<Objects Count=\"" << objs.size();
|
||||
if (isExporting(nullptr) == 0U) {
|
||||
writer.Stream() << "\" " << fcAttrDependencies << "=\"1";
|
||||
}
|
||||
@@ -1265,7 +1265,7 @@ void Document::writeObjects(const std::vector<DocumentObject*>& obj,
|
||||
writer.incInd(); // indentation for 'Object type'
|
||||
|
||||
if (isExporting(nullptr) == 0U) {
|
||||
for (const auto o : obj) {
|
||||
for (const auto o : objs) {
|
||||
const auto& outList =
|
||||
o->getOutList(DocumentObject::OutListNoHidden | DocumentObject::OutListNoXLinked);
|
||||
writer.Stream() << writer.ind()
|
||||
@@ -1294,7 +1294,7 @@ void Document::writeObjects(const std::vector<DocumentObject*>& obj,
|
||||
}
|
||||
|
||||
std::vector<DocumentObject*>::const_iterator it;
|
||||
for (it = obj.begin(); it != obj.end(); ++it) {
|
||||
for (it = objs.begin(); it != objs.end(); ++it) {
|
||||
writer.Stream() << writer.ind() << "<Object "
|
||||
<< "type=\"" << (*it)->getTypeId().getName() << "\" "
|
||||
<< "name=\"" << (*it)->getExportName() << "\" "
|
||||
@@ -1324,10 +1324,10 @@ void Document::writeObjects(const std::vector<DocumentObject*>& obj,
|
||||
writer.Stream() << writer.ind() << "</Objects>" << '\n';
|
||||
|
||||
// writing the features itself
|
||||
writer.Stream() << writer.ind() << "<ObjectData Count=\"" << obj.size() << "\">" << '\n';
|
||||
writer.Stream() << writer.ind() << "<ObjectData Count=\"" << objs.size() << "\">" << '\n';
|
||||
|
||||
writer.incInd(); // indentation for 'Object name'
|
||||
for (it = obj.begin(); it != obj.end(); ++it) {
|
||||
for (it = objs.begin(); it != objs.end(); ++it) {
|
||||
writer.Stream() << writer.ind() << "<Object name=\"" << (*it)->getExportName() << "\"";
|
||||
if ((*it)->hasExtensions()) {
|
||||
writer.Stream() << " Extensions=\"True\"";
|
||||
@@ -2036,11 +2036,11 @@ bool Document::afterRestore(const std::vector<DocumentObject*>& objArray, bool c
|
||||
return false;
|
||||
}
|
||||
|
||||
// some link type property cannot restore link information until other
|
||||
// objects has been restored. For example, PropertyExpressionEngine and
|
||||
// PropertySheet with expression containing label reference. So we add the
|
||||
// Property::afterRestore() interface to let them sort it out. Note, this
|
||||
// API is not called in object dedpenency order, because the order
|
||||
// Some link type properties cannot restore link information until other
|
||||
// objects have been restored. For example, PropertyExpressionEngine and
|
||||
// PropertySheet with expressions containing a label reference. So we add
|
||||
// the Property::afterRestore() interface to let them sort it out. Note,
|
||||
// this API is not called in object dependency order, because the order
|
||||
// information is not ready yet.
|
||||
std::map<DocumentObject*, std::vector<Property*>> propMap;
|
||||
for (auto obj : objArray) {
|
||||
@@ -2228,7 +2228,7 @@ vector<DocumentObject*> Document::getTouched() const
|
||||
return result;
|
||||
}
|
||||
|
||||
void Document::setClosable(const bool c) // NOLINT
|
||||
void Document::setClosable(bool c) // NOLINT
|
||||
{
|
||||
setStatus(Document::Closable, c);
|
||||
}
|
||||
@@ -2508,7 +2508,7 @@ std::vector<Document*> Document::getDependentDocuments(const bool sort)
|
||||
}
|
||||
|
||||
std::vector<Document*> Document::getDependentDocuments(std::vector<Document*> docs,
|
||||
const bool sort)
|
||||
const bool sort)
|
||||
{
|
||||
DependencyList depList;
|
||||
std::map<Document*, Vertex> docMap;
|
||||
@@ -2572,11 +2572,6 @@ std::vector<Document*> Document::getDependentDocuments(std::vector<Document*> do
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Document::_rebuildDependencyList(const std::vector<DocumentObject*>& objs)
|
||||
{
|
||||
(void)objs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Signal that object identifiers, typically a property or document object has been renamed.
|
||||
*
|
||||
@@ -3144,15 +3139,15 @@ Document::addObjects(const char* sType, const std::vector<std::string>& objectNa
|
||||
return objects;
|
||||
}
|
||||
|
||||
void Document::addObject(DocumentObject* pcObject, const char* pObjectName)
|
||||
void Document::addObject(DocumentObject* obj, const char* name)
|
||||
{
|
||||
if (pcObject->getDocument()) {
|
||||
if (obj->getDocument()) {
|
||||
throw Base::RuntimeError("Document object is already added to a document");
|
||||
}
|
||||
|
||||
pcObject->setDocument(this);
|
||||
obj->setDocument(this);
|
||||
|
||||
_addObject(pcObject, pObjectName, AddObjectOption::SetNewStatus | AddObjectOption::ActivateObject);
|
||||
_addObject(obj, name, AddObjectOption::SetNewStatus | AddObjectOption::ActivateObject);
|
||||
}
|
||||
|
||||
void Document::_addObject(DocumentObject* pcObject, const char* pObjectName, AddObjectOptions options, const char* viewType)
|
||||
|
||||
1334
src/App/Document.h
1334
src/App/Document.h
File diff suppressed because it is too large
Load Diff
@@ -206,13 +206,6 @@ bool DocumentObject::recomputeFeature(bool recursive)
|
||||
return isValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set this document object touched.
|
||||
* Touching a document object does not mean to recompute it, it only means that
|
||||
* other document objects that link it (i.e. its InList) will be recomputed.
|
||||
* If it should be forced to recompute a document object then use
|
||||
* \ref enforceRecompute() instead.
|
||||
*/
|
||||
void DocumentObject::touch(bool noRecompute)
|
||||
{
|
||||
if (!noRecompute) {
|
||||
@@ -224,10 +217,6 @@ void DocumentObject::touch(bool noRecompute)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set this document object freezed.
|
||||
* A freezed document object does not recompute ever.
|
||||
*/
|
||||
void DocumentObject::freeze()
|
||||
{
|
||||
StatusBits.set(ObjectStatus::Freeze);
|
||||
@@ -250,10 +239,6 @@ void DocumentObject::freeze()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set this document object unfreezed.
|
||||
* A freezed document object does not recompute ever.
|
||||
*/
|
||||
void DocumentObject::unfreeze(bool noRecompute)
|
||||
{
|
||||
StatusBits.reset(ObjectStatus::Freeze);
|
||||
@@ -271,31 +256,16 @@ void DocumentObject::unfreeze(bool noRecompute)
|
||||
touch(noRecompute);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether the document object is touched or not.
|
||||
* @return true if document object is touched, false if not.
|
||||
*/
|
||||
bool DocumentObject::isTouched() const
|
||||
{
|
||||
return ExpressionEngine.isTouched() || StatusBits.test(ObjectStatus::Touch);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enforces this document object to be recomputed.
|
||||
* This can be useful to recompute the feature without
|
||||
* having to change one of its input properties.
|
||||
*/
|
||||
void DocumentObject::enforceRecompute()
|
||||
{
|
||||
touch(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether the document object must be recomputed or not.
|
||||
* This means that the 'Enforce' flag is set or that \ref mustExecute()
|
||||
* returns a value > 0.
|
||||
* @return true if document object must be recomputed, false if not.
|
||||
*/
|
||||
bool DocumentObject::mustRecompute() const
|
||||
{
|
||||
if (StatusBits.test(ObjectStatus::Freeze)) {
|
||||
@@ -646,7 +616,7 @@ bool DocumentObject::isInOutListRecursive(DocumentObject* linkTo) const
|
||||
}
|
||||
|
||||
std::vector<std::list<App::DocumentObject*>>
|
||||
DocumentObject::getPathsByOutList(App::DocumentObject* to) const
|
||||
DocumentObject::getPathsByOutList(const App::DocumentObject* to) const
|
||||
{
|
||||
return _pDoc->getPathsByOutList(this, to);
|
||||
}
|
||||
@@ -1210,33 +1180,16 @@ void DocumentObject::Save(Base::Writer& writer) const
|
||||
App::ExtensionContainer::Save(writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Associate the expression \expr with the object identifier \a path in this document object.
|
||||
* @param path Target object identifier for the result of the expression
|
||||
* @param expr Expression tree
|
||||
*/
|
||||
|
||||
void DocumentObject::setExpression(const ObjectIdentifier& path, std::shared_ptr<Expression> expr)
|
||||
{
|
||||
ExpressionEngine.setValue(path, std::move(expr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear the expression of the object identifier \a path in this document object.
|
||||
* @param path Target object identifier
|
||||
*/
|
||||
|
||||
void DocumentObject::clearExpression(const ObjectIdentifier& path)
|
||||
{
|
||||
setExpression(path, std::shared_ptr<Expression>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get expression information associated with \a path.
|
||||
* @param path Object identifier
|
||||
* @return Expression info, containing expression and optional comment.
|
||||
*/
|
||||
|
||||
const PropertyExpressionEngine::ExpressionInfo
|
||||
DocumentObject::getExpression(const ObjectIdentifier& path) const
|
||||
{
|
||||
@@ -1250,13 +1203,6 @@ DocumentObject::getExpression(const ObjectIdentifier& path) const
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Invoke ExpressionEngine's renameObjectIdentifier, to possibly rewrite expressions using
|
||||
* the \a paths map with current and new identifiers.
|
||||
*
|
||||
* @param paths
|
||||
*/
|
||||
|
||||
void DocumentObject::renameObjectIdentifiers(
|
||||
const std::map<ObjectIdentifier, ObjectIdentifier>& paths)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -97,10 +97,31 @@ public:
|
||||
*/
|
||||
virtual bool extensionGetSubObjects(std::vector<std::string>& ret, int reason) const;
|
||||
|
||||
/** Get the linked object
|
||||
* @sa DocumentObject::getLinkedObject()
|
||||
/**
|
||||
* @brief Get the linked object of this extension.
|
||||
*
|
||||
* @return Return turn if handled, the linked object is returned in \c ret
|
||||
* This method returns the linked object of this document object. If there
|
||||
* is no linked object, it will return the container object of the
|
||||
* extension.
|
||||
*
|
||||
* @param[out] ret The linked object is returned in this parameter.
|
||||
*
|
||||
* @param[in] recurse If true, it will recursively resolve the link until it
|
||||
* reaches the final linked object.
|
||||
*
|
||||
* @param mat[in,out] If non-null, it is used as the current transformation
|
||||
* matrix on input. On output it is used as the accumulated transformation
|
||||
* up until the final linked object.
|
||||
*
|
||||
* @param[in] transform If false, then it will not accumulate the object's own
|
||||
* placement into @p mat, which lets you override the object's placement.
|
||||
*
|
||||
* @param[in] depth This parameter indicates the level on which we are
|
||||
* resolving the link.
|
||||
*
|
||||
* @return Returns true if the linked object is successfully retrieved and
|
||||
* returned in @p ret. If the linked object is not found or is invalid, it
|
||||
* returns false.
|
||||
*/
|
||||
virtual bool extensionGetLinkedObject(DocumentObject*& ret,
|
||||
bool recursive,
|
||||
|
||||
@@ -97,7 +97,6 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
* This class creates the dependency graph for a document.
|
||||
*
|
||||
*/
|
||||
|
||||
class GraphCreator
|
||||
{
|
||||
public:
|
||||
@@ -132,7 +131,6 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
* @param docObj Document object to get an ID from
|
||||
* @return A string
|
||||
*/
|
||||
|
||||
std::string getId(const DocumentObject* docObj)
|
||||
{
|
||||
std::string id;
|
||||
@@ -150,7 +148,6 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
* @param path
|
||||
* @return A string
|
||||
*/
|
||||
|
||||
std::string getId(const ObjectIdentifier& path)
|
||||
{
|
||||
DocumentObject* docObj = path.getDocumentObject();
|
||||
@@ -183,7 +180,6 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
* @brief setGraphAttributes Set graph attributes on a subgraph for a DocumentObject node.
|
||||
* @param obj DocumentObject
|
||||
*/
|
||||
|
||||
void setGraphAttributes(const DocumentObject* obj)
|
||||
{
|
||||
assert(GraphList.find(obj) != GraphList.end());
|
||||
@@ -201,7 +197,6 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
* @param vertex Property node
|
||||
* @param name Name of node
|
||||
*/
|
||||
|
||||
void setPropertyVertexAttributes(Graph& g, Vertex vertex, const std::string& name)
|
||||
{
|
||||
get(vertex_attribute, g)[vertex]["label"] = name;
|
||||
@@ -217,7 +212,6 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
* @param obj DocumentObject to assess.
|
||||
* @param CSSubgraphs Boolean if the GeoFeatureGroups are created as subgraphs
|
||||
*/
|
||||
|
||||
void addExpressionSubgraphIfNeeded(DocumentObject* obj, bool CSsubgraphs)
|
||||
{
|
||||
|
||||
@@ -283,7 +277,6 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
* @param docObj The document object to add.
|
||||
* @param name Name of node.
|
||||
*/
|
||||
|
||||
void add(DocumentObject* docObj,
|
||||
const std::string& name,
|
||||
const std::string& label,
|
||||
|
||||
@@ -341,6 +341,17 @@ public:
|
||||
const char* flattenSubname(const char* subname) const;
|
||||
void expandSubname(std::string& subname) const;
|
||||
|
||||
/**
|
||||
* @brief Get the object the link points to.
|
||||
*
|
||||
* This method returns the linked object of this link. The @p depth
|
||||
* parameter is used as an indication of how deep the recursion is as a
|
||||
* safeguard against infinite recursion caused by cyclic dependencies.
|
||||
*
|
||||
* @param[in] depth The level on which we are resolving the link.
|
||||
*
|
||||
* @return Returns the linked object or @c nullptr if there is no linked value.
|
||||
*/
|
||||
DocumentObject* getLink(int depth = 0) const;
|
||||
|
||||
Base::Matrix4D getTransform(bool transform) const;
|
||||
@@ -403,6 +414,33 @@ public:
|
||||
const char* subname = nullptr,
|
||||
const std::vector<std::string>& subs = std::vector<std::string>());
|
||||
|
||||
/**
|
||||
* @brief Get the true linked object.
|
||||
*
|
||||
* This method returns the true linked object, which is the object that the
|
||||
* link points to. The @p depth parameter is used as an indication of the
|
||||
* current level of recursion is as a safeguard against infinite recursion
|
||||
* caused by cyclic dependencies.
|
||||
*
|
||||
* @param recurse If true, it will recursively resolve the link until it reaches
|
||||
* the final linked object, or until it reaches the maximum recursion depth.
|
||||
*
|
||||
* @param mat If non-null, it is used as the current transformation matrix on
|
||||
* input. On output it is used as the accumulated transformation up until
|
||||
* the final linked object.
|
||||
*
|
||||
* @param depth This parameter indicates the level on which we are
|
||||
* resolving the link.
|
||||
*
|
||||
* @param noElement If true, it will not return the linked object if it is
|
||||
* a link to an element.
|
||||
*
|
||||
* @return Returns the true linked object. If the linked object is not found
|
||||
* or is invalid, it returns @c nullptr.
|
||||
*
|
||||
* @sa DocumentObject::getLinkedObject() which may return itself if it is not a link.
|
||||
*
|
||||
*/
|
||||
DocumentObject* getTrueLinkedObject(bool recurse,
|
||||
Base::Matrix4D* mat = nullptr,
|
||||
int depth = 0,
|
||||
|
||||
@@ -100,7 +100,6 @@ public:
|
||||
/**
|
||||
* @brief The ExpressionInfo struct encapsulates an expression.
|
||||
*/
|
||||
|
||||
struct ExpressionInfo
|
||||
{
|
||||
std::shared_ptr<App::Expression> expression; /**< The actual expression tree */
|
||||
|
||||
@@ -262,14 +262,20 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** Update object label reference in this property
|
||||
/**
|
||||
* @brief Update the object label reference of this property.
|
||||
*
|
||||
* @param obj: the object owner of the changing label
|
||||
* @param ref: subname reference to old label
|
||||
* @param newLabel: the future new label
|
||||
* This method does not update the property itself, but returns a copy of
|
||||
* the property with the updated label reference if the property is
|
||||
* affected. The copy will later be assigned to this property by calling its
|
||||
* Paste() method.
|
||||
*
|
||||
* @return Returns a copy of the property if its link reference is affected.
|
||||
* The copy will later be assgiend to this property by calling its Paste().
|
||||
* @param[in] obj The object owner of the changing label.
|
||||
* @param[in] ref The subname reference to old label.
|
||||
* @param[in] newLabel The future new label.
|
||||
*
|
||||
* @return A copy of the property if its link reference is affected,
|
||||
* otherwise `nullptr`.
|
||||
*/
|
||||
virtual Property*
|
||||
CopyOnLabelChange(App::DocumentObject* obj, const std::string& ref, const char* newLabel) const
|
||||
@@ -556,13 +562,17 @@ public:
|
||||
*/
|
||||
static void getLabelReferences(std::vector<std::string>& labels, const char* subname);
|
||||
|
||||
/** Helper function to collect changed property when an object re-label
|
||||
/**
|
||||
* @brief Update label references on label change of a document object.
|
||||
*
|
||||
* @param obj: the object that owns the label
|
||||
* @param newLabel: the new label
|
||||
* This helper function collects changed properties when an object re-label
|
||||
* takes place. It returns a map from affected properties to copies of
|
||||
* those affectedd propertiess with updated subname references.
|
||||
*
|
||||
* @return return a map from the affected property to a copy of it with
|
||||
* updated subname references
|
||||
* @param[in] obj The object that owns the label that is changed.
|
||||
* @param[in] newLabel The new label of the object.
|
||||
*
|
||||
* @return The map from affected property to a copy of it.
|
||||
*/
|
||||
static std::vector<std::pair<Property*, std::unique_ptr<Property>>>
|
||||
updateLabelReferences(App::DocumentObject* obj, const char* newLabel);
|
||||
|
||||
@@ -19,36 +19,225 @@
|
||||
/**
|
||||
* @defgroup DocumentGroup Document
|
||||
* @ingroup APP
|
||||
* @brief The class that represents a FreeCAD document
|
||||
* @brief The class that represents a FreeCAD document.
|
||||
*
|
||||
* This (besides the App::Application class) is the most important class in FreeCAD.
|
||||
* It contains all the data of the opened, saved, or newly created FreeCAD Document.
|
||||
* The App::Document manages the Undo and Redo mechanism and the linking of documents.
|
||||
* This (besides the App::Application class) is the most important class in
|
||||
* FreeCAD. It contains all the data of the opened, saved, or newly created
|
||||
* FreeCAD %Document. The App::Document class manages the undo and redo
|
||||
* mechanism and linking of documents.
|
||||
*
|
||||
* Note: the documents are not free objects. They are completely handled by the
|
||||
* App::Application. Only the Application can Open or destroy a document.
|
||||
* Note: Documents are not freestanding objects. They are completely handled by the
|
||||
* App::Application class. Only the application can open or destroy a document.
|
||||
*
|
||||
* \section Exception Exception handling
|
||||
* As the document is the main data structure of FreeCAD we have to take a close
|
||||
* look at how Exceptions affect the integrity of the App::Document.
|
||||
* @section SecDocumentProperties Documents as property containers
|
||||
*
|
||||
* \section UndoRedo Undo Redo an Transactions
|
||||
* Undo Redo handling is one of the major mechanism of a document in terms of
|
||||
* user friendliness and speed (no one will wait for Undo too long).
|
||||
* The main role of a document is being a container of @ref DocumentObjectGroup
|
||||
* "DocumentObjects". Both a @ref DocumentObjectGroup "DocumentObject" and a
|
||||
* @ref App::Document "Document" are @ref PropertyFramework
|
||||
* "PropertyContainers" and can hold properties.
|
||||
*
|
||||
* \section Dependency Graph and dependency handling
|
||||
* The FreeCAD document handles the dependencies of its DocumentObjects with
|
||||
* an adjacency list. This gives the opportunity to calculate the shortest
|
||||
* recompute path. Also, it enables more complicated dependencies beyond trees.
|
||||
* However, there is a crucial difference between the properties in a document
|
||||
* and in a document object. The properties in a document cannot be the target
|
||||
* of expressions and they do not take part in the dependency check mechanism.
|
||||
* This means that if a document object references a property of a document and
|
||||
* the document property is changed, the document object that references the
|
||||
* document property will not be marked to be recomputed. As such, the
|
||||
* properties in a document should be regarded as simple properties for
|
||||
* file-related information.
|
||||
*
|
||||
* @see App::Application
|
||||
* @see App::DocumentObject
|
||||
* @section SecObjectManagement Object management
|
||||
*
|
||||
* As mentioned above, a document is a container of document objects. Document
|
||||
* objects can only exist inside a document and the document provides
|
||||
* functionality to create, remove, and access document objects. For example,
|
||||
* it is possible to get objects of a specific type or with a specific
|
||||
* extension.
|
||||
*
|
||||
* The document also manages the names and labels document objects, ensuring
|
||||
* that names are unique and that labels are unique if configured to have
|
||||
* unique labels.
|
||||
*
|
||||
* @section DependencyGraph Dependencies between document objects
|
||||
*
|
||||
* Objects can link to other objects in the same document or in other documents
|
||||
* and as such dependencies between document objects come into existence. The
|
||||
* document is responsible for recomputing document objects if some property of
|
||||
* a document object changes. The dependencies between document objects
|
||||
* determine in which order the objects must be recomputed.
|
||||
*
|
||||
* To compute the objects in the right order, the document computes a
|
||||
* dependency graph based on the information contained in the OutLists and
|
||||
* InLists of the document objects. For more information on OutLists and
|
||||
* InLists, see @ref SecDocumentObjectRecompute "Document Objects". Given the
|
||||
* dependency graph, the document computes the list of objects in topological
|
||||
* order (not to be confused with topological naming) which means that the
|
||||
* objects without dependencies come first and then the objects that depend on
|
||||
* these objects, etc.
|
||||
*
|
||||
* The document will check for each object in the list whether the object is
|
||||
* "touched", which means that it is marked to be recomputed. If so, the
|
||||
* object is recomputed and the objects in the InList of that object are
|
||||
* touched as well. Because of the topological order, these objects will come
|
||||
* in a later iteration.
|
||||
*
|
||||
* This mechanism allows FreeCAD to recompute only the objects that need to be
|
||||
* recomputed and in only one pass over the list of objects. However, it is
|
||||
* important that the dependency graph does not contain cycles and is a
|
||||
* "Directed Acyclic Graph" or DAG. As such, cyclic dependencies are not
|
||||
* allowed in FreeCAD.
|
||||
*
|
||||
* @section SecUndoRedo Undo Redo and Transactions
|
||||
*
|
||||
* Another important responsbility of documents is to manage undo and redo
|
||||
* actions. The information to support undo and redo is captured in
|
||||
* transactions. It is important to understand that transactions are a feature
|
||||
* of document objects and not of documents. This means that a change of a
|
||||
* property inside a document (as opposed to inside a document object) is not
|
||||
* captured by the transaction system (similar to the fact that document
|
||||
* properties do not support expressions).
|
||||
*
|
||||
* The transaction system is quite complex and acts on various levels.
|
||||
* Although the transactions themselves only capture changes regarding document
|
||||
* objects, the transactions are managed in the document. Although the
|
||||
* transactions are managed inside a document, it is possible to support
|
||||
* transactions that affect multiple documents. This is managed by the GUI and
|
||||
* if a change affects multiple documents, then all documents will store
|
||||
* transactions that change its document and they will all have the same
|
||||
* transaction ID.
|
||||
*
|
||||
* The mechanisms for undo and redo are part of the @ref APP "App" level, but
|
||||
* the GUI defines the transactions (where to open a transaction, where to
|
||||
* commit or abort) and it initiates the undo and redo actions.
|
||||
*
|
||||
* The transaction system makes use of classes with very similar names which
|
||||
* can be confusing. Here is a short overview:
|
||||
*
|
||||
* - A @ref App::TransactionalObject "TransactionalObject" is a base class that
|
||||
* provides the functionality to support transactions. It is inherited by
|
||||
* @ref App::DocumentObject "DocumentObject".
|
||||
* - A @ref App::TransactionObject "TransactionObject" is a class that
|
||||
* represents a single action and can express adding a new object, removing
|
||||
* an object or changing an object. Subclasses of the transaction object are
|
||||
* @ref App::TransactionDocumentObject "TransactionDocumentObject" and
|
||||
* @ref Gui::TransactionViewProvider "Gui::TransactionViewProvider".
|
||||
* - A @ref App::Transaction "Transaction" captures a single undo or redo
|
||||
* action and consists of multiple @ref App::TransactionObject
|
||||
* "TransactionObjects" associated with their @ref App::TransactionalObject
|
||||
* "TransactionalObject", often a @ref App::DocumentObject "DocumentObject".
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup DocumentObjectGroup Document Object
|
||||
* @ingroup APP
|
||||
* @brief %Base class of all objects handled in the Document.
|
||||
* @brief %Base class of all objects handled in the @ref App::Document "Document".
|
||||
*
|
||||
* A DocumentObject is the base class of all objects that can be contained in a
|
||||
* FreeCAD @ref App::Document "Document". Document objects can represent any
|
||||
* object that can be created in a FreeCAD Document, such as features:
|
||||
* Part::Feature, Mesh::Feature, Sketcher::SketchObject, but also other objects
|
||||
* such as App::Link, App::DocumentObjectGroup, App::VarSet, or
|
||||
* SpreadSheet::Sheet that do not necessary represent geometry.
|
||||
*
|
||||
* Document objects provide the functionality to handle properties (it extends
|
||||
* @ref App::PropertyContainer "PropertyContainer"), transactions (it extends
|
||||
* @ref App::TransactionalObject "TransactionalObject") and extensions (it
|
||||
* extends @ref App::ExtensionContainer "ExtensionContainer"), and expressions.
|
||||
* Expressions are managed by the property @ref
|
||||
* App::DocumentObject::ExpressionEngine "ExpressionEngine", which is a special
|
||||
* type of a link property that contains expressions that may link to other
|
||||
* document objects.
|
||||
*
|
||||
* @section SecDocumentObjectRecompute Recomputing Document Objects
|
||||
*
|
||||
* Objects can be recomputed, which means that the properties of the object are
|
||||
* recomputed. Since properties may depend on other document objects, for
|
||||
* example because of the @ref App::DocumentObject::ExpressionEngine
|
||||
* "ExpressionEngine" property, these document objects have to be computed
|
||||
* first. Managing the order of recomputation is managed by the @ref
|
||||
* App::Document "Document" which calls the @ref
|
||||
* App::DocumentObject::recompute() "recompute()" on the document object. To
|
||||
* signal that a document object needs to be recomputed, the document object
|
||||
* can be touched (see @ref App::DocumentObject::touch() "touch()" and @ref
|
||||
* App::DocumentObject::isTouched() "isTouched()").
|
||||
*
|
||||
* As part of recomputation, the document object can also be executed or
|
||||
* "invoked", (see @ref App::DocumentObject::execute() "execute()") which
|
||||
* results in recomputing the output properties of the object.
|
||||
*
|
||||
* Although recomputation is mostly orchestrated by the @ref App::Document
|
||||
* "Document", document objects play an important role in capturing the
|
||||
* dependencies between document objects in terms of OutLists and InLists.
|
||||
*
|
||||
* Dependencies between document objects come into existence because of links
|
||||
* and if a document object `A` links to another document object `B`, then `B`
|
||||
* is in the OutList of `A` and `A` is in the InList of `B`. The InList for an
|
||||
* object `Obj` represents the document objects that are dependent on it. The
|
||||
* outlist of an object `Obj` represent the dependencies of it. So, to
|
||||
* recompute `Obj`, first the objects in the outlist need to be recomputed.
|
||||
* Vice versa, if a property of an object is changed, the InList indicates
|
||||
* which other objects depend on it and need to be recomputed.
|
||||
*
|
||||
* So, as mentioned above, links define dependencies between document objects
|
||||
* These dependencies are recorded by means of setting the value of a @ref
|
||||
* App::PropertyLink "PropertyLink" (and similar properties) in a document
|
||||
* object `Obj` to a document object `Value`. Within @ref
|
||||
* App::PropertyLink::setValue() "PropertyLink::setValue()" (and similar
|
||||
* methods for other link properties), the (internal) methods _addBackLink() or
|
||||
* _removeBackLink() will be called on `Value` with as argument the container
|
||||
* of the property link `Obj`, indicating that `Obj` depends on `Value`. With
|
||||
* this methodology, each document object will build up its own InList that can
|
||||
* be used during recomputation to query which other document objects need to
|
||||
* be computed.
|
||||
*
|
||||
* The OutList and InList can be accessed by the methods @ref
|
||||
* App::DocumentObject::getOutList() "getOutList()" and @ref
|
||||
* App::DocumentObject::getInList() "getInList()".
|
||||
*
|
||||
* @section SecDocumentObjectProperties Properties
|
||||
*
|
||||
* The document object introduces three properties:
|
||||
*
|
||||
* - @ref App::DocumentObject::Label "Label" which is a string that identifies
|
||||
* the object in the document and is used to display the object in the GUI.
|
||||
* - @ref App::DocumentObject::Label2 "Label2" which is a string that contains
|
||||
* additional information about the object and is used for the description of
|
||||
* the object.
|
||||
* - @ref App::DocumentObject::ExpressionEngine "ExpressionEngine" which
|
||||
* contains a mapping from @ref App::ObjectIdentifier "ObjectIdentifier" to
|
||||
* @ref App::Expression "Expression". The object identifier defines the
|
||||
* properties that store the result of the expression.
|
||||
* - @ref App::DocumentObject::Visibility "Visibility" which is a boolean
|
||||
* that indicates whether the object is visible in App namespace.
|
||||
*
|
||||
* @section SecDocumentObjectSignals Signals
|
||||
*
|
||||
* A document object has three signals that can be connected to:
|
||||
*
|
||||
* - @ref App::DocumentObject::signalBeforeChange "signalBeforeChange" which is
|
||||
* emitted before a property of the document object is changed. This signal
|
||||
* can be used to prepare for changes to the document object.
|
||||
* - @ref App::DocumentObject::signalChanged "signalChanged" which is emitted
|
||||
* after a property of the document object has changed.
|
||||
* - @ref App::DocumentObject::signalEarlyChanged "signalEarlyChanged" which
|
||||
* is also emitted after a property has changed but emitted right before
|
||||
* "signalChanged".
|
||||
*
|
||||
* Note that at the @ref App::Document "Document" level, there are also similar
|
||||
* signals.
|
||||
*
|
||||
* @section SecDocumentObjectSeparation Separation App/Gui
|
||||
*
|
||||
* In FreeCAD there is a strict separation between the App and Gui parts. A
|
||||
* @ref App::DocumentObject "DocumentObject" typically has a Gui::ViewProvider
|
||||
* class associated with it. The method @ref
|
||||
* App::DocumentObject::getViewProviderName() "getViewProviderName()" defines
|
||||
* what the type of the class of the view provider is, allowing the Gui to
|
||||
* retrieve the type and construct a view provider.
|
||||
*
|
||||
* Another intresting aspect of the separation is that the property @ref
|
||||
* App::DocumentObject::Visibility "Visibility" is defined both in
|
||||
* App::DocumentObject and in @ref Gui::ViewProviderDocumentObject::Visibility
|
||||
* "Gui::ViewProviderDocumentObject".
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user