Xcos MVC: fix header licences
[scilab.git] / scilab / modules / scicos / src / cpp / view_scilab / ports_management.hxx
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2014 - Scilab Enterprises - Paul Bignier
4  *  Copyright (C) 2014 - Scilab Enterprises - Clement DAVID
5  *
6  *  This file must be used under the terms of the CeCILL.
7  *  This source file is licensed as described in the file COPYING, which
8  *  you should have received as part of this distribution.  The terms
9  *  are also available at
10  *  http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
11  *
12  */
13
14 #ifndef PORTS_MANAGEMENT_HXX_
15 #define PORTS_MANAGEMENT_HXX_
16
17 #include <string>
18 #include <vector>
19 #include <algorithm>
20
21 #include "internal.hxx"
22 #include "double.hxx"
23 #include "string.hxx"
24
25 #include "Controller.hxx"
26
27 namespace org_scilab_modules_scicos
28 {
29 namespace view_scilab
30 {
31
32 /*
33  * Return a Scilab encoded value for a property.
34  */
35 template<typename Adaptor, object_properties_t p>
36 types::InternalType* get_ports_property(const Adaptor& adaptor, object_properties_t port_kind, const Controller& controller)
37 {
38     model::Block* adaptee = adaptor.getAdaptee();
39
40     // Retrieve the identifiers
41     std::vector<ScicosID> ids;
42     controller.getObjectProperty(adaptee->id(), adaptee->kind(), port_kind, ids);
43
44     // Translate identifiers: shared variables
45     int i = 0;
46     size_t datatypeIndex = 0;
47     // Translate identifiers to return values
48     switch (p)
49     {
50         case STYLE:
51         case LABEL:
52         {
53             types::String* o = new types::String(ids.size(), 1);
54             for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
55             {
56                 std::string s;
57                 controller.getObjectProperty(*it, PORT, p, s);
58                 o->set(i, s.data());
59             }
60             return o;
61         }
62         case DATATYPE_ROWS:
63             datatypeIndex = 0;
64             // no break
65         case DATATYPE_COLS:
66             datatypeIndex = 1;
67             // no break
68         case DATATYPE_TYPE:
69         {
70             datatypeIndex = 2;
71
72             types::Double* o = new types::Double(ids.size(), 1);
73             for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
74             {
75                 std::vector<int> v;
76                 controller.getObjectProperty(*it, PORT, DATATYPE, v);
77                 o[i] = v[datatypeIndex];
78             }
79             return o;
80         }
81         case IMPLICIT:
82         {
83             static const wchar_t E[] = L"E";
84             static const wchar_t I[] = L"I";
85             types::String* o = new types::String(ids.size(), 1);
86             for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
87             {
88                 bool v;
89                 controller.getObjectProperty(*it, PORT, p, v);
90                 o->set(i, (v == false) ? E : I);
91             }
92             return o;
93         }
94         case CONNECTED_SIGNALS:
95         {
96             double* v;
97             types::Double* o = new types::Double(ids.size(), 1, &v);
98
99             ScicosID diagram;
100             controller.getObjectProperty(adaptee->id(), adaptee->kind(), PARENT_DIAGRAM, diagram);
101
102             std::vector<ScicosID> children;
103             if (diagram != 0)
104             {
105                 controller.getObjectProperty(diagram, DIAGRAM, CHILDREN, children);
106             }
107
108             for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
109             {
110                 ScicosID id;
111                 controller.getObjectProperty(*it, PORT, p, id);
112
113                 std::vector<ScicosID>::iterator found = std::find(children.begin(), children.end(), id);
114
115                 if (found != children.end())
116                 {
117                     v[i] = std::distance(found, children.begin());
118                 }
119                 else
120                 {
121                     v[i] = 0;
122                 }
123             }
124             return o;
125         }
126         default:
127             return 0;
128     }
129 }
130
131 /*
132  * Set a Scilab encoded values as a property.
133  *
134  * \note this method will return false if one of the ports does not exist
135  */
136 template<typename Adaptor, object_properties_t p>
137 bool set_ports_property(const Adaptor& adaptor, object_properties_t port_kind, Controller& controller, types::InternalType* v)
138 {
139     model::Block* adaptee = adaptor.getAdaptee();
140
141     // Retrieve the ports identifiers
142     std::vector<ScicosID> ids;
143     controller.getObjectProperty(adaptee->id(), adaptee->kind(), port_kind, ids);
144
145     if (v->getType() == types::InternalType::ScilabString)
146     {
147         types::String* current = v->getAs<types::String>();
148         if (current->getCols() != 0 && current->getCols() != 1)
149         {
150             return false;
151         }
152
153         size_t rows = current->getRows();
154         if (rows != ids.size())
155         {
156             return false;
157         }
158
159         // Translate identifiers: shared variables
160         int i = 0;
161         // Translate identifiers from values
162         switch (p)
163         {
164             case STYLE:
165             case LABEL:
166             {
167                 for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
168                 {
169                     char* c_str = wide_string_to_UTF8(current->get(i));
170                     controller.setObjectProperty(*it, PORT, p, std::string(c_str));
171                     FREE(c_str);
172                 }
173                 return true;
174             }
175             case IMPLICIT:
176             {
177                 static const wchar_t E[] = L"E";
178                 static const wchar_t I[] = L"I";
179
180                 for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
181                 {
182                     if (current->get(i) == I)
183                     {
184                         controller.setObjectProperty(*it, PORT, p, true);
185                     }
186                     else if (current->get(i) == E)
187                     {
188                         controller.setObjectProperty(*it, PORT, p, false);
189                     }
190                     else
191                     {
192                         return false;
193                     }
194                 }
195                 return true;
196             }
197             default:
198                 return false;
199         }
200     }
201     else if (v->getType() == types::InternalType::ScilabDouble)
202     {
203         types::Double* current = v->getAs<types::Double>();
204         if (current->getCols() != 0 && current->getCols() != 1)
205         {
206             return false;
207         }
208
209         size_t rows = current->getRows();
210         if (rows != ids.size())
211         {
212             return false;
213         }
214
215         // Translate identifiers: shared variables
216         int i = 0;
217         size_t datatypeIndex = 0;
218         // Translate identifiers from values
219         switch (p)
220         {
221             case FIRING:
222                 for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
223                 {
224                     double firing = current->get(i);
225
226                     controller.setObjectProperty(*it, PORT, p, firing);
227                 }
228                 return true;
229             case STYLE:
230             case LABEL:
231                 // Do nothing, because if the sizes match, then there are already zero concerned ports, so no ports to update
232                 return true;
233
234             case DATATYPE_ROWS:
235                 datatypeIndex = 0;
236                 // no break
237             case DATATYPE_COLS:
238                 datatypeIndex = 1;
239                 // no break
240             case DATATYPE_TYPE:
241             {
242                 datatypeIndex = 2;
243
244                 for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
245                 {
246                     std::vector<int> v;
247                     controller.getObjectProperty(*it, PORT, DATATYPE, v);
248
249                     double data = current->get(i);
250                     if (std::floor(data) != data)
251                     {
252                         return false;
253                     }
254
255                     v[datatypeIndex] = static_cast<int>(data);
256                     controller.setObjectProperty(*it, PORT, DATATYPE, v);
257                 }
258                 return true;
259             }
260
261             case IMPLICIT:
262                 // Do nothing, because if the sizes match, then there are already zero concerned ports, so no ports to update
263                 return true;
264         }
265
266     }
267     return false;
268 }
269
270 template<typename Adaptor, object_properties_t p>
271 bool fillNewPorts(std::vector<int>& newPorts, const std::vector<ScicosID>& children, double* d)
272 {
273     for (std::vector<int>::iterator it = newPorts.begin(); it != newPorts.end(); ++it, ++d)
274     {
275
276         if (p == CONNECTED_SIGNALS)   // the associated link must exist
277         {
278             if (0 > *d && *d >= children.size())
279             {
280                 return false;
281             }
282         } // no check is performed for other properties as newPorts will contains value not index
283
284         *it = static_cast<int>(*d);
285     }
286     return true;
287 }
288
289 template<typename Adaptor, object_properties_t p>
290 void updateNewPort(ScicosID oldPort, int newPort, Controller& controller,
291                    std::vector<ScicosID>& children, std::vector<ScicosID>& deletedObjects)
292 {
293     if (p == CONNECTED_SIGNALS)
294     {
295         // update signal and manage deconnection, using newPort as a children index
296         ScicosID oldSignal;
297         controller.getObjectProperty(oldPort, PORT, CONNECTED_SIGNALS, oldSignal);
298         ScicosID newSignal = children[newPort];
299         if (oldSignal != newSignal)
300         {
301             // disconnect the old link
302             ScicosID oldSignalSrc;
303             controller.getObjectProperty(oldSignal, LINK, SOURCE_PORT, oldSignalSrc);
304             ScicosID oldSignalDst;
305             controller.getObjectProperty(oldSignal, LINK, DESTINATION_PORT, oldSignalDst);
306             ScicosID unconnected = 0;
307             if (oldSignalSrc == oldPort)
308             {
309                 controller.setObjectProperty(oldSignalDst, PORT, CONNECTED_SIGNALS, unconnected);
310             }
311             else   // oldSignalDst == oldPort
312             {
313                 controller.setObjectProperty(oldSignalSrc, PORT, CONNECTED_SIGNALS, unconnected);
314             }
315             // Link de-association is not performed as the link will be removed
316             // connect the new link
317             controller.setObjectProperty(newSignal, LINK, SOURCE_PORT, 0);
318             controller.setObjectProperty(oldPort, PORT, CONNECTED_SIGNALS, newSignal);
319             children.erase(std::find(children.begin(), children.end(), oldSignal));
320             deletedObjects.push_back(oldSignal);
321         }
322     }
323     else
324     {
325         // update the p property, using newPort as a value
326         controller.setObjectProperty(oldPort, PORT, p, newPort);
327     }
328 }
329
330 template<typename Adaptor, object_properties_t p>
331 bool addNewPort(ScicosID newPortID, int newPort, const std::vector<ScicosID>& children, Controller& controller)
332 {
333     bool status = true;
334     if (p == CONNECTED_SIGNALS)
335     {
336         // set the connected signal if applicable, using newPort as a children index
337         if (newPort != 0)
338         {
339             ScicosID signal = children[newPort];
340             status = controller.setObjectProperty(newPortID, PORT, CONNECTED_SIGNALS, signal);
341         }
342     }
343     else
344     {
345         // set the requested property, using newPort as a value
346         status = controller.setObjectProperty(newPortID, PORT, p, newPort);
347     }
348
349     return status;
350 }
351
352 /**
353  * Update the ports with a specific property.
354  *
355  * Create ports if needed, remove ports if needed and set a default property on each port.
356  */
357 template<typename Adaptor, object_properties_t p>
358 bool update_ports_property(const Adaptor& adaptor, object_properties_t port_kind,  Controller& controller, types::InternalType* v)
359 {
360     model::Block* adaptee = adaptor.getAdaptee();
361
362     if (v->getType() != types::InternalType::ScilabDouble)
363     {
364         return false;
365     }
366     types::Double* value = v->getAs<types::Double>();
367
368     ScicosID parentDiagram;
369     controller.getObjectProperty(adaptee->id(), BLOCK, PARENT_DIAGRAM, parentDiagram);
370
371     std::vector<ScicosID> children;
372     if (parentDiagram != 0)
373     {
374         controller.getObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
375     }
376
377     std::vector<int> newPorts = std::vector<int>(value->getSize());
378
379     // retrieve old data
380     std::vector<ScicosID> oldPorts;
381     controller.getObjectProperty(adaptee->id(), adaptee->kind(), port_kind, oldPorts);
382     std::vector<ScicosID> previousPorts = oldPorts;
383
384     double* d = value->getReal();
385     if (!fillNewPorts<Adaptor, p>(newPorts, children, d))
386     {
387         return false;
388     }
389
390     std::vector<ScicosID> deletedObjects;
391
392     // updated ports
393     while (!oldPorts.empty() && !newPorts.empty())
394     {
395         ScicosID oldPort = oldPorts.back();
396         oldPorts.pop_back();
397         int newPort = newPorts.back();
398         newPorts.pop_back();
399
400         updateNewPort<Adaptor, p>(oldPort, newPort, controller, children, deletedObjects);
401     }
402
403     // removed ports
404     if (!oldPorts.empty())
405     {
406         previousPorts.erase(previousPorts.begin() + oldPorts.size(), previousPorts.end());
407
408         while (!oldPorts.empty())
409         {
410             ScicosID oldPort = oldPorts.back();
411             oldPorts.pop_back();
412
413             ScicosID signal;
414             controller.getObjectProperty(oldPort, PORT, CONNECTED_SIGNALS, signal);
415             if (signal != 0)
416             {
417                 // the link is connected, disconnect the other side
418                 ScicosID oldSignalSrc;
419                 controller.getObjectProperty(signal, LINK, SOURCE_PORT, oldSignalSrc);
420                 ScicosID oldSignalDst;
421                 controller.getObjectProperty(signal, LINK, DESTINATION_PORT, oldSignalDst);
422
423                 ScicosID unconnected = 0;
424                 if (oldSignalSrc == oldPort)
425                 {
426                     controller.setObjectProperty(oldSignalDst, PORT, CONNECTED_SIGNALS, unconnected);
427                 }
428                 else     // oldSignalDst == oldPort
429                 {
430                     controller.setObjectProperty(oldSignalSrc, PORT, CONNECTED_SIGNALS, unconnected);
431                 }
432
433                 children.erase(std::find(children.begin(), children.end(), signal));
434                 deletedObjects.push_back(signal);
435             }
436
437             deletedObjects.push_back(oldPort);
438         }
439
440         controller.setObjectProperty(adaptee->id(), BLOCK, port_kind, previousPorts);
441     }
442
443     // added ports
444     if (!newPorts.empty())
445     {
446         while (!newPorts.empty())
447         {
448             int newPort = newPorts.back();
449             oldPorts.pop_back();
450
451             ScicosID id = controller.createObject(PORT);
452             controller.setObjectProperty(id, PORT, SOURCE_BLOCK, adaptee->id());
453             addNewPort<Adaptor, p>(id, newPort, children, controller);
454             previousPorts.push_back(id);
455         }
456
457         controller.setObjectProperty(adaptee->id(), BLOCK, port_kind, previousPorts);
458     }
459
460     // remove objects from the model after de-association
461     if (parentDiagram != 0)
462     {
463         controller.setObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
464     }
465     for (std::vector<ScicosID>::iterator it = deletedObjects.begin(); it != deletedObjects.end(); ++it)
466     {
467         controller.deleteObject(*it);
468     }
469
470     return true;
471 }
472
473
474 } /* namespace view_scilab */
475 } /* namespace org_scilab_modules_scicos */
476
477 #endif /* PORTS_MANAGEMENT_HXX_ */