From d3dea0178da769bafee657354fec1e6bc23267ca Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Wed, 28 Aug 2019 14:01:37 +0800 Subject: [PATCH] App/Gui: unify NotImplementedError handling in python features Recognize NotImplementedError as an indication to call the C++ implementation. --- src/App/FeaturePython.cpp | 62 ++++- src/App/FeaturePython.h | 8 +- src/Gui/ViewProviderPythonFeature.cpp | 328 +++++++++++++++++--------- src/Gui/ViewProviderPythonFeature.h | 120 ++++++---- 4 files changed, 349 insertions(+), 169 deletions(-) diff --git a/src/App/FeaturePython.cpp b/src/App/FeaturePython.cpp index f85c955a16..c8cc778c3b 100644 --- a/src/App/FeaturePython.cpp +++ b/src/App/FeaturePython.cpp @@ -84,6 +84,10 @@ bool FeaturePythonImp::execute() } } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } Base::PyException e; // extract the Python error text e.ReportException(); std::stringstream str; @@ -272,6 +276,10 @@ bool FeaturePythonImp::getSubObject(DocumentObject *&ret, const char *subname, return true; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } Base::PyException e; // extract the Python error text e.ReportException(); ret = 0; @@ -301,6 +309,10 @@ bool FeaturePythonImp::getSubObjects(std::vector &ret, int reason) return true; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } Base::PyException e; // extract the Python error text e.ReportException(); return true; @@ -346,6 +358,10 @@ bool FeaturePythonImp::getLinkedObject(DocumentObject *&ret, bool recurse, return true; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } Base::PyException e; // extract the Python error text e.ReportException(); ret = 0; @@ -369,11 +385,14 @@ int FeaturePythonImp::hasChildElement() const { return static_cast(ok) ? 1 : 0; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return -1; + } Base::PyException e; // extract the Python error text e.ReportException(); + return 0; } - - return -1; } int FeaturePythonImp::isElementVisible(const char *element) const { @@ -386,10 +405,14 @@ int FeaturePythonImp::isElementVisible(const char *element) const { return Py::Int(Base::pyCall(py_isElementVisible.ptr(),args.ptr())); } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return -2; + } Base::PyException e; // extract the Python error text e.ReportException(); + return -1; } - return -2; } int FeaturePythonImp::setElementVisible(const char *element, bool visible) { @@ -403,11 +426,14 @@ int FeaturePythonImp::setElementVisible(const char *element, bool visible) { return Py::Int(Base::pyCall(py_setElementVisible.ptr(),args.ptr())); } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return -2; + } Base::PyException e; // extract the Python error text e.ReportException(); + return -1; } - - return -2; } bool FeaturePythonImp::allowOverrideViewProviderName() const @@ -442,6 +468,10 @@ int FeaturePythonImp::canLinkProperties() const { return ok?1:0; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return -1; + } Base::PyException e; // extract the Python error text e.ReportException(); return 0; @@ -458,6 +488,10 @@ int FeaturePythonImp::allowDuplicateLabel() const { return ok?1:0; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return -1; + } Base::PyException e; // extract the Python error text e.ReportException(); return 0; @@ -474,13 +508,17 @@ int FeaturePythonImp::canLoadPartial() const { return ret; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return -1; + } Base::PyException e; // extract the Python error text e.ReportException(); + return 0; } - return -1; } -bool FeaturePythonImp::redirectSubName(std::ostringstream &ss, +int FeaturePythonImp::redirectSubName(std::ostringstream &ss, App::DocumentObject *topParent, App::DocumentObject *child) const { FC_PY_CALL_CHECK(redirectSubName); @@ -493,16 +531,20 @@ bool FeaturePythonImp::redirectSubName(std::ostringstream &ss, args.setItem(3,child?Py::Object(child->getPyObject(),true):Py::Object()); Py::Object ret(Base::pyCall(py_redirectSubName.ptr(),args.ptr())); if(ret.isNone()) - return false; + return 0; ss.str(""); ss << ret.as_string(); - return true; + return 1; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return -1; + } Base::PyException e; // extract the Python error text e.ReportException(); + return 0; } - return false; } // --------------------------------------------------------- diff --git a/src/App/FeaturePython.h b/src/App/FeaturePython.h index 0ef810b949..404a7292ad 100644 --- a/src/App/FeaturePython.h +++ b/src/App/FeaturePython.h @@ -67,7 +67,7 @@ public: int allowDuplicateLabel() const; - bool redirectSubName(std::ostringstream &ss, + int redirectSubName(std::ostringstream &ss, App::DocumentObject *topParent, App::DocumentObject *child) const; int canLoadPartial() const; @@ -272,8 +272,10 @@ public: virtual bool redirectSubName(std::ostringstream &ss, App::DocumentObject *topParent, App::DocumentObject *child) const override { - return imp->redirectSubName(ss,topParent,child) || - FeatureT::redirectSubName(ss,topParent,child); + int ret = imp->redirectSubName(ss,topParent,child); + if(ret < 0) + return FeatureT::redirectSubName(ss,topParent,child); + return ret?true:false; } virtual int canLoadPartial() const override { diff --git a/src/Gui/ViewProviderPythonFeature.cpp b/src/Gui/ViewProviderPythonFeature.cpp index 9425cb9b39..c5ea875ddc 100644 --- a/src/Gui/ViewProviderPythonFeature.cpp +++ b/src/Gui/ViewProviderPythonFeature.cpp @@ -369,19 +369,21 @@ QIcon ViewProviderPythonFeatureImp::getIcon() const } } catch (Py::Exception&) { - Base::PyException e; // extract the Python error text - e.ReportException(); + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) + PyErr_Clear(); + else { + Base::PyException e; // extract the Python error text + e.ReportException(); + } } return QIcon(); } -std::vector -ViewProviderPythonFeatureImp::claimChildren(std::vector&& base) const +bool ViewProviderPythonFeatureImp::claimChildren(std::vector &children) const { - _FC_PY_CALL_CHECK(claimChildren,return (std::move(base))); + _FC_PY_CALL_CHECK(claimChildren,return(false)); - std::vector children; Base::PyGILStateLocker lock; try { Py::Sequence list(Base::pyCall(py_claimChildren.ptr())); @@ -394,24 +396,10 @@ ViewProviderPythonFeatureImp::claimChildren(std::vector&& } } catch (Py::Exception&) { - Base::PyException e; // extract the Python error text - e.ReportException(); - } - - return children; -} - -bool ViewProviderPythonFeatureImp::useNewSelectionModel() const -{ - _FC_PY_CALL_CHECK(useNewSelectionModel,return(true)); - - // Run the useNewSelectionModel method of the proxy object. - Base::PyGILStateLocker lock; - try { - Py::Boolean ok(Py::Callable(py_useNewSelectionModel).apply(Py::Tuple())); - return (bool)ok; - } - catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } Base::PyException e; // extract the Python error text e.ReportException(); } @@ -419,9 +407,32 @@ bool ViewProviderPythonFeatureImp::useNewSelectionModel() const return true; } -std::string ViewProviderPythonFeatureImp::getElement(const SoDetail *det) const +ViewProviderPythonFeatureImp::ValueT +ViewProviderPythonFeatureImp::useNewSelectionModel() const { - _FC_PY_CALL_CHECK(getElement,return(std::string())); + FC_PY_CALL_CHECK(useNewSelectionModel); + + // Run the useNewSelectionModel method of the proxy object. + Base::PyGILStateLocker lock; + try { + Py::Boolean ok(Py::Callable(py_useNewSelectionModel).apply(Py::Tuple())); + return ok?Accepted:Rejected; + } + catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } + Base::PyException e; // extract the Python error text + e.ReportException(); + } + + return Accepted; +} + +bool ViewProviderPythonFeatureImp::getElement(const SoDetail *det, std::string &res) const +{ + _FC_PY_CALL_CHECK(getElement,return(false)); // Run the onChanged method of the proxy object. Base::PyGILStateLocker lock; @@ -434,17 +445,22 @@ std::string ViewProviderPythonFeatureImp::getElement(const SoDetail *det) const Py::Tuple args(1); args.setItem(0, Py::Object(pivy, true)); Py::String name(Base::pyCall(py_getElement.ptr(),args.ptr())); - return (std::string)name; + res = name; + return true; } catch (const Base::Exception& e) { e.ReportException(); } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } Base::PyException e; // extract the Python error text e.ReportException(); } - return std::string(); + return true; } ViewProviderPythonFeatureImp::ValueT @@ -467,37 +483,46 @@ ViewProviderPythonFeatureImp::getElementPicked(const SoPickedPoint *pp, std::str e.ReportException(); } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } - return NotImplemented; + return Rejected; } -SoDetail* ViewProviderPythonFeatureImp::getDetail(const char* name) const +bool ViewProviderPythonFeatureImp::getDetail(const char* name, SoDetail *&det) const { - _FC_PY_CALL_CHECK(getDetail,return(0)); + _FC_PY_CALL_CHECK(getDetail,return(false)); // Run the onChanged method of the proxy object. Base::PyGILStateLocker lock; try { Py::Tuple args(1); args.setItem(0, Py::String(name)); - Py::Object det(Base::pyCall(py_getDetail.ptr(),args.ptr())); + Py::Object pydet(Base::pyCall(py_getDetail.ptr(),args.ptr())); void* ptr = 0; - Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoDetail *", det.ptr(), &ptr, 0); + Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoDetail *", pydet.ptr(), &ptr, 0); SoDetail* detail = reinterpret_cast(ptr); - return detail ? detail->copy() : 0; + det = detail ? detail->copy() : 0; + return true; } catch (const Base::Exception& e) { e.ReportException(); } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } Base::PyException e; // extract the Python error text e.ReportException(); } - return 0; + return true; } ViewProviderPythonFeatureImp::ValueT ViewProviderPythonFeatureImp::getDetailPath( @@ -532,6 +557,10 @@ ViewProviderPythonFeatureImp::ValueT ViewProviderPythonFeatureImp::getDetailPath e.ReportException(); } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } @@ -575,23 +604,15 @@ ViewProviderPythonFeatureImp::setEdit(int ModNum) } } catch (Py::Exception&) { - // If an explicit NotImplementedError is raised then - // handle it differently to other RuntimeError if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } - // If a runtime error occurred when calling setEdit - // then handle it like returning false - if (PyErr_ExceptionMatches(PyExc_RuntimeError)) { - PyErr_Clear(); - return Rejected; - } Base::PyException e; // extract the Python error text e.ReportException(); } - return NotImplemented; + return Rejected; } ViewProviderPythonFeatureImp::ValueT @@ -624,28 +645,21 @@ ViewProviderPythonFeatureImp::unsetEdit(int ModNum) } } catch (Py::Exception&) { - // If an explicit NotImplementedError is raised then - // handle it differently to other RuntimeError if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } - // If a runtime error occurred when calling setEdit - // then handle it like returning false - if (PyErr_ExceptionMatches(PyExc_RuntimeError)) { - PyErr_Clear(); - return Rejected; - } Base::PyException e; // extract the Python error text e.ReportException(); } - return NotImplemented; + return Rejected; } -bool ViewProviderPythonFeatureImp::setEditViewer(View3DInventorViewer *viewer, int ModNum) +ViewProviderPythonFeatureImp::ValueT +ViewProviderPythonFeatureImp::setEditViewer(View3DInventorViewer *viewer, int ModNum) { - _FC_PY_CALL_CHECK(setEditViewer,return(false)) + FC_PY_CALL_CHECK(setEditViewer) Base::PyGILStateLocker lock; try { @@ -654,18 +668,23 @@ bool ViewProviderPythonFeatureImp::setEditViewer(View3DInventorViewer *viewer, i args.setItem(1, Py::Object(viewer->getPyObject(),true)); args.setItem(2, Py::Int(ModNum)); Py::Object ret(Base::pyCall(py_setEditViewer.ptr(),args.ptr())); - return ret.isTrue(); + return ret.isTrue()?Accepted:Rejected; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } - return false; + return Rejected; } -bool ViewProviderPythonFeatureImp::unsetEditViewer(View3DInventorViewer *viewer) +ViewProviderPythonFeatureImp::ValueT +ViewProviderPythonFeatureImp::unsetEditViewer(View3DInventorViewer *viewer) { - _FC_PY_CALL_CHECK(unsetEditViewer,return(false)) + FC_PY_CALL_CHECK(unsetEditViewer) // Run the onChanged method of the proxy object. Base::PyGILStateLocker lock; @@ -674,13 +693,17 @@ bool ViewProviderPythonFeatureImp::unsetEditViewer(View3DInventorViewer *viewer) args.setItem(0, Py::Object(object->getPyObject(),true)); args.setItem(1, Py::Object(viewer->getPyObject(),true)); Py::Object ret(Base::pyCall(py_unsetEditViewer.ptr(),args.ptr())); - return ret.isTrue(); + return ret.isTrue()?Accepted:Rejected; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } - return false; + return Rejected; } ViewProviderPythonFeatureImp::ValueT @@ -705,16 +728,20 @@ ViewProviderPythonFeatureImp::doubleClicked(void) } } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } - return NotImplemented; + return Rejected; } -void ViewProviderPythonFeatureImp::setupContextMenu(QMenu* menu) +bool ViewProviderPythonFeatureImp::setupContextMenu(QMenu* menu) { - _FC_PY_CALL_CHECK(setupContextMenu,return); + _FC_PY_CALL_CHECK(setupContextMenu,return(false)); // Run the attach method of the proxy object. Base::PyGILStateLocker lock; @@ -725,7 +752,7 @@ void ViewProviderPythonFeatureImp::setupContextMenu(QMenu* menu) wrap.loadWidgetsModule(); Py::Tuple args(1); args.setItem(0, wrap.fromQWidget(menu, "QMenu")); - Base::pyCall(py_setupContextMenu.ptr(),args.ptr()); + return Base::pyCall(py_setupContextMenu.ptr(),args.ptr()).isTrue(); } else { PythonWrapper wrap; @@ -734,13 +761,18 @@ void ViewProviderPythonFeatureImp::setupContextMenu(QMenu* menu) Py::Tuple args(2); args.setItem(0, Py::Object(object->getPyObject(), true)); args.setItem(1, wrap.fromQWidget(menu, "QMenu")); - Base::pyCall(py_setupContextMenu.ptr(),args.ptr()); + return Base::pyCall(py_setupContextMenu.ptr(),args.ptr()).isTrue(); } } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } Base::PyException e; // extract the Python error text e.ReportException(); } + return true; } void ViewProviderPythonFeatureImp::attach(App::DocumentObject *pcObject) @@ -855,9 +887,10 @@ void ViewProviderPythonFeatureImp::finishRestoring() } } -bool ViewProviderPythonFeatureImp::onDelete(const std::vector & sub) +ViewProviderPythonFeatureImp::ValueT +ViewProviderPythonFeatureImp::onDelete(const std::vector & sub) { - _FC_PY_CALL_CHECK(onDelete,return(true)); + FC_PY_CALL_CHECK(onDelete); Base::PyGILStateLocker lock; try { @@ -871,22 +904,25 @@ bool ViewProviderPythonFeatureImp::onDelete(const std::vector & sub Py::Tuple args(1); args.setItem(0, seq); Py::Boolean ok(Base::pyCall(py_onDelete.ptr(),args.ptr())); - return (bool)ok; + return ok?Accepted:Rejected; } else { Py::Tuple args(2); args.setItem(0, Py::Object(object->getPyObject(), true)); args.setItem(1, seq); Py::Boolean ok(Base::pyCall(py_onDelete.ptr(),args.ptr())); - return (bool)ok; + return ok?Accepted:Rejected; } } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); + return Rejected; } - - return true; } ViewProviderPythonFeatureImp::ValueT @@ -901,47 +937,59 @@ ViewProviderPythonFeatureImp::canDelete(App::DocumentObject *obj) const return Py::Boolean(Base::pyCall(py_canDelete.ptr(),args.ptr()))?Accepted:Rejected; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); return Rejected; } } -bool ViewProviderPythonFeatureImp::canAddToSceneGraph() const +ViewProviderPythonFeatureImp::ValueT +ViewProviderPythonFeatureImp::canAddToSceneGraph() const { - _FC_PY_CALL_CHECK(canAddToSceneGraph,return(true)); + FC_PY_CALL_CHECK(canAddToSceneGraph); Base::PyGILStateLocker lock; try { - return Py::Boolean(Py::Callable(py_canAddToSceneGraph).apply(Py::Tuple())); + return Py::Boolean(Py::Callable(py_canAddToSceneGraph).apply(Py::Tuple()))?Accepted:Rejected; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } - return true; + return Accepted; } -const char* ViewProviderPythonFeatureImp::getDefaultDisplayMode() const +bool ViewProviderPythonFeatureImp::getDefaultDisplayMode(std::string &mode) const { _FC_PY_CALL_CHECK(getDefaultDisplayMode,return(0)); // Run the getDefaultDisplayMode method of the proxy object. Base::PyGILStateLocker lock; - static std::string mode; try { Py::String str(Base::pyCall(py_getDefaultDisplayMode.ptr())); //if (str.isUnicode()) // str = str.encode("ascii"); // json converts strings into unicode mode = str.as_std_string("ascii"); - return mode.c_str(); + return true; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } Base::PyException e; // extract the Python error text e.ReportException(); } - return 0; + return true; } std::vector ViewProviderPythonFeatureImp::getDisplayModes(void) const @@ -970,8 +1018,12 @@ std::vector ViewProviderPythonFeatureImp::getDisplayModes(void) con } } catch (Py::Exception&) { - Base::PyException e; // extract the Python error text - e.ReportException(); + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) + PyErr_Clear(); + else { + Base::PyException e; // extract the Python error text + e.ReportException(); + } } return modes; @@ -1008,6 +1060,10 @@ ViewProviderPythonFeatureImp::canDragObjects() const return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } @@ -1028,6 +1084,10 @@ ViewProviderPythonFeatureImp::canDragObject(App::DocumentObject* obj) const return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } @@ -1058,6 +1118,10 @@ ViewProviderPythonFeatureImp::dragObject(App::DocumentObject* obj) } } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } @@ -1076,6 +1140,10 @@ ViewProviderPythonFeatureImp::canDropObjects() const return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } @@ -1096,6 +1164,10 @@ ViewProviderPythonFeatureImp::canDropObject(App::DocumentObject* obj) const return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } @@ -1125,9 +1197,11 @@ ViewProviderPythonFeatureImp::dropObject(App::DocumentObject* obj) } } catch (Py::Exception&) { - Base::PyException e; // extract the Python error text - e.ReportException(); - throw e; + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } + Base::PyException::ThrowException(); } return Rejected; @@ -1145,6 +1219,10 @@ ViewProviderPythonFeatureImp::canDragAndDropObject(App::DocumentObject *obj) con return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } @@ -1173,6 +1251,10 @@ ViewProviderPythonFeatureImp::canDropObjectEx(App::DocumentObject* obj, return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } @@ -1180,11 +1262,10 @@ ViewProviderPythonFeatureImp::canDropObjectEx(App::DocumentObject* obj, return Rejected; } -ViewProviderPythonFeatureImp::ValueT -ViewProviderPythonFeatureImp::dropObjectEx(App::DocumentObject* obj, App::DocumentObject *owner, +bool ViewProviderPythonFeatureImp::dropObjectEx(App::DocumentObject* obj, App::DocumentObject *owner, const char *subname, const std::vector &elements,std::string &ret) { - FC_PY_CALL_CHECK(dropObjectEx); + _FC_PY_CALL_CHECK(dropObjectEx, return(false)); Base::PyGILStateLocker lock; try { @@ -1201,29 +1282,38 @@ ViewProviderPythonFeatureImp::dropObjectEx(App::DocumentObject* obj, App::Docume res = Base::pyCall(py_dropObjectEx.ptr(),args.ptr()); if(!res.isNone()) ret = res.as_string(); - return Accepted; + return true; } catch (Py::Exception&) { - Base::PyException e; // extract the Python error text - throw e; + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } + Base::PyException::ThrowException(); } + return true; } -bool ViewProviderPythonFeatureImp::isShow() const +ViewProviderPythonFeatureImp::ValueT +ViewProviderPythonFeatureImp::isShow() const { - _FC_PY_CALL_CHECK(isShow,return(false)); + FC_PY_CALL_CHECK(isShow); Base::PyGILStateLocker lock; try { Py::Boolean ok(Base::pyCall(py_isShow.ptr())); - return static_cast(ok) ? true : false; + return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } - return false; + return Rejected; } @@ -1238,6 +1328,10 @@ ViewProviderPythonFeatureImp::canRemoveChildrenFromRoot() const { return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } @@ -1257,10 +1351,14 @@ bool ViewProviderPythonFeatureImp::getDropPrefix(std::string &prefix) const { return true; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } Base::PyException e; // extract the Python error text e.ReportException(); } - return false; + return true; } ViewProviderPythonFeatureImp::ValueT @@ -1281,16 +1379,20 @@ ViewProviderPythonFeatureImp::replaceObject( return ok ? Accepted : Rejected; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return NotImplemented; + } Base::PyException e; // extract the Python error text e.ReportException(); } return Rejected; } -ViewProviderDocumentObject * -ViewProviderPythonFeatureImp::getLinkedViewProvider(bool recursive) const +bool ViewProviderPythonFeatureImp::getLinkedViewProvider( + ViewProviderDocumentObject *&vp, std::string *subname, bool recursive) const { - _FC_PY_CALL_CHECK(getLinkedViewProvider,return(0)); + _FC_PY_CALL_CHECK(getLinkedViewProvider,return(false)); Base::PyGILStateLocker lock; try { @@ -1298,19 +1400,33 @@ ViewProviderPythonFeatureImp::getLinkedViewProvider(bool recursive) const args.setItem(0,Py::Boolean(recursive)); Py::Object res(Base::pyCall(py_getLinkedViewProvider.ptr(),args.ptr())); if(res.isNone()) - return 0; - if(PyObject_TypeCheck(res.ptr(),&ViewProviderDocumentObjectPy::Type)) - return static_cast( + return true; + if(PyObject_TypeCheck(res.ptr(),&ViewProviderDocumentObjectPy::Type)) { + vp = static_cast( res.ptr())->getViewProviderDocumentObjectPtr(); - - FC_ERR("getLinkedViewProvider(): invalid return object type '" - << res.ptr()->ob_type->tp_name << "'"); + } else if (PySequence_Check(res.ptr()) && PySequence_Length(res.ptr())==2) { + Py::Sequence seq(res); + Py::Object item0(seq[0].ptr()); + Py::Object item1(seq[0].ptr()); + if(PyObject_TypeCheck(item0.ptr(), &ViewProviderDocumentObjectPy::Type) && item1.isString()) { + if(subname) + *subname = Py::String(item1).as_std_string("utf-8"); + vp = static_cast( + item0.ptr())->getViewProviderDocumentObjectPtr(); + } + } else + FC_ERR("getLinkedViewProvider(): invalid return type, expects ViewObject or (ViewObject, subname)"); + return true; } catch (Py::Exception&) { + if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { + PyErr_Clear(); + return false; + } Base::PyException e; // extract the Python error text e.ReportException(); } - return 0; + return true; } diff --git a/src/Gui/ViewProviderPythonFeature.h b/src/Gui/ViewProviderPythonFeature.h index d95ad42a6e..c4de2ff499 100644 --- a/src/Gui/ViewProviderPythonFeature.h +++ b/src/Gui/ViewProviderPythonFeature.h @@ -54,19 +54,19 @@ public: // Returns the icon QIcon getIcon() const; - std::vector claimChildren(std::vector&&) const; - bool useNewSelectionModel() const; + bool claimChildren(std::vector&) const; + ValueT useNewSelectionModel() const; ValueT getElementPicked(const SoPickedPoint *pp, std::string &subname) const; - std::string getElement(const SoDetail *det) const; - SoDetail* getDetail(const char*) const; + bool getElement(const SoDetail *det, std::string &) const; + bool getDetail(const char*, SoDetail *&det) const; ValueT getDetailPath(const char *name, SoFullPath *path, bool append, SoDetail *&det) const; std::vector getSelectionShape(const char* Element) const; ValueT setEdit(int ModNum); ValueT unsetEdit(int ModNum); - bool setEditViewer(View3DInventorViewer*, int ModNum); - bool unsetEditViewer(View3DInventorViewer*); + ValueT setEditViewer(View3DInventorViewer*, int ModNum); + ValueT unsetEditViewer(View3DInventorViewer*); ValueT doubleClicked(void); - void setupContextMenu(QMenu* menu); + bool setupContextMenu(QMenu* menu); /** @name Update data methods*/ //@{ @@ -75,16 +75,16 @@ public: void onChanged(const App::Property* prop); void startRestoring(); void finishRestoring(); - bool onDelete(const std::vector & sub); + ValueT onDelete(const std::vector & sub); ValueT canDelete(App::DocumentObject *obj) const; //@} /** @name Display methods */ //@{ /// Returns true if the icon must always appear enabled in the tree view - bool isShow() const; + ValueT isShow() const; /// get the default display mode - const char* getDefaultDisplayMode() const; + bool getDefaultDisplayMode(std::string &mode) const; /// returns a list of all possible modes std::vector getDisplayModes(void) const; /// set the display mode @@ -113,14 +113,15 @@ public: ValueT canDropObjectEx(App::DocumentObject *obj, App::DocumentObject *, const char *,const std::vector &elements) const; /** Add an object with full quanlified name to the view provider by drag and drop */ - ValueT dropObjectEx(App::DocumentObject *obj, App::DocumentObject *, + bool dropObjectEx(App::DocumentObject *obj, App::DocumentObject *, const char *, const std::vector &elements, std::string &ret); ValueT replaceObject(App::DocumentObject *, App::DocumentObject *); //@} - ViewProviderDocumentObject *getLinkedViewProvider(bool recursive) const; + bool getLinkedViewProvider(ViewProviderDocumentObject *&res, + std::string *subname, bool recursive) const; - bool canAddToSceneGraph() const; + ValueT canAddToSceneGraph() const; bool getDropPrefix(std::string &prefix) const; @@ -214,7 +215,10 @@ public: } std::vector claimChildren() const override { - return imp->claimChildren(ViewProviderT::claimChildren()); + std::vector res; + if(!imp->claimChildren(res)) + return ViewProviderT::claimChildren(); + return res; } /** @name Nodes */ @@ -234,7 +238,14 @@ public: /** @name Selection handling */ //@{ virtual bool useNewSelectionModel() const override { - return imp->useNewSelectionModel(); + switch(imp->useNewSelectionModel()) { + case ViewProviderPythonFeatureImp::Accepted: + return true; + case ViewProviderPythonFeatureImp::Rejected: + return false; + default: + return ViewProviderT::useNewSelectionModel(); + } } virtual bool getElementPicked(const SoPickedPoint *pp, std::string &subname) const override { auto ret = imp->getElementPicked(pp,subname); @@ -245,13 +256,15 @@ public: return false; } virtual std::string getElement(const SoDetail *det) const override { - std::string name = imp->getElement(det); - if (!name.empty()) return name; - return ViewProviderT::getElement(det); + std::string name; + if(!imp->getElement(det,name)) + return ViewProviderT::getElement(det); + return name; } virtual SoDetail* getDetail(const char* name) const override { - SoDetail* det = imp->getDetail(name); - if (det) return det; + SoDetail *det = 0; + if(!imp->getDetail(name,det)) + return det; return ViewProviderT::getDetail(name); } virtual bool getDetailPath(const char *name, SoFullPath *path, bool append,SoDetail *&det) const override { @@ -280,9 +293,14 @@ public: ViewProviderT::getTaskViewContent(c); } virtual bool onDelete(const std::vector & sub) override { - bool ok = imp->onDelete(sub); - if (!ok) return ok; - return ViewProviderT::onDelete(sub); + switch(imp->onDelete(sub)) { + case ViewProviderPythonFeatureImp::Accepted: + return true; + case ViewProviderPythonFeatureImp::Rejected: + return false; + default: + return ViewProviderT::onDelete(sub); + } } virtual bool canDelete(App::DocumentObject *obj) const override { switch(imp->canDelete(obj)) { @@ -405,13 +423,8 @@ public: { App::AutoTransaction committer; std::string ret; - switch (imp->dropObjectEx(obj,owner,subname,elements,ret)) { - case ViewProviderPythonFeatureImp::NotImplemented: + if(!imp->dropObjectEx(obj,owner,subname,elements,ret)) ret = ViewProviderT::dropObjectEx(obj,owner,subname,elements); - break; - default: - break; - } return ret; } //@} @@ -420,13 +433,21 @@ public: //@{ /// Returns true if the icon must always appear enabled in the tree view virtual bool isShow() const override { - bool ok = imp->isShow(); - if (ok) return ok; - return ViewProviderT::isShow(); + switch(imp->isShow()) { + case ViewProviderPythonFeatureImp::Accepted: + return true; + case ViewProviderPythonFeatureImp::Rejected: + return false; + default: + return ViewProviderT::isShow(); + } } /// get the default display mode virtual const char* getDefaultDisplayMode() const override { - return imp->getDefaultDisplayMode(); + defaultMode.clear(); + if(imp->getDefaultDisplayMode(defaultMode)) + return defaultMode.c_str(); + return ViewProviderT::getDefaultDisplayMode(); } /// returns a list of all possible modes virtual std::vector getDisplayModes(void) const override { @@ -459,7 +480,14 @@ public: } virtual bool canAddToSceneGraph() const override { - return ViewProviderT::canAddToSceneGraph() && imp->canAddToSceneGraph(); + switch(imp->canAddToSceneGraph()) { + case ViewProviderPythonFeatureImp::Accepted: + return true; + case ViewProviderPythonFeatureImp::Rejected: + return false; + default: + return ViewProviderT::canAddToSceneGraph(); + } } protected: @@ -540,28 +568,19 @@ protected: } } -//FIXME: ViewProviderPythonFeatureT hides overloaded virtual functions -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Woverloaded-virtual" -#endif - - virtual ViewProviderDocumentObject *getLinkedViewProvider(bool recursive=false) const { - auto res = imp->getLinkedViewProvider(recursive); - if(!res) - res = ViewProviderT::getLinkedViewProvider(); + virtual ViewProviderDocumentObject *getLinkedViewProvider( + std::string *subname=0, bool recursive=false) const override{ + ViewProviderDocumentObject *res = 0; + if(!imp->getLinkedViewProvider(res, subname, recursive)) + res = ViewProviderT::getLinkedViewProvider(subname,recursive); return res; } -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - public: virtual void setupContextMenu(QMenu* menu, QObject* recipient, const char* member) override { - ViewProviderT::setupContextMenu(menu, recipient, member); - imp->setupContextMenu(menu); + if(!imp->setupContextMenu(menu)) + ViewProviderT::setupContextMenu(menu, recipient, member); } protected: @@ -586,6 +605,7 @@ protected: private: ViewProviderPythonFeatureImp* imp; App::PropertyPythonObject Proxy; + mutable std::string defaultMode; std::string viewerMode; bool _attached; };