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