Merge pull request #19084 from tritao/gui-selection-viewproviderfeaturepy
Gui: Provide `ViewProviderFeaturePython` selection callbacks
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <array>
|
||||
# include <set>
|
||||
# include <boost/algorithm/string/predicate.hpp>
|
||||
# include <QApplication>
|
||||
#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<ViewProvider*> 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);
|
||||
|
||||
@@ -32,37 +32,29 @@ using namespace Gui;
|
||||
|
||||
std::vector<SelectionObserverPython*> 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<SelectionObserverPython*>::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);
|
||||
}
|
||||
|
||||
@@ -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<SelectionObserverPython*> _instances;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <App/DocumentObjectPy.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <CXX/Python3/Objects.hxx>
|
||||
|
||||
#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));
|
||||
|
||||
@@ -26,17 +26,19 @@
|
||||
#include <App/AutoTransaction.h>
|
||||
#include <App/PropertyPythonObject.h>
|
||||
#include <App/FeaturePython.h>
|
||||
#include <Gui/Selection/SelectionObserverPython.h>
|
||||
|
||||
#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<App::DocumentObject*>&) 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)
|
||||
|
||||
Reference in New Issue
Block a user