diff --git a/src/Gui/Selection/Selection.cpp b/src/Gui/Selection/Selection.cpp index 0c9b8c65a8..801be68e77 100644 --- a/src/Gui/Selection/Selection.cpp +++ b/src/Gui/Selection/Selection.cpp @@ -25,6 +25,7 @@ #ifndef _PreComp_ # include +# include # include # include #endif @@ -52,6 +53,7 @@ #include "SelectionFilterPy.h" #include "SelectionObserverPython.h" #include "Tree.h" +#include "ViewProvider.h" #include "ViewProviderDocumentObject.h" @@ -391,6 +393,25 @@ void SelectionSingleton::enablePickedList(bool enable) } } +static void notifyDocumentObjectViewProvider(const SelectionChanges& changes) { + const auto* doc = App::GetApplication().getDocument(changes.pDocName); + if (!doc) { + return; + } + + const auto* obj = doc->getObject(changes.pObjectName); + if (!obj) { + return; + } + + auto* vp = Application::Instance->getViewProvider(obj); + if (!vp) { + return; + } + + vp->onSelectionChanged(changes); +} + void SelectionSingleton::notify(SelectionChanges &&Chng) { if(Notifying) { @@ -401,7 +422,7 @@ void SelectionSingleton::notify(SelectionChanges &&Chng) NotificationQueue.push_back(std::move(Chng)); while(!NotificationQueue.empty()) { const auto &msg = NotificationQueue.front(); - bool notify; + bool notify = false; switch(msg.Type) { case SelectionChanges::AddSelection: notify = isSelected(msg.pDocName, msg.pObjectName, msg.pSubName, ResolveMode::NoResolve); @@ -420,6 +441,9 @@ void SelectionSingleton::notify(SelectionChanges &&Chng) notify = true; } if(notify) { + // Notify the view provider of the object. + notifyDocumentObjectViewProvider(msg); + Notify(msg); try { signalSelectionChanged(msg); @@ -1454,6 +1478,21 @@ void SelectionSingleton::clearCompleteSelection(bool clearPreSelect) clearPreSelect?"Gui.Selection.clearSelection()" :"Gui.Selection.clearSelection(False)"); + // Send the clear selection notification to all view providers associated with the + // objects being deselected. + + std::set viewProviders; + for (_SelObj& sel : _SelList) { + if (auto vp = Application::Instance->getViewProvider(sel.pObject)) { + viewProviders.insert(vp); + } + } + + for (auto& vp : viewProviders) { + SelectionChanges Chng(SelectionChanges::ClrSelection); + vp->onSelectionChanged(Chng); + } + _SelList.clear(); SelectionChanges Chng(SelectionChanges::ClrSelection); diff --git a/src/Gui/Selection/SelectionObserverPython.cpp b/src/Gui/Selection/SelectionObserverPython.cpp index e1f670df28..2d41f5c45a 100644 --- a/src/Gui/Selection/SelectionObserverPython.cpp +++ b/src/Gui/Selection/SelectionObserverPython.cpp @@ -32,37 +32,29 @@ using namespace Gui; std::vector SelectionObserverPython::_instances; -SelectionObserverPython::SelectionObserverPython(const Py::Object& obj, ResolveMode resolve) - : SelectionObserver(true, resolve), inst(obj) +void SelectionObserverPythonHandler::init(PyObject* obj) { + this->inst = obj; + #undef FC_PY_ELEMENT -#define FC_PY_ELEMENT(_name) FC_PY_GetCallable(obj.ptr(),#_name,py_##_name); +#define FC_PY_ELEMENT(_name) FC_PY_GetCallable(obj,#_name,py_##_name); FC_PY_SEL_OBSERVER } -SelectionObserverPython::~SelectionObserverPython() = default; - -void SelectionObserverPython::addObserver(const Py::Object& obj, ResolveMode resolve) +SelectionObserverPythonHandler::~SelectionObserverPythonHandler() { - _instances.push_back(new SelectionObserverPython(obj, resolve)); -} +#undef FC_PY_ELEMENT +#define FC_PY_ELEMENT(_name) py_##_name = Py::None(); -void SelectionObserverPython::removeObserver(const Py::Object& obj) -{ - SelectionObserverPython* obs=nullptr; - for (std::vector::iterator it = - _instances.begin(); it != _instances.end(); ++it) { - if ((*it)->inst == obj) { - obs = *it; - _instances.erase(it); - break; - } + try { + FC_PY_SEL_OBSERVER + } + catch (Py::Exception& e) { + e.clear(); } - - delete obs; } -void SelectionObserverPython::onSelectionChanged(const SelectionChanges& msg) +void SelectionObserverPythonHandler::handleSelectionChanged(const SelectionChanges& msg) { switch (msg.Type) { @@ -92,7 +84,7 @@ void SelectionObserverPython::onSelectionChanged(const SelectionChanges& msg) } } -void SelectionObserverPython::pickedListChanged() +void SelectionObserverPythonHandler::pickedListChanged() { if(py_pickedListChanged.isNone()) return; @@ -106,7 +98,7 @@ void SelectionObserverPython::pickedListChanged() } } -void SelectionObserverPython::addSelection(const SelectionChanges& msg) +void SelectionObserverPythonHandler::addSelection(const SelectionChanges& msg) { if(py_addSelection.isNone()) return; @@ -129,7 +121,7 @@ void SelectionObserverPython::addSelection(const SelectionChanges& msg) } } -void SelectionObserverPython::removeSelection(const SelectionChanges& msg) +void SelectionObserverPythonHandler::removeSelection(const SelectionChanges& msg) { if(py_removeSelection.isNone()) return; @@ -147,7 +139,7 @@ void SelectionObserverPython::removeSelection(const SelectionChanges& msg) } } -void SelectionObserverPython::setSelection(const SelectionChanges& msg) +void SelectionObserverPythonHandler::setSelection(const SelectionChanges& msg) { if(py_setSelection.isNone()) return; @@ -163,7 +155,7 @@ void SelectionObserverPython::setSelection(const SelectionChanges& msg) } } -void SelectionObserverPython::clearSelection(const SelectionChanges& msg) +void SelectionObserverPythonHandler::clearSelection(const SelectionChanges& msg) { if(py_clearSelection.isNone()) return; @@ -179,7 +171,7 @@ void SelectionObserverPython::clearSelection(const SelectionChanges& msg) } } -void SelectionObserverPython::setPreselection(const SelectionChanges& msg) +void SelectionObserverPythonHandler::setPreselection(const SelectionChanges& msg) { if(py_setPreselection.isNone()) return; @@ -197,7 +189,7 @@ void SelectionObserverPython::setPreselection(const SelectionChanges& msg) } } -void SelectionObserverPython::removePreselection(const SelectionChanges& msg) +void SelectionObserverPythonHandler::removePreselection(const SelectionChanges& msg) { if(py_removePreselection.isNone()) return; @@ -214,3 +206,36 @@ void SelectionObserverPython::removePreselection(const SelectionChanges& msg) e.ReportException(); } } + + +SelectionObserverPython::SelectionObserverPython(const Py::Object& obj, ResolveMode resolve) + : SelectionObserver(true, resolve) +{ + this->init(obj.ptr()); +} + +SelectionObserverPython::~SelectionObserverPython() = default; + +void SelectionObserverPython::addObserver(const Py::Object& obj, ResolveMode resolve) +{ + _instances.push_back(new SelectionObserverPython(obj, resolve)); +} + +void SelectionObserverPython::removeObserver(const Py::Object& obj) +{ + SelectionObserverPython* obs=nullptr; + for (auto it =_instances.begin(); it != _instances.end(); ++it) { + if ((*it)->inst == obj) { + obs = *it; + _instances.erase(it); + break; + } + } + + delete obs; +} + +void SelectionObserverPython::onSelectionChanged(const SelectionChanges& msg) +{ + handleSelectionChanged(msg); +} diff --git a/src/Gui/Selection/SelectionObserverPython.h b/src/Gui/Selection/SelectionObserverPython.h index 3f5643487e..5eed3a217c 100644 --- a/src/Gui/Selection/SelectionObserverPython.h +++ b/src/Gui/Selection/SelectionObserverPython.h @@ -30,26 +30,18 @@ namespace Gui { -/** - * The SelectionObserverPython class implements a mechanism to register - * a Python class instance implementing the required interface in order - * to be notified on selection changes. - * - * @author Werner Mayer - */ -class GuiExport SelectionObserverPython : public SelectionObserver +class GuiExport SelectionObserverPythonHandler { public: /// Constructor - explicit SelectionObserverPython(const Py::Object& obj, ResolveMode resolve = ResolveMode::OldStyleElement); - ~SelectionObserverPython() override; + explicit SelectionObserverPythonHandler() = default; + virtual ~SelectionObserverPythonHandler(); - static void addObserver(const Py::Object& obj, ResolveMode resolve = ResolveMode::OldStyleElement); - static void removeObserver(const Py::Object& obj); + void init(PyObject* obj); + void handleSelectionChanged(const SelectionChanges& msg); -private: - void onSelectionChanged(const SelectionChanges& msg) override; +protected: void addSelection(const SelectionChanges&); void removeSelection(const SelectionChanges&); void setSelection(const SelectionChanges&); @@ -59,7 +51,8 @@ private: void pickedListChanged(); private: - Py::Object inst; + + PyObject* inst{nullptr}; #define FC_PY_SEL_OBSERVER \ FC_PY_ELEMENT(onSelectionChanged) \ @@ -75,7 +68,30 @@ private: #define FC_PY_ELEMENT(_name) Py::Object py_##_name; FC_PY_SEL_OBSERVER +}; +/** + * The SelectionObserverPython class implements a mechanism to register + * a Python class instance implementing the required interface in order + * to be notified on selection changes. + * + * @author Werner Mayer + */ +class GuiExport SelectionObserverPython : public SelectionObserverPythonHandler, public SelectionObserver +{ + +public: + /// Constructor + explicit SelectionObserverPython(const Py::Object& obj, ResolveMode resolve = ResolveMode::OldStyleElement); + ~SelectionObserverPython() override; + + static void addObserver(const Py::Object& obj, ResolveMode resolve = ResolveMode::OldStyleElement); + static void removeObserver(const Py::Object& obj); + +private: + void onSelectionChanged(const SelectionChanges& msg) override; + + Py::Object inst; static std::vector _instances; }; diff --git a/src/Gui/ViewProvider.h b/src/Gui/ViewProvider.h index 4f394a0496..7b199119a2 100644 --- a/src/Gui/ViewProvider.h +++ b/src/Gui/ViewProvider.h @@ -74,6 +74,7 @@ class View3DInventorViewer; class ViewProviderPy; class ObjectItem; class MDIView; +class SelectionChanges; enum ViewStatus { UpdateData = 0, @@ -164,6 +165,8 @@ public: /// indicates if the ViewProvider use the new Selection model virtual bool useNewSelectionModel() const; virtual bool isSelectable() const {return true;} + /// called when the selection changes for the view provider + virtual void onSelectionChanged(const SelectionChanges&) {} /// return a hit element given the picked point which contains the full node path virtual bool getElementPicked(const SoPickedPoint *, std::string &subname) const; /// return a hit element to the selection path or 0 diff --git a/src/Gui/ViewProviderFeaturePython.cpp b/src/Gui/ViewProviderFeaturePython.cpp index 7b24735582..23c4c1383c 100644 --- a/src/Gui/ViewProviderFeaturePython.cpp +++ b/src/Gui/ViewProviderFeaturePython.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include "ViewProviderFeaturePython.h" #include "Application.h" @@ -44,6 +45,7 @@ #include "PythonWrapper.h" #include "View3DInventorViewer.h" #include "ViewProviderDocumentObjectPy.h" +#include "Selection.h" FC_LOG_LEVEL_INIT("ViewProviderFeaturePython", true, true) @@ -74,6 +76,8 @@ ViewProviderFeaturePythonImp::~ViewProviderFeaturePythonImp() catch (Py::Exception& e) { e.clear(); } + + this->selectionObserver.~SelectionObserverPythonHandler(); } void ViewProviderFeaturePythonImp::init(PyObject *pyobj) { @@ -84,6 +88,8 @@ void ViewProviderFeaturePythonImp::init(PyObject *pyobj) { #define FC_PY_ELEMENT(_name) FC_PY_ELEMENT_INIT(_name) FC_PY_VIEW_OBJECT + + this->selectionObserver.init(pyobj); } #define FC_PY_CALL_CHECK(_name) _FC_PY_CALL_CHECK(_name,return(NotImplemented)) @@ -202,6 +208,10 @@ ViewProviderFeaturePythonImp::useNewSelectionModel() const return Accepted; } +void ViewProviderFeaturePythonImp::onSelectionChanged(const SelectionChanges& changes) { + this->selectionObserver.handleSelectionChanged(changes); +} + bool ViewProviderFeaturePythonImp::getElement(const SoDetail *det, std::string &res) const { _FC_PY_CALL_CHECK(getElement,return(false)); diff --git a/src/Gui/ViewProviderFeaturePython.h b/src/Gui/ViewProviderFeaturePython.h index 023247019e..cc2737db8f 100644 --- a/src/Gui/ViewProviderFeaturePython.h +++ b/src/Gui/ViewProviderFeaturePython.h @@ -26,17 +26,19 @@ #include #include #include +#include #include "ViewProviderGeometryObject.h" #include "Document.h" - class SoSensor; class SoDragger; class SoNode; namespace Gui { +class SelectionChanges; + class GuiExport ViewProviderFeaturePythonImp { public: @@ -55,6 +57,7 @@ public: QIcon getIcon() const; bool claimChildren(std::vector&) const; ValueT useNewSelectionModel() const; + void onSelectionChanged(const SelectionChanges&); ValueT getElementPicked(const SoPickedPoint *pp, std::string &subname) const; bool getElement(const SoDetail *det, std::string &) const; bool getDetail(const char*, SoDetail *&det) const; @@ -130,6 +133,7 @@ public: private: ViewProviderDocumentObject* object; App::PropertyPythonObject &Proxy; + SelectionObserverPythonHandler selectionObserver; bool has__object__{false}; #define FC_PY_VIEW_OBJECT \ @@ -253,6 +257,10 @@ public: return ViewProviderT::useNewSelectionModel(); } } + /// called when the selection changes for the view provider + void onSelectionChanged(const SelectionChanges& changes) override { + return imp->onSelectionChanged(changes); + } bool getElementPicked(const SoPickedPoint *pp, std::string &subname) const override { auto ret = imp->getElementPicked(pp,subname); if(ret == ViewProviderFeaturePythonImp::NotImplemented)