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 c93741d72f
commit 08f0511b1f
12 changed files with 1875 additions and 950 deletions

View File

@@ -103,13 +103,18 @@ DocumentObjectT::DocumentObjectT()
{
}
DocumentObjectT::DocumentObjectT(DocumentObject* obj)
DocumentObjectT::DocumentObjectT(const DocumentObject* obj)
{
object = obj->getNameInDocument();
label = obj->Label.getValue();
document = obj->getDocument()->getName();
}
DocumentObjectT::DocumentObjectT(const Property* prop)
{
*this = prop;
}
DocumentObjectT::~DocumentObjectT()
{
}
@@ -121,6 +126,7 @@ void DocumentObjectT::operator=(const DocumentObjectT& obj)
object = obj.object;
label = obj.label;
document = obj.document;
property = obj.property;
}
void DocumentObjectT::operator=(const DocumentObject* obj)
@@ -128,6 +134,16 @@ void DocumentObjectT::operator=(const DocumentObject* obj)
object = obj->getNameInDocument();
label = obj->Label.getValue();
document = obj->getDocument()->getName();
property.clear();
}
void DocumentObjectT::operator=(const Property *prop) {
auto obj = dynamic_cast<const DocumentObject*>(prop->getContainer());
assert(obj);
object = obj->getNameInDocument();
label = obj->Label.getValue();
document = obj->getDocument()->getName();
property = prop->getName();
}
Document* DocumentObjectT::getDocument() const
@@ -192,6 +208,27 @@ std::string DocumentObjectT::getObjectPython() const
return str.str();
}
std::string DocumentObjectT::getPropertyName() const {
return property;
}
std::string DocumentObjectT::getPropertyPython() const
{
std::stringstream str;
str << "FreeCAD.getDocument('" << document
<< "').getObject('" << object
<< "')";
if(property.size())
str << '.' << property;
return str.str();
}
Property *DocumentObjectT::getProperty() const {
auto obj = getObject();
if(obj)
return obj->getPropertyByName(property.c_str());
return 0;
}
// -----------------------------------------------------------------------------
DocumentObserver::DocumentObserver() : _document(0)

View File

