PropertyLinkSubList: make it backwards-compatible with PropertyLinkSub

To assist porting Sketch's Support property from linkSub to linkSubList.
Includes file reading backwards compatibility.
This commit is contained in:
DeepSOIC 2015-06-29 20:22:38 +03:00 committed by Stefan Tröger
parent eccff10d90
commit ac5730996d
3 changed files with 172 additions and 35 deletions

View File

@ -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<App::PropertyLinkSubList*>(prop)->Restore_FromLinkSub(reader);
}
}
}
}
catch (const Base::XMLParseException&) {
throw; // re-throw

View File

@ -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<DocumentObject*>& lValue,const std::vector<const char*>& 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<DocumentObject*>& lValue,c
void PropertyLinkSubList::setValues(const std::vector<DocumentObject*>& lValue,const std::vector<std::string>& 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<string> &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<DocumentObject*> values;
values.reserve(size);
std::vector<std::string> 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<size; i++) {
Py::Object item = list[i];
if (item.isTuple()) {
Py::Tuple tup(item);
if (PyObject_TypeCheck(tup[0].ptr(), &(DocumentObjectPy::Type))){
DocumentObjectPy *pcObj;
pcObj = static_cast<DocumentObjectPy*>(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<DocumentObject*> values;
values.reserve(size);
std::vector<std::string> SubNames;
SubNames.reserve(size);
for (Py::Sequence::size_type i=0; i<size; i++) {
Py::Object item = list[i];
if (item.isTuple()) {
Py::Tuple tup(item);
if (PyObject_TypeCheck(tup[0].ptr(), &(DocumentObjectPy::Type))){
DocumentObjectPy *pcObj;
pcObj = static_cast<DocumentObjectPy*>(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<DocumentObjectPy*>(*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<DocumentObjectPy*>(*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<std::string> 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<DocumentObject*>(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();

View File

@ -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<DocumentObject*>&,const std::vector<const char*>&);
void setValues(const std::vector<DocumentObject*>&,const std::vector<std::string>&);
/**
* @brief setValue: PropertyLinkSub-compatible overload
* @param SubList
*/
void setValue(App::DocumentObject *lValue, const std::vector<std::string> &SubList=std::vector<std::string>());
// 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<std::string> &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);