FreeCAD

Форк
0
/
FeaturePython.cpp 
632 строки · 20.9 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de>              *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23

24
#include "PreCompiled.h"
25
#ifndef _PreComp_
26
# include <sstream>
27
#endif
28

29
#include <App/DocumentObjectPy.h>
30
#include <Base/Interpreter.h>
31
#include <Base/MatrixPy.h>
32
#include <Base/Tools.h>
33

34
#include "FeaturePython.h"
35
#include "FeaturePythonPyImp.h"
36

37

38
using namespace App;
39

40
FeaturePythonImp::FeaturePythonImp(App::DocumentObject* o)
41
    : object(o)
42
{
43
}
44

45
FeaturePythonImp::~FeaturePythonImp()
46
{
47
    Base::PyGILStateLocker lock;
48
#undef FC_PY_ELEMENT
49
#define FC_PY_ELEMENT(_name) py_##_name = Py::None();
50

51
    try {
52
        FC_PY_FEATURE_PYTHON
53
    }
54
    catch (Py::Exception& e) {
55
        e.clear();
56
    }
57
}
58

59
void FeaturePythonImp::init(PyObject *pyobj) {
60
    Base::PyGILStateLocker lock;
61
    has__object__ = !!PyObject_HasAttrString(pyobj, "__object__");
62

63
#undef FC_PY_ELEMENT
64
#define FC_PY_ELEMENT(_name) FC_PY_ELEMENT_INIT(_name)
65

66
    FC_PY_FEATURE_PYTHON
67
}
68

69
#define FC_PY_CALL_CHECK(_name) _FC_PY_CALL_CHECK(_name,return(false))
70

71
/*!
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.
74
 */
75
bool FeaturePythonImp::execute()
76
{
77
    FC_PY_CALL_CHECK(execute)
78
    Base::PyGILStateLocker lock;
79
    try {
80
        if (has__object__) {
81
            Py::Object res = Base::pyCall(py_execute.ptr());
82
            if (res.isBoolean() && !res.isTrue())
83
                return false;
84
            return true;
85
        }
86
        else {
87
            Py::Tuple args(1);
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())
91
                return false;
92
            return true;
93
        }
94
    }
95
    catch (Py::Exception&) {
96
        if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
97
            PyErr_Clear();
98
            return false;
99
        }
100
        Base::PyException::ThrowException(); // extract the Python error text
101
    }
102

103
    return false;
104
}
105

106
bool FeaturePythonImp::mustExecute() const
107
{
108
    FC_PY_CALL_CHECK(mustExecute)
109
    Base::PyGILStateLocker lock;
110
    try {
111
        if (has__object__) {
112
            Py::Object res(Base::pyCall(py_mustExecute.ptr()));
113
            return res.isTrue();
114
        }
115
        else {
116
            Py::Tuple args(1);
117
            args.setItem(0, Py::Object(object->getPyObject(), true));
118
            Py::Object res(Base::pyCall(py_mustExecute.ptr(),args.ptr()));
119
            return res.isTrue();
120
        }
121
    }
122
    catch (Py::Exception&) {
123
        Base::PyException e; // extract the Python error text
124
        e.ReportException();
125
    }
126
    return false;
127
}
128

129

130
void FeaturePythonImp::onBeforeChange(const Property* prop)
131
{
132
    if (py_onBeforeChange.isNone())
133
        return;
134

135
    // Run the execute method of the proxy object.
136
    Base::PyGILStateLocker lock;
137
    try {
138
        const char *prop_name = object->getPropertyName(prop);
139
        if (!prop_name)
140
            return;
141
        if (has__object__) {
142
            Py::Tuple args(1);
143
            args.setItem(0, Py::String(prop_name));
144
            Base::pyCall(py_onBeforeChange.ptr(),args.ptr());
145
        }
146
        else {
147
            Py::Tuple args(2);
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());
151
        }
152
    }
153
    catch (Py::Exception&) {
154
        Base::PyException e; // extract the Python error text
155
        e.ReportException();
156
    }
157
}
158

159
bool FeaturePythonImp::onBeforeChangeLabel(std::string &newLabel)
160
{
161
    if(py_onBeforeChangeLabel.isNone())
162
        return false;
163

164
    // Run the execute method of the proxy object.
165
    Base::PyGILStateLocker lock;
166
    try {
167
        Py::Tuple args(2);
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()));
171
        if(!ret.isNone()) {
172
            if(!ret.isString())
173
                throw Py::TypeError("onBeforeChangeLabel expects to return a string");
174
            newLabel = ret.as_string();
175
            return true;
176
        }