@@ -83,13 +83,17 @@ public:
/*! Constructor */
DocumentObjectT();
/*! Constructor */
DocumentObjectT(DocumentObject*);
DocumentObjectT(const DocumentObject*);
/*! Constructor */
DocumentObjectT(const Property*);
/*! Destructor */
~DocumentObjectT();
/*! Assignment operator */
void operator=(const DocumentObjectT&);
/*! Assignment operator */
void operator=(const DocumentObject*);
/*! Assignment operator */
void operator=(const Property*);
/*! Get a pointer to the document or 0 if it doesn't exist any more. */
Document* getDocument() const;
@@ -99,23 +103,35 @@ public:
std::string getDocumentPython() const;
/*! Get a pointer to the document object or 0 if it doesn't exist any more. */
DocumentObject* getObject() const;
/*! Get a pointer to the property or 0 if it doesn't exist any more. */
Property* getProperty() const;
/*! Get the name of the document object. */
std::string getObjectName() const;
/*! Get the label of the document object. */
std::string getObjectLabel() const;
/*! Get the name of the property. */
std::string getPropertyName() const;
/*! Get the document object as Python command. */
std::string getObjectPython() const;
/*! Get the property as Python command. */
std::string getPropertyPython() const;
/*! Get a pointer to the document or 0 if it doesn't exist any more or the type doesn't match. */
template<typename T>
inline T* getObjectAs() const
{
return Base::freecad_dynamic_cast<T>(getObject());
}
template<typename T>
inline T* getPropertyAs() const
{
return Base::freecad_dynamic_cast<T>(getProperty());
}
private:
std::string document;
std::string object;
std::string label;
std::string property;
};
/**

View File

@@ -59,95 +59,38 @@ void DocumentObserverPython::removeObserver(const Py::Object& obj)
DocumentObserverPython::DocumentObserverPython(const Py::Object& obj) : inst(obj)
{
this->connectApplicationCreatedDocument = App::GetApplication().signalNewDocument.connect(boost::bind
(&DocumentObserverPython::slotCreatedDocument, this, _1));
this->connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(boost::bind
(&DocumentObserverPython::slotDeletedDocument, this, _1));
this->connectApplicationRelabelDocument = App::GetApplication().signalRelabelDocument.connect(boost::bind
(&DocumentObserverPython::slotRelabelDocument, this, _1));
this->connectApplicationActivateDocument = App::GetApplication().signalActiveDocument.connect(boost::bind
(&DocumentObserverPython::slotActivateDocument, this, _1));
this->connectApplicationUndoDocument = App::GetApplication().signalUndoDocument.connect(boost::bind
(&DocumentObserverPython::slotUndoDocument, this, _1));
this->connectApplicationRedoDocument = App::GetApplication().signalRedoDocument.connect(boost::bind
(&DocumentObserverPython::slotRedoDocument, this, _1));
#define signalCreatedDocument signalNewDocument
#define signalCreatedObject signalNewObject
#define signalRecomputedObject signalObjectRecomputed
#define signalRecomputedDocument signalRecomputed
#define signalActivateDocument signalActiveDocument
#define signalDeletedDocument signalDeleteDocument
this->connectDocumentBeforeChange = App::GetApplication().signalBeforeChangeDocument.connect(boost::bind
(&DocumentObserverPython::slotBeforeChangeDocument, this, _1, _2));
this->connectDocumentChanged = App::GetApplication().signalChangedDocument.connect(boost::bind
(&DocumentObserverPython::slotChangedDocument, this, _1, _2));
this->connectDocumentCreatedObject = App::GetApplication().signalNewObject.connect(boost::bind
(&DocumentObserverPython::slotCreatedObject, this, _1));
this->connectDocumentDeletedObject = App::GetApplication().signalDeletedObject.connect(boost::bind
(&DocumentObserverPython::slotDeletedObject, this, _1));
this->connectDocumentBeforeChangeObject = App::GetApplication().signalBeforeChangeObject.connect(boost::bind
(&DocumentObserverPython::slotBeforeChangeObject, this, _1, _2));
this->connectDocumentChangedObject = App::GetApplication().signalChangedObject.connect(boost::bind
(&DocumentObserverPython::slotChangedObject, this, _1, _2));
#undef FC_PY_ELEMENT
#define FC_PY_ELEMENT(_name,...) do{\
FC_PY_GetCallable(obj.ptr(),"slot" #_name, py##_name);\
if(!py##_name.isNone())\
connect##_name = App::GetApplication().signal##_name.connect(\
boost::bind(&DocumentObserverPython::slot##_name, this, ##__VA_ARGS__));\
}while(0);
this->connectDocumentObjectRecomputed = App::GetApplication().signalObjectRecomputed.connect(boost::bind
(&DocumentObserverPython::slotRecomputedObject, this, _1));
this->connectDocumentRecomputed = App::GetApplication().signalRecomputed.connect(boost::bind
(&DocumentObserverPython::slotRecomputedDocument, this, _1));
this->connectDocumentOpenTransaction = App::GetApplication().signalOpenTransaction.connect(boost::bind
(&DocumentObserverPython::slotOpenTransaction, this, _1, _2));
this->connectDocumentCommitTransaction = App::GetApplication().signalCommitTransaction.connect(boost::bind
(&DocumentObserverPython::slotCommitTransaction, this, _1));
this->connectDocumentAbortTransaction = App::GetApplication().signalAbortTransaction.connect(boost::bind
(&DocumentObserverPython::slotAbortTransaction, this, _1));
this->connectDocumentStartSave = App::GetApplication().signalStartSaveDocument.connect(boost::bind
(&DocumentObserverPython::slotStartSaveDocument, this, _1, _2));
this->connectDocumentFinishSave = App::GetApplication().signalFinishSaveDocument.connect(boost::bind
(&DocumentObserverPython::slotFinishSaveDocument, this, _1, _2));
this->connectObjectAppendDynamicProperty = App::GetApplication().signalAppendDynamicProperty.connect(boost::bind
(&DocumentObserverPython::slotAppendDynamicProperty, this, _1));
this->connectObjectRemoveDynamicProperty = App::GetApplication().signalRemoveDynamicProperty.connect(boost::bind
(&DocumentObserverPython::slotRemoveDynamicProperty, this, _1));
this->connectObjectChangePropertyEditor = App::GetApplication().signalChangePropertyEditor.connect(boost::bind
(&DocumentObserverPython::slotChangePropertyEditor, this, _1));
FC_PY_DOC_OBSERVER
}
DocumentObserverPython::~DocumentObserverPython()
{
this->connectApplicationCreatedDocument.disconnect();
this->connectApplicationDeletedDocument.disconnect();
this->connectApplicationRelabelDocument.disconnect();
this->connectApplicationActivateDocument.disconnect();
this->connectApplicationUndoDocument.disconnect();
this->connectApplicationRedoDocument.disconnect();
this->connectDocumentBeforeChange.disconnect();
this->connectDocumentChanged.disconnect();
this->connectDocumentCreatedObject.disconnect();
this->connectDocumentDeletedObject.disconnect();
this->connectDocumentBeforeChangeObject.disconnect();
this->connectDocumentChangedObject.disconnect();
this->connectDocumentObjectRecomputed.disconnect();
this->connectDocumentRecomputed.disconnect();
this->connectDocumentOpenTransaction.disconnect();
this->connectDocumentCommitTransaction.disconnect();
this->connectDocumentAbortTransaction.disconnect();
this->connectDocumentStartSave.disconnect();
this->connectDocumentFinishSave.disconnect();
this->connectObjectAppendDynamicProperty.disconnect();
this->connectObjectRemoveDynamicProperty.disconnect();
this->connectObjectChangePropertyEditor.disconnect();
#undef FC_PY_ELEMENT
#define FC_PY_ELEMENT(_name,...) connect##_name.disconnect();
FC_PY_DOC_OBSERVER
}
void DocumentObserverPython::slotCreatedDocument(const App::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<App::Document&>(Doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
Base::pyCall(pyCreatedDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -159,12 +102,9 @@ void DocumentObserverPython::slotDeletedDocument(const App::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<App::Document&>(Doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
Base::pyCall(pyDeletedDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -176,12 +116,9 @@ void DocumentObserverPython::slotRelabelDocument(const App::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<App::Document&>(Doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
Base::pyCall(pyRelabelDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -193,12 +130,9 @@ void DocumentObserverPython::slotActivateDocument(const App::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<App::Document&>(Doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
Base::pyCall(pyActivateDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -210,12 +144,9 @@ void DocumentObserverPython::slotUndoDocument(const App::Document& Doc)
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotUndoDocument"))) {
Py::Callable method(this->inst.getAttr(std::string("slotUndoDocument")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
Base::pyCall(pyUndoDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -223,16 +154,66 @@ void DocumentObserverPython::slotUndoDocument(const App::Document& Doc)
}
}
void DocumentObserverPython::slotRedoDocument(const App::Document& Doc)
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotRedoDocument"))) {
Py::Callable method(this->inst.getAttr(std::string("slotRedoDocument")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
Base::pyCall(pyRedoDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void DocumentObserverPython::slotUndo()
{
Base::PyGILStateLocker lock;
try {
Base::pyCall(pyUndo.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void DocumentObserverPython::slotRedo()
{
Base::PyGILStateLocker lock;
try {
Base::pyCall(pyRedo.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void DocumentObserverPython::slotBeforeCloseTransaction(bool abort)
{
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Boolean(abort));
Base::pyCall(pyBeforeCloseTransaction.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void DocumentObserverPython::slotCloseTransaction(bool abort)
{
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Boolean(abort));
Base::pyCall(pyCloseTransaction.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -244,17 +225,14 @@ void DocumentObserverPython::slotBeforeChangeDocument(const App::Document& Doc,
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotBeforeChangeDocument"))) {
Py::Callable method(this->inst.getAttr(std::string("slotBeforeChangeDocument")));
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).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 = Doc.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<App::Document&>(Doc).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 = Doc.getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
Base::pyCall(pyBeforeChangeDocument.ptr(),args.ptr());
}
}
catch (Py::Exception&) {
@@ -267,17 +245,14 @@ void DocumentObserverPython::slotChangedDocument(const App::Document& Doc, const
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotChangedDocument"))) {
Py::Callable method(this->inst.getAttr(std::string("slotChangedDocument")));
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).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 = Doc.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<App::Document&>(Doc).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 = Doc.getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
Base::pyCall(pyChangedDocument.ptr(),args.ptr());
}
}
catch (Py::Exception&) {
@@ -290,12 +265,9 @@ void DocumentObserverPython::slotCreatedObject(const App::DocumentObject& 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<App::DocumentObject&>(Obj).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::DocumentObject&>(Obj).getPyObject(), true));
Base::pyCall(pyCreatedObject.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -307,12 +279,9 @@ void DocumentObserverPython::slotDeletedObject(const App::DocumentObject& 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<App::DocumentObject&>(Obj).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::DocumentObject&>(Obj).getPyObject(), true));
Base::pyCall(pyDeletedObject.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -325,17 +294,14 @@ void DocumentObserverPython::slotBeforeChangeObject(const App::DocumentObject& O
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotBeforeChangeObject"))) {
Py::Callable method(this->inst.getAttr(std::string("slotBeforeChangeObject")));
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::DocumentObject&>(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<App::DocumentObject&>(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(pyBeforeChangeObject.ptr(),args.ptr());
}
}
catch (Py::Exception&) {
@@ -349,17 +315,14 @@ void DocumentObserverPython::slotChangedObject(const App::DocumentObject& 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<App::DocumentObject&>(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<App::DocumentObject&>(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&) {
@@ -372,12 +335,9 @@ void DocumentObserverPython::slotRecomputedObject(const App::DocumentObject& Obj
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotRecomputedObject"))) {
Py::Callable method(this->inst.getAttr(std::string("slotRecomputedObject")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::DocumentObject&>(Obj).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::DocumentObject&>(Obj).getPyObject(), true));
Base::pyCall(pyRecomputedObject.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -389,12 +349,23 @@ void DocumentObserverPython::slotRecomputedDocument(const App::Document& doc)
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotRecomputedDocument"))) {
Py::Callable method(this->inst.getAttr(std::string("slotRecomputedDocument")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
Base::pyCall(pyRecomputedDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void DocumentObserverPython::slotBeforeRecomputeDocument(const App::Document& doc)
{
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
Base::pyCall(pyBeforeRecomputeDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -406,13 +377,10 @@ void DocumentObserverPython::slotOpenTransaction(const App::Document& doc, std::
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotOpenTransaction"))) {
Py::Callable method(this->inst.getAttr(std::string("slotOpenTransaction")));
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
args.setItem(1, Py::String(str));
method.apply(args);
}
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
args.setItem(1, Py::String(str));
Base::pyCall(pyOpenTransaction.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -424,12 +392,9 @@ void DocumentObserverPython::slotCommitTransaction(const App::Document& doc)
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotCommitTransaction"))) {
Py::Callable method(this->inst.getAttr(std::string("slotCommitTransaction")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
Base::pyCall(pyCommitTransaction.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -441,12 +406,9 @@ void DocumentObserverPython::slotAbortTransaction(const App::Document& doc)
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotAbortTransaction"))) {
Py::Callable method(this->inst.getAttr(std::string("slotAbortTransaction")));
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
method.apply(args);
}
Py::Tuple args(1);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
Base::pyCall(pyAbortTransaction.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -458,18 +420,15 @@ void DocumentObserverPython::slotAppendDynamicProperty(const App::Property& Prop
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotAppendDynamicProperty"))) {
auto container = Prop.getContainer();
Py::Callable method(this->inst.getAttr(std::string("slotAppendDynamicProperty")));
Py::Tuple args(2);
args.setItem(0, Py::Object(container->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 = container->getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
method.apply(args);
}
auto container = Prop.getContainer();
Py::Tuple args(2);
args.setItem(0, Py::Object(container->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 = container->getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
Base::pyCall(pyAppendDynamicProperty.ptr(),args.ptr());
}
}
catch (Py::Exception&) {
@@ -482,18 +441,15 @@ void DocumentObserverPython::slotRemoveDynamicProperty(const App::Property& Prop
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotRemoveDynamicProperty"))) {
auto container = Prop.getContainer();
Py::Callable method(this->inst.getAttr(std::string("slotRemoveDynamicProperty")));
Py::Tuple args(2);
args.setItem(0, Py::Object(container->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 = container->getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
method.apply(args);
}
auto container = Prop.getContainer();
Py::Tuple args(2);
args.setItem(0, Py::Object(container->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 = container->getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
Base::pyCall(pyRemoveDynamicProperty.ptr(),args.ptr());
}
}
catch (Py::Exception&) {
@@ -502,22 +458,19 @@ void DocumentObserverPython::slotRemoveDynamicProperty(const App::Property& Prop
}
}
void DocumentObserverPython::slotChangePropertyEditor(const App::Property& Prop)
void DocumentObserverPython::slotChangePropertyEditor(const App::Document &, const App::Property& Prop)
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotChangePropertyEditor"))) {
auto container = Prop.getContainer();
Py::Callable method(this->inst.getAttr(std::string("slotChangePropertyEditor")));
Py::Tuple args(2);
args.setItem(0, Py::Object(container->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 = container->getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
method.apply(args);
}
auto container = Prop.getContainer();
Py::Tuple args(2);
args.setItem(0, Py::Object(container->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 = container->getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
Base::pyCall(pyChangePropertyEditor.ptr(),args.ptr());
}
}
catch (Py::Exception&) {
@@ -530,13 +483,10 @@ void DocumentObserverPython::slotStartSaveDocument(const App::Document& doc, con
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotStartSaveDocument"))) {
Py::Callable method(this->inst.getAttr(std::string("slotStartSaveDocument")));
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
args.setItem(1, Py::String(file));
method.apply(args);
}
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
args.setItem(1, Py::String(file));
Base::pyCall(pyStartSaveDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
@@ -548,13 +498,10 @@ void DocumentObserverPython::slotFinishSaveDocument(const App::Document& doc, co
{
Base::PyGILStateLocker lock;
try {
if (this->inst.hasAttr(std::string("slotFinishSaveDocument"))) {
Py::Callable method(this->inst.getAttr(std::string("slotFinishSaveDocument")));
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
args.setItem(1, Py::String(file));
method.apply(args);
}
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::Document&>(doc).getPyObject(), true));
args.setItem(1, Py::String(file));
Base::pyCall(pyFinishSaveDocument.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text

View File

@@ -77,6 +77,8 @@ private:
void slotRedoDocument(const App::Document& Doc);
/** Called when a given object is recomputed */
void slotRecomputedObject(const App::DocumentObject& Obj);
/** Called before an observed document is recomputed */
void slotBeforeRecomputeDocument(const App::Document& Doc);
/** Called when an observed document is recomputed */
void slotRecomputedDocument(const App::Document& Doc);
/** Called when an observed document opens a transaction */
@@ -85,12 +87,20 @@ private:
void slotCommitTransaction(const App::Document& Doc);
/** Called when an observed document aborts a transaction */
void slotAbortTransaction(const App::Document& Doc);
/** Called after application wide undo */
void slotUndo();
/** Called after application wide redo */
void slotRedo();
/** Called before closing/aborting application active transaction */
void slotBeforeCloseTransaction(bool abort);
/** Called after closing/aborting application active transaction */
void slotCloseTransaction(bool abort);
/** Called when an object gets a new dynamic property added*/
void slotAppendDynamicProperty(const App::Property& Prop);
/** Called when an object gets a dynamic property removed*/
void slotRemoveDynamicProperty(const App::Property& Prop);
/** Called when an object property gets a new editor relevant status like hidden or read only*/
void slotChangePropertyEditor(const App::Property& Prop);
void slotChangePropertyEditor(const App::Document &Doc, const App::Property& Prop);
/** Called when a document is about to be saved*/
void slotStartSaveDocument(const App::Document&, const std::string&);
/** Called when an document has been saved*/
@@ -101,28 +111,42 @@ private:
static std::vector<DocumentObserverPython*> _instances;
typedef boost::signals2::connection Connection;
Connection connectApplicationCreatedDocument;
Connection connectApplicationDeletedDocument;
Connection connectApplicationRelabelDocument;
Connection connectApplicationActivateDocument;
Connection connectApplicationUndoDocument;
Connection connectApplicationRedoDocument;
Connection connectDocumentBeforeChange;
Connection connectDocumentChanged;
Connection connectDocumentCreatedObject;
Connection connectDocumentDeletedObject;
Connection connectDocumentBeforeChangeObject;
Connection connectDocumentChangedObject;
Connection connectDocumentObjectRecomputed;
Connection connectDocumentRecomputed;
Connection connectDocumentOpenTransaction;
Connection connectDocumentCommitTransaction;
Connection connectDocumentAbortTransaction;
Connection connectDocumentStartSave;
Connection connectDocumentFinishSave;
Connection connectObjectAppendDynamicProperty;
Connection connectObjectRemoveDynamicProperty;
Connection connectObjectChangePropertyEditor;
#define FC_PY_DOC_OBSERVER \
FC_PY_ELEMENT(CreatedDocument,_1) \
FC_PY_ELEMENT(DeletedDocument,_1) \
FC_PY_ELEMENT(RelabelDocument,_1) \
FC_PY_ELEMENT(ActivateDocument,_1) \
FC_PY_ELEMENT(UndoDocument,_1) \
FC_PY_ELEMENT(RedoDocument,_1) \
FC_PY_ELEMENT(BeforeChangeDocument,_1,_2) \
FC_PY_ELEMENT(ChangedDocument,_1,_2) \
FC_PY_ELEMENT(CreatedObject,_1) \
FC_PY_ELEMENT(DeletedObject,_1) \
FC_PY_ELEMENT(BeforeChangeObject,_1,_2) \
FC_PY_ELEMENT(ChangedObject,_1,_2) \
FC_PY_ELEMENT(RecomputedObject,_1) \
FC_PY_ELEMENT(BeforeRecomputeDocument,_1) \
FC_PY_ELEMENT(RecomputedDocument,_1) \
FC_PY_ELEMENT(OpenTransaction,_1,_2) \
FC_PY_ELEMENT(CommitTransaction,_1) \
FC_PY_ELEMENT(AbortTransaction,_1) \
FC_PY_ELEMENT(Undo) \
FC_PY_ELEMENT(Redo) \
FC_PY_ELEMENT(BeforeCloseTransaction,_1) \
FC_PY_ELEMENT(CloseTransaction,_1) \
FC_PY_ELEMENT(StartSaveDocument,_1,_2) \
FC_PY_ELEMENT(FinishSaveDocument,_1,_2) \
FC_PY_ELEMENT(AppendDynamicProperty,_1) \
FC_PY_ELEMENT(RemoveDynamicProperty,_1) \
FC_PY_ELEMENT(ChangePropertyEditor,_1,_2)
#undef FC_PY_ELEMENT
#define FC_PY_ELEMENT(_name,...) \
Connection connect##_name;\
Py::Object py##_name;
FC_PY_DOC_OBSERVER
};
} //namespace App

