diff --git a/src/App/Document.cpp b/src/App/Document.cpp index b960cc8a9019..83d67f69abbb 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -159,6 +159,7 @@ struct DocumentP int iTransactionMode; bool rollback; bool undoing; ///< document in the middle of undo or redo + std::vector pendingRecomputes; std::bitset<32> StatusBits; int iUndoMode; unsigned int UndoMemSize; @@ -1792,12 +1793,18 @@ Document::readObjects(Base::XMLReader& reader) return objs; } +void Document::addRecomputeObject(DocumentObject *obj) { + if(testStatus(Status::Importing) && obj) + d->pendingRecomputes.push_back(obj); +} + std::vector Document::importObjects(Base::XMLReader& reader) { d->hashers.clear(); Base::ObjectStatusLocker restoreBit(Status::Restoring, this); Base::ObjectStatusLocker restoreBit2(Status::Importing, this); + d->pendingRecomputes.clear(); reader.readElement("Document"); long scheme = reader.getAttributeAsInteger("SchemaVersion"); reader.DocumentSchema = scheme; @@ -1822,9 +1829,21 @@ Document::importObjects(Base::XMLReader& reader) } reader.readEndElement("Document"); - signalImportObjects(objs, reader); + signalImportObjects(objs, reader); afterRestore(objs); + + if(d->pendingRecomputes.size()) { + for(auto obj : d->pendingRecomputes) { + if(obj) { + FC_LOG("recompute '" << obj->getNameInDocument() << "' after restore"); + obj->touch(); + } + } + recompute(objs); + } + d->pendingRecomputes.clear(); + signalFinishImportObjects(objs); d->hashers.clear(); return objs; diff --git a/src/App/Document.h b/src/App/Document.h index c6fc60b4d03a..aa35158ffec9 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -476,7 +476,8 @@ class AppExport Document : public App::PropertyContainer return !links.empty(); } - void addRemapProperty(Property *prop); + /// Called by objects during restore to ask for recompute + void addRecomputeObject(DocumentObject *obj); /// Function called to signal that an object identifier has been renamed void renameObjectIdentifiers(const std::map & paths, const std::function &selector = [](const App::DocumentObject *) { return true; }); diff --git a/src/App/DocumentObject.cpp b/src/App/DocumentObject.cpp index be2bece1e030..e3d2c4288c84 100644 --- a/src/App/DocumentObject.cpp +++ b/src/App/DocumentObject.cpp @@ -856,3 +856,68 @@ bool DocumentObject::hasChildElement() const { } return false; } + +DocumentObject *DocumentObject::resolve(const char *subname, + App::DocumentObject **parent, std::string *childName, const char **subElement) const +{ + auto self = const_cast(this); + if(parent) *parent = 0; + if(subElement) *subElement = 0; + if(!subname || *subname==0) + return self; + + auto obj = getSubObject(subname); + if(!obj) + return self; + + if(!parent && !subElement) + return obj; + + // NOTE, the convension of '.' separated SubName demands a mandatory ending + // '.' for each object name in SubName, even if there is no subelement + // following it. So finding the last dot will give us the end of the last + // object name. + const char *dot = strrchr(subname,'.'); + if(!dot || dot == subname) { + if(subElement) + *subElement = dot?dot+1:subname; + return obj; // this means no parent object reference in SubName + } + + if(parent) + *parent = self; + + bool elementMapChecked = false; + const char *lastDot = dot; + for(--dot;;--dot) { + // check for the second last dot, which is the end of the last parent object + if(*dot == '.' || dot == subname) { + // We can't get parent object by its name, because the object may be + // externally linked (i.e. in a different document). So go through + // getSubObject again. + if(!elementMapChecked) { + elementMapChecked = true; + const char *sub = dot==subname?dot:dot+1; + if(Data::ComplexGeoData::isMappedElement(sub)) + lastDot = dot; + } + if(dot==subname) + break; + auto sobj = getSubObject(std::string(subname,dot-subname+1).c_str()); + if(parent) *parent = sobj; + if(sobj!=this) + break; + } + } + if(childName && lastDot!=dot) { + if(*dot == '.') + ++dot; + const char *nextDot = strchr(dot,'.'); + assert(nextDot); + *childName = std::string(dot,nextDot-dot); + } + if(subElement) + *subElement = *lastDot=='.'?lastDot+1:lastDot; + return obj; +} + diff --git a/src/App/DocumentObject.h b/src/App/DocumentObject.h index acdca5cf82dc..8e23ccf1ec9c 100644 --- a/src/App/DocumentObject.h +++ b/src/App/DocumentObject.h @@ -351,6 +351,20 @@ class AppExport DocumentObject: public App::TransactionalObject return _pcViewProviderName.c_str(); } + /** Resolve the last document object referenced in the subname + * + * @param subname: dot separated subname + * @param parent: return the direct parent of the object + * @param childName: return child name to be passed to is/setElementVisible() + * @param subElement: return non-object sub-element name if found. The + * pointer is guaranteed to be within the buffer pointed to by 'subname' + * + * @return Returns the last referenced document object in the subname. If no + * such object in subname, return pObject. + */ + App::DocumentObject *resolve(const char *subname, App::DocumentObject **parent=0, + std::string *childName=0, const char **subElement=0) const; + protected: /// recompute only this object virtual App::DocumentObjectExecReturn *recompute(void); diff --git a/src/App/DocumentObjectPy.xml b/src/App/DocumentObjectPy.xml index 9be5ea40d148..9f1546f39fcc 100644 --- a/src/App/DocumentObjectPy.xml +++ b/src/App/DocumentObjectPy.xml @@ -147,6 +147,32 @@ referencing subobject. Get all paths from this object to another object following the OutList. + + + +resolve(subname) -- resolve the sub object + +Returns a tuple (subobj,parent,elementName,subElement), where 'subobj' is the +last object referenced in 'subname', and 'parent' is the direct parent of +'subobj', and 'elementName' is the child name of the subobj, which can be used +to call parent.isElementVisible/setElementVisible(). 'subElement' is the +non-object sub-element name if any. + + + + + + +resolveSubElement(subname,append,type) -- resolve both new and old style sub element + +subname: subname reference contianing object hierarchy +append: Whether to append object hierarchy prefix inside subname to returned element name +type: 0: normal, 1: for import, 2: for export + +Return tuple(obj,newElementName,oldElementName) + + + A list of all objects this object links to. diff --git a/src/App/DocumentObjectPyImp.cpp b/src/App/DocumentObjectPyImp.cpp index 6f92eca88fe1..a052be450955 100644 --- a/src/App/DocumentObjectPyImp.cpp +++ b/src/App/DocumentObjectPyImp.cpp @@ -26,6 +26,7 @@ #include "DocumentObject.h" #include "Document.h" #include "Expression.h" +#include "GeoFeature.h" #include "GroupExtension.h" #include "GeoFeatureGroupExtension.h" @@ -690,3 +691,48 @@ int DocumentObjectPy::setCustomAttributes(const char* attr, PyObject *obj) Py::Int DocumentObjectPy::getID() const { return Py::Int(getDocumentObjectPtr()->getID()); } + +PyObject *DocumentObjectPy::resolve(PyObject *args) +{ + const char *subname; + if (!PyArg_ParseTuple(args, "s",&subname)) + return NULL; // NULL triggers exception + + PY_TRY { + std::string elementName; + const char *subElement = 0; + App::DocumentObject *parent = 0; + auto obj = getDocumentObjectPtr()->resolve(subname,&parent,&elementName,&subElement); + + Py::Tuple ret(4); + ret.setItem(0,Py::Object(obj->getPyObject(),true)); + ret.setItem(1,parent?Py::Object(parent->getPyObject(),true):Py::None()); + ret.setItem(2,Py::String(elementName.c_str())); + ret.setItem(3,Py::String(subElement?subElement:"")); + return Py::new_reference_to(ret); + } PY_CATCH; + + Py_Return; +} + +PyObject *DocumentObjectPy::resolveSubElement(PyObject *args) +{ + const char *subname; + PyObject *append = Py_False; + int type = 0; + if (!PyArg_ParseTuple(args, "s|Oi",&subname,&append,&type)) + return NULL; // NULL triggers exception + + PY_TRY { + std::pair elementName; + auto obj = GeoFeature::resolveElement(getDocumentObjectPtr(), subname,elementName, + PyObject_IsTrue(append),(GeoFeature::ElementNameType)type); + Py::Tuple ret(3); + ret.setItem(0,obj?Py::Object(obj->getPyObject(),true):Py::None()); + ret.setItem(1,Py::String(elementName.first)); + ret.setItem(2,Py::String(elementName.second)); + return Py::new_reference_to(ret); + } PY_CATCH; + + Py_Return; +} diff --git a/src/App/GeoFeature.cpp b/src/App/GeoFeature.cpp index bff633ca7c3a..3e8551494c64 100644 --- a/src/App/GeoFeature.cpp +++ b/src/App/GeoFeature.cpp @@ -26,10 +26,14 @@ #ifndef _PreComp_ #endif +#include +#include "Document.h" #include "GeoFeature.h" #include "GeoFeatureGroupExtension.h" #include +FC_LOG_LEVEL_INIT("GeoFeature",true,true); + using namespace App; @@ -79,3 +83,106 @@ PyObject* GeoFeature::getPyObject(void) } return Py::new_reference_to(PythonObject); } + + +std::pair GeoFeature::getElementName( + const char *name, ElementNameType type) const +{ + (void)type; + + std::pair ret; + if(!name) return ret; + + auto prop = getPropertyOfGeometry(); + if(!prop) return ret; + + auto geo = prop->getComplexData(); + if(!geo) return ret; + + if(Data::ComplexGeoData::isMappedElement(name)) { + const char *oldName = geo->getElementName(name); + const char *dot = strrchr(name,'.'); + if(oldName != name) { + if(!dot) { + ret.first = name; + ret.first += '.'; + }else + ret.first.assign(name,dot-name+1); + ret.first += oldName; + ret.second = oldName; + }else{ + if(FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) + FC_WARN("element mapped name not found " << name); + ret.first = name; + if(dot) + ret.second = dot+1; + } + return ret; + } + const char *newName = geo->getElementName(name,true); + if(newName != name) { + std::ostringstream ss; + ss << Data::ComplexGeoData::elementMapPrefix() << newName << '.' << name; + ret.first = ss.str(); + ret.second = name; + }else + ret.second = name; + return ret; +} + +DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subname, + std::pair &elementName, bool append, + ElementNameType type, const DocumentObject *filter) +{ + const char *element = 0; + if(!obj || !obj->getNameInDocument()) + return 0; + obj = obj->resolve(subname,0,0,&element); + if(!obj) + return 0; + obj = obj->getLinkedObject(true); + if(!obj || (filter && obj!=filter)) + return 0; + if(!element || !element[0]) + return obj; + + auto geo = dynamic_cast(obj); + if(!geo) + return obj; + if(!append) + elementName = geo->getElementName(element,type); + else{ + const auto &names = geo->getElementName(element,type); + if(names.first.size() && names.second.size()) { + std::string prefix(subname,element-subname); + elementName.first = prefix + names.first; + elementName.second = prefix + names.second; + } + } + return obj; +} + +void GeoFeature::updateElementReference() { + auto prop = getPropertyOfGeometry(); + if(!prop) return; + auto geo = prop->getComplexData(); + if(!geo || !geo->getElementMapSize()) return; + auto elementMap = geo->getElementMap(); + if(_elementMapCache != elementMap) { + _elementMapCache.swap(elementMap); + for(auto obj : getInListEx(true)) + PropertyLinkSub::updateElementReferences(this,obj); + } +} + +void GeoFeature::onChanged(const Property *prop) { + if(!isRestoring() && prop==getPropertyOfGeometry()) + updateElementReference(); + DocumentObject::onChanged(prop); +} + +void GeoFeature::onDocumentRestored() { + if(!getDocument()->testStatus(Document::Status::Importing)) + updateElementReference(); + DocumentObject::onDocumentRestored(); +} diff --git a/src/App/GeoFeature.h b/src/App/GeoFeature.h index 673b1516c37a..ab11c0fed32a 100644 --- a/src/App/GeoFeature.h +++ b/src/App/GeoFeature.h @@ -66,7 +66,56 @@ class AppExport GeoFeature : public App::DocumentObject * @return the Python binding object */ virtual PyObject* getPyObject(void); + + /// Specify the type of element name to return when calling getElementName() + enum ElementNameType { + /// Normal usage + Normal=0, + /// For importing + Import=1, + /// For exporting + Export=2, + }; + /** Return the new and old style sub-element name + * + * @param name: input name + * @param type: desired element name type to return + * + * @return a pair(newName,oldName). New element name may be empty. + * + * NOTE: Unlike ComplexGeoData::getElementName(), this function + * relies on ComplexGeoData::elementMapPrefix() to decide whether + * it is a forward query, i.e. mapped -> original, or reverse query. + * The reason being that, unlike ComplexGeoData who deals with the + * actual element map data, GeoFeature here sits at a higher level. + * GeoFeature should be dealing with whatever various PropertyLinkSub(s) + * is assigned. + * + * This function is made virtual, so that inherited class can do something + * unusual, such as Sketcher::SketcherObject, which uses this to expose its + * private geometries without a correpsonding TopoShape, and yet being + * source code compatible. + */ + virtual std::pair getElementName( + const char *name, ElementNameType type=Normal) const; + /** Resolve both the new and old style element name + * + * @param obj: top parent object + * @param subname: subname reference + * @param elementName: output of a pair(newElementName,oldElementName) + * @param append: Whether to include subname prefix into the returned + * element name + * @param type: the type of element name to request + * @param filter: If none zero, then only perform lookup when the element + * owner object is the same as this filter + * + * @return Return the owner object of the element + */ + static DocumentObject *resolveElement(App::DocumentObject *obj, + const char *subname, std::pair &elementName, + bool append=false, ElementNameType type=Normal,const DocumentObject *filter=0); + /** * @brief Calculates the placement in the global reference coordinate system * @@ -80,6 +129,14 @@ class AppExport GeoFeature : public App::DocumentObject * @return Base::Placement The transformation from the global reference coordinate system */ Base::Placement globalPlacement() const; + +protected: + virtual void onChanged(const Property* prop); + virtual void onDocumentRestored(); + void updateElementReference(); + +private: + std::map _elementMapCache; }; } //namespace App diff --git a/src/App/PropertyLinks.cpp b/src/App/PropertyLinks.cpp index 95abc4ecf8c7..2ed84e630c9d 100644 --- a/src/App/PropertyLinks.cpp +++ b/src/App/PropertyLinks.cpp @@ -40,11 +40,13 @@ #include #include #include +#include #include "Application.h" #include "DocumentObject.h" #include "DocumentObjectPy.h" #include "Document.h" +#include "GeoFeature.h" #include "PropertyLinks.h" @@ -498,6 +500,7 @@ void PropertyLinkSub::setValue(App::DocumentObject * lValue, const std::vector props; + obj->getPropertyList(props); + for(auto prop : props) { + auto linksub = dynamic_cast(prop); + if(linksub) { + linksub->updateElementReference(feature); + continue; + } + auto linksubs = dynamic_cast(prop); + if(linksubs) { + linksubs->updateElementReference(feature); + continue; + } + auto xlink = dynamic_cast(prop); + if(xlink) { + linksubs->updateElementReference(feature); + continue; + } + } +} + +bool PropertyLinkSub::updateElementReference(DocumentObject *feature, + App::DocumentObject *obj, std::string &sub, + std::pair &shadow) +{ + if(!obj || !obj->getNameInDocument()) return false; + std::pair elementName; + if(!GeoFeature::resolveElement(obj,shadow.first.size()?shadow.first.c_str():sub.c_str(), + elementName,true,GeoFeature::ElementNameType::Export,feature)) + return false; + if(elementName.first.empty()) + return false; + FC_TRACE("element reference cache " << shadow.first << " -> " << elementName.first); + shadow.swap(elementName); + auto pos2 = shadow.first.rfind('.'); + if(pos2 == std::string::npos) + return false; + ++pos2; + auto pos = sub.rfind('.'); + if(pos == std::string::npos) + pos = 0; + else + ++pos; + if(sub.compare(pos,sub.size()-pos,&shadow.first[pos2])!=0) { + FC_LOG("element reference update " << sub << " -> " << shadow.first); + sub.replace(pos,sub.size()-pos,&shadow.first[pos2]); + return true; + } + return false; +} + +void PropertyLinkSub::updateElementReference(DocumentObject *feature) { + if(!feature) _ShadowSubList.clear(); + _ShadowSubList.resize(_cSubList.size()); + if(!_pcLinkSub || !_pcLinkSub->getNameInDocument()) + return; + int i=0; + bool touched = false; + for(auto &sub : _cSubList) { + if(updateElementReference(feature,_pcLinkSub,sub,_ShadowSubList[i++])) + touched = true; + } + for(int idx : _mapped) { + if(idx<(int)_cSubList.size() && _ShadowSubList[idx].first.size()) { + _cSubList[idx] = _ShadowSubList[idx].first; + touched = true; + } + } + _mapped.clear(); + if(touched) + touch(); +} + static std::string importSubName(Base::XMLReader &reader, const char *sub) { std::ostringstream str; for(const char *dot=strchr(sub,'.');dot;sub=dot+1,dot=strchr(sub,'.')) @@ -598,9 +675,6 @@ static std::string importSubName(Base::XMLReader &reader, const char *sub) { static std::string exportSubName(const App::DocumentObject *obj, const char *sub) { - if(!obj || !obj->getNameInDocument() || !obj->getDocument()->isExporting()) - return std::string(sub); - std::ostringstream str; for(const char *dot=strchr(sub,'.');dot;sub=dot+1,dot=strchr(sub,'.')) { // name with trailing '.' @@ -653,8 +727,13 @@ static std::string tryImportSubName(const std::map &nam return std::string(); } +#define ATTR_SHADOW "shadowed" +#define ATTR_MAPPED "mapped" + void PropertyLinkSub::Save (Base::Writer &writer) const { + assert(_cSubList.size() == _ShadowSubList.size()); + std::string internal_name; // it can happen that the object is still alive but is not part of the document anymore and thus // returns 0 @@ -662,9 +741,28 @@ void PropertyLinkSub::Save (Base::Writer &writer) const internal_name = _pcLinkSub->getExportName(); writer.Stream() << writer.ind() << "" << std::endl; writer.incInd(); - for(unsigned int i = 0;i<_cSubList.size(); i++) - writer.Stream() << writer.ind() << "" << endl; + bool exporting = _pcLinkSub&&_pcLinkSub->getNameInDocument()&&_pcLinkSub->getDocument()->isExporting(); + for(unsigned int i = 0;i<_cSubList.size(); i++) { + const auto &shadow = _ShadowSubList[i]; + // shadow.second stores the old style element name. For backward + // compatibility reason, we shall store the old name into attribute + // 'value' whenver possible. + const auto &sub = shadow.second.empty()?_cSubList[i]:shadow.second; + writer.Stream() << writer.ind() << "" << endl; + } writer.decInd(); writer.Stream() << writer.ind() << "" << endl ; } @@ -679,19 +777,23 @@ void PropertyLinkSub::Restore(Base::XMLReader &reader) // Property not in a DocumentObject! assert(getContainer()->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId()) ); + App::Document* document = static_cast(getContainer())->getDocument(); + std::vector mapped; std::vector values(count); // Sub may store '.' separated object names, so be aware of the possible mapping when import for (int i = 0; i < count; i++) { reader.readElement("Sub"); - values[i] = importSubName(reader,reader.getAttribute("value")); + values[i] = importSubName(reader,reader.getAttribute( + reader.hasAttribute(ATTR_SHADOW)?ATTR_SHADOW:"value")); + if(reader.hasAttribute(ATTR_MAPPED)) + mapped.push_back(i); } reader.readEndElement("LinkSub"); DocumentObject *pcObject; if (!name.empty()) { - App::Document* document = static_cast(getContainer())->getDocument(); pcObject = document ? document->getObject(name.c_str()) : 0; if (!pcObject) { if (reader.isVerbose()) { @@ -700,6 +802,7 @@ void PropertyLinkSub::Restore(Base::XMLReader &reader) } } setValue(pcObject,values); + _mapped.swap(mapped); } else { setValue(0); @@ -782,6 +885,7 @@ void PropertyLinkSubList::setSize(int newSize) { _lValueList.resize(newSize); _lSubList .resize(newSize); + _ShadowSubList.resize(newSize); } int PropertyLinkSubList::getSize(void) const @@ -812,14 +916,14 @@ void PropertyLinkSubList::setValue(DocumentObject* lValue,const char* SubName) _lValueList[0]=lValue; _lSubList.resize(1); _lSubList[0]=SubName; - hasSetValue(); } else { aboutToSetValue(); _lValueList.clear(); _lSubList.clear(); - hasSetValue(); } + updateElementReference(0); + hasSetValue(); } void PropertyLinkSubList::setValues(const std::vector& lValue,const std::vector& lSubNames) @@ -853,6 +957,7 @@ void PropertyLinkSubList::setValues(const std::vector& lValue,c int i = 0; for (std::vector::const_iterator it = lSubNames.begin();it!=lSubNames.end();++it) _lSubList[i] = *it; + updateElementReference(0); hasSetValue(); } @@ -884,6 +989,7 @@ void PropertyLinkSubList::setValues(const std::vector& lValue,c aboutToSetValue(); _lValueList = lValue; _lSubList = lSubNames; + updateElementReference(0); hasSetValue(); } @@ -923,6 +1029,7 @@ void PropertyLinkSubList::setValue(DocumentObject* lValue, const std::vector_lSubList = SubList; this->_lValueList.insert(this->_lValueList.begin(), size, lValue); } + updateElementReference(0); hasSetValue(); } @@ -1143,15 +1250,63 @@ void PropertyLinkSubList::setPyObject(PyObject *value) } } +void PropertyLinkSubList::updateElementReference(DocumentObject *feature) { + if(!feature) _ShadowSubList.clear(); + _ShadowSubList.resize(_lSubList.size()); + int i=0; + bool touched = false; + for(auto &sub : _lSubList) { + auto obj = _lValueList[i]; + if(PropertyLinkSub::updateElementReference(feature,obj,sub,_ShadowSubList[i++])) + touched = true; + } + for(int idx : _mapped) { + if(idx<(int)_lSubList.size() && _ShadowSubList[idx].first.size()) { + _lSubList[idx] = _ShadowSubList[idx].first; + touched = true; + } + } + _mapped.clear(); + if(touched) + touch(); +} + void PropertyLinkSubList::Save (Base::Writer &writer) const { - writer.Stream() << writer.ind() << "" << endl; + assert(_lSubList.size() == _ShadowSubList.size()); + + int count = 0; + for(auto obj : _lValueList) { + if(obj && obj->getNameInDocument()) + ++count; + } + writer.Stream() << writer.ind() << "" << endl; writer.incInd(); for (int i = 0; i < getSize(); i++) { - writer.Stream() << writer.ind() << - "getExportName() << "\" " << - "sub=\"" << exportSubName(_lValueList[i],_lSubList[i].c_str()) << "\"/>" << endl; + auto obj = _lValueList[i]; + if(!obj || !obj->getNameInDocument()) + continue; + bool exporting = obj->getDocument()->isExporting(); + const auto &shadow = _ShadowSubList[i]; + // shadow.second stores the old style element name. For backward + // compatibility reason, we shall store the old name into attribute + // 'value' whenver possible. + const auto &sub = shadow.second.empty()?_lSubList[i]:shadow.second; + + writer.Stream() << writer.ind() << "getExportName() << "\" sub=\""; + if(exporting) { + writer.Stream() << exportSubName(obj,sub.c_str()); + if(shadow.second.size() && _lSubList[i]==shadow.first) + writer.Stream() << "\" " ATTR_MAPPED "=\"1"; + } else { + writer.Stream() << sub; + if(shadow.second.size()) { + // Stores the actual value that is shadowed. For new version FC, + // we will restore this shadowed value instead. + writer.Stream() << "\" " ATTR_SHADOW "=\"" << _lSubList[i]; + } + } + writer.Stream() << "\"/>" << endl; } writer.decInd(); @@ -1169,6 +1324,9 @@ void PropertyLinkSubList::Restore(Base::XMLReader &reader) values.reserve(count); std::vector SubNames; SubNames.reserve(count); + DocumentObject* father = dynamic_cast(getContainer()); + App::Document* document = father ? father->getDocument() : 0; + std::vector mapped; for (int i = 0; i < count; i++) { reader.readElement("Link"); std::string name = reader.getName(reader.getAttribute("obj")); @@ -1176,12 +1334,13 @@ void PropertyLinkSubList::Restore(Base::XMLReader &reader) // referenced objects in XML which do not exist anymore in the new // document. Thus, we should silently ignore this. // Property not in an object! - DocumentObject* father = dynamic_cast(getContainer()); - App::Document* document = father ? father->getDocument() : 0; DocumentObject* child = document ? document->getObject(name.c_str()) : 0; if (child) { values.push_back(child); - SubNames.push_back(importSubName(reader,reader.getAttribute("sub"))); + SubNames.push_back(importSubName(reader,reader.getAttribute( + reader.hasAttribute(ATTR_SHADOW)?ATTR_SHADOW:"sub"))); + if(reader.hasAttribute(ATTR_MAPPED)) + mapped.push_back(i); } else if (reader.isVerbose()) Base::Console().Warning("Lost link to '%s' while loading, maybe " "an object was not loaded correctly\n",name.c_str()); @@ -1191,6 +1350,7 @@ void PropertyLinkSubList::Restore(Base::XMLReader &reader) // assignment setValues(values,SubNames); + _mapped.swap(mapped); } Property *PropertyLinkSubList::CopyOnImportExternal( @@ -1617,6 +1777,7 @@ void PropertyXLink::detach() { if(docInfo) { aboutToSetValue(); resetLink(); + updateElementReference(0); hasSetValue(); } } @@ -1629,6 +1790,7 @@ void PropertyXLink::setSubName(const char *subname, bool transaction) { else subName.clear(); registerXLinkLabel(this); + updateElementReference(0); if(transaction) hasSetValue(); } @@ -1753,18 +1915,42 @@ bool PropertyXLink::isRestored() const { stamp==docInfo->pcDoc->LastModifiedDate.getValue(); } +void PropertyXLink::updateElementReference(DocumentObject *feature) { + if(!feature) { + shadowSub.first.clear(); + shadowSub.second.clear(); + } + bool touched = PropertyLinkSub::updateElementReference(feature,_pcLink,subName,shadowSub); + if(_mapped && shadowSub.first.size()) { + touched = true; + subName = shadowSub.first; + } + _mapped = false; + if(touched) + touch(); +} + void PropertyXLink::Save (Base::Writer &writer) const { auto owner = dynamic_cast(getContainer()); if(!owner || !owner->getDocument()) return; + + // shadowSub stores the old style element name. For backward + // compatibility reason, we shall store the old name into attribute + // 'value' whenver possible. + const auto &sub = shadowSub.second.empty()?subName:shadowSub.second; + auto exporting = owner->getDocument()->isExporting(); if(_pcLink && exporting==Document::Exporting) { // this means, we are exporting with all dependency included. So, store as // local object - writer.Stream() << writer.ind() << "getExportName() << "\" sub=\"" << - exportSubName(_pcLink,subName.c_str()) << - "\"/>" << std::endl; + + writer.Stream() << writer.ind() << "getExportName() << "\" sub=\"" + << exportSubName(_pcLink,sub.c_str()); + if(shadowSub.second.size() && shadowSub.first==subName) + writer.Stream() << "\"" ATTR_MAPPED "=\"1"; + writer.Stream() << "\"/>" << std::endl; return; } const char *path = filePath.c_str(); @@ -1790,8 +1976,14 @@ void PropertyXLink::Save (Base::Writer &writer) const { "pcDoc?docInfo->pcDoc->LastModifiedDate.getValue():"") << "\" name=\"" << objectName << - "\" sub=\"" << subName << - "\" relative=\"" << (relativePath?"true":"false") << "\"/>" << std::endl; + "\" sub=\"" << sub << + "\" relative=\"" << (relativePath?"true":"false"); + if(shadowSub.second.size()) { + // Stores the actual value that is shadowed. For new version FC, + // we will restore this shadowed value instead. + writer.Stream() << "\" " ATTR_SHADOW "=\"" << subName; + } + writer.Stream() << "\"/>" << std::endl; } void PropertyXLink::Restore(Base::XMLReader &reader) @@ -1811,13 +2003,18 @@ void PropertyXLink::Restore(Base::XMLReader &reader) name = reader.getName(reader.getAttribute("name")); else name = reader.getAttribute("name"); - std::string subname; - if(reader.getAttribute("sub")) - subname = importSubName(reader,reader.getAttribute("sub")); - // Property not in a DocumentObject! assert(getContainer()->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId())); + DocumentObject* parent = static_cast(getContainer()); + Document *document = parent->getDocument(); + + std::string subname; + if(reader.getAttribute("sub")) { + subname = importSubName(reader,reader.getAttribute( + reader.hasAttribute(ATTR_SHADOW)?ATTR_SHADOW:"sub")); + } + bool mapped = reader.hasAttribute(ATTR_MAPPED); if (name.empty()) { setValue(0); @@ -1827,11 +2024,10 @@ void PropertyXLink::Restore(Base::XMLReader &reader) if(file.size()) { this->stamp = stamp; setValue(file.c_str(),name.c_str(),subname.c_str(),relativePath); + _mapped = mapped; return; } - DocumentObject* parent = static_cast(getContainer()); - Document *document = parent->getDocument(); DocumentObject* object = document ? document->getObject(name.c_str()) : 0; if(!object) { if(reader.isVerbose()) { @@ -1840,6 +2036,7 @@ void PropertyXLink::Restore(Base::XMLReader &reader) } } setValue(object,subname.c_str(),relativePath); + _mapped = mapped; } Property *PropertyXLink::CopyOnImportExternal( diff --git a/src/App/PropertyLinks.h b/src/App/PropertyLinks.h index 34550f34e0bc..b6dbcbb8dd11 100644 --- a/src/App/PropertyLinks.h +++ b/src/App/PropertyLinks.h @@ -303,9 +303,17 @@ class AppExport PropertyLinkSub: public Property, public ScopedLink return sizeof(App::DocumentObject *); } + static void updateElementReferences(DocumentObject *feature, DocumentObject *obj); + static bool updateElementReference(DocumentObject *feature, + App::DocumentObject *obj, std::string &sub, std::pair &shadow); + + void updateElementReference(DocumentObject *feature); + protected: App::DocumentObject* _pcLinkSub; std::vector _cSubList; + std::vector > _ShadowSubList; + std::vector _mapped; }; /** The general Link Property with Child scope @@ -401,10 +409,14 @@ class AppExport PropertyLinkSubList: public PropertyLists, public ScopedLink virtual unsigned int getMemSize (void) const; + void updateElementReference(DocumentObject *feature); + private: //FIXME: Do not make two independent lists because this will lead to some inconsistencies! std::vector _lValueList; std::vector _lSubList; + std::vector > _ShadowSubList; + std::vector _mapped; }; /** The general Link Property with Child scope @@ -471,6 +483,8 @@ class AppExport PropertyXLink : public PropertyLinkGlobal static std::map > getDocumentOutList(App::Document *doc=0); static std::map > getDocumentInList(App::Document *doc=0); + void updateElementReference(DocumentObject *feature); + protected: void unlink(); void detach(); @@ -479,8 +493,10 @@ class AppExport PropertyXLink : public PropertyLinkGlobal std::string filePath; std::string objectName; std::string subName; + std::pair shadowSub; std::string stamp; bool relativePath; + bool _mapped; DocInfoPtr docInfo; }; diff --git a/src/Gui/CommandLink.cpp b/src/Gui/CommandLink.cpp index d5cca5b7cfed..9116c4154bbc 100644 --- a/src/Gui/CommandLink.cpp +++ b/src/Gui/CommandLink.cpp @@ -601,7 +601,7 @@ static std::map > getLinkImpor std::map > objMap; for(auto &sel : Selection().getCompleteSelection(false)) { App::DocumentObject *parent = 0; - auto obj = Selection().resolveObject(sel.pObject,sel.SubName,&parent); + auto obj = sel.pObject->resolve(sel.SubName,&parent); if(!parent || parent->getDocument()==obj->getDocument()) { if(!checking) FC_WARN("skip invalid parent of " << diff --git a/src/Gui/PropertyView.cpp b/src/Gui/PropertyView.cpp index 7e4be92cc2e0..b1d063e4ac32 100644 --- a/src/Gui/PropertyView.cpp +++ b/src/Gui/PropertyView.cpp @@ -250,7 +250,7 @@ void PropertyView::onSelectionChanged(const SelectionChanges& msg) for(auto &sel : array) { if(!sel.pObject) continue; App::DocumentObject *parent = 0; - App::DocumentObject *ob = Gui::Selection().resolveObject(sel.pObject,sel.SubName,&parent); + App::DocumentObject *ob = sel.pObject->resolve(sel.SubName,&parent); if(!ob) continue; if(parent) { auto parentVp = Application::Instance->getViewProvider(parent); diff --git a/src/Gui/Selection.cpp b/src/Gui/Selection.cpp index c542f0742a93..e2e06345df5b 100644 --- a/src/Gui/Selection.cpp +++ b/src/Gui/Selection.cpp @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include "MainWindow.h" #include "ViewProviderDocumentObject.h" @@ -332,12 +332,11 @@ std::vector SelectionSingleton::getSelection(const c std::map > objMap; - for(std::list<_SelObj>::const_iterator It = _SelList.begin();It != _SelList.end();++It) { - if(!It->pDoc) continue; + for(auto &sel : _SelList) { + if(!sel.pDoc) continue; const char *subelement = 0; - auto obj = getObjectOfType(It->pObject,It->SubName.c_str(), - App::DocumentObject::getClassTypeId(),resolve,&subelement); - if(!obj || (pcDoc && It->pObject->getDocument()!=pcDoc)) + auto obj = getObjectOfType(sel,App::DocumentObject::getClassTypeId(),resolve,&subelement); + if(!obj || (pcDoc && sel.pObject->getDocument()!=pcDoc)) continue; // In case we are resolving objects, make sure no duplicates @@ -351,13 +350,13 @@ std::vector SelectionSingleton::getSelection(const c tempSelObj.DocName = obj->getDocument()->getName(); tempSelObj.FeatName = obj->getNameInDocument(); - tempSelObj.SubName = subelement; + tempSelObj.SubName = subelement; tempSelObj.TypeName = obj->getTypeId().getName(); tempSelObj.pObject = obj; tempSelObj.pDoc = obj->getDocument(); - tempSelObj.x = It->x; - tempSelObj.y = It->y; - tempSelObj.z = It->z; + tempSelObj.x = sel.x; + tempSelObj.y = sel.y; + tempSelObj.z = sel.z; temp.push_back(tempSelObj); } @@ -373,11 +372,10 @@ bool SelectionSingleton::hasSelection(const char* doc, bool resolve) const if (!pcDoc) return false; } - for(std::list<_SelObj>::const_iterator It = _SelList.begin();It != _SelList.end();++It) { - if(!It->pDoc) continue; - auto obj = getObjectOfType(It->pObject, It->SubName.c_str(), - App::DocumentObject::getClassTypeId(),resolve); - if(obj && (!pcDoc || It->pObject->getDocument()==pcDoc)) { + for(auto &sel : _SelList) { + if(!sel.pDoc) continue; + auto obj = getObjectOfType(sel,App::DocumentObject::getClassTypeId(),resolve); + if(obj && (!pcDoc || sel.pObject->getDocument()==pcDoc)) { return true; } } @@ -425,7 +423,7 @@ std::vector SelectionSingleton::getPickedListEx(const char* pDo } std::vector SelectionSingleton::getObjectList(const char* pDocName, Base::Type typeId, - const std::list<_SelObj> &objList, int resolve, bool single) const + std::list<_SelObj> &objList, int resolve, bool single) const { std::vector temp; if(single) temp.reserve(1); @@ -442,10 +440,10 @@ std::vector SelectionSingleton::getObjectList(const char* pDocN return temp; } - for (const auto &sel : objList) { + for (auto &sel : objList) { if(!sel.pDoc) continue; const char *subelement = 0; - auto obj = getObjectOfType(sel.pObject,sel.SubName.c_str(),typeId,resolve,&subelement); + auto obj = getObjectOfType(sel,typeId,resolve,&subelement); if(!obj || (pcDoc && sel.pObject->getDocument()!=pcDoc)) continue; auto it = SortMap.find(obj); @@ -521,50 +519,33 @@ int SelectionSingleton::getAsPropertyLinkSubList(App::PropertyLinkSubList &prop) return objs.size(); } -App::DocumentObject *SelectionSingleton::getObjectOfType(App::DocumentObject *pObject, - const char *subname, Base::Type type, int resolve,const char **subelement) { - if(!pObject || !pObject->getNameInDocument()) +App::DocumentObject *SelectionSingleton::getObjectOfType(_SelObj &sel, + Base::Type typeId, int resolve, const char **subelement) +{ + auto obj = sel.pObject; + if(!obj || !obj->getNameInDocument()) return 0; - auto ret = pObject; - if(subelement) - *subelement = subname; + const char *subname = sel.SubName.c_str(); if(resolve) { - if(subname && *subname) { - const char *dot = strrchr(subname,'.'); - if(dot && dot!=subname && resolve>1) { - const char *prev = dot-1; - for(;prev!=subname;--prev) { - if(*prev == '.') { - ++prev; - break; - } - } - if(Data::ComplexGeoData::isMappedElement(prev)) { - if(prev!=subname) - dot = prev-1; - else - dot = 0; - } - } - if(subelement) { - if(!dot) - *subelement = subname; - else - *subelement = dot+1; - } - if(dot) { - ret = ret->getSubObject(subname); - if(!ret || !ret->getNameInDocument()) - return 0; - } + if(!sel.resolved) { + sel.resolved = true; + std::pair elementName; + sel.pResolvedObject = App::GeoFeature::resolveElement(obj,subname,elementName); + sel.newElementName = elementName.first; + sel.oldElementName = elementName.second; + if(sel.newElementName.empty()) + sel.newElementName = sel.oldElementName; } - auto linked = ret->getLinkedObject(true); - if(linked && linked->isDerivedFrom(type)) - return ret; + obj = sel.pResolvedObject; + if(resolve>1) + subname = sel.newElementName.c_str(); + else + subname = sel.oldElementName.c_str(); } - if(ret->isDerivedFrom(type)) - return ret; - return 0; + if(!obj || !obj->isDerivedFrom(typeId)) + return 0; + if(subelement) *subelement = subname; + return obj; } vector SelectionSingleton::getObjectsOfType(const Base::Type& typeId, const char* pDocName, int resolve) const @@ -579,9 +560,9 @@ vector SelectionSingleton::getObjectsOfType(const Base::Ty } std::set objs; - for (std::list<_SelObj>::const_iterator It = _SelList.begin();It != _SelList.end();++It) { - if(pcDoc && pcDoc!=It->pDoc) continue; - App::DocumentObject *pObject = getObjectOfType(It->pObject,It->SubName.c_str(),typeId,resolve); + for(auto &sel : _SelList) { + if(pcDoc && pcDoc!=sel.pDoc) continue; + App::DocumentObject *pObject = getObjectOfType(sel,typeId,resolve); if (pObject) { auto ret = objs.insert(pObject); if(ret.second) @@ -610,8 +591,8 @@ unsigned int SelectionSingleton::countObjectsOfType(const Base::Type& typeId, co return 0; } - for (std::list<_SelObj>::const_iterator It = _SelList.begin();It != _SelList.end();++It) { - if((!pcDoc||pcDoc==It->pDoc) && getObjectOfType(It->pObject,It->SubName.c_str(),typeId,resolve)) + for (auto &sel : _SelList) { + if((!pcDoc||pcDoc==sel.pDoc) && getObjectOfType(sel,typeId,resolve)) iNbr++; } @@ -639,23 +620,23 @@ void SelectionSingleton::slotSelectionChanged(const SelectionChanges& msg) { { App::Document* pDoc = getDocument(msg.pDocName); if(!pDoc) return; - const char *subname = 0; - App::DocumentObject* pObject = getObjectOfType(pDoc->getObject(msg.pObjectName), - msg.pSubName, App::DocumentObject::getClassTypeId(),2,&subname); + std::pair elementName; + auto &newElementName = elementName.first; + auto &oldElementName = elementName.second; + auto pObject = App::GeoFeature::resolveElement( + pDoc->getObject(msg.pObjectName),msg.pSubName,elementName); if (!pObject) return; std::string docName(pObject->getDocument()->getName()); std::string objName(pObject->getNameInDocument()); SelectionChanges msg2(msg); msg2.pDocName = docName.c_str(); msg2.pObjectName = objName.c_str(); - msg2.pSubName = subname; + msg2.pSubName = newElementName.size()?newElementName.c_str():oldElementName.c_str(); signalSelectionChanged3(msg2); - if(Data::ComplexGeoData::isMappedElement(subname)) { - const char *dot = strchr(subname,'.'); - if(dot) - msg2.pSubName = dot+1; - } + + msg2.pSubName = oldElementName.c_str(); signalSelectionChanged2(msg2); + }else { signalSelectionChanged3(msg); signalSelectionChanged2(msg); @@ -671,13 +652,20 @@ bool SelectionSingleton::setPreselect(const char* pDocName, const char* pObjectN App::Document* pDoc = getDocument(pDocName); if (!pDoc || !pObjectName) return false; - const char *SubName = pSubName; - App::DocumentObject* pObject = getObjectOfType(pDoc->getObject(pObjectName), - pSubName, App::DocumentObject::getClassTypeId(),gateResolve,&SubName); + std::pair elementName; + auto &newElementName = elementName.first; + auto &oldElementName = elementName.second; + auto pObject = App::GeoFeature::resolveElement( + pDoc->getObject(pObjectName),pSubName,elementName); if (!pObject) return false; - if (!ActiveGate->allow(pObject->getDocument(),pObject,SubName)) { + const char *subelement = pSubName; + if(gateResolve > 1) + subelement = newElementName.size()?newElementName.c_str():oldElementName.c_str(); + else if(gateResolve) + subelement = oldElementName.c_str(); + if (!ActiveGate->allow(pObject->getDocument(),pObject,subelement)) { QString msg; if (ActiveGate->notAllowedReason.length() > 0){ msg = QObject::tr(ActiveGate->notAllowedReason.c_str()); @@ -863,12 +851,21 @@ bool SelectionSingleton::addSelection(const char* pDocName, const char* pObjectN else temp.pObject = 0; + temp.DocName = pDocName; + temp.FeatName = pObjectName ? pObjectName : ""; + temp.SubName = pSubName ? pSubName : ""; + temp.x = x; + temp.y = y; + temp.z = z; + + if (temp.pObject) + temp.TypeName = temp.pObject->getTypeId().getName(); + // check for a Selection Gate if (ActiveGate) { - const char *SubName = pSubName; - auto pObject = getObjectOfType(temp.pObject, pSubName, - App::DocumentObject::getClassTypeId(),gateResolve,&SubName); - if (!ActiveGate->allow(pObject?pObject->getDocument():temp.pDoc,pObject,SubName)) { + const char *subelement = 0; + auto pObject = getObjectOfType(temp,App::DocumentObject::getClassTypeId(),gateResolve,&subelement); + if (!ActiveGate->allow(pObject?pObject->getDocument():temp.pDoc,pObject,subelement)) { if (getMainWindow()) { QString msg; if (ActiveGate->notAllowedReason.length() > 0) { @@ -886,16 +883,6 @@ bool SelectionSingleton::addSelection(const char* pDocName, const char* pObjectN } } - temp.DocName = pDocName; - temp.FeatName = pObjectName ? pObjectName : ""; - temp.SubName = pSubName ? pSubName : ""; - temp.x = x; - temp.y = y; - temp.z = z; - - if (temp.pObject) - temp.TypeName = temp.pObject->getTypeId().getName(); - _SelList.push_back(temp); SelectionChanges Chng; @@ -909,7 +896,6 @@ bool SelectionSingleton::addSelection(const char* pDocName, const char* pObjectN Chng.z = z; Chng.Type = SelectionChanges::AddSelection; - FC_LOG("Add Selection "<< (pDocName?pDocName:"(null)")<<'.'<< (pObjectName?pObjectName:"(null)")<<'.' << @@ -1104,68 +1090,6 @@ void SelectionSingleton::rmvSelection(const char* pDocName, const char* pObjectN } } -App::DocumentObject *SelectionSingleton::resolveObject( - App::DocumentObject *pObject, const char *subname, - App::DocumentObject **parent, std::string *elementName, - const char **subElement) -{ - if(parent) *parent = 0; - if(subElement) *subElement = 0; - if(!pObject || !subname || *subname==0) - return pObject; - - auto obj = pObject->getSubObject(subname); - if(!obj) - return pObject; - - if(!parent && !subElement) - return obj; - - // NOTE, the convension of '.' separated SubName demands a mandatory ending - // '.' for each object name in SubName, even if there is no subelement - // following it. So finding the last dot will give us the end of the last - // object name. - const char *dot = strrchr(subname,'.'); - if(!dot || dot == subname) { - if(subElement && dot) - *subElement = dot+1; - return obj; // this means no parent object reference in SubName - } - - if(parent) - *parent = pObject; - - bool elementMapChecked = false; - const char *lastDot = dot; - for(--dot;dot!=subname;--dot) { - // check for the second last dot, which is the end of the last parent object - if(*dot == '.') { - // We can't get parent object by its name, because the object may be - // externally linked (i.e. in a different document). So go through - // getSubObject again. - auto sobj = pObject->getSubObject(std::string(subname,dot-subname+1).c_str()); - if(parent) *parent = sobj; - if(sobj!=pObject) - break; - if(!elementMapChecked) { - elementMapChecked = true; - if(Data::ComplexGeoData::isMappedElement(dot+1)) - lastDot = dot; - } - } - } - if(elementName && lastDot!=dot) { - if(*dot == '.') - ++dot; - const char *nextDot = strchr(dot,'.'); - assert(nextDot); - *elementName = std::string(dot,nextDot-dot); - } - if(subElement) - *subElement = lastDot+1; - return obj; -} - void SelectionSingleton::setVisible(int visible) { std::set > filter; if(visible<0) @@ -1178,7 +1102,7 @@ void SelectionSingleton::setVisible(int visible) { // get parent object App::DocumentObject *parent = 0; std::string elementName; - auto obj = Selection().resolveObject(sel.pObject,sel.SubName.c_str(),&parent,&elementName); + auto obj = sel.pObject->resolve(sel.SubName.c_str(),&parent,&elementName); if(!obj || !obj->getNameInDocument() || (parent && !parent->getNameInDocument())) continue; // try call parent object's setElementVisibility @@ -1583,13 +1507,6 @@ PyMethodDef SelectionSingleton::Methods[] = { "Gui.Selection.addSelectionGate(Gate())"}, {"removeSelectionGate", (PyCFunction) SelectionSingleton::sRemoveSelectionGate, METH_VARARGS, "removeSelectionGate() -- remove the active selection gate\n"}, - {"resolveObject", (PyCFunction) SelectionSingleton::sResolveObject, 1, - "resolveObject(object, subname) -- resolve the sub object\n" - "Returns a tuple (subobj,parent,elementName,subElement), where 'subobj' is the last\n" - "object referenced in 'subname', and 'parent' is the direct parent of 'subobj', and\n" - "'elementName' is the child name of the subobj, which can be used to call\n" - "parent.isElementVisible/setElementVisible(). 'subElement' is the non-object\n" - "sub-element name if any."}, {"setVisible", (PyCFunction) SelectionSingleton::sSetVisible, 1, "setVisible(visible=None) -- set visibility of all selection items\n" "If 'visible' is None, then toggle visibility"}, @@ -2014,28 +1931,3 @@ PyObject *SelectionSingleton::sSetVisible(PyObject * /*self*/, PyObject *args, P Py_Return; } -PyObject *SelectionSingleton::sResolveObject(PyObject * /*self*/, PyObject *args, PyObject * /*kwd*/) -{ - PyObject *pyobj; - const char *subname; - if (!PyArg_ParseTuple(args, "O!s",&App::DocumentObjectPy::Type,&pyobj,&subname)) - return NULL; // NULL triggers exception - - PY_TRY { - std::string elementName; - const char *subElement = 0; - App::DocumentObject *parent = 0; - auto obj = Selection().resolveObject( - static_cast(pyobj)->getDocumentObjectPtr(), - subname,&parent,&elementName,&subElement); - - Py::Tuple ret(4); - ret.setItem(0,Py::Object(obj->getPyObject(),true)); - ret.setItem(1,parent?Py::Object(parent->getPyObject(),true):Py::None()); - ret.setItem(2,Py::String(elementName.c_str())); - ret.setItem(3,Py::String(subElement?subElement:"")); - return Py::new_reference_to(ret); - } PY_CATCH; - - Py_Return; -} diff --git a/src/Gui/Selection.h b/src/Gui/Selection.h index cf349d4d16dd..035b2a44c6e6 100644 --- a/src/Gui/Selection.h +++ b/src/Gui/Selection.h @@ -310,24 +310,6 @@ class GuiExport SelectionSingleton : public Base::Subject inline std::vector getObjectsOfType( const char* pDocName=0, int resolve=1) const; - /** Resolve the last document object referenced in the subname - * - * @param pObject: the top parent object - * @param subname: dot separated subname - * @param parent: return the direct parent of the object - * @param elementName: return element name to be passed to - * DocumentObject::is//setElementVisible() - * @param subElement: return non-object sub-element name if found. The - * pointer is guaranteed to be within the buffer pointed to by 'subname' - * - * @return Returns the last referenced document object in the subname. If no - * such object in subname, return pObject. - * @ - */ - static App::DocumentObject *resolveObject(App::DocumentObject *pObject, - const char *subname, App::DocumentObject **parent=0, - std::string *elementName=0, const char **subElement=0); - /** Set selection object visibility * * @param visible: 1: make visible, 0: make invisible, -1: toggle visibility @@ -420,7 +402,6 @@ class GuiExport SelectionSingleton : public Base::Subject _SelList; + mutable std::list<_SelObj> _SelList; - std::list<_SelObj> _PickedList; + mutable std::list<_SelObj> _PickedList; bool _needPickedList; - std::vector getObjectList(const char* pDocName,Base::Type typeId, const std::list<_SelObj> &objs, int resolve, bool single=false) const; + std::vector getObjectList(const char* pDocName,Base::Type typeId, std::list<_SelObj> &objs, int resolve, bool single=false) const; - static App::DocumentObject *getObjectOfType(App::DocumentObject *pObject, - const char *subname, Base::Type type, int resolve, const char **subelement=0); + static App::DocumentObject *getObjectOfType(_SelObj &sel, Base::Type type, + int resolve, const char **subelement=0); static SelectionSingleton* _pcSingleton;