From 1cdd2d166f855a5ab5ede93b9ebcac5f5b746b2e Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 14 Sep 2019 00:52:09 +0200 Subject: [PATCH] Add virtual method allowOverrideViewProviderName to DocumentObject to indicate if a DocumentObject's view provider type can be overriden. For most object types this is not allowed to avoid to create incompatible combinations via Python or manipulated project files and possibly provoke crashes. For more details see also: https://forum.freecadweb.org/viewtopic.php?f=10&t=38970&p=333951#p333951 --- src/App/Document.cpp | 59 +++++++++++++++++++++++++++++++-------- src/App/DocumentObject.h | 18 +++++++++++- src/App/FeaturePython.cpp | 5 ++++ src/App/FeaturePython.h | 6 +++- 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 961340bdb6..3ca4a38a72 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -1851,8 +1851,12 @@ void Document::writeObjects(const std::vector& obj, writer.Stream() << writer.ind() << "getTypeId().getName() << "\" " << "name=\"" << (*it)->getExportName() << "\" " - << "id=\"" << (*it)->getID() << "\" " - << "ViewType=\"" << (*it)->getViewProviderNameStored() << "\" "; + << "id=\"" << (*it)->getID() << "\" "; + + // Only write out custom view provider types + std::string viewType = (*it)->getViewProviderNameStored(); + if (viewType != (*it)->getViewProviderName()) + writer.Stream() << "ViewType=\"" << viewType << "\" "; // See DocumentObjectPy::getState if ((*it)->testStatus(ObjectStatus::Touch)) @@ -3476,7 +3480,7 @@ bool Document::recomputeFeature(DocumentObject* Feat, bool recursive) } DocumentObject * Document::addObject(const char* sType, const char* pObjectName, - bool isNew, const char *viewType, bool isPartial) + bool isNew, const char* viewType, bool isPartial) { Base::BaseClass* base = static_cast(Base::Type::createInstanceByName(sType,true)); @@ -3537,8 +3541,17 @@ DocumentObject * Document::addObject(const char* sType, const char* pObjectName, pcObject->setStatus(ObjectStatus::PartialObject, isPartial); - if (!viewType || viewType[0] == '\0') - viewType = pcObject->getViewProviderNameOverride(); + // If an object does not allow to override its view provider then ignore any + // input of the Document.xml or from Python as this information could be wrong. + // In this case the default type from getViewProviderName() is used. + if (pcObject->allowOverrideViewProviderName()) { + if (!viewType || viewType[0] == '\0') { + viewType = pcObject->getViewProviderNameOverride(); + } + } + else { + viewType = pcObject->getViewProviderName(); + } if (viewType && viewType[0] != '\0') pcObject->_pcViewProviderName = viewType; @@ -3632,8 +3645,16 @@ std::vector Document::addObjects(const char* sType, const std: // mark the object as new (i.e. set status bit 2) and send the signal pcObject->setStatus(ObjectStatus::New, true); - const char *viewType = pcObject->getViewProviderNameOverride(); - pcObject->_pcViewProviderName = viewType?viewType:""; + // If an object does not allow to override its view provider then use + // getViewProviderName() instead. + if (pcObject->allowOverrideViewProviderName()) { + const char *viewType = pcObject->getViewProviderNameOverride(); + pcObject->_pcViewProviderName = viewType ? viewType : ""; + } + else { + const char *viewType = pcObject->getViewProviderName(); + pcObject->_pcViewProviderName = viewType ? viewType : ""; + } signalNewObject(*pcObject); @@ -3691,8 +3712,16 @@ void Document::addObject(DocumentObject* pcObject, const char* pObjectName) // mark the object as new (i.e. set status bit 2) and send the signal pcObject->setStatus(ObjectStatus::New, true); - const char *viewType = pcObject->getViewProviderNameOverride(); - pcObject->_pcViewProviderName = viewType?viewType:""; + // If an object does not allow to override its view provider then use + // getViewProviderName() instead. + if (pcObject->allowOverrideViewProviderName()) { + const char *viewType = pcObject->getViewProviderNameOverride(); + pcObject->_pcViewProviderName = viewType ? viewType : ""; + } + else { + const char *viewType = pcObject->getViewProviderName(); + pcObject->_pcViewProviderName = viewType ? viewType : ""; + } signalNewObject(*pcObject); @@ -3723,8 +3752,16 @@ void Document::_addObject(DocumentObject* pcObject, const char* pObjectName) d->activeUndoTransaction->addObjectDel(pcObject); } - const char *viewType = pcObject->getViewProviderNameOverride(); - pcObject->_pcViewProviderName = viewType?viewType:""; + // If an object does not allow to override its view provider then use + // getViewProviderName() instead. + if (pcObject->allowOverrideViewProviderName()) { + const char *viewType = pcObject->getViewProviderNameOverride(); + pcObject->_pcViewProviderName = viewType ? viewType : ""; + } + else { + const char *viewType = pcObject->getViewProviderName(); + pcObject->_pcViewProviderName = viewType ? viewType : ""; + } // send the signal signalNewObject(*pcObject); diff --git a/src/App/DocumentObject.h b/src/App/DocumentObject.h index f2599bb300..879ff4f260 100644 --- a/src/App/DocumentObject.h +++ b/src/App/DocumentObject.h @@ -110,10 +110,26 @@ public: virtual const char* getViewProviderName(void) const { return ""; } - /// This function is introduced to allow Python feature override its view provider + /** + * This function is introduced to allow Python feature override its view provider. + * The default implementation just returns \ref getViewProviderName(). + * + * If this method is reimplemented in sub-classes then also reimplement \ref + * allowOverrideViewProviderName() accordingly. + */ virtual const char *getViewProviderNameOverride() const { return getViewProviderName(); } + /** + * The function indicates whether the object type allows to define a view provider type + * different than the standard type. The default implementation returns false. + * The function can be overriden by Python feature to return true where the type can be + * retrieved from its proxy object. + * \sa getViewProviderNameOverride() + */ + virtual bool allowOverrideViewProviderName() const { + return false; + } /// Constructor DocumentObject(void); virtual ~DocumentObject(); diff --git a/src/App/FeaturePython.cpp b/src/App/FeaturePython.cpp index 9c61f3db01..f85c955a16 100644 --- a/src/App/FeaturePython.cpp +++ b/src/App/FeaturePython.cpp @@ -410,6 +410,11 @@ int FeaturePythonImp::setElementVisible(const char *element, bool visible) { return -2; } +bool FeaturePythonImp::allowOverrideViewProviderName() const +{ + return true; +} + std::string FeaturePythonImp::getViewProviderName() { _FC_PY_CALL_CHECK(getViewProviderName,return(std::string())); diff --git a/src/App/FeaturePython.h b/src/App/FeaturePython.h index 8183fb3886..0ef810b949 100644 --- a/src/App/FeaturePython.h +++ b/src/App/FeaturePython.h @@ -51,6 +51,7 @@ public: bool onBeforeChangeLabel(std::string &newLabel); void onChanged(const Property* prop); void onDocumentRestored(); + bool allowOverrideViewProviderName() const; std::string getViewProviderName(); PyObject *getPyObject(void); @@ -192,7 +193,10 @@ public: } return DocumentObject::StdReturn; } - virtual const char* getViewProviderNameOverride(void) const override{ + virtual bool allowOverrideViewProviderName() const { + return imp->allowOverrideViewProviderName(); + } + virtual const char* getViewProviderNameOverride(void) const override { viewProviderName = imp->getViewProviderName(); if(viewProviderName.size()) return viewProviderName.c_str();