1
/***************************************************************************
2
* Copyright (c) 2018 Stefan Tröger <stefantroeger@gmx.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
***************************************************************************/
23
#include "PreCompiled.h"
25
#include <Base/Interpreter.h>
27
#include "Application.h"
29
#include "DocumentObserverPython.h"
30
#include "ViewProvider.h"
31
#include "ViewProviderDocumentObject.h"
35
namespace sp = std::placeholders;
37
std::vector<DocumentObserverPython*> DocumentObserverPython::_instances;
39
void DocumentObserverPython::addObserver(const Py::Object& obj)
41
_instances.push_back(new DocumentObserverPython(obj));
44
void DocumentObserverPython::removeObserver(const Py::Object& obj)
46
DocumentObserverPython* obs=nullptr;
47
for (std::vector<DocumentObserverPython*>::iterator it =
48
_instances.begin(); it != _instances.end(); ++it) {
49
if ((*it)->inst == obj) {
59
DocumentObserverPython::DocumentObserverPython(const Py::Object& obj) : inst(obj)
62
#define FC_PY_ELEMENT_ARG1(_name1, _name2) do {\
63
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py);\
64
if (!py##_name1.py.isNone())\
65
py##_name1.slot = Application::Instance->signal##_name2.connect(\
66
std::bind(&DocumentObserverPython::slot##_name1, this, sp::_1));\
70
#define FC_PY_ELEMENT_ARG2(_name1, _name2) do {\
71
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py);\
72
if (!py##_name1.py.isNone())\
73
py##_name1.slot = Application::Instance->signal##_name2.connect(\
74
std::bind(&DocumentObserverPython::slot##_name1, this, sp::_1, sp::_2));\
78
FC_PY_ELEMENT_ARG1(CreatedDocument, NewDocument)
79
FC_PY_ELEMENT_ARG1(DeletedDocument, DeleteDocument)
80
FC_PY_ELEMENT_ARG1(RelabelDocument, RelabelDocument)
81
FC_PY_ELEMENT_ARG1(RenameDocument, RenameDocument)
82
FC_PY_ELEMENT_ARG1(ActivateDocument, ActiveDocument)
83
FC_PY_ELEMENT_ARG1(CreatedObject, NewObject)
84
FC_PY_ELEMENT_ARG1(DeletedObject, DeletedObject)
85
FC_PY_ELEMENT_ARG2(BeforeChangeObject, BeforeChangeObject)
86
FC_PY_ELEMENT_ARG2(ChangedObject, ChangedObject)
87
FC_PY_ELEMENT_ARG1(InEdit, InEdit)
88
FC_PY_ELEMENT_ARG1(ResetEdit, ResetEdit)
92
DocumentObserverPython::~DocumentObserverPython() = default;
94
void DocumentObserverPython::slotCreatedDocument(const Gui::Document& Doc)
96
Base::PyGILStateLocker lock;
99
args.setItem(0, Py::asObject(const_cast<Gui::Document&>(Doc).getPyObject()));
100
Base::pyCall(pyCreatedDocument.ptr(),args.ptr());
102
catch (Py::Exception&) {
103
Base::PyException e; // extract the Python error text
108
void DocumentObserverPython::slotDeletedDocument(const Gui::Document& Doc)
110
Base::PyGILStateLocker lock;
113
args.setItem(0, Py::asObject(const_cast<Gui::Document&>(Doc).getPyObject()));
114
Base::pyCall(pyDeletedDocument.ptr(),args.ptr());
116
catch (Py::Exception&) {
117
Base::PyException e; // extract the Python error text
122
void DocumentObserverPython::slotRelabelDocument(const Gui::Document& Doc)
124
Base::PyGILStateLocker lock;
127
args.setItem(0, Py::asObject(const_cast<Gui::Document&>(Doc).getPyObject()));
128
Base::pyCall(pyRelabelDocument.ptr(),args.ptr());
130
catch (Py::Exception&) {
131
Base::PyException e; // extract the Python error text
136
void DocumentObserverPython::slotRenameDocument(const Gui::Document& Doc)
138
Base::PyGILStateLocker lock;
141
args.setItem(0, Py::asObject(const_cast<Gui::Document&>(Doc).getPyObject()));
142
Base::pyCall(pyRenameDocument.ptr(),args.ptr());
144
catch (Py::Exception&) {
145
Base::PyException e; // extract the Python error text
150
void DocumentObserverPython::slotActivateDocument(const Gui::Document& Doc)
152
Base::PyGILStateLocker lock;
155
args.setItem(0, Py::asObject(const_cast<Gui::Document&>(Doc).getPyObject()));
156
Base::pyCall(pyActivateDocument.ptr(),args.ptr());
158
catch (Py::Exception&) {
159
Base::PyException e; // extract the Python error text
164
void DocumentObserverPython::slotCreatedObject(const Gui::ViewProvider& Obj)
166
Base::PyGILStateLocker lock;
169
args.setItem(0, Py::asObject(const_cast<Gui::ViewProvider&>(Obj).getPyObject()));
170
Base::pyCall(pyCreatedObject.ptr(),args.ptr());
172
catch (Py::Exception&) {
173
Base::PyException e; // extract the Python error text
178
void DocumentObserverPython::slotDeletedObject(const Gui::ViewProvider& Obj)
180
Base::PyGILStateLocker lock;
183
args.setItem(0, Py::asObject(const_cast<Gui::ViewProvider&>(Obj).getPyObject()));
184
Base::pyCall(pyDeletedObject.ptr(),args.ptr());
186
catch (Py::Exception&) {
187
Base::PyException e; // extract the Python error text
192
void DocumentObserverPython::slotBeforeChangeObject(const Gui::ViewProvider& Obj,
193
const App::Property& Prop)
195
Base::PyGILStateLocker lock;
198
args.setItem(0, Py::asObject(const_cast<Gui::ViewProvider&>(Obj).getPyObject()));
199
// If a property is touched but not part of a document object then its name is null.
200
// In this case the slot function must not be called.
201
const char* prop_name = Obj.getPropertyName(&Prop);
203
args.setItem(1, Py::String(prop_name));
204
Base::pyCall(pyBeforeChangeObject.ptr(),args.ptr());
207
catch (Py::Exception&) {
208
Base::PyException e; // extract the Python error text
213
void DocumentObserverPython::slotChangedObject(const Gui::ViewProvider& Obj,
214
const App::Property& Prop)
216
Base::PyGILStateLocker lock;
219
args.setItem(0, Py::asObject(const_cast<Gui::ViewProvider&>(Obj).getPyObject()));
220
// If a property is touched but not part of a document object then its name is null.
221
// In this case the slot function must not be called.
222
const char* prop_name = Obj.getPropertyName(&Prop);
224
args.setItem(1, Py::String(prop_name));
225
Base::pyCall(pyChangedObject.ptr(),args.ptr());
228
catch (Py::Exception&) {
229
Base::PyException e; // extract the Python error text
234
void DocumentObserverPython::slotInEdit(const Gui::ViewProviderDocumentObject& Obj)
236
Base::PyGILStateLocker lock;
239
args.setItem(0, Py::asObject(const_cast<Gui::ViewProviderDocumentObject&>(Obj).getPyObject()));
240
Base::pyCall(pyInEdit.ptr(),args.ptr());
242
catch (Py::Exception&) {
243
Base::PyException e; // extract the Python error text
248
void DocumentObserverPython::slotResetEdit(const Gui::ViewProviderDocumentObject& Obj)
250
Base::PyGILStateLocker lock;
253
args.setItem(0, Py::asObject(const_cast<Gui::ViewProviderDocumentObject&>(Obj).getPyObject()));
254
Base::pyCall(pyResetEdit.ptr(),args.ptr());
256
catch (Py::Exception&) {
257
Base::PyException e; // extract the Python error text