* Bug #14586 - Xcos simulation stop button did not work.
[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                 if (current->getSize() < static_cast<int>(ids.size()))
323                 {
324                     std::string adapter = adapterName<p>(port_kind);
325                     std::string field = adapterFieldName<p>(port_kind);
326                     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);
327                     return false;
328                 }
329
330                 std::wstring Explicit = L"E";
331                 std::wstring Implicit = L"I";
332                 for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
333                 {
334                     if (current->get(i) == Implicit)
335                     {
336                         controller.setObjectProperty(*it, PORT, p, true);
337                     }
338                     else if (current->get(i) == Explicit)
339                     {
340                         controller.setObjectProperty(*it, PORT, p, false);
341                     }
342                     else
343                     {
344                         std::string adapter = adapterName<p>(port_kind);
345                         std::string field = adapterFieldName<p>(port_kind);
346                         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'");
347                         return false;
348                     }
349                 }
350                 return true;
351             }
352             default:
353                 std::string adapter = adapterName<p>(port_kind);
354                 std::string field = adapterFieldName<p>(port_kind);
355                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s .\n"), adapter.data(), field.data());
356                 return false;
357         }
358     }
359     else if (v->getType() == types::InternalType::ScilabDouble)
360     {
361         types::Double* current = v->getAs<types::Double>();
362
363         // Translate identifiers: shared variables
364         int i = 0;
365         size_t datatypeIndex = -1;
366         // Translate identifiers from values
367         switch (p)
368         {
369             case FIRING:
370                 if (current->isEmpty())
371                 {
372                     return true;
373                 }
374
375                 if (current->getSize() < static_cast<int>(ids.size()))
376                 {
377                     std::string adapter = adapterName<p>(port_kind);
378                     std::string field = adapterFieldName<p>(port_kind);
379                     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);
380                     return false;
381                 }
382
383                 for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
384                 {
385                     double firing = current->get(i);
386
387                     controller.setObjectProperty(*it, PORT, p, firing);
388                 }
389                 return true;
390             case STYLE:
391             case LABEL:
392                 // Do nothing, because if the sizes match, then there are already zero concerned ports, so no ports to update
393                 return true;
394
395             case DATATYPE_TYPE:
396                 datatypeIndex++;
397             // no break
398             case DATATYPE_COLS:
399                 datatypeIndex++;
400             // no break
401             case DATATYPE_ROWS:
402             {
403                 datatypeIndex++;
404
405                 // ignore the set without error
406                 if (current->getSize() != static_cast<int>(ids.size()))
407                 {
408                     return true;
409                 }
410
411                 for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
412                 {
413                     std::vector<int> newDataType;
414                     controller.getObjectProperty(*it, PORT, DATATYPE, newDataType);
415
416                     double data = current->get(i);
417                     if (std::floor(data) != data)
418                     {
419                         std::string adapter = adapterName<p>(port_kind);
420                         std::string field = adapterFieldName<p>(port_kind);
421                         get_or_allocate_logger()->log(LOG_ERROR, _("Wrong value for field %s.%s: Round number expected.\n"), adapter.data(), field.data());
422                         return false;
423                     }
424
425                     newDataType[datatypeIndex] = static_cast<int>(data);
426                     controller.setObjectProperty(*it, PORT, DATATYPE, newDataType);
427                 }
428                 return true;
429             }
430
431             case IMPLICIT:
432                 // Do nothing, because if the sizes match, then there are already zero concerned ports, so no ports to update
433                 return true;
434
435             default:
436                 std::string adapter = adapterName<p>(port_kind);
437                 std::string field = adapterFieldName<p>(port_kind);
438                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s .\n"), adapter.data(), field.data());
439                 return false;
440         }
441
442     }
443     else if (v->getType() == types::InternalType::ScilabBool)
444     {
445         switch (p)
446         {
447             case FIRING:
448                 // firing=%f is interpreted as "no initial event on the corresponding port", so set a negative value.
449                 for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it)
450                 {
451                     controller.setObjectProperty(*it, PORT, p, -1);
452                 }
453                 return true;
454             default:
455                 std::string adapter = adapterName<p>(port_kind);
456                 std::string field = adapterFieldName<p>(port_kind);
457                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s .\n"), adapter.data(), field.data());
458                 return false;
459         }
460     }
461     std::string adapter = adapterName<p>(port_kind);
462     std::string field = adapterFieldName<p>(port_kind);
463     get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s .\n"), adapter.data(), field.data());
464     return false;
465 }
466
467 /**
468  * Fill \a newPorts with \a d values checking content if possible.
469  *
470  * \param newPorts new ports children's index or value to be filled
471  * \param children all object in the current layer (diagram or superblock)
472  * \param d the C-array values to set
473  * \return true on success, false otherwise
474  */
475 template<typename Adaptor, object_properties_t p>
476 inline bool fillNewPorts(std::deque<int>& newPorts, const std::vector<ScicosID>& children, const double* d)
477 {
478     for (std::deque<int>::iterator it = newPorts.begin(); it != newPorts.end(); ++it, ++d)
479     {
480
481         if (p == CONNECTED_SIGNALS)   // the associated link must exist
482         {
483             if (0 > *d && *d >= children.size())
484             {
485                 return false;
486             }
487             *it = static_cast<int>(*d - 1); // 'd' contains indexes
488         } // no check is performed for other properties as newPorts will contains value not index
489         else
490         {
491             *it = static_cast<int>(*d);
492         }
493     }
494     return true;
495 }
496
497 /**
498  * Set the port value
499  *
500  * \param oldPort the old port object ID
501  * \param newPort new port children's index or value
502  * \param controller current transaction instance
503  * \param children all object in the current layer (diagram or superblock)
504  * \param deletedObjects trash used to delete objects
505  */
506 template<typename Adaptor, object_properties_t p>
507 inline bool updateNewPort(const ScicosID oldPort, int newPort, Controller& controller,
508                           std::vector<ScicosID>& children, std::vector<ScicosID>& deletedObjects)
509 {
510     if (p == CONNECTED_SIGNALS)
511     {
512         // update signal and manage deconnection, using newPort as a children index
513         ScicosID oldSignal;
514         controller.getObjectProperty(oldPort, PORT, CONNECTED_SIGNALS, oldSignal);
515
516         ScicosID newSignal;
517         if (children.size() > 0 && newPort >= 0)
518         {
519             newSignal = children[newPort];
520         }
521         else
522         {
523             newSignal = 0;
524         }
525
526         if (oldSignal != newSignal)
527         {
528             if (oldSignal == 0)
529             {
530                 // FIXME: The port was not linked, check if Link #newSignal has an unconnected end that is connectable to the port (Link kind)
531                 return false;
532             }
533             // disconnect the old link
534             ScicosID oldSignalSrc;
535             controller.getObjectProperty(oldSignal, LINK, SOURCE_PORT, oldSignalSrc);
536             ScicosID oldSignalDst;
537             controller.getObjectProperty(oldSignal, LINK, DESTINATION_PORT, oldSignalDst);
538             ScicosID unconnected = 0;
539             if (oldSignalSrc == oldPort)
540             {
541                 controller.setObjectProperty(oldSignalDst, PORT, CONNECTED_SIGNALS, unconnected);
542             }
543             else   // oldSignalDst == oldPort
544             {
545                 controller.setObjectProperty(oldSignalSrc, PORT, CONNECTED_SIGNALS, unconnected);
546             }
547             // Link de-association is not performed as the link will be removed
548             // connect the new link if there is one
549             if (newSignal != 0)
550             {
551                 controller.setObjectProperty(newSignal, LINK, SOURCE_PORT, 0);
552                 controller.setObjectProperty(oldPort, PORT, CONNECTED_SIGNALS, newSignal);
553                 children.erase(std::find(children.begin(), children.end(), oldSignal));
554                 deletedObjects.push_back(oldSignal);
555             }
556         }
557     }
558     else
559     {
560         // update the p property, using newPort as a value
561         int datatypeIndex = -1;
562         switch (p)
563         {
564             case DATATYPE_TYPE:
565                 datatypeIndex++;
566             // no break
567             case DATATYPE_COLS:
568                 datatypeIndex++;
569             // no break
570             case DATATYPE_ROWS:
571             {
572                 datatypeIndex++;
573                 std::vector<int> datatype;
574                 controller.getObjectProperty(oldPort, PORT, DATATYPE, datatype);
575                 datatype[datatypeIndex] = newPort;
576                 controller.setObjectProperty(oldPort, PORT, DATATYPE, datatype);
577                 return true;
578             }
579             default:
580                 controller.setObjectProperty(oldPort, PORT, p, newPort);
581         }
582     }
583     return true;
584 }
585
586 /**
587  * Add a new port
588  *
589  * \param newPortID the old port object ID
590  * \param newPort new port children's index or value
591  * \param children all object in the current layer (diagram or superblock)
592  * \param controller current transaction instance
593  * \return true on success, false otherwise
594  */
595 template<typename Adaptor, object_properties_t p>
596 inline bool addNewPort(const ScicosID newPortID, int newPort, const std::vector<ScicosID>& children, Controller& controller)
597 {
598     bool status = true;
599     if (p == CONNECTED_SIGNALS)
600     {
601         // set the connected signal if applicable, using newPort as a children index
602         if (children.size() > 0)
603         {
604             ScicosID signal = children[newPort];
605             status = controller.setObjectProperty(newPortID, PORT, CONNECTED_SIGNALS, signal) != FAIL;
606         }
607     }
608     else
609     {
610         // set the requested property, using newPort as a value
611         int datatypeIndex = -1;
612         switch (p)
613         {
614             case DATATYPE_TYPE:
615                 datatypeIndex++;
616             // no break
617             case DATATYPE_COLS:
618                 datatypeIndex++;
619             // no break
620             case DATATYPE_ROWS:
621             {
622                 datatypeIndex++;
623                 std::vector<int> datatype;
624                 controller.getObjectProperty(newPortID, PORT, DATATYPE, datatype);
625                 datatype[datatypeIndex] = newPort;
626                 return controller.setObjectProperty(newPortID, PORT, DATATYPE, datatype) != FAIL;
627             }
628             default:
629                 return controller.setObjectProperty(newPortID, PORT, p, newPort) != FAIL;
630         }
631     }
632
633     return status;
634 }
635
636 /**
637  * Update the ports with a specific property.
638  *
639  * Create ports if needed, remove ports if needed and set a default property on each port.
640  */
641 template<typename Adaptor, object_properties_t p>
642 bool update_ports_property(const Adaptor& adaptor, const object_properties_t port_kind, Controller& controller, types::InternalType* v)
643 {
644     ScicosID adaptee = adaptor.getAdaptee()->id();
645
646     if (v->getType() != types::InternalType::ScilabDouble)
647     {
648         std::string adapter = adapterName<p>(port_kind);
649         std::string field = adapterFieldName<p>(port_kind);
650         get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: Real matrix expected.\n"), adapter.data(), field.data());
651         return false;
652     }
653     types::Double* value = v->getAs<types::Double>();
654
655     ScicosID parentBlock;
656     controller.getObjectProperty(adaptee, BLOCK, PARENT_BLOCK, parentBlock);
657     ScicosID parentDiagram;
658     controller.getObjectProperty(adaptee, BLOCK, PARENT_DIAGRAM, parentDiagram);
659
660     std::vector<ScicosID> children;
661     if (parentBlock != 0)
662     {
663         // Adding to a superblock
664         controller.getObjectProperty(parentBlock, BLOCK, CHILDREN, children);
665     }
666     if (parentDiagram != 0 && children.empty())
667     {
668         // Adding to a diagram
669         controller.getObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
670     }
671
672     std::deque<int> newPorts (value->getSize());
673
674     // retrieve old data
675     std::vector<ScicosID> previousPorts;
676     controller.getObjectProperty(adaptee, BLOCK, port_kind, previousPorts);
677     std::deque<ScicosID> oldPorts(previousPorts.begin(), previousPorts.end());
678
679     double* d = value->getReal();
680     if (!fillNewPorts<Adaptor, p>(newPorts, children, d))
681     {
682         std::string adapter = adapterName<p>(port_kind);
683         std::string field = adapterFieldName<p>(port_kind);
684         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());
685         return false;
686     }
687
688     std::vector<ScicosID> deletedObjects;
689
690     // updated ports
691     while (!oldPorts.empty() && !newPorts.empty())
692     {
693         ScicosID oldPort = oldPorts.front();
694         oldPorts.pop_front();
695         int newPort = newPorts.front();
696         newPorts.pop_front();
697
698         if (!updateNewPort<Adaptor, p>(oldPort, newPort, controller, children, deletedObjects))
699         {
700             std::string adapter = adapterName<p>(port_kind);
701             std::string field = adapterFieldName<p>(port_kind);
702             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());
703             return false;
704         }
705     }
706
707     // removed ports
708     if (!oldPorts.empty())
709     {
710         previousPorts.erase(previousPorts.end() - oldPorts.size(), previousPorts.end());
711
712         while (!oldPorts.empty())
713         {
714             ScicosID oldPort = oldPorts.front();
715             oldPorts.pop_front();
716
717             ScicosID signal;
718             controller.getObjectProperty(oldPort, PORT, CONNECTED_SIGNALS, signal);
719             if (signal != 0)
720             {
721                 // the link is connected, disconnect the other side
722                 ScicosID oldSignalSrc;
723                 controller.getObjectProperty(signal, LINK, SOURCE_PORT, oldSignalSrc);
724                 ScicosID oldSignalDst;
725                 controller.getObjectProperty(signal, LINK, DESTINATION_PORT, oldSignalDst);
726
727                 ScicosID unconnected = 0;
728                 if (oldSignalSrc == oldPort)
729                 {
730                     controller.setObjectProperty(oldSignalDst, PORT, CONNECTED_SIGNALS, unconnected);
731                 }
732                 else     // oldSignalDst == oldPort
733                 {
734                     controller.setObjectProperty(oldSignalSrc, PORT, CONNECTED_SIGNALS, unconnected);
735                 }
736
737                 children.erase(std::find(children.begin(), children.end(), signal));
738                 deletedObjects.push_back(signal);
739             }
740
741             deletedObjects.push_back(oldPort);
742         }
743
744         controller.setObjectProperty(adaptee, BLOCK, port_kind, previousPorts);
745     }
746
747     // added ports
748     if (!newPorts.empty())
749     {
750         while (!newPorts.empty())
751         {
752             int newPort = newPorts.front();
753             newPorts.pop_front();
754
755             ScicosID id = controller.createObject(PORT);
756             controller.setObjectProperty(id, PORT, SOURCE_BLOCK, adaptee);
757             switch (port_kind)
758             {
759                 case INPUTS:
760                     controller.setObjectProperty(id, PORT, PORT_KIND, static_cast<int>(PORT_IN));
761                     break;
762                 case OUTPUTS:
763                     controller.setObjectProperty(id, PORT, PORT_KIND, static_cast<int>(PORT_OUT));
764                     break;
765                 case EVENT_INPUTS:
766                     controller.setObjectProperty(id, PORT, PORT_KIND, static_cast<int>(PORT_EIN));
767                     break;
768                 case EVENT_OUTPUTS:
769                     controller.setObjectProperty(id, PORT, PORT_KIND, static_cast<int>(PORT_EOUT));
770                     break;
771                 default:
772                     // should never happen
773                     assert(!"Not managed kind of port");
774                     return false;
775             }
776             addNewPort<Adaptor, p>(id, newPort, children, controller);
777             previousPorts.push_back(id);
778         }
779
780         controller.setObjectProperty(adaptee, BLOCK, port_kind, previousPorts);
781     }
782
783     // remove objects from the model after de-association
784     if (parentDiagram != 0)
785     {
786         for (const ScicosID & id : children)
787         {
788             controller.referenceObject(id);
789         }
790         controller.setObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
791     }
792     else if (parentBlock != 0)
793     {
794         for (const ScicosID & id : children)
795         {
796             controller.referenceObject(id);
797         }
798         controller.setObjectProperty(parentBlock, BLOCK, CHILDREN, children);
799     }
800     for (std::vector<ScicosID>::iterator it = deletedObjects.begin(); it != deletedObjects.end(); ++it)
801     {
802         controller.deleteObject(*it);
803     }
804
805     return true;
806 }
807
808 } /* namespace view_scilab */
809 } /* namespace org_scilab_modules_scicos */
810
811 #endif /* PORTS_MANAGEMENT_HXX_ */