View File

@@ -30,15 +30,16 @@
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <Base/Reader.h>
#include <Base/MatrixPy.h>
#include <Base/Tools.h>
#include <App/DocumentObjectPy.h>
#include "FeaturePython.h"
#include "FeaturePythonPyImp.h"
using namespace App;
FeaturePythonImp::FeaturePythonImp(App::DocumentObject* o) : object(o)
FeaturePythonImp::FeaturePythonImp(App::DocumentObject* o)
: object(o), has__object__(false)
{
}
@@ -46,43 +47,40 @@ FeaturePythonImp::~FeaturePythonImp()
{
}
void FeaturePythonImp::init(PyObject *pyobj) {
Base::PyGILStateLocker lock;
has__object__ = !!PyObject_HasAttrString(pyobj, "__object__");
#undef FC_PY_ELEMENT
#define FC_PY_ELEMENT(_name) FC_PY_ELEMENT_INIT(_name)
FC_PY_FEATURE_PYTHON
}
#define FC_PY_CALL_CHECK(_name) _FC_PY_CALL_CHECK(_name,return(false))
/*!
Calls the execute() method of the Python feature class. If the Python feature class doesn't have an execute()
method or if it returns False this method also return false and true otherwise.
*/
bool FeaturePythonImp::execute()
{
// avoid recursive calls of execute()
if (object->testStatus(App::PythonCall))
return false;
// Run the execute method of the proxy object.
FC_PY_CALL_CHECK(execute)
Base::PyGILStateLocker lock;
try {
Property* proxy = object->getPropertyByName("Proxy");
if (proxy && proxy->getTypeId() == PropertyPythonObject::getClassTypeId()) {
Py::Object feature = static_cast<PropertyPythonObject*>(proxy)->getValue();
if (feature.hasAttr(std::string("execute"))) {
if (feature.hasAttr("__object__")) {
Base::ObjectStatusLocker<ObjectStatus, DocumentObject> exe(App::PythonCall, object);
Py::Callable method(feature.getAttr(std::string("execute")));
Py::Tuple args;
Py::Object res = method.apply(args);
if (res.isBoolean() && !res.isTrue())
return false;
return true;
}
else {
Base::ObjectStatusLocker<ObjectStatus, DocumentObject> exe(App::PythonCall, object);
Py::Callable method(feature.getAttr(std::string("execute")));
Py::Tuple args(1);
args.setItem(0, Py::Object(object->getPyObject(), true));
Py::Object res = method.apply(args);
if (res.isBoolean() && !res.isTrue())
return false;
return true;
}
}
if (has__object__) {
Py::Object res = Base::pyCall(py_execute.ptr());
if (res.isBoolean() && !res.isTrue())
return false;
return true;
}
else {
Py::Tuple args(1);
args.setItem(0, Py::Object(object->getPyObject(), true));
Py::Object res = Base::pyCall(py_execute.ptr(),args.ptr());
if (res.isBoolean() && !res.isTrue())
return false;
return true;
}
}
catch (Py::Exception&) {
@@ -96,35 +94,51 @@ bool FeaturePythonImp::execute()
return false;
}
bool FeaturePythonImp::mustExecute() const
{
FC_PY_CALL_CHECK(mustExecute)
Base::PyGILStateLocker lock;
try {
if (has__object__) {
Py::Object res(Base::pyCall(py_mustExecute.ptr()));
return res.isTrue();
}
else {
Py::Tuple args(1);
args.setItem(0, Py::Object(object->getPyObject(), true));
Py::Object res(Base::pyCall(py_mustExecute.ptr(),args.ptr()));
return res.isTrue();
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
return false;
}
void FeaturePythonImp::onBeforeChange(const Property* prop)
{
if(py_onBeforeChange.isNone())
return;
// Run the execute method of the proxy object.
Base::PyGILStateLocker lock;
try {
Property* proxy = object->getPropertyByName("Proxy");
if (proxy && proxy->getTypeId() == PropertyPythonObject::getClassTypeId()) {
Py::Object feature = static_cast<PropertyPythonObject*>(proxy)->getValue();
if (feature.hasAttr(std::string("onBeforeChange"))) {
if (feature.hasAttr("__object__")) {
Py::Callable method(feature.getAttr(std::string("onBeforeChange")));
Py::Tuple args(1);
const char* prop_name = object->getPropertyName(prop);
if (prop_name) {
args.setItem(0, Py::String(prop_name));
method.apply(args);
}
}
else {
Py::Callable method(feature.getAttr(std::string("onBeforeChange")));
Py::Tuple args(2);
args.setItem(0, Py::Object(object->getPyObject(), true));
const char* prop_name = object->getPropertyName(prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
method.apply(args);
}
}
}
const char *prop_name = object->getPropertyName(prop);
if(prop_name == 0)
return;
if (has__object__) {
Py::Tuple args(1);
args.setItem(0, Py::String(prop_name));
Base::pyCall(py_onBeforeChange.ptr(),args.ptr());
}
else {
Py::Tuple args(2);
args.setItem(0, Py::Object(object->getPyObject(), true));
args.setItem(1, Py::String(prop_name));
Base::pyCall(py_onBeforeChange.ptr(),args.ptr());
}
}
catch (Py::Exception&) {
@@ -133,35 +147,52 @@ void FeaturePythonImp::onBeforeChange(const Property* prop)
}
}
void FeaturePythonImp::onChanged(const Property* prop)
bool FeaturePythonImp::onBeforeChangeLabel(std::string &newLabel)
{
if(py_onBeforeChangeLabel.isNone())
return false;
// Run the execute method of the proxy object.
Base::PyGILStateLocker lock;
try {
Property* proxy = object->getPropertyByName("Proxy");
if (proxy && proxy->getTypeId() == PropertyPythonObject::getClassTypeId()) {
Py::Object feature = static_cast<PropertyPythonObject*>(proxy)->getValue();
if (feature.hasAttr(std::string("onChanged"))) {
if (feature.hasAttr("__object__")) {
Py::Callable method(feature.getAttr(std::string("onChanged")));
Py::Tuple args(1);
const char* prop_name = object->getPropertyName(prop);
if (prop_name) {
args.setItem(0, Py::String(prop_name));
method.apply(args);
}
}
else {
Py::Callable method(feature.getAttr(std::string("onChanged")));
Py::Tuple args(2);
args.setItem(0, Py::Object(object->getPyObject(), true));
const char* prop_name = object->getPropertyName(prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
method.apply(args);
}
}
}
Py::Tuple args(2);
args.setItem(0, Py::Object(object->getPyObject(), true));
args.setItem(1,Py::String(newLabel));
Py::Object ret(Base::pyCall(py_onBeforeChangeLabel.ptr(),args.ptr()));
if(!ret.isNone()) {
if(!ret.isString())
throw Base::TypeError("onBeforeChangeLabel expects to return a string");
newLabel = ret.as_string();
return true;
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
return false;
}
void FeaturePythonImp::onChanged(const Property* prop)
{
if(py_onChanged.isNone())
return;
// Run the execute method of the proxy object.
Base::PyGILStateLocker lock;
try {
const char *prop_name = object->getPropertyName(prop);
if(prop_name == 0)
return;
if (has__object__) {
Py::Tuple args(1);
args.setItem(0, Py::String(prop_name));
Base::pyCall(py_onChanged.ptr(),args.ptr());
}
else {
Py::Tuple args(2);
args.setItem(0, Py::Object(object->getPyObject(), true));
args.setItem(1, Py::String(prop_name));
Base::pyCall(py_onChanged.ptr(),args.ptr());
}
}
catch (Py::Exception&) {
@@ -172,25 +203,18 @@ void FeaturePythonImp::onChanged(const Property* prop)
void FeaturePythonImp::onDocumentRestored()
{
_FC_PY_CALL_CHECK(onDocumentRestored,return);
// Run the execute method of the proxy object.
Base::PyGILStateLocker lock;
try {
Property* proxy = object->getPropertyByName("Proxy");
if (proxy && proxy->getTypeId() == PropertyPythonObject::getClassTypeId()) {
Py::Object feature = static_cast<PropertyPythonObject*>(proxy)->getValue();
if (feature.hasAttr(std::string("onDocumentRestored"))) {
if (feature.hasAttr("__object__")) {
Py::Callable method(feature.getAttr(std::string("onDocumentRestored")));
Py::Tuple args;
method.apply(args);
}
else {
Py::Callable method(feature.getAttr(std::string("onDocumentRestored")));
Py::Tuple args(1);
args.setItem(0, Py::Object(object->getPyObject(), true));
method.apply(args);
}
}
if (has__object__) {
Base::pyCall(py_onDocumentRestored.ptr());
}
else {
Py::Tuple args(1);
args.setItem(0, Py::Object(object->getPyObject(), true));
Base::pyCall(py_onDocumentRestored.ptr(),args.ptr());
}
}
catch (Py::Exception&) {
@@ -199,12 +223,283 @@ void FeaturePythonImp::onDocumentRestored()
}
}
bool FeaturePythonImp::getSubObject(DocumentObject *&ret, const char *subname,
PyObject **pyObj, Base::Matrix4D *_mat, bool transform, int depth) const
{
FC_PY_CALL_CHECK(getSubObject);
Base::PyGILStateLocker lock;
try {
Py::Tuple args(6);
args.setItem(0, Py::Object(object->getPyObject(), true));
if(!subname) subname = "";
args.setItem(1,Py::String(subname));
args.setItem(2,Py::Int(pyObj?2:1));
Base::MatrixPy *pyMat = new Base::MatrixPy(new Base::Matrix4D);
if(_mat) *pyMat->getMatrixPtr() = *_mat;
args.setItem(3,Py::Object(pyMat));
args.setItem(4,Py::Boolean(transform));
args.setItem(5,Py::Int(depth));
Py::Object res(Base::pyCall(py_getSubObject.ptr(),args.ptr()));
if(res.isNone()) {
ret = 0;
return true;
}
if(!res.isTrue())
return false;
if(!res.isSequence())
throw Base::TypeError("getSubObject expects return type of tuple");
Py::Sequence seq(res);
if(seq.length() < 2 ||
(!seq.getItem(0).isNone() &&
!PyObject_TypeCheck(seq.getItem(0).ptr(),&DocumentObjectPy::Type)) ||
!PyObject_TypeCheck(seq.getItem(1).ptr(),&Base::MatrixPy::Type))
{
throw Base::TypeError("getSubObject expects return type of (obj,matrix,pyobj)");
}
if(_mat)
*_mat = *static_cast<Base::MatrixPy*>(seq.getItem(1).ptr())->getMatrixPtr();
if(pyObj) {
if(seq.length()>2)
*pyObj = Py::new_reference_to(seq.getItem(2));
else
*pyObj = Py::new_reference_to(Py::None());
}
if(seq.getItem(0).isNone())
ret = 0;
else
ret = static_cast<DocumentObjectPy*>(seq.getItem(0).ptr())->getDocumentObjectPtr();
return true;
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
ret = 0;
return true;
}
}
bool FeaturePythonImp::getSubObjects(std::vector<std::string> &ret, int reason) const {
FC_PY_CALL_CHECK(getSubObjects);
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::Object(object->getPyObject(), true));
args.setItem(1, Py::Int(reason));
Py::Object res(Base::pyCall(py_getSubObjects.ptr(),args.ptr()));
if(!res.isTrue())
return true;
if(!res.isSequence())
throw Base::TypeError("getSubObjects expects return type of tuple");
Py::Sequence seq(res);
for(size_t i=0;i<seq.length();++i) {
Py::Object name(seq[i].ptr());
if(!name.isString())
throw Base::TypeError("getSubObjects expects string in returned sequence");
ret.push_back(name.as_string());
}
return true;
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
return true;
}
}
bool FeaturePythonImp::getLinkedObject(DocumentObject *&ret, bool recurse,
Base::Matrix4D *_mat, bool transform, int depth) const
{
FC_PY_CALL_CHECK(getLinkedObject);
Base::PyGILStateLocker lock;
try {
Py::Tuple args(5);
args.setItem(0, Py::Object(object->getPyObject(), true));
args.setItem(1,Py::Boolean(recurse));
Base::MatrixPy *pyMat = new Base::MatrixPy(new Base::Matrix4D);
if(_mat) *pyMat->getMatrixPtr() = *_mat;
args.setItem(2,Py::Object(pyMat));
args.setItem(3,Py::Boolean(transform));
args.setItem(4,Py::Int(depth));
Py::Object res(Base::pyCall(py_getLinkedObject.ptr(),args.ptr()));
if(!res.isTrue()) {
ret = object;
return true;
}
if(!res.isSequence())
throw Base::TypeError("getLinkedObject expects return type of (object,matrix)");
Py::Sequence seq(res);
if(seq.length() != 2 ||
(!seq.getItem(0).isNone() &&
!PyObject_TypeCheck(seq.getItem(0).ptr(),&DocumentObjectPy::Type)) ||
!PyObject_TypeCheck(seq.getItem(1).ptr(),&Base::MatrixPy::Type))
{
throw Base::TypeError("getLinkedObject expects return type of (object,matrix)");
}
if(_mat)
*_mat = *static_cast<Base::MatrixPy*>(seq.getItem(1).ptr())->getMatrixPtr();
if(seq.getItem(0).isNone())
ret = object;
else
ret = static_cast<DocumentObjectPy*>(seq.getItem(0).ptr())->getDocumentObjectPtr();
return true;
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
ret = 0;
return true;
}
}
PyObject *FeaturePythonImp::getPyObject(void)
{
// ref counter is set to 1
return new FeaturePythonPyT<DocumentObjectPy>(object);
}
int FeaturePythonImp::hasChildElement() const {
_FC_PY_CALL_CHECK(hasChildElement,return(-1));
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(object->getPyObject(), true));
Py::Boolean ok(Base::pyCall(py_hasChildElement.ptr(),args.ptr()));
return static_cast<bool>(ok) ? 1 : 0;
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
return -1;
}
int FeaturePythonImp::isElementVisible(const char *element) const {
_FC_PY_CALL_CHECK(isElementVisible,return(-2));
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::Object(object->getPyObject(), true));
args.setItem(1,Py::String(element?element:""));
return Py::Int(Base::pyCall(py_isElementVisible.ptr(),args.ptr()));
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
return -2;
}
int FeaturePythonImp::setElementVisible(const char *element, bool visible) {
_FC_PY_CALL_CHECK(setElementVisible,return(-2));
Base::PyGILStateLocker lock;
try {
Py::Tuple args(3);
args.setItem(0, Py::Object(object->getPyObject(), true));
args.setItem(1,Py::String(element?element:""));
args.setItem(2,Py::Boolean(visible));
return Py::Int(Base::pyCall(py_setElementVisible.ptr(),args.ptr()));
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
return -2;
}
std::string FeaturePythonImp::getViewProviderName()
{
_FC_PY_CALL_CHECK(getViewProviderName,return(std::string()));
Base::PyGILStateLocker lock;
try {
Py::TupleN args(Py::Object(object->getPyObject(), true));
Py::String ret(Base::pyCall(py_getViewProviderName.ptr(),args.ptr()));
return ret.as_string();
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
return std::string();
}
int FeaturePythonImp::canLinkProperties() const {
_FC_PY_CALL_CHECK(canLinkProperties,return(-1));
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(object->getPyObject(), true));
Py::Boolean ok(Base::pyCall(py_canLinkProperties.ptr(),args.ptr()));
return ok?1:0;
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
return 0;
}
}
int FeaturePythonImp::allowDuplicateLabel() const {
_FC_PY_CALL_CHECK(allowDuplicateLabel,return(-1));
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(object->getPyObject(), true));
Py::Boolean ok(Base::pyCall(py_allowDuplicateLabel.ptr(),args.ptr()));
return ok?1:0;
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
return 0;
}
}
int FeaturePythonImp::canLoadPartial() const {
_FC_PY_CALL_CHECK(canLoadPartial,return(-1));
Base::PyGILStateLocker lock;
try {
Py::Tuple args(1);
args.setItem(0, Py::Object(object->getPyObject(), true));
Py::Int ret(Base::pyCall(py_canLoadPartial.ptr(),args.ptr()));
return ret;
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
return -1;
}
bool FeaturePythonImp::redirectSubName(std::ostringstream &ss,
App::DocumentObject *topParent, App::DocumentObject *child) const
{
FC_PY_CALL_CHECK(redirectSubName);
Base::PyGILStateLocker lock;
try {
Py::Tuple args(4);
args.setItem(0, Py::Object(object->getPyObject(), true));
args.setItem(1,Py::String(ss.str()));
args.setItem(2,topParent?Py::Object(topParent->getPyObject(),true):Py::Object());
args.setItem(3,child?Py::Object(child->getPyObject(),true):Py::Object());
Py::Object ret(Base::pyCall(py_redirectSubName.ptr(),args.ptr()));
if(ret.isNone())
return false;
ss.str("");
ss << ret.as_string();
return true;
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
return false;
}
// ---------------------------------------------------------
namespace App {

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

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

View File

@@ -76,16 +76,25 @@ private:
static std::vector<DocumentObserverPython*> _instances;
typedef boost::signals2::connection Connection;
Connection connectApplicationCreatedDocument;
Connection connectApplicationDeletedDocument;
Connection connectApplicationRelabelDocument;
Connection connectApplicationRenameDocument;
Connection connectApplicationActivateDocument;
Connection connectDocumentCreatedObject;
Connection connectDocumentDeletedObject;
Connection connectDocumentChangedObject;
Connection connectDocumentObjectInEdit;
Connection connectDocumentObjectResetEdit;
#define FC_PY_GDOC_OBSERVER \
FC_PY_ELEMENT(CreatedDocument,_1) \
FC_PY_ELEMENT(DeletedDocument,_1) \
FC_PY_ELEMENT(RelabelDocument,_1) \
FC_PY_ELEMENT(RenameDocument,_1) \
FC_PY_ELEMENT(ActivateDocument,_1) \
FC_PY_ELEMENT(CreatedObject,_1) \
FC_PY_ELEMENT(DeletedObject,_1) \
FC_PY_ELEMENT(ChangedObject,_1,_2) \
FC_PY_ELEMENT(InEdit,_1) \
FC_PY_ELEMENT(ResetEdit,_1)
#undef FC_PY_ELEMENT
#define FC_PY_ELEMENT(_name,...) \
Connection connect##_name;\
Py::Object py##_name;
FC_PY_GDOC_OBSERVER
};
} //namespace Gui

File diff suppressed because it is too large Load Diff

View File

@@ -24,9 +24,12 @@
#ifndef GUI_VIEWPROVIDERPYTHONFEATURE_H
#define GUI_VIEWPROVIDERPYTHONFEATURE_H
#include <App/Application.h>
#include <Gui/ViewProviderGeometryObject.h>
#include <Gui/Document.h>
#include <App/PropertyPythonObject.h>
#include <App/DynamicProperty.h>
#include <App/FeaturePython.h>
class SoSensor;
class SoDragger;
@@ -44,19 +47,23 @@ public:
};
/// constructor.
ViewProviderPythonFeatureImp(ViewProviderDocumentObject*);
ViewProviderPythonFeatureImp(ViewProviderDocumentObject*, App::PropertyPythonObject &);
/// destructor.
~ViewProviderPythonFeatureImp();
// Returns the icon
QIcon getIcon() const;
std::vector<App::DocumentObject*> claimChildren(const std::vector<App::DocumentObject*>&) const;
std::vector<App::DocumentObject*> claimChildren(std::vector<App::DocumentObject*>&&) const;
bool useNewSelectionModel() const;
ValueT getElementPicked(const SoPickedPoint *pp, std::string &subname) const;
std::string getElement(const SoDetail *det) const;
SoDetail* getDetail(const char*) const;
ValueT getDetailPath(const char *name, SoFullPath *path, bool append, SoDetail *&det) const;
std::vector<Base::Vector3d> getSelectionShape(const char* Element) const;
ValueT setEdit(int ModNum);
ValueT unsetEdit(int ModNum);
bool setEditViewer(View3DInventorViewer*, int ModNum);
bool unsetEditViewer(View3DInventorViewer*);
ValueT doubleClicked(void);
void setupContextMenu(QMenu* menu);
@@ -68,6 +75,7 @@ public:
void startRestoring();
void finishRestoring();
bool onDelete(const std::vector<std::string> & sub);
ValueT canDelete(App::DocumentObject *obj) const;
//@}
/** @name Display methods */
@@ -82,6 +90,8 @@ public:
std::string setDisplayMode(const char* ModeName);
//@}
ValueT canRemoveChildrenFromRoot() const;
/** @name Drag and drop */
//@{
/// Returns true if the view provider generally supports dragging objects
@@ -96,10 +106,86 @@ public:
ValueT canDropObject(App::DocumentObject*) const;
/// If the dropped object type is accepted the object will be added as child
ValueT dropObject(App::DocumentObject*);
/** Return false to force drop only operation for a give object*/
ValueT canDragAndDropObject(App::DocumentObject*) const;
/** Query object dropping with full quanlified name */
ValueT canDropObjectEx(App::DocumentObject *obj, App::DocumentObject *,
const char *,const std::vector<std::string> &elements) const;
/** Add an object with full quanlified name to the view provider by drag and drop */
ValueT dropObjectEx(App::DocumentObject *obj, App::DocumentObject *,
const char *, const std::vector<std::string> &elements, std::string &ret);
ValueT replaceObject(App::DocumentObject *, App::DocumentObject *);
//@}
ViewProviderDocumentObject *getLinkedViewProvider(bool recursive) const;
bool canAddToSceneGraph() const;
bool getDropPrefix(std::string &prefix) const;
private:
ViewProviderDocumentObject* object;
App::PropertyPythonObject &Proxy;
bool has__object__;
#define FC_PY_VIEW_OBJECT \
FC_PY_ELEMENT(getIcon) \
FC_PY_ELEMENT(claimChildren) \
FC_PY_ELEMENT(useNewSelectionModel) \
FC_PY_ELEMENT(getElementPicked) \
FC_PY_ELEMENT(getElement) \
FC_PY_ELEMENT(getDetail) \
FC_PY_ELEMENT(getDetailPath) \
FC_PY_ELEMENT(getSelectionShape) \
FC_PY_ELEMENT(setEdit) \
FC_PY_ELEMENT(unsetEdit) \
FC_PY_ELEMENT(setEditViewer) \
FC_PY_ELEMENT(unsetEditViewer) \
FC_PY_ELEMENT(doubleClicked) \
FC_PY_ELEMENT(setupContextMenu) \
FC_PY_ELEMENT(attach) \
FC_PY_ELEMENT(updateData) \
FC_PY_ELEMENT(onChanged) \
FC_PY_ELEMENT(startRestoring) \
FC_PY_ELEMENT(finishRestoring) \
FC_PY_ELEMENT(onDelete) \
FC_PY_ELEMENT(canDelete) \
FC_PY_ELEMENT(isShow) \
FC_PY_ELEMENT(getDefaultDisplayMode) \
FC_PY_ELEMENT(getDisplayModes) \
FC_PY_ELEMENT(setDisplayMode) \
FC_PY_ELEMENT(canRemoveChildrenFromRoot) \
FC_PY_ELEMENT(canDragObjects) \
FC_PY_ELEMENT(canDragObject) \
FC_PY_ELEMENT(dragObject) \
FC_PY_ELEMENT(canDropObjects) \
FC_PY_ELEMENT(canDropObject) \
FC_PY_ELEMENT(dropObject) \
FC_PY_ELEMENT(canDragAndDropObject) \
FC_PY_ELEMENT(canDropObjectEx) \
FC_PY_ELEMENT(dropObjectEx) \
FC_PY_ELEMENT(canAddToSceneGraph) \
FC_PY_ELEMENT(getDropPrefix) \
FC_PY_ELEMENT(replaceObject) \
FC_PY_ELEMENT(getLinkedViewProvider) \
#undef FC_PY_ELEMENT
#define FC_PY_ELEMENT(_name) FC_PY_ELEMENT_DEFINE(_name)
FC_PY_VIEW_OBJECT
#undef FC_PY_ELEMENT
#define FC_PY_ELEMENT(_name) FC_PY_ELEMENT_FLAG(_name)
enum Flag {
FC_PY_VIEW_OBJECT
FlagMax,
};
typedef std::bitset<FlagMax> Flags;
mutable Flags _Flags;
public:
void init(PyObject *pyobj);
};
template <class ViewProviderT>
@@ -111,7 +197,7 @@ public:
/// constructor.
ViewProviderPythonFeatureT() : _attached(false) {
ADD_PROPERTY(Proxy,(Py::Object()));
imp = new ViewProviderPythonFeatureImp(this);
imp = new ViewProviderPythonFeatureImp(this,Proxy);
}
/// destructor.
virtual ~ViewProviderPythonFeatureT() {
@@ -149,6 +235,14 @@ public:
virtual bool useNewSelectionModel() const {
return imp->useNewSelectionModel();
}
virtual bool getElementPicked(const SoPickedPoint *pp, std::string &subname) const {
auto ret = imp->getElementPicked(pp,subname);
if(ret == ViewProviderPythonFeatureImp::NotImplemented)
return ViewProviderT::getElementPicked(pp,subname);
else if(ret == ViewProviderPythonFeatureImp::Accepted)
return true;
return false;
}
virtual std::string getElement(const SoDetail *det) const {
std::string name = imp->getElement(det);
if (!name.empty()) return name;
@@ -159,6 +253,12 @@ public:
if (det) return det;
return ViewProviderT::getDetail(name);
}
virtual bool getDetailPath(const char *name, SoFullPath *path, bool append,SoDetail *&det) const {
auto ret = imp->getDetailPath(name,path,append,det);
if(ret == ViewProviderPythonFeatureImp::NotImplemented)
return ViewProviderT::getDetailPath(name,path,append,det);
return ret == ViewProviderPythonFeatureImp::Accepted;
}
virtual std::vector<Base::Vector3d> getSelectionShape(const char* Element) const {
return ViewProviderT::getSelectionShape(Element);
};
@@ -183,15 +283,27 @@ public:
if (!ok) return ok;
return ViewProviderT::onDelete(sub);
}
virtual bool canDelete(App::DocumentObject *obj) const override {
switch(imp->canDelete(obj)) {
case ViewProviderPythonFeatureImp::Accepted:
return true;
case ViewProviderPythonFeatureImp::Rejected:
return false;
default:
return ViewProviderT::canDelete(obj);
}
}
//@}
/** @name Restoring view provider from document load */
//@{
virtual void startRestoring() {
ViewProviderT::startRestoring();
imp->startRestoring();
}
virtual void finishRestoring() {
imp->finishRestoring();
ViewProviderT::finishRestoring();
}
//@}
@@ -221,6 +333,7 @@ public:
}
/// Starts to drag the object
virtual void dragObject(App::DocumentObject* obj) {
App::AutoTransaction committer;
switch (imp->dragObject(obj)) {
case ViewProviderPythonFeatureImp::Accepted:
case ViewProviderPythonFeatureImp::Rejected:
@@ -253,6 +366,7 @@ public:
}
/// If the dropped object type is accepted the object will be added as child
virtual void dropObject(App::DocumentObject* obj) {
App::AutoTransaction committer;
switch (imp->dropObject(obj)) {
case ViewProviderPythonFeatureImp::Accepted:
case ViewProviderPythonFeatureImp::Rejected:
@@ -261,6 +375,44 @@ public:
return ViewProviderT::dropObject(obj);
}
}
/** Return false to force drop only operation for a give object*/
virtual bool canDragAndDropObject(App::DocumentObject *obj) const override {
switch (imp->canDragAndDropObject(obj)) {
case ViewProviderPythonFeatureImp::Accepted:
return true;
case ViewProviderPythonFeatureImp::Rejected:
return false;
default:
return ViewProviderT::canDragAndDropObject(obj);
}
}
virtual bool canDropObjectEx(App::DocumentObject *obj, App::DocumentObject *owner,
const char *subname, const std::vector<std::string> &elements) const override
{
switch (imp->canDropObjectEx(obj,owner,subname,elements)) {
case ViewProviderPythonFeatureImp::Accepted:
return true;
case ViewProviderPythonFeatureImp::Rejected:
return false;
default:
return ViewProviderT::canDropObjectEx(obj,owner,subname,elements);
}
}
/** Add an object with full quanlified name to the view provider by drag and drop */
virtual std::string dropObjectEx(App::DocumentObject *obj, App::DocumentObject *owner,
const char *subname, const std::vector<std::string> &elements)
{
App::AutoTransaction committer;
std::string ret;
switch (imp->dropObjectEx(obj,owner,subname,elements,ret)) {
case ViewProviderPythonFeatureImp::NotImplemented:
ret = ViewProviderT::dropObjectEx(obj,owner,subname,elements);
break;
default:
break;
}
return ret;
}
//@}
/** @name Display methods */
@@ -290,14 +442,29 @@ public:
}
//@}
virtual bool canRemoveChildrenFromRoot() const override {
switch(imp->canRemoveChildrenFromRoot()) {
case ViewProviderPythonFeatureImp::NotImplemented:
return ViewProviderT::canRemoveChildrenFromRoot();
case ViewProviderPythonFeatureImp::Accepted:
return true;
default:
return false;
}
}
PyObject* getPyObject() {
return ViewProviderT::getPyObject();
}
virtual bool canAddToSceneGraph() const override {
return ViewProviderT::canAddToSceneGraph() && imp->canAddToSceneGraph();
}
protected:
virtual void onChanged(const App::Property* prop) {
if (prop == &Proxy) {
imp->init(Proxy.getValue().ptr());
if (ViewProviderT::pcObject && !Proxy.getValue().is(Py::_None())) {
if (!_attached) {
_attached = true;
@@ -307,6 +474,12 @@ protected:
ViewProviderT::DisplayMode.touch();
ViewProviderT::setOverrideMode(viewerMode);
}
if(!this->testStatus(Gui::isRestoring) &&
ViewProviderT::canAddToSceneGraph() &&
!imp->canAddToSceneGraph())
{
this->getDocument()->toggleInSceneGraph(this);
}
ViewProviderT::updateView();
}
}
@@ -338,6 +511,40 @@ protected:
return ViewProviderT::unsetEdit(ModNum);
}
}
virtual void setEditViewer(View3DInventorViewer *viewer, int ModNum) {
if(!imp->setEditViewer(viewer,ModNum))
ViewProviderT::setEditViewer(viewer,ModNum);
}
virtual void unsetEditViewer(View3DInventorViewer *viewer) {
if(!imp->unsetEditViewer(viewer))
ViewProviderT::unsetEditViewer(viewer);
}
virtual std::string getDropPrefix() const {
std::string prefix;
if(!imp->getDropPrefix(prefix))
return ViewProviderT::getDropPrefix();
return prefix;
}
virtual int replaceObject(App::DocumentObject *oldObj, App::DocumentObject *newObj) {
App::AutoTransaction committer;
switch (imp->replaceObject(oldObj,newObj)) {
case ViewProviderPythonFeatureImp::Accepted:
return 1;
case ViewProviderPythonFeatureImp::Rejected:
return 0;
default:
return ViewProviderT::replaceObject(oldObj,newObj);
}
}
virtual ViewProviderDocumentObject *getLinkedViewProvider(bool recursive=false) const {
auto res = imp->getLinkedViewProvider(recursive);
if(!res)
res = ViewProviderT::getLinkedViewProvider();
return res;
}
public:
virtual void setupContextMenu(QMenu* menu, QObject* recipient, const char* member)
@@ -349,6 +556,7 @@ public:
protected:
virtual bool doubleClicked(void)
{
App::AutoTransaction committer;
switch (imp->doubleClicked()) {
case ViewProviderPythonFeatureImp::Accepted:
return true;

View File

@@ -402,6 +402,23 @@ Py::Object PythonWrapper::fromQIcon(const QIcon* icon)
throw Py::RuntimeError("Failed to wrap icon");
}
QIcon *PythonWrapper::toQIcon(PyObject *pyobj)
{
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)
PyTypeObject * type = Shiboken::SbkType<QIcon>();
if(type) {
if (Shiboken::Object::checkType(pyobj)) {
SbkObject* sbkobject = reinterpret_cast<SbkObject *>(pyobj);
void* cppobject = Shiboken::Object::cppPointer(sbkobject, type);
return reinterpret_cast<QIcon*>(cppobject);
}
}
#else
Q_UNUSED(pyobj);
#endif
return 0;
}
Py::Object PythonWrapper::fromQWidget(QWidget* widget, const char* className)
{
#if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE)

View File

@@ -56,6 +56,7 @@ public:
and the Python wrapper takes ownership of it.
*/
Py::Object fromQIcon(const QIcon*);
QIcon *toQIcon(PyObject *pyobj);
static void createChildrenNameAttributes(PyObject* root, QObject* object);
static void setParent(PyObject* pyWdg, QObject* parent);
};