Methods to support Toponaming element maps
This commit is contained in:
@@ -637,6 +637,11 @@ unsigned int ComplexGeoData::getMemSize() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<IndexedName> ComplexGeoData::getHigherElements(const char *, bool) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void ComplexGeoData::setMappedChildElements(const std::vector<Data::ElementMap::MappedChildElements> & children)
|
||||
{
|
||||
// DO NOT reset element map if there is one. Because we allow mixing child
|
||||
|
||||
@@ -321,6 +321,9 @@ public:
|
||||
/// Get the current element map size
|
||||
size_t getElementMapSize(bool flush=true) const;
|
||||
|
||||
/// Return the higher level element names of the given element
|
||||
virtual std::vector<IndexedName> getHigherElements(const char *name, bool silent=false) const;
|
||||
|
||||
/// Return the current element map version
|
||||
virtual std::string getElementMapVersion() const;
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <App/GeoFeaturePy.h>
|
||||
|
||||
#include "ComplexGeoData.h"
|
||||
#include "Document.h"
|
||||
#include "GeoFeature.h"
|
||||
#include "GeoFeatureGroupExtension.h"
|
||||
#include "ElementNamingUtils.h"
|
||||
@@ -146,12 +147,27 @@ DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subn
|
||||
subname = "";
|
||||
const char *element = Data::findElementName(subname);
|
||||
if(_element) *_element = element;
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
elementName.first.clear();
|
||||
elementName.second.clear();
|
||||
auto sobj = obj->getSubObject(std::string(subname, element).c_str());
|
||||
if(!sobj)
|
||||
return nullptr;
|
||||
auto linked = sobj->getLinkedObject(true);
|
||||
auto geo = Base::freecad_dynamic_cast<GeoFeature>(linked);
|
||||
// if(!geo && linked) {
|
||||
// auto ext = linked->getExtensionByType<LinkBaseExtension>(true);
|
||||
// if(ext)
|
||||
// geo = Base::freecad_dynamic_cast<GeoFeature>(ext->getTrueLinkedObject(true));
|
||||
// }
|
||||
#else
|
||||
auto sobj = obj->getSubObject(subname);
|
||||
if(!sobj)
|
||||
return nullptr;
|
||||
obj = sobj->getLinkedObject(true);
|
||||
auto geo = dynamic_cast<GeoFeature*>(obj);
|
||||
if(geoFeature)
|
||||
#endif
|
||||
if(geoFeature)
|
||||
*geoFeature = geo;
|
||||
if(!obj || (filter && obj!=filter))
|
||||
return nullptr;
|
||||
@@ -189,3 +205,81 @@ void GeoFeature::setMaterialAppearance(const App::Material& material)
|
||||
{
|
||||
Q_UNUSED(material)
|
||||
}
|
||||
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
bool GeoFeature::hasMissingElement(const char *subname) {
|
||||
return Data::hasMissingElement(subname);
|
||||
if(!subname)
|
||||
return false;
|
||||
auto dot = strrchr(subname,'.');
|
||||
if(!dot)
|
||||
return subname[0]=='?';
|
||||
return dot[1]=='?';
|
||||
}
|
||||
|
||||
void GeoFeature::updateElementReference() {
|
||||
auto prop = getPropertyOfGeometry();
|
||||
if(!prop) return;
|
||||
auto geo = prop->getComplexData();
|
||||
if(!geo) return;
|
||||
bool reset = false;
|
||||
// auto version = getElementMapVersion(prop);
|
||||
// if(_ElementMapVersion.getStrValue().empty())
|
||||
// _ElementMapVersion.setValue(version);
|
||||
// else if(_ElementMapVersion.getStrValue()!=version) {
|
||||
// reset = true;
|
||||
// _ElementMapVersion.setValue(version);
|
||||
// }
|
||||
PropertyLinkBase::updateElementReferences(this,reset);
|
||||
}
|
||||
|
||||
void GeoFeature::onChanged(const Property *prop) {
|
||||
if(prop==getPropertyOfGeometry()) {
|
||||
if(getDocument() && !getDocument()->testStatus(Document::Restoring)
|
||||
&& !getDocument()->isPerformingTransaction())
|
||||
{
|
||||
updateElementReference();
|
||||
}
|
||||
}
|
||||
DocumentObject::onChanged(prop);
|
||||
}
|
||||
|
||||
//void GeoFeature::onDocumentRestored() {
|
||||
// if(!getDocument()->testStatus(Document::Status::Importing))
|
||||
// _ElementMapVersion.setValue(getElementMapVersion(getPropertyOfGeometry(),true));
|
||||
// DocumentObject::onDocumentRestored();
|
||||
//}
|
||||
|
||||
//const std::vector<std::string>&
|
||||
//GeoFeature::searchElementCache(const std::string &element,
|
||||
// Data::SearchOptions options,
|
||||
// double tol,
|
||||
// double atol) const
|
||||
//{
|
||||
// static std::vector<std::string> none;
|
||||
// (void)element;
|
||||
// (void)options;
|
||||
// (void)tol;
|
||||
// (void)atol;
|
||||
// return none;
|
||||
//}
|
||||
|
||||
//const std::vector<const char *>&
|
||||
//GeoFeature::getElementTypes(bool /*all*/) const
|
||||
//{
|
||||
// static std::vector<const char *> nil;
|
||||
// auto prop = getPropertyOfGeometry();
|
||||
// if (!prop)
|
||||
// return nil;
|
||||
// return prop->getComplexData()->getElementTypes();
|
||||
//}
|
||||
|
||||
std::vector<Data::IndexedName>
|
||||
GeoFeature::getHigherElements(const char *element, bool silent) const
|
||||
{
|
||||
auto prop = getPropertyOfGeometry();
|
||||
if (!prop)
|
||||
return {};
|
||||
return prop->getComplexData()->getHigherElements(element, silent);
|
||||
}
|
||||
#endif
|
||||
@@ -140,7 +140,44 @@ public:
|
||||
* appearance from an App::Material object.
|
||||
*/
|
||||
virtual void setMaterialAppearance(const App::Material& material);
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
static bool hasMissingElement(const char *subname);
|
||||
|
||||
/** Search sub element using internal cached geometry
|
||||
*
|
||||
* @param element: element name
|
||||
* @param options: search options
|
||||
* @param tol: coordinate tolerance
|
||||
* @param atol: angle tolerance
|
||||
*
|
||||
* @return Returns a list of found element reference to the new goemetry.
|
||||
* The returned value will be invalidated when the geometry is changed.
|
||||
*
|
||||
* Before changing the property of geometry, GeoFeature will internally
|
||||
* make a snapshot of all referenced element geometry. After change, user
|
||||
* code may call this function to search for the new element name that
|
||||
* reference to the same geometry of the old element.
|
||||
*/
|
||||
// virtual const std::vector<std::string>& searchElementCache(const std::string &element,
|
||||
// Data::SearchOptions options = Data::SearchOption::CheckGeometry,
|
||||
// double tol = 1e-7,
|
||||
// double atol = 1e-10) const;
|
||||
|
||||
|
||||
/// Return the object that owns the shape that contains the give element name
|
||||
virtual DocumentObject *getElementOwner(const Data::MappedName & /*name*/) const
|
||||
{return nullptr;}
|
||||
|
||||
// virtual const std::vector<const char *>& getElementTypes(bool all=true) const;
|
||||
|
||||
/// Return the higher level element names of the given element
|
||||
virtual std::vector<Data::IndexedName> getHigherElements(const char *name, bool silent=false) const;
|
||||
|
||||
protected:
|
||||
void onChanged(const Property* prop) override;
|
||||
// void onDocumentRestored() override;
|
||||
void updateElementReference();
|
||||
#endif
|
||||
protected:
|
||||
std::pair<std::string, std::string> _getElementName(const char* name,
|
||||
const Data::MappedElement& mapped) const;
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include "DocumentObject.h"
|
||||
#include "DocumentObjectPy.h"
|
||||
#include "ObjectIdentifier.h"
|
||||
#include "ElementNamingUtils.h"
|
||||
#include "GeoFeature.h"
|
||||
|
||||
|
||||
FC_LOG_LEVEL_INIT("PropertyLinks",true,true)
|
||||
@@ -55,6 +57,9 @@ namespace sp = std::placeholders;
|
||||
TYPESYSTEM_SOURCE_ABSTRACT(App::PropertyLinkBase , App::Property)
|
||||
|
||||
static std::unordered_map<std::string, std::set<PropertyLinkBase*> > _LabelMap;
|
||||
|
||||
static std::unordered_map<App::DocumentObject *, std::unordered_set<PropertyLinkBase*> > _ElementRefMap;
|
||||
|
||||
PropertyLinkBase::PropertyLinkBase() = default;
|
||||
|
||||
PropertyLinkBase::~PropertyLinkBase() {
|
||||
@@ -97,6 +102,17 @@ bool PropertyLinkBase::isSame(const Property &other) const
|
||||
}
|
||||
|
||||
void PropertyLinkBase::unregisterElementReference() {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
for(auto obj : _ElementRefs) {
|
||||
auto it = _ElementRefMap.find(obj);
|
||||
if(it != _ElementRefMap.end()) {
|
||||
it->second.erase(this);
|
||||
if(it->second.empty())
|
||||
_ElementRefMap.erase(it);
|
||||
}
|
||||
}
|
||||
_ElementRefs.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
void PropertyLinkBase::unregisterLabelReferences()
|
||||
@@ -202,15 +218,58 @@ static std::string propertyName(const Property *prop) {
|
||||
}
|
||||
|
||||
void PropertyLinkBase::updateElementReferences(DocumentObject *feature, bool reverse) {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
if(!feature || !feature->getNameInDocument())
|
||||
return;
|
||||
auto it = _ElementRefMap.find(feature);
|
||||
if(it == _ElementRefMap.end())
|
||||
return;
|
||||
std::vector<PropertyLinkBase*> props;
|
||||
props.reserve(it->second.size());
|
||||
props.insert(props.end(),it->second.begin(),it->second.end());
|
||||
for(auto prop : props) {
|
||||
if(prop->getContainer()) {
|
||||
try {
|
||||
prop->updateElementReference(feature,reverse,true);
|
||||
}catch(Base::Exception &e) {
|
||||
e.ReportException();
|
||||
FC_ERR("Failed to update element reference of " << propertyName(prop));
|
||||
}catch(std::exception &e) {
|
||||
FC_ERR("Failed to update element reference of " << propertyName(prop)
|
||||
<< ": " << e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)feature;
|
||||
(void)reverse;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PropertyLinkBase::_registerElementReference(App::DocumentObject *obj, std::string &sub, ShadowSub &shadow)
|
||||
{
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
if(!obj || !obj->getNameInDocument() || sub.empty())
|
||||
return;
|
||||
if(shadow.first.empty()) {
|
||||
_updateElementReference(0,obj,sub,shadow,false);
|
||||
return;
|
||||
}
|
||||
GeoFeature *geo = 0;
|
||||
const char *element = 0;
|
||||
std::pair<std::string, std::string> elementName;
|
||||
GeoFeature::resolveElement(obj,sub.c_str(), elementName,true,
|
||||
GeoFeature::ElementNameType::Export,0,&element,&geo);
|
||||
if(!geo || !element || !element[0])
|
||||
return;
|
||||
|
||||
if(_ElementRefs.insert(geo).second)
|
||||
_ElementRefMap[geo].insert(this);
|
||||
#else
|
||||
(void)obj;
|
||||
(void)sub;
|
||||
(void)shadow;
|
||||
#endif
|
||||
}
|
||||
|
||||
class StringGuard {
|
||||
@@ -275,12 +334,171 @@ bool PropertyLinkBase::_updateElementReference(DocumentObject *feature,
|
||||
App::DocumentObject *obj, std::string &sub, ShadowSub &shadow,
|
||||
bool reverse, bool notify)
|
||||
{
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
if (!obj || !obj->getNameInDocument()) return false;
|
||||
ShadowSub elementName;
|
||||
const char* subname;
|
||||
if (shadow.first.size())
|
||||
subname = shadow.first.c_str();
|
||||
else if (shadow.second.size())
|
||||
subname = shadow.second.c_str();
|
||||
else
|
||||
subname = sub.c_str();
|
||||
GeoFeature* geo = 0;
|
||||
const char* element = 0;
|
||||
auto ret = GeoFeature::resolveElement(obj,
|
||||
subname,
|
||||
elementName,
|
||||
true,
|
||||
GeoFeature::ElementNameType::Export,
|
||||
feature,
|
||||
&element,
|
||||
&geo);
|
||||
if (!ret || !geo || !element || !element[0]) {
|
||||
if (elementName.second.size())
|
||||
shadow.second.swap(elementName.second);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_ElementRefs.insert(geo).second)
|
||||
_ElementRefMap[geo].insert(this);
|
||||
|
||||
if (!reverse) {
|
||||
if (elementName.first.empty()) {
|
||||
shadow.second.swap(elementName.second);
|
||||
return false;
|
||||
}
|
||||
if (shadow == elementName)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool missing = Data::hasMissingElement(elementName.second.c_str());
|
||||
if (feature == geo && (missing || reverse)) {
|
||||
// If the referenced element is missing, or we are generating element
|
||||
// map for the first time, or we are re-generating the element map due
|
||||
// to version change, i.e. 'reverse', try search by geometry first
|
||||
const char* oldElement = Data::findElementName(shadow.second.c_str());
|
||||
if (!Data::hasMissingElement(oldElement)) {
|
||||
// const auto& names = geo->searchElementCache(oldElement);
|
||||
std::vector<std::string> names; // searchElementCache isn't implemented.
|
||||
if (names.size()) {
|
||||
missing = false;
|
||||
std::string newsub(subname, strlen(subname) - strlen(element));
|
||||
newsub += names.front();
|
||||
GeoFeature::resolveElement(obj,
|
||||
newsub.c_str(),
|
||||
elementName,
|
||||
true,
|
||||
GeoFeature::ElementNameType::Export,
|
||||
feature);
|
||||
const auto& oldName = shadow.first.size() ? shadow.first : shadow.second;
|
||||
const auto& newName =
|
||||
elementName.first.size() ? elementName.first : elementName.second;
|
||||
if (oldName != newName) {
|
||||
FC_WARN(propertyName(this)
|
||||
<< " auto change element reference " << ret->getFullName() << " "
|
||||
<< oldName << " -> " << newName);
|
||||
}
|
||||
}
|
||||
// Note: the following code proves to be too risky. There is no way
|
||||
// (so far) to ensure the recompute do not change the geometry. If
|
||||
// the geometry does remain the same, the above geometry search
|
||||
// should be able to find the new reference any way!
|
||||
#if 0
|
||||
else if (missing && reverse && shadow.first.size()) {
|
||||
// reverse means we are trying to either generate the element
|
||||
// name for the first time, or upgrade to a new map version. In
|
||||
// case of upgrading, we still consult the original mapped name
|
||||
// in first try. Here means the first try failed, and the
|
||||
// geometry search cannot find any match, so we try the
|
||||
// non-mapped name as a last resort.
|
||||
//
|
||||
// WARNING! We are assuming the recomputation is done with no
|
||||
// actual property change, and the resulting geometry remains
|
||||
// the same. If this condition is not met, the result may be
|
||||
// undesirable. TODO: find a way to ensure this condition.
|
||||
|
||||
GeoFeature::resolveElement(obj, shadow.second.c_str(), elementName, true,
|
||||
GeoFeature::ElementNameType::Export,feature);
|
||||
if(!elementName.second.empty()) {
|
||||
missing = Data::ComplexGeoData::hasMissingElement(elementName.second.c_str());
|
||||
if (!missing) {
|
||||
FC_WARN(propertyName(this)
|
||||
<< " element reference changed " << ret->getFullName() << " "
|
||||
<< shadow.first << " -> " << elementName.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (notify)
|
||||
aboutToSetValue();
|
||||
|
||||
auto updateSub = [&](const std::string& newSub) {
|
||||
if (sub != newSub) {
|
||||
//signalUpdateElementReference(sub, newSub);
|
||||
sub = newSub;
|
||||
}
|
||||
};
|
||||
|
||||
if (missing) {
|
||||
FC_WARN(propertyName(this)
|
||||
<< " missing element reference " << ret->getFullName() << " "
|
||||
<< (elementName.first.size() ? elementName.first : elementName.second));
|
||||
shadow.second.swap(elementName.second);
|
||||
}
|
||||
else {
|
||||
FC_TRACE(propertyName(this) << " element reference shadow update " << ret->getFullName()
|
||||
<< " " << shadow.first << " -> " << elementName.first);
|
||||
shadow.swap(elementName);
|
||||
if (shadow.first.size() && Data::hasMappedElementName(sub.c_str()))
|
||||
updateSub(shadow.first);
|
||||
}
|
||||
|
||||
if (reverse) {
|
||||
if (shadow.first.size() && Data::hasMappedElementName(sub.c_str()))
|
||||
updateSub(shadow.first);
|
||||
else
|
||||
updateSub(shadow.second);
|
||||
return true;
|
||||
}
|
||||
if (missing) {
|
||||
if (sub != shadow.first)
|
||||
updateSub(shadow.second);
|
||||
return true;
|
||||
}
|
||||
auto pos2 = shadow.first.rfind('.');
|
||||
if (pos2 == std::string::npos)
|
||||
return true;
|
||||
++pos2;
|
||||
auto pos = sub.rfind('.');
|
||||
if (pos == std::string::npos)
|
||||
pos = 0;
|
||||
else
|
||||
++pos;
|
||||
if (pos == pos2) {
|
||||
if (sub.compare(pos, sub.size() - pos, &shadow.first[pos2]) != 0) {
|
||||
FC_LOG("element reference update " << sub << " -> " << shadow.first);
|
||||
std::string newSub(sub);
|
||||
newSub.replace(pos, sub.size() - pos, &shadow.first[pos2]);
|
||||
updateSub(newSub);
|
||||
}
|
||||
}
|
||||
else if (sub != shadow.second) {
|
||||
FC_LOG("element reference update " << sub << " -> " << shadow.second);
|
||||
updateSub(shadow.second);
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
(void)feature;
|
||||
(void)obj;
|
||||
(void)reverse;
|
||||
(void)notify;
|
||||
shadow.second = sub;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::pair<DocumentObject*, std::string>
|
||||
@@ -297,6 +515,13 @@ PropertyLinkBase::tryReplaceLink(const PropertyContainer *owner, DocumentObject
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
} else if (newObj == obj) {
|
||||
// This means the new object is already sub-object of this parent
|
||||
// (consider a case of swapping the tool and base object of the Cut
|
||||
// feature). We'll swap the old and new object.
|
||||
return tryReplaceLink(owner, obj, parent, newObj, oldObj, subname);
|
||||
#endif
|
||||
}
|
||||
if(!subname || !subname[0])
|
||||
return res;
|
||||
@@ -323,6 +548,10 @@ PropertyLinkBase::tryReplaceLink(const PropertyContainer *owner, DocumentObject
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
}else if(sobj == newObj) {
|
||||
return tryReplaceLink(owner, obj, parent, newObj, oldObj, subname);
|
||||
#endif
|
||||
}else if(prev == parent)
|
||||
break;
|
||||
prev = sobj;
|
||||
@@ -910,18 +1139,19 @@ void PropertyLinkSub::setValue(App::DocumentObject * lValue,
|
||||
std::vector<std::string> &&subs, std::vector<ShadowSub> &&shadows)
|
||||
{
|
||||
auto parent = Base::freecad_dynamic_cast<App::DocumentObject>(getContainer());
|
||||
if(lValue) {
|
||||
if(!lValue->isAttachedToDocument())
|
||||
if (lValue) {
|
||||
if (!lValue->isAttachedToDocument())
|
||||
throw Base::ValueError("PropertyLinkSub: invalid document object");
|
||||
if(!testFlag(LinkAllowExternal) && parent && parent->getDocument()!=lValue->getDocument())
|
||||
if (!testFlag(LinkAllowExternal) && parent
|
||||
&& parent->getDocument() != lValue->getDocument())
|
||||
throw Base::ValueError("PropertyLinkSub does not support external object");
|
||||
}
|
||||
aboutToSetValue();
|
||||
#ifndef USE_OLD_DAG
|
||||
if(parent) {
|
||||
if (parent) {
|
||||
// before accessing internals make sure the object is not about to be destroyed
|
||||
// otherwise the backlink contains dangling pointers
|
||||
if (!parent->testStatus(ObjectStatus::Destroy) && _pcScope!=LinkScope::Hidden) {
|
||||
if (!parent->testStatus(ObjectStatus::Destroy) && _pcScope != LinkScope::Hidden) {
|
||||
if (_pcLinkSub)
|
||||
_pcLinkSub->_removeBackLink(parent);
|
||||
if (lValue)
|
||||
@@ -929,11 +1159,12 @@ void PropertyLinkSub::setValue(App::DocumentObject * lValue,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
_pcLinkSub=lValue;
|
||||
_cSubList=std::move(subs);
|
||||
if(shadows.size()==_cSubList.size())
|
||||
_pcLinkSub = lValue;
|
||||
_cSubList = std::move(subs);
|
||||
if (shadows.size() == _cSubList.size()) {
|
||||
_ShadowSubList = std::move(shadows);
|
||||
else
|
||||
onContainerRestored(); // re-register element references
|
||||
} else
|
||||
updateElementReference(nullptr);
|
||||
checkLabelReferences(_cSubList);
|
||||
hasSetValue();
|
||||
@@ -950,13 +1181,24 @@ const std::vector<std::string>& PropertyLinkSub::getSubValues() const
|
||||
}
|
||||
|
||||
static inline const std::string &getSubNameWithStyle(const std::string &subName,
|
||||
const PropertyLinkBase::ShadowSub &shadow, bool newStyle)
|
||||
const PropertyLinkBase::ShadowSub &shadow, bool newStyle, std::string &tmp)
|
||||
{
|
||||
if(!newStyle) {
|
||||
if(!shadow.second.empty())
|
||||
return shadow.second;
|
||||
}else if(!shadow.first.empty())
|
||||
}else if(!shadow.first.empty()) {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
if (Data::hasMissingElement(shadow.second.c_str())) {
|
||||
auto pos = shadow.first.rfind('.');
|
||||
if (pos != std::string::npos) {
|
||||
tmp = shadow.first.substr(0, pos+1);
|
||||
tmp += shadow.second;
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return shadow.first;
|
||||
}
|
||||
return subName;
|
||||
}
|
||||
|
||||
@@ -964,13 +1206,27 @@ std::vector<std::string> PropertyLinkSub::getSubValues(bool newStyle) const {
|
||||
assert(_cSubList.size() == _ShadowSubList.size());
|
||||
std::vector<std::string> ret;
|
||||
ret.reserve(_cSubList.size());
|
||||
std::string tmp;
|
||||
for(size_t i=0;i<_ShadowSubList.size();++i)
|
||||
ret.push_back(getSubNameWithStyle(_cSubList[i],_ShadowSubList[i],newStyle));
|
||||
ret.push_back(getSubNameWithStyle(_cSubList[i],_ShadowSubList[i],newStyle,tmp));
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> PropertyLinkSub::getSubValuesStartsWith(const char* starter, bool newStyle) const
|
||||
{
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
assert(_cSubList.size() == _ShadowSubList.size());
|
||||
std::vector<std::string> ret;
|
||||
std::string tmp;
|
||||
for(size_t i=0;i<_ShadowSubList.size();++i) {
|
||||
const auto &sub = getSubNameWithStyle(_cSubList[i],_ShadowSubList[i],newStyle,tmp);
|
||||
auto element = Data::findElementName(sub.c_str());
|
||||
if(element && boost::starts_with(element,starter))
|
||||
ret.emplace_back(element);
|
||||
}
|
||||
return ret;
|
||||
|
||||
#else
|
||||
(void)newStyle;
|
||||
|
||||
std::vector<std::string> temp;
|
||||
@@ -980,6 +1236,7 @@ std::vector<std::string> PropertyLinkSub::getSubValuesStartsWith(const char* sta
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
#endif
|
||||
}
|
||||
|
||||
App::DocumentObject * PropertyLinkSub::getValue(Base::Type t) const
|
||||
@@ -993,8 +1250,14 @@ PyObject *PropertyLinkSub::getPyObject()
|
||||
Py::List list(static_cast<int>(_cSubList.size()));
|
||||
if (_pcLinkSub) {
|
||||
tup[0] = Py::asObject(_pcLinkSub->getPyObject());
|
||||
int i = 0;
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
for (auto &sub : getSubValues(true))
|
||||
list[i++] = Py::String(sub);
|
||||
#else
|
||||
for(unsigned int i = 0;i<_cSubList.size(); i++)
|
||||
list[i] = Py::String(_cSubList[i]);
|
||||
#endif
|
||||
tup[1] = list;
|
||||
return Py::new_reference_to(tup);
|
||||
}
|
||||
@@ -1460,6 +1723,9 @@ Property *PropertyLinkSub::Copy() const
|
||||
PropertyLinkSub *p= new PropertyLinkSub();
|
||||
p->_pcLinkSub = _pcLinkSub;
|
||||
p->_cSubList = _cSubList;
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
p->_ShadowSubList = _ShadowSubList;
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -1468,7 +1734,12 @@ void PropertyLinkSub::Paste(const Property &from)
|
||||
if(!from.isDerivedFrom(PropertyLinkSub::getClassTypeId()))
|
||||
throw Base::TypeError("Incompatible property to paste to");
|
||||
auto &link = static_cast<const PropertyLinkSub&>(from);
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
setValue(link._pcLinkSub, link._cSubList,
|
||||
std::vector<ShadowSub>(link._ShadowSubList));
|
||||
#else
|
||||
setValue(link._pcLinkSub, link._cSubList);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PropertyLinkSub::getLinks(std::vector<App::DocumentObject *> &objs,
|
||||
@@ -1727,9 +1998,10 @@ void PropertyLinkSubList::setValues(std::vector<DocumentObject*>&& lValue,
|
||||
aboutToSetValue();
|
||||
_lValueList = std::move(lValue);
|
||||
_lSubList = std::move(lSubNames);
|
||||
if(ShadowSubList.size()==_lSubList.size())
|
||||
if(ShadowSubList.size()==_lSubList.size()) {
|
||||
_ShadowSubList = std::move(ShadowSubList);
|
||||
else
|
||||
onContainerRestored(); // re-register element references
|
||||
} else
|
||||
updateElementReference(nullptr);
|
||||
checkLabelReferences(_lSubList);
|
||||
hasSetValue();
|
||||
@@ -1914,14 +2186,26 @@ void PropertyLinkSubList::setSubListValues(const std::vector<PropertyLinkSubList
|
||||
{
|
||||
std::vector<DocumentObject*> links;
|
||||
std::vector<std::string> subs;
|
||||
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
for (std::vector<PropertyLinkSubList::SubSet>::const_iterator it = values.begin(); it != values.end(); ++it) {
|
||||
if (it->second.empty()) {
|
||||
links.push_back(it->first);
|
||||
subs.emplace_back();
|
||||
continue;
|
||||
}
|
||||
for (std::vector<std::string>::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt) {
|
||||
links.push_back(it->first);
|
||||
subs.push_back(*jt);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (const auto & value : values) {
|
||||
for (const auto& jt : value.second) {
|
||||
links.push_back(value.first);
|
||||
subs.push_back(jt);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
setValues(links, subs);
|
||||
}
|
||||
|
||||
@@ -2386,6 +2670,9 @@ Property *PropertyLinkSubList::Copy() const
|
||||
PropertyLinkSubList *p = new PropertyLinkSubList();
|
||||
p->_lValueList = _lValueList;
|
||||
p->_lSubList = _lSubList;
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
p->_ShadowSubList = _ShadowSubList;
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -2394,7 +2681,12 @@ void PropertyLinkSubList::Paste(const Property &from)
|
||||
if(!from.isDerivedFrom(PropertyLinkSubList::getClassTypeId()))
|
||||
throw Base::TypeError("Incompatible property to paste to");
|
||||
auto &link = static_cast<const PropertyLinkSubList&>(from);
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
setValues(link._lValueList, link._lSubList,
|
||||
std::vector<ShadowSub>(link._ShadowSubList));
|
||||
#else
|
||||
setValues(link._lValueList, link._lSubList);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int PropertyLinkSubList::getMemSize () const
|
||||
@@ -2409,8 +2701,9 @@ std::vector<std::string> PropertyLinkSubList::getSubValues(bool newStyle) const
|
||||
assert(_lSubList.size() == _ShadowSubList.size());
|
||||
std::vector<std::string> ret;
|
||||
ret.reserve(_ShadowSubList.size());
|
||||
std::string tmp;
|
||||
for(size_t i=0;i<_ShadowSubList.size();++i)
|
||||
ret.push_back(getSubNameWithStyle(_lSubList[i],_ShadowSubList[i],newStyle));
|
||||
ret.push_back(getSubNameWithStyle(_lSubList[i],_ShadowSubList[i],newStyle,tmp));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2965,9 +3258,12 @@ void PropertyXLink::setSubValues(std::vector<std::string> &&subs,
|
||||
{
|
||||
_SubList = std::move(subs);
|
||||
_ShadowSubList.clear();
|
||||
if(shadows.size() == _SubList.size())
|
||||
if(shadows.size() == _SubList.size()) {
|
||||
_ShadowSubList = std::move(shadows);
|
||||
else
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
onContainerRestored(); // re-register element references
|
||||
#endif
|
||||
} else
|
||||
updateElementReference(nullptr);
|
||||
checkLabelReferences(_SubList);
|
||||
}
|
||||
@@ -3468,8 +3764,12 @@ void PropertyXLink::copyTo(PropertyXLink &other,
|
||||
}
|
||||
if(subs)
|
||||
other._SubList = std::move(*subs);
|
||||
else
|
||||
else {
|
||||
other._SubList = _SubList;
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
other._ShadowSubList = _ShadowSubList;
|
||||
#endif
|
||||
}
|
||||
other._Flags = _Flags;
|
||||
}
|
||||
|
||||
@@ -3497,10 +3797,19 @@ void PropertyXLink::Paste(const Property &from)
|
||||
FC_WARN("Object '" << other.docName << '#' << other.objectName << "' not found");
|
||||
return;
|
||||
}
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
setValue(obj,std::vector<std::string>(other._SubList),
|
||||
std::vector<ShadowSub>(other._ShadowSubList));
|
||||
} else
|
||||
setValue(std::string(other.filePath),std::string(other.objectName),
|
||||
std::vector<std::string>(other._SubList),
|
||||
std::vector<ShadowSub>(other._ShadowSubList));
|
||||
#else
|
||||
setValue(obj,std::vector<std::string>(other._SubList));
|
||||
} else
|
||||
setValue(std::string(other.filePath),std::string(other.objectName),
|
||||
std::vector<std::string>(other._SubList));
|
||||
#endif
|
||||
setFlag(LinkAllowPartial,other.testFlag(LinkAllowPartial));
|
||||
}
|
||||
|
||||
@@ -3652,7 +3961,7 @@ void PropertyXLink::setPyObject(PyObject *value) {
|
||||
const char *PropertyXLink::getSubName(bool newStyle) const {
|
||||
if(_SubList.empty() || _ShadowSubList.empty())
|
||||
return "";
|
||||
return getSubNameWithStyle(_SubList[0],_ShadowSubList[0],newStyle).c_str();
|
||||
return getSubNameWithStyle(_SubList[0],_ShadowSubList[0],newStyle,tmpShadow).c_str();
|
||||
}
|
||||
|
||||
void PropertyXLink::getLinks(std::vector<App::DocumentObject *> &objs,
|
||||
@@ -3683,8 +3992,9 @@ std::vector<std::string> PropertyXLink::getSubValues(bool newStyle) const {
|
||||
assert(_SubList.size() == _ShadowSubList.size());
|
||||
std::vector<std::string> ret;
|
||||
ret.reserve(_SubList.size());
|
||||
std::string tmp;
|
||||
for(size_t i=0;i<_ShadowSubList.size();++i)
|
||||
ret.push_back(getSubNameWithStyle(_SubList[i],_ShadowSubList[i],newStyle));
|
||||
ret.push_back(getSubNameWithStyle(_SubList[i],_ShadowSubList[i],newStyle,tmp));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1169,6 +1169,7 @@ protected:
|
||||
std::vector<ShadowSub> _ShadowSubList;
|
||||
std::vector<int> _mapped;
|
||||
PropertyLinkBase *parentProp;
|
||||
mutable std::string tmpShadow;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user