872 lines
41 KiB
C++
872 lines
41 KiB
C++
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
/****************************************************************************
|
|
* Copyright (c) 2017 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
|
|
* *
|
|
* 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 *
|
|
* *
|
|
****************************************************************************/
|
|
|
|
#ifndef APP_LINK_H
|
|
#define APP_LINK_H
|
|
|
|
#include <unordered_set>
|
|
#include <Base/Parameter.h>
|
|
#include <Base/Bitmask.h>
|
|
#include "DocumentObject.h"
|
|
#include "DocumentObjectExtension.h"
|
|
#include "FeaturePython.h"
|
|
#include "GroupExtension.h"
|
|
#include "PropertyLinks.h"
|
|
|
|
|
|
// FIXME: ISO C++11 requires at least one argument for the "..." in a variadic macro
|
|
#if defined(__clang__)
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
|
|
#endif
|
|
|
|
#define LINK_THROW(_type, _msg) \
|
|
do { \
|
|
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) \
|
|
FC_ERR(_msg); \
|
|
throw _type(_msg); \
|
|
} while (0)
|
|
|
|
namespace App
|
|
{
|
|
|
|
class AppExport LinkBaseExtension: public App::DocumentObjectExtension
|
|
{
|
|
EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(App::LinkExtension);
|
|
using inherited = App::DocumentObjectExtension;
|
|
|
|
public:
|
|
LinkBaseExtension();
|
|
~LinkBaseExtension() override = default;
|
|
|
|
PropertyBool _LinkTouched;
|
|
PropertyInteger _LinkOwner;
|
|
PropertyLinkList _ChildCache; // cache for plain group expansion
|
|
|
|
enum
|
|
{
|
|
LinkModeNone,
|
|
LinkModeAutoDelete,
|
|
LinkModeAutoLink,
|
|
LinkModeAutoUnlink,
|
|
};
|
|
|
|
/** \name Parameter definition
|
|
*
|
|
* 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
|
|
*/
|
|
//@{
|
|
|
|
#define LINK_PARAM_LINK_PLACEMENT(...) \
|
|
(LinkPlacement, \
|
|
Base::Placement, \
|
|
App::PropertyPlacement, \
|
|
Base::Placement(), \
|
|
"Link placement", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_PLACEMENT(...) \
|
|
(Placement, \
|
|
Base::Placement, \
|
|
App::PropertyPlacement, \
|
|
Base::Placement(), \
|
|
"Alias to LinkPlacement to make the link object compatibale with other objects", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_OBJECT(...) \
|
|
(LinkedObject, App::DocumentObject*, App::PropertyLink, 0, "Linked object", ##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_TRANSFORM(...) \
|
|
(LinkTransform, \
|
|
bool, \
|
|
App::PropertyBool, \
|
|
false, \
|
|
"Set to false to override linked object's placement", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_CLAIM_CHILD(...) \
|
|
(LinkClaimChild, \
|
|
bool, \
|
|
App::PropertyBool, \
|
|
false, \
|
|
"Claim the linked object as a child", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_COPY_ON_CHANGE(...) \
|
|
(LinkCopyOnChange, \
|
|
long, \
|
|
App::PropertyEnumeration, \
|
|
((long)0), \
|
|
"Disabled: turns off copy-on-change\n" \
|
|
"Enabled: copies the linked object when any property marked CopyOnChange changes\n" \
|
|
"Owned: the linked object has been copied and is owned by the link; changes to the original\n"\
|
|
" will be synced back to the copy\n" \
|
|
"Tracking: copies the linked object when any property marked CopyOnChange changes, and keeps\n"\
|
|
" future edits to the link in sync with the original", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_COPY_ON_CHANGE_SOURCE(...) \
|
|
(LinkCopyOnChangeSource, \
|
|
App::DocumentObject*, \
|
|
App::PropertyLink, \
|
|
0, \
|
|
"The copy-on-change source object", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_COPY_ON_CHANGE_GROUP(...) \
|
|
(LinkCopyOnChangeGroup, \
|
|
App::DocumentObject*, \
|
|
App::PropertyLink, \
|
|
0, \
|
|
"Linked to an internal group object for holding on change copies", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_COPY_ON_CHANGE_TOUCHED(...) \
|
|
(LinkCopyOnChangeTouched, \
|
|
bool, \
|
|
App::PropertyBool, \
|
|
0, \
|
|
"Indicating the copy on change source object has been changed", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_SCALE(...) \
|
|
(Scale, double, App::PropertyFloat, 1.0, "Scale factor", ##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_SCALE_VECTOR(...) \
|
|
(ScaleVector, \
|
|
Base::Vector3d, \
|
|
App::PropertyVector, \
|
|
Base::Vector3d(1, 1, 1), \
|
|
"Scale factors", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_PLACEMENTS(...) \
|
|
(PlacementList, \
|
|
std::vector<Base::Placement>, \
|
|
App::PropertyPlacementList, \
|
|
std::vector<Base::Placement>(), \
|
|
"The placement for each link element", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_SCALES(...) \
|
|
(ScaleList, \
|
|
std::vector<Base::Vector3d>, \
|
|
App::PropertyVectorList, \
|
|
std::vector<Base::Vector3d>(), \
|
|
"The scale factors for each link element", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_VISIBILITIES(...) \
|
|
(VisibilityList, \
|
|
boost::dynamic_bitset<>, \
|
|
App::PropertyBoolList, \
|
|
boost::dynamic_bitset<>(), \
|
|
"The visibility state of each link element", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_COUNT(...) \
|
|
(ElementCount, int, App::PropertyInteger, 0, "Link element count", ##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_ELEMENTS(...) \
|
|
(ElementList, \
|
|
std::vector<App::DocumentObject*>, \
|
|
App::PropertyLinkList, \
|
|
std::vector<App::DocumentObject*>(), \
|
|
"The link element object list", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_SHOW_ELEMENT(...) \
|
|
(ShowElement, bool, App::PropertyBool, true, "Enable link element list", ##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_MODE(...) \
|
|
(LinkMode, long, App::PropertyEnumeration, ((long)0), "Link group mode", ##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_LINK_EXECUTE(...) \
|
|
(LinkExecute, \
|
|
const char*, \
|
|
App::PropertyString, \
|
|
(""), \
|
|
"Link execute function. Default to 'appLinkExecute'. 'None' to disable.", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM_COLORED_ELEMENTS(...) \
|
|
(ColoredElements, \
|
|
App::DocumentObject*, \
|
|
App::PropertyLinkSubHidden, \
|
|
0, \
|
|
"Link colored elements", \
|
|
##__VA_ARGS__)
|
|
|
|
#define LINK_PARAM(_param) (LINK_PARAM_##_param())
|
|
|
|
#define LINK_PNAME(_param) BOOST_PP_TUPLE_ELEM(0, _param)
|
|
#define LINK_PTYPE(_param) BOOST_PP_TUPLE_ELEM(1, _param)
|
|
#define LINK_PPTYPE(_param) BOOST_PP_TUPLE_ELEM(2, _param)
|
|
#define LINK_PDEF(_param) BOOST_PP_TUPLE_ELEM(3, _param)
|
|
#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) \
|
|
LINK_PARAM(LINK_PLACEMENT) \
|
|
LINK_PARAM(OBJECT) \
|
|
LINK_PARAM(CLAIM_CHILD) \
|
|
LINK_PARAM(TRANSFORM) \
|
|
LINK_PARAM(SCALE) \
|
|
LINK_PARAM(SCALE_VECTOR) \
|
|
LINK_PARAM(PLACEMENTS) \
|
|
LINK_PARAM(SCALES) \
|
|
LINK_PARAM(VISIBILITIES) \
|
|
LINK_PARAM(COUNT) \
|
|
LINK_PARAM(ELEMENTS) \
|
|
LINK_PARAM(SHOW_ELEMENT) \
|
|
LINK_PARAM(MODE) \
|
|
LINK_PARAM(LINK_EXECUTE) \
|
|
LINK_PARAM(COLORED_ELEMENTS) \
|
|
LINK_PARAM(COPY_ON_CHANGE) \
|
|
LINK_PARAM(COPY_ON_CHANGE_SOURCE) \
|
|
LINK_PARAM(COPY_ON_CHANGE_GROUP) \
|
|
LINK_PARAM(COPY_ON_CHANGE_TOUCHED)
|
|
|
|
enum PropIndex
|
|
{
|
|
#define LINK_PINDEX_DEFINE(_1, _2, _param) LINK_PINDEX(_param),
|
|
|
|
// defines Prop##Name enumeration value
|
|
BOOST_PP_SEQ_FOR_EACH(LINK_PINDEX_DEFINE, _, LINK_PARAMS) PropMax
|
|
};
|
|
|
|
virtual void setProperty(int idx, Property* prop);
|
|
Property* getProperty(int idx);
|
|
Property* getProperty(const char*);
|
|
|
|
struct PropInfo
|
|
{
|
|
int index;
|
|
const char* name;
|
|
Base::Type type;
|
|
const char* doc;
|
|
|
|
PropInfo(int index, const char* name, Base::Type type, const char* doc)
|
|
: index(index)
|
|
, name(name)
|
|
, type(type)
|
|
, doc(doc)
|
|
{}
|
|
|
|
PropInfo()
|
|
: index(0)
|
|
, name(nullptr)
|
|
, doc(nullptr)
|
|
{}
|
|
};
|
|
|
|
#define LINK_PROP_INFO(_1, _var, _param) \
|
|
_var.push_back(PropInfo(BOOST_PP_CAT(Prop, LINK_PNAME(_param)), \
|
|
BOOST_PP_STRINGIZE(LINK_PNAME(_param)), \
|
|
LINK_PPTYPE(_param)::getClassTypeId(), \
|
|
LINK_PDOC(_param)));
|
|
|
|
virtual const std::vector<PropInfo>& getPropertyInfo() const;
|
|
|
|
using PropInfoMap = std::map<std::string, PropInfo>;
|
|
virtual const PropInfoMap& getPropertyInfoMap() const;
|
|
|
|
enum LinkCopyOnChangeType
|
|
{
|
|
CopyOnChangeDisabled = 0,
|
|
CopyOnChangeEnabled = 1,
|
|
CopyOnChangeOwned = 2,
|
|
CopyOnChangeTracking = 3
|
|
};
|
|
|
|
#define LINK_PROP_GET(_1, _2, _param) \
|
|
LINK_PTYPE(_param) BOOST_PP_SEQ_CAT((get)(LINK_PNAME(_param))(Value))() const \
|
|
{ \
|
|
auto prop = props[LINK_PINDEX(_param)]; \
|
|
if (!prop) \
|
|
return LINK_PDEF(_param); \
|
|
return static_cast<const LINK_PPTYPE(_param)*>(prop)->getValue(); \
|
|
} \
|
|
const LINK_PPTYPE(_param) * BOOST_PP_SEQ_CAT((get)(LINK_PNAME(_param))(Property))() const \
|
|
{ \
|
|
auto prop = props[LINK_PINDEX(_param)]; \
|
|
return static_cast<const LINK_PPTYPE(_param)*>(prop); \
|
|
} \
|
|
LINK_PPTYPE(_param) * BOOST_PP_SEQ_CAT((get)(LINK_PNAME(_param))(Property))() \
|
|
{ \
|
|
auto prop = props[LINK_PINDEX(_param)]; \
|
|
return static_cast<LINK_PPTYPE(_param)*>(prop); \
|
|
}
|
|
|
|
// defines get##Name##Property() and get##Name##Value() accessor
|
|
BOOST_PP_SEQ_FOR_EACH(LINK_PROP_GET, _, LINK_PARAMS)
|
|
|
|
PropertyLinkList* _getElementListProperty() const;
|
|
const std::vector<App::DocumentObject*>& _getElementListValue() const;
|
|
|
|
PropertyBool* _getShowElementProperty() const;
|
|
bool _getShowElementValue() const;
|
|
|
|
PropertyInteger* _getElementCountProperty() const;
|
|
int _getElementCountValue() const;
|
|
|
|
std::vector<DocumentObject*> getLinkedChildren(bool filter = true) const;
|
|
|
|
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;
|
|
Base::Vector3d getScaleVector() const;
|
|
|
|
App::GroupExtension* linkedPlainGroup() const;
|
|
|
|
bool linkTransform() const;
|
|
|
|
const char* getSubName() const
|
|
{
|
|
parseSubName();
|
|
return !mySubName.empty() ? mySubName.c_str() : nullptr;
|
|
}
|
|
|
|
const std::vector<std::string>& getSubElements() const
|
|
{
|
|
parseSubName();
|
|
return mySubElements;
|
|
}
|
|
|
|
bool extensionGetSubObject(DocumentObject*& ret,
|
|
const char* subname,
|
|
PyObject** pyObj = nullptr,
|
|
Base::Matrix4D* mat = nullptr,
|
|
bool transform = false,
|
|
int depth = 0) const override;
|
|
|
|
bool extensionGetSubObjects(std::vector<std::string>& ret, int reason) const override;
|
|
|
|
bool extensionGetLinkedObject(DocumentObject*& ret,
|
|
bool recurse,
|
|
Base::Matrix4D* mat,
|
|
bool transform,
|
|
int depth) const override;
|
|
|
|
App::DocumentObjectExecReturn* extensionExecute() override;
|
|
short extensionMustExecute() override;
|
|
void extensionOnChanged(const Property* p) override;
|
|
void onExtendedUnsetupObject() override;
|
|
void onExtendedDocumentRestored() override;
|
|
|
|
int extensionSetElementVisible(const char*, bool) override;
|
|
int extensionIsElementVisible(const char*) override;
|
|
bool extensionHasChildElement() const override;
|
|
|
|
PyObject* getExtensionPyObject() override;
|
|
|
|
Property* extensionGetPropertyByName(const char* name) const override;
|
|
|
|
static int getArrayIndex(const char* subname, const char** psubname = nullptr);
|
|
int getElementIndex(const char* subname, const char** psubname = nullptr) const;
|
|
void elementNameFromIndex(int idx, std::ostream& ss) const;
|
|
|
|
DocumentObject* getContainer();
|
|
const DocumentObject* getContainer() const;
|
|
|
|
void setLink(int index,
|
|
DocumentObject* obj,
|
|
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,
|
|
bool noElement = false) const;
|
|
|
|
using LinkPropMap = std::map<const Property*, std::pair<LinkBaseExtension*, int>>;
|
|
|
|
bool hasPlacement() const
|
|
{
|
|
return getLinkPlacementProperty() || getPlacementProperty();
|
|
}
|
|
|
|
void cacheChildLabel(int enable = -1) const;
|
|
|
|
static bool
|
|
setupCopyOnChange(App::DocumentObject* obj,
|
|
App::DocumentObject* linked,
|
|
std::vector<fastsignals::scoped_connection>* copyOnChangeConns,
|
|
bool checkExisting);
|
|
|
|
static bool isCopyOnChangeProperty(App::DocumentObject* obj, const Property& prop);
|
|
|
|
void syncCopyOnChange();
|
|
|
|
/** 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,
|
|
};
|
|
|
|
/** Include or exclude object from list of objects to copy on change
|
|
* @param obj: input object
|
|
* @param options: control options. @sa OnChangeCopyOptions.
|
|
*/
|
|
void setOnChangeCopyObject(App::DocumentObject* obj, OnChangeCopyOptions options);
|
|
|
|
std::vector<App::DocumentObject*>
|
|
getOnChangeCopyObjects(std::vector<App::DocumentObject*>* excludes = nullptr,
|
|
App::DocumentObject* src = nullptr);
|
|
|
|
bool isLinkedToConfigurableObject() const;
|
|
|
|
void monitorOnChangeCopyObjects(const std::vector<App::DocumentObject*>& objs);
|
|
|
|
/// Check if the linked object is a copy on change
|
|
bool isLinkMutated() const;
|
|
|
|
protected:
|
|
void
|
|
_handleChangedPropertyName(Base::XMLReader& reader, const char* TypeName, const char* PropName);
|
|
void parseSubName() const;
|
|
void update(App::DocumentObject* parent, const Property* prop);
|
|
void checkCopyOnChange(App::DocumentObject* parent, const App::Property& prop);
|
|
void setupCopyOnChange(App::DocumentObject* parent, bool checkSource = false);
|
|
App::DocumentObject* makeCopyOnChange();
|
|
void syncElementList();
|
|
void detachElement(App::DocumentObject* obj);
|
|
void detachElements();
|
|
void checkGeoElementMap(const App::DocumentObject* obj,
|
|
const App::DocumentObject* linked,
|
|
PyObject** pyObj,
|
|
const char* postfix) const;
|
|
void updateGroup();
|
|
void slotChangedPlainGroup(const App::DocumentObject&, const App::Property&);
|
|
|
|
protected:
|
|
std::vector<Property*> props;
|
|
std::unordered_set<const App::DocumentObject*> myHiddenElements;
|
|
mutable std::vector<std::string> mySubElements;
|
|
mutable std::string mySubName;
|
|
|
|
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
|
|
mutable bool enableLabelCache {false};
|
|
bool hasOldSubElement {false};
|
|
|
|
std::vector<fastsignals::scoped_connection> copyOnChangeConns;
|
|
std::vector<fastsignals::scoped_connection> copyOnChangeSrcConns;
|
|
bool hasCopyOnChange {true};
|
|
|
|
mutable bool checkingProperty = false;
|
|
bool pauseCopyOnChange = false;
|
|
|
|
fastsignals::scoped_connection connCopyOnChangeSource;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
using LinkBaseExtensionPython = ExtensionPythonT<LinkBaseExtension>;
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
class AppExport LinkExtension: public LinkBaseExtension
|
|
{
|
|
EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(App::LinkExtension);
|
|
using inherited = LinkBaseExtension;
|
|
|
|
public:
|
|
LinkExtension();
|
|
~LinkExtension() override = default;
|
|
|
|
/** \name Helpers for defining extended parameter
|
|
*
|
|
* extended parameter 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
|
|
*
|
|
* 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)
|
|
#define LINK_EPTYPE(_param) BOOST_PP_TUPLE_ELEM(7, _param)
|
|
#define LINK_EGROUP(_param) BOOST_PP_TUPLE_ELEM(8, _param)
|
|
|
|
#define _LINK_PROP_ADD(_add_property, _param) \
|
|
_add_property(BOOST_PP_STRINGIZE(LINK_ENAME(_param)), \
|
|
LINK_ENAME(_param), \
|
|
(LINK_PDEF(_param)), \
|
|
LINK_EGROUP(_param), \
|
|
LINK_EPTYPE(_param), \
|
|
LINK_PDOC(_param)); \
|
|
setProperty(LINK_PINDEX(_param), &LINK_ENAME(_param));
|
|
|
|
#define LINK_PROP_ADD(_1, _2, _param) _LINK_PROP_ADD(_ADD_PROPERTY_TYPE, _param);
|
|
|
|
#define LINK_PROP_ADD_EXTENSION(_1, _2, _param) \
|
|
_LINK_PROP_ADD(_EXTENSION_ADD_PROPERTY_TYPE, _param);
|
|
|
|
#define LINK_PROPS_ADD(_seq) BOOST_PP_SEQ_FOR_EACH(LINK_PROP_ADD, _, _seq)
|
|
|
|
#define LINK_PROPS_ADD_EXTENSION(_seq) BOOST_PP_SEQ_FOR_EACH(LINK_PROP_ADD_EXTENSION, _, _seq)
|
|
|
|
#define _LINK_PROP_SET(_1, _2, _param) setProperty(LINK_PINDEX(_param), &LINK_ENAME(_param));
|
|
|
|
#define LINK_PROPS_SET(_seq) BOOST_PP_SEQ_FOR_EACH(_LINK_PROP_SET, _, _seq)
|
|
|
|
/// Helper for defining default extended parameter
|
|
#define _LINK_PARAM_EXT(_name, _type, _ptype, _def, _doc, ...) \
|
|
((_name, _type, _ptype, _def, _doc, _name, _ptype, App::Prop_None, " Link"))
|
|
|
|
/** Define default extended parameter
|
|
* It simply reuses Name as Property_Name, Property_Type as
|
|
* Derived_Property_Type, and App::Prop_None as App::PropertyType
|
|
*/
|
|
#define LINK_PARAM_EXT(_param) BOOST_PP_EXPAND(_LINK_PARAM_EXT LINK_PARAM_##_param())
|
|
|
|
/// Helper for extended parameter with app property type
|
|
#define _LINK_PARAM_EXT_ATYPE(_name, _type, _ptype, _def, _doc, _atype) \
|
|
((_name, _type, _ptype, _def, _doc, _name, _ptype, _atype, " Link"))
|
|
|
|
/// Define extended parameter with app property type
|
|
#define LINK_PARAM_EXT_ATYPE(_param, _atype) \
|
|
BOOST_PP_EXPAND(_LINK_PARAM_EXT_ATYPE LINK_PARAM_##_param(_atype))
|
|
|
|
/// Helper for extended parameter with derived property type
|
|
#define _LINK_PARAM_EXT_TYPE(_name, _type, _ptype, _def, _doc, _dtype) \
|
|
((_name, _type, _ptype, _def, _doc, _name, _dtype, App::Prop_None, " Link"))
|
|
|
|
/// Define extended parameter with derived property type
|
|
#define LINK_PARAM_EXT_TYPE(_param, _dtype) \
|
|
BOOST_PP_EXPAND(_LINK_PARAM_EXT_TYPE LINK_PARAM_##_param(_dtype))
|
|
|
|
/// Helper for extended parameter with a different property name
|
|
#define _LINK_PARAM_EXT_NAME(_name, _type, _ptype, _def, _doc, _pname) \
|
|
((_name, _type, _ptype, _def, _doc, _pname, _ptype, App::Prop_None, " Link"))
|
|
|
|
/// Define extended parameter with a different property name
|
|
#define LINK_PARAM_EXT_NAME(_param, _pname) \
|
|
BOOST_PP_EXPAND(_LINK_PARAM_EXT_NAME LINK_PARAM_##_param(_pname))
|
|
//@}
|
|
|
|
#define LINK_PARAMS_EXT \
|
|
LINK_PARAM_EXT(SCALE) \
|
|
LINK_PARAM_EXT_ATYPE(SCALE_VECTOR, App::Prop_Hidden) \
|
|
LINK_PARAM_EXT(SCALES) \
|
|
LINK_PARAM_EXT(VISIBILITIES) \
|
|
LINK_PARAM_EXT(PLACEMENTS) \
|
|
LINK_PARAM_EXT(ELEMENTS)
|
|
|
|
#define LINK_PROP_DEFINE(_1, _2, _param) LINK_ETYPE(_param) LINK_ENAME(_param);
|
|
#define LINK_PROPS_DEFINE(_seq) BOOST_PP_SEQ_FOR_EACH(LINK_PROP_DEFINE, _, _seq)
|
|
|
|
// defines the actual properties
|
|
LINK_PROPS_DEFINE(LINK_PARAMS_EXT)
|
|
|
|
void onExtendedDocumentRestored() override
|
|
{
|
|
LINK_PROPS_SET(LINK_PARAMS_EXT);
|
|
inherited::onExtendedDocumentRestored();
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
using LinkExtensionPython = ExtensionPythonT<LinkExtension>;
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
class AppExport Link: public App::DocumentObject, public App::LinkExtension
|
|
{
|
|
PROPERTY_HEADER_WITH_EXTENSIONS(App::Link);
|
|
using inherited = App::DocumentObject;
|
|
|
|
public:
|
|
#define LINK_PARAMS_LINK \
|
|
LINK_PARAM_EXT_TYPE(OBJECT, App::PropertyXLink) \
|
|
LINK_PARAM_EXT(CLAIM_CHILD) \
|
|
LINK_PARAM_EXT(TRANSFORM) \
|
|
LINK_PARAM_EXT(LINK_PLACEMENT) \
|
|
LINK_PARAM_EXT(PLACEMENT) \
|
|
LINK_PARAM_EXT(SHOW_ELEMENT) \
|
|
LINK_PARAM_EXT_TYPE(COUNT, App::PropertyIntegerConstraint) \
|
|
LINK_PARAM_EXT(LINK_EXECUTE) \
|
|
LINK_PARAM_EXT_ATYPE(COLORED_ELEMENTS, App::Prop_Hidden) \
|
|
LINK_PARAM_EXT(COPY_ON_CHANGE) \
|
|
LINK_PARAM_EXT_TYPE(COPY_ON_CHANGE_SOURCE, App::PropertyXLink) \
|
|
LINK_PARAM_EXT(COPY_ON_CHANGE_GROUP) \
|
|
LINK_PARAM_EXT(COPY_ON_CHANGE_TOUCHED)
|
|
|
|
LINK_PROPS_DEFINE(LINK_PARAMS_LINK)
|
|
|
|
Link();
|
|
|
|
const char* getViewProviderName() const override
|
|
{
|
|
return "Gui::ViewProviderLink";
|
|
}
|
|
|
|
void onDocumentRestored() override
|
|
{
|
|
LINK_PROPS_SET(LINK_PARAMS_LINK);
|
|
inherited::onDocumentRestored();
|
|
}
|
|
|
|
void handleChangedPropertyName(Base::XMLReader& reader,
|
|
const char* TypeName,
|
|
const char* PropName) override
|
|
{
|
|
_handleChangedPropertyName(reader, TypeName, PropName);
|
|
}
|
|
|
|
bool canLinkProperties() const override;
|
|
|
|
Base::Placement getPlacementOf(const std::string& sub, DocumentObject* targetObj = nullptr) override;
|
|
|
|
bool isLink() const override;
|
|
|
|
bool isLinkGroup() const override;
|
|
};
|
|
|
|
using LinkPython = App::FeaturePythonT<Link>;
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
class AppExport LinkElement: public App::DocumentObject, public App::LinkBaseExtension
|
|
{
|
|
PROPERTY_HEADER_WITH_EXTENSIONS(App::LinkElement);
|
|
using inherited = App::DocumentObject;
|
|
|
|
public:
|
|
#define LINK_PARAMS_ELEMENT \
|
|
LINK_PARAM_EXT(SCALE) \
|
|
LINK_PARAM_EXT_ATYPE(SCALE_VECTOR, App::Prop_Hidden) \
|
|
LINK_PARAM_EXT_TYPE(OBJECT, App::PropertyXLink) \
|
|
LINK_PARAM_EXT(TRANSFORM) \
|
|
LINK_PARAM_EXT(LINK_PLACEMENT) \
|
|
LINK_PARAM_EXT(PLACEMENT) \
|
|
LINK_PARAM_EXT(COPY_ON_CHANGE) \
|
|
LINK_PARAM_EXT_TYPE(COPY_ON_CHANGE_SOURCE, App::PropertyXLink) \
|
|
LINK_PARAM_EXT(COPY_ON_CHANGE_GROUP) \
|
|
LINK_PARAM_EXT(COPY_ON_CHANGE_TOUCHED)
|
|
|
|
// defines the actual properties
|
|
LINK_PROPS_DEFINE(LINK_PARAMS_ELEMENT)
|
|
|
|
LinkElement();
|
|
const char* getViewProviderName() const override
|
|
{
|
|
return "Gui::ViewProviderLink";
|
|
}
|
|
|
|
void onDocumentRestored() override
|
|
{
|
|
LINK_PROPS_SET(LINK_PARAMS_ELEMENT);
|
|
inherited::onDocumentRestored();
|
|
}
|
|
|
|
bool canDelete() const;
|
|
|
|
void handleChangedPropertyName(Base::XMLReader& reader,
|
|
const char* TypeName,
|
|
const char* PropName) override
|
|
{
|
|
_handleChangedPropertyName(reader, TypeName, PropName);
|
|
}
|
|
|
|
bool isLink() const override;
|
|
|
|
App::Link* getLinkGroup() const;
|
|
|
|
Base::Placement getPlacementOf(const std::string& sub, DocumentObject* targetObj = nullptr) override;
|
|
};
|
|
|
|
using LinkElementPython = App::FeaturePythonT<LinkElement>;
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
class AppExport LinkGroup: public App::DocumentObject, public App::LinkBaseExtension
|
|
{
|
|
PROPERTY_HEADER_WITH_EXTENSIONS(App::LinkGroup);
|
|
using inherited = App::DocumentObject;
|
|
|
|
public:
|
|
#define LINK_PARAMS_GROUP \
|
|
LINK_PARAM_EXT(ELEMENTS) \
|
|
LINK_PARAM_EXT(PLACEMENT) \
|
|
LINK_PARAM_EXT(VISIBILITIES) \
|
|
LINK_PARAM_EXT(MODE) \
|
|
LINK_PARAM_EXT_ATYPE(COLORED_ELEMENTS, App::Prop_Hidden)
|
|
|
|
// defines the actual properties
|
|
LINK_PROPS_DEFINE(LINK_PARAMS_GROUP)
|
|
|
|
LinkGroup();
|
|
|
|
const char* getViewProviderName() const override
|
|
{
|
|
return "Gui::ViewProviderLink";
|
|
}
|
|
|
|
void onDocumentRestored() override
|
|
{
|
|
LINK_PROPS_SET(LINK_PARAMS_GROUP);
|
|
inherited::onDocumentRestored();
|
|
}
|
|
};
|
|
|
|
using LinkGroupPython = App::FeaturePythonT<LinkGroup>;
|
|
|
|
} // namespace App
|
|
|
|
ENABLE_BITMASK_OPERATORS(App::Link::OnChangeCopyOptions)
|
|
|
|
/*[[[cog
|
|
import LinkParams
|
|
LinkParams.declare()
|
|
]]]*/
|
|
|
|
namespace App
|
|
{
|
|
/** Convenient class to obtain App::Link related parameters
|
|
|
|
* The parameters are under group "User parameter:BaseApp/Preferences/Link"
|
|
*
|
|
* This class is auto generated by LinkParams.py. Modify that file
|
|
* instead of this one, if you want to add any parameter. You need
|
|
* to install Cog Python package for code generation:
|
|
* @code
|
|
* pip install cogapp
|
|
* @endcode
|
|
*
|
|
* Once modified, you can regenerate the header and the source file,
|
|
* @code
|
|
* python3 -m cogapp -r Link.h Link.cpp
|
|
* @endcode
|
|
*
|
|
* You can add a new parameter by adding lines in LinkParams.py. Available
|
|
* parameter types are 'Int, UInt, String, Bool, Float'. For example, to add
|
|
* a new Int type parameter,
|
|
* @code
|
|
* ParamInt(parameter_name, default_value, documentation, on_change=False)
|
|
* @endcode
|
|
*
|
|
* If there is special handling on parameter change, pass in on_change=True.
|
|
* And you need to provide a function implementation in Link.cpp with
|
|
* the following signature.
|
|
* @code
|
|
* void LinkParams:on<parameter_name>Changed()
|
|
* @endcode
|
|
*/
|
|
class AppExport LinkParams
|
|
{
|
|
public:
|
|
static ParameterGrp::handle getHandle();
|
|
|
|
//@{
|
|
/// Accessor for parameter CopyOnChangeApplyToAll
|
|
///
|
|
/// Stores the last user choice of whether to apply CopyOnChange setup to all link
|
|
/// that links to the same configurable object
|
|
static const bool& getCopyOnChangeApplyToAll();
|
|
static const bool& defaultCopyOnChangeApplyToAll();
|
|
static void removeCopyOnChangeApplyToAll();
|
|
static void setCopyOnChangeApplyToAll(const bool& v);
|
|
static const char* docCopyOnChangeApplyToAll();
|
|
//@}
|
|
|
|
// Auto generated code. See class document of LinkParams.
|
|
};
|
|
} // namespace App
|
|
//[[[end]]]
|
|
|
|
|
|
#if defined(__clang__)
|
|
#pragma clang diagnostic pop
|
|
#endif
|
|
|
|
#endif // APP_LINK_H
|