DependencyGraph: show invalid links in red

This commit is contained in:
Stefan Tröger
2017-07-21 08:26:36 +02:00
committed by wmayer
parent d0954e6e42
commit 79bb7b7f50
3 changed files with 124 additions and 39 deletions

View File

@@ -258,6 +258,7 @@ void Document::exportGraphviz(std::ostream& out) const
buildAdjacencyList();
addEdges();
markCycles();
markOutOfScopeLinks();
}
/**
@@ -663,6 +664,7 @@ void Document::exportGraphviz(std::ostream& out) const
edgeAttrMap[edge]["ltail"] = getClusterName(docObj);
if (GraphList[*It2])
edgeAttrMap[edge]["lhead"] = getClusterName(*It2);
}
}
@@ -767,6 +769,24 @@ void Document::exportGraphviz(std::ostream& out) const
for (auto ei = out_edges.begin(), ei_end = out_edges.end(); ei != ei_end; ++ei)
edgeAttrMap[ei->second]["color"] = "red";
}
void markOutOfScopeLinks() {
const boost::property_map<Graph, boost::edge_attribute_t>::type& edgeAttrMap = boost::get(boost::edge_attribute, DepList);
for( auto obj : objects) {
std::vector<App::DocumentObject*> invalids;
GeoFeatureGroupExtension::getInvalidLinkObjects(obj, invalids);
//isLinkValid returns true for non-link properties
for(auto linkedObj : invalids) {
auto res = edge(GlobalVertexList[getId(obj)], GlobalVertexList[getId(linkedObj)], DepList);
if(res.second)
edgeAttrMap[res.first]["color"] = "red";
}
}
}
const struct DocumentP* d;
Graph DepList;

View File

@@ -210,47 +210,63 @@ void GeoFeatureGroupExtension::extensionOnChanged(const Property* p) {
}
std::vector< DocumentObject* > GeoFeatureGroupExtension::getScopedObjectsFromLinks(DocumentObject* obj, LinkScope scope) {
std::vector< DocumentObject* > GeoFeatureGroupExtension::getScopedObjectsFromLinks(const 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<App::Property*> list;
obj->getPropertyList(list);
for(App::Property* prop : list) {
if(prop->getTypeId().isDerivedFrom(App::PropertyLink::getClassTypeId()) &&
static_cast<App::PropertyLink*>(prop)->getScope() == scope) {
result.push_back(static_cast<App::PropertyLink*>(prop)->getValue());
}
else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkList::getClassTypeId()) &&
static_cast<App::PropertyLinkList*>(prop)->getScope() == scope) {
auto vec = static_cast<App::PropertyLinkList*>(prop)->getValues();
result.insert(result.end(), vec.begin(), vec.end());
}
else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkSub::getClassTypeId()) &&
static_cast<App::PropertyLinkSub*>(prop)->getScope() == scope) {
result.push_back(static_cast<App::PropertyLinkSub*>(prop)->getValue());
}
else if(prop->getTypeId().isDerivedFrom(App::PropertyLinkSubList::getClassTypeId()) &&
static_cast<App::PropertyLinkSubList*>(prop)->getScope() == scope) {
auto vec = static_cast<App::PropertyLinkSubList*>(prop)->getValues();
result.insert(result.end(), vec.begin(), vec.end());
}
auto vec = getScopedObjectsFromLink(prop, scope);
result.insert(result.end(), vec.begin(), vec.end());
}
//clear all null objects and douplicates
result.erase(std::remove(result.begin(), result.end(), nullptr), result.end());
std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()), result.end());
return result;
}
std::vector< DocumentObject* > GeoFeatureGroupExtension::getScopedObjectsFromLink(App::Property* prop, LinkScope scope) {
void GeoFeatureGroupExtension::getCSOutList(App::DocumentObject* obj, std::vector< DocumentObject* >& vec) {
std::vector< App::DocumentObject* > result;
if(prop->getTypeId().isDerivedFrom(App::PropertyLink::getClassTypeId()) &&
static_cast<App::PropertyLink*>(prop)->getScope() == scope) {
result.push_back(static_cast<App::PropertyLink*>(prop)->getValue());
}
if(prop->getTypeId().isDerivedFrom(App::PropertyLinkList::getClassTypeId()) &&
static_cast<App::PropertyLinkList*>(prop)->getScope() == scope) {
auto vec = static_cast<App::PropertyLinkList*>(prop)->getValues();
result.insert(result.end(), vec.begin(), vec.end());
}
if(prop->getTypeId().isDerivedFrom(App::PropertyLinkSub::getClassTypeId()) &&
static_cast<App::PropertyLinkSub*>(prop)->getScope() == scope) {
result.push_back(static_cast<App::PropertyLinkSub*>(prop)->getValue());
}
if(prop->getTypeId().isDerivedFrom(App::PropertyLinkSubList::getClassTypeId()) &&
static_cast<App::PropertyLinkSubList*>(prop)->getScope() == scope) {
auto vec = static_cast<App::PropertyLinkSubList*>(prop)->getValues();
result.insert(result.end(), vec.begin(), vec.end());
}
//it is important to remove all nullptrs
result.erase(std::remove(result.begin(), result.end(), nullptr), result.end());
return result;
}
void GeoFeatureGroupExtension::getCSOutList(const App::DocumentObject* obj, std::vector< DocumentObject* >& vec) {
if(!obj)
return;
@@ -287,7 +303,7 @@ void GeoFeatureGroupExtension::getCSOutList(App::DocumentObject* obj, std::vecto
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
}
void GeoFeatureGroupExtension::getCSInList(DocumentObject* obj, std::vector< DocumentObject* >& vec) {
void GeoFeatureGroupExtension::getCSInList(const DocumentObject* obj, std::vector< DocumentObject* >& vec) {
if(!obj)
return;
@@ -328,7 +344,7 @@ void GeoFeatureGroupExtension::getCSInList(DocumentObject* obj, std::vector< Doc
}
void GeoFeatureGroupExtension::getCSRelevantLinks(DocumentObject* obj, std::vector< DocumentObject* >& vec ) {
void GeoFeatureGroupExtension::getCSRelevantLinks(const DocumentObject* obj, std::vector< DocumentObject* >& vec ) {
//get all out links
getCSOutList(obj, vec);
@@ -348,14 +364,55 @@ void GeoFeatureGroupExtension::getCSRelevantLinks(DocumentObject* obj, std::vect
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
}
bool GeoFeatureGroupExtension::areLinksValid(DocumentObject* obj) {
bool GeoFeatureGroupExtension::areLinksValid(const DocumentObject* obj) {
//no cross CS link for local links.
std::vector<App::Property*> list;
obj->getPropertyList(list);
for(App::Property* prop : list) {
if(!isLinkValid(prop))
return false;
}
return true;
}
bool GeoFeatureGroupExtension::isLinkValid(App::Property* prop) {
//get the object that holds the property
if(!prop->getContainer()->isDerivedFrom(App::DocumentObject::getClassTypeId()))
return true; //this link comes not from a document object, scopes are meaningless
auto obj = static_cast<App::DocumentObject*>(prop->getContainer());
//no cross CS link for local links.
auto result = getScopedObjectsFromLink(prop, 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 = getScopedObjectsFromLink(prop, LinkScope::Child);
auto groupExt = group->getExtensionByType<App::GeoFeatureGroupExtension>();
for(auto link : result) {
if(!groupExt->hasObject(link, true))
return false;
}
}
return true;
}
void GeoFeatureGroupExtension::getInvalidLinkObjects(const DocumentObject* obj, std::vector< DocumentObject* >& vec) {
//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;
if(getGroupOfObject(link) != group)
vec.push_back(link);
}
//for links with scope SubGroup we need to check if all features are part of subgroups
@@ -363,14 +420,13 @@ bool GeoFeatureGroupExtension::areLinksValid(DocumentObject* obj) {
result = getScopedObjectsFromLinks(obj, LinkScope::Child);
auto groupExt = group->getExtensionByType<App::GeoFeatureGroupExtension>();
for(auto link : result) {
if(!groupExt->hasObject(link, true))
return false;
if(!groupExt->hasObject(link, true))
vec.push_back(link);
}
}
return true;
}
// Python feature ---------------------------------------------------------
namespace App {

View File

@@ -102,21 +102,30 @@ public:
/// Collects GeoFeatureGroup relevant objects that are linked from the given one. That means all linked objects
/// including their links (recursively) except GeoFeatureGroups, where the recursion stops. Expressions
/// links are ignored. An exception is thrown when there are dependency loops.
static void getCSOutList(App::DocumentObject* obj, std::vector<App::DocumentObject*>& vec);
static void getCSOutList(const App::DocumentObject* obj, std::vector<App::DocumentObject*>& vec);
/// Collects GeoFeatureGroup relevant objects that link to the given one. That means all objects
/// including their parents (recursively) except GeoFeatureGroups, where the recursion stops. Expression
/// links are ignored. An exception is thrown when there are dependency loops.
static void getCSInList(App::DocumentObject* obj, std::vector<App::DocumentObject*>& vec);
static void getCSInList(const App::DocumentObject* obj, std::vector<App::DocumentObject*>& vec);
/// Collects all links that are relevant for the coordinate system, meaning all recursive links to
/// obj and from obj excluding expressions and stopping the recursion at other geofeaturegroups.
/// The result is the combination of CSOutList and CSInList.
static void getCSRelevantLinks(App::DocumentObject* obj, std::vector<App::DocumentObject*>& vec);
static void getCSRelevantLinks(const App::DocumentObject* obj, std::vector<App::DocumentObject*>& vec);
/// Checks if the links of the given object comply with all GeoFeatureGroup requrirements, that means
/// if normal links are only withing the parent GeoFeatureGroup.
static bool areLinksValid(App::DocumentObject* obj);
static bool areLinksValid(const App::DocumentObject* obj);
/// Checks if the given link complies with all GeoFeatureGroup requrirements, that means
/// if normal links are only withing the parent GeoFeatureGroup.
static bool isLinkValid(App::Property* link);
//Returns all objects that are wrongly linked from this object, meaning which are out of scope of the
//links of obj
static void getInvalidLinkObjects(const App::DocumentObject* obj, std::vector<App::DocumentObject*>& vec);
private:
Base::Placement recursiveGroupPlacement(GeoFeatureGroupExtension* group);
static std::vector<App::DocumentObject*> getScopedObjectsFromLinks(App::DocumentObject*, LinkScope scope = LinkScope::Local);
static std::vector<App::DocumentObject*> getScopedObjectsFromLinks(const App::DocumentObject*, LinkScope scope = LinkScope::Local);
static std::vector<App::DocumentObject*> getScopedObjectsFromLink(App::Property*, LinkScope scope = LinkScope::Local);
};
typedef ExtensionPythonT<GroupExtensionPythonT<GeoFeatureGroupExtension>> GeoFeatureGroupExtensionPython;