177
    }
178
    catch (Py::Exception&) {
179
        Base::PyException e; // extract the Python error text
180
        e.ReportException();
181
    }
182
    return false;
183
}
184

185
void FeaturePythonImp::onChanged(const Property* prop)
186
{
187
    if (py_onChanged.isNone())
188
        return;
189
    // Run the execute method of the proxy object.
190
    Base::PyGILStateLocker lock;
191
    try {
192
        const char *prop_name = object->getPropertyName(prop);
193
        if (!prop_name)
194
            return;
195
        if (has__object__) {
196
            Py::Tuple args(1);
197
            args.setItem(0, Py::String(prop_name));
198
            Base::pyCall(py_onChanged.ptr(),args.ptr());
199
        }
200
        else {
201
            Py::Tuple args(2);
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());
205
        }
206
    }
207
    catch (Py::Exception&) {
208
        Base::PyException e; // extract the Python error text
209
        e.ReportException();
210
    }
211
}
212

213
void FeaturePythonImp::onDocumentRestored()
214
{
215
    _FC_PY_CALL_CHECK(onDocumentRestored,return);
216

217
    // Run the execute method of the proxy object.
218
    Base::PyGILStateLocker lock;
219
    try {
220
        if (has__object__) {
221
            Base::pyCall(py_onDocumentRestored.ptr());
222
        }
223
        else {
224
            Py::Tuple args(1);
225
            args.setItem(0, Py::Object(object->getPyObject(), true));
226
            Base::pyCall(py_onDocumentRestored.ptr(),args.ptr());
227
        }
228
    }
229
    catch (Py::Exception&) {
230
        Base::PyException e; // extract the Python error text
231
        e.ReportException();
232
    }
233
}
234

235
void FeaturePythonImp::unsetupObject()
236
{
237
    _FC_PY_CALL_CHECK(unsetupObject, return);
238

239
    // Run the execute method of the proxy object.
240
    Base::PyGILStateLocker lock;
241
    try {
242
        if (has__object__) {
243
            Base::pyCall(py_unsetupObject.ptr());
244
        }
245
        else {
246
            Py::Tuple args(1);
247
            args.setItem(0, Py::Object(object->getPyObject(), true));
248
            Base::pyCall(py_unsetupObject.ptr(), args.ptr());
249
        }
250
    }
251
    catch (Py::Exception&) {
252
        Base::PyException e; // extract the Python error text
253
        e.ReportException();
254
    }
255
}
256

257
bool FeaturePythonImp::getSubObject(DocumentObject *&ret, const char *subname,
258
    PyObject **pyObj, Base::Matrix4D *_mat, bool transform, int depth) const
259
{
260
    FC_PY_CALL_CHECK(getSubObject);
261
    Base::PyGILStateLocker lock;
262
    try {
263
        Py::Tuple args(6);
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));
273

274
        Py::Object res(Base::pyCall(py_getSubObject.ptr(),args.ptr()));
275
        if(res.isNone()) {
276
            ret = nullptr;
277
            return true;
278
        }
279
        if(!res.isTrue())
280
            return false;
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))
288
        {
289
            throw Py::TypeError("getSubObject expects return type of (obj,matrix,pyobj)");
290
        }
291
        if(_mat)
292
            *_mat = *static_cast<Base::MatrixPy*>(seq.getItem(1).ptr())->getMatrixPtr();
293
        if(pyObj) {
294
            if(seq.length()>2)
295
                *pyObj = Py::new_reference_to(seq.getItem(2));
296
            else
297
                *pyObj = Py::new_reference_to(Py::None());
298
        }
299
        if(seq.getItem(0).isNone())
300
            ret = nullptr;
301
        else
302
            ret = static_cast<DocumentObjectPy*>(seq.getItem(0).ptr())->getDocumentObjectPtr();
303
        return true;
304
    }
305
    catch (Py::Exception&) {
306
        if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
307
            PyErr_Clear();
308
            return false;
309
        }
310
        Base::PyException e; // extract the Python error text
311
        e.ReportException();
312
        ret = nullptr;
313
        return true;
314
    }
315
}
316

