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