Python feature/observer related changes

* Add new API and signal handler in document observer

* Pre initialize python handler function to improve performance. In
  case Python code use dynamic patching, i.e. add class method at
  runtime (which is rare and should be discouraged), the python feature
  can be re-initialized by simply assign proeprty Proxy again.

* Add property tracking in DocumentObjectT

* WidgetFactory adds support for accepting python QIcon, which is used
  by ViewProviderPythonFeature
This commit is contained in:
Zheng, Lei
2019-07-11 13:57:53 +08:00
committed by wmayer
parent f7edaabe43
commit ad57821cf9
12 changed files with 1875 additions and 950 deletions

View File

@@ -60,57 +60,36 @@ void DocumentObserverPython::removeObserver(const Py::Object& obj)
DocumentObserverPython::DocumentObserverPython(const Py::Object& obj) : inst(obj)
{
this->connectApplicationCreatedDocument = Gui::Application::Instance->signalNewDocument.connect(boost::bind
(&DocumentObserverPython::slotCreatedDocument, this, _1));
this->connectApplicationDeletedDocument = Gui::Application::Instance->signalDeleteDocument.connect(boost::bind
(&DocumentObserverPython::slotDeletedDocument, this, _1));
this->connectApplicationRelabelDocument = Gui::Application::Instance->signalRelabelDocument.connect(boost::bind
(&DocumentObserverPython::slotRelabelDocument, this, _1));
this->connectApplicationRenameDocument = Gui::Application::Instance->signalRenameDocument.connect(boost::bind
(&DocumentObserverPython::slotRelabelDocument, this, _1));
this->connectApplicationActivateDocument = Gui::Application::Instance->signalActiveDocument.connect(boost::bind
(&DocumentObserverPython::slotActivateDocument, this, _1));
#define signalCreatedDocument signalNewDocument
#define signalCreatedObject signalNewObject
#define signalDeletedDocument signalDeleteDocument
#define signalActivateDocument signalActiveDocument
this->connectDocumentCreatedObject = Gui::Application::Instance->signalNewObject.connect(boost::bind
(&DocumentObserverPython::slotCreatedObject, this, _1));
this->connectDocumentDeletedObject = Gui::Application::Instance->signalDeletedObject.connect(boost::bind
(&DocumentObserverPython::slotDeletedObject, this, _1));
this->connectDocumentChangedObject = Gui::Application::Instance->signalChangedObject.connect(boost::bind
(&DocumentObserverPython::slotChangedObject, this, _1, _2));
this->connectDocumentObjectInEdit = Gui::Application::Instance->signalInEdit.connect(boost::bind
(&DocumentObserverPython::slotInEdit, this, _1));
this->connectDocumentObjectResetEdit = Gui::Application::Instance->signalResetEdit.connect(boost::bind
(&DocumentObserverPython::slotResetEdit, this, _1));
#undef FC_PY_ELEMENT
#define FC_PY_ELEMENT(_name,...) \
FC_PY_GetCallable(obj.ptr(),"slot" #_name, py##_name);\
if(!py##_name.isNone())\
connect##_name = Application::Instance->signal##_name.connect(\
boost::bind(&DocumentObserverPython::slot##_name, this, ## __VA_ARGS__));
FC_PY_GDOC_OBSERVER
}
DocumentObserverPython::~DocumentObserverPython()
{
this->connectApplicationCreatedDocument.disconnect();
this->connectApplicationDeletedDocument.disconnect();
this->connectApplicationRelabelDocument.disconnect();
this->connectApplicationRenameDocument.disconnect();
this->connectApplicationActivateDocument.disconnect();
#undef FC_PY_ELEMENT
#define FC_PY_ELEMENT(_name,...) connect##_name.disconnect();
this->connectDocumentCreatedObject.disconnect();
this->connectDocumentDeletedObject.disconnect();
this->connectDocumentChangedObject.disconnect();
this->connectDocumentObjectInEdit.disconnect();
this->connectDocumentObjectResetEdit.disconnect();
FC_PY_GDOC_OBSERVER
}
void DocumentObserverPython::slotCreatedDocument(const Gui::Document& Doc)
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotCreatedDocument"))) {
Py::Callable method(this->inst.getAttr(std::string("slotCreatedDocument")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::Document&>(Doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::Document&>(Doc).getPyObject(), true));
Base::pyCall(pyCreatedDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -122,12 +101,9 @@ void DocumentObserverPython::slotDeletedDocument(const Gui::Document& Doc)
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotDeletedDocument"))) {
Py::Callable method(this->inst.getAttr(std::string("slotDeletedDocument")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::Document&>(Doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::Document&>(Doc).getPyObject(), true));
Base::pyCall(pyDeletedDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -139,12 +115,9 @@ void DocumentObserverPython::slotRelabelDocument(const Gui::Document& Doc)
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotRelabelDocument"))) {
Py::Callable method(this->inst.getAttr(std::string("slotRelabelDocument")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::Document&>(Doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::Document&>(Doc).getPyObject(), true));
Base::pyCall(pyRelabelDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -156,12 +129,9 @@ void DocumentObserverPython::slotRenameDocument(const Gui::Document& Doc)
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotRenameDocument"))) {
Py::Callable method(this->inst.getAttr(std::string("slotRenameDocument")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::Document&>(Doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::Document&>(Doc).getPyObject(), true));
Base::pyCall(pyRenameDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -173,12 +143,9 @@ void DocumentObserverPython::slotActivateDocument(const Gui::Document& Doc)
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotActivateDocument"))) {
Py::Callable method(this->inst.getAttr(std::string("slotActivateDocument")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::Document&>(Doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::Document&>(Doc).getPyObject(), true));
Base::pyCall(pyActivateDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -190,12 +157,9 @@ void DocumentObserverPython::slotCreatedObject(const Gui::ViewProvider& Obj)
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotCreatedObject"))) {
Py::Callable method(this->inst.getAttr(std::string("slotCreatedObject")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::ViewProvider&>(Obj).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::ViewProvider&>(Obj).getPyObject(), true));
Base::pyCall(pyCreatedObject.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -207,12 +171,9 @@ void DocumentObserverPython::slotDeletedObject(const Gui::ViewProvider& Obj)
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotDeletedObject"))) {
Py::Callable method(this->inst.getAttr(std::string("slotDeletedObject")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::ViewProvider&>(Obj).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::ViewProvider&>(Obj).getPyObject(), true));
Base::pyCall(pyDeletedObject.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -225,17 +186,14 @@ void DocumentObserverPython::slotChangedObject(const Gui::ViewProvider& Obj,
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotChangedObject"))) {
Py::Callable method(this->inst.getAttr(std::string("slotChangedObject")));
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<Gui::ViewProvider&>(Obj).getPyObject(), true));
// If a property is touched but not part of a document object then its name is null.
// In this case the slot function must not be called.
const char* prop_name = Obj.getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
method.apply(args);
}
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<Gui::ViewProvider&>(Obj).getPyObject(), true));
// If a property is touched but not part of a document object then its name is null.
// In this case the slot function must not be called.
const char* prop_name = Obj.getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
Base::pyCall(pyChangedObject.ptr(),args.ptr());
}
}
catch (Py::Exception&) {
@@ -248,12 +206,9 @@ void DocumentObserverPython::slotInEdit(const Gui::ViewProviderDocumentObject& O
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotInEdit"))) {
Py::Callable method(this->inst.getAttr(std::string("slotInEdit")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::ViewProviderDocumentObject&>(Obj).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::ViewProviderDocumentObject&>(Obj).getPyObject(), true));
Base::pyCall(pyInEdit.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -265,12 +220,9 @@ void DocumentObserverPython::slotResetEdit(const Gui::ViewProviderDocumentObject
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotResetEdit"))) {
Py::Callable method(this->inst.getAttr(std::string("slotResetEdit")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::ViewProviderDocumentObject&>(Obj).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<Gui::ViewProviderDocumentObject&>(Obj).getPyObject(), true));
Base::pyCall(pyResetEdit.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text