diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 43b6073237..09f99c7326 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -3540,17 +3540,8 @@ DocumentObject * Document::addObject(const char* sType, const char* pObjectName, pcObject->setStatus(ObjectStatus::PartialObject, isPartial); - // 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') + viewType = pcObject->getViewProviderNameOverride(); if (viewType && viewType[0] != '\0') pcObject->_pcViewProviderName = viewType; @@ -3644,16 +3635,8 @@ 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); - // 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 : ""; - } + const char *viewType = pcObject->getViewProviderNameOverride(); + pcObject->_pcViewProviderName = viewType ? viewType : ""; signalNewObject(*pcObject); @@ -3711,16 +3694,8 @@ 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); - // 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 : ""; - } + const char *viewType = pcObject->getViewProviderNameOverride(); + pcObject->_pcViewProviderName = viewType ? viewType : ""; signalNewObject(*pcObject); @@ -3751,16 +3726,8 @@ void Document::_addObject(DocumentObject* pcObject, const char* pObjectName) d->activeUndoTransaction->addObjectDel(pcObject); } - // 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 : ""; - } + const char *viewType = pcObject->getViewProviderNameOverride(); + pcObject->_pcViewProviderName = viewType ? viewType : ""; // send the signal signalNewObject(*pcObject); diff --git a/src/App/DocumentObject.h b/src/App/DocumentObject.h index 1b423da5b3..139f76569a 100644 --- a/src/App/DocumentObject.h +++ b/src/App/DocumentObject.h @@ -114,22 +114,15 @@ public: * 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. + * The core will only accept the overridden view provider if it returns + * true when calling Gui::ViewProviderDocumentObject::allowOverride(obj). + * If not, the view provider will be reverted to the one returned from \ref + * getViewProviderName(). */ 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 overridden 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 ef423f7f29..f846cf576d 100644 --- a/src/App/FeaturePython.cpp +++ b/src/App/FeaturePython.cpp @@ -435,11 +435,6 @@ int FeaturePythonImp::setElementVisible(const char *element, bool visible) { } } -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 b8cad17c05..2c90a6c894 100644 --- a/src/App/FeaturePython.h +++ b/src/App/FeaturePython.h @@ -57,7 +57,6 @@ public: bool onBeforeChangeLabel(std::string &newLabel); void onChanged(const Property* prop); void onDocumentRestored(); - bool allowOverrideViewProviderName() const; std::string getViewProviderName(); PyObject *getPyObject(void); @@ -200,9 +199,6 @@ public: } return DocumentObject::StdReturn; } - virtual bool allowOverrideViewProviderName() const { - return imp->allowOverrideViewProviderName(); - } virtual const char* getViewProviderNameOverride(void) const override { viewProviderName = imp->getViewProviderName(); if(viewProviderName.size()) diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 2cf307e5e7..9aa3b3813e 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -621,44 +621,52 @@ void Document::slotNewObject(const App::DocumentObject& Obj) if (!pcProvider) { //Base::Console().Log("Document::slotNewObject() called\n"); std::string cName = Obj.getViewProviderNameStored(); - if (cName.empty()) { - // handle document object with no view provider specified - Base::Console().Log("%s has no view provider specified\n", Obj.getTypeId().getName()); - return; + for(;;) { + if (cName.empty()) { + // handle document object with no view provider specified + FC_LOG(Obj.getFullName() << " has no view provider specified"); + return; + } + Base::BaseClass* base = static_cast( + Base::Type::createInstanceByName(cName.c_str(),true)); + pcProvider = Base::freecad_dynamic_cast(base); + if (!pcProvider) { + // type not derived from ViewProviderDocumentObject!!! + FC_ERR("Invalid view provider type '" << cName << "' for " << Obj.getFullName()); + delete base; + return; + } else if (cName!=Obj.getViewProviderName() && !pcProvider->allowOverride(Obj)) { + FC_WARN("View provider type '" << cName << "' does not support " << Obj.getFullName()); + delete base; + pcProvider = 0; + cName = Obj.getViewProviderName(); + } else + break; } setModified(true); - Base::BaseClass* base = static_cast(Base::Type::createInstanceByName(cName.c_str(),true)); - if (base) { - // type not derived from ViewProviderDocumentObject!!! - assert(base->getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId())); - pcProvider = static_cast(base); - d->_ViewProviderMap[&Obj] = pcProvider; - d->_CoinMap[pcProvider->getRoot()] = pcProvider; - pcProvider->setStatus(Gui::ViewStatus::TouchDocument, d->_changeViewTouchDocument); + d->_ViewProviderMap[&Obj] = pcProvider; + d->_CoinMap[pcProvider->getRoot()] = pcProvider; + pcProvider->setStatus(Gui::ViewStatus::TouchDocument, d->_changeViewTouchDocument); - try { - // if successfully created set the right name and calculate the view - //FIXME: Consider to change argument of attach() to const pointer - pcProvider->attach(const_cast(&Obj)); - pcProvider->updateView(); - pcProvider->setActiveMode(); - } - catch(const Base::MemoryException& e){ - FC_ERR("Memory exception in " << Obj.getFullName() << " thrown: " << e.what()); - } - catch(Base::Exception &e){ - e.ReportException(); - } + try { + // if successfully created set the right name and calculate the view + //FIXME: Consider to change argument of attach() to const pointer + pcProvider->attach(const_cast(&Obj)); + pcProvider->updateView(); + pcProvider->setActiveMode(); + } + catch(const Base::MemoryException& e){ + FC_ERR("Memory exception in " << Obj.getFullName() << " thrown: " << e.what()); + } + catch(Base::Exception &e){ + e.ReportException(); + } #ifndef FC_DEBUG - catch(...){ - FC_ERR("Unknown exception in Feature " << Obj.getFullName() << " thrown"); - } + catch(...){ + FC_ERR("Unknown exception in Feature " << Obj.getFullName() << " thrown"); + } #endif - } - else { - FC_WARN("no view provider for the object " << cName << " found"); - } }else{ try { pcProvider->reattach(const_cast(&Obj)); diff --git a/src/Gui/ViewProviderDocumentObject.h b/src/Gui/ViewProviderDocumentObject.h index 7f833611db..79bda407c1 100644 --- a/src/Gui/ViewProviderDocumentObject.h +++ b/src/Gui/ViewProviderDocumentObject.h @@ -139,6 +139,14 @@ public: virtual std::string getFullName() const override; + /** Allow this class to be used as an override for the original view provider of the given object + * + * @sa App::DocumentObject::getViewProviderNameOverride() + */ + virtual bool allowOverride(const App::DocumentObject &) const { + return false; + } + protected: /*! Get the active mdi view of the document this view provider is part of. @note The returned mdi view doesn't need to be a 3d view but can be e.g. diff --git a/src/Gui/ViewProviderLink.cpp b/src/Gui/ViewProviderLink.cpp index e63cc1a9cd..388a02938e 100644 --- a/src/Gui/ViewProviderLink.cpp +++ b/src/Gui/ViewProviderLink.cpp @@ -1711,15 +1711,22 @@ QPixmap ViewProviderLink::getOverlayPixmap() const { void ViewProviderLink::onChanged(const App::Property* prop) { if(prop==&ChildViewProvider) { childVp = freecad_dynamic_cast(ChildViewProvider.getObject().get()); - if(childVp) { - childVp->setPropertyPrefix("ChildViewProvider."); - childVp->Visibility.setValue(getObject()->Visibility.getValue()); - childVp->attach(getObject()); - childVp->updateView(); - childVp->setActiveMode(); - if(pcModeSwitch->getNumChildren()>1){ - childVpLink = LinkInfo::get(childVp,0); - pcModeSwitch->replaceChild(1,childVpLink->getSnapshot(LinkView::SnapshotTransform)); + if(childVp && getObject()) { + if(strcmp(childVp->getTypeId().getName(),getObject()->getViewProviderName())!=0 + && !childVp->allowOverride(*getObject())) + { + FC_ERR("Child view provider type '" << childVp->getTypeId().getName() + << "' does not support " << getObject()->getFullName()); + } else { + childVp->setPropertyPrefix("ChildViewProvider."); + childVp->Visibility.setValue(getObject()->Visibility.getValue()); + childVp->attach(getObject()); + childVp->updateView(); + childVp->setActiveMode(); + if(pcModeSwitch->getNumChildren()>1){ + childVpLink = LinkInfo::get(childVp,0); + pcModeSwitch->replaceChild(1,childVpLink->getSnapshot(LinkView::SnapshotTransform)); + } } } }else if(!isRestoring()) { diff --git a/src/Gui/ViewProviderLink.h b/src/Gui/ViewProviderLink.h index fb0e358203..1e274f132b 100644 --- a/src/Gui/ViewProviderLink.h +++ b/src/Gui/ViewProviderLink.h @@ -265,6 +265,10 @@ public: virtual ViewProviderDocumentObject *getLinkedViewProvider( std::string *subname=0, bool recursive=false) const override; + virtual bool allowOverride(const App::DocumentObject &) const override { + return true; + } + protected: bool setEdit(int ModNum) override; void setEditViewer(View3DInventorViewer*, int ModNum) override; diff --git a/src/Mod/Part/Gui/ViewProviderExt.cpp b/src/Mod/Part/Gui/ViewProviderExt.cpp index 1b14e94ca0..39896d656c 100644 --- a/src/Mod/Part/Gui/ViewProviderExt.cpp +++ b/src/Mod/Part/Gui/ViewProviderExt.cpp @@ -467,6 +467,12 @@ void ViewProviderPartExt::onChanged(const App::Property* prop) ViewProviderGeometryObject::onChanged(prop); } +bool ViewProviderPartExt::allowOverride(const App::DocumentObject &) const { + // Many derived view providers still uses static_cast to get object + // pointer, so check for exact type here. + return getTypeId() == ViewProviderPartExt::getClassTypeId(); +} + void ViewProviderPartExt::attach(App::DocumentObject *pcFeat) { // call parent attach method diff --git a/src/Mod/Part/Gui/ViewProviderExt.h b/src/Mod/Part/Gui/ViewProviderExt.h index 8063d5aea3..9bd8a89e74 100644 --- a/src/Mod/Part/Gui/ViewProviderExt.h +++ b/src/Mod/Part/Gui/ViewProviderExt.h @@ -134,6 +134,8 @@ public: } virtual void forceUpdate(bool enable = true) override; + virtual bool allowOverride(const App::DocumentObject &) const override; + /** @name Edit methods */ //@{ void setupContextMenu(QMenu*, QObject*, const char*) override;