a54e21c13dc404d94e47b4a40380060e5b8ed5e4
[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  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 #ifndef PORTS_MANAGEMENT_HXX_
18 #define PORTS_MANAGEMENT_HXX_
19
20 #include <cmath>
21
22 #include <deque>
23 #include <string>
24 #include <vector>
25 #include <algorithm>
26 #include <iterator>
27 #include <cassert>
28
29 #include "internal.hxx"
30 #include "bool.hxx"
31 #include "double.hxx"
32 #include "string.hxx"
33
34 #include "utilities.hxx"
35 #include "Controller.hxx"
36 #include "controller_helpers.hxx"
37 #include "model/Port.hxx"
38
39 extern "C" {
40 #include "sci_malloc.h"
41 #include "charEncoding.h"
42 #include "localization.h"
43 }
44
45 namespace org_scilab_modules_scicos
46 {
47 namespace view_scilab
48 {
49
50 /*
51  * Utilities function to emit the error messages
52  */
53 template<object_properties_t p>
54 std::string adapterName(const object_properties_t /*port_kind*/)
55 {
56     switch (p)
57     {
58         case CONNECTED_SIGNALS:
59         case IMPLICIT:
60         case LABEL:
61         case STYLE:
62             return "graphics";
63         case DATATYPE_ROWS:
64         case DATATYPE_COLS:
65         case DATATYPE_TYPE:
66         case FIRING:
67             return "model";
68     }
69 }
70
71 template<object_properties_t p>
72 std::string adapterFieldName(const object_properties_t port_kind)
73 {
74     std::string postfix;
75     switch (p)
76     {
77         case CONNECTED_SIGNALS:
78         {
79             switch (port_kind)
80             {
81                 case INPUTS:
82                     return "pin";
83                 case OUTPUTS:
84                     return "pout";
85                 case EVENT_INPUTS:
86                     return "pein";
87                 case EVENT_OUTPUTS:
88                     return "peout";
89                 default:
90                     break;
91             }
92         }
93         break;
94         case IMPLICIT:
95             postfix = "_implicit";
96             break;
97         case LABEL:
98             postfix = "_label";
99             break;
100         case STYLE:
101             postfix = "_style";
102             break;
103         case DATATYPE_TYPE:
104             postfix = "typ";
105             break;
106         case DATATYPE_ROWS:
107             postfix = "2";
108             break;
109         case DATATYPE_COLS:
110             break;
111         case FIRING:
112             return "firing";
113         default:
114             break;
115     }
116
117     std::string prefix;
118     switch (port_kind)
119     {
120         case INPUTS:
121             prefix = "in";
122             break;
123         case OUTPUTS:
124             prefix = "out";
125             break;
126         case EVENT_INPUTS:
127             prefix = "evtin";
128             break;
129         case EVENT_OUTPUTS:
130             prefix = "evtout";
131             break;
132         default:
133             break;
134     }
135
136     return prefix + postfix;
137 }
138
139 /*
140  * Return a Scilab encoded value for a property.
141  */
142 template<typename Adaptor, object_properties_t p>
143 types::InternalType* get_ports_property(const Adaptor& adaptor, const object_properties_t port_kind, const Controller& controller)
144 {
145     ScicosID adaptee = adaptor.getAdaptee()->id();
146
147     // Retrieve the identifiers
148     std::vector<ScicosID> ids;
149     controller.getObjectProperty(adaptee, BLOCK, port_kind, ids);
150
151     // Translate identifiers: shared variables
152     int i = 0;
153     size_t datatypeIndex = -1;
154     // Translate identifiers to return values
155     switch (p)
156     {
157         case STYLE:
158         case LABEL:
159         {
160             if (ids.empty())
161             {
162                 return new types::String(L"");
163             }
164             types::String* o = new types::String((int)ids.size(), 1);
165             for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
166             {
167                 std::string s;
168                 controller.getObjectProperty(*it, PORT, p, s);
169                 o->set(i, s.data());
170             }
171             return o;
172         }
173         case DATATYPE_TYPE:
174             // The type defaults to [1] if no port has been defined
175             if (ids.empty())
176             {
177                 return new types::Double(1);
178             }
179             datatypeIndex++;
180             // no break
181         case DATATYPE_COLS:
182             datatypeIndex++;
183             // no break
184         case DATATYPE_ROWS:
185         {
186             datatypeIndex++;
187             double* data;
188             types::Double* o = new types::Double((int)ids.size(), 1, &data);
189             for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
190             {
191                 std::vector<int> v;
192                 controller.getObjectProperty(*it, PORT, DATATYPE, v);
193                 data[i] = v[datatypeIndex];
194             }
195             return o;
196         }
197         case FIRING:
198         {
199             double* data;
200             types::Double* o = new types::Double((int)ids.size(), 1, &data);
201             for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
202             {
203                 controller.getObjectProperty(*it, PORT, p, data[i]);
204             }
205             return o;
206         }
207         case IMPLICIT:
208         {
209             if (ids.size() == 0)
210             {
211                 // When no port is present, return an empty matrix
212                 return types::Double::Empty();
213             }
214
215             types::String* o = new types::String((int)ids.size(), 1);
216             for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
217             {
218                 bool v;
219                 controller.getObjectProperty(*it, PORT, p, v);
220                 o->set(i, (v == false) ? L"E" : L"I");
221             }
222             return o;
223         }
224         case CONNECTED_SIGNALS:
225         {
226             double* v;
227             types::Double* o = new types::Double((int)ids.size(), 1, &v);
228
229             ScicosID parentDiagram;
230             controller.getObjectProperty(adaptee, BLOCK, PARENT_DIAGRAM, parentDiagram);
231
232             std::vector<ScicosID> children;
233             if (parentDiagram != 0)
234             {
235                 // Adding to a diagram
236                 controller.getObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
237             }
238             else
239             {
240                 ScicosID parentBlock;
241                 controller.getObjectProperty(adaptee, BLOCK, PARENT_BLOCK, parentBlock);
242                 if (parentBlock != 0)
243                 {
244                     // Adding to a superblock
245                     controller.getObjectProperty(parentBlock, BLOCK, CHILDREN, children);
246                 }
247             }
248
249             for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
250             {
251                 ScicosID id;
252                 controller.getObjectProperty(*it, PORT, p, id);
253
254                 v[i] = 0;
255
256                 if (id == 0)
257                 {
258                     // Unconnected port, no need to search in 'children'
259                 }
260                 else
261                 {
262                     std::vector<ScicosID>::iterator found = std::find(children.begin(), children.end(), id);
263
264                     if (found != children.end())
265                     {
266                         v[i] = static_cast<double>(std::distance(children.begin(), found)) + 1;
267                     }
268                 }
269             }
270             return o;
271         }
272         default:
273             return 0;
274     }
275 }
276
277 /*
278  * Set a Scilab encoded values as a property.
279  *
280  * \note this method will ignore or return false if one of the ports does not exist, depending on the property setted.
281  */
282 template<typename Adaptor, object_properties_t p>
283 bool set_ports_property(const Adaptor& adaptor, const object_properties_t port_kind, Controller& controller, types::InternalType* v)
284 {
285     ScicosID adaptee = adaptor.getAdaptee()->id();
286
287     // Retrieve the ports identifiers
288     std::vector<ScicosID> ids;
289     controller.getObjectProperty(adaptee, BLOCK, port_kind, ids);
290
291     if (v->getType() == types::InternalType::ScilabString)
292     {
293         types::String* current = v->getAs<types::String>();
294
295         // Translate identifiers: shared variables
296         int i = 0;
297         // Translate identifiers from values
298         switch (p)
299         {
300             case STYLE:
301             case LABEL:
302             {
303                 for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
304                 {
305                     char* c_str = NULL;
306                     if (i >= current->getSize())
307                     {
308                         // If the input isn't large enough, fill each port with empty strings
309                         c_str = wide_string_to_UTF8(L"");
310                     }
311                     else
312                     {
313                         c_str = wide_string_to_UTF8(current->get(i));
314                     }
315                     controller.setObjectProperty(*it, PORT, p, std::string(c_str));
316                     FREE(c_str);
317                 }
318                 return true;
319             }
320             case IMPLICIT:
321             {
322                 int maxSize = static_cast<int>(ids.size());
323                 if (current->getSize() < maxSize)
324                 {
325                     maxSize = current->getSize();
326                 }
327
328                 std::wstring Explicit = L"E";
329                 std::wstring Implicit = L"I";
330                 for (; i < maxSize; ++i)
331                 {
332                     if (current->get(i) == Implicit)
333                     {
334                         controller.setObjectProperty(ids[i], PORT, p, true);
335                     }
336                     else if (current->get(i) == Explicit)
337                     {
338                         controller.setObjectProperty(ids[i], PORT, p, false);
339                     }
340                     else
341                     {
342                         std::string adapter = adapterName<p>(port_kind);
343                         std::string field = adapterFieldName<p>(port_kind);
344                         get_or_allocate_logger()->log(LOG_ERROR, _("Wrong value for field %s.%s: %s or %s vector expected.\n"), adapter.data(), field.data(), "'E'", "'I'");
345                         return false;
346                     }
347                 }
348                 for (i = maxSize; i < ids.size(); ++i)
349                 {
350                     // Tag the missing ports as Explicit. This is done to fix the resizing of pin & pout.
351                     controller.setObjectProperty(ids[i], PORT, p, false);
352                 }
353                 return true;
354             }
355             default:
356                 std::string adapter = adapterName<p>(port_kind);
357                 std::string field = adapterFieldName<p>(port_kind);
358                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s .\n"), adapter.data(), field.data());
359                 return false;
360         }
361     }
362     else if (v->getType() == types::InternalType::ScilabDouble)
363     {
364         types::Double* current = v->getAs<types::Double>();
365
366         // Translate identifiers: shared variables
367         int i = 0;
368         size_t datatypeIndex = -1;
369         // Translate identifiers from values
370         switch (p)
371         {
372             case FIRING:
373                 if (current->isEmpty())
374                 {
375                     return true;
376                 }
377
378                 if (current->getSize() < static_cast<int>(ids.size()))
379                 {
380                     std::string adapter = adapterName<p>(port_kind);
381                     std::string field = adapterFieldName<p>(port_kind);
382                     get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s.%s: %d-by-%d expected.\n"), adapter.data(), field.data(), ids.size(), 1);
383                     return false;
384                 }
385
386                 for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
387                 {
388                     double firing = current->get(i);
389
390                     controller.setObjectProperty(*it, PORT, p, firing);
391                 }
392                 return true;
393             case STYLE:
394             case LABEL:
395                 // Do nothing, because if the sizes match, then there are already zero concerned ports, so no ports to update
396                 return true;
397
398             case DATATYPE_TYPE:
399                 datatypeIndex++;
400                 // no break
401             case DATATYPE_COLS:
402                 datatypeIndex++;
403                 // no break
404             case DATATYPE_ROWS:
405             {
406                 datatypeIndex++;
407
408                 // ignore the set without error
409                 if (current->getSize() != static_cast<int>(ids.size()))
410                 {
411                     return true;
412                 }
413
414                 for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
415                 {
416                     std::vector<int> newDataType;
417                     controller.getObjectProperty(*it, PORT, DATATYPE, newDataType);
418
419                     double data = current->get(i);
420                     if (std::floor(data) != data)
421                     {
422                         std::string adapter = adapterName<p>(port_kind);
423                         std::string field = adapterFieldName<p>(port_kind);
424                         get_or_allocate_logger()->log(LOG_ERROR, _("Wrong value for field %s.%s: Round number expected.\n"), adapter.data(), field.data());
425                         return false;
426                     }
427
428                     newDataType[datatypeIndex] = static_cast<int>(data);
429                     controller.setObjectProperty(*it, PORT, DATATYPE, newDataType);
430                 }
431                 return true;
432             }
433
434             case IMPLICIT:
435                 // Do nothing, because if the sizes match, then there are already zero concerned ports, so no ports to update
436                 return true;
437
438             default:
439                 std::string adapter = adapterName<p>(port_kind);
440                 std::string field = adapterFieldName<p>(port_kind);
441                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s .\n"), adapter.data(), field.data());
442                 return false;
443         }
444
445     }
446     else if (v->getType() == types::InternalType::ScilabBool)
447     {
448         switch (p)
449         {
450             case FIRING:
451                 // firing=%f is interpreted as "no initial event on the corresponding port", so set a negative value.
452                 for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it)
453                 {
454                     controller.setObjectProperty(*it, PORT, p, -1);
455                 }
456                 return true;
457             default:
458                 std::string adapter = adapterName<p>(port_kind);
459                 std::string field = adapterFieldName<p>(port_kind);
460                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s .\n"), adapter.data(), field.data());
461                 return false;
462         }
463     }
464     std::string adapter = adapterName<p>(port_kind);
465     std::string field = adapterFieldName<p>(port_kind);
466     get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s .\n"), adapter.data(), field.data());
467     return false;
468 }
469
470 /**
471  * Fill \a newPorts with \a d values checking content if possible.
472  *
473  * \param newPorts new ports children's index or value to be filled
474  * \param children all object in the current layer (diagram or superblock)
475  * \param d the C-array values to set
476  * \return true on success, false otherwise
477  */
478 template<typename Adaptor, object_properties_t p>
479 inline bool fillNewPorts(std::deque<int>& newPorts, const std::vector<ScicosID>& children, const double* d)
480 {
481     for (std::deque<int>::iterator it = newPorts.begin(); it != newPorts.end(); ++it, ++d)
482     {
483
484         if (p == CONNECTED_SIGNALS)   // the associated link must exist
485         {
486             if (0 > *d && *d >= children.size())
487             {
488                 return false;
489             }
490             *it = static_cast<int>(*d - 1); // 'd' contains indexes
491         } // no check is performed for other properties as newPorts will contains value not index
492         else
493         {
494             *it = static_cast<int>(*d);
495         }
496     }
497     return true;
498 }
499
500 /**
501  * Set the port value
502  *
503  * \param oldPort the old port object ID
504  * \param newPort new port children's index or value
505  * \param controller current transaction instance
506  * \param children all object in the current layer (diagram or superblock)
507  * \param deletedObjects trash used to delete objects
508  */
509 template<typename Adaptor, object_properties_t p>
510 inline bool updateNewPort(const ScicosID oldPort, int newPort, Controller& controller,
511                           std::vector<ScicosID>& children, std::vector<ScicosID>& deletedObjects)
512 {
513     if (p == CONNECTED_SIGNALS)
514     {
515         // update signal and manage deconnection, using newPort as a children index
516         ScicosID oldSignal;
517         controller.getObjectProperty(oldPort, PORT, CONNECTED_SIGNALS, oldSignal);
518
519         ScicosID newSignal;
520         if (children.size() > 0 && newPort >= 0)
521         {
522             newSignal = children[newPort];
523         }
524         else
525         {
526             newSignal = 0;
527         }
528
529         if (oldSignal != newSignal)
530         {
531             if (oldSignal == 0)
532             {
533                 // FIXME: The port was not linked, check if Link #newSignal has an unconnected end that is connectable to the port (Link kind)
534                 return false;
535             }
536             // disconnect the old link
537             ScicosID oldSignalSrc;
538             controller.getObjectProperty(oldSignal, LINK, SOURCE_PORT, oldSignalSrc);
539             ScicosID oldSignalDst;
540             controller.getObjectProperty(oldSignal, LINK, DESTINATION_PORT, oldSignalDst);
541             ScicosID unconnected = 0;
542             if (oldSignalSrc == oldPort)
543             {
544                 controller.setObjectProperty(oldSignalDst, PORT, CONNECTED_SIGNALS, unconnected);
545             }
546             else   // oldSignalDst == oldPort
547             {
548                 controller.setObjectProperty(oldSignalSrc, PORT, CONNECTED_SIGNALS, unconnected);
549             }
550             // Link de-association is not performed as the link will be removed
551             // connect the new link if there is one
552             if (newSignal != 0)
553             {
554                 controller.setObjectProperty(newSignal, LINK, SOURCE_PORT, 0);
555                 controller.setObjectProperty(oldPort, PORT, CONNECTED_SIGNALS, newSignal);
556                 children.erase(std::find(children.begin(), children.end(), oldSignal));
557                 deletedObjects.push_back(oldSignal);
558             }
559         }
560     }
561     else
562     {
563         // update the p property, using newPort as a value
564         int datatypeIndex = -1;
565         switch (p)
566         {
567             case DATATYPE_TYPE:
568                 datatypeIndex++;
569                 // no break
570             case DATATYPE_COLS:
571                 datatypeIndex++;
572                 // no break
573             case DATATYPE_ROWS:
574             {
575                 datatypeIndex++;
576                 std::vector<int> datatype;
577                 controller.getObjectProperty(oldPort, PORT, DATATYPE, datatype);
578                 datatype[datatypeIndex] = newPort;
579                 controller.setObjectProperty(oldPort, PORT, DATATYPE, datatype);
580                 return true;
581             }
582             default:
583                 controller.setObjectProperty(oldPort, PORT, p, newPort);
584         }
585     }
586     return true;
587 }
588
589 /**
590  * Add a new port
591  *
592  * \param newPortID the old port object ID
593  * \param newPort new port children's index or value
594  * \param children all object in the current layer (diagram or superblock)
595  * \param controller current transaction instance
596  * \return true on success, false otherwise
597  */
598 template<typename Adaptor, object_properties_t p>
599 inline bool addNewPort(const ScicosID newPortID, int newPort, const std::vector<ScicosID>& children, Controller& controller)
600 {
601     bool status = true;
602     if (p == CONNECTED_SIGNALS)
603     {
604         // set the connected signal if applicable, using newPort as a children index
605         if (children.size() > 0)
606         {
607             ScicosID signal = children[newPort];
608             status = controller.setObjectProperty(newPortID, PORT, CONNECTED_SIGNALS, signal) != FAIL;
609         }
610     }
611     else
612     {
613         // set the requested property, using newPort as a value
614         int datatypeIndex = -1;
615         switch (p)
616         {
617             case DATATYPE_TYPE:
618                 datatypeIndex++;
619                 // no break
620             case DATATYPE_COLS:
621                 datatypeIndex++;
622                 // no break
623             case DATATYPE_ROWS:
624             {
625                 datatypeIndex++;
626                 std::vector<int> datatype;
627                 controller.getObjectProperty(newPortID, PORT, DATATYPE, datatype);
628                 datatype[datatypeIndex] = newPort;
629                 return controller.setObjectProperty(newPortID, PORT, DATATYPE, datatype) != FAIL;
630             }
631             default:
632                 return controller.setObjectProperty(newPortID, PORT, p, newPort) != FAIL;
633         }
634     }
635
636     return status;
637 }
638
639 /**
640  * Update the ports with a specific property.
641  *
642  * Create ports if needed, remove ports if needed and set a default property on each port.
643  */
644 template<typename Adaptor, object_properties_t p>
645 bool update_ports_property(const Adaptor& adaptor, const object_properties_t port_kind, Controller& controller, types::InternalType* v)
646 {
647     ScicosID adaptee = adaptor.getAdaptee()->id();
648
649     if (v->getType() != types::InternalType::ScilabDouble)
650     {
651         std::string adapter = adapterName<p>(port_kind);
652         std::string field = adapterFieldName<p>(port_kind);
653         get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: Real matrix expected.\n"), adapter.data(), field.data());
654         return false;
655     }
656     types::Double* value = v->getAs<types::Double>();
657
658     ScicosID parentBlock;
659     controller.getObjectProperty(adaptee, BLOCK, PARENT_BLOCK, parentBlock);
660     ScicosID parentDiagram;
661     controller.getObjectProperty(adaptee, BLOCK, PARENT_DIAGRAM, parentDiagram);
662
663     std::vector<ScicosID> children;
664     if (parentBlock != 0)
665     {
666         // Adding to a superblock
667         controller.getObjectProperty(parentBlock, BLOCK, CHILDREN, children);
668     }
669     if (parentDiagram != 0 && children.empty())
670     {
671         // Adding to a diagram
672         controller.getObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
673     }
674
675     std::deque<int> newPorts (value->getSize());
676
677     // retrieve old data
678     std::vector<ScicosID> previousPorts;
679     controller.getObjectProperty(adaptee, BLOCK, port_kind, previousPorts);
680     std::deque<ScicosID> oldPorts(previousPorts.begin(), previousPorts.end());
681
682     double* d = value->getReal();
683     if (!fillNewPorts<Adaptor, p>(newPorts, children, d))
684     {
685         std::string adapter = adapterName<p>(port_kind);
686         std::string field = adapterFieldName<p>(port_kind);
687         get_or_allocate_logger()->log(LOG_ERROR, _("Wrong value for field %s.%s: Must be in the interval [%d, %d].\n"), adapter.data(), field.data(), 1, children.size());
688         return false;
689     }
690
691     std::vector<ScicosID> deletedObjects;
692
693     // updated ports
694     while (!oldPorts.empty() && !newPorts.empty())
695     {
696         ScicosID oldPort = oldPorts.front();
697         oldPorts.pop_front();
698         int newPort = newPorts.front();
699         newPorts.pop_front();
700
701         if (!updateNewPort<Adaptor, p>(oldPort, newPort, controller, children, deletedObjects))
702         {
703             std::string adapter = adapterName<p>(port_kind);
704             std::string field = adapterFieldName<p>(port_kind);
705             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong value for field %s.%s: FIXME port has not been updated.\n"), adapter.data(), field.data(), 1, children.size());
706             return false;
707         }
708     }
709
710     // removed ports
711     if (!oldPorts.empty())
712     {
713         previousPorts.erase(previousPorts.end() - oldPorts.size(), previousPorts.end());
714
715         while (!oldPorts.empty())
716         {
717             ScicosID oldPort = oldPorts.front();
718             oldPorts.pop_front();
719
720             ScicosID signal;
721             controller.getObjectProperty(oldPort, PORT, CONNECTED_SIGNALS, signal);
722             if (signal != 0)
723             {
724                 // the link is connected, disconnect the other side
725                 ScicosID oldSignalSrc;
726                 controller.getObjectProperty(signal, LINK, SOURCE_PORT, oldSignalSrc);
727                 ScicosID oldSignalDst;
728                 controller.getObjectProperty(signal, LINK, DESTINATION_PORT, oldSignalDst);
729
730                 ScicosID unconnected = 0;
731                 if (oldSignalSrc == oldPort)
732                 {
733                     controller.setObjectProperty(oldSignalDst, PORT, CONNECTED_SIGNALS, unconnected);
734                 }
735                 else     // oldSignalDst == oldPort
736                 {
737                     controller.setObjectProperty(oldSignalSrc, PORT, CONNECTED_SIGNALS, unconnected);
738                 }
739
740                 children.erase(std::find(children.begin(), children.end(), signal));
741                 deletedObjects.push_back(signal);
742             }
743
744             deletedObjects.push_back(oldPort);
745         }
746
747         controller.setObjectProperty(adaptee, BLOCK, port_kind, previousPorts);
748     }
749
750     // added ports
751     if (!newPorts.empty())
752     {
753         while (!newPorts.empty())
754         {
755             int newPort = newPorts.front();
756             newPorts.pop_front();
757
758             ScicosID id = controller.createObject(PORT);
759             controller.setObjectProperty(id, PORT, SOURCE_BLOCK, adaptee);
760             switch (port_kind)
761             {
762                 case INPUTS:
763                     controller.setObjectProperty(id, PORT, PORT_KIND, static_cast<int>(PORT_IN));
764                     break;
765                 case OUTPUTS:
766                     controller.setObjectProperty(id, PORT, PORT_KIND, static_cast<int>(PORT_OUT));
767                     break;
768                 case EVENT_INPUTS:
769                     controller.setObjectProperty(id, PORT, PORT_KIND, static_cast<int>(PORT_EIN));
770                     break;
771                 case EVENT_OUTPUTS:
772                     controller.setObjectProperty(id, PORT, PORT_KIND, static_cast<int>(PORT_EOUT));
773                     break;
774                 default:
775                     // should never happen
776                     assert(!"Not managed kind of port");
777                     return false;
778             }
779             addNewPort<Adaptor, p>(id, newPort, children, controller);
780             previousPorts.push_back(id);
781         }
782
783         controller.setObjectProperty(adaptee, BLOCK, port_kind, previousPorts);
784     }
785
786     // remove objects from the model after de-association
787     if (parentDiagram != 0)
788     {
789         for (const ScicosID & id : children)
790         {
791             controller.referenceObject(id);
792         }
793         controller.setObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
794     }
795     else if (parentBlock != 0)
796     {
797         for (const ScicosID & id : children)
798         {
799             controller.referenceObject(id);
800         }
801         controller.setObjectProperty(parentBlock, BLOCK, CHILDREN, children);
802     }
803     for (std::vector<ScicosID>::iterator it = deletedObjects.begin(); it != deletedObjects.end(); ++it)
804     {
805         controller.deleteObject(*it);
806     }
807
808     return true;
809 }
810
811 } /* namespace view_scilab */
812 } /* namespace org_scilab_modules_scicos */
813
814 #endif /* PORTS_MANAGEMENT_HXX_ */