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

@@ -46,13 +46,109 @@ public:
~FeaturePythonImp();
bool execute();
bool mustExecute() const;
void onBeforeChange(const Property* prop);
bool onBeforeChangeLabel(std::string &newLabel);
void onChanged(const Property* prop);
void onDocumentRestored();
std::string getViewProviderName();
PyObject *getPyObject(void);
bool getSubObject(App::DocumentObject *&ret, const char *subname, PyObject **pyObj,
Base::Matrix4D *mat, bool transform, int depth) const;
bool getSubObjects(std::vector<std::string> &ret, int reason) const;
bool getLinkedObject(App::DocumentObject *&ret, bool recurse,
Base::Matrix4D *mat, bool transform, int depth) const;
int canLinkProperties() const;
int allowDuplicateLabel() const;
bool redirectSubName(std::ostringstream &ss,
App::DocumentObject *topParent, App::DocumentObject *child) const;
int canLoadPartial() const;
/// return true to activate tree view group object handling
int hasChildElement() const;
/// Get sub-element visibility
int isElementVisible(const char *) const;
/// Set sub-element visibility
int setElementVisible(const char *, bool);
private:
App::DocumentObject* object;
bool has__object__;
#define FC_PY_FEATURE_PYTHON \
FC_PY_ELEMENT(execute)\
FC_PY_ELEMENT(mustExecute)\
FC_PY_ELEMENT(onBeforeChange)\
FC_PY_ELEMENT(onBeforeChangeLabel)\
FC_PY_ELEMENT(onChanged)\
FC_PY_ELEMENT(onDocumentRestored)\
FC_PY_ELEMENT(getViewProviderName)\
FC_PY_ELEMENT(getSubObject)\
FC_PY_ELEMENT(getSubObjects)\
FC_PY_ELEMENT(getLinkedObject)\
FC_PY_ELEMENT(canLinkProperties)\
FC_PY_ELEMENT(allowDuplicateLabel)\
FC_PY_ELEMENT(redirectSubName)\
FC_PY_ELEMENT(canLoadPartial)\
FC_PY_ELEMENT(hasChildElement)\
FC_PY_ELEMENT(isElementVisible)\
FC_PY_ELEMENT(setElementVisible)
#define FC_PY_ELEMENT_DEFINE(_name) \
Py::Object py_##_name;
#define FC_PY_ELEMENT_INIT(_name) \
FC_PY_GetCallable(pyobj,#_name,py_##_name);\
if(!py_##_name.isNone()) {\
PyObject *pyRecursive = PyObject_GetAttrString(pyobj, \
"__allow_recursive_" #_name);\
if(!pyRecursive) {\
PyErr_Clear();\
_Flags.set(FlagAllowRecursive_##_name, false);\
}else{\
_Flags.set(FlagAllowRecursive_##_name, PyObject_IsTrue(pyRecursive));\
Py_DECREF(pyRecursive);\
}\
}
#define FC_PY_ELEMENT_FLAG(_name) \
FlagCalling_##_name,\
FlagAllowRecursive_##_name,
#define _FC_PY_CALL_CHECK(_name,_ret) \
if((!_Flags.test(FlagAllowRecursive_##_name) \
&& _Flags.test(FlagCalling_##_name)) \
|| py_##_name.isNone()) \
{\
_ret;\
}\
Base::BitsetLocker<Flags> guard(_Flags, FlagCalling_##_name);
#undef FC_PY_ELEMENT
#define FC_PY_ELEMENT(_name) FC_PY_ELEMENT_DEFINE(_name)
FC_PY_FEATURE_PYTHON
#undef FC_PY_ELEMENT
#define FC_PY_ELEMENT(_name) FC_PY_ELEMENT_FLAG(_name)
enum Flag {
FC_PY_FEATURE_PYTHON
FlagMax,
};
typedef std::bitset<FlagMax> Flags;
mutable Flags _Flags;
public:
void init(PyObject *pyobj);
};
/**
@@ -80,7 +176,9 @@ public:
short mustExecute() const {
if (this->isTouched())
return 1;
return FeatureT::mustExecute();
auto ret = FeatureT::mustExecute();
if(ret) return ret;
return imp->mustExecute()?1:0;
}
/// recalculate the Feature
virtual DocumentObjectExecReturn *execute(void) {
@@ -94,12 +192,93 @@ public:
}
return DocumentObject::StdReturn;
}
virtual const char* getViewProviderNameOverride(void) const override{
viewProviderName = imp->getViewProviderName();
if(viewProviderName.size())
return viewProviderName.c_str();
return FeatureT::getViewProviderNameOverride();
}
/// returns the type name of the ViewProvider
virtual const char* getViewProviderName(void) const {
return FeatureT::getViewProviderName();
//return "Gui::ViewProviderPythonFeature";
}
virtual App::DocumentObject *getSubObject(const char *subname, PyObject **pyObj,
Base::Matrix4D *mat, bool transform, int depth) const override
{
App::DocumentObject *ret = 0;
if(imp->getSubObject(ret,subname,pyObj,mat,transform,depth))
return ret;
return FeatureT::getSubObject(subname,pyObj,mat,transform,depth);
}
virtual std::vector<std::string> getSubObjects(int reason=0) const override {
std::vector<std::string> ret;
if(imp->getSubObjects(ret,reason))
return ret;
return FeatureT::getSubObjects(reason);
}
virtual App::DocumentObject *getLinkedObject(bool recurse,
Base::Matrix4D *mat, bool transform, int depth) const override
{
App::DocumentObject *ret = 0;
if(imp->getLinkedObject(ret,recurse,mat,transform,depth))
return ret;
return FeatureT::getLinkedObject(recurse,mat,transform,depth);
}
/// return true to activate tree view group object handling
virtual bool hasChildElement() const override {
int ret = imp->hasChildElement();
if(ret<0)
return FeatureT::hasChildElement();
return ret?true:false;
}
/// Get sub-element visibility
virtual int isElementVisible(const char *element) const override {
int ret = imp->isElementVisible(element);
if(ret == -2)
return FeatureT::isElementVisible(element);
return ret;
}
/// Set sub-element visibility
virtual int setElementVisible(const char *element, bool visible) override {
int ret = imp->setElementVisible(element,visible);
if(ret == -2)
return FeatureT::setElementVisible(element,visible);
return ret;
}
virtual bool canLinkProperties() const override {
int ret = imp->canLinkProperties();
if(ret < 0)
return FeatureT::canLinkProperties();
return ret?true:false;
}
virtual bool allowDuplicateLabel() const override {
int ret = imp->allowDuplicateLabel();
if(ret < 0)
return FeatureT::allowDuplicateLabel();
return ret?true:false;
}
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);
}
virtual int canLoadPartial() const override {
int ret = imp->canLoadPartial();
if(ret>=0)
return ret;
return FeatureT::canLoadPartial();
}
PyObject *getPyObject(void) {
if (FeatureT::PythonObject.is(Py::_None())) {
// ref counter is set to 1
@@ -119,7 +298,13 @@ protected:
FeatureT::onBeforeChange(prop);
imp->onBeforeChange(prop);
}
virtual void onBeforeChangeLabel(std::string &newLabel) override{
if(!imp->onBeforeChangeLabel(newLabel))
FeatureT::onBeforeChangeLabel(newLabel);
}
virtual void onChanged(const Property* prop) {
if(prop == &Proxy)
imp->init(Proxy.getValue().ptr());
imp->onChanged(prop);
FeatureT::onChanged(prop);
}
@@ -130,8 +315,8 @@ protected:
private:
FeaturePythonImp* imp;
DynamicProperty* props;
PropertyPythonObject Proxy;
mutable std::string viewProviderName;
};
// Special Feature-Python classes