317
bool FeaturePythonImp::getSubObjects(std::vector<std::string> &ret, int reason) const {
318
    FC_PY_CALL_CHECK(getSubObjects);
319
    Base::PyGILStateLocker lock;
320
    try {
321
        Py::Tuple args(2);
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()));
325
        if(!res.isTrue())
326
            return true;
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());
332
            if(!name.isString())
333
                throw Py::TypeError("getSubObjects expects string in returned sequence");
334
            ret.push_back(name.as_string());
335
        }
336
        return true;
337
    }
338
    catch (Py::Exception&) {
339
        if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
340
            PyErr_Clear();
341
            return false;
342
        }
343
        Base::PyException e; // extract the Python error text
344
        e.ReportException();
345
        return true;
346
    }
347
}
348

349
bool FeaturePythonImp::getLinkedObject(DocumentObject *&ret, bool recurse,
350
        Base::Matrix4D *_mat, bool transform, int depth) const
351
{
352
    FC_PY_CALL_CHECK(getLinkedObject);
353
    Base::PyGILStateLocker lock;
354
    try {
355
        Py::Tuple args(5);
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));
363

364
        Py::Object res(Base::pyCall(py_getLinkedObject.ptr(),args.ptr()));
365
        if(!res.isTrue()) {
366
            ret = object;
367
            return true;
368
        }
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))
376
        {
377
            throw Py::TypeError("getLinkedObject expects return type of (object,matrix)");
378
        }
379
        if(_mat)
380
            *_mat = *static_cast<Base::MatrixPy*>(seq.getItem(1).ptr())->getMatrixPtr();
381
        if(seq.getItem(0).isNone())
382
            ret = object;
383
        else
384
            ret = static_cast<DocumentObjectPy*>(seq.getItem(0).ptr())->getDocumentObjectPtr();
385
        return true;
386
    }
387
    catch (Py::Exception&) {
388
        if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
389
            PyErr_Clear();
390
            return false;
391
        }
392
        Base::PyException e; // extract the Python error text
393
        e.ReportException();
394
        ret = nullptr;
395
        return true;
396
    }
397
}
398

399
PyObject *FeaturePythonImp::getPyObject()
400
{
401
    // ref counter is set to 1
402
    return new FeaturePythonPyT<DocumentObjectPy>(object);
403
}
404

405
FeaturePythonImp::ValueT
406
FeaturePythonImp::hasChildElement() const
407
{
408
    _FC_PY_CALL_CHECK(hasChildElement,return(NotImplemented));
409
    Base::PyGILStateLocker lock;
410
    try {
411
        Py::Tuple args(1);
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;
415
    }
416
    catch (Py::Exception&) {
417
        if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
418
            PyErr_Clear();
419
            return NotImplemented;
420
        }
421

422
        Base::PyException e; // extract the Python error text
423
        e.ReportException();
424
        return Rejected;
425
    }
426
}
427

428
int FeaturePythonImp::isElementVisible(const char *element) const {
429
    _FC_PY_CALL_CHECK(isElementVisible,return(-2));
430
    Base::PyGILStateLocker lock;
431
    try {
432
        Py::Tuple args(2);
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()));
436
    }
437
    catch (Py::Exception&) {
438
        if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
439
            PyErr_Clear();
440
            return -2;
441
        }
442
        Base::PyException e; // extract the Python error text
443
        e.ReportException();
444
        return -1;
445
    }
446
}
447

448
int FeaturePythonImp::setElementVisible(const char *element, bool visible) {
449
    _FC_PY_CALL_CHECK(setElementVisible,return(-2));
450
    Base::PyGILStateLocker lock;
451
    try {
452
        Py::Tuple args(3);
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()));
457
    }
458
    catch (Py::Exception&) {
459
        if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
460
            PyErr_Clear();
461
            return -2;
462
        }
463
        Base::PyException e; // extract the Python error text
464
        e.ReportException();
465
        return -1;
466
    }
467
}
468

469
std::string FeaturePythonImp::getViewProviderName()
470
{
471
    _FC_PY_CALL_CHECK(getViewProviderName,return(std::string()));
472
    Base::PyGILStateLocker lock;
473
    try {
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();
477
    }
478
    catch (Py::Exception&) {
479
        Base::PyException e; // extract the Python error text
480
        e.ReportException();
481
    }
482

483
    return {};
484
}
485

486
FeaturePythonImp::ValueT
487
FeaturePythonImp::canLinkProperties() const
488
{
489
    _FC_PY_CALL_CHECK(canLinkProperties,return(NotImplemented));
490
    Base::PyGILStateLocker lock;
491
    try {
492
        Py::Tuple args(1);
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;
496
    }
497
    catch (Py::Exception&) {
498
        if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
499
            PyErr_Clear();
500
            return NotImplemented;
501
        }
502
        Base::PyException e; // extract the Python error text
503
        e.ReportException();
504
        return Rejected;
505
    }
506
}
507

508
FeaturePythonImp::ValueT
509
FeaturePythonImp::allowDuplicateLabel() const
510
{
511
    _FC_PY_CALL_CHECK(allowDuplicateLabel,return(NotImplemented));
512
    Base::PyGILStateLocker lock;
513
    try {
514
        Py::Tuple args(1);
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;
518
    }
519
    catch (Py::Exception&) {
520
        if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
521
            PyErr_Clear();
522
            return NotImplemented;
523
        }
524

525
        Base::PyException e; // extract the Python error text
526
        e.ReportException();
527
        return Rejected;
528
    }
529
}
530

531
int FeaturePythonImp::canLoadPartial() const {
532
    _FC_PY_CALL_CHECK(canLoadPartial,return(-1));
533
    Base::PyGILStateLocker lock;
534
    try {
535
        Py::Tuple args(1);
536
        args.setItem(0, Py::Object(object->getPyObject(), true));
537
        Py::Int ret(Base::pyCall(py_canLoadPartial.ptr(),args.ptr()));
538
        return ret;
539
    }
540
    catch (Py::Exception&) {
541
        if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
542
            PyErr_Clear();
543
            return -1;
544
        }
545
        Base::PyException e; // extract the Python error text
546
        e.ReportException();
547
        return 0;
548
    }
549
}
550

551
FeaturePythonImp::ValueT
552
FeaturePythonImp::redirectSubName(std::ostringstream &ss,
553
                                  App::DocumentObject *topParent,
554
                                  App::DocumentObject *child) const
555
{
556
    _FC_PY_CALL_CHECK(redirectSubName,return(NotImplemented));
557
    Base::PyGILStateLocker lock;
558
    try {
559
        Py::Tuple args(4);
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()));
565
        if (ret.isNone())
566
            return Rejected;
567
        ss.str("");
568
        ss << ret.as_string();
569
        return Accepted;
570
    }
571
    catch (Py::Exception&) {
572
        if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
573
            PyErr_Clear();
574
            return NotImplemented;
575
        }
576

577
        Base::PyException e; // extract the Python error text
578
        e.ReportException();
579
        return Rejected;
580
    }
581
}
582

583
bool FeaturePythonImp::editProperty(const char *name)
584
{
585
    _FC_PY_CALL_CHECK(editProperty,return false);
586
    Base::PyGILStateLocker lock;
587
    try {
588
        Py::Tuple args(1);
589
        args.setItem(0, Py::String(name));
590
        Py::Object ret(Base::pyCall(py_editProperty.ptr(),args.ptr()));
591
        return ret.isTrue();
592
    }
593
    catch (Py::Exception&) {
594
        if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
595
            PyErr_Clear();
596
            return false;
597
        }
598

599
        Base::PyException e; // extract the Python error text
600
        e.ReportException();
601
    }
602
    return false;
603
}
604

605
// ---------------------------------------------------------
606

607
namespace App {
608
PROPERTY_SOURCE_TEMPLATE(App::FeaturePython, App::DocumentObject)
609
template<> const char* App::FeaturePython::getViewProviderName() const {
610
    return "Gui::ViewProviderPythonFeature";
611
}
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);
616
    }
617
    return Py::new_reference_to(PythonObject);
618
}
619
// explicit template instantiation
620
template class AppExport FeaturePythonT<DocumentObject>;
621
}
622

623
// ---------------------------------------------------------
624

625
namespace App {
626
PROPERTY_SOURCE_TEMPLATE(App::GeometryPython, App::GeoFeature)
627
template<> const char* App::GeometryPython::getViewProviderName() const {
628
    return "Gui::ViewProviderPythonGeometry";
629
}
630
// explicit template instantiation
631
template class AppExport FeaturePythonT<GeoFeature>;
632
}
633

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.