From f5b48a636d471235f2eade2a43c04aaaaefc30a4 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 5 May 2016 17:12:17 +0200 Subject: [PATCH] + fixes #0002518: Propertylink enhancement. --- src/App/FeatureTest.cpp | 7 +- src/App/FeatureTest.h | 7 +- src/App/PropertyLinks.cpp | 425 +++++++++++++++++++++++--------------- src/App/PropertyLinks.h | 124 ++++++----- src/Gui/Selection.h | 2 +- 5 files changed, 320 insertions(+), 245 deletions(-) diff --git a/src/App/FeatureTest.cpp b/src/App/FeatureTest.cpp index 4d4017e267..e735e821d5 100644 --- a/src/App/FeatureTest.cpp +++ b/src/App/FeatureTest.cpp @@ -75,9 +75,10 @@ FeatureTest::FeatureTest() ADD_PROPERTY(IntegerList,(4711) ); ADD_PROPERTY(FloatList ,(47.11f) ); - ADD_PROPERTY(Link ,(0)); - ADD_PROPERTY(LinkSub, (0)); - ADD_PROPERTY(LinkList ,(0)); + ADD_PROPERTY(Link ,(0)); + ADD_PROPERTY(LinkSub ,(0)); + ADD_PROPERTY(LinkList ,(0)); + ADD_PROPERTY(LinkSubList,(0)); ADD_PROPERTY(Vector ,(1.0,2.0,3.0)); ADD_PROPERTY(VectorList,(3.0,2.0,1.0)); diff --git a/src/App/FeatureTest.h b/src/App/FeatureTest.h index c48173aa63..ba58f2436a 100644 --- a/src/App/FeatureTest.h +++ b/src/App/FeatureTest.h @@ -70,9 +70,10 @@ public: App::PropertyFloatList FloatList; // Standard Properties (PropertyLinks.h) - App::PropertyLink Link; - App::PropertyLinkSub LinkSub; - App::PropertyLinkList LinkList; + App::PropertyLink Link; + App::PropertyLinkSub LinkSub; + App::PropertyLinkList LinkList; + App::PropertyLinkSubList LinkSubList; // Standard Properties (PropertyGeo.h) App::PropertyMatrix Matrix; diff --git a/src/App/PropertyLinks.cpp b/src/App/PropertyLinks.cpp index 2487f59d26..4277e1177c 100644 --- a/src/App/PropertyLinks.cpp +++ b/src/App/PropertyLinks.cpp @@ -167,6 +167,162 @@ void PropertyLink::Paste(const Property &from) hasSetValue(); } +//************************************************************************** +// PropertyLinkList +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TYPESYSTEM_SOURCE(App::PropertyLinkList, App::PropertyLists); + +//************************************************************************** +// Construction/Destruction + + +PropertyLinkList::PropertyLinkList() +{ + +} + +PropertyLinkList::~PropertyLinkList() +{ + +} + +void PropertyLinkList::setSize(int newSize) +{ + _lValueList.resize(newSize); +} + +int PropertyLinkList::getSize(void) const +{ + return static_cast(_lValueList.size()); +} + +void PropertyLinkList::setValue(DocumentObject* lValue) +{ + if (lValue){ + aboutToSetValue(); + _lValueList.resize(1); + _lValueList[0] = lValue; + hasSetValue(); + } +} + +void PropertyLinkList::setValues(const std::vector& lValue) +{ + aboutToSetValue(); + _lValueList = lValue; + hasSetValue(); +} + +PyObject *PropertyLinkList::getPyObject(void) +{ + int count = getSize(); +#if 0//FIXME: Should switch to tuple + Py::Tuple sequence(count); +#else + Py::List sequence(count); +#endif + for (int i = 0; igetPyObject())); + } + + return Py::new_reference_to(sequence); +} + +void PropertyLinkList::setPyObject(PyObject *value) +{ + if (PyTuple_Check(value) || PyList_Check(value)) { + Py::Sequence list(value); + Py::Sequence::size_type size = list.size(); + std::vector values; + values.resize(size); + + for (Py::Sequence::size_type i = 0; i < size; i++) { + Py::Object item = list[i]; + if (!PyObject_TypeCheck(*item, &(DocumentObjectPy::Type))) { + std::string error = std::string("type in list must be 'DocumentObject', not "); + error += (*item)->ob_type->tp_name; + throw Base::TypeError(error); + } + + values[i] = static_cast(*item)->getDocumentObjectPtr(); + } + + setValues(values); + } + else if (PyObject_TypeCheck(value, &(DocumentObjectPy::Type))) { + DocumentObjectPy *pcObject = static_cast(value); + setValue(pcObject->getDocumentObjectPtr()); + } + 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); + } +} + +void PropertyLinkList::Save(Base::Writer &writer) const +{ + writer.Stream() << writer.ind() << "" << endl; + writer.incInd(); + for (int i = 0; igetNameInDocument() << "\"/>" << endl;; + writer.decInd(); + writer.Stream() << writer.ind() << "" << endl; +} + +void PropertyLinkList::Restore(Base::XMLReader &reader) +{ + // read my element + reader.readElement("LinkList"); + // get the value of my attribute + int count = reader.getAttributeAsInteger("count"); + assert(getContainer()->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId())); + + std::vector values; + values.reserve(count); + for (int i = 0; i < count; i++) { + reader.readElement("Link"); + std::string name = reader.getAttribute("value"); + // In order to do copy/paste it must be allowed to have defined some + // referenced objects in XML which do not exist anymore in the new + // document. Thus, we should silently ingore this. + // Property not in an object! + DocumentObject* father = static_cast(getContainer()); + App::Document* document = father->getDocument(); + DocumentObject* child = document ? document->getObject(name.c_str()) : 0; + if (child) + values.push_back(child); + else if (reader.isVerbose()) + Base::Console().Warning("Lost link to '%s' while loading, maybe " + "an object was not loaded correctly\n", name.c_str()); + } + + reader.readEndElement("LinkList"); + + // assignment + setValues(values); +} + +Property *PropertyLinkList::Copy(void) const +{ + PropertyLinkList *p = new PropertyLinkList(); + p->_lValueList = _lValueList; + return p; +} + +void PropertyLinkList::Paste(const Property &from) +{ + aboutToSetValue(); + _lValueList = dynamic_cast(from)._lValueList; + hasSetValue(); +} + +unsigned int PropertyLinkList::getMemSize(void) const +{ + return static_cast(_lValueList.size() * sizeof(App::DocumentObject *)); +} + //************************************************************************** // PropertyLinkSub //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -297,7 +453,7 @@ void PropertyLinkSub::Save (Base::Writer &writer) const writer.Stream() << writer.ind() << "" << std::endl; writer.incInd(); for(unsigned int i = 0;i<_cSubList.size(); i++) - writer.Stream() << writer.ind() << "" << endl; ; + writer.Stream() << writer.ind() << "" << endl; writer.decInd(); writer.Stream() << writer.ind() << "" << endl ; } @@ -322,7 +478,7 @@ void PropertyLinkSub::Restore(Base::XMLReader &reader) reader.readEndElement("LinkSub"); DocumentObject *pcObject; - if (name != ""){ + if (!name.empty()) { App::Document* document = static_cast(getContainer())->getDocument(); pcObject = document ? document->getObject(name.c_str()) : 0; if (!pcObject) { @@ -354,161 +510,6 @@ void PropertyLinkSub::Paste(const Property &from) hasSetValue(); } -//************************************************************************** -// PropertyLinkList -//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -TYPESYSTEM_SOURCE(App::PropertyLinkList , App::PropertyLists); - -//************************************************************************** -// Construction/Destruction - - -PropertyLinkList::PropertyLinkList() -{ - -} - -PropertyLinkList::~PropertyLinkList() -{ - -} - -void PropertyLinkList::setSize(int newSize) -{ - _lValueList.resize(newSize); -} - -int PropertyLinkList::getSize(void) const -{ - return static_cast(_lValueList.size()); -} - -void PropertyLinkList::setValue(DocumentObject* lValue) -{ - if (lValue){ - aboutToSetValue(); - _lValueList.resize(1); - _lValueList[0]=lValue; - hasSetValue(); - } -} - -void PropertyLinkList::setValues(const std::vector& lValue) -{ - aboutToSetValue(); - _lValueList=lValue; - hasSetValue(); -} - -PyObject *PropertyLinkList::getPyObject(void) -{ - int count = getSize(); -#if 0//FIXME: Should switch to tuple - Py::Tuple sequence(count); -#else - Py::List sequence(count); -#endif - for (int i = 0;igetPyObject())); - } - - return Py::new_reference_to(sequence); -} - -void PropertyLinkList::setPyObject(PyObject *value) -{ - if (PyTuple_Check(value) || PyList_Check(value)) { - Py::Sequence list(value); - Py::Sequence::size_type size = list.size(); - std::vector values; - values.resize(size); - - for (Py::Sequence::size_type i=0; i < size; i++) { - Py::Object item = list[i]; - if (!PyObject_TypeCheck(*item, &(DocumentObjectPy::Type))) { - std::string error = std::string("type in list must be 'DocumentObject', not "); - error += (*item)->ob_type->tp_name; - throw Base::TypeError(error); - } - - values[i] = static_cast(*item)->getDocumentObjectPtr(); - } - - setValues(values); - } - else if(PyObject_TypeCheck(value, &(DocumentObjectPy::Type))) { - DocumentObjectPy *pcObject = static_cast(value); - setValue(pcObject->getDocumentObjectPtr()); - } - 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); - } -} - -void PropertyLinkList::Save (Base::Writer &writer) const -{ - writer.Stream() << writer.ind() << "" << endl; - writer.incInd(); - for(int i = 0;igetNameInDocument() <<"\"/>" << endl; ; - writer.decInd(); - writer.Stream() << writer.ind() << "" << endl ; -} - -void PropertyLinkList::Restore(Base::XMLReader &reader) -{ - // read my element - reader.readElement("LinkList"); - // get the value of my attribute - int count = reader.getAttributeAsInteger("count"); - assert(getContainer()->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId()) ); - - std::vector values; - values.reserve(count); - for (int i = 0; i < count; i++) { - reader.readElement("Link"); - std::string name = reader.getAttribute("value"); - // In order to do copy/paste it must be allowed to have defined some - // referenced objects in XML which do not exist anymore in the new - // document. Thus, we should silently ingore this. - // Property not in an object! - DocumentObject* father = static_cast(getContainer()); - App::Document* document = father->getDocument(); - DocumentObject* child = document ? document->getObject(name.c_str()) : 0; - if (child) - values.push_back(child); - else if (reader.isVerbose()) - Base::Console().Warning("Lost link to '%s' while loading, maybe " - "an object was not loaded correctly\n",name.c_str()); - } - - reader.readEndElement("LinkList"); - - // assignment - setValues(values); -} - -Property *PropertyLinkList::Copy(void) const -{ - PropertyLinkList *p = new PropertyLinkList(); - p->_lValueList = _lValueList; - return p; -} - -void PropertyLinkList::Paste(const Property &from) -{ - aboutToSetValue(); - _lValueList = dynamic_cast(from)._lValueList; - hasSetValue(); -} - -unsigned int PropertyLinkList::getMemSize (void) const -{ - return static_cast(_lValueList.size() * sizeof(App::DocumentObject *)); -} //************************************************************************** // PropertyLinkSubList //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -542,14 +543,15 @@ int PropertyLinkSubList::getSize(void) const void PropertyLinkSubList::setValue(DocumentObject* lValue,const char* SubName) { - if (lValue){ + if (lValue) { aboutToSetValue(); _lValueList.resize(1); _lValueList[0]=lValue; _lSubList.resize(1); _lSubList[0]=SubName; hasSetValue(); - } else { + } + else { aboutToSetValue(); _lValueList.clear(); _lSubList.clear(); @@ -589,7 +591,8 @@ void PropertyLinkSubList::setValue(DocumentObject* lValue, const std::vector_lValueList.push_back(lValue); this->_lSubList.clear(); - } else { + } + else { this->_lSubList = SubList; this->_lValueList.insert(this->_lValueList.begin(), size, lValue); } @@ -637,15 +640,81 @@ DocumentObject *PropertyLinkSubList::getValue() const return ret; } +void PropertyLinkSubList::setSubListValues(const std::vector& values) +{ + std::vector links; + std::vector subs; + + for (std::vector::const_iterator it = values.begin(); it != values.end(); ++it) { + for (std::vector::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt) { + links.push_back(it->first); + subs.push_back(*jt); + } + } + + setValues(links, subs); +} + +std::vector PropertyLinkSubList::getSubListValues() const +{ + std::vector values; + if (_lValueList.size() != _lSubList.size()) + throw Base::Exception("PropertyLinkSubList::getSubListValues: size of subelements list != size of objects list"); + + std::map > tmp; + for (std::size_t i = 0; i < _lValueList.size(); i++) { + App::DocumentObject* link = _lValueList[i]; + std::string sub = _lSubList[i]; + if (tmp.find(link) == tmp.end()) { + // make sure to keep the same order as in '_lValueList' + PropertyLinkSubList::SubSet item; + item.first = link; + values.push_back(item); + } + + tmp[link].push_back(sub); + } + + for (std::vector::iterator it = values.begin(); it != values.end(); ++it) { + it->second = tmp[it->first]; + } + + return values; +} + PyObject *PropertyLinkSubList::getPyObject(void) { +#if 1 + std::vector subLists = getSubListValues(); + std::size_t count = subLists.size(); +#if 0//FIXME: Should switch to tuple + Py::Tuple sequence(count); +#else + Py::List sequence(count); +#endif + for (std::size_t i = 0; igetPyObject()); + + const std::vector& sub = subLists[i].second; + Py::Tuple items(sub.size()); + for (std::size_t j = 0; j < sub.size(); j++) { + items[j] = Py::String(sub[j]); + } + + tup[1] = items; + sequence[i] = tup; + } + + return Py::new_reference_to(sequence); +#else unsigned int count = getSize(); #if 0//FIXME: Should switch to tuple Py::Tuple sequence(count); #else Py::List sequence(count); #endif - for(unsigned int i = 0;igetPyObject()); std::string subItem; @@ -655,6 +724,7 @@ PyObject *PropertyLinkSubList::getPyObject(void) sequence[i] = tup; } return Py::new_reference_to(sequence); +#endif } void PropertyLinkSubList::setPyObject(PyObject *value) @@ -663,8 +733,8 @@ void PropertyLinkSubList::setPyObject(PyObject *value) PropertyLinkSub dummy; dummy.setPyObject(value); this->setValue(dummy.getValue(), dummy.getSubValues()); - } catch (Base::TypeError) { - + } + catch (Base::TypeError) { if (PyTuple_Check(value) || PyList_Check(value)) { Py::Sequence list(value); Py::Sequence::size_type size = list.size(); @@ -678,11 +748,21 @@ void PropertyLinkSubList::setPyObject(PyObject *value) if (item.isTuple()) { Py::Tuple tup(item); if (PyObject_TypeCheck(tup[0].ptr(), &(DocumentObjectPy::Type))){ - DocumentObjectPy *pcObj; - pcObj = static_cast(tup[0].ptr()); - values.push_back(pcObj->getDocumentObjectPtr()); - if (Py::Object(tup[1].ptr()).isString()){ - SubNames.push_back(Py::String(tup[1].ptr())); + if (tup[1].isString()) { + DocumentObjectPy *pcObj; + pcObj = static_cast(tup[0].ptr()); + values.push_back(pcObj->getDocumentObjectPtr()); + SubNames.push_back(Py::String(tup[1])); + } + else if (tup[1].isSequence()) { + Py::Sequence list(tup[1]); + for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { + SubNames.push_back(Py::String(*it)); + } + + DocumentObjectPy *pcObj; + pcObj = static_cast(tup[0].ptr()); + values.insert(values.end(), list.size(), pcObj->getDocumentObjectPtr()); } } } @@ -710,12 +790,13 @@ void PropertyLinkSubList::Save (Base::Writer &writer) const { writer.Stream() << writer.ind() << "" << endl; writer.incInd(); - for(int i = 0;igetNameInDocument() << "\" " << - "sub=\"" << _lSubList[i] << - "\"/>" << endl; ; + "obj=\"" << _lValueList[i]->getNameInDocument() << "\" " << + "sub=\"" << _lSubList[i] << "\"/>" << endl; + } + writer.decInd(); writer.Stream() << writer.ind() << "" << endl ; } diff --git a/src/App/PropertyLinks.h b/src/App/PropertyLinks.h index 10d764603b..42a8ce85b5 100644 --- a/src/App/PropertyLinks.h +++ b/src/App/PropertyLinks.h @@ -98,6 +98,59 @@ protected: App::DocumentObject *_pcLink; }; +class AppExport PropertyLinkList : public PropertyLists +{ + TYPESYSTEM_HEADER(); + +public: + /** + * A constructor. + * A more elaborate description of the constructor. + */ + PropertyLinkList(); + + /** + * A destructor. + * A more elaborate description of the destructor. + */ + virtual ~PropertyLinkList(); + + virtual void setSize(int newSize); + virtual int getSize(void) const; + + /** Sets the property + */ + void setValue(DocumentObject*); + void setValues(const std::vector&); + + /// index operator + DocumentObject* operator[] (const int idx) const { + return _lValueList.operator[] (idx); + } + + + void set1Value(const int idx, DocumentObject* value) { + _lValueList.operator[] (idx) = value; + } + + const std::vector &getValues(void) const { + return _lValueList; + } + + virtual PyObject *getPyObject(void); + virtual void setPyObject(PyObject *); + + virtual void Save(Base::Writer &writer) const; + virtual void Restore(Base::XMLReader &reader); + + virtual Property *Copy(void) const; + virtual void Paste(const Property &from); + + virtual unsigned int getMemSize(void) const; + +private: + std::vector _lValueList; +}; /** the Link Poperty with sub elements * This property links a object and a defined sequence of @@ -166,65 +219,12 @@ protected: }; -class AppExport PropertyLinkList: public PropertyLists -{ - TYPESYSTEM_HEADER(); - -public: - /** - * A constructor. - * A more elaborate description of the constructor. - */ - PropertyLinkList(); - - /** - * A destructor. - * A more elaborate description of the destructor. - */ - virtual ~PropertyLinkList(); - - virtual void setSize(int newSize); - virtual int getSize(void) const; - - /** Sets the property - */ - void setValue(DocumentObject*); - void setValues(const std::vector&); - - /// index operator - DocumentObject* operator[] (const int idx) const { - return _lValueList.operator[] (idx); - } - - - void set1Value (const int idx, DocumentObject* value) { - _lValueList.operator[] (idx) = value; - } - - const std::vector &getValues(void) const { - return _lValueList; - } - - virtual PyObject *getPyObject(void); - virtual void setPyObject(PyObject *); - - virtual void Save (Base::Writer &writer) const; - virtual void Restore(Base::XMLReader &reader); - - virtual Property *Copy(void) const; - virtual void Paste(const Property &from); - - virtual unsigned int getMemSize (void) const; - -private: - std::vector _lValueList; -}; - class AppExport PropertyLinkSubList: public PropertyLists { TYPESYSTEM_HEADER(); public: + typedef std::pair > SubSet; /** * A constructor. * A more elaborate description of the constructor. @@ -237,13 +237,6 @@ public: */ virtual ~PropertyLinkSubList(); - struct SubSet { - SubSet(DocumentObject*o,const char*s):obj(o),sub(s){} - SubSet(DocumentObject*o,const std::string &s):obj(o),sub(s.c_str()){} - DocumentObject* obj; - const char* sub; - }; - virtual void setSize(int newSize); virtual int getSize(void) const; @@ -260,11 +253,6 @@ public: */ 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)); - } - const std::vector &getValues(void) const { return _lValueList; } @@ -283,6 +271,9 @@ public: return _lSubList; } + void setSubListValues(const std::vector&); + std::vector getSubListValues() const; + virtual PyObject *getPyObject(void); virtual void setPyObject(PyObject *); @@ -296,6 +287,7 @@ public: virtual unsigned int getMemSize (void) const; private: + //FIXME: Do not make two independent lists because this will lead to some inconsistencies! std::vector _lValueList; std::vector _lSubList; }; diff --git a/src/Gui/Selection.h b/src/Gui/Selection.h index 1ec24569c0..f79f6e67f5 100644 --- a/src/Gui/Selection.h +++ b/src/Gui/Selection.h @@ -297,7 +297,7 @@ public: /** * @brief getAsPropertyLinkSubList fills PropertyLinkSubList with current selection. - * @param prop (output). The property object to recieve links + * @param prop (output). The property object to receive links * @return the number of items written to the link */ int getAsPropertyLinkSubList(App::PropertyLinkSubList &prop) const;