diff --git a/src/App/DocumentObject.cpp b/src/App/DocumentObject.cpp index 3dbb72a8fc..0ad90ebb77 100644 --- a/src/App/DocumentObject.cpp +++ b/src/App/DocumentObject.cpp @@ -76,7 +76,7 @@ App::DocumentObjectExecReturn *DocumentObject::recompute(void) { //check if the links are valid before making the recompute if(!GeoFeatureGroupExtension::areLinksValid(this)) - return new App::DocumentObjectExecReturn("Links between different GeoFeatureGroups are not valid", this); + return new App::DocumentObjectExecReturn("Links go out of the allowed scope", this); // set/unset the execution bit ObjectStatusLocker exe(App::Recompute, this); diff --git a/src/App/GeoFeatureGroupExtension.cpp b/src/App/GeoFeatureGroupExtension.cpp index e57aecf21e..e8e90df186 100644 --- a/src/App/GeoFeatureGroupExtension.cpp +++ b/src/App/GeoFeatureGroupExtension.cpp @@ -210,23 +210,33 @@ void GeoFeatureGroupExtension::extensionOnChanged(const Property* p) { } -std::vector< DocumentObject* > GeoFeatureGroupExtension::getObjectsFromLinks(DocumentObject* obj) { +std::vector< DocumentObject* > GeoFeatureGroupExtension::getScopedObjectsFromLinks(DocumentObject* obj, LinkScope scope) { //we get all linked objects. We can't use outList() as this includes the links from expressions std::vector< App::DocumentObject* > result; std::vector list; obj->getPropertyList(list); for(App::Property* prop : list) { - if(prop->getTypeId().isDerivedFrom(App::PropertyLink::getClassTypeId())) + if(prop->getTypeId().isDerivedFrom(App::PropertyLink::getClassTypeId()) && + static_cast(prop)->getScope() == scope) { + result.push_back(static_cast(prop)->getValue()); - else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkList::getClassTypeId())) { + } + else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkList::getClassTypeId()) && + static_cast(prop)->getScope() == scope) { + auto vec = static_cast(prop)->getValues(); result.insert(result.end(), vec.begin(), vec.end()); } - else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkSub::getClassTypeId())) + else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkSub::getClassTypeId()) && + static_cast(prop)->getScope() == scope) { + result.push_back(static_cast(prop)->getValue()); - else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkSubList::getClassTypeId())) { - auto vec = static_cast(prop)->getValues(); + } + else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkSubList::getClassTypeId()) && + static_cast(prop)->getScope() == scope) { + + auto vec = static_cast(prop)->getValues(); result.insert(result.end(), vec.begin(), vec.end()); } } @@ -249,8 +259,9 @@ void GeoFeatureGroupExtension::getCSOutList(App::DocumentObject* obj, std::vecto if(obj->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId())) return; - //we get all linked objects. We can't use outList() as this includes the links from expressions - auto result = getObjectsFromLinks(obj); + //we get all relevant linked objects. We can't use outList() as this includes the links from expressions, + //also we only want links with scope Local + auto result = getScopedObjectsFromLinks(obj); //we remove all links to origin features and origins, they belong to a CS too and can't be moved result.erase(std::remove_if(result.begin(), result.end(), [](App::DocumentObject* obj)->bool { @@ -295,9 +306,9 @@ void GeoFeatureGroupExtension::getCSInList(DocumentObject* obj, std::vector< Doc if(std::find(vec.begin(), vec.end(), parent) != vec.end()) throw Base::Exception("Graph is not DAG"); - //check if the link is real or if it is a expression one (could also be both, so it is not + //check if the link is real Local scope one or if it is a expression one (could also be both, so it is not //enough to check the expressions) - auto res = getObjectsFromLinks(parent); + auto res = getScopedObjectsFromLinks(parent); if(std::find(res.begin(), res.end(), obj) != res.end()) result.push_back(parent); } @@ -338,16 +349,25 @@ void GeoFeatureGroupExtension::getCSRelevantLinks(DocumentObject* obj, std::vect } bool GeoFeatureGroupExtension::areLinksValid(DocumentObject* obj) { - - //we get all linked objects. We can't use outList() as this includes the links from expressions - auto result = getObjectsFromLinks(obj); - - //no cross CS links. + + //no cross CS link for local links. + auto result = getScopedObjectsFromLinks(obj, LinkScope::Local); auto group = obj->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId()) ? obj : getGroupOfObject(obj); for(auto link : result) { if(getGroupOfObject(link) != group) return false; } + + //for links with scope SubGroup we need to check if all features are part of subgroups + if(group) { + result = getScopedObjectsFromLinks(obj, LinkScope::SubGroup); + auto groupExt = group->getExtensionByType(); + for(auto link : result) { + if(!groupExt->hasObject(link, true)) + return false; + } + } + return true; } diff --git a/src/App/GeoFeatureGroupExtension.h b/src/App/GeoFeatureGroupExtension.h index ae3246f4c9..6042ee0e2c 100644 --- a/src/App/GeoFeatureGroupExtension.h +++ b/src/App/GeoFeatureGroupExtension.h @@ -116,7 +116,7 @@ public: static bool areLinksValid(App::DocumentObject* obj); private: Base::Placement recursiveGroupPlacement(GeoFeatureGroupExtension* group); - static std::vector getObjectsFromLinks(App::DocumentObject*); + static std::vector getScopedObjectsFromLinks(App::DocumentObject*, LinkScope scope = LinkScope::Local); }; typedef ExtensionPythonT> GeoFeatureGroupExtensionPython; diff --git a/src/App/PropertyLinks.h b/src/App/PropertyLinks.h index a2b65f3b5b..27a932a4be 100644 --- a/src/App/PropertyLinks.h +++ b/src/App/PropertyLinks.h @@ -39,9 +39,19 @@ namespace App { class DocumentObject; +enum class LinkScope { + Local, + SubGroup, + Global +}; -/** the general Link Poperty - * Main Purpose of this property is to Link Objects and Feautures in a document. +/** The general Link Property + * Main Purpose of this property is to Link Objects and Feautures in a document. Like all links this + * property is scope aware, meaning it does define which objects are allowed to be linked depending + * of the GeoFeatureGroup where it is in. + * + * @note Links that invalid in respect to the scope this property is set to are not rejected. They + * are only detected to be invalid and prevent the feature from recomputing. */ class AppExport PropertyLink : public Property { @@ -93,9 +103,23 @@ public: } virtual const char* getEditorName(void) const { return "Gui::PropertyEditor::PropertyLinkItem"; } + + /** + * @brief Set the links scope + * Allows to define what kind of links are allowed. Only in the Local GeoFeatureGroup, in this an + * all SubGroups or to all object within the Glocal scope. + */ + void setScope(LinkScope scope) {_pcScope = scope;}; + /** + * @brief Get the links scope + * Retreive what kind of links are allowed. Only in the Local GeoFeatureGroup, in this an + * all SubGroups or to all object within the Glocal scope. + */ + LinkScope getScope() {return _pcScope;}; protected: App::DocumentObject *_pcLink; + LinkScope _pcScope = LinkScope::Local; }; class AppExport PropertyLinkList : public PropertyLists @@ -148,8 +172,22 @@ public: virtual unsigned int getMemSize(void) const; + /** + * @brief Set the links scope + * Allows to define what kind of links are allowed. Only in the Local GeoFeatureGroup, in this an + * all SubGroups or to all object within the Glocal scope. + */ + void setScope(LinkScope scope) {_pcScope = scope;}; + /** + * @brief Get the links scope + * Retreive what kind of links are allowed. Only in the Local GeoFeatureGroup, in this an + * all SubGroups or to all object within the Glocal scope. + */ + LinkScope getScope() {return _pcScope;}; + private: std::vector _lValueList; + LinkScope _pcScope = LinkScope::Local; }; /** the Link Poperty with sub elements @@ -212,11 +250,24 @@ public: virtual unsigned int getMemSize (void) const{ return sizeof(App::DocumentObject *); } + + /** + * @brief Set the links scope + * Allows to define what kind of links are allowed. Only in the Local GeoFeatureGroup, in this an + * all SubGroups or to all object within the Glocal scope. + */ + void setScope(LinkScope scope) {_pcScope = scope;}; + /** + * @brief Get the links scope + * Retreive what kind of links are allowed. Only in the Local GeoFeatureGroup, in this an + * all SubGroups or to all object within the Glocal scope. + */ + LinkScope getScope() {return _pcScope;}; protected: - App::DocumentObject *_pcLinkSub; + App::DocumentObject* _pcLinkSub; std::vector _cSubList; - + LinkScope _pcScope = LinkScope::Local; }; class AppExport PropertyLinkSubList: public PropertyLists @@ -285,10 +336,24 @@ public: virtual unsigned int getMemSize (void) const; + /** + * @brief Set the links scope + * Allows to define what kind of links are allowed. Only in the Local GeoFeatureGroup, in this an + * all SubGroups or to all object within the Glocal scope. + */ + void setScope(LinkScope scope) {_pcScope = scope;}; + /** + * @brief Get the links scope + * Retreive what kind of links are allowed. Only in the Local GeoFeatureGroup, in this an + * all SubGroups or to all object within the Glocal scope. + */ + LinkScope getScope() {return _pcScope;}; + private: //FIXME: Do not make two independent lists because this will lead to some inconsistencies! std::vector _lValueList; std::vector _lSubList; + LinkScope _pcScope = LinkScope::Local; }; } // namespace App