From 292f6dcaa755d6e3cfced8666e22ae67c437d053 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 21 Nov 2021 18:59:28 +0100 Subject: [PATCH] Gui: make AbstractSplitViewPy acting as sub-class of MDIViewPy --- src/Gui/SplitView3DInventor.cpp | 114 +++++++++++++++++++++----------- src/Gui/SplitView3DInventor.h | 14 ++-- 2 files changed, 86 insertions(+), 42 deletions(-) diff --git a/src/Gui/SplitView3DInventor.cpp b/src/Gui/SplitView3DInventor.cpp index 7db754c7dd..78a7102da5 100644 --- a/src/Gui/SplitView3DInventor.cpp +++ b/src/Gui/SplitView3DInventor.cpp @@ -38,6 +38,7 @@ #include "Application.h" #include "NavigationStyle.h" #include "View3DPy.h" +#include using namespace Gui; @@ -47,7 +48,7 @@ TYPESYSTEM_SOURCE_ABSTRACT(Gui::AbstractSplitView,Gui::MDIView) AbstractSplitView::AbstractSplitView(Gui::Document* pcDocument, QWidget* parent, Qt::WindowFlags wflags) : MDIView(pcDocument,parent, wflags) { - _viewerPy = 0; + _viewerPy = nullptr; // important for highlighting setMouseTracking(true); } @@ -59,7 +60,7 @@ AbstractSplitView::~AbstractSplitView() delete *it; } if (_viewerPy) { - static_cast(_viewerPy)->_view = 0; + Base::PyGILStateLocker lock; Py_DECREF(_viewerPy); } } @@ -72,6 +73,12 @@ void AbstractSplitView::deleteSelf() MDIView::deleteSelf(); } +void AbstractSplitView::viewAll() +{ + for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) + (*it)->viewAll(); +} + bool AbstractSplitView::containsViewProvider(const ViewProvider* vp) const { for (auto it = _viewer.begin(); it != _viewer.end(); ++it) { @@ -307,8 +314,7 @@ const char *AbstractSplitView::getName(void) const bool AbstractSplitView::onMsg(const char* pMsg, const char**) { if (strcmp("ViewFit",pMsg) == 0 ) { - for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) - (*it)->viewAll(); + viewAll(); return true; } else if (strcmp("ViewBottom",pMsg) == 0) { @@ -439,6 +445,8 @@ void AbstractSplitViewPy::init_type() behaviors().doc("Python binding class for the Inventor viewer class"); // you must have overwritten the virtual functions behaviors().supportRepr(); + behaviors().supportGetattr(); + behaviors().supportSetattr(); behaviors().supportSequenceType(); add_varargs_method("fitAll",&AbstractSplitViewPy::fitAll,"fitAll()"); @@ -452,10 +460,12 @@ void AbstractSplitViewPy::init_type() add_varargs_method("viewIsometric",&AbstractSplitViewPy::viewIsometric,"viewIsometric()"); add_varargs_method("getViewer",&AbstractSplitViewPy::getViewer,"getViewer(index)"); add_varargs_method("close",&AbstractSplitViewPy::close,"close()"); + add_varargs_method("cast_to_base", &AbstractSplitViewPy::cast_to_base, "cast_to_base() cast to MDIView class"); + behaviors().readyType(); } AbstractSplitViewPy::AbstractSplitViewPy(AbstractSplitView *vi) - : _view(vi) + : base(vi) { } @@ -463,30 +473,61 @@ AbstractSplitViewPy::~AbstractSplitViewPy() { } -void AbstractSplitViewPy::testExistence() +Py::Object AbstractSplitViewPy::cast_to_base(const Py::Tuple&) { - if (!(_view && _view->getViewer(0))) - throw Py::RuntimeError("Object already deleted"); + return Gui::MDIViewPy::create(base.getMDIViewPtr()); } Py::Object AbstractSplitViewPy::repr() { - std::string s; std::ostringstream s_out; - if (!_view) + if (!getSplitViewPtr()) throw Py::RuntimeError("Cannot print representation of deleted object"); s_out << "AbstractSplitView"; return Py::String(s_out.str()); } +// Since with PyCXX it's not possible to make a sub-class of MDIViewPy +// a trick is to use MDIViewPy as class member and override getattr() to +// join the attributes of both classes. This way all methods of MDIViewPy +// appear for SheetViewPy, too. +Py::Object AbstractSplitViewPy::getattr(const char * attr) +{ + getSplitViewPtr(); + std::string name( attr ); + if (name == "__dict__" || name == "__class__") { + Py::Dict dict_self(BaseType::getattr("__dict__")); + Py::Dict dict_base(base.getattr("__dict__")); + for (auto it : dict_base) { + dict_self.setItem(it.first, it.second); + } + return dict_self; + } + + try { + return BaseType::getattr(attr); + } + catch (Py::AttributeError& e) { + e.clear(); + return base.getattr(attr); + } +} + +AbstractSplitView* AbstractSplitViewPy::getSplitViewPtr() +{ + AbstractSplitView* view = qobject_cast(base.getMDIViewPtr()); + if (!(view && view->getViewer(0))) + throw Py::RuntimeError("Object already deleted"); + return view; +} + Py::Object AbstractSplitViewPy::fitAll(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewFit", 0); + getSplitViewPtr()->onMsg("ViewFit", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -504,10 +545,9 @@ Py::Object AbstractSplitViewPy::viewBottom(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewBottom", 0); + getSplitViewPtr()->onMsg("ViewBottom", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -526,10 +566,9 @@ Py::Object AbstractSplitViewPy::viewFront(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewFront", 0); + getSplitViewPtr()->onMsg("ViewFront", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -548,10 +587,9 @@ Py::Object AbstractSplitViewPy::viewLeft(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewLeft", 0); + getSplitViewPtr()->onMsg("ViewLeft", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -570,10 +608,9 @@ Py::Object AbstractSplitViewPy::viewRear(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewRear", 0); + getSplitViewPtr()->onMsg("ViewRear", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -592,10 +629,9 @@ Py::Object AbstractSplitViewPy::viewRight(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewRight", 0); + getSplitViewPtr()->onMsg("ViewRight", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -614,10 +650,9 @@ Py::Object AbstractSplitViewPy::viewTop(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewTop", 0); + getSplitViewPtr()->onMsg("ViewTop", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -636,10 +671,9 @@ Py::Object AbstractSplitViewPy::viewIsometric(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); try { - _view->onMsg("ViewAxo", 0); + getSplitViewPtr()->onMsg("ViewAxo", 0); } catch (const Base::Exception& e) { throw Py::RuntimeError(e.what()); @@ -659,10 +693,9 @@ Py::Object AbstractSplitViewPy::getViewer(const Py::Tuple& args) int viewIndex; if (!PyArg_ParseTuple(args.ptr(), "i", &viewIndex)) throw Py::Exception(); - testExistence(); try { - Gui::View3DInventorViewer* view = _view->getViewer(viewIndex); + Gui::View3DInventorViewer* view = getSplitViewPtr()->getViewer(viewIndex); if (!view) throw Py::IndexError("Index out of range"); return Py::asObject(view->getPyObject()); @@ -673,6 +706,10 @@ Py::Object AbstractSplitViewPy::getViewer(const Py::Tuple& args) catch (const std::exception& e) { throw Py::RuntimeError(e.what()); } + catch (const Py::Exception&) { + // re-throw + throw; + } catch(...) { throw Py::RuntimeError("Unknown C++ exception"); } @@ -680,29 +717,28 @@ Py::Object AbstractSplitViewPy::getViewer(const Py::Tuple& args) Py::Object AbstractSplitViewPy::sequence_item(ssize_t viewIndex) { - testExistence(); - if (viewIndex >= _view->getSize() || viewIndex < 0) + AbstractSplitView* view = getSplitViewPtr(); + if (viewIndex >= view->getSize() || viewIndex < 0) throw Py::IndexError("Index out of range"); - PyObject* viewer = _view->getViewer(viewIndex)->getPyObject(); + PyObject* viewer = view->getViewer(viewIndex)->getPyObject(); return Py::asObject(viewer); } int AbstractSplitViewPy::sequence_length() { - testExistence(); - return _view->getSize(); + AbstractSplitView* view = getSplitViewPtr(); + return view->getSize(); } Py::Object AbstractSplitViewPy::close(const Py::Tuple& args) { if (!PyArg_ParseTuple(args.ptr(), "")) throw Py::Exception(); - testExistence(); - _view->close(); - if (_view->parentWidget()) - _view->parentWidget()->deleteLater(); - _view = 0; + AbstractSplitView* view = getSplitViewPtr(); + view->close(); + if (view->parentWidget()) + view->parentWidget()->deleteLater(); return Py::None(); } @@ -791,3 +827,5 @@ SplitView3DInventor::SplitView3DInventor(int views, Gui::Document* pcDocument, Q SplitView3DInventor::~SplitView3DInventor() { } + +#include "moc_SplitView3DInventor.cpp" diff --git a/src/Gui/SplitView3DInventor.h b/src/Gui/SplitView3DInventor.h index bbbdd6d3fd..da0bfb56a6 100644 --- a/src/Gui/SplitView3DInventor.h +++ b/src/Gui/SplitView3DInventor.h @@ -25,6 +25,7 @@ #define GUI_SPLITVIEW3DINVENTOR_H #include "MDIView.h" +#include "MDIViewPy.h" #include #include @@ -39,6 +40,8 @@ class AbstractSplitViewPy; */ class GuiExport AbstractSplitView : public MDIView, public ParameterGrp::ObserverType { + Q_OBJECT + TYPESYSTEM_HEADER(); public: @@ -53,6 +56,7 @@ public: virtual void OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::MessageType Reason); virtual void onUpdate(void); virtual void deleteSelf(); + virtual void viewAll(); View3DInventorViewer *getViewer(unsigned int) const; void setOverrideCursor(const QCursor&); @@ -75,12 +79,16 @@ protected: class AbstractSplitViewPy : public Py::PythonExtension { public: - static void init_type(void); // announce properties and methods + using BaseType = Py::PythonExtension; + static void init_type(); // announce properties and methods AbstractSplitViewPy(AbstractSplitView *vi); ~AbstractSplitViewPy(); + AbstractSplitView* getSplitViewPtr(); Py::Object repr(); + Py::Object getattr(const char *); + Py::Object cast_to_base(const Py::Tuple&); Py::Object fitAll(const Py::Tuple&); Py::Object viewBottom(const Py::Tuple&); @@ -96,9 +104,7 @@ public: int sequence_length(); private: - AbstractSplitView* _view; - friend class AbstractSplitView; - void testExistence(); + Gui::MDIViewPy base; }; /** The SplitView3DInventor class allows to create a window with two or more Inventor views.