1
/***************************************************************************
2
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
24
#include "PreCompiled.h"
29
#include <App/DocumentObjectPy.h>
30
#include <Base/Interpreter.h>
31
#include <Base/MatrixPy.h>
32
#include <Base/Tools.h>
34
#include "FeaturePython.h"
35
#include "FeaturePythonPyImp.h"
40
FeaturePythonImp::FeaturePythonImp(App::DocumentObject* o)
45
FeaturePythonImp::~FeaturePythonImp()
47
Base::PyGILStateLocker lock;
49
#define FC_PY_ELEMENT(_name) py_##_name = Py::None();
54
catch (Py::Exception& e) {
59
void FeaturePythonImp::init(PyObject *pyobj) {
60
Base::PyGILStateLocker lock;
61
has__object__ = !!PyObject_HasAttrString(pyobj, "__object__");
64
#define FC_PY_ELEMENT(_name) FC_PY_ELEMENT_INIT(_name)
69
#define FC_PY_CALL_CHECK(_name) _FC_PY_CALL_CHECK(_name,return(false))
72
Calls the execute() method of the Python feature class. If the Python feature class doesn't have an execute()
73
method or if it returns False this method also return false and true otherwise.
75
bool FeaturePythonImp::execute()
77
FC_PY_CALL_CHECK(execute)
78
Base::PyGILStateLocker lock;
81
Py::Object res = Base::pyCall(py_execute.ptr());
82
if (res.isBoolean() && !res.isTrue())
88
args.setItem(0, Py::Object(object->getPyObject(), true));
89
Py::Object res = Base::pyCall(py_execute.ptr(),args.ptr());
90
if (res.isBoolean() && !res.isTrue())
95
catch (Py::Exception&) {
96
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
100
Base::PyException::ThrowException(); // extract the Python error text
106
bool FeaturePythonImp::mustExecute() const
108
FC_PY_CALL_CHECK(mustExecute)
109
Base::PyGILStateLocker lock;
112
Py::Object res(Base::pyCall(py_mustExecute.ptr()));
117
args.setItem(0, Py::Object(object->getPyObject(), true));
118
Py::Object res(Base::pyCall(py_mustExecute.ptr(),args.ptr()));
122
catch (Py::Exception&) {
123
Base::PyException e; // extract the Python error text
130
void FeaturePythonImp::onBeforeChange(const Property* prop)
132
if (py_onBeforeChange.isNone())
135
// Run the execute method of the proxy object.
136
Base::PyGILStateLocker lock;
138
const char *prop_name = object->getPropertyName(prop);
143
args.setItem(0, Py::String(prop_name));
144
Base::pyCall(py_onBeforeChange.ptr(),args.ptr());
148
args.setItem(0, Py::Object(object->getPyObject(), true));
149
args.setItem(1, Py::String(prop_name));
150
Base::pyCall(py_onBeforeChange.ptr(),args.ptr());
153
catch (Py::Exception&) {
154
Base::PyException e; // extract the Python error text
159
bool FeaturePythonImp::onBeforeChangeLabel(std::string &newLabel)
161
if(py_onBeforeChangeLabel.isNone())
164
// Run the execute method of the proxy object.
165
Base::PyGILStateLocker lock;
168
args.setItem(0, Py::Object(object->getPyObject(), true));
169
args.setItem(1,Py::String(newLabel));
170
Py::Object ret(Base::pyCall(py_onBeforeChangeLabel.ptr(),args.ptr()));
173
throw Py::TypeError("onBeforeChangeLabel expects to return a string");
174
newLabel = ret.as_string();
178
catch (Py::Exception&) {
179
Base::PyException e; // extract the Python error text
185
void FeaturePythonImp::onChanged(const Property* prop)
187
if (py_onChanged.isNone())
189
// Run the execute method of the proxy object.
190
Base::PyGILStateLocker lock;
192
const char *prop_name = object->getPropertyName(prop);
197
args.setItem(0, Py::String(prop_name));
198
Base::pyCall(py_onChanged.ptr(),args.ptr());
202
args.setItem(0, Py::Object(object->getPyObject(), true));
203
args.setItem(1, Py::String(prop_name));
204
Base::pyCall(py_onChanged.ptr(),args.ptr());
207
catch (Py::Exception&) {
208
Base::PyException e; // extract the Python error text
213
void FeaturePythonImp::onDocumentRestored()
215
_FC_PY_CALL_CHECK(onDocumentRestored,return);
217
// Run the execute method of the proxy object.
218
Base::PyGILStateLocker lock;
221
Base::pyCall(py_onDocumentRestored.ptr());
225
args.setItem(0, Py::Object(object->getPyObject(), true));
226
Base::pyCall(py_onDocumentRestored.ptr(),args.ptr());
229
catch (Py::Exception&) {
230
Base::PyException e; // extract the Python error text
235
void FeaturePythonImp::unsetupObject()
237
_FC_PY_CALL_CHECK(unsetupObject, return);
239
// Run the execute method of the proxy object.
240
Base::PyGILStateLocker lock;
243
Base::pyCall(py_unsetupObject.ptr());
247
args.setItem(0, Py::Object(object->getPyObject(), true));
248
Base::pyCall(py_unsetupObject.ptr(), args.ptr());
251
catch (Py::Exception&) {
252
Base::PyException e; // extract the Python error text
257
bool FeaturePythonImp::getSubObject(DocumentObject *&ret, const char *subname,
258
PyObject **pyObj, Base::Matrix4D *_mat, bool transform, int depth) const
260
FC_PY_CALL_CHECK(getSubObject);
261
Base::PyGILStateLocker lock;
264
args.setItem(0, Py::Object(object->getPyObject(), true));
265
if(!subname) subname = "";
266
args.setItem(1,Py::String(subname));
267
args.setItem(2,Py::Int(pyObj?2:1));
268
Base::MatrixPy *pyMat = new Base::MatrixPy(new Base::Matrix4D);
269
if(_mat) *pyMat->getMatrixPtr() = *_mat;
270
args.setItem(3,Py::asObject(pyMat));
271
args.setItem(4,Py::Boolean(transform));
272
args.setItem(5,Py::Int(depth));
274
Py::Object res(Base::pyCall(py_getSubObject.ptr(),args.ptr()));
281
if(!res.isSequence())
282
throw Py::TypeError("getSubObject expects return type of tuple");
283
Py::Sequence seq(res);
284
if(seq.length() < 2 ||
285
(!seq.getItem(0).isNone() &&
286
!PyObject_TypeCheck(seq.getItem(0).ptr(),&DocumentObjectPy::Type)) ||
287
!PyObject_TypeCheck(seq.getItem(1).ptr(),&Base::MatrixPy::Type))
289
throw Py::TypeError("getSubObject expects return type of (obj,matrix,pyobj)");
292
*_mat = *static_cast<Base::MatrixPy*>(seq.getItem(1).ptr())->getMatrixPtr();
295
*pyObj = Py::new_reference_to(seq.getItem(2));
297
*pyObj = Py::new_reference_to(Py::None());
299
if(seq.getItem(0).isNone())
302
ret = static_cast<DocumentObjectPy*>(seq.getItem(0).ptr())->getDocumentObjectPtr();
305
catch (Py::Exception&) {
306
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
310
Base::PyException e; // extract the Python error text
317
bool FeaturePythonImp::getSubObjects(std::vector<std::string> &ret, int reason) const {
318
FC_PY_CALL_CHECK(getSubObjects);
319
Base::PyGILStateLocker lock;
322
args.setItem(0, Py::Object(object->getPyObject(), true));
323
args.setItem(1, Py::Int(reason));
324
Py::Object res(Base::pyCall(py_getSubObjects.ptr(),args.ptr()));
327
if(!res.isSequence())
328
throw Py::TypeError("getSubObjects expects return type of tuple");
329
Py::Sequence seq(res);
330
for(Py_ssize_t i=0;i<seq.length();++i) {
331
Py::Object name(seq[i].ptr());
333
throw Py::TypeError("getSubObjects expects string in returned sequence");
334
ret.push_back(name.as_string());
338
catch (Py::Exception&) {
339
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
343
Base::PyException e; // extract the Python error text
349
bool FeaturePythonImp::getLinkedObject(DocumentObject *&ret, bool recurse,
350
Base::Matrix4D *_mat, bool transform, int depth) const
352
FC_PY_CALL_CHECK(getLinkedObject);
353
Base::PyGILStateLocker lock;
356
args.setItem(0, Py::Object(object->getPyObject(), true));
357
args.setItem(1,Py::Boolean(recurse));
358
Base::MatrixPy *pyMat = new Base::MatrixPy(new Base::Matrix4D);
359
if(_mat) *pyMat->getMatrixPtr() = *_mat;
360
args.setItem(2,Py::asObject(pyMat));
361
args.setItem(3,Py::Boolean(transform));
362
args.setItem(4,Py::Int(depth));
364
Py::Object res(Base::pyCall(py_getLinkedObject.ptr(),args.ptr()));
369
if(!res.isSequence())
370
throw Py::TypeError("getLinkedObject expects return type of (object,matrix)");
371
Py::Sequence seq(res);
372
if(seq.length() != 2 ||
373
(!seq.getItem(0).isNone() &&
374
!PyObject_TypeCheck(seq.getItem(0).ptr(),&DocumentObjectPy::Type)) ||
375
!PyObject_TypeCheck(seq.getItem(1).ptr(),&Base::MatrixPy::Type))
377
throw Py::TypeError("getLinkedObject expects return type of (object,matrix)");
380
*_mat = *static_cast<Base::MatrixPy*>(seq.getItem(1).ptr())->getMatrixPtr();
381
if(seq.getItem(0).isNone())
384
ret = static_cast<DocumentObjectPy*>(seq.getItem(0).ptr())->getDocumentObjectPtr();
387
catch (Py::Exception&) {
388
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
392
Base::PyException e; // extract the Python error text
399
PyObject *FeaturePythonImp::getPyObject()
401
// ref counter is set to 1
402
return new FeaturePythonPyT<DocumentObjectPy>(object);
405
FeaturePythonImp::ValueT
406
FeaturePythonImp::hasChildElement() const
408
_FC_PY_CALL_CHECK(hasChildElement,return(NotImplemented));
409
Base::PyGILStateLocker lock;
412
args.setItem(0, Py::Object(object->getPyObject(), true));
413
Py::Boolean ok(Base::pyCall(py_hasChildElement.ptr(),args.ptr()));
414
return static_cast<bool>(ok) ? Accepted : Rejected;
416
catch (Py::Exception&) {
417
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
419
return NotImplemented;
422
Base::PyException e; // extract the Python error text
428
int FeaturePythonImp::isElementVisible(const char *element) const {
429
_FC_PY_CALL_CHECK(isElementVisible,return(-2));
430
Base::PyGILStateLocker lock;
433
args.setItem(0, Py::Object(object->getPyObject(), true));
434
args.setItem(1,Py::String(element?element:""));
435
return Py::Int(Base::pyCall(py_isElementVisible.ptr(),args.ptr()));
437
catch (Py::Exception&) {
438
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
442
Base::PyException e; // extract the Python error text
448
int FeaturePythonImp::setElementVisible(const char *element, bool visible) {
449
_FC_PY_CALL_CHECK(setElementVisible,return(-2));
450
Base::PyGILStateLocker lock;
453
args.setItem(0, Py::Object(object->getPyObject(), true));
454
args.setItem(1,Py::String(element?element:""));
455
args.setItem(2,Py::Boolean(visible));
456
return Py::Int(Base::pyCall(py_setElementVisible.ptr(),args.ptr()));
458
catch (Py::Exception&) {
459
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
463
Base::PyException e; // extract the Python error text
469
std::string FeaturePythonImp::getViewProviderName()
471
_FC_PY_CALL_CHECK(getViewProviderName,return(std::string()));
472
Base::PyGILStateLocker lock;
474
Py::TupleN args(Py::Object(object->getPyObject(), true));
475
Py::String ret(Base::pyCall(py_getViewProviderName.ptr(),args.ptr()));
476
return ret.as_string();
478
catch (Py::Exception&) {
479
Base::PyException e; // extract the Python error text
486
FeaturePythonImp::ValueT
487
FeaturePythonImp::canLinkProperties() const
489
_FC_PY_CALL_CHECK(canLinkProperties,return(NotImplemented));
490
Base::PyGILStateLocker lock;
493
args.setItem(0, Py::Object(object->getPyObject(), true));
494
Py::Boolean ok(Base::pyCall(py_canLinkProperties.ptr(),args.ptr()));
495
return ok ? Accepted : Rejected;
497
catch (Py::Exception&) {
498
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
500
return NotImplemented;
502
Base::PyException e; // extract the Python error text
508
FeaturePythonImp::ValueT
509
FeaturePythonImp::allowDuplicateLabel() const
511
_FC_PY_CALL_CHECK(allowDuplicateLabel,return(NotImplemented));
512
Base::PyGILStateLocker lock;
515
args.setItem(0, Py::Object(object->getPyObject(), true));
516
Py::Boolean ok(Base::pyCall(py_allowDuplicateLabel.ptr(),args.ptr()));
517
return ok ? Accepted : Rejected;
519
catch (Py::Exception&) {
520
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
522
return NotImplemented;
525
Base::PyException e; // extract the Python error text
531
int FeaturePythonImp::canLoadPartial() const {
532
_FC_PY_CALL_CHECK(canLoadPartial,return(-1));
533
Base::PyGILStateLocker lock;
536
args.setItem(0, Py::Object(object->getPyObject(), true));
537
Py::Int ret(Base::pyCall(py_canLoadPartial.ptr(),args.ptr()));
540
catch (Py::Exception&) {
541
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
545
Base::PyException e; // extract the Python error text
551
FeaturePythonImp::ValueT
552
FeaturePythonImp::redirectSubName(std::ostringstream &ss,
553
App::DocumentObject *topParent,
554
App::DocumentObject *child) const
556
_FC_PY_CALL_CHECK(redirectSubName,return(NotImplemented));
557
Base::PyGILStateLocker lock;
560
args.setItem(0, Py::Object(object->getPyObject(), true));
561
args.setItem(1,Py::String(ss.str()));
562
args.setItem(2,topParent?Py::Object(topParent->getPyObject(),true):Py::Object());
563
args.setItem(3,child?Py::Object(child->getPyObject(),true):Py::Object());
564
Py::Object ret(Base::pyCall(py_redirectSubName.ptr(),args.ptr()));
568
ss << ret.as_string();
571
catch (Py::Exception&) {
572
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
574
return NotImplemented;
577
Base::PyException e; // extract the Python error text
583
bool FeaturePythonImp::editProperty(const char *name)
585
_FC_PY_CALL_CHECK(editProperty,return false);
586
Base::PyGILStateLocker lock;
589
args.setItem(0, Py::String(name));
590
Py::Object ret(Base::pyCall(py_editProperty.ptr(),args.ptr()));
593
catch (Py::Exception&) {
594
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
599
Base::PyException e; // extract the Python error text
605
// ---------------------------------------------------------
608
PROPERTY_SOURCE_TEMPLATE(App::FeaturePython, App::DocumentObject)
609
template<> const char* App::FeaturePython::getViewProviderName() const {
610
return "Gui::ViewProviderPythonFeature";
612
template<> PyObject* App::FeaturePython::getPyObject() {
613
if (PythonObject.is(Py::_None())) {
614
// ref counter is set to 1
615
PythonObject = Py::Object(new FeaturePythonPyT<DocumentObjectPy>(this),true);
617
return Py::new_reference_to(PythonObject);
619
// explicit template instantiation
620
template class AppExport FeaturePythonT<DocumentObject>;
623
// ---------------------------------------------------------
626
PROPERTY_SOURCE_TEMPLATE(App::GeometryPython, App::GeoFeature)
627
template<> const char* App::GeometryPython::getViewProviderName() const {
628
return "Gui::ViewProviderPythonGeometry";
630
// explicit template instantiation
631
template class AppExport FeaturePythonT<GeoFeature>;