From ac5730996d88997677dd65525f0c9d1776f73423 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Mon, 29 Jun 2015 20:22:38 +0300 Subject: [PATCH] PropertyLinkSubList: make it backwards-compatible with PropertyLinkSub To assist porting Sketch's Support property from linkSub to linkSubList. Includes file reading backwards compatibility. --- src/App/PropertyContainer.cpp | 13 ++- src/App/PropertyLinks.cpp | 174 +++++++++++++++++++++++++++------- src/App/PropertyLinks.h | 20 +++- 3 files changed, 172 insertions(+), 35 deletions(-) diff --git a/src/App/PropertyContainer.cpp b/src/App/PropertyContainer.cpp index 5dea4b36b..9a6c34141 100644 --- a/src/App/PropertyContainer.cpp +++ b/src/App/PropertyContainer.cpp @@ -233,9 +233,18 @@ void PropertyContainer::Restore(Base::XMLReader &reader) // subclass of PropertyContainer might change the type of a property but // not its name. In this case we would force to read-in a wrong property // type and the behaviour would be undefined. + // Exception: PropertyLinkSubList can read PropertyLinkSub try { - if (prop && strcmp(prop->getTypeId().getName(), TypeName) == 0) - prop->Restore(reader); + if(prop){ + if (strcmp(prop->getTypeId().getName(), TypeName) == 0){ + prop->Restore(reader); + } else if (prop->isDerivedFrom(App::PropertyLinkSubList::getClassTypeId())){ + App::PropertyLinkSub tmp;//getTypeId() is not static =( + if (0 == strcmp(tmp.getTypeId().getName(),TypeName)) { + static_cast(prop)->Restore_FromLinkSub(reader); + } + } + } } catch (const Base::XMLParseException&) { throw; // re-throw diff --git a/src/App/PropertyLinks.cpp b/src/App/PropertyLinks.cpp index b366faea7..88652a7c2 100644 --- a/src/App/PropertyLinks.cpp +++ b/src/App/PropertyLinks.cpp @@ -547,11 +547,18 @@ void PropertyLinkSubList::setValue(DocumentObject* lValue,const char* SubName) _lSubList.resize(1); _lSubList[0]=SubName; hasSetValue(); + } else { + aboutToSetValue(); + _lValueList.clear(); + _lSubList.clear(); + hasSetValue(); } } void PropertyLinkSubList::setValues(const std::vector& lValue,const std::vector& lSubNames) { + if (lValue.size() != lSubNames.size()) + throw Base::Exception("PropertyLinkSubList::setValues: size of subelements list != size of objects list"); aboutToSetValue(); _lValueList = lValue; _lSubList.resize(lSubNames.size()); @@ -563,12 +570,71 @@ void PropertyLinkSubList::setValues(const std::vector& lValue,c void PropertyLinkSubList::setValues(const std::vector& lValue,const std::vector& lSubNames) { + if (lValue.size() != lSubNames.size()) + throw Base::Exception("PropertyLinkSubList::setValues: size of subelements list != size of objects list"); aboutToSetValue(); _lValueList = lValue; _lSubList = lSubNames; hasSetValue(); } +void PropertyLinkSubList::setValue(DocumentObject* lValue, const std::vector &SubList) +{ + aboutToSetValue(); + int size = SubList.size(); + this->_lValueList.clear(); + if (size == 0) { + if (lValue) + this->_lValueList.push_back(lValue); + this->_lSubList.clear(); + } else { + this->_lSubList = SubList; + this->_lValueList.insert(this->_lValueList.begin(), size, lValue); + } + hasSetValue(); +} + +const string PropertyLinkSubList::getPyReprString() +{ + assert(this->_lValueList.size() == this->_lSubList.size()); + + if (this->_lValueList.size() == 0) + return std::string("None"); + + std::stringstream strm; + strm << "["; + for ( int i = 0 ; i < this->_lSubList.size() ; i++) { + if (i>0) + strm << ",("; + else + strm << "("; + App::DocumentObject* obj = this->_lValueList[i]; + if (obj) { + strm << "App.getDocument('" << obj->getDocument()->getName() << "')." << obj->getNameInDocument(); + } else { + strm << "None"; + } + strm << ","; + strm << "'" << this->_lSubList[i] << "'"; + strm << ")"; + } + strm << "]"; + return strm.str(); +} + +DocumentObject *PropertyLinkSubList::getValue() const +{ + App::DocumentObject* ret = 0; + //FIXME: cache this to avoid iterating each time, to improve speed + for (int i = 0 ; i < this->_lValueList.size() ; i++){ + if (ret == 0) + ret = this->_lValueList[i]; + if (ret != this->_lValueList[i]) + return 0; + } + return ret; +} + PyObject *PropertyLinkSubList::getPyObject(void) { unsigned int count = getSize(); @@ -591,44 +657,50 @@ PyObject *PropertyLinkSubList::getPyObject(void) void PropertyLinkSubList::setPyObject(PyObject *value) { - if (PyTuple_Check(value) || PyList_Check(value)) { - Py::Sequence list(value); - Py::Sequence::size_type size = list.size(); + try { //try PropertyLinkSub syntax + PropertyLinkSub dummy; + dummy.setPyObject(value); + this->setValue(dummy.getValue(), dummy.getSubValues()); + } catch (Base::TypeError) { - std::vector values; - values.reserve(size); - std::vector SubNames; - SubNames.reserve(size); + if (PyTuple_Check(value) || PyList_Check(value)) { + Py::Sequence list(value); + Py::Sequence::size_type size = list.size(); - for (Py::Sequence::size_type i=0; i(tup[0].ptr()); - values.push_back(pcObj->getDocumentObjectPtr()); - if (Py::Object(tup[1].ptr()).isString()){ - SubNames.push_back(Py::String(tup[1].ptr())); + std::vector values; + values.reserve(size); + std::vector SubNames; + SubNames.reserve(size); + for (Py::Sequence::size_type i=0; i(tup[0].ptr()); + values.push_back(pcObj->getDocumentObjectPtr()); + if (Py::Object(tup[1].ptr()).isString()){ + SubNames.push_back(Py::String(tup[1].ptr())); + } } } + else if (PyObject_TypeCheck(*item, &(DocumentObjectPy::Type))) { + DocumentObjectPy *pcObj; + pcObj = static_cast(*item); + values.push_back(pcObj->getDocumentObjectPtr()); + } + else if (item.isString()) { + SubNames.push_back(Py::String(item)); + } } - else if (PyObject_TypeCheck(*item, &(DocumentObjectPy::Type))) { - DocumentObjectPy *pcObj; - pcObj = static_cast(*item); - values.push_back(pcObj->getDocumentObjectPtr()); - } - else if (item.isString()) { - SubNames.push_back(Py::String(item)); - } - } - setValues(values,SubNames); - } - else { - std::string error = std::string("type must be 'DocumentObject' or list of 'DocumentObject', not "); - error += value->ob_type->tp_name; - throw Base::TypeError(error); + setValues(values,SubNames); + } + else { + std::string error = std::string("type must be 'DocumentObject' or list of 'DocumentObject', not "); + error += value->ob_type->tp_name; + throw Base::TypeError(error); + } } } @@ -683,6 +755,44 @@ void PropertyLinkSubList::Restore(Base::XMLReader &reader) setValues(values,SubNames); } +void PropertyLinkSubList::Restore_FromLinkSub(XMLReader &reader) +{ + //Copy-paste from PropertyLinkSub::Restore() + // read my element + reader.readElement("LinkSub"); + // get the values of my attributes + std::string name = reader.getAttribute("value"); + int count = reader.getAttributeAsInteger("count"); + + // Property not in a DocumentObject! + assert(getContainer()->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId()) ); + + std::vector values(count); + for (int i = 0; i < count; i++) { + reader.readElement("Sub"); + values[i] = reader.getAttribute("value"); + } + + reader.readEndElement("LinkSub"); + + DocumentObject *pcObject; + if (name != ""){ + App::Document* document = static_cast(getContainer())->getDocument(); + pcObject = document ? document->getObject(name.c_str()) : 0; + if (!pcObject) { + if (reader.isVerbose()) { + Base::Console().Warning("Lost link to '%s' while loading, maybe " + "an object was not loaded correctly\n",name.c_str()); + } + } + setValue(pcObject,values); + } + else { + setValue(0); + } + +} + Property *PropertyLinkSubList::Copy(void) const { PropertyLinkSubList *p = new PropertyLinkSubList(); diff --git a/src/App/PropertyLinks.h b/src/App/PropertyLinks.h index 98d3adccd..87d3c1217 100644 --- a/src/App/PropertyLinks.h +++ b/src/App/PropertyLinks.h @@ -247,12 +247,19 @@ public: virtual void setSize(int newSize); virtual int getSize(void) const; - /** Sets the property + /** Sets the property. + * setValue(0, whatever) clears the property */ void setValue(DocumentObject*,const char*); void setValues(const std::vector&,const std::vector&); void setValues(const std::vector&,const std::vector&); + /** + * @brief setValue: PropertyLinkSub-compatible overload + * @param SubList + */ + void setValue(App::DocumentObject *lValue, const std::vector &SubList=std::vector()); + // index operator SubSet operator[] (const int idx) const { return SubSet(_lValueList.operator[] (idx),_lSubList.operator [](idx)); @@ -262,6 +269,16 @@ public: return _lValueList; } + const std::string getPyReprString(); + + /** + * @brief getValue emulates the action of a single-object link. + * @return reference to object, if the link os to only one object. NULL if + * the link is empty, or links to subelements of more than one documant + * object. + */ + DocumentObject* getValue() const; + const std::vector &getSubValues(void) const { return _lSubList; } @@ -271,6 +288,7 @@ public: virtual void Save (Base::Writer &writer) const; virtual void Restore(Base::XMLReader &reader); + virtual void Restore_FromLinkSub(Base::XMLReader &reader); virtual Property *Copy(void) const; virtual void Paste(const Property &from);