1
/***************************************************************************
2
* Copyright (c) 2009 Werner Mayer <wmayer[at]users.sourceforge.net> *
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 <CXX/Objects.hxx>
30
#include "Application.h"
32
#include "DocumentObject.h"
33
#include "DocumentObserverPython.h"
34
#include <Base/Interpreter.h>
38
namespace sp = std::placeholders;
40
std::vector<DocumentObserverPython*> DocumentObserverPython::_instances;
42
void DocumentObserverPython::addObserver(const Py::Object& obj)
44
_instances.push_back(new DocumentObserverPython(obj));
47
void DocumentObserverPython::removeObserver(const Py::Object& obj)
49
DocumentObserverPython* obs=nullptr;
50
for (std::vector<DocumentObserverPython*>::iterator it =
51
_instances.begin(); it != _instances.end(); ++it) {
52
if ((*it)->inst == obj) {
62
DocumentObserverPython::DocumentObserverPython(const Py::Object& obj) : inst(obj)
64
#define FC_PY_ELEMENT_ARG0(_name1, _name2) do {\
65
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py);\
66
if (!py##_name1.py.isNone())\
67
py##_name1.slot = App::GetApplication().signal##_name2.connect(\
68
std::bind(&DocumentObserverPython::slot##_name1, this));\
73
#define FC_PY_ELEMENT_ARG1(_name1, _name2) do {\
74
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py);\
75
if (!py##_name1.py.isNone())\
76
py##_name1.slot = App::GetApplication().signal##_name2.connect(\
77
std::bind(&DocumentObserverPython::slot##_name1, this, sp::_1));\
82
#define FC_PY_ELEMENT_ARG2(_name1, _name2) do {\
83
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py);\
84
if (!py##_name1.py.isNone())\
85
py##_name1.slot = App::GetApplication().signal##_name2.connect(\
86
std::bind(&DocumentObserverPython::slot##_name1, this, sp::_1, sp::_2));\
90
FC_PY_ELEMENT_ARG1(CreatedDocument, NewDocument)
91
FC_PY_ELEMENT_ARG1(DeletedDocument, DeleteDocument)
92
FC_PY_ELEMENT_ARG1(RelabelDocument, RelabelDocument)
93
FC_PY_ELEMENT_ARG1(ActivateDocument, ActiveDocument)
94
FC_PY_ELEMENT_ARG1(UndoDocument, UndoDocument)
95
FC_PY_ELEMENT_ARG1(RedoDocument, RedoDocument)
96
FC_PY_ELEMENT_ARG2(BeforeChangeDocument, BeforeChangeDocument)
97
FC_PY_ELEMENT_ARG2(ChangedDocument, ChangedDocument)
98
FC_PY_ELEMENT_ARG1(CreatedObject, NewObject)
99
FC_PY_ELEMENT_ARG1(DeletedObject, DeletedObject)
100
FC_PY_ELEMENT_ARG2(BeforeChangeObject, BeforeChangeObject)
101
FC_PY_ELEMENT_ARG2(ChangedObject, ChangedObject)
102
FC_PY_ELEMENT_ARG1(RecomputedObject, ObjectRecomputed)
103
FC_PY_ELEMENT_ARG1(BeforeRecomputeDocument, BeforeRecomputeDocument)
104
FC_PY_ELEMENT_ARG1(RecomputedDocument, Recomputed)
105
FC_PY_ELEMENT_ARG2(OpenTransaction, OpenTransaction)
106
FC_PY_ELEMENT_ARG1(CommitTransaction, CommitTransaction)
107
FC_PY_ELEMENT_ARG1(AbortTransaction, AbortTransaction)
108
FC_PY_ELEMENT_ARG0(Undo, Undo)
109
FC_PY_ELEMENT_ARG0(Redo, Redo)
110
FC_PY_ELEMENT_ARG1(BeforeCloseTransaction, BeforeCloseTransaction)
111
FC_PY_ELEMENT_ARG1(CloseTransaction, CloseTransaction)
112
FC_PY_ELEMENT_ARG2(StartSaveDocument, StartSaveDocument)
113
FC_PY_ELEMENT_ARG2(FinishSaveDocument, FinishSaveDocument)
114
FC_PY_ELEMENT_ARG1(AppendDynamicProperty, AppendDynamicProperty)
115
FC_PY_ELEMENT_ARG1(RemoveDynamicProperty, RemoveDynamicProperty)
116
FC_PY_ELEMENT_ARG2(ChangePropertyEditor, ChangePropertyEditor)
117
FC_PY_ELEMENT_ARG2(BeforeAddingDynamicExtension, BeforeAddingDynamicExtension)
118
FC_PY_ELEMENT_ARG2(AddedDynamicExtension, AddedDynamicExtension)
122
DocumentObserverPython::~DocumentObserverPython() = default;
124
void DocumentObserverPython::slotCreatedDocument(const App::Document& Doc)
126
Base::PyGILStateLocker lock;
129
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
130
Base::pyCall(pyCreatedDocument.ptr(),args.ptr());
132
catch (Py::Exception&) {
133
Base::PyException e; // extract the Python error text
138
void DocumentObserverPython::slotDeletedDocument(const App::Document& Doc)
140
Base::PyGILStateLocker lock;
143
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
144
Base::pyCall(pyDeletedDocument.ptr(),args.ptr());
146
catch (Py::Exception&) {
147
Base::PyException e; // extract the Python error text
152
void DocumentObserverPython::slotRelabelDocument(const App::Document& Doc)
154
Base::PyGILStateLocker lock;
157
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
158
Base::pyCall(pyRelabelDocument.ptr(),args.ptr());
160
catch (Py::Exception&) {
161
Base::PyException e; // extract the Python error text
166
void DocumentObserverPython::slotActivateDocument(const App::Document& Doc)
168
Base::PyGILStateLocker lock;
171
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
172
Base::pyCall(pyActivateDocument.ptr(),args.ptr());
174
catch (Py::Exception&) {
175
Base::PyException e; // extract the Python error text
180
void DocumentObserverPython::slotUndoDocument(const App::Document& Doc)
182
Base::PyGILStateLocker lock;
185
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
186
Base::pyCall(pyUndoDocument.ptr(),args.ptr());
188
catch (Py::Exception&) {
189
Base::PyException e; // extract the Python error text
195
void DocumentObserverPython::slotRedoDocument(const App::Document& Doc)
197
Base::PyGILStateLocker lock;
200
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
201
Base::pyCall(pyRedoDocument.ptr(),args.ptr());
203
catch (Py::Exception&) {
204
Base::PyException e; // extract the Python error text
209
void DocumentObserverPython::slotUndo()
211
Base::PyGILStateLocker lock;
213
Base::pyCall(pyUndo.ptr());
215
catch (Py::Exception&) {
216
Base::PyException e; // extract the Python error text
221
void DocumentObserverPython::slotRedo()
223
Base::PyGILStateLocker lock;
225
Base::pyCall(pyRedo.ptr());
227
catch (Py::Exception&) {
228
Base::PyException e; // extract the Python error text
233
void DocumentObserverPython::slotBeforeCloseTransaction(bool abort)
235
Base::PyGILStateLocker lock;
238
args.setItem(0, Py::Boolean(abort));
239
Base::pyCall(pyBeforeCloseTransaction.ptr(),args.ptr());
241
catch (Py::Exception&) {
242
Base::PyException e; // extract the Python error text
247
void DocumentObserverPython::slotCloseTransaction(bool abort)
249
Base::PyGILStateLocker lock;
252
args.setItem(0, Py::Boolean(abort));
253
Base::pyCall(pyCloseTransaction.ptr(),args.ptr());
255
catch (Py::Exception&) {
256
Base::PyException e; // extract the Python error text
261
void DocumentObserverPython::slotBeforeChangeDocument(const App::Document& Doc, const App::Property& Prop)
263
Base::PyGILStateLocker lock;
266
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
267
// If a property is touched but not part of a document object then its name is null.
268
// In this case the slot function must not be called.
269
const char* prop_name = Doc.getPropertyName(&Prop);
271
args.setItem(1, Py::String(prop_name));
272
Base::pyCall(pyBeforeChangeDocument.ptr(),args.ptr());
275
catch (Py::Exception&) {
276
Base::PyException e; // extract the Python error text
281
void DocumentObserverPython::slotChangedDocument(const App::Document& Doc, const App::Property& Prop)
283
Base::PyGILStateLocker lock;
286
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
287
// If a property is touched but not part of a document object then its name is null.
288
// In this case the slot function must not be called.
289
const char* prop_name = Doc.getPropertyName(&Prop);
291
args.setItem(1, Py::String(prop_name));
292
Base::pyCall(pyChangedDocument.ptr(),args.ptr());
295
catch (Py::Exception&) {
296
Base::PyException e; // extract the Python error text
301
void DocumentObserverPython::slotCreatedObject(const App::DocumentObject& Obj)
303
Base::PyGILStateLocker lock;
306
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
307
Base::pyCall(pyCreatedObject.ptr(),args.ptr());
309
catch (Py::Exception&) {
310
Base::PyException e; // extract the Python error text
315
void DocumentObserverPython::slotDeletedObject(const App::DocumentObject& Obj)
317
Base::PyGILStateLocker lock;
320
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
321
Base::pyCall(pyDeletedObject.ptr(),args.ptr());
323
catch (Py::Exception&) {
324
Base::PyException e; // extract the Python error text
329
void DocumentObserverPython::slotBeforeChangeObject(const App::DocumentObject& Obj,
330
const App::Property& Prop)
332
Base::PyGILStateLocker lock;
335
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
336
// If a property is touched but not part of a document object then its name is null.
337
// In this case the slot function must not be called.
338
const char* prop_name = Obj.getPropertyName(&Prop);
340
args.setItem(1, Py::String(prop_name));
341
Base::pyCall(pyBeforeChangeObject.ptr(),args.ptr());
344
catch (Py::Exception&) {
345
Base::PyException e; // extract the Python error text
350
void DocumentObserverPython::slotChangedObject(const App::DocumentObject& Obj,
351
const App::Property& Prop)
353
Base::PyGILStateLocker lock;
356
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
357
// If a property is touched but not part of a document object then its name is null.
358
// In this case the slot function must not be called.
359
const char* prop_name = Obj.getPropertyName(&Prop);
361
args.setItem(1, Py::String(prop_name));
362
Base::pyCall(pyChangedObject.ptr(),args.ptr());
365
catch (Py::Exception&) {
366
Base::PyException e; // extract the Python error text
371
void DocumentObserverPython::slotRecomputedObject(const App::DocumentObject& Obj)
373
Base::PyGILStateLocker lock;
376
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
377
Base::pyCall(pyRecomputedObject.ptr(),args.ptr());
379
catch (Py::Exception&) {
380
Base::PyException e; // extract the Python error text
385
void DocumentObserverPython::slotRecomputedDocument(const App::Document& doc)
387
Base::PyGILStateLocker lock;
390
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
391
Base::pyCall(pyRecomputedDocument.ptr(),args.ptr());
393
catch (Py::Exception&) {
394
Base::PyException e; // extract the Python error text
399
void DocumentObserverPython::slotBeforeRecomputeDocument(const App::Document& doc)
401
Base::PyGILStateLocker lock;
404
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
405
Base::pyCall(pyBeforeRecomputeDocument.ptr(),args.ptr());
407
catch (Py::Exception&) {
408
Base::PyException e; // extract the Python error text
413
void DocumentObserverPython::slotOpenTransaction(const App::Document& doc, std::string str)
415
Base::PyGILStateLocker lock;
418
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
419
args.setItem(1, Py::String(str));
420
Base::pyCall(pyOpenTransaction.ptr(),args.ptr());
422
catch (Py::Exception&) {
423
Base::PyException e; // extract the Python error text
428
void DocumentObserverPython::slotCommitTransaction(const App::Document& doc)
430
Base::PyGILStateLocker lock;
433
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
434
Base::pyCall(pyCommitTransaction.ptr(),args.ptr());
436
catch (Py::Exception&) {
437
Base::PyException e; // extract the Python error text
442
void DocumentObserverPython::slotAbortTransaction(const App::Document& doc)
444
Base::PyGILStateLocker lock;
447
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
448
Base::pyCall(pyAbortTransaction.ptr(),args.ptr());
450
catch (Py::Exception&) {
451
Base::PyException e; // extract the Python error text
456
void DocumentObserverPython::slotAppendDynamicProperty(const App::Property& Prop)
458
Base::PyGILStateLocker lock;
460
auto container = Prop.getContainer();
462
args.setItem(0, Py::asObject(container->getPyObject()));
463
// If a property is touched but not part of a document object then its name is null.
464
// In this case the slot function must not be called.
465
const char* prop_name = container->getPropertyName(&Prop);
467
args.setItem(1, Py::String(prop_name));
468
Base::pyCall(pyAppendDynamicProperty.ptr(),args.ptr());
471
catch (Py::Exception&) {
472
Base::PyException e; // extract the Python error text
477
void DocumentObserverPython::slotRemoveDynamicProperty(const App::Property& Prop)
479
Base::PyGILStateLocker lock;
481
auto container = Prop.getContainer();
483
args.setItem(0, Py::asObject(container->getPyObject()));
484
// If a property is touched but not part of a document object then its name is null.
485
// In this case the slot function must not be called.
486
const char* prop_name = container->getPropertyName(&Prop);
488
args.setItem(1, Py::String(prop_name));
489
Base::pyCall(pyRemoveDynamicProperty.ptr(),args.ptr());
492
catch (Py::Exception&) {
493
Base::PyException e; // extract the Python error text
498
void DocumentObserverPython::slotChangePropertyEditor(const App::Document &, const App::Property& Prop)
500
Base::PyGILStateLocker lock;
502
auto container = Prop.getContainer();
504
args.setItem(0, Py::asObject(container->getPyObject()));
505
// If a property is touched but not part of a document object then its name is null.
506
// In this case the slot function must not be called.
507
const char* prop_name = container->getPropertyName(&Prop);
509
args.setItem(1, Py::String(prop_name));
510
Base::pyCall(pyChangePropertyEditor.ptr(),args.ptr());
513
catch (Py::Exception&) {
514
Base::PyException e; // extract the Python error text
519
void DocumentObserverPython::slotStartSaveDocument(const App::Document& doc, const std::string& file)
521
Base::PyGILStateLocker lock;
524
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
525
args.setItem(1, Py::String(file));
526
Base::pyCall(pyStartSaveDocument.ptr(),args.ptr());
528
catch (Py::Exception&) {
529
Base::PyException e; // extract the Python error text
534
void DocumentObserverPython::slotFinishSaveDocument(const App::Document& doc, const std::string& file)
536
Base::PyGILStateLocker lock;
539
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
540
args.setItem(1, Py::String(file));
541
Base::pyCall(pyFinishSaveDocument.ptr(),args.ptr());
543
catch (Py::Exception&) {
544
Base::PyException e; // extract the Python error text
549
void DocumentObserverPython::slotBeforeAddingDynamicExtension(const App::ExtensionContainer& extcont, std::string extension)
551
Base::PyGILStateLocker lock;
554
args.setItem(0, Py::asObject(const_cast<App::ExtensionContainer&>(extcont).getPyObject()));
555
args.setItem(1, Py::String(extension));
556
Base::pyCall(pyBeforeAddingDynamicExtension.ptr(),args.ptr());
558
catch (Py::Exception&) {
559
Base::PyException e; // extract the Python error text
564
void DocumentObserverPython::slotAddedDynamicExtension(const App::ExtensionContainer& extcont, std::string extension)
566
Base::PyGILStateLocker lock;
569
args.setItem(0, Py::asObject(const_cast<App::ExtensionContainer&>(extcont).getPyObject()));
570
args.setItem(1, Py::String(extension));
571
Base::pyCall(pyAddedDynamicExtension.ptr(),args.ptr());
573
catch (Py::Exception&) {
574
Base::PyException e; // extract the Python error text