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