ad8f013e219a72589bb5bbcb88ec01e66a05b3ec
[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 <utility>
17 #include <algorithm>
18 #include <iterator>
19
20 #include "utilities.hxx"
21
22 #define REF_DEBUG 0
23 #if REF_DEBUG
24 #include "scilabWrite.hxx"
25 #define REF_PRINT(uid, refCount) \
26         do { \
27         std::stringstream print; \
28         print << "referenceObject( " << uid << " ) : " << refCount << std::endl; \
29         scilabForcedWrite(print.str().data()); \
30         } while(0)
31 #define UNREF_PRINT(uid, count) \
32         do { \
33         std::stringstream print; \
34         print << "unreferenceObject( " << uid << " ) : " << refCount << std::endl; \
35         scilabForcedWrite(print.str().data()); \
36         } while(0)
37 #define CLONE_PRINT(uid, clone) \
38         do { \
39         std::stringstream print; \
40         print << "cloneObject( " << uid << " ) : " << clone << std::endl; \
41         scilabForcedWrite(print.str().data()); \
42         } while(0)
43 #else
44 #define REF_PRINT(uid, refCount)
45 #define UNREF_PRINT(uid, refCount)
46 #define CLONE_PRINT(uid, clone)
47 #endif
48
49 #include "Controller.hxx"
50
51 #include "LoggerView.hxx"
52
53 namespace org_scilab_modules_scicos
54 {
55
56 /*
57  * Implement SharedData methods
58  */
59 Controller::SharedData::SharedData() :
60     model(), allNamedViews(), allViews()
61 {
62 }
63
64 Controller::SharedData::~SharedData()
65 {
66     for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
67     {
68         delete *iter;
69     }
70 }
71
72 Controller::SharedData Controller::m_instance;
73
74 View* Controller::register_view(const std::string& name, View* v)
75 {
76     m_instance.allNamedViews.push_back(name);
77     m_instance.allViews.push_back(v);
78     return v;
79 }
80
81 void Controller::unregister_view(View* v)
82 {
83     view_set_t::iterator it = std::find(m_instance.allViews.begin(), m_instance.allViews.end(), v);
84     if (it != m_instance.allViews.end())
85     {
86         size_t d = std::distance(m_instance.allViews.begin(), it);
87         m_instance.allNamedViews.erase(m_instance.allNamedViews.begin() + d);
88         m_instance.allViews.erase(m_instance.allViews.begin() + d);
89     }
90 }
91
92 View* Controller::unregister_view(const std::string& name)
93 {
94     View* view = nullptr;
95
96     view_name_set_t::iterator it = std::find(m_instance.allNamedViews.begin(), m_instance.allNamedViews.end(), name);
97     if (it != m_instance.allNamedViews.end())
98     {
99         size_t d = std::distance(m_instance.allNamedViews.begin(), it);
100         view = *(m_instance.allViews.begin() + d);
101         m_instance.allNamedViews.erase(m_instance.allNamedViews.begin() + d);
102         m_instance.allViews.erase(m_instance.allViews.begin() + d);
103     }
104
105     return view;
106 }
107
108 View* Controller::look_for_view(const std::string& name)
109 {
110     View* view = nullptr;
111
112     view_name_set_t::iterator it = std::find(m_instance.allNamedViews.begin(), m_instance.allNamedViews.end(), name);
113     if (it != m_instance.allNamedViews.end())
114     {
115         size_t d = std::distance(m_instance.allNamedViews.begin(), it);
116         view = *(m_instance.allViews.begin() + d);
117     }
118
119     return view;
120 }
121
122 Controller::Controller()
123 {
124 }
125
126 Controller::~Controller()
127 {
128 }
129
130 ScicosID Controller::createObject(kind_t k)
131 {
132     ScicosID uid = m_instance.model.createObject(k);
133
134     for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
135     {
136         (*iter)->objectCreated(uid, k);
137     }
138
139     return uid;
140 }
141
142 unsigned Controller::referenceObject(const ScicosID uid) const
143 {
144     unsigned refCount = m_instance.model.referenceObject(uid);
145     REF_PRINT(uid, refCount);
146
147     auto o = getObject(uid);
148     for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
149     {
150         (*iter)->objectReferenced(uid, o->kind(), refCount);
151     }
152
153     return refCount;
154 }
155
156 void Controller::deleteObject(ScicosID uid)
157 {
158     // if this object is the empty uid, ignore it : is is not stored in the model
159     if (uid == 0)
160     {
161         return;
162     }
163
164     auto initial = getObject(uid);
165     if (initial == nullptr)
166     {
167         // defensive programming
168         return;
169     }
170     const kind_t k = initial->kind();
171
172     // if this object has been referenced somewhere else do not delete it but decrement the reference counter
173     unsigned& refCount = m_instance.model.referenceCount(uid);
174     if (refCount > 0)
175     {
176         --refCount;
177         UNREF_PRINT(uid, refCount);
178
179         for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
180         {
181             (*iter)->objectUnreferenced(uid, k, refCount);
182         }
183         return;
184     }
185
186     // We need to delete this object and cleanup all the referenced model object
187
188     // disconnect / remove references of weak connected objects and decrement the reference count of all strongly connected objects.
189     if (k == ANNOTATION)
190     {
191         unlinkVector(uid, k, PARENT_DIAGRAM, CHILDREN);
192         unlinkVector(uid, k, PARENT_BLOCK, CHILDREN);
193         // RELATED_TO is not referenced back
194     }
195     else if (k == BLOCK)
196     {
197         unlinkVector(uid, k, PARENT_DIAGRAM, CHILDREN);
198         unlinkVector(uid, k, PARENT_BLOCK, CHILDREN);
199
200         deleteVector(uid, k, INPUTS);
201         deleteVector(uid, k, OUTPUTS);
202         deleteVector(uid, k, EVENT_INPUTS);
203         deleteVector(uid, k, EVENT_OUTPUTS);
204
205         unlink(uid, k, CHILDREN, PARENT_BLOCK);
206         deleteVector(uid, k, CHILDREN);
207         // FIXME what about REFERENCED_PORT ?
208     }
209     else if (k == DIAGRAM)
210     {
211         unlink(uid, k, CHILDREN, PARENT_DIAGRAM);
212         deleteVector(uid, k, CHILDREN);
213     }
214     else if (k == LINK)
215     {
216         unlinkVector(uid, k, PARENT_DIAGRAM, CHILDREN);
217         unlinkVector(uid, k, PARENT_BLOCK, CHILDREN);
218
219         unlinkVector(uid, k, SOURCE_PORT, CONNECTED_SIGNALS);
220         unlinkVector(uid, k, DESTINATION_PORT, CONNECTED_SIGNALS);
221     }
222     else if (k == PORT)
223     {
224         unlinkVector(uid, k, SOURCE_BLOCK, INPUTS);
225         unlinkVector(uid, k, SOURCE_BLOCK, OUTPUTS);
226         unlinkVector(uid, k, SOURCE_BLOCK, EVENT_INPUTS);
227         unlinkVector(uid, k, SOURCE_BLOCK, EVENT_OUTPUTS);
228
229         unlink(uid, k, CONNECTED_SIGNALS, SOURCE_PORT);
230         unlink(uid, k, CONNECTED_SIGNALS, DESTINATION_PORT);
231     }
232
233     // delete the object
234     m_instance.model.deleteObject(uid);
235
236     for (view_set_t::iterator iter = m_instance.allViews.begin(); iter != m_instance.allViews.end(); ++iter)
237     {
238         (*iter)->objectDeleted(uid, k);
239     }
240 }
241
242 void Controller::unlinkVector(ScicosID uid, kind_t k, object_properties_t uid_prop, object_properties_t ref_prop)
243 {
244     ScicosID v;
245     getObjectProperty(uid, k, uid_prop, v);
246     if (v != 0)
247     {
248         auto o = getObject(v);
249         if (o == nullptr)
250         {
251             return;
252         }
253
254         std::vector<ScicosID> children;
255         getObjectProperty(o->id(), o->kind(), ref_prop, children);
256
257         std::vector<ScicosID>::iterator it = std::find(children.begin(), children.end(), uid);
258         if (it != children.end())
259         {
260             children.erase(it);
261         }
262
263         setObjectProperty(o->id(), o->kind(), ref_prop, children);
264     }
265 }
266
267 void Controller::unlink(ScicosID uid, kind_t k, object_properties_t uid_prop, object_properties_t ref_prop)
268 {
269     std::vector<ScicosID> v;
270     getObjectProperty(uid, k, uid_prop, v);
271     for (const ScicosID id : v)
272     {
273         if (id != 0)
274         {
275             auto o = getObject(id);
276             if (o == nullptr)
277             {
278                 continue;
279             }
280
281             // Find which end of the link is connected to the port
282             ScicosID oppositeRef;
283             getObjectProperty(o->id(), o->kind(), ref_prop, oppositeRef);
284             if (oppositeRef == uid)
285             {
286                 setObjectProperty(o->id(), o->kind(), ref_prop, ScicosID());
287             }
288         }
289     }
290 }
291
292 void Controller::deleteVector(ScicosID uid, kind_t k, object_properties_t uid_prop)
293 {
294     std::vector<ScicosID> children;
295     getObjectProperty(uid, k, uid_prop, children);
296
297     for (ScicosID id : children)
298     {
299         deleteObject(id);
300     }
301 }
302
303 ScicosID Controller::cloneObject(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, bool cloneChildren, bool clonePorts)
304 {
305     auto initial = getObject(uid);
306     const kind_t k = initial->kind();
307     ScicosID o = createObject(k);
308     mapped.insert(std::make_pair(uid, o));
309
310     // Get then set all properties per type that do not manage ScicosID
311     cloneProperties<double>(initial, o);
312     cloneProperties<int>(initial, o);
313     cloneProperties<bool>(initial, o);
314     cloneProperties<std::string>(initial, o);
315     cloneProperties<std::vector<double> >(initial, o);
316     cloneProperties<std::vector<int> >(initial, o);
317     cloneProperties<std::vector<std::string> >(initial, o);
318
319     // deep copy children, manage ScicosID and std::vector<ScicosID>
320     if (k == ANNOTATION)
321     {
322         deepClone(mapped, uid, o, k, PARENT_DIAGRAM, false);
323         deepClone(mapped, uid, o, k, PARENT_BLOCK, false);
324         deepClone(mapped, uid, o, k, RELATED_TO, true);
325     }
326     else if (k == BLOCK)
327     {
328         deepClone(mapped, uid, o, k, PARENT_DIAGRAM, false);
329         if (clonePorts)
330         {
331             // Only copy the block, without any port
332             deepCloneVector(mapped, uid, o, k, INPUTS, true);
333             deepCloneVector(mapped, uid, o, k, OUTPUTS, true);
334             deepCloneVector(mapped, uid, o, k, EVENT_INPUTS, true);
335             deepCloneVector(mapped, uid, o, k, EVENT_OUTPUTS, true);
336         }
337
338         deepClone(mapped, uid, o, k, PARENT_BLOCK, false);
339         if (cloneChildren)
340         {
341             deepCloneVector(mapped, uid, o, k, CHILDREN, true);
342         }
343         // FIXME what about REFERENCED_PORT ?
344     }
345     else if (k == DIAGRAM)
346     {
347         if (cloneChildren)
348         {
349             deepCloneVector(mapped, uid, o, k, CHILDREN, true);
350         }
351     }
352     else if (k == LINK)
353     {
354         deepClone(mapped, uid, o, k, PARENT_DIAGRAM, false);
355         deepClone(mapped, uid, o, k, PARENT_BLOCK, false);
356         deepClone(mapped, uid, o, k, SOURCE_PORT, false);
357         deepClone(mapped, uid, o, k, DESTINATION_PORT, false);
358     }
359     else if (k == PORT)
360     {
361         deepClone(mapped, uid, o, k, SOURCE_BLOCK, false);
362         deepCloneVector(mapped, uid, o, k, CONNECTED_SIGNALS, false);
363     }
364
365     return o;
366 }
367
368 void Controller::deepClone(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, ScicosID clone, kind_t k, object_properties_t p, bool cloneIfNotFound)
369 {
370     ScicosID v;
371     getObjectProperty(uid, k, p, v);
372
373     ScicosID cloned = 0;
374
375     std::map<ScicosID, ScicosID>::iterator it = mapped.find(v);
376     if (it != mapped.end())
377     {
378         cloned = it->second;
379     }
380     else
381     {
382         if (cloneIfNotFound)
383         {
384             if (v != 0)
385             {
386                 cloned = cloneObject(mapped, v, true, true);
387             }
388             else
389             {
390                 cloned = 0;
391             }
392         }
393         else
394         {
395             cloned = 0;
396         }
397     }
398
399     setObjectProperty(clone, k, p, cloned);
400 }
401
402 void Controller::deepCloneVector(std::map<ScicosID, ScicosID>& mapped, ScicosID uid, ScicosID clone, kind_t k, object_properties_t p, bool cloneIfNotFound)
403 {
404     std::vector<ScicosID> v;
405     getObjectProperty(uid, k, p, v);
406
407     std::vector<ScicosID> cloned;
408     cloned.reserve(v.size());
409
410     for (const ScicosID & id : v)
411     {
412         if (id == 0)
413         {
414             // Deleted Block, the cloning is done at Adapter level
415             cloned.push_back(id);
416             continue;
417         }
418
419         std::map<ScicosID, ScicosID>::iterator it = mapped.find(id);
420         if (it != mapped.end())
421         {
422             cloned.push_back(it->second);
423         }
424         else
425         {
426             if (cloneIfNotFound)
427             {
428                 if (id != 0)
429                 {
430                     cloned.push_back(cloneObject(mapped, id, true, true));
431                 }
432                 else
433                 {
434                     cloned.push_back(ScicosID());
435                 }
436             }
437             else
438             {
439                 cloned.push_back(ScicosID());
440             }
441         }
442     }
443
444     setObjectProperty(clone, k, p, cloned);
445 }
446
447 ScicosID Controller::cloneObject(ScicosID uid, bool cloneChildren, bool clonePorts)
448 {
449     std::map<ScicosID, ScicosID> mapped;
450     ScicosID clone = cloneObject(mapped, uid, cloneChildren, clonePorts);
451     CLONE_PRINT(uid, clone);
452     return clone;
453 }
454
455 kind_t Controller::getKind(ScicosID uid) const
456 {
457     return m_instance.model.getKind(uid);
458 }
459
460 std::vector<ScicosID> Controller::getAll(kind_t k) const
461 {
462     return m_instance.model.getAll(k);
463 }
464
465 void Controller::sortAndFillKind(std::vector<ScicosID>& uids, std::vector<int>& kinds)
466 {
467     // create a container of pair
468     struct local_pair
469     {
470         ScicosID first;
471         int second;
472     };
473     std::vector<local_pair> container(uids.size());
474
475     // fill it
476     for (size_t i = 0; i < uids.size(); ++i)
477     {
478         container[i] = { uids[i], getKind(uids[i]) };
479     }
480
481     // sort according to the kinds
482     std::stable_sort(container.begin(), container.end(), [] (const local_pair & a, const local_pair & b)
483     {
484         return a.second < b.second;
485     });
486
487     // move things back
488     uids.clear();
489     kinds.reserve(uids.capacity());
490     for (const auto& v : container)
491     {
492         uids.push_back(v.first);
493         kinds.push_back(v.second);
494     }
495 }
496
497
498
499 model::BaseObject* Controller::getObject(ScicosID uid) const
500 {
501     return m_instance.model.getObject(uid);
502 }
503
504 } /* namespace org_scilab_modules_scicos */