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