Doc: Improve the App::Link documentation

This commit is contained in:
Pieter Hijma
2025-10-17 15:15:26 +02:00
parent 393434026a
commit 16592cae48

View File

@@ -51,6 +51,12 @@
namespace App
{
/**
* @brief The base class of the link extension.
*
* The functionality in this class is reused in LinkExtension, LinkElement, and
* LinkGroup.
*/
class AppExport LinkBaseExtension: public App::DocumentObjectExtension
{
EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(App::LinkExtension);
@@ -60,25 +66,31 @@ public:
LinkBaseExtension();
~LinkBaseExtension() override = default;
/// Whether the link has been touched (i.e. its linked object changed)
PropertyBool _LinkTouched;
/// Contains the object ID of the object that owns the link.
PropertyInteger _LinkOwner;
/// Cache of children of the link group.
PropertyLinkList _ChildCache; // cache for plain group expansion
/// Options for the link mode.
enum
{
LinkModeNone,
LinkModeAutoDelete,
LinkModeAutoLink,
LinkModeAutoUnlink,
LinkModeNone, ///< No mode for the link.
LinkModeAutoDelete, ///< Delete the linked object when the link is deleted.
LinkModeAutoLink, ///< Create link elements of sub-element automatically (unused).
LinkModeAutoUnlink, ///< Unused option.
};
/** \name Parameter definition
/**
* @name Parameter definition.
* @brief Parameter definition (Name, Type, Property Type, Default, Document).
*
* Parameter definition (Name, Type, Property Type, Default, Document).
* The variadic is here so that the parameter can be extended by adding
* extra fields. See LINK_PARAM_EXT() for an example
* extra fields. See LINK_PARAM_EXT() for an example.
*
* @{
*/
//@{
#define LINK_PARAM_LINK_PLACEMENT(...) \
(LinkPlacement, \
@@ -229,7 +241,7 @@ public:
#define LINK_PDOC(_param) BOOST_PP_TUPLE_ELEM(4, _param)
#define LINK_PINDEX(_param) BOOST_PP_CAT(Prop, LINK_PNAME(_param))
//@}
/// @}
#define LINK_PARAMS \
LINK_PARAM(PLACEMENT) \
@@ -253,6 +265,7 @@ public:
LINK_PARAM(COPY_ON_CHANGE_GROUP) \
LINK_PARAM(COPY_ON_CHANGE_TOUCHED)
/// The property indices.
enum PropIndex
{
#define LINK_PINDEX_DEFINE(_1, _2, _param) LINK_PINDEX(_param),
@@ -261,17 +274,49 @@ public:
BOOST_PP_SEQ_FOR_EACH(LINK_PINDEX_DEFINE, _, LINK_PARAMS) PropMax
};
/**
* @brief Set a property to a given index..
*
* @param[in] idx The property index obtained from the PropIndex enum.
* @param[in] prop The property to set.
*/
virtual void setProperty(int idx, Property* prop);
/**
* @brief Get a property by its index.
*
* @param[in] idx The property index obtained from the PropIndex enum.
*
* @return The property at the given index, or nullptr if the index is out
* of range or the property is not set.
*/
Property* getProperty(int idx);
/**
*
* @brief Get a property by its name.
*
* @param[in] name The name of the property to get.
* @return The property with the given name, or nullptr if not found.
*/
Property* getProperty(const char*);
/// Information about a link property.
struct PropInfo
{
int index;
const char* name;
Base::Type type;
const char* doc;
int index; ///< The property index obtained from the PropIndex enum.
const char* name; ///< The name of the property.
Base::Type type; ///< The type of the property.
const char* doc; ///< The documentation string of the property.
/**
* @brief Construct a property info.
*
* @param[in] index The property index obtained from the PropIndex enum.
* @param[in] name The name of the property.
* @param[in] type The type of the property.
* @param[in] doc The documentation string of the property.
*/
PropInfo(int index, const char* name, Base::Type type, const char* doc)
: index(index)
, name(name)
@@ -292,17 +337,22 @@ public:
LINK_PPTYPE(_param)::getClassTypeId(), \
LINK_PDOC(_param)));
/// Get the property info of this link.
virtual const std::vector<PropInfo>& getPropertyInfo() const;
/// A mapping from property name to its info.
using PropInfoMap = std::map<std::string, PropInfo>;
/// Get the property info map of this link.
virtual const PropInfoMap& getPropertyInfoMap() const;
/// The types for copy on change links.
enum LinkCopyOnChangeType
{
CopyOnChangeDisabled = 0,
CopyOnChangeEnabled = 1,
CopyOnChangeOwned = 2,
CopyOnChangeTracking = 3
CopyOnChangeDisabled = 0, ///< No copy on change behavior.
CopyOnChangeEnabled = 1, ///< Copy on change is enabled but not necessarily in effect.
CopyOnChangeOwned = 2, ///< Copy on change is enabled and in effect.
CopyOnChangeTracking = 3 ///< Tracking copy-on-change behavior.
};
#define LINK_PROP_GET(_1, _2, _param) \
@@ -327,18 +377,52 @@ public:
// defines get##Name##Property() and get##Name##Value() accessor
BOOST_PP_SEQ_FOR_EACH(LINK_PROP_GET, _, LINK_PARAMS)
/// Get the element list of this link.
PropertyLinkList* _getElementListProperty() const;
/// Get the element value list of this link.
const std::vector<App::DocumentObject*>& _getElementListValue() const;
/// Get the show element property.
PropertyBool* _getShowElementProperty() const;
/// Get the show element value.
bool _getShowElementValue() const;
/// Get the element count property.
PropertyInteger* _getElementCountProperty() const;
/// Get the element count value.
int _getElementCountValue() const;
/**
* @brief Get the linked children of this link.
*
* @param[in] filter If true, it will filter out objects that are a group.
*
* @return A vector of linked children.
*/
std::vector<DocumentObject*> getLinkedChildren(bool filter = true) const;
/**
* @brief Get a flattened subname.
*
* Get a flattened subname in case it references an object inside a linked
* plain group.
*
* @param[in] subname The subname to flatten.
* @return Returns the flattened subname.
*/
const char* flattenSubname(const char* subname) const;
/**
* @brief Expand the subname.
*
* Expand the subname in case it references an object inside a linked plain
* group.
*
* @param[in,out] subname The subname to expand. It will be modified in place.
*/
void expandSubname(std::string& subname) const;
/**
@@ -354,19 +438,34 @@ public:
*/
DocumentObject* getLink(int depth = 0) const;
/**
* @brief Get the transformation matrix of the link.
*
* @param[in] transform If true, it will take into account the placement of
* the link or the original object, if false, it will only provide the
* scaling.
*
* @return The transformation matrix of the link.
*/
Base::Matrix4D getTransform(bool transform) const;
/// Get the scale vector of the link.
Base::Vector3d getScaleVector() const;
/// Get the linked plain group if the linked object is a plain group.
App::GroupExtension* linkedPlainGroup() const;
/// Whether to transform the link together with the linked object.
bool linkTransform() const;
/// Get the subname of the link.
const char* getSubName() const
{
parseSubName();
return !mySubName.empty() ? mySubName.c_str() : nullptr;
}
/// Get the sub-elements of the link.
const std::vector<std::string>& getSubElements() const
{
parseSubName();
@@ -402,13 +501,56 @@ public:
Property* extensionGetPropertyByName(const char* name) const override;
/**
* @brief Get the array index from a subname.
*
* @param[in] subname The subname to get the array index from.
* @param[in,out] psubname If not null, it will point to the position
* in the subname after the array index.
*
* @return The array index, or -1 if there is no array index.
*/
static int getArrayIndex(const char* subname, const char** psubname = nullptr);
/**
* @brief Get the element index from a subname.
*
* This method will acquire the element index from a subname using various
* strategies.
*
* @param[in] subname The subname to get the element index from.
* @param[in,out] psubname If not null, it will point to the position
* in the subname after the element index.
*
* @return The element index, or -1 if there is no element index.
*/
int getElementIndex(const char* subname, const char** psubname = nullptr) const;
/**
*
* @brief Get the element name from an index.
*
* This method will return the element name corresponding to the given
* index.
*
* @param[in] idx The index of the element.
* @param[out] ss The output stream to write the element name to.
*/
void elementNameFromIndex(int idx, std::ostream& ss) const;
/// Get the container object of this link.
DocumentObject* getContainer();
/// Get the container object of this link (const version).
const DocumentObject* getContainer() const;
/**
* @brief Set the linked object.
*
* @param[in] index The index of the link property to set.
* @param[in] obj The object to link to.
* @param[in] subname The subname to link to.
* @param[in] subs The sub-elements to link to.
*/
void setLink(int index,
DocumentObject* obj,
const char* subname = nullptr,
@@ -424,17 +566,13 @@ public:
*
* @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.
*
@@ -446,52 +584,109 @@ public:
int depth = 0,
bool noElement = false) const;
using LinkPropMap = std::map<const Property*, std::pair<LinkBaseExtension*, int>>;
/// Check whether the link has a placement property.
bool hasPlacement() const
{
return getLinkPlacementProperty() || getPlacementProperty();
}
/**
* @brief Enable the cache for child labels.
*
* @param[in] enable If -1, it will enable the cache and only clear it. If
* 0, it will clear the cache and disableit. If 1, it will enable the cache and fill it
* with the current child elements.
*/
void cacheChildLabel(int enable = -1) const;
/**
* @brief Setup copy on change behavior.
*
* This static method sets up the copy on change behavior for a given object.
*
* @param[in] obj The object to set up copy on change for.
* @param[in] linked The linked object to copy from.
* @param[in,out] copyOnChangeConns The vector to store the connections for copy on change.
* @param[in] checkExisting If true, it will check the links properties
* against the properties of the linked object.
*
* @return True if the setup was successful, false otherwise.
*/
static bool
setupCopyOnChange(App::DocumentObject* obj,
App::DocumentObject* linked,
std::vector<fastsignals::scoped_connection>* copyOnChangeConns,
bool checkExisting);
/**
* @brief Check if a property is marked as copy on change.
*
* @param[in] obj The object to check the property on.
* @param[in] prop The property to check.
* @return True if the property is marked as copy on change, false otherwise.
*/
static bool isCopyOnChangeProperty(App::DocumentObject* obj, const Property& prop);
/**
* @brief Synchronize the copy on change object with the source object.
*
* This means updating the mutated copy in the copy-on-change group.
*/
void syncCopyOnChange();
/** Options used in setOnChangeCopyObject()
* Multiple options can be combined by bitwise or operator
/**
* @brief Options used in setOnChangeCopyObject()
*
* Multiple options can be combined by bitwise or operator.
*/
enum class OnChangeCopyOptions
{
/// No options set
None = 0,
/// If set, then exclude the input from object list to copy on change, or else, include the
/// input object.
Exclude = 1,
/// If set , then apply the setting to all links to the input object, or else, apply only to
/// this link.
ApplyAll = 2,
None = 0, ///< No options set
Exclude = 1, ///< Exclude an object to be copied when the configuration changes.
ApplyAll = 2, ///< Apply the configuration to all links.
};
/** Include or exclude object from list of objects to copy on change
* @param obj: input object
* @param options: control options. @sa OnChangeCopyOptions.
/**
* @brief Include or exclude an object from the list of objects to copy on change.
*
* @param[in] obj: The object to include or exclude.
* @param[in] options: control options of type OnChangeCopyOptions.
*/
void setOnChangeCopyObject(App::DocumentObject* obj, OnChangeCopyOptions options);
/**
* @brief Get the list of objects that are set to be copied on change.
*
* @param[out] excludes: If not null, it will contain the objects that are
* excluded from copy-on-change.
* @param[in] src: The source of the copy on change link. If `nullptr`, it
* will use the `LinkCopyOnChangeSource` property to determine the source
* or if not a copy-on-change link, the linked object.
*
* @return Objects that depend on the source of the copy-on-change link.
*/
std::vector<App::DocumentObject*>
getOnChangeCopyObjects(std::vector<App::DocumentObject*>* excludes = nullptr,
App::DocumentObject* src = nullptr);
/**
* @brief Check whether this link is configurable one.
*
* This essentially means that the linked object has copy-on-change properties.
*
* @return True if the link is configurable, false otherwise.
*/
bool isLinkedToConfigurableObject() const;
/**
* @brief Monitor changes on the list of copy-on-change objects.
*
* This function has as input the list of dependencies of original
* dependencies of the copy-on-change link. It sets up connections to
* monitor these original objects, to update the copy-on-change links.
*
* @param[in] objs The list of objects to monitor.
*/
void monitorOnChangeCopyObjects(const std::vector<App::DocumentObject*>& objs);
/// Check if the linked object is a copy on change
@@ -500,43 +695,140 @@ public:
protected:
void
_handleChangedPropertyName(Base::XMLReader& reader, const char* TypeName, const char* PropName);
/// Parse the subname into mySubName and mySubElements
void parseSubName() const;
/**
* @brief Update the link when a property changes.
*
* It fullfills a role similar to DocumentObject::onChanged().
*
* @param[in] parent The parent document object.
* @param[in] prop The property that changed.
*/
void update(App::DocumentObject* parent, const Property* prop);
/**
* @brief Check a property in case of copy-on-change.
*
* If a copy is a copy-on-change property in the parent, copy the property
* from the source to the link (in the copy-on-change group).
*
* @param[in] parent The parent document object.
* @param[in] prop The property to check.
*/
void checkCopyOnChange(App::DocumentObject* parent, const App::Property& prop);
/**
* @brief Setup copy-on-change behavior for this link.
*
* Transform a regular link into a copy-on-change link. This means that
* the linked object is copied in the copy-on-change group and that the
* linked object will point to this copy, while the copy-on-change source
* will point to the original.
*
* @param[in] parent The parent document object.
* @param[in] checkSource If true, it will check the and set the
* copy-on-change source property.
*/
void setupCopyOnChange(App::DocumentObject* parent, bool checkSource = false);
/**
* @brief Make a copy-of-change link from this link.
*
* This function retrieves the dependencies from the linked object and
* copies them. It will put these copies into the copy-on-change group and
* the linked object will be the root of these list of dependencies, making
* it equivalent to the original linked object.
*
* @return The new copy-on-change link object.
*/
App::DocumentObject* makeCopyOnChange();
/// Sync the link elements in this link.
void syncElementList();
/**
* @brief Detach a linked element.
*
* Depending on earlier set options, the object may be deleted.
*
* @param[in] obj The object to detach.
*/
void detachElement(App::DocumentObject* obj);
/// Detach all linked elements.
void detachElements();
/**
* @brief Check the geo element map for a linked object.
*
* This method checks if subnames are in accordance with the geo element
* map.
*
* @param[in] obj The document object containing the link.
* @param[in] linked The linked document object.
* @param[in] pyObj The Python object corresponding to the linked object.
* @param[in] postfix The postfix that should be taken into account regarding subelements.
*/
void checkGeoElementMap(const App::DocumentObject* obj,
const App::DocumentObject* linked,
PyObject** pyObj,
const char* postfix) const;
/// Update the connections for a group of link elements.
void updateGroup();
void slotChangedPlainGroup(const App::DocumentObject&, const App::Property&);
/**
* @brief Slot called when a plain group changes.
*
* @param[in] obj The document object that changed.
* @param[in] prop The property that changed.
*/
void slotChangedPlainGroup(const App::DocumentObject& obj, const App::Property& prop);
protected:
/// The properties for the link.
std::vector<Property*> props;
/// A set of elements to hide.
std::unordered_set<const App::DocumentObject*> myHiddenElements;
/// Cached subelements.
mutable std::vector<std::string> mySubElements;
/// Cached subname.
mutable std::string mySubName;
/// Connections to monitor plain group changes.
std::unordered_map<const App::DocumentObject*, fastsignals::scoped_connection>
plainGroupConns;
long prevLinkedObjectID = 0;
mutable std::unordered_map<std::string, int> myLabelCache; // for label based subname lookup
/// Cache for label based subname lookup.
mutable std::unordered_map<std::string, int> myLabelCache;
/// Whether the label cache is enabled.
mutable bool enableLabelCache {false};
/// Whether the link has old style subelement.
bool hasOldSubElement {false};
/// Connections for copy on change behavior.
std::vector<fastsignals::scoped_connection> copyOnChangeConns;
/// Connections for the source objects for copy on change.
std::vector<fastsignals::scoped_connection> copyOnChangeSrcConns;
/// Whether the link has copy on change behavior.
bool hasCopyOnChange {true};
/// Whether we are checking properties to avoid recursion.
mutable bool checkingProperty = false;
/// Whether to pause copy on change updates.
bool pauseCopyOnChange = false;
/// Connection for monitoring changes on the copy on change source.
fastsignals::scoped_connection connCopyOnChangeSource;
};
@@ -546,6 +838,13 @@ using LinkBaseExtensionPython = ExtensionPythonT<LinkBaseExtension>;
///////////////////////////////////////////////////////////////////////////
/**
* @brief The link extension class.
*
* This class implements the link extension functionality and is the extension
* that makes @ref App::Link "Link" a link.
*/
class AppExport LinkExtension: public LinkBaseExtension
{
EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(App::LinkExtension);
@@ -555,20 +854,23 @@ public:
LinkExtension();
~LinkExtension() override = default;
/** \name Helpers for defining extended parameter
/**
* @name Helpers for defining extended properties.
* @brief Macros that help define properties that extend the properties of the linked object.
*
* extended parameter definition
* (Name, Type, Property_Type, Default, Document, Property_Name,
* Derived_Property_Type, App_Property_Type, Group)
* Extended property definition:
* `(Name, Type, Property_Type, Default, %Document, Property_Name,
* Derived_Property_Type, App_Property_Type, Group)`
*
* This helper simply reuses Name as Property_Name, Property_Type as
* Derived_Property_type, Prop_None as App_Propert_Type
* This helper simply reuses `Name` as `Property_Name`, `Property_Type` as
* `Derived_Property_type`, `Prop_None` as `App_Propert_Type`.
*
* Note: Because PropertyView will merge linked object's properties into
* @note
* Because PropertyView will merge linked object's properties into
* ours, we set the default group name as ' Link' with a leading space to
* try to make our group before others
* {@
*/
//@{
#define LINK_ENAME(_param) BOOST_PP_TUPLE_ELEM(5, _param)
#define LINK_ETYPE(_param) BOOST_PP_TUPLE_ELEM(6, _param)
@@ -659,6 +961,13 @@ using LinkExtensionPython = ExtensionPythonT<LinkExtension>;
///////////////////////////////////////////////////////////////////////////
/**
* @brief The Link class.
*
* Instances of this class represent links to other objects in the document or
* even to objects in other documents.
*/
class AppExport Link: public App::DocumentObject, public App::LinkExtension
{
PROPERTY_HEADER_WITH_EXTENSIONS(App::Link);
@@ -715,6 +1024,16 @@ using LinkPython = App::FeaturePythonT<Link>;
///////////////////////////////////////////////////////////////////////////
/**
* @brief A class that represents an element of a link.
*
* A link with an element count greater than 0 will contain multiple links to
* the linked object, all with their own placement, scale, and visibility.
* These links are instances of this class. The link itself becomes a special
* link pointing to the same linked object, but its element list will contain
* references to the element links.
*/
class AppExport LinkElement: public App::DocumentObject, public App::LinkBaseExtension
{
PROPERTY_HEADER_WITH_EXTENSIONS(App::LinkElement);
@@ -733,10 +1052,12 @@ public:
LINK_PARAM_EXT(COPY_ON_CHANGE_GROUP) \
LINK_PARAM_EXT(COPY_ON_CHANGE_TOUCHED)
// defines the actual properties
/// Define the various properties for a link element.
LINK_PROPS_DEFINE(LINK_PARAMS_ELEMENT)
LinkElement();
const char* getViewProviderName() const override
{
return "Gui::ViewProviderLink";
@@ -748,6 +1069,7 @@ public:
inherited::onDocumentRestored();
}
/// Check whether this link element can be deleted.
bool canDelete() const;
void handleChangedPropertyName(Base::XMLReader& reader,
@@ -759,6 +1081,7 @@ public:
bool isLink() const override;
/// Get the parent link of this link element.
App::Link* getLinkGroup() const;
Base::Placement getPlacementOf(const std::string& sub, DocumentObject* targetObj = nullptr) override;
@@ -768,6 +1091,20 @@ using LinkElementPython = App::FeaturePythonT<LinkElement>;
///////////////////////////////////////////////////////////////////////////
/**
* @brief A class that represents a group of links.
*
* Other than "upgrading" a normal Link to having multiple @ref
* App::LinkElement "LinkElements", a link group is a grouping for document
* objects where the group itself has a separate placement or visibility of the
* elements.
*
* A link group can contain the objects directly as children (called a simple
* group), or it can contain links to the objects. In the latter case, it is
* possible to create a group with transform links which means that the
* placement of the original objects affect the placement of the links as well.
*/
class AppExport LinkGroup: public App::DocumentObject, public App::LinkBaseExtension
{
PROPERTY_HEADER_WITH_EXTENSIONS(App::LinkGroup);
@@ -781,7 +1118,7 @@ public:
LINK_PARAM_EXT(MODE) \
LINK_PARAM_EXT_ATYPE(COLORED_ELEMENTS, App::Prop_Hidden)
// defines the actual properties
/// Define the various properties of the link group.
LINK_PROPS_DEFINE(LINK_PARAMS_GROUP)
LinkGroup();