Merge pull request #15501 from bgbsww/bgbsww-toponamingSaveRestore4

Toponaming: Transfer in getLinksTo
This commit is contained in:
Chris Hennes
2024-07-22 11:23:12 -05:00
committed by GitHub
13 changed files with 536 additions and 29 deletions

View File

@@ -364,7 +364,7 @@ bool GeoFeatureGroupExtension::extensionGetSubObject(DocumentObject *&ret, const
*mat *= const_cast<GeoFeatureGroupExtension*>(this)->placement().getValue().toMatrix();
}else if((dot=strchr(subname,'.'))) {
if(subname[0]!='$')
ret = Group.find(std::string(subname,dot));
ret = Group.findUsingMap(std::string(subname,dot));
else{
std::string name = std::string(subname+1,dot);
for(auto child : Group.getValues()) {

View File

@@ -381,7 +381,7 @@ bool GroupExtension::extensionGetSubObject(DocumentObject *&ret, const char *sub
if(!dot)
return false;
if(subname[0]!='$')
ret = Group.find(std::string(subname,dot));
ret = Group.findUsingMap(std::string(subname,dot));
else{
std::string name = std::string(subname+1,dot);
for(auto child : Group.getValues()) {

View File

@@ -1147,7 +1147,7 @@ int LinkBaseExtension::getElementIndex(const char *subname, const char **psubnam
// Try search by element objects' name
std::string name(subname,dot);
if(_ChildCache.getSize()) {
auto obj=_ChildCache.find(name,&idx);
auto obj=_ChildCache.findUsingMap(name,&idx);
if(obj) {
auto group = obj->getExtensionByType<GroupExtension>(true,false);
if(group) {

View File

@@ -25,6 +25,7 @@
#include <App/Application.h>
#include <App/Document.h>
#include <App/DocumentObject.h>
#include <App/DocumentObserver.h>
#include <Base/Reader.h>
#include <Base/Tools.h>
#include <Base/Writer.h>
@@ -1079,3 +1080,48 @@ void PropertyExpressionEngine::onRelabeledDocument(const App::Document &doc)
e.second.expression->visit(v);
}
}
void PropertyExpressionEngine::getLinksTo(std::vector<App::ObjectIdentifier>& identifiers,
App::DocumentObject* obj,
const char* subname,
bool all) const
{
Expression::DepOption option =
all ? Expression::DepOption::DepAll : Expression::DepOption::DepNormal;
App::SubObjectT objT(obj, subname);
auto sobj = objT.getSubObject();
auto subElement = objT.getOldElementName();
for (auto& [expressionId, expressionInfo] : expressions) {
const auto& deps = expressionInfo.expression->getDeps(option);
auto it = deps.find(obj);
if (it == deps.end()) {
continue;
}
auto [docObj, map] = *it;
for (auto& [key, paths] : map) {
if (!subname) {
identifiers.push_back(expressionId);
break;
}
bool found = false;
for (const auto& path : paths) {
if (path.getSubObjectName() == subname) {
identifiers.push_back(expressionId);
found = true;
break;
}
App::SubObjectT sobjT(obj, path.getSubObjectName().c_str());
if (sobjT.getSubObject() == sobj && sobjT.getOldElementName() == subElement) {
identifiers.push_back(expressionId);
found = true;
break;
}
}
if (found) {
break;
}
}
}
}

View File

@@ -160,6 +160,11 @@ public:
void afterRestore() override;
void onContainerRestored() override;
void getLinksTo(std::vector<App::ObjectIdentifier> &identifiers,
App::DocumentObject *obj,
const char *subname=nullptr,
bool all=false) const override;
/* Python interface */
PyObject *getPyObject() override;
void setPyObject(PyObject *) override;

View File

@@ -37,6 +37,7 @@
#include "Document.h"
#include "DocumentObject.h"
#include "DocumentObjectPy.h"
#include "DocumentObserver.h"
#include "ObjectIdentifier.h"
#include "ElementNamingUtils.h"
#include "GeoFeature.h"
@@ -71,6 +72,14 @@ void PropertyLinkBase::setAllowExternal(bool allow) {
setFlag(LinkAllowExternal,allow);
}
void PropertyLinkBase::setSilentRestore(bool allow) {
setFlag(LinkSilentRestore,allow);
}
void PropertyLinkBase::setReturnNewElement(bool enable) {
setFlag(LinkNewElement, enable);
}
void PropertyLinkBase::hasSetValue() {
auto owner = dynamic_cast<DocumentObject*>(getContainer());
if(owner)
@@ -508,7 +517,7 @@ bool PropertyLinkBase::_updateElementReference(DocumentObject *feature,
(void)obj;
(void)reverse;
(void)notify;
shadow.second = sub;
shadow.oldName = sub;
return false;
#endif
}
@@ -791,6 +800,17 @@ void PropertyLink::getLinks(std::vector<App::DocumentObject *> &objs,
objs.push_back(_pcLink);
}
void PropertyLink::getLinksTo(std::vector<App::ObjectIdentifier>& identifiers,
App::DocumentObject* obj,
const char* subname,
bool all) const
{
(void)subname;
if ((all || _pcScope != LinkScope::Hidden) && obj && _pcLink == obj) {
identifiers.emplace_back(*this);
}
}
void PropertyLink::breakLink(App::DocumentObject *obj, bool clear) {
if(_pcLink == obj || (clear && getContainer()==obj))
setValue(nullptr);
@@ -1075,7 +1095,25 @@ unsigned int PropertyLinkList::getMemSize() const
return static_cast<unsigned int>(_lValueList.size() * sizeof(App::DocumentObject *));
}
DocumentObject *PropertyLinkList::find(const std::string &name, int *pindex) const {
DocumentObject *PropertyLinkList::find(const char *name, int *pindex) const {
const int DONT_MAP_UNDER = 10;
if (!name)
return nullptr;
if(_lValueList.size() <= DONT_MAP_UNDER ) {
int index = -1;
for (auto obj : _lValueList) {
++index;
if(obj && obj->getNameInDocument()
&& boost::equals(name, obj->getNameInDocument())) {
if(pindex)
*pindex = index;
return obj;
}
}
return nullptr;
}
// We're using a map. Do we need to (re)create it?
if(_nameMap.empty() || _nameMap.size()>_lValueList.size()) {
_nameMap.clear();
for(int i=0;i<(int)_lValueList.size();++i) {
@@ -1084,6 +1122,7 @@ DocumentObject *PropertyLinkList::find(const std::string &name, int *pindex) con
_nameMap[obj->getNameInDocument()] = i;
}
}
// Now lookup up in that map
auto it = _nameMap.find(name);
if(it == _nameMap.end())
return nullptr;
@@ -1091,6 +1130,17 @@ DocumentObject *PropertyLinkList::find(const std::string &name, int *pindex) con
return _lValueList[it->second];
}
DocumentObject *PropertyLinkList::findUsingMap(const std::string &name, int *pindex) const {
if (_nameMap.size() == _lValueList.size()) {
auto it = _nameMap.find(name);
if(it == _nameMap.end())
return nullptr;
if(pindex) *pindex = it->second;
return _lValueList[it->second];
}
return find(name.c_str(), pindex);
}
void PropertyLinkList::getLinks(std::vector<App::DocumentObject *> &objs,
bool all, std::vector<std::string> *subs, bool newStyle) const
{
@@ -1105,6 +1155,25 @@ void PropertyLinkList::getLinks(std::vector<App::DocumentObject *> &objs,
}
}
void PropertyLinkList::getLinksTo(std::vector<App::ObjectIdentifier>& identifiers,
App::DocumentObject* obj,
const char* subname,
bool all) const
{
(void)subname;
if (!obj || (!all && _pcScope == LinkScope::Hidden)) {
return;
}
int i = -1;
for (auto o : _lValueList) {
++i;
if (o == obj) {
identifiers.emplace_back(*this, i);
break;
}
}
}
void PropertyLinkList::breakLink(App::DocumentObject *obj, bool clear) {
if(clear && getContainer()==obj) {
setValues({});
@@ -1287,7 +1356,7 @@ PyObject *PropertyLinkSub::getPyObject()
tup[0] = Py::asObject(_pcLinkSub->getPyObject());
#ifdef FC_USE_TNP_FIX
int i = 0;
for (auto &sub : getSubValues(true))
for (auto &sub : getSubValues(testFlag(LinkNewElement)))
list[i++] = Py::String(sub);
#else
for(unsigned int i = 0;i<_cSubList.size(); i++)
@@ -1565,6 +1634,58 @@ std::string PropertyLinkBase::tryImportSubName(const App::DocumentObject *obj, c
return {};
}
void PropertyLinkBase::_getLinksTo(std::vector<App::ObjectIdentifier>& identifiers,
App::DocumentObject* obj,
const char* subname,
const std::vector<std::string>& subs,
const std::vector<PropertyLinkBase::ShadowSub>& shadows) const
{
if (!subname) {
identifiers.emplace_back(*this);
return;
}
App::SubObjectT objT(obj, subname);
auto subObject = objT.getSubObject();
auto subElement = objT.getOldElementName();
int i = -1;
for (const auto& sub : subs) {
++i;
if (sub == subname) {
identifiers.emplace_back(*this);
return;
}
if (!subObject) {
continue;
}
// There is a subobject and the subname doesn't match our current entry
App::SubObjectT sobjT(obj, sub.c_str());
if (sobjT.getSubObject() == subObject && sobjT.getOldElementName() == subElement) {
identifiers.emplace_back(*this);
return;
}
// The oldElementName ( short, I.E. "Edge5" ) doesn't match.
if (i < (int)shadows.size()) {
const auto& [shadowNewName, shadowOldName] = shadows[i];
if (shadowNewName == subname || shadowOldName == subname) {
identifiers.emplace_back(*this);
return;
}
if (!subObject) {
continue;
}
App::SubObjectT shadowobjT(obj,
shadowNewName.empty() ? shadowOldName.c_str()
: shadowNewName.c_str());
if (shadowobjT.getSubObject() == subObject
&& shadowobjT.getOldElementName() == subElement) {
identifiers.emplace_back(*this);
return;
}
}
}
}
#define ATTR_SHADOWED "shadowed"
#define ATTR_SHADOW "shadow"
#define ATTR_MAPPED "mapped"
@@ -1793,6 +1914,18 @@ void PropertyLinkSub::getLinks(std::vector<App::DocumentObject *> &objs,
}
}
void PropertyLinkSub::getLinksTo(std::vector<App::ObjectIdentifier>& identifiers,
App::DocumentObject* obj,
const char* subname,
bool all) const
{
if (all || _pcScope != LinkScope::Hidden) {
if (obj && obj == _pcLinkSub) {
_getLinksTo(identifiers, obj, subname, _cSubList, _ShadowSubList);
}
}
}
void PropertyLinkSub::breakLink(App::DocumentObject *obj, bool clear) {
if(obj == _pcLinkSub || (clear && getContainer()==obj))
setValue(nullptr);
@@ -2763,6 +2896,49 @@ void PropertyLinkSubList::getLinks(std::vector<App::DocumentObject *> &objs,
}
}
void PropertyLinkSubList::getLinksTo(std::vector<App::ObjectIdentifier>& identifiers,
App::DocumentObject* obj,
const char* subname,
bool all) const
{
if (!obj || (!all && _pcScope == LinkScope::Hidden)) {
return;
}
App::SubObjectT objT(obj, subname);
auto subObject = objT.getSubObject();
auto subElement = objT.getOldElementName();
int i = -1;
for (const auto& o : _lValueList) {
++i;
if (o != obj) {
continue;
}
if (!subname || (i < (int)_lSubList.size() && subname == _lSubList[i])) {
identifiers.emplace_back(*this, i);
continue;
}
if (!subObject || i < (int)_lSubList.size()) {
continue;
}
App::SubObjectT sobjT(obj, _lSubList[i].c_str());
if (sobjT.getSubObject() == subObject && sobjT.getOldElementName() == subElement) {
identifiers.emplace_back(*this);
continue;
}
if (i < (int)_ShadowSubList.size()) {
const auto& shadow = _ShadowSubList[i];
App::SubObjectT sobjT(obj,
shadow.newName.empty() ? shadow.oldName.c_str()
: shadow.newName.c_str());
if (sobjT.getSubObject() == subObject && sobjT.getOldElementName() == subElement) {
identifiers.emplace_back(*this);
continue;
}
}
}
}
void PropertyLinkSubList::breakLink(App::DocumentObject *obj, bool clear) {
std::vector<DocumentObject*> values;
std::vector<std::string> subs;
@@ -3502,6 +3678,8 @@ int PropertyXLink::checkRestore(std::string *msg) const {
return 0;
}
if(!_pcLink) {
if (testFlag(LinkSilentRestore))
return 0;
if(testFlag(LinkAllowPartial) &&
(!docInfo->pcDoc ||
docInfo->pcDoc->testStatus(App::Document::PartialDoc)))
@@ -3598,6 +3776,7 @@ void PropertyXLink::Save (Base::Writer &writer) const {
<< "<XLink file=\"" << encodeAttribute(path)
<< "\" stamp=\"" << (docInfo&&docInfo->pcDoc?docInfo->pcDoc->LastModifiedDate.getValue():"")
<< "\" name=\"" << objectName;
}
if(testFlag(LinkAllowPartial))
@@ -3665,6 +3844,7 @@ void PropertyXLink::Restore(Base::XMLReader &reader)
stampAttr = reader.getAttribute("stamp");
if(reader.hasAttribute("file"))
file = reader.getAttribute("file");
setFlag(LinkAllowPartial,
reader.hasAttribute("partial") &&
reader.getAttributeAsInteger("partial"));
@@ -4013,6 +4193,17 @@ void PropertyXLink::getLinks(std::vector<App::DocumentObject *> &objs,
}
}
void PropertyXLink::getLinksTo(std::vector<App::ObjectIdentifier> &identifiers,
App::DocumentObject *obj,
const char *subname,
bool all) const {
if (all || _pcScope != LinkScope::Hidden) {
if (obj && obj == _pcLink) {
_getLinksTo(identifiers, obj, subname, _SubList, _ShadowSubList);
}
}
}
bool PropertyXLink::adjustLink(const std::set<App::DocumentObject*> &inList) {
if (_pcScope==LinkScope::Hidden)
return false;
@@ -4667,6 +4858,75 @@ void PropertyXLinkSubList::getLinks(std::vector<App::DocumentObject *> &objs,
}
}
// Same algorithm as _getLinksTo above, but returns all matches
void PropertyXLinkSubList::_getLinksToList(
std::vector<App::ObjectIdentifier>& identifiers,
App::DocumentObject* obj,
const char* subname,
const std::vector<std::string>& subs,
const std::vector<PropertyLinkBase::ShadowSub>& shadows) const
{
if (!subname) {
identifiers.emplace_back(*this);
return;
}
App::SubObjectT objT(obj, subname);
auto subObject = objT.getSubObject();
auto subElement = objT.getOldElementName();
int i = -1;
for (const auto& sub : subs) {
++i;
if (sub == subname) {
identifiers.emplace_back(*this, i);
continue;
}
if (!subObject) {
continue;
}
// There is a subobject and the subname doesn't match our current entry
App::SubObjectT sobjT(obj, sub.c_str());
if (sobjT.getSubObject() == subObject && sobjT.getOldElementName() == subElement) {
identifiers.emplace_back(*this, i);
continue;
}
// The oldElementName ( short, I.E. "Edge5" ) doesn't match.
if (i < (int)shadows.size()) {
const auto& [shadowNewName, shadowOldName] = shadows[i];
if (shadowNewName == subname || shadowOldName == subname) {
identifiers.emplace_back(*this, i);
continue;
}
if (!subObject) {
continue;
}
App::SubObjectT shadowobjT(obj,
shadowNewName.empty() ? shadowOldName.c_str()
: shadowNewName.c_str());
if (shadowobjT.getSubObject() == subObject
&& shadowobjT.getOldElementName() == subElement) {
identifiers.emplace_back(*this, i);
continue;
}
}
}
}
void PropertyXLinkSubList::getLinksTo(std::vector<App::ObjectIdentifier>& identifiers,
App::DocumentObject* obj,
const char* subname,
bool all) const
{
if (all || _pcScope != LinkScope::Hidden) {
for (auto& l : _Links) {
// This is the same algorithm as _getLinksTo, but returns lists, not single entries
if (obj && obj == l._pcLink) {
_getLinksToList(identifiers, obj, subname, l._SubList, l._ShadowSubList);
}
}
}
}
void PropertyXLinkSubList::breakLink(App::DocumentObject *obj, bool clear) {
if(clear && getContainer()==obj) {
setValue(nullptr);
@@ -4858,8 +5118,10 @@ void PropertyXLinkContainer::afterRestore() {
if(info.docLabel != obj->getDocument()->Label.getValue())
_DocMap[App::quote(info.docLabel)] = obj->getDocument()->Label.getValue();
}
if(_Deps.insert(std::make_pair(obj,info.xlink->getScope()==LinkScope::Hidden)).second)
if(_Deps.insert(std::make_pair(obj,info.xlink->getScope()==LinkScope::Hidden)).second) {
_XLinks[obj->getFullName()] = std::move(info.xlink);
onAddDep(obj);
}
}
_XLinkRestores.reset();
}
@@ -4881,6 +5143,7 @@ void PropertyXLinkContainer::breakLink(App::DocumentObject *obj, bool clear) {
else if (!it->second)
obj->_removeBackLink(owner);
_Deps.erase(it);
onRemoveDep(obj);
hasSetValue();
return;
}
@@ -5003,14 +5266,30 @@ void PropertyXLinkContainer::Restore(Base::XMLReader &reader) {
void PropertyXLinkContainer::aboutToSetChildValue(App::Property &prop) {
auto xlink = dynamic_cast<App::PropertyXLink*>(&prop);
if(xlink && xlink->testFlag(LinkDetached)) {
if(_Deps.erase(const_cast<App::DocumentObject*>(xlink->getValue())))
onBreakLink(xlink->getValue());
auto obj = const_cast<App::DocumentObject*>(xlink->getValue());
if(_Deps.erase(obj)) {
_onBreakLink(xlink->getValue());
onRemoveDep(obj);
}
}
}
void PropertyXLinkContainer::onBreakLink(DocumentObject *) {
}
void PropertyXLinkContainer::_onBreakLink(DocumentObject *obj) {
try {
onBreakLink(obj);
} catch (Base::Exception &e) {
e.ReportException();
FC_ERR("Exception on breaking link property " << getFullName());
} catch (std::exception &e) {
FC_ERR("Exception on breaking link property " << getFullName() << ": " << e.what());
} catch (...) {
FC_ERR("Exception on breaking link property " << getFullName());
}
}
PropertyXLink *PropertyXLinkContainer::createXLink() {
return new PropertyXLink(false,this);
}

View File

@@ -31,7 +31,6 @@
#include <unordered_set>
#include <unordered_map>
// #include "GeoFeature.h"
#include "Property.h"
namespace Base {
@@ -184,6 +183,19 @@ public:
virtual void getLinks(std::vector<App::DocumentObject *> &objs,
bool all=false, std::vector<std::string> *subs=nullptr, bool newStyle=true) const = 0;
/** Obtain identifiers from this link property that link to a give object
* @param identifiers: holds the returned identifier to reference the given object
* @param obj: the referenced object
* @param subname: optional subname reference
* @param all: if true, then return all the references regardless of
* this LinkScope. If false, then return only if the LinkScope
* is not hidden.
*/
virtual void getLinksTo(std::vector<App::ObjectIdentifier> &identifiers,
App::DocumentObject *obj,
const char *subname=nullptr,
bool all=false) const = 0;
/** Called to reset this link property
*
* @param obj: reset link property if it is linked to this object
@@ -546,6 +558,8 @@ public:
LinkAllowPartial,
LinkRestoreLabel,
LinkSyncSubObject, // used by DlgPropertyLink
LinkNewElement, // return new element name in getPyObject
LinkSilentRestore, // do not report error on restore (e.g. missing external link)
};
inline bool testFlag(int flag) const {
return _Flags.test((std::size_t)flag);
@@ -553,6 +567,12 @@ public:
virtual void setAllowPartial(bool enable) { (void)enable; }
void setReturnNewElement(bool enable);
void setSilentRestore(bool enable);
boost::signals2::signal<void(const std::string &, const std::string &)> signalUpdateElementReference;
protected:
void hasSetValue() override;
@@ -562,6 +582,13 @@ protected:
_Flags.set((std::size_t)flag,value);
}
void _getLinksTo(
std::vector<App::ObjectIdentifier> &identifiers,
App::DocumentObject *obj,
const char *subname,
const std::vector<std::string> &subs,
const std::vector<PropertyLinkBase::ShadowSub> &shadows) const;
private:
std::set<std::string> _LabelRefs;
std::set<App::DocumentObject*> _ElementRefs;
@@ -631,6 +658,11 @@ public:
void getLinks(std::vector<App::DocumentObject *> &objs,
bool all=false, std::vector<std::string> *subs=nullptr, bool newStyle=true) const override;
void getLinksTo(std::vector<App::ObjectIdentifier> &identifiers,
App::DocumentObject *obj,
const char *subname=nullptr,
bool all=false) const override;
void breakLink(App::DocumentObject *obj, bool clear) override;
bool adjustLink(const std::set<App::DocumentObject *> &inList) override;
@@ -721,6 +753,11 @@ public:
void getLinks(std::vector<App::DocumentObject *> &objs,
bool all=false, std::vector<std::string> *subs=nullptr, bool newStyle=true) const override;
void getLinksTo(std::vector<App::ObjectIdentifier> &identifiers,
App::DocumentObject *obj,
const char *subname=nullptr,
bool all=false) const override;
void breakLink(App::DocumentObject *obj, bool clear) override;
bool adjustLink(const std::set<App::DocumentObject *> &inList) override;
@@ -728,11 +765,8 @@ public:
Property *CopyOnLinkReplace(const App::DocumentObject *parent,
App::DocumentObject *oldObj, App::DocumentObject *newObj) const override;
DocumentObject *find(const std::string &, int *pindex=nullptr) const;
DocumentObject *find(const char *sub, int *pindex=nullptr) const {
if(!sub) return nullptr;
return find(std::string(sub),pindex);
}
DocumentObject *findUsingMap(const std::string &, int *pindex=nullptr) const;
DocumentObject *find(const char *sub, int *pindex=nullptr) const;
protected:
DocumentObject *getPyValue(PyObject *item) const override;
@@ -862,6 +896,11 @@ public:
void getLinks(std::vector<App::DocumentObject *> &objs,
bool all=false, std::vector<std::string> *subs=nullptr, bool newStyle=true) const override;
void getLinksTo(std::vector<App::ObjectIdentifier> &identifiers,
App::DocumentObject *obj,
const char *subname=nullptr,
bool all=false) const override;
void breakLink(App::DocumentObject *obj, bool clear) override;
bool adjustLink(const std::set<App::DocumentObject *> &inList) override;
@@ -1009,6 +1048,11 @@ public:
void getLinks(std::vector<App::DocumentObject *> &objs,
bool all=false, std::vector<std::string> *subs=nullptr, bool newStyle=true) const override;
void getLinksTo(std::vector<App::ObjectIdentifier> &identifiers,
App::DocumentObject *obj,
const char *subname=nullptr,
bool all=false) const override;
void breakLink(App::DocumentObject *obj, bool clear) override;
bool adjustLink(const std::set<App::DocumentObject *> &inList) override;
@@ -1132,6 +1176,11 @@ public:
void getLinks(std::vector<App::DocumentObject *> &objs,
bool all=false, std::vector<std::string> *subs=nullptr, bool newStyle=true) const override;
void getLinksTo(std::vector<App::ObjectIdentifier> &identifiers,
App::DocumentObject *obj,
const char *subname=nullptr,
bool all=false) const override;
bool adjustLink(const std::set<App::DocumentObject *> &inList) override;
const std::vector<std::string>& getSubValues() const {
@@ -1302,6 +1351,11 @@ public:
void getLinks(std::vector<App::DocumentObject *> &objs,
bool all=false, std::vector<std::string> *subs=nullptr, bool newStyle=true) const override;
void getLinksTo(std::vector<App::ObjectIdentifier> &identifiers,
App::DocumentObject *obj,
const char *subname=nullptr,
bool all=false) const override;
void breakLink(App::DocumentObject *obj, bool clear) override;
bool adjustLink(const std::set<App::DocumentObject *> &inList) override;
@@ -1317,6 +1371,14 @@ public:
void setSyncSubObject(bool enable);
protected:
void _getLinksToList(
std::vector<App::ObjectIdentifier> &identifiers,
App::DocumentObject *obj,
const char *subname,
const std::vector<std::string> &subs,
const std::vector<PropertyLinkBase::ShadowSub> &shadows) const;
protected:
std::list<PropertyXLinkSub> _Links;
};
@@ -1369,6 +1431,8 @@ protected:
void updateDeps(std::map<DocumentObject*,bool> &&newDeps);
void clearDeps();
void _onBreakLink(App::DocumentObject *obj);
protected:
std::map<App::DocumentObject*,bool> _Deps;
std::map<std::string, std::unique_ptr<PropertyXLink> > _XLinks;

View File

@@ -27,6 +27,7 @@
#include <Base/Writer.h>
#include "PropertyGeometryList.h"
#include "GeometryMigrationExtension.h"
#include "GeometryPy.h"
#include "Part2DObject.h"
@@ -84,26 +85,43 @@ void PropertyGeometryList::setValue(const Geometry* lValue)
void PropertyGeometryList::setValues(const std::vector<Geometry*>& lValue)
{
auto copy = lValue;
for(auto &geo : copy) // copy of the individual geometry pointers
geo = geo->clone();
setValues(std::move(copy));
aboutToSetValue();
std::sort(_lValueList.begin(), _lValueList.end());
for (auto & geo : copy) {
auto range = std::equal_range(_lValueList.begin(), _lValueList.end(), geo);
// clone if the new entry does not exist in the original value list, or
// else, simply reuse it (i.e. erase it so that it won't get deleted below).
if (range.first == range.second)
geo = geo->clone();
else
_lValueList.erase(range.first, range.second);
}
for (auto v : _lValueList)
delete v;
_lValueList = std::move(copy);
hasSetValue();
}
void PropertyGeometryList::setValues(std::vector<Geometry*> &&lValue)
{
// Unlike above, the moved version of setValues() indicates the caller want
// us to manager the memory of the passed in values. So no need clone.
aboutToSetValue();
std::set<Geometry*> valueSet(_lValueList.begin(),_lValueList.end());
for(auto v : lValue)
valueSet.erase(v);
std::sort(_lValueList.begin(), _lValueList.end());
for (auto geo : lValue) {
auto range = std::equal_range(_lValueList.begin(), _lValueList.end(), geo);
_lValueList.erase(range.first, range.second);
}
for (auto geo : _lValueList)
delete geo;
_lValueList = std::move(lValue);
for(auto v : valueSet)
delete v;
hasSetValue();
}
void PropertyGeometryList::set1Value(int idx, std::unique_ptr<Geometry> &&lValue)
{
if (!lValue)
return;
if(idx>=(int)_lValueList.size())
throw Base::IndexError("Index out of bound");
aboutToSetValue();
@@ -171,6 +189,12 @@ void PropertyGeometryList::trySaveGeometry(Geometry * geom, Base::Writer &writer
// Not all geometry classes implement Save() and throw an exception instead
try {
geom->Save(writer);
for( auto & ext : geom->getExtensions() ) {
auto extension = ext.lock();
auto gpe = freecad_dynamic_cast<GeometryMigrationPersistenceExtension>(extension.get());
if (gpe)
gpe->postSave(writer);
}
}
catch (const Base::NotImplementedError& e) {
Base::Console().Warning(std::string("PropertyGeometryList"), "Not yet implemented: %s\n", e.what());
@@ -181,6 +205,17 @@ void PropertyGeometryList::tryRestoreGeometry(Geometry * geom, Base::XMLReader &
{
// Not all geometry classes implement Restore() and throw an exception instead
try {
if (!reader.getAttributeAsInteger("migrated", "0") && reader.hasAttribute("id")) {
auto ext = std::make_unique<GeometryMigrationExtension>();
ext->setId(reader.getAttributeAsInteger("id"));
if(reader.hasAttribute("ref")) {
const char *ref = reader.getAttribute("ref");
int index = reader.getAttributeAsInteger("refIndex", "1");
unsigned long flags = (unsigned long)reader.getAttributeAsUnsigned("flags");
ext->setReference(ref, index, flags);
}
geom->setExtension(std::move(ext));
}
geom->Restore(reader);
}
catch (const Base::NotImplementedError& e) {
@@ -193,8 +228,16 @@ void PropertyGeometryList::Save(Writer &writer) const
writer.Stream() << writer.ind() << "<GeometryList count=\"" << getSize() <<"\">" << endl;
writer.incInd();
for (int i = 0; i < getSize(); i++) {
writer.Stream() << writer.ind() << "<Geometry type=\""
<< _lValueList[i]->getTypeId().getName() << "\">" << endl;;
writer.Stream() << writer.ind() << "<Geometry type=\""
<< _lValueList[i]->getTypeId().getName() << "\"" << endl;
for( auto &e : _lValueList[i]->getExtensions() ) {
auto ext = e.lock();
auto gpe = freecad_dynamic_cast<GeometryMigrationPersistenceExtension>(ext.get());
if (gpe)
gpe->preSave(writer);
}
writer.Stream() << " migrated=\"1\">\n";
writer.incInd();
trySaveGeometry(_lValueList[i], writer);
writer.decInd();
@@ -263,3 +306,10 @@ unsigned int PropertyGeometryList::getMemSize() const
size += _lValueList[i]->getMemSize();
return size;
}
void PropertyGeometryList::moveValues(PropertyGeometryList &&other)
{
setValues(std::move(other._lValueList));
}

View File

@@ -64,8 +64,10 @@ public:
void setValues(const std::vector<Geometry*>&);
void setValues(std::vector<Geometry*>&&);
void moveValues(PropertyGeometryList &&other);
/// index operator
const Geometry *operator[] (const int idx) const {
Geometry *operator[] (const int idx) const {
return _lValueList[idx];
}

View File

@@ -303,8 +303,14 @@ void PropertyPartShape::Save (Base::Writer &writer) const
writer.Stream() << " file=\""
<< writer.addFile(getFileName(binary?".bin":".brp").c_str(), this)
<< "\"/>\n";
} else if(binary) {
writer.Stream() << " binary=\"1\">\n";
_Shape.exportBinary(writer.beginCharStream(Base::CharStreamFormat::Base64Encoded));
writer.endCharStream() << writer.ind() << "</Part>\n";
} else {
writer.Stream() << "/>\n";
writer.Stream() << " brep=\"1\">\n";
_Shape.exportBrep(writer.beginCharStream(Base::CharStreamFormat::Raw)<<'\n');
writer.endCharStream() << '\n' << writer.ind() << "</Part>\n";
}
if(_SaveHasher) {

View File

@@ -423,7 +423,7 @@ App::DocumentObject *Feature::getSubObject(const char *subname,
if (dot) {
auto body = PartDesign::Body::findBodyOf(this);
if (body) {
auto feat = body->Group.find(std::string(subname, dot));
auto feat = body->Group.findUsingMap(std::string(subname, dot));
if (feat) {
Base::Matrix4D _mat;
if (!transform) {

View File

@@ -31,6 +31,7 @@
#include <App/Document.h>
#include <App/DocumentObject.h>
#include <App/DocumentObserver.h>
#include <App/Expression.h>
#include <App/ExpressionParser.h>
#include <App/ExpressionVisitors.h>
@@ -2267,3 +2268,52 @@ bool PropertySheet::hasSpan() const
{
return !mergedCells.empty();
}
void PropertySheet::getLinksTo(std::vector<App::ObjectIdentifier>& identifiers,
App::DocumentObject* obj,
const char* subname,
bool all) const
{
Expression::DepOption option =
all ? Expression::DepOption::DepAll : Expression::DepOption::DepNormal;
App::SubObjectT objT(obj, subname);
auto subObject = objT.getSubObject();
auto subElement = objT.getOldElementName();
auto owner = Base::freecad_dynamic_cast<App::DocumentObject>(getContainer());
for (const auto& [cellName, cellExpression] : data) {
if (auto expr = cellExpression->getExpression()) {
const auto& deps = expr->getDeps(option);
auto it = deps.find(obj);
if (it == deps.end()) {
continue;
}
const auto [docObj, depsList] = *it;
for (auto& [depName, paths] : depsList) {
if (!subname) {
identifiers.emplace_back(owner, cellName.toString().c_str());
break;
}
bool found = false;
for (const auto& path : paths) {
if (path.getSubObjectName() == subname) {
identifiers.emplace_back(owner, cellName.toString().c_str());
found = true;
break;
}
App::SubObjectT sobjT(obj, path.getSubObjectName().c_str());
if (sobjT.getSubObject() == subObject
&& sobjT.getOldElementName() == subElement) {
identifiers.emplace_back(owner, cellName.toString().c_str());
found = true;
break;
}
}
if (found) {
break;
}
}
}
}
}

View File

@@ -78,6 +78,11 @@ public:
void Restore(Base::XMLReader& reader) override;
void getLinksTo(std::vector<App::ObjectIdentifier>& identifiers,
App::DocumentObject* obj,
const char* subname = nullptr,
bool all = false) const override;
void copyCells(Base::Writer& writer, const std::vector<App::Range>& ranges) const;
void pasteCells(Base::XMLReader& reader, App::Range dstRange);