Scicos: speedup model transformation
[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             return 0;
174         }
175         return res;
176     }
177
178     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
179     {
180         model::Block* adaptee = adaptor.getAdaptee();
181
182         // Corner-case the content is an empty matrix
183         if (v->getType() == types::InternalType::ScilabDouble)
184         {
185             types::Double* current = v->getAs<types::Double>();
186             if (!current->isEmpty())
187             {
188                 return false;
189             }
190         }
191
192         std::vector<double> exprs;
193         if (!var2vec(v, exprs))
194         {
195             return false;
196         }
197         controller.setObjectProperty(adaptee, EXPRS, exprs);
198         return true;
199     }
200 };
201
202 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)
203 {
204     auto it = cache.find(adaptee->id());
205     if (it != cache.end())
206     {
207         // if already present, do not refresh it !
208         return it->second;
209     }
210
211     std::vector<ScicosID> ids;
212     controller.getObjectProperty(adaptee, port_kind, ids);
213
214     std::vector<ScicosID> children;
215     ScicosID parentBlock;
216     controller.getObjectProperty(adaptee, PARENT_BLOCK, parentBlock);
217     if (parentBlock == ScicosID())
218     {
219         // Adding to a diagram
220         ScicosID parentDiagram;
221         controller.getObjectProperty(adaptee, PARENT_DIAGRAM, parentDiagram);
222
223         controller.getObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
224     }
225     else
226     {
227         // Adding to a superblock
228         controller.getObjectProperty(parentBlock, BLOCK, CHILDREN, children);
229     }
230
231     std::vector<int> ret(ids.size());
232     // foreach ports, resolve it or discard
233     int i = 0;
234     for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
235     {
236         ScicosID id;
237         controller.getObjectProperty(*it, PORT, CONNECTED_SIGNALS, id);
238
239         if (id == ScicosID())
240         {
241             // Unconnected port, no need to search in 'children'
242             ret[i] = 0;
243         }
244         else
245         {
246             std::vector<ScicosID>::iterator found = std::find(children.begin(), children.end(), id);
247             if (found != children.end())
248             {
249                 ret[i] = static_cast<int>(std::distance(children.begin(), found)) + 1;
250             }
251             else
252             {
253                 // connected link not found ; discard it !
254                 ret[i] = 0;
255             }
256         }
257     }
258
259     cache.insert({adaptee->id(), ret});
260     return ret;
261 }
262
263 types::InternalType* cached_ports_get(std::map<ScicosID, std::vector<int> >& cache, const GraphicsAdapter& adaptor, const object_properties_t port_kind, const Controller& controller)
264 {
265     auto it = cache.find(adaptor.getAdaptee()->id());
266     if (it == cache.end())
267     {
268         return get_ports_property<GraphicsAdapter, CONNECTED_SIGNALS>(adaptor, port_kind, controller);
269     }
270
271     std::vector<int> const& ports = it->second;
272
273     double* data;
274     types::Double* ret = new types::Double(static_cast<int>(ports.size()), 1, &data);
275
276 #ifdef _MSC_VER
277     std::transform(ports.begin(), ports.end(), stdext::checked_array_iterator<double*>(data, ports.size()), [](int p)
278     {
279         return p;
280     });
281 #else
282     std::transform(ports.begin(), ports.end(), data, [](int p)
283     {
284         return p;
285     });
286 #endif
287
288     return ret;
289 }
290 bool cached_ports_set(std::map<ScicosID, std::vector<int> >& cache, GraphicsAdapter& adaptor, const object_properties_t port_kind, Controller& controller, types::InternalType* v)
291 {
292     auto it = cache.find(adaptor.getAdaptee()->id());
293     if (it == cache.end())
294     {
295         return update_ports_property<GraphicsAdapter, CONNECTED_SIGNALS>(adaptor, port_kind, controller, v);
296     }
297
298     if (v->getType() != types::InternalType::ScilabDouble)
299     {
300         return false;
301     }
302     types::Double* value = v->getAs<types::Double>();
303
304     // store the updated value locally
305     {
306         std::vector<int>& ports = it->second;
307
308         ports.resize(value->getSize());
309         for (int i = 0; i < value->getSize(); ++i)
310         {
311             ports[i] = static_cast<int>(value->get(i));
312         }
313     }
314
315     // enforce a the same number of port on the Model
316     {
317         const std::vector<int>& ports = it->second;
318
319         std::vector<ScicosID> objects;
320         controller.getObjectProperty(adaptor.getAdaptee(), port_kind, objects);
321
322         if (ports.size() < objects.size())
323         {
324             // remove existing ports
325             for (size_t i = ports.size(); i < objects.size(); ++i)
326             {
327                 ScicosID p = objects[i];
328
329                 ScicosID signal;
330                 controller.getObjectProperty(p, PORT, CONNECTED_SIGNALS, signal);
331                 if (signal != ScicosID())
332                 {
333                     model::Link* link = controller.getBaseObject<model::Link>(signal);
334                     ScicosID opposite;
335                     controller.getObjectProperty(link, DESTINATION_PORT, opposite);
336                     if (opposite == p)
337                     {
338                         controller.setObjectProperty(link, DESTINATION_PORT, ScicosID());
339                     }
340                     controller.getObjectProperty(link, SOURCE_PORT, opposite);
341                     if (opposite == p)
342                     {
343                         controller.setObjectProperty(link, SOURCE_PORT, ScicosID());
344                     }
345                 }
346                 controller.deleteObject(p);
347             }
348             objects.resize(ports.size());
349         }
350         else
351         {
352             // add missing ports
353             for (size_t i = objects.size(); i < ports.size(); ++i)
354             {
355                 model::Port* p = controller.createBaseObject<model::Port>(PORT);
356
357                 controller.setObjectProperty(p, SOURCE_BLOCK, adaptor.getAdaptee()->id());
358                 controller.setObjectProperty(p, PORT_KIND, port_from_property(port_kind));
359
360                 objects.push_back(p->id());
361             }
362         }
363         controller.setObjectProperty(adaptor.getAdaptee(), port_kind, objects);
364     }
365     return true;
366 }
367
368 struct pin
369 {
370
371     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
372     {
373         return cached_ports_get(partial_pin, adaptor, INPUTS, controller);
374     }
375
376     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
377     {
378         return cached_ports_set(partial_pin, adaptor, INPUTS, controller, v);
379     }
380 };
381
382 struct pout
383 {
384
385     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
386     {
387         return cached_ports_get(partial_pout, adaptor, OUTPUTS, controller);
388     }
389
390     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
391     {
392         return cached_ports_set(partial_pout, adaptor, OUTPUTS, controller, v);
393     }
394 };
395
396 struct pein
397 {
398
399     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
400     {
401         return cached_ports_get(partial_pein, adaptor, EVENT_INPUTS, controller);
402     }
403
404     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
405     {
406         return cached_ports_set(partial_pein, adaptor, EVENT_INPUTS, controller, v);
407     }
408 };
409
410 struct peout
411 {
412
413     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
414     {
415         return cached_ports_get(partial_peout, adaptor, EVENT_OUTPUTS, controller);
416     }
417
418     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
419     {
420         return cached_ports_set(partial_peout, adaptor, EVENT_OUTPUTS, controller, v);
421     }
422 };
423
424 struct gr_i
425 {
426
427     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& /*controller*/)
428     {
429         return adaptor.getGrIContent();
430     }
431
432     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& /*controller*/)
433     {
434         adaptor.setGrIContent(v);
435         return true;
436     }
437 };
438
439 struct id
440 {
441
442     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
443     {
444         ScicosID adaptee = adaptor.getAdaptee()->id();
445
446         std::string id;
447         controller.getObjectProperty(adaptee, BLOCK, DESCRIPTION, id);
448
449         types::String* o = new types::String(1, 1);
450         o->set(0, id.data());
451
452         return o;
453     }
454
455     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
456     {
457         if (v->getType() != types::InternalType::ScilabString)
458         {
459             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: string expected.\n"), "graphics", "id");
460             return false;
461         }
462
463         types::String* current = v->getAs<types::String>();
464         if (!current->isScalar())
465         {
466             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s.%s: %d-by-%d expected.\n"), "graphics", "id", 1, 1);
467             return false;
468         }
469
470         ScicosID adaptee = adaptor.getAdaptee()->id();
471
472         char* c_str = wide_string_to_UTF8(current->get(0));
473         std::string id(c_str);
474         FREE(c_str);
475
476         controller.setObjectProperty(adaptee, BLOCK, DESCRIPTION, id);
477         return true;
478     }
479 };
480
481 struct in_implicit
482 {
483
484     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
485     {
486         return get_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, INPUTS, controller);
487     }
488
489     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
490     {
491         return set_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, INPUTS, controller, v);
492     }
493 };
494
495 struct out_implicit
496 {
497
498     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
499     {
500         return get_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, OUTPUTS, controller);
501     }
502
503     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
504     {
505         return set_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, OUTPUTS, controller, v);
506     }
507 };
508
509 struct in_style
510 {
511
512     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
513     {
514         return get_ports_property<GraphicsAdapter, STYLE>(adaptor, INPUTS, controller);
515     }
516
517     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
518     {
519         return set_ports_property<GraphicsAdapter, STYLE>(adaptor, INPUTS, controller, v);
520     }
521 };
522
523 struct out_style
524 {
525
526     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
527     {
528         return get_ports_property<GraphicsAdapter, STYLE>(adaptor, OUTPUTS, controller);
529     }
530
531     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
532     {
533         return set_ports_property<GraphicsAdapter, STYLE>(adaptor, OUTPUTS, controller, v);
534     }
535 };
536
537 struct in_label
538 {
539
540     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
541     {
542         return get_ports_property<GraphicsAdapter, LABEL>(adaptor, INPUTS, controller);
543     }
544
545     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
546     {
547         return set_ports_property<GraphicsAdapter, LABEL>(adaptor, INPUTS, controller, v);
548     }
549 };
550
551 struct out_label
552 {
553
554     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
555     {
556         return get_ports_property<GraphicsAdapter, LABEL>(adaptor, OUTPUTS, controller);
557     }
558
559     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
560     {
561         return set_ports_property<GraphicsAdapter, LABEL>(adaptor, OUTPUTS, controller, v);
562     }
563 };
564
565 struct style
566 {
567
568     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
569     {
570         model::Block* adaptee = adaptor.getAdaptee();
571
572         std::string style;
573         controller.getObjectProperty(adaptee, STYLE, style);
574
575         return new types::String(style.c_str());
576     }
577
578     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
579     {
580         model::Block* adaptee = adaptor.getAdaptee();
581         if (v->getType() == types::InternalType::ScilabString)
582         {
583             types::String* current = v->getAs<types::String>();
584             if (!current->isScalar())
585             {
586                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s.%s: %d-by-%d expected.\n"), "graphics", "style", 1, 1);
587                 return false;
588             }
589
590             char* c_str = wide_string_to_UTF8(current->get(0));
591             std::string style(c_str);
592             FREE(c_str);
593
594             controller.setObjectProperty(adaptee, STYLE, style);
595             return true;
596         }
597         else if (v->getType() == types::InternalType::ScilabDouble)
598         {
599             types::Double* current = v->getAs<types::Double>();
600             if (current->getSize() != 0)
601             {
602                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: string expected.\n"), "graphics", "style");
603                 return false;
604             }
605
606             std::string style;
607             controller.setObjectProperty(adaptee, STYLE, style);
608             return true;
609         }
610
611         get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: string expected.\n"), "graphics", "style");
612         return false;
613     }
614 };
615
616 } /* namespace */
617
618 template<> property<GraphicsAdapter>::props_t property<GraphicsAdapter>::fields = property<GraphicsAdapter>::props_t();
619 static void initialize_fields()
620 {
621     if (property<GraphicsAdapter>::properties_have_not_been_set())
622     {
623         property<GraphicsAdapter>::reserve_properties(16);
624         property<GraphicsAdapter>::add_property(L"orig", &orig::get, &orig::set);
625         property<GraphicsAdapter>::add_property(L"sz", &sz::get, &sz::set);
626         property<GraphicsAdapter>::add_property(L"exprs", &exprs::get, &exprs::set);
627         property<GraphicsAdapter>::add_property(L"pin", &pin::get, &pin::set);
628         property<GraphicsAdapter>::add_property(L"pout", &pout::get, &pout::set);
629         property<GraphicsAdapter>::add_property(L"pein", &pein::get, &pein::set);
630         property<GraphicsAdapter>::add_property(L"peout", &peout::get, &peout::set);
631         property<GraphicsAdapter>::add_property(L"gr_i", &gr_i::get, &gr_i::set);
632         property<GraphicsAdapter>::add_property(L"id", &id::get, &id::set);
633         property<GraphicsAdapter>::add_property(L"in_implicit", &in_implicit::get, &in_implicit::set);
634         property<GraphicsAdapter>::add_property(L"out_implicit", &out_implicit::get, &out_implicit::set);
635         property<GraphicsAdapter>::add_property(L"in_style", &in_style::get, &in_style::set);
636         property<GraphicsAdapter>::add_property(L"out_style", &out_style::get, &out_style::set);
637         property<GraphicsAdapter>::add_property(L"in_label", &in_label::get, &in_label::set);
638         property<GraphicsAdapter>::add_property(L"out_label", &out_label::get, &out_label::set);
639         property<GraphicsAdapter>::add_property(L"style", &style::get, &style::set);
640         property<GraphicsAdapter>::shrink_to_fit();
641     }
642 }
643
644 GraphicsAdapter::GraphicsAdapter() :
645     BaseAdapter<GraphicsAdapter, org_scilab_modules_scicos::model::Block>(),
646     gr_i_content(reference_value(types::Double::Empty()))
647 {
648     initialize_fields();
649 }
650
651 GraphicsAdapter::GraphicsAdapter(const Controller& c, model::Block* adaptee) :
652     BaseAdapter<GraphicsAdapter, org_scilab_modules_scicos::model::Block>(c, adaptee),
653     gr_i_content(reference_value(types::Double::Empty()))
654 {
655     initialize_fields();
656
657     Controller controller;
658     cached_ports_init(partial_pin, adaptee, INPUTS, controller);
659     cached_ports_init(partial_pout, adaptee, OUTPUTS, controller);
660     cached_ports_init(partial_pein, adaptee, EVENT_INPUTS, controller);
661     cached_ports_init(partial_peout, adaptee, EVENT_OUTPUTS, controller);
662 }
663
664 GraphicsAdapter::~GraphicsAdapter()
665 {
666     gr_i_content->DecreaseRef();
667     gr_i_content->killMe();
668
669     if (getAdaptee() != nullptr && getAdaptee()->refCount() == 0)
670     {
671         partial_pin.erase(getAdaptee()->id());
672         partial_pout.erase(getAdaptee()->id());
673         partial_pein.erase(getAdaptee()->id());
674         partial_peout.erase(getAdaptee()->id());
675     }
676 }
677
678 std::wstring GraphicsAdapter::getTypeStr() const
679 {
680     return getSharedTypeStr();
681 }
682
683 std::wstring GraphicsAdapter::getShortTypeStr() const
684 {
685     return getSharedTypeStr();
686 }
687
688 types::InternalType* GraphicsAdapter::getGrIContent() const
689 {
690     return gr_i_content;
691 }
692
693 void GraphicsAdapter::setGrIContent(types::InternalType* v)
694 {
695     types::InternalType* temp = gr_i_content;
696
697     v->IncreaseRef();
698     gr_i_content = v;
699
700     temp->DecreaseRef();
701     temp->killMe();
702 }
703
704 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)
705 {
706     auto it = cache.find(adaptee->id());
707     if (it == cache.end())
708     {
709         // unable to relink as there is no information to do so
710         return;
711     }
712     std::vector<int>& cached_information = it->second;
713
714     std::vector<ScicosID> ports;
715     controller.getObjectProperty(adaptee, p, ports);
716
717     if (cached_information.size() != ports.size())
718     {
719         // defensive programming: unable to relink as something goes wrong on the adapters
720         return;
721     }
722
723     bool isConnected = true;
724     for (size_t i = 0; i < cached_information.size(); ++i)
725     {
726         ScicosID connectedSignal;
727         controller.getObjectProperty(ports[i], PORT, CONNECTED_SIGNALS, connectedSignal);
728
729         if (connectedSignal != ScicosID())
730         {
731             cached_information[i] = (int)std::distance(children.begin(), std::find(children.begin(), children.end(), connectedSignal));
732         }
733         else
734         {
735             isConnected = false;
736         }
737     }
738
739     if (isConnected)
740     {
741         cache.erase(it);
742     }
743 }
744
745 void GraphicsAdapter::relink(Controller& controller, model::Block* adaptee, const std::vector<ScicosID>& children)
746 {
747     relink_cached(controller, adaptee, children, partial_pin, INPUTS);
748     relink_cached(controller, adaptee, children, partial_pout, OUTPUTS);
749     relink_cached(controller, adaptee, children, partial_pein, EVENT_INPUTS);
750     relink_cached(controller, adaptee, children, partial_peout, EVENT_OUTPUTS);
751 }
752
753 void copyOnClone(model::BaseObject* original, model::BaseObject* cloned, std::map<ScicosID, std::vector<int> >& cache)
754 {
755
756     auto it = cache.find(original->id());
757     if (it != cache.end())
758         cache.insert({cloned->id(), it->second});
759 }
760
761 void GraphicsAdapter::add_partial_links_information(Controller& controller, model::BaseObject* original, model::BaseObject* cloned)
762 {
763     // precondition
764     if (cloned == nullptr)
765     {
766         return;
767     }
768
769     if (original->kind() == BLOCK)
770     {
771         // add the from / to information if applicable
772         copyOnClone(original, cloned, partial_pin);
773         copyOnClone(original, cloned, partial_pout);
774         copyOnClone(original, cloned, partial_pein);
775         copyOnClone(original, cloned, partial_peout);
776     }
777
778     switch (original->kind())
779     {
780         // handle recursion
781         case DIAGRAM:
782         case BLOCK:
783         {
784             std::vector<ScicosID> originalChildren;
785             controller.getObjectProperty(original, CHILDREN, originalChildren);
786             std::vector<ScicosID> clonedChildren;
787             controller.getObjectProperty(cloned, CHILDREN, clonedChildren);
788
789             for (size_t i = 0; i < originalChildren.size(); ++i)
790             {
791                 // a clone preserve position thus null ID, ignore them on
792                 // this loop
793                 if (originalChildren[i] != ScicosID())
794                 {
795                     add_partial_links_information(controller, controller.getBaseObject(originalChildren[i]), controller.getBaseObject(clonedChildren[i]));
796                 }
797             }
798             break;
799         }
800
801         default:
802             break;
803     }
804 }
805
806 void GraphicsAdapter::remove_partial_links_information(model::Block* o)
807 {
808     partial_pin.erase(o->id());
809     partial_pout.erase(o->id());
810     partial_pein.erase(o->id());
811     partial_peout.erase(o->id());
812 }
813
814 } /* namespace view_scilab */
815 } /* namespace org_scilab_modules_scicos */