App: add hiddenref() expression built-in function
Any object reference inside this function is treated as hidden to exclude it from dependency calculation. This function allows some form of cyclic depdenency. Merger note: renamed from "HREF" to "HIDDENREF" to avoid confusion with the standard "hypertext reference" use of HREF.
This commit is contained in:
@@ -33,18 +33,19 @@
|
||||
|
||||
/// Here the FreeCAD includes sorted by Base,App,Gui......
|
||||
#include <Base/GeometryPyCXX.h>
|
||||
#include <App/ComplexGeoData.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/QuantityPy.h>
|
||||
#include <Base/Console.h>
|
||||
#include <App/DocumentObjectPy.h>
|
||||
#include "ComplexGeoData.h"
|
||||
#include "Property.h"
|
||||
#include "Application.h"
|
||||
#include "Document.h"
|
||||
#include "DocumentObject.h"
|
||||
#include "ObjectIdentifier.h"
|
||||
#include "ExpressionParser.h"
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/QuantityPy.h>
|
||||
#include <App/Link.h>
|
||||
#include <Base/Console.h>
|
||||
#include "Link.h"
|
||||
|
||||
FC_LOG_LEVEL_INIT("Expression",true,true)
|
||||
|
||||
@@ -1086,32 +1087,58 @@ enum PseudoPropertyType {
|
||||
PseudoCadquery,
|
||||
};
|
||||
|
||||
std::pair<DocumentObject*,std::string> ObjectIdentifier::getDep(std::vector<std::string> *labels) const {
|
||||
void ObjectIdentifier::getDepLabels(std::vector<std::string> &labels) const {
|
||||
getDepLabels(ResolveResults(*this),labels);
|
||||
}
|
||||
|
||||
void ObjectIdentifier::getDepLabels(
|
||||
const ResolveResults &result, std::vector<std::string> &labels) const
|
||||
{
|
||||
if(documentObjectName.getString().size()) {
|
||||
if(documentObjectName.isRealString())
|
||||
labels.push_back(documentObjectName.getString());
|
||||
} else if(result.propertyIndex == 1)
|
||||
labels.push_back(components[0].name.getString());
|
||||
if(subObjectName.getString().size())
|
||||
PropertyLinkBase::getLabelReferences(labels,subObjectName.getString().c_str());
|
||||
}
|
||||
|
||||
ObjectIdentifier::Dependencies
|
||||
ObjectIdentifier::getDep(bool needProps, std::vector<std::string> *labels) const
|
||||
{
|
||||
Dependencies deps;
|
||||
getDep(deps,needProps,labels);
|
||||
return deps;
|
||||
}
|
||||
|
||||
void ObjectIdentifier::getDep(
|
||||
Dependencies &deps, bool needProps, std::vector<std::string> *labels) const
|
||||
{
|
||||
ResolveResults result(*this);
|
||||
if(labels) {
|
||||
if(documentObjectName.getString().size()) {
|
||||
if(documentObjectName.isRealString())
|
||||
labels->push_back(documentObjectName.getString());
|
||||
} else if(result.propertyIndex == 1)
|
||||
labels->push_back(components[0].name.getString());
|
||||
if(subObjectName.getString().size())
|
||||
PropertyLinkBase::getLabelReferences(*labels,subObjectName.getString().c_str());
|
||||
if(labels)
|
||||
getDepLabels(result,*labels);
|
||||
|
||||
if(!result.resolvedDocumentObject)
|
||||
return;
|
||||
|
||||
if(!needProps) {
|
||||
deps[result.resolvedDocumentObject];
|
||||
return;
|
||||
}
|
||||
if(subObjectName.getString().empty()) {
|
||||
if(result.propertyType==PseudoNone) {
|
||||
CellAddress addr;
|
||||
if(addr.parseAbsoluteAddress(result.propertyName.c_str()))
|
||||
return std::make_pair(result.resolvedDocumentObject,addr.toString(true));
|
||||
return std::make_pair(result.resolvedDocumentObject,result.propertyName);
|
||||
}else if(result.propertyType == PseudoSelf
|
||||
&& result.resolvedDocumentObject
|
||||
&& result.propertyIndex+1 < (int)components.size())
|
||||
{
|
||||
return std::make_pair(result.resolvedDocumentObject,
|
||||
components[result.propertyIndex+1].getName());
|
||||
}
|
||||
|
||||
if(!result.resolvedProperty) {
|
||||
if(result.propertyName.size())
|
||||
deps[result.resolvedDocumentObject].insert(result.propertyName);
|
||||
return;
|
||||
}
|
||||
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
access(result,0,&deps);
|
||||
}catch(Py::Exception &) {
|
||||
Base::PyException e;
|
||||
}catch(...){
|
||||
}
|
||||
return std::make_pair(result.resolvedDocumentObject,std::string());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1241,7 +1268,7 @@ Property *ObjectIdentifier::resolveProperty(const App::DocumentObject *obj,
|
||||
if(!obj)
|
||||
return 0;
|
||||
|
||||
static std::map<std::string,int> _props = {
|
||||
static std::unordered_map<const char*,int,CStringHasher,CStringHasher> _props = {
|
||||
{"_shape",PseudoShape},
|
||||
{"_pla",PseudoPlacement},
|
||||
{"_matrix",PseudoMatrix},
|
||||
@@ -1270,23 +1297,8 @@ Property *ObjectIdentifier::resolveProperty(const App::DocumentObject *obj,
|
||||
}
|
||||
return &const_cast<App::DocumentObject*>(obj)->Label; //fake the property
|
||||
}
|
||||
|
||||
auto prop = obj->getPropertyByName(propertyName);
|
||||
if(prop && !prop->testStatus(Property::Hidden) && !(prop->getType() & PropertyType::Prop_Hidden))
|
||||
return prop;
|
||||
|
||||
auto linked = obj->getLinkedObject(true);
|
||||
if(!linked || linked==obj) {
|
||||
auto ext = obj->getExtensionByType<App::LinkBaseExtension>(true);
|
||||
if(!ext)
|
||||
return prop;
|
||||
linked = ext->getTrueLinkedObject(true);
|
||||
if(!linked || linked==obj)
|
||||
return prop;
|
||||
}
|
||||
|
||||
auto linkedProp = linked->getPropertyByName(propertyName);
|
||||
return linkedProp?linkedProp:prop;
|
||||
|
||||
return obj->getPropertyByName(propertyName);
|
||||
}
|
||||
|
||||
|
||||
@@ -1503,7 +1515,8 @@ void ObjectIdentifier::String::checkImport(const App::DocumentObject *owner,
|
||||
}
|
||||
}
|
||||
|
||||
Py::Object ObjectIdentifier::access(const ResolveResults &result, Py::Object *value) const
|
||||
Py::Object ObjectIdentifier::access(const ResolveResults &result,
|
||||
Py::Object *value, Dependencies *deps) const
|
||||
{
|
||||
if(!result.resolvedDocumentObject || !result.resolvedProperty ||
|
||||
(subObjectName.getString().size() && !result.resolvedSubObject))
|
||||
@@ -1647,13 +1660,65 @@ Py::Object ObjectIdentifier::access(const ResolveResults &result, Py::Object *va
|
||||
break;
|
||||
}}}
|
||||
}
|
||||
|
||||
auto setPropDep = [deps](DocumentObject *obj, Property *prop, const char *propName) {
|
||||
if(!deps || !obj)
|
||||
return;
|
||||
if(prop && prop->getContainer()!=obj) {
|
||||
auto linkTouched = Base::freecad_dynamic_cast<PropertyBool>(
|
||||
obj->getPropertyByName("_LinkTouched"));
|
||||
if(linkTouched)
|
||||
propName = linkTouched->getName();
|
||||
else {
|
||||
auto propOwner = Base::freecad_dynamic_cast<DocumentObject>(prop->getContainer());
|
||||
if(propOwner)
|
||||
obj = propOwner;
|
||||
else
|
||||
propName = 0;
|
||||
}
|
||||
}
|
||||
auto &propset = (*deps)[obj];
|
||||
// inserting a null name in the propset indicates the dependency is
|
||||
// on all properties of the corresponding object.
|
||||
if(propset.size()!=1 || propset.begin()->size()) {
|
||||
if(!propName)
|
||||
propset.clear();
|
||||
propset.insert(propName);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
App::DocumentObject *lastObj = result.resolvedDocumentObject;
|
||||
if(result.resolvedSubObject) {
|
||||
setPropDep(lastObj,0,0);
|
||||
lastObj = result.resolvedSubObject;
|
||||
}
|
||||
if(ptype == PseudoNone)
|
||||
setPropDep(lastObj, result.resolvedProperty, result.resolvedProperty->getName());
|
||||
else
|
||||
setPropDep(lastObj,0,0);
|
||||
lastObj = 0;
|
||||
|
||||
if(components.empty())
|
||||
return pyobj;
|
||||
|
||||
size_t count = components.size();
|
||||
if(value) --count;
|
||||
assert(idx<=count);
|
||||
for(;idx<count;++idx)
|
||||
|
||||
for(;idx<count;++idx) {
|
||||
if(PyObject_TypeCheck(*pyobj, &DocumentObjectPy::Type))
|
||||
lastObj = static_cast<DocumentObjectPy*>(*pyobj)->getDocumentObjectPtr();
|
||||
else if(lastObj) {
|
||||
const char *attr = components[idx].getName().c_str();
|
||||
auto prop = lastObj->getPropertyByName(attr);
|
||||
if(!prop && pyobj.hasAttr(attr))
|
||||
attr = 0;
|
||||
setPropDep(lastObj,prop,attr);
|
||||
lastObj = 0;
|
||||
}
|
||||
pyobj = components[idx].get(pyobj);
|
||||
}
|
||||
if(value) {
|
||||
components[idx].set(pyobj,*value);
|
||||
return Py::Object();
|
||||
|
||||
Reference in New Issue
Block a user