110125bed7ca0fd5bbdd1f677e40e2e29394f445
[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-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 STYLE:
222             case LABEL:
223                 // Do nothing, because if the sizes match, then there are already zero concerned ports, so no ports to update
224                 return true;
225
226             case DATATYPE_ROWS:
227                 datatypeIndex = 0;
228             // no break
229             case DATATYPE_COLS:
230                 datatypeIndex = 1;
231             // no break
232             case DATATYPE_TYPE:
233             {
234                 datatypeIndex = 2;
235
236                 for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
237                 {
238                     std::vector<int> v;
239                     controller.getObjectProperty(*it, PORT, DATATYPE, v);
240
241                     double data = current->get(i);
242                     if (std::floor(data) != data)
243                     {
244                         return false;
245                     }
246
247                     v[datatypeIndex] = static_cast<int>(data);
248                     controller.setObjectProperty(*it, PORT, DATATYPE, v);
249                 }
250                 return true;
251             }
252
253             case IMPLICIT:
254                 // Do nothing, because if the sizes match, then there are already zero concerned ports, so no ports to update
255                 return true;
256         }
257
258     }
259     return false;
260 }
261
262 template<typename Adaptor, object_properties_t p>
263 bool fillNewPorts(std::vector<int>& newPorts, const std::vector<ScicosID>& children, double* d)
264 {
265     for (std::vector<int>::iterator it = newPorts.begin(); it != newPorts.end(); ++it, ++d)
266     {
267
268         if (p == CONNECTED_SIGNALS)   // the associated link must exist
269         {
270             if (0 > *d && *d >= children.size())
271             {
272                 return false;
273             }
274         } // no check is performed for other properties as newPorts will contains value not index
275
276         *it = static_cast<int>(*d);
277     }
278     return true;
279 }
280
281 template<typename Adaptor, object_properties_t p>
282 void updateNewPort(ScicosID oldPort, int newPort, Controller& controller,
283                    std::vector<ScicosID>& children, std::vector<ScicosID>& deletedObjects)
284 {
285     if (p == CONNECTED_SIGNALS)
286     {
287         // update signal and manage deconnection, using newPort as a children index
288         ScicosID oldSignal;
289         controller.getObjectProperty(oldPort, PORT, CONNECTED_SIGNALS, oldSignal);
290         ScicosID newSignal = children[newPort];
291         if (oldSignal != newSignal)
292         {
293             // disconnect the old link
294             ScicosID oldSignalSrc;
295             controller.getObjectProperty(oldSignal, LINK, SOURCE_PORT, oldSignalSrc);
296             ScicosID oldSignalDst;
297             controller.getObjectProperty(oldSignal, LINK, DESTINATION_PORT, oldSignalDst);
298             ScicosID unconnected = 0;
299             if (oldSignalSrc == oldPort)
300             {
301                 controller.setObjectProperty(oldSignalDst, PORT, CONNECTED_SIGNALS, unconnected);
302             }
303             else   // oldSignalDst == oldPort
304             {
305                 controller.setObjectProperty(oldSignalSrc, PORT, CONNECTED_SIGNALS, unconnected);
306             }
307             // Link de-association is not performed as the link will be removed
308             // connect the new link
309             controller.setObjectProperty(newSignal, LINK, SOURCE_PORT, 0);
310             controller.setObjectProperty(oldPort, PORT, CONNECTED_SIGNALS, newSignal);
311             children.erase(std::find(children.begin(), children.end(), oldSignal));
312             deletedObjects.push_back(oldSignal);
313         }
314     }
315     else
316     {
317         // update the p property, using newPort as a value
318         controller.setObjectProperty(oldPort, PORT, p, newPort);
319     }
320 }
321
322 template<typename Adaptor, object_properties_t p>
323 bool addNewPort(ScicosID newPortID, int newPort, const std::vector<ScicosID>& children, Controller& controller)
324 {
325     bool status = true;
326     if (p == CONNECTED_SIGNALS)
327     {
328         // set the connected signal if applicable, using newPort as a children index
329         if (newPort != 0)
330         {
331             ScicosID signal = children[newPort];
332             status = controller.setObjectProperty(newPortID, PORT, CONNECTED_SIGNALS, signal);
333         }
334     }
335     else
336     {
337         // set the requested property, using newPort as a value
338         status = controller.setObjectProperty(newPortID, PORT, p, newPort);
339     }
340
341     return status;
342 }
343
344 /**
345  * Update the ports with a specific property.
346  *
347  * Create ports if needed, remove ports if needed and set a default property on each port.
348  */
349 template<typename Adaptor, object_properties_t p>
350 bool update_ports_property(const Adaptor& adaptor, object_properties_t port_kind,  Controller& controller, types::InternalType* v)
351 {
352     model::Block* adaptee = adaptor.getAdaptee();
353
354     if (v->getType() != types::InternalType::ScilabDouble)
355     {
356         return false;
357     }
358     types::Double* value = v->getAs<types::Double>();
359
360     ScicosID parentDiagram;
361     controller.getObjectProperty(adaptee->id(), BLOCK, PARENT_DIAGRAM, parentDiagram);
362
363     std::vector<ScicosID> children;
364     if (parentDiagram != 0)
365     {
366         controller.getObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
367     }
368
369     std::vector<int> newPorts = std::vector<int>(value->getSize());
370
371     // retrieve old data
372     std::vector<ScicosID> oldPorts;
373     controller.getObjectProperty(adaptee->id(), adaptee->kind(), port_kind, oldPorts);
374     std::vector<ScicosID> previousPorts = oldPorts;
375
376     double* d = value->getReal();
377     if (!fillNewPorts<Adaptor, p>(newPorts, children, d))
378     {
379         return false;
380     }
381
382     std::vector<ScicosID> deletedObjects;
383
384     // updated ports
385     while (!oldPorts.empty() && !newPorts.empty())
386     {
387         ScicosID oldPort = oldPorts.back();
388         oldPorts.pop_back();
389         int newPort = newPorts.back();
390         newPorts.pop_back();
391
392         updateNewPort<Adaptor, p>(oldPort, newPort, controller, children, deletedObjects);
393     }
394
395     // removed ports
396     if (!oldPorts.empty())
397     {
398         previousPorts.erase(previousPorts.begin() + oldPorts.size(), previousPorts.end());
399
400         while (!oldPorts.empty())
401         {
402             ScicosID oldPort = oldPorts.back();
403             oldPorts.pop_back();
404
405             ScicosID signal;
406             controller.getObjectProperty(oldPort, PORT, CONNECTED_SIGNALS, signal);
407             if (signal != 0)
408             {
409                 // the link is connected, disconnect the other side
410                 ScicosID oldSignalSrc;
411                 controller.getObjectProperty(signal, LINK, SOURCE_PORT, oldSignalSrc);
412                 ScicosID oldSignalDst;
413                 controller.getObjectProperty(signal, LINK, DESTINATION_PORT, oldSignalDst);
414
415                 ScicosID unconnected = 0;
416                 if (oldSignalSrc == oldPort)
417                 {
418                     controller.setObjectProperty(oldSignalDst, PORT, CONNECTED_SIGNALS, unconnected);
419                 }
420                 else     // oldSignalDst == oldPort
421                 {
422                     controller.setObjectProperty(oldSignalSrc, PORT, CONNECTED_SIGNALS, unconnected);
423                 }
424
425                 children.erase(std::find(children.begin(), children.end(), signal));
426                 deletedObjects.push_back(signal);
427             }
428
429             deletedObjects.push_back(oldPort);
430         }
431
432         controller.setObjectProperty(adaptee->id(), BLOCK, port_kind, previousPorts);
433     }
434
435     // added ports
436     if (!newPorts.empty())
437     {
438         while (!newPorts.empty())
439         {
440             int newPort = newPorts.back();
441             oldPorts.pop_back();
442
443             ScicosID id = controller.createObject(PORT);
444             controller.setObjectProperty(id, PORT, SOURCE_BLOCK, adaptee->id());
445             addNewPort<Adaptor, p>(id, newPort, children, controller);
446             previousPorts.push_back(id);
447         }
448
449         controller.setObjectProperty(adaptee->id(), BLOCK, port_kind, previousPorts);
450     }
451
452     // remove objects from the model after de-association
453     if (parentDiagram != 0)
454     {
455         controller.setObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
456     }
457     for (std::vector<ScicosID>::iterator it = deletedObjects.begin(); it != deletedObjects.end(); ++it)
458     {
459         controller.deleteObject(*it);
460     }
461
462     return true;
463 }
464
465
466 } /* view_scilab */
467 } /* namespace org_scilab_modules_scicos */
468
469 #endif /* PORTS_MANAGEMENT_HXX_ */