Xcos MVC: implement clone / delete on the Model side
[scilab.git] / scilab / modules / scicos / src / cpp / Controller.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2014-2014 - Scilab Enterprises - Clement DAVID
4  *
5  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12
13 #include <algorithm>
14
15 #include "Controller.hxx"
16
17 #include "LoggerView.hxx"
18
19 namespace org_scilab_modules_scicos
20 {
21
22 /*
23  * Implement SharedData methods
24  */
25 Controller::SharedData::SharedData() :
26     model(), allViews()
27 {
28     LoggerView* v = new LoggerView();
29     allViews.push_back(v);
30 }
31
32 Controller::SharedData::~SharedData()
33 {
34     for (view_set_t::iterator iter = _instance->allViews.begin(); iter != _instance->allViews.end(); ++iter)
35     {
36         delete *iter;
37     }
38 }
39
40 Controller::SharedData* Controller::_instance = 0;
41
42 void Controller::delete_all_instances()
43 {
44     if (_instance == 0)
45     {
46         return;
47     }
48
49     delete _instance;
50 }
51
52 void Controller::register_view(View* v)
53 {
54     if (_instance == 0)
55     {
56         _instance = new SharedData();
57     }
58
59     _instance->allViews.push_back(v);
60 }
61
62 void Controller::unregister_view(View* v)
63 {
64     if (_instance == 0)
65     {
66         return;
67     }
68
69     view_set_t::iterator it = std::find(_instance->allViews.begin(), _instance->allViews.end(), v);
70     if (it != _instance->allViews.end())
71     {
72         _instance->allViews.erase(it);
73     }
74 }
75
76 Controller::Controller()
77 {
78     if (_instance == 0)
79     {
80         _instance = new SharedData();
81     }
82 }
83
84 Controller::Controller(const Controller& c)
85 {
86     // _instance is already initialized
87
88     // silent unused parameter warnings
89     (void) c;
90 }
91
92 Controller::~Controller()
93 {
94 }
95
96 ScicosID Controller::createObject(kind_t k)
97 {
98     ScicosID id = _instance->model.createObject(k);
99
100     for (view_set_t::iterator iter = _instance->allViews.begin(); iter != _instance->allViews.end(); ++iter)
101     {
102         (*iter)->objectCreated(id, k);
103     }
104
105     return id;
106 }
107
108 static void unlink_vector(Controller& controller, ScicosID uid, kind_t k, object_properties_t uid_prop, object_properties_t ref_prop)
109 {
110     ScicosID v;
111     controller.getObjectProperty(uid, k, uid_prop, v);
112     if (v != 0)
113     {
114         model::BaseObject* o = controller.getObject(v);
115
116         std::vector<ScicosID> children;
117         controller.getObjectProperty(o->id(), o->kind(), ref_prop, children);
118
119         std::vector<ScicosID>::iterator it = std::find(children.begin(), children.end(), uid);
120         if (it != children.end())
121         {
122             children.erase(it);
123         }
124
125         controller.setObjectProperty(o->id(), o->kind(), ref_prop, children);
126     }
127 }
128
129 static void unlink(Controller& controller, ScicosID uid, kind_t k, object_properties_t uid_prop, object_properties_t ref_prop)
130 {
131     ScicosID v;
132     controller.getObjectProperty(uid, k, uid_prop, v);
133     if (v != 0)
134     {
135         model::BaseObject* o = controller.getObject(v);
136         controller.setObjectProperty(o->id(), o->kind(), ref_prop, 0);
137     }
138 }
139
140 void Controller::deleteObject(ScicosID uid)
141 {
142     // disconnect / remove references first
143     model::BaseObject* initial = getObject(uid);
144     const kind_t k = initial->kind();
145     if (k == ANNOTATION)
146     {
147         unlink_vector(*this, uid, k, PARENT_DIAGRAM, CHILDREN);
148         // RELATED_TO is not referenced back
149     }
150     else if (k == BLOCK)
151     {
152         unlink_vector(*this, uid, k, PARENT_DIAGRAM, CHILDREN);
153         // INPUTS will be removed on delete
154         // OUTPUTS will be removed on delete
155         // EVENT_INPUTS will be removed on delete
156         // EVENT_OUTPUTS will be removed on delete
157         unlink_vector(*this, uid, k, PARENT_BLOCK, CHILDREN);
158         // CHILDREN will be removed on delete
159         // FIXME what about REFERENCED_PORT ?
160     }
161     else if (k == DIAGRAM)
162     {
163         // CHILDREN will be removed on delete
164     }
165     else if (k == LINK)
166     {
167         unlink_vector(*this, uid, k, PARENT_DIAGRAM, CHILDREN);
168         unlink_vector(*this, uid, k, SOURCE_PORT, CONNECTED_SIGNALS);
169         unlink_vector(*this, uid, k, DESTINATION_PORT, CONNECTED_SIGNALS);
170     }
171     else if (k == PORT)
172     {
173         unlink(*this, uid, k, SOURCE_BLOCK, INPUTS);
174         unlink(*this, uid, k, SOURCE_BLOCK, OUTPUTS);
175         unlink(*this, uid, k, SOURCE_BLOCK, EVENT_INPUTS);
176         unlink(*this, uid, k, SOURCE_BLOCK, EVENT_OUTPUTS);
177
178         unlink(*this, uid, k, CONNECTED_SIGNALS, SOURCE_PORT);
179         unlink(*this, uid, k, CONNECTED_SIGNALS, DESTINATION_PORT);
180     }
181
182     // delete the object
183     _instance->model.deleteObject(uid);
184
185     for (view_set_t::iterator iter = _instance->allViews.begin(); iter != _instance->allViews.end(); ++iter)
186     {
187         (*iter)->objectDeleted(uid);
188     }
189 }
190
191 ScicosID Controller::cloneObject(std::map<ScicosID, ScicosID>& mapped, ScicosID uid)
192 {
193     model::BaseObject* initial = getObject(uid);
194     const kind_t k = initial->kind();
195     ScicosID o = createObject(k);
196     mapped.insert(std::make_pair(uid, o));
197
198     // Get then set all properties per type that do not manage ScicosID
199     cloneProperties<double>(initial, o);
200     cloneProperties<int>(initial, o);
201     cloneProperties<bool>(initial, o);
202     cloneProperties<std::string>(initial, o);
203     cloneProperties<std::vector<double> >(initial, o);
204     cloneProperties<std::vector<int> >(initial, o);
205     cloneProperties<std::vector<std::string> >(initial, o);
206
207     // deep copy children, manage ScicosID and std::vector<ScicosID>
208     if (k == ANNOTATION)
209     {
210         deepClone(mapped, uid, o, k, PARENT_DIAGRAM, false);
211         deepClone(mapped, uid, o, k, RELATED_TO, true);
212     }
213     else if (k == BLOCK)
214     {
215         deepClone(mapped, uid, o, k, PARENT_DIAGRAM, false);
216         deepCloneVector(mapped, uid, o, k, INPUTS, true);
217         deepCloneVector(mapped, uid, o, k, OUTPUTS, true);
218         deepCloneVector(mapped, uid, o, k, EVENT_INPUTS, true);
219         deepCloneVector(mapped, uid, o, k, EVENT_OUTPUTS, true);
220         deepClone(mapped, uid, o, k, PARENT_BLOCK, false);
221         deepCloneVector(mapped, uid, o, k, CHILDREN, true);
222         // FIXME what about REFERENCED_PORT ?
223     }
224     else if (k == DIAGRAM)
225     {
226         deepCloneVector(mapped, uid, o, k, CHILDREN, true);
227     }
228     else if (k == LINK)
229     {
230         deepClone(mapped, uid, o, k, PARENT_DIAGRAM, false);
231         deepClone(mapped, uid, o, k, SOURCE_PORT, true);
232         deepClone(mapped, uid, o, k, DESTINATION_PORT, true);
233     }
234     else if (k == PORT)
235     {
236         deepClone(mapped, uid, o, k, SOURCE_BLOCK, true);
237         deepCloneVector(mapped, uid, o, k, CONNECTED_SIGNALS, true);
238     }
239
240     return o;
241 }
242
243 void Controller::deepClone(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, ScicosID clone, kind_t k, object_properties_t p, bool cloneIfNotFound)
244 {
245     ScicosID v;
246     getObjectProperty(uid, k, p, v);
247
248     ScicosID cloned = 0;
249
250     std::map<ScicosID, ScicosID>::iterator it = mapped.find(v);
251     if (it != mapped.end())
252     {
253         cloned = it->second;
254     }
255     else
256     {
257         if (cloneIfNotFound)
258         {
259             if (v != 0)
260             {
261                 cloned = cloneObject(mapped, v);
262             }
263             else
264             {
265                 cloned = 0;
266             }
267         }
268         else
269         {
270             cloned = 0;
271         }
272     }
273
274     setObjectProperty(clone, k, p, cloned);
275 }
276
277 void Controller::deepCloneVector(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, ScicosID clone, kind_t k, object_properties_t p, bool cloneIfNotFound)
278 {
279     std::vector<ScicosID> v;
280     getObjectProperty(uid, k, p, v);
281
282     std::vector<ScicosID> cloned;
283     cloned.reserve(v.size());
284
285     for (const ScicosID& id : v)
286     {
287
288         std::map<ScicosID, ScicosID>::iterator it = mapped.find(id);
289         if (it != mapped.end())
290         {
291             cloned.push_back(it->second);
292         }
293         else
294         {
295             if (cloneIfNotFound)
296             {
297                 if (id != 0)
298                 {
299                     cloned.push_back(cloneObject(mapped, id));
300                 }
301                 else
302                 {
303                     cloned.push_back(0);
304                 }
305             }
306             else
307             {
308                 cloned.push_back(0);
309             }
310         }
311     }
312
313     setObjectProperty(clone, k, p, cloned);
314 }
315
316 ScicosID Controller::cloneObject(ScicosID uid)
317 {
318     std::map<ScicosID, ScicosID> mapped;
319     return cloneObject(mapped, uid);
320 }
321
322 model::BaseObject* Controller::getObject(ScicosID uid)
323 {
324     return _instance->model.getObject(uid);
325 }
326
327 update_status_t Controller::setObject(model::BaseObject* o)
328 {
329     update_status_t status = _instance->model.setObject(o);
330
331     if (status == SUCCESS)
332     {
333         for (view_set_t::iterator iter = _instance->allViews.begin(); iter != _instance->allViews.end(); ++iter)
334         {
335             (*iter)->objectUpdated(o->id(), o->kind());
336         }
337     }
338     return status;
339 }
340
341 } /* namespace org_scilab_modules_scicos */