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:
Zheng, Lei
2019-12-23 11:50:11 +08:00
committed by Chris Hennes
parent 7e272d00f8
commit fdae470c1b
11 changed files with 500 additions and 225 deletions

View File

@@ -4483,7 +4483,7 @@ void PropertyXLinkContainer::afterRestore() {
if(info.docLabel != obj->getDocument()->Label.getValue())
_DocMap[App::quote(info.docLabel)] = obj->getDocument()->Label.getValue();
}
if(_Deps.insert(obj).second)
if(_Deps.insert(std::make_pair(obj,info.xlink->getScope()==LinkScope::Hidden)).second)
_XLinks[obj->getFullName()] = std::move(info.xlink);
}
_XLinkRestores.reset();
@@ -4496,24 +4496,27 @@ void PropertyXLinkContainer::breakLink(App::DocumentObject *obj, bool clear) {
if(!owner || !owner->getNameInDocument())
return;
if(!clear || obj!=owner) {
if(!_Deps.erase(obj))
auto it = _Deps.find(obj);
if(it == _Deps.end())
return;
aboutToSetValue();
onBreakLink(obj);
if(obj->getDocument() == owner->getDocument())
obj->_removeBackLink(owner);
else
if (obj->getDocument() != owner->getDocument())
_XLinks.erase(obj->getFullName());
else if (!it->second)
obj->_removeBackLink(owner);
_Deps.erase(it);
hasSetValue();
return;
}
if(obj!=owner)
return;
for(auto obj : _Deps) {
for(auto &v : _Deps) {
auto obj = v.first;
if(!obj || !obj->getNameInDocument())
continue;
onBreakLink(obj);
if(obj->getDocument()==owner->getDocument())
if(!v.second && obj->getDocument()==owner->getDocument())
obj->_removeBackLink(owner);
}
_XLinks.clear();
@@ -4553,6 +4556,19 @@ void PropertyXLinkContainer::Save (Base::Writer &writer) const {
writer.Stream() << "\" docs=\"" << docSet.size();
}
std::ostringstream ss;
int hidden = 0;
int i=-1;
for(auto &v : _XLinks) {
++i;
if(v.second->getScope() == LinkScope::Hidden) {
ss << i << ' ';
++hidden;
}
}
if(hidden)
writer.Stream() << "\" hidden=\"" << ss.str();
writer.Stream() << "\">" << std::endl;
writer.incInd();
@@ -4575,6 +4591,15 @@ void PropertyXLinkContainer::Restore(Base::XMLReader &reader) {
auto count = reader.getAttributeAsUnsigned("count");
_XLinkRestores.reset(new std::vector<RestoreInfo>(count));
if(reader.hasAttribute("hidden")) {
std::istringstream iss(reader.getAttribute("hidden"));
int index;
while(iss >> index) {
if(index>=0 && index<static_cast<int>(count))
_XLinkRestores->at(index).hidden = true;
}
}
if(reader.hasAttribute("docs")) {
auto docCount = reader.getAttributeAsUnsigned("docs");
_DocMap.clear();
@@ -4593,6 +4618,8 @@ void PropertyXLinkContainer::Restore(Base::XMLReader &reader) {
for(auto &info : *_XLinkRestores) {
info.xlink.reset(createXLink());
if(info.hidden)
info.xlink->setScope(LinkScope::Hidden);
info.xlink->Restore(reader);
}
reader.readEndElement("XLinks");
@@ -4624,16 +4651,23 @@ bool PropertyXLinkContainer::isLinkedToDocument(const App::Document &doc) const
return false;
}
void PropertyXLinkContainer::updateDeps(std::set<DocumentObject*> &&newDeps) {
void PropertyXLinkContainer::updateDeps(std::map<DocumentObject*,bool> &&newDeps) {
auto owner = Base::freecad_dynamic_cast<App::DocumentObject>(getContainer());
if(!owner || !owner->getNameInDocument())
return;
newDeps.erase(owner);
for(auto obj : newDeps) {
for(auto &v : newDeps) {
auto obj = v.first;
if(obj && obj->getNameInDocument()) {
auto it = _Deps.find(obj);
if(it != _Deps.end()) {
if(v.second != it->second) {
if(v.second)
obj->_removeBackLink(owner);
else
obj->_addBackLink(owner);
}
_Deps.erase(it);
continue;
}
@@ -4643,21 +4677,21 @@ void PropertyXLinkContainer::updateDeps(std::set<DocumentObject*> &&newDeps) {
xlink.reset(createXLink());
xlink->setValue(obj);
}
xlink->setScope(v.second?LinkScope::Hidden:LinkScope::Global);
}
#ifndef USE_OLD_DAG
else
else if(!v.second)
obj->_addBackLink(owner);
#endif
onAddDep(obj);
}
}
for(auto obj : _Deps) {
for(auto &v : _Deps) {
auto obj = v.first;
if(!obj || !obj->getNameInDocument())
continue;
if(obj->getDocument()==owner->getDocument()) {
#ifndef USE_OLD_DAG
obj->_removeBackLink(owner);
#endif
if(!v.second)
obj->_removeBackLink(owner);
}else
_XLinks.erase(obj->getFullName());
onRemoveDep(obj);
@@ -4681,8 +4715,9 @@ void PropertyXLinkContainer::clearDeps() {
return;
#ifndef USE_OLD_DAG
if (!owner->testStatus(ObjectStatus::Destroy)) {
for(auto obj : _Deps) {
if(obj && obj->getNameInDocument() && obj->getDocument()==owner->getDocument())
for(auto &v : _Deps) {
auto obj = v.first;
if(!v.second && obj && obj->getNameInDocument() && obj->getDocument()==owner->getDocument())
obj->_removeBackLink(owner);
}
}
@@ -4692,8 +4727,11 @@ void PropertyXLinkContainer::clearDeps() {
_LinkRestored = false;
}
void PropertyXLinkContainer::getLinks(std::vector<App::DocumentObject *> &objs,
bool, std::vector<std::string> * /*subs*/, bool /*newStyle*/) const
void PropertyXLinkContainer::getLinks(std::vector<App::DocumentObject *> &objs,
bool all, std::vector<std::string> * /*subs*/, bool /*newStyle*/) const
{
objs.insert(objs.end(),_Deps.begin(),_Deps.end());
for(auto &v : _Deps) {
if(all || !v.second)
objs.push_back(v.first);
}
}