* Bug #15456 fixed: Xcos 5.5.x files did not load properly
[scilab.git] / scilab / modules / scicos / src / cpp / view_scilab / GraphicsAdapter.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2014-2016 - Scilab Enterprises - Clement DAVID
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15
16 #include <cwchar>
17
18 #include <string>
19 #include <vector>
20 #include <iostream>
21 #include <iomanip>
22 #include <algorithm>
23 #include <functional>
24
25 #include "list.hxx"
26 #include "tlist.hxx"
27 #include "double.hxx"
28 #include "string.hxx"
29
30 #include "utilities.hxx"
31 #include "Controller.hxx"
32 #include "GraphicsAdapter.hxx"
33 #include "ports_management.hxx"
34 #include "controller_helpers.hxx"
35
36 #include "var2vec.hxx"
37 #include "vec2var.hxx"
38
39 extern "C" {
40 #include "localization.h"
41 #include "sci_malloc.h"
42 #include "charEncoding.h"
43 }
44
45 namespace org_scilab_modules_scicos
46 {
47 namespace view_scilab
48 {
49 namespace
50 {
51
52 const std::wstring MBLOCK (L"MBLOCK");
53 const std::wstring MPBLOCK (L"MPBLOCK");
54 const std::wstring in (L"in");
55 const std::wstring intype (L"intype");
56 const std::wstring out (L"out");
57 const std::wstring outtype (L"outtype");
58 const std::wstring param (L"param");
59 const std::wstring paramv (L"paramv");
60 const std::wstring pprop (L"pprop");
61 const std::wstring nameF (L"nameF");
62 const std::wstring funtxt (L"funtxt");
63
64 // shared informations for relinking across adapters hierarchy
65 std::map<ScicosID, std::vector<int> > partial_pin;
66 std::map<ScicosID, std::vector<int> > partial_pout;
67 std::map<ScicosID, std::vector<int> > partial_pein;
68 std::map<ScicosID, std::vector<int> > partial_peout;
69
70 struct orig
71 {
72
73     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
74     {
75         double* data;
76         types::Double* o = new types::Double(1, 2, &data);
77         model::Block* adaptee = adaptor.getAdaptee();
78
79         std::vector<double> geom;
80         controller.getObjectProperty(adaptee, GEOMETRY, geom);
81
82         data[0] = geom[0];
83         data[1] = geom[1];
84
85         return o;
86     }
87
88     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
89     {
90
91         if (v->getType() != types::InternalType::ScilabDouble)
92         {
93             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: Real matrix expected.\n"), "graphics", "orig");
94             return false;
95         }
96
97         types::Double* current = v->getAs<types::Double>();
98         if (current->getSize() != 2)
99         {
100             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s.%s: %d-by-%d expected.\n"), "graphics", "orig", 1, 2);
101             return false;
102         }
103
104         model::Block* adaptee = adaptor.getAdaptee();
105         std::vector<double> geom;
106         controller.getObjectProperty(adaptee, GEOMETRY, geom);
107
108         geom[0] = current->get(0);
109         geom[1] = current->get(1);
110
111         controller.setObjectProperty(adaptee, GEOMETRY, geom);
112         return true;
113     }
114 };
115
116 struct sz
117 {
118
119     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
120     {
121         double* data;
122         types::Double* o = new types::Double(1, 2, &data);
123         model::Block* adaptee = adaptor.getAdaptee();
124
125         std::vector<double> geom;
126         controller.getObjectProperty(adaptee, GEOMETRY, geom);
127
128         data[0] = geom[2];
129         data[1] = geom[3];
130         return o;
131     }
132
133     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
134     {
135         if (v->getType() != types::InternalType::ScilabDouble)
136         {
137             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: Real matrix expected.\n"), "graphics", "sz");
138             return false;
139         }
140
141         types::Double* current = v->getAs<types::Double>();
142         if (current->getSize() != 2)
143         {
144             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s.%s: %d-by-%d expected.\n"), "graphics", "sz", 1, 2);
145             return false;
146         }
147
148         model::Block* adaptee = adaptor.getAdaptee();
149         std::vector<double> geom;
150         controller.getObjectProperty(adaptee, GEOMETRY, geom);
151
152         geom[2] = current->get(0);
153         geom[3] = current->get(1);
154
155         controller.setObjectProperty(adaptee, GEOMETRY, geom);
156         return true;
157     }
158 };
159
160 struct exprs
161 {
162
163     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
164     {
165         model::Block* adaptee = adaptor.getAdaptee();
166
167         std::vector<double> exprs;
168         controller.getObjectProperty(adaptee, EXPRS, exprs);
169
170         types::InternalType* res;
171         if (!vec2var(exprs, res))
172         {
173             // if invalid data, return a valid value
174             return types::Double::Empty();
175         }
176         return res;
177     }
178
179     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
180     {
181         model::Block* adaptee = adaptor.getAdaptee();
182
183         // Corner-case the content is an empty matrix
184         if (v->getType() == types::InternalType::ScilabDouble)
185         {
186             types::Double* current = v->getAs<types::Double>();
187             if (!current->isEmpty())
188             {
189                 return false;
190             }
191         }
192
193         std::vector<double> exprs;
194         if (!var2vec(v, exprs))
195         {
196             return false;
197         }
198         controller.setObjectProperty(adaptee, EXPRS, exprs);
199         return true;
200     }
201 };
202
203 std::vector<int> cached_ports_init(std::map<ScicosID, std::vector<int> >& cache, model::Block* adaptee, const object_properties_t port_kind, const Controller& controller)
204 {
205     auto it = cache.find(adaptee->id());
206     if (it != cache.end())
207     {
208         // if already present, do not refresh it !
209         return it->second;
210     }
211
212     std::vector<ScicosID> ids;
213     controller.getObjectProperty(adaptee, port_kind, ids);
214
215     std::vector<ScicosID> children;
216     ScicosID parentBlock;
217     controller.getObjectProperty(adaptee, PARENT_BLOCK, parentBlock);
218     if (parentBlock == ScicosID())
219     {
220         // Adding to a diagram
221         ScicosID parentDiagram;
222         controller.getObjectProperty(adaptee, PARENT_DIAGRAM, parentDiagram);
223
224         controller.getObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
225     }
226     else
227     {
228         // Adding to a superblock
229         controller.getObjectProperty(parentBlock, BLOCK, CHILDREN, children);
230     }
231
232     std::vector<int> ret(ids.size());
233     // foreach ports, resolve it or discard
234     int i = 0;
235     for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
236     {
237         ScicosID id;
238         controller.getObjectProperty(*it, PORT, CONNECTED_SIGNALS, id);
239
240         if (id == ScicosID())
241         {
242             // Unconnected port, no need to search in 'children'
243             ret[i] = 0;
244         }
245         else
246         {
247             std::vector<ScicosID>::iterator found = std::find(children.begin(), children.end(), id);
248             if (found != children.end())
249             {
250                 ret[i] = static_cast<int>(std::distance(children.begin(), found)) + 1;
251             }
252             else
253             {
254                 // connected link not found ; discard it !
255                 ret[i] = 0;
256             }
257         }
258     }
259
260     cache.insert({adaptee->id(), ret});
261     return ret;
262 }
263
264 types::InternalType* cached_ports_get(std::map<ScicosID, std::vector<int> >& cache, const GraphicsAdapter& adaptor, const object_properties_t port_kind, const Controller& controller)
265 {
266     auto it = cache.find(adaptor.getAdaptee()->id());
267     if (it == cache.end())
268     {
269         return get_ports_property<GraphicsAdapter, CONNECTED_SIGNALS>(adaptor, port_kind, controller);
270     }
271
272     std::vector<int> const& ports = it->second;
273
274     double* data;
275     types::Double* ret = new types::Double(static_cast<int>(ports.size()), 1, &data);
276
277 #ifdef _MSC_VER
278     std::transform(ports.begin(), ports.end(), stdext::checked_array_iterator<double*>(data, ports.size()), [](int p)
279     {
280         return p;
281     });
282 #else
283     std::transform(ports.begin(), ports.end(), data, [](int p)
284     {
285         return p;
286     });
287 #endif
288
289     return ret;
290 }
291 bool cached_ports_set(std::map<ScicosID, std::vector<int> >& cache, GraphicsAdapter& adaptor, const object_properties_t port_kind, Controller& controller, types::InternalType* v)
292 {
293     auto it = cache.find(adaptor.getAdaptee()->id());
294     if (it == cache.end())
295     {
296         return update_ports_property<GraphicsAdapter, CONNECTED_SIGNALS>(adaptor, port_kind, controller, v);
297     }
298
299     if (v->getType() != types::InternalType::ScilabDouble)
300     {
301         return false;
302     }
303     types::Double* value = v->getAs<types::Double>();
304
305     // store the updated value locally
306     {
307         std::vector<int>& ports = it->second;
308
309         ports.resize(value->getSize());
310         for (int i = 0; i < value->getSize(); ++i)
311         {
312             ports[i] = static_cast<int>(value->get(i));
313         }
314     }
315
316     // enforce a the same number of port on the Model
317     {
318         const std::vector<int>& ports = it->second;
319
320         std::vector<ScicosID> objects;
321         controller.getObjectProperty(adaptor.getAdaptee(), port_kind, objects);
322
323         if (ports.size() < objects.size())
324         {
325             // remove existing ports
326             for (size_t i = ports.size(); i < objects.size(); ++i)
327             {
328                 ScicosID p = objects[i];
329
330                 ScicosID signal;
331                 controller.getObjectProperty(p, PORT, CONNECTED_SIGNALS, signal);
332                 if (signal != ScicosID())
333                 {
334                     model::Link* link = controller.getBaseObject<model::Link>(signal);
335                     ScicosID opposite;
336                     controller.getObjectProperty(link, DESTINATION_PORT, opposite);
337                     if (opposite == p)
338                     {
339                         controller.setObjectProperty(link, DESTINATION_PORT, ScicosID());
340                     }
341                     controller.getObjectProperty(link, SOURCE_PORT, opposite);
342                     if (opposite == p)
343                     {
344                         controller.setObjectProperty(link, SOURCE_PORT, ScicosID());
345                     }
346                 }
347                 controller.deleteObject(p);
348             }
349             objects.resize(ports.size());
350         }
351         else
352         {
353             // add missing ports
354             for (size_t i = objects.size(); i < ports.size(); ++i)
355             {
356                 model::Port* p = controller.createBaseObject<model::Port>(PORT);
357
358                 controller.setObjectProperty(p, SOURCE_BLOCK, adaptor.getAdaptee()->id());
359                 controller.setObjectProperty(p, PORT_KIND, port_from_property(port_kind));
360
361                 objects.push_back(p->id());
362             }
363         }
364         controller.setObjectProperty(adaptor.getAdaptee(), port_kind, objects);
365     }
366     return true;
367 }
368
369 struct pin
370 {
371
372     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
373     {
374         return cached_ports_get(partial_pin, adaptor, INPUTS, controller);
375     }
376
377     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
378     {
379         return cached_ports_set(partial_pin, adaptor, INPUTS, controller, v);
380     }
381 };
382
383 struct pout
384 {
385
386     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
387     {
388         return cached_ports_get(partial_pout, adaptor, OUTPUTS, controller);
389     }
390
391     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
392     {
393         return cached_ports_set(partial_pout, adaptor, OUTPUTS, controller, v);
394     }
395 };
396
397 struct pein
398 {
399
400     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
401     {
402         return cached_ports_get(partial_pein, adaptor, EVENT_INPUTS, controller);
403     }
404
405     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
406     {
407         return cached_ports_set(partial_pein, adaptor, EVENT_INPUTS, controller, v);
408     }
409 };
410
411 struct peout
412 {
413
414     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
415     {
416         return cached_ports_get(partial_peout, adaptor, EVENT_OUTPUTS, controller);
417     }
418
419     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
420     {
421         return cached_ports_set(partial_peout, adaptor, EVENT_OUTPUTS, controller, v);
422     }
423 };
424
425 struct gr_i
426 {
427
428     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& /*controller*/)
429     {
430         return adaptor.getGrIContent();
431     }
432
433     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& /*controller*/)
434     {
435         adaptor.setGrIContent(v);
436         return true;
437     }
438 };
439
440 struct id
441 {
442
443     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
444     {
445         ScicosID adaptee = adaptor.getAdaptee()->id();
446
447         std::string id;
448         controller.getObjectProperty(adaptee, BLOCK, DESCRIPTION, id);
449
450         types::String* o = new types::String(1, 1);
451         o->set(0, id.data());
452
453         return o;
454     }
455
456     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
457     {
458         if (v->getType() != types::InternalType::ScilabString)
459         {
460             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: string expected.\n"), "graphics", "id");
461             return false;
462         }
463
464         types::String* current = v->getAs<types::String>();
465         if (!current->isScalar())
466         {
467             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s.%s: %d-by-%d expected.\n"), "graphics", "id", 1, 1);
468             return false;
469         }
470
471         ScicosID adaptee = adaptor.getAdaptee()->id();
472
473         char* c_str = wide_string_to_UTF8(current->get(0));
474         std::string id(c_str);
475         FREE(c_str);
476
477         controller.setObjectProperty(adaptee, BLOCK, DESCRIPTION, id);
478         return true;
479     }
480 };
481
482 struct in_implicit
483 {
484
485     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
486     {
487         return get_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, INPUTS, controller);
488     }
489
490     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
491     {
492         return set_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, INPUTS, controller, v);
493     }
494 };
495
496 struct out_implicit
497 {
498
499     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
500     {
501         return get_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, OUTPUTS, controller);
502     }
503
504     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
505     {
506         return set_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, OUTPUTS, controller, v);
507     }
508 };
509
510 struct in_style
511 {
512
513     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
514     {
515         return get_ports_property<GraphicsAdapter, STYLE>(adaptor, INPUTS, controller);
516     }
517
518     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
519     {
520         return set_ports_property<GraphicsAdapter, STYLE>(adaptor, INPUTS, controller, v);
521     }
522 };
523
524 struct out_style
525 {
526
527     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
528     {
529         return get_ports_property<GraphicsAdapter, STYLE>(adaptor, OUTPUTS, controller);
530     }
531
532     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
533     {
534         return set_ports_property<GraphicsAdapter, STYLE>(adaptor, OUTPUTS, controller, v);
535     }
536 };
537
538 struct in_label
539 {
540
541     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
542     {
543         return get_ports_property<GraphicsAdapter, LABEL>(adaptor, INPUTS, controller);
544     }
545
546     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
547     {
548         return set_ports_property<GraphicsAdapter, LABEL>(adaptor, INPUTS, controller, v);
549     }
550 };
551
552 struct out_label
553 {
554
555     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
556     {
557         return get_ports_property<GraphicsAdapter, LABEL>(adaptor, OUTPUTS, controller);
558     }
559
560     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
561     {
562         return set_ports_property<GraphicsAdapter, LABEL>(adaptor, OUTPUTS, controller, v);
563     }
564 };
565
566 struct style
567 {
568
569     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
570     {
571         model::Block* adaptee = adaptor.getAdaptee();
572
573         std::string style;
574         controller.getObjectProperty(adaptee, STYLE, style);
575
576         return new types::String(style.c_str());
577     }
578
579     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
580     {
581         model::Block* adaptee = adaptor.getAdaptee();
582         if (v->getType() == types::InternalType::ScilabString)
583         {
584             types::String* current = v->getAs<types::String>();
585             if (!current->isScalar())
586             {
587                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s.%s: %d-by-%d expected.\n"), "graphics", "style", 1, 1);
588                 return false;
589             }
590
591             char* c_str = wide_string_to_UTF8(current->get(0));
592             std::string style(c_str);
593             FREE(c_str);
594
595             controller.setObjectProperty(adaptee, STYLE, style);
596             return true;
597         }
598         else if (v->getType() == types::InternalType::ScilabDouble)
599         {
600             types::Double* current = v->getAs<types::Double>();
601             if (current->getSize() != 0)
602             {
603                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: string expected.\n"), "graphics", "style");
604                 return false;
605             }
606
607             std::string style;
608             controller.setObjectProperty(adaptee, STYLE, style);
609             return true;
610         }
611
612         get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: string expected.\n"), "graphics", "style");
613         return false;
614     }
615 };
616
617 } /* namespace */
618
619 template<> property<GraphicsAdapter>::props_t property<GraphicsAdapter>::fields = property<GraphicsAdapter>::props_t();
620 static void initialize_fields()
621 {
622     if (property<GraphicsAdapter>::properties_have_not_been_set())
623     {
624         property<GraphicsAdapter>::reserve_properties(16);
625         property<GraphicsAdapter>::add_property(L"orig", &orig::get, &orig::set);
626         property<GraphicsAdapter>::add_property(L"sz", &sz::get, &sz::set);
627         property<GraphicsAdapter>::add_property(L"exprs", &exprs::get, &exprs::set);
628         property<GraphicsAdapter>::add_property(L"pin", &pin::get, &pin::set);
629         property<GraphicsAdapter>::add_property(L"pout", &pout::get, &pout::set);
630         property<GraphicsAdapter>::add_property(L"pein", &pein::get, &pein::set);
631         property<GraphicsAdapter>::add_property(L"peout", &peout::get, &peout::set);
632         property<GraphicsAdapter>::add_property(L"gr_i", &gr_i::get, &gr_i::set);
633         property<GraphicsAdapter>::add_property(L"id", &id::get, &id::set);
634         property<GraphicsAdapter>::add_property(L"in_implicit", &in_implicit::get, &in_implicit::set);
635         property<GraphicsAdapter>::add_property(L"out_implicit", &out_implicit::get, &out_implicit::set);
636         property<GraphicsAdapter>::add_property(L"in_style", &in_style::get, &in_style::set);
637         property<GraphicsAdapter>::add_property(L"out_style", &out_style::get, &out_style::set);
638         property<GraphicsAdapter>::add_property(L"in_label", &in_label::get, &in_label::set);
639         property<GraphicsAdapter>::add_property(L"out_label", &out_label::get, &out_label::set);
640         property<GraphicsAdapter>::add_property(L"style", &style::get, &style::set);
641         property<GraphicsAdapter>::shrink_to_fit();
642     }
643 }
644
645 GraphicsAdapter::GraphicsAdapter() :
646     BaseAdapter<GraphicsAdapter, org_scilab_modules_scicos::model::Block>(),
647     gr_i_content(reference_value(types::Double::Empty()))
648 {
649     initialize_fields();
650 }
651
652 GraphicsAdapter::GraphicsAdapter(const Controller& c, model::Block* adaptee) :
653     BaseAdapter<GraphicsAdapter, org_scilab_modules_scicos::model::Block>(c, adaptee),
654     gr_i_content(reference_value(types::Double::Empty()))
655 {
656     initialize_fields();
657
658     Controller controller;
659     cached_ports_init(partial_pin, adaptee, INPUTS, controller);
660     cached_ports_init(partial_pout, adaptee, OUTPUTS, controller);
661     cached_ports_init(partial_pein, adaptee, EVENT_INPUTS, controller);
662     cached_ports_init(partial_peout, adaptee, EVENT_OUTPUTS, controller);
663 }
664
665 GraphicsAdapter::~GraphicsAdapter()
666 {
667     gr_i_content->DecreaseRef();
668     gr_i_content->killMe();
669
670     if (getAdaptee() != nullptr && getAdaptee()->refCount() == 0)
671     {
672         partial_pin.erase(getAdaptee()->id());
673         partial_pout.erase(getAdaptee()->id());
674         partial_pein.erase(getAdaptee()->id());
675         partial_peout.erase(getAdaptee()->id());
676     }
677 }
678
679 std::wstring GraphicsAdapter::getTypeStr() const
680 {
681     return getSharedTypeStr();
682 }
683
684 std::wstring GraphicsAdapter::getShortTypeStr() const
685 {
686     return getSharedTypeStr();
687 }
688
689 types::InternalType* GraphicsAdapter::getGrIContent() const
690 {
691     return gr_i_content;
692 }
693
694 void GraphicsAdapter::setGrIContent(types::InternalType* v)
695 {
696     types::InternalType* temp = gr_i_content;
697
698     v->IncreaseRef();
699     gr_i_content = v;
700
701     temp->DecreaseRef();
702     temp->killMe();
703 }
704
705 static void relink_cached(Controller& controller, model::BaseObject* adaptee, const std::vector<ScicosID>& children, std::map<ScicosID, std::vector<int> >& cache, object_properties_t p)
706 {
707     auto it = cache.find(adaptee->id());
708     if (it == cache.end())
709     {
710         // unable to relink as there is no information to do so
711         return;
712     }
713     std::vector<int>& cached_information = it->second;
714
715     std::vector<ScicosID> ports;
716     controller.getObjectProperty(adaptee, p, ports);
717
718     if (cached_information.size() != ports.size())
719     {
720         // defensive programming: unable to relink as something goes wrong on the adapters
721         return;
722     }
723
724     bool isConnected = true;
725     for (size_t i = 0; i < cached_information.size(); ++i)
726     {
727         ScicosID connectedSignal;
728         controller.getObjectProperty(ports[i], PORT, CONNECTED_SIGNALS, connectedSignal);
729
730         if (connectedSignal != ScicosID())
731         {
732             cached_information[i] = (int)std::distance(children.begin(), std::find(children.begin(), children.end(), connectedSignal));
733         }
734         else
735         {
736             isConnected = false;
737         }
738     }
739
740     if (isConnected)
741     {
742         cache.erase(it);
743     }
744 }
745
746 void GraphicsAdapter::relink(Controller& controller, model::Block* adaptee, const std::vector<ScicosID>& children)
747 {
748     relink_cached(controller, adaptee, children, partial_pin, INPUTS);
749     relink_cached(controller, adaptee, children, partial_pout, OUTPUTS);
750     relink_cached(controller, adaptee, children, partial_pein, EVENT_INPUTS);
751     relink_cached(controller, adaptee, children, partial_peout, EVENT_OUTPUTS);
752 }
753
754 void copyOnClone(model::BaseObject* original, model::BaseObject* cloned, std::map<ScicosID, std::vector<int> >& cache)
755 {
756
757     auto it = cache.find(original->id());
758     if (it != cache.end())
759         cache.insert({cloned->id(), it->second});
760 }
761
762 void GraphicsAdapter::add_partial_links_information(Controller& controller, model::BaseObject* original, model::BaseObject* cloned)
763 {
764     // precondition
765     if (cloned == nullptr)
766     {
767         return;
768     }
769
770     if (original->kind() == BLOCK)
771     {
772         // add the from / to information if applicable
773         copyOnClone(original, cloned, partial_pin);
774         copyOnClone(original, cloned, partial_pout);
775         copyOnClone(original, cloned, partial_pein);
776         copyOnClone(original, cloned, partial_peout);
777     }
778
779     switch (original->kind())
780     {
781         // handle recursion
782         case DIAGRAM:
783         case BLOCK:
784         {
785             std::vector<ScicosID> originalChildren;
786             controller.getObjectProperty(original, CHILDREN, originalChildren);
787             std::vector<ScicosID> clonedChildren;
788             controller.getObjectProperty(cloned, CHILDREN, clonedChildren);
789
790             for (size_t i = 0; i < originalChildren.size(); ++i)
791             {
792                 // a clone preserve position thus null ID, ignore them on
793                 // this loop
794                 if (originalChildren[i] != ScicosID())
795                 {
796                     add_partial_links_information(controller, controller.getBaseObject(originalChildren[i]), controller.getBaseObject(clonedChildren[i]));
797                 }
798             }
799             break;
800         }
801
802         default:
803             break;
804     }
805 }
806
807 void GraphicsAdapter::remove_partial_links_information(model::Block* o)
808 {
809     partial_pin.erase(o->id());
810     partial_pout.erase(o->id());
811     partial_pein.erase(o->id());
812     partial_peout.erase(o->id());
813 }
814
815 } /* namespace view_scilab */
816 } /* namespace org_scilab_modules_scicos */