Update CHANGES.md before the release
[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  *  Copyright (C) 2017-2018 - ESI Group - 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 #include <cwchar>
18
19 #include <algorithm>
20 #include <functional>
21 #include <iomanip>
22 #include <iostream>
23 #include <string>
24 #include <vector>
25
26 #include "double.hxx"
27 #include "list.hxx"
28 #include "string.hxx"
29 #include "tlist.hxx"
30
31 #include "Controller.hxx"
32 #include "GraphicsAdapter.hxx"
33 #include "controller_helpers.hxx"
34 #include "ports_management.hxx"
35 #include "utilities.hxx"
36
37 #include "var2vec.hxx"
38 #include "vec2var.hxx"
39
40 extern "C" {
41 #include "charEncoding.h"
42 #include "localization.h"
43 #include "sci_malloc.h"
44 }
45
46 namespace org_scilab_modules_scicos
47 {
48 namespace view_scilab
49 {
50 namespace
51 {
52
53 const std::wstring MBLOCK(L"MBLOCK");
54 const std::wstring MPBLOCK(L"MPBLOCK");
55 const std::wstring in(L"in");
56 const std::wstring intype(L"intype");
57 const std::wstring out(L"out");
58 const std::wstring outtype(L"outtype");
59 const std::wstring param(L"param");
60 const std::wstring paramv(L"paramv");
61 const std::wstring pprop(L"pprop");
62 const std::wstring nameF(L"nameF");
63 const std::wstring funtxt(L"funtxt");
64
65 // shared informations for relinking across adapters hierarchy
66 partials_ports_t partial_ports;
67
68 struct orig
69 {
70
71     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
72     {
73         double* data;
74         types::Double* o = new types::Double(1, 2, &data);
75         model::Block* adaptee = adaptor.getAdaptee();
76
77         std::vector<double> geom;
78         controller.getObjectProperty(adaptee, GEOMETRY, geom);
79
80         data[0] = geom[0];
81         data[1] = geom[1];
82
83         return o;
84     }
85
86     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
87     {
88
89         if (v->getType() != types::InternalType::ScilabDouble)
90         {
91             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: Real matrix expected.\n"), "graphics", "orig");
92             return false;
93         }
94
95         types::Double* current = v->getAs<types::Double>();
96         if (current->getSize() != 2)
97         {
98             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s.%s: %d-by-%d expected.\n"), "graphics", "orig", 1, 2);
99             return false;
100         }
101
102         model::Block* adaptee = adaptor.getAdaptee();
103         std::vector<double> geom;
104         controller.getObjectProperty(adaptee, GEOMETRY, geom);
105
106         geom[0] = current->get(0);
107         geom[1] = current->get(1);
108
109         controller.setObjectProperty(adaptee, GEOMETRY, geom);
110         return true;
111     }
112 };
113
114 struct sz
115 {
116
117     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
118     {
119         double* data;
120         types::Double* o = new types::Double(1, 2, &data);
121         model::Block* adaptee = adaptor.getAdaptee();
122
123         std::vector<double> geom;
124         controller.getObjectProperty(adaptee, GEOMETRY, geom);
125
126         data[0] = geom[2];
127         data[1] = geom[3];
128         return o;
129     }
130
131     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
132     {
133         if (v->getType() != types::InternalType::ScilabDouble)
134         {
135             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: Real matrix expected.\n"), "graphics", "sz");
136             return false;
137         }
138
139         types::Double* current = v->getAs<types::Double>();
140         if (current->getSize() != 2)
141         {
142             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s.%s: %d-by-%d expected.\n"), "graphics", "sz", 1, 2);
143             return false;
144         }
145
146         model::Block* adaptee = adaptor.getAdaptee();
147         std::vector<double> geom;
148         controller.getObjectProperty(adaptee, GEOMETRY, geom);
149
150         geom[2] = current->get(0);
151         geom[3] = current->get(1);
152
153         controller.setObjectProperty(adaptee, GEOMETRY, geom);
154         return true;
155     }
156 };
157
158 struct exprs
159 {
160
161     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
162     {
163         model::Block* adaptee = adaptor.getAdaptee();
164
165         std::vector<double> exprs;
166         controller.getObjectProperty(adaptee, EXPRS, exprs);
167
168         types::InternalType* res;
169         if (!vec2var(exprs, res))
170         {
171             // if invalid data, return a valid value
172             return types::Double::Empty();
173         }
174         return res;
175     }
176
177     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
178     {
179         model::Block* adaptee = adaptor.getAdaptee();
180
181         // Corner-case the content is an empty matrix
182         if (v->getType() == types::InternalType::ScilabDouble)
183         {
184             types::Double* current = v->getAs<types::Double>();
185             if (!current->isEmpty())
186             {
187                 return false;
188             }
189         }
190
191         std::vector<double> exprs;
192         if (!var2vec(v, exprs))
193         {
194             return false;
195         }
196         controller.setObjectProperty(adaptee, EXPRS, exprs);
197         return true;
198     }
199 };
200
201 void cached_ports_init(partial_port_t::value_type& cache, model::Block* adaptee, const object_properties_t port_kind, const Controller& controller)
202 {
203     std::vector<ScicosID> ids;
204     controller.getObjectProperty(adaptee, port_kind, ids);
205
206     std::vector<ScicosID> children;
207     ScicosID parentBlock;
208     controller.getObjectProperty(adaptee, PARENT_BLOCK, parentBlock);
209     if (parentBlock == ScicosID())
210     {
211         // Adding to a diagram
212         ScicosID parentDiagram;
213         controller.getObjectProperty(adaptee, PARENT_DIAGRAM, parentDiagram);
214
215         controller.getObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
216     }
217     else
218     {
219         // Adding to a superblock
220         controller.getObjectProperty(parentBlock, BLOCK, CHILDREN, children);
221     }
222
223     cache.resize(ids.size());
224     // foreach ports, resolve it or discard
225     int i = 0;
226     for (std::vector<ScicosID>::iterator it = ids.begin(); it != ids.end(); ++it, ++i)
227     {
228         ScicosID id;
229         controller.getObjectProperty(*it, PORT, CONNECTED_SIGNALS, id);
230
231         if (id == ScicosID())
232         {
233             // Unconnected port, no need to search in 'children'
234             cache[i] = 0;
235         }
236         else
237         {
238             std::vector<ScicosID>::iterator found = std::find(children.begin(), children.end(), id);
239             if (found != children.end())
240             {
241                 cache[i] = static_cast<int>(std::distance(children.begin(), found)) + 1;
242             }
243             else
244             {
245                 // connected link not found ; discard it !
246                 cache[i] = 0;
247             }
248         }
249     }
250 }
251
252 types::InternalType* cached_ports_get(const GraphicsAdapter& adaptor, const object_properties_t port_kind, const Controller& controller)
253 {
254     auto it = partial_ports.find(adaptor.getAdaptee()->id());
255     if (it == partial_ports.end())
256     {
257         return get_ports_property<GraphicsAdapter, CONNECTED_SIGNALS>(adaptor, port_kind, controller);
258     }
259
260     std::vector<int>* pPorts;
261     switch (port_kind)
262     {
263         case INPUTS:
264             pPorts = &it->second.pin;
265             break;
266         case OUTPUTS:
267             pPorts = &it->second.pout;
268             break;
269         case EVENT_INPUTS:
270             pPorts = &it->second.pein;
271             break;
272         case EVENT_OUTPUTS:
273             pPorts = &it->second.peout;
274             break;
275         default:
276             return nullptr;
277     }
278     std::vector<int> const& ports = *pPorts;
279
280     double* data;
281     types::Double* ret = new types::Double(static_cast<int>(ports.size()), 1, &data);
282
283     std::transform(ports.begin(), ports.end(), data, [](int p)
284     {
285         return p;
286     });
287
288     return ret;
289 }
290 bool cached_ports_set(GraphicsAdapter& adaptor, const object_properties_t port_kind, Controller& controller, types::InternalType* v)
291 {
292     auto it = partial_ports.find(adaptor.getAdaptee()->id());
293     if (it == partial_ports.end())
294     {
295         bool status = update_ports_property<GraphicsAdapter, CONNECTED_SIGNALS>(adaptor, port_kind, controller, v);
296         if (status)
297         {
298             return status;
299         }
300         else
301         {
302             // allocate partial information and continue
303             it = partial_ports.insert({adaptor.getAdaptee()->id(), {}}).first;
304         }
305     }
306
307     if (v->getType() != types::InternalType::ScilabDouble)
308     {
309         return false;
310     }
311     types::Double* value = v->getAs<types::Double>();
312     std::vector<int>* pPorts;
313     switch (port_kind)
314     {
315         case INPUTS:
316             pPorts = &it->second.pin;
317             break;
318         case OUTPUTS:
319             pPorts = &it->second.pout;
320             break;
321         case EVENT_INPUTS:
322             pPorts = &it->second.pein;
323             break;
324         case EVENT_OUTPUTS:
325             pPorts = &it->second.peout;
326             break;
327         default:
328             return false;
329     }
330     std::vector<int>& ports = *pPorts;
331
332     // store the updated value locally
333     {
334         ports.resize(value->getSize());
335         for (int i = 0; i < value->getSize(); ++i)
336         {
337             ports[i] = static_cast<int>(value->get(i));
338         }
339     }
340
341     // enforce the same number of port on the Model
342     {
343         std::vector<ScicosID> objects;
344         controller.getObjectProperty(adaptor.getAdaptee(), port_kind, objects);
345
346         if (ports.size() < objects.size())
347         {
348             // remove existing ports
349             for (size_t i = ports.size(); i < objects.size(); ++i)
350             {
351                 ScicosID p = objects[i];
352
353                 ScicosID signal;
354                 controller.getObjectProperty(p, PORT, CONNECTED_SIGNALS, signal);
355                 if (signal != ScicosID())
356                 {
357                     model::Link* link = controller.getBaseObject<model::Link>(signal);
358                     ScicosID opposite;
359                     controller.getObjectProperty(link, DESTINATION_PORT, opposite);
360                     if (opposite == p)
361                     {
362                         controller.setObjectProperty(link, DESTINATION_PORT, ScicosID());
363                     }
364                     controller.getObjectProperty(link, SOURCE_PORT, opposite);
365                     if (opposite == p)
366                     {
367                         controller.setObjectProperty(link, SOURCE_PORT, ScicosID());
368                     }
369                 }
370                 controller.deleteObject(p);
371             }
372             objects.resize(ports.size());
373         }
374         else
375         {
376             // add missing ports
377             for (size_t i = objects.size(); i < ports.size(); ++i)
378             {
379                 model::Port* p = controller.createBaseObject<model::Port>(PORT);
380
381                 controller.setObjectProperty(p, SOURCE_BLOCK, adaptor.getAdaptee()->id());
382                 controller.setObjectProperty(p, PORT_KIND, port_from_property(port_kind));
383
384                 objects.push_back(p->id());
385             }
386         }
387         controller.setObjectProperty(adaptor.getAdaptee(), port_kind, objects);
388     }
389     return true;
390 }
391
392 struct pin
393 {
394
395     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
396     {
397         return cached_ports_get(adaptor, INPUTS, controller);
398     }
399
400     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
401     {
402         return cached_ports_set(adaptor, INPUTS, controller, v);
403     }
404 };
405
406 struct pout
407 {
408
409     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
410     {
411         return cached_ports_get(adaptor, OUTPUTS, controller);
412     }
413
414     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
415     {
416         return cached_ports_set(adaptor, OUTPUTS, controller, v);
417     }
418 };
419
420 struct pein
421 {
422
423     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
424     {
425         return cached_ports_get(adaptor, EVENT_INPUTS, controller);
426     }
427
428     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
429     {
430         return cached_ports_set(adaptor, EVENT_INPUTS, controller, v);
431     }
432 };
433
434 struct peout
435 {
436
437     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
438     {
439         return cached_ports_get(adaptor, EVENT_OUTPUTS, controller);
440     }
441
442     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
443     {
444         return cached_ports_set(adaptor, EVENT_OUTPUTS, controller, v);
445     }
446 };
447
448 struct gr_i
449 {
450
451     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& /*controller*/)
452     {
453         return adaptor.getGrIContent();
454     }
455
456     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& /*controller*/)
457     {
458         adaptor.setGrIContent(v);
459         return true;
460     }
461 };
462
463 struct id
464 {
465
466     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
467     {
468         model::Block* adaptee = adaptor.getAdaptee();
469
470         ScicosID label;
471         std::string description;
472
473         controller.getObjectProperty(adaptee, LABEL, label);
474         if (label != ScicosID())
475         {
476             controller.getObjectProperty(label, ANNOTATION, DESCRIPTION, description);
477         }
478         else
479         {
480             controller.getObjectProperty(adaptee, DESCRIPTION, description);
481         }
482
483         types::String* o = new types::String(1, 1);
484         o->set(0, description.data());
485         return o;
486     }
487
488     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
489     {
490         if (v->getType() != types::InternalType::ScilabString)
491         {
492             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: string expected.\n"), "graphics", "id");
493             return false;
494         }
495
496         types::String* current = v->getAs<types::String>();
497         if (!current->isScalar())
498         {
499             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s.%s: %d-by-%d expected.\n"), "graphics", "id", 1, 1);
500             return false;
501         }
502
503         char* c_str = wide_string_to_UTF8(current->get(0));
504         std::string description(c_str);
505         FREE(c_str);
506
507         model::Block* adaptee = adaptor.getAdaptee();
508
509         ScicosID label;
510         controller.getObjectProperty(adaptee, LABEL, label);
511         if (label != ScicosID())
512         {
513             controller.setObjectProperty(label, ANNOTATION, DESCRIPTION, description);
514         }
515         else
516         {
517             controller.setObjectProperty(adaptee, DESCRIPTION, description);
518         }
519         return true;
520     }
521 };
522
523 struct in_implicit
524 {
525
526     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
527     {
528         return get_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, INPUTS, controller);
529     }
530
531     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
532     {
533         return set_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, INPUTS, controller, v);
534     }
535 };
536
537 struct out_implicit
538 {
539
540     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
541     {
542         return get_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, OUTPUTS, controller);
543     }
544
545     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
546     {
547         return set_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, OUTPUTS, controller, v);
548     }
549 };
550
551 struct in_style
552 {
553
554     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
555     {
556         return get_ports_property<GraphicsAdapter, STYLE>(adaptor, INPUTS, controller);
557     }
558
559     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
560     {
561         return set_ports_property<GraphicsAdapter, STYLE>(adaptor, INPUTS, controller, v);
562     }
563 };
564
565 struct out_style
566 {
567
568     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
569     {
570         return get_ports_property<GraphicsAdapter, STYLE>(adaptor, OUTPUTS, controller);
571     }
572
573     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
574     {
575         return set_ports_property<GraphicsAdapter, STYLE>(adaptor, OUTPUTS, controller, v);
576     }
577 };
578
579 struct in_label
580 {
581
582     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
583     {
584         return get_ports_property<GraphicsAdapter, LABEL>(adaptor, INPUTS, controller);
585     }
586
587     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
588     {
589         return set_ports_property<GraphicsAdapter, LABEL>(adaptor, INPUTS, controller, v);
590     }
591 };
592
593 struct out_label
594 {
595
596     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
597     {
598         return get_ports_property<GraphicsAdapter, LABEL>(adaptor, OUTPUTS, controller);
599     }
600
601     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
602     {
603         return set_ports_property<GraphicsAdapter, LABEL>(adaptor, OUTPUTS, controller, v);
604     }
605 };
606
607 struct style
608 {
609
610     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
611     {
612         model::Block* adaptee = adaptor.getAdaptee();
613
614         std::string style;
615         controller.getObjectProperty(adaptee, STYLE, style);
616
617         return new types::String(style.c_str());
618     }
619
620     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
621     {
622         model::Block* adaptee = adaptor.getAdaptee();
623         if (v->getType() == types::InternalType::ScilabString)
624         {
625             types::String* current = v->getAs<types::String>();
626             if (!current->isScalar())
627             {
628                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s.%s: %d-by-%d expected.\n"), "graphics", "style", 1, 1);
629                 return false;
630             }
631
632             char* c_str = wide_string_to_UTF8(current->get(0));
633             std::string style(c_str);
634             FREE(c_str);
635
636             controller.setObjectProperty(adaptee, STYLE, style);
637             return true;
638         }
639         else if (v->getType() == types::InternalType::ScilabDouble)
640         {
641             types::Double* current = v->getAs<types::Double>();
642             if (current->getSize() != 0)
643             {
644                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: string expected.\n"), "graphics", "style");
645                 return false;
646             }
647
648             std::string style;
649             controller.setObjectProperty(adaptee, STYLE, style);
650             return true;
651         }
652
653         get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: string expected.\n"), "graphics", "style");
654         return false;
655     }
656 };
657
658 } /* namespace */
659
660 #ifndef _MSC_VER
661 template<>
662 #endif
663 property<GraphicsAdapter>::props_t property<GraphicsAdapter>::fields = property<GraphicsAdapter>::props_t();
664 static void initialize_fields()
665 {
666     if (property<GraphicsAdapter>::properties_have_not_been_set())
667     {
668         property<GraphicsAdapter>::reserve_properties(16);
669         property<GraphicsAdapter>::add_property(L"orig", &orig::get, &orig::set);
670         property<GraphicsAdapter>::add_property(L"sz", &sz::get, &sz::set);
671         property<GraphicsAdapter>::add_property(L"exprs", &exprs::get, &exprs::set);
672         property<GraphicsAdapter>::add_property(L"pin", &pin::get, &pin::set);
673         property<GraphicsAdapter>::add_property(L"pout", &pout::get, &pout::set);
674         property<GraphicsAdapter>::add_property(L"pein", &pein::get, &pein::set);
675         property<GraphicsAdapter>::add_property(L"peout", &peout::get, &peout::set);
676         property<GraphicsAdapter>::add_property(L"gr_i", &gr_i::get, &gr_i::set);
677         property<GraphicsAdapter>::add_property(L"id", &id::get, &id::set);
678         property<GraphicsAdapter>::add_property(L"in_implicit", &in_implicit::get, &in_implicit::set);
679         property<GraphicsAdapter>::add_property(L"out_implicit", &out_implicit::get, &out_implicit::set);
680         property<GraphicsAdapter>::add_property(L"in_style", &in_style::get, &in_style::set);
681         property<GraphicsAdapter>::add_property(L"out_style", &out_style::get, &out_style::set);
682         property<GraphicsAdapter>::add_property(L"in_label", &in_label::get, &in_label::set);
683         property<GraphicsAdapter>::add_property(L"out_label", &out_label::get, &out_label::set);
684         property<GraphicsAdapter>::add_property(L"style", &style::get, &style::set);
685         property<GraphicsAdapter>::shrink_to_fit();
686     }
687 }
688
689 GraphicsAdapter::GraphicsAdapter() : BaseAdapter<GraphicsAdapter, org_scilab_modules_scicos::model::Block>(),
690     gr_i_content(reference_value(types::Double::Empty()))
691 {
692     initialize_fields();
693 }
694
695 GraphicsAdapter::GraphicsAdapter(const Controller& c, model::Block* adaptee) : BaseAdapter<GraphicsAdapter, org_scilab_modules_scicos::model::Block>(c, adaptee),
696     gr_i_content(reference_value(types::Double::Empty()))
697 {
698     initialize_fields();
699 }
700
701 GraphicsAdapter::~GraphicsAdapter()
702 {
703     gr_i_content->DecreaseRef();
704     gr_i_content->killMe();
705 }
706
707 std::wstring GraphicsAdapter::getTypeStr() const
708 {
709     return getSharedTypeStr();
710 }
711
712 std::wstring GraphicsAdapter::getShortTypeStr() const
713 {
714     return getSharedTypeStr();
715 }
716
717 types::InternalType* GraphicsAdapter::getGrIContent() const
718 {
719     return gr_i_content;
720 }
721
722 void GraphicsAdapter::setGrIContent(types::InternalType* v)
723 {
724     types::InternalType* temp = gr_i_content;
725
726     v->IncreaseRef();
727     gr_i_content = v;
728
729     temp->DecreaseRef();
730     temp->killMe();
731 }
732
733 static void relink_cached(Controller& controller, model::BaseObject* adaptee, const std::vector<ScicosID>& children, partial_port_t::value_type& cached_information, object_properties_t p, const partials_ports_t::iterator& it)
734 {
735     std::vector<ScicosID> ports;
736     controller.getObjectProperty(adaptee, p, ports);
737
738     if (cached_information.size() != ports.size())
739     {
740         // defensive programming: unable to relink as something goes wrong on the adapters
741         return;
742     }
743
744     for (size_t i = 0; i < cached_information.size(); ++i)
745     {
746         // relink
747         int index = cached_information[i];
748         if (0 < index && index <= children.size())
749         {
750             // common case: relink to a pre-connected block
751             model::BaseObject* opposite = controller.getBaseObject(children[index - 1]);
752             if (opposite == nullptr || opposite->kind() != LINK)
753             {
754                 continue;
755             }
756
757             model::Port* port = controller.getBaseObject<model::Port>(ports[i]);
758             controller.setObjectProperty(port, CONNECTED_SIGNALS, opposite->id());
759         }
760         else if (index == 0)
761         {
762             // corner case: relink to non connected block, smart-connect the links if there is enough ports.
763             // TODO: is it already done ?
764         }
765     }
766 }
767
768 // delete the current shared values if the block is fully connected
769 static void refresh_shared_values(Controller& controller, model::Block* adaptee, partials_ports_t::iterator& it)
770 {
771     /*
772     // early cleanup is commented out to pass tests where :
773     //  1. within a SuperBlock
774     //  2. a link is created
775     //  3. connected using lnk.from (which might erase the partials)
776     //  4. connected using lnk.to
777     //
778     //  The check show that as the partials are deleted on 3 (if commented out) *BUT* the
779     //  block does not appear as connected due to setLinkEnd extra checks for both start
780     //  and end. On 4, where setLinkEnd succeed for both side, we have already lost the
781     //  reference on this block.
782
783     auto are_all_connected = [&controller,
784                               adaptee](object_properties_t portKind)
785     {
786         std::vector<ScicosID> ports;
787         controller.getObjectProperty(adaptee, portKind, ports);
788
789         for (ScicosID p : ports)
790         {
791             ScicosID connectedSignal = ScicosID();
792             controller.getObjectProperty(p, PORT, CONNECTED_SIGNALS, connectedSignal);
793
794             if (connectedSignal == ScicosID())
795             {
796                 return false;
797             }
798         }
799         return true;
800     };
801
802     if (are_all_connected(INPUTS) && are_all_connected(OUTPUTS) && are_all_connected(EVENT_INPUTS) && are_all_connected(EVENT_OUTPUTS))
803     {
804
805         partial_ports.erase(it);
806     }
807     */
808 }
809
810 void GraphicsAdapter::relink(Controller& controller, model::Block* adaptee, const std::vector<ScicosID>& children)
811 {
812     auto it = partial_ports.find(adaptee->id());
813     if (it == partial_ports.end())
814     {
815         // unable to relink as there is no information to do so
816         return;
817     }
818
819
820     relink_cached(controller, adaptee, children, it->second.pin, INPUTS, it);
821     relink_cached(controller, adaptee, children, it->second.pout, OUTPUTS, it);
822     relink_cached(controller, adaptee, children, it->second.pein, EVENT_INPUTS, it);
823     relink_cached(controller, adaptee, children, it->second.peout, EVENT_OUTPUTS, it);
824
825     refresh_shared_values(controller, adaptee, it);
826 }
827
828 static bool incorrectly_connected(Controller& controller, model::Port* port,
829                                   partial_port_t::value_type& graphics_port,
830                                   const std::vector<ScicosID>& children)
831 {
832     ScicosID signal;
833     controller.getObjectProperty(port, CONNECTED_SIGNALS,
834                                  signal);
835     for (int idx : graphics_port)
836     {
837         if (0 > idx || idx >= children.size())
838         {
839             return true;
840         }
841         else if (children[idx] != signal)
842         {
843             return true;
844         }
845     }
846
847     return false;
848 }
849
850 // Remove partial information if not needed anymore
851 static void cleanup(Controller& controller, const std::vector<ScicosID>& children, model::Port* src, model::Port* dst)
852 {
853     // check if the source block is fully connected
854     ScicosID source_block = ScicosID();
855     controller.getObjectProperty(src, SOURCE_BLOCK, source_block);
856
857     auto source_it = partial_ports.find(source_block);
858     if (source_it == partial_ports.end())
859     {
860         return;
861     }
862
863     if (incorrectly_connected(controller, src, source_it->second.pin, children) ||
864             incorrectly_connected(controller, src, source_it->second.pout, children) ||
865             incorrectly_connected(controller, src, source_it->second.pein, children) ||
866             incorrectly_connected(controller, src, source_it->second.peout, children))
867     {
868         return;
869     }
870
871     // check if the destination block is fully connected
872     ScicosID destination_block = ScicosID();
873     controller.getObjectProperty(dst, SOURCE_BLOCK, destination_block);
874
875     auto destination_it = partial_ports.find(destination_block);
876     if (destination_it == partial_ports.end())
877     {
878         return;
879     }
880
881     if (incorrectly_connected(controller, dst, destination_it->second.pin, children) ||
882             incorrectly_connected(controller, dst, destination_it->second.pout, children) ||
883             incorrectly_connected(controller, dst, destination_it->second.pein, children) ||
884             incorrectly_connected(controller, dst, destination_it->second.peout, children))
885     {
886         return;
887     }
888
889
890     // erase the partial information
891     partial_ports.erase(source_it);
892     partial_ports.erase(destination_it);
893 }
894
895 void GraphicsAdapter::reverse_relink(Controller& controller, model::Link* adaptee, int index, const std::vector<ScicosID>& children)
896 {
897     if (adaptee->id() != children[index])
898     {
899         return;
900     }
901
902     ScicosID source = ScicosID();
903     ScicosID destination = ScicosID();
904     controller.getObjectProperty(adaptee, SOURCE_PORT, source);
905     controller.getObjectProperty(adaptee, DESTINATION_PORT, destination);
906
907     model::Port* src = controller.getBaseObject<model::Port>(source);
908     model::Port* dst = controller.getBaseObject<model::Port>(destination);
909
910     ScicosID source_parent = ScicosID();
911     ScicosID destination_parent = ScicosID();
912     controller.getObjectProperty(src, SOURCE_BLOCK, source_parent);
913     controller.getObjectProperty(dst, SOURCE_BLOCK, destination_parent);
914
915     int linkType = 0;
916     controller.getObjectProperty(adaptee, KIND, linkType);
917
918     auto source_it = partial_ports.find(source_parent);
919     if (source_it != partial_ports.end())
920     {
921         if (linkType == model::activation)
922         {
923             std::vector<ScicosID> ports;
924             controller.getObjectProperty(source_parent, BLOCK, EVENT_OUTPUTS, ports);
925             int port_index = (int)std::distance(ports.begin(), std::find(ports.begin(), ports.end(), source));
926             if (port_index < source_it->second.peout.size())
927             {
928                 source_it->second.peout[port_index] = index + 1;
929             }
930         }
931         else // model::regular || model::implicit
932         {
933             std::vector<ScicosID> ports;
934             controller.getObjectProperty(source_parent, BLOCK, OUTPUTS, ports);
935             int port_index = (int)std::distance(ports.begin(), std::find(ports.begin(), ports.end(), source));
936             if (port_index < source_it->second.pout.size()) // regular indexing
937             {
938                 source_it->second.pout[port_index] = index + 1;
939             }
940             else if (linkType == model::implicit &&
941                      port_index < source_it->second.pin.size()) // second try for implicit reversed link
942             {
943                 source_it->second.pin[port_index] = index + 1;
944             }
945         }
946     }
947
948     auto destination_it = partial_ports.find(destination_parent);
949     if (destination_it != partial_ports.end())
950     {
951         if (linkType == model::activation)
952         {
953             std::vector<ScicosID> ports;
954             controller.getObjectProperty(destination_parent, BLOCK, EVENT_INPUTS, ports);
955             int port_index = (int)std::distance(ports.begin(), std::find(ports.begin(), ports.end(), destination));
956             if (port_index < destination_it->second.pein.size())
957             {
958                 destination_it->second.pein[port_index] = index + 1;
959             }
960         }
961         else // model::regular || model::implicit
962         {
963             std::vector<ScicosID> ports;
964             controller.getObjectProperty(destination_parent, BLOCK, INPUTS, ports);
965             int port_index = (int)std::distance(ports.begin(), std::find(ports.begin(), ports.end(), destination));
966             if (port_index < destination_it->second.pin.size()) // regular indexing
967             {
968                 destination_it->second.pin[port_index] = index + 1;
969             }
970             else if (linkType == model::implicit &&
971                      port_index < destination_it->second.pout.size()) // second try for implicit reversed link
972             {
973                 destination_it->second.pout[port_index] = index + 1;
974             }
975         }
976     }
977
978     if (source_it != partial_ports.end() && destination_it != partial_ports.end())
979     {
980     }
981     cleanup(controller, children, src, dst);
982 }
983
984 inline std::ptrdiff_t indexof(const std::vector<int>& vec, int value)
985 {
986     return std::distance(vec.begin(), std::find(vec.begin(), vec.end(), value));
987 }
988
989 static void resolve_ports(Controller& controller, model::Block* block, const object_properties_t port_kind, std::vector<int>& resolved, const std::vector<ScicosID>& children)
990 {
991     std::vector<ScicosID> ports;
992     controller.getObjectProperty(block, port_kind, ports);
993
994     resolved.resize(ports.size());
995     for (size_t i = 0; i < ports.size(); ++i)
996     {
997         ScicosID link;
998         controller.getObjectProperty(ports[i], PORT, CONNECTED_SIGNALS, link);
999         if (link == ScicosID())
1000         {
1001             resolved[i] = 0;
1002         }
1003         else
1004         {
1005             auto found = std::find(children.begin(), children.end(), link);
1006             resolved[i] = std::distance(children.begin(), found) + 1;
1007         }
1008     }
1009 }
1010
1011 void GraphicsAdapter::add_partial_links_information(Controller& controller, ScicosID original, ScicosID cloned)
1012 {
1013     auto it = partial_ports.find(original);
1014     if (it != partial_ports.end())
1015     {
1016         partial_ports.insert(std::make_pair(cloned, it->second));
1017     }
1018     else
1019     {
1020         model::Block* block = controller.getBaseObject<model::Block>(original);
1021
1022         std::vector<ScicosID> children;
1023         ScicosID parentBlock;
1024         controller.getObjectProperty(block, PARENT_BLOCK, parentBlock);
1025         if (parentBlock == ScicosID())
1026         {
1027             // Adding to a diagram
1028             ScicosID parentDiagram;
1029             controller.getObjectProperty(block, PARENT_DIAGRAM, parentDiagram);
1030
1031             controller.getObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
1032         }
1033         else
1034         {
1035             // Adding to a superblock
1036             controller.getObjectProperty(parentBlock, BLOCK, CHILDREN, children);
1037         }
1038
1039         partial_port_t removed_interface;
1040         resolve_ports(controller, block, INPUTS, removed_interface.pin, children);
1041         resolve_ports(controller, block, OUTPUTS, removed_interface.pout, children);
1042         resolve_ports(controller, block, EVENT_INPUTS, removed_interface.pein, children);
1043         resolve_ports(controller, block, EVENT_OUTPUTS, removed_interface.peout, children);
1044
1045         partial_ports.insert(std::make_pair(cloned, removed_interface));
1046     }
1047 }
1048
1049 static bool connected(const partial_port_t& p)
1050 {
1051     for (int idx : p.pin)
1052     {
1053         if (idx == 0)
1054         {
1055             return false;
1056         }
1057     }
1058     for (int idx : p.pout)
1059     {
1060         if (idx == 0)
1061         {
1062             return false;
1063         }
1064     }
1065     for (int idx : p.pein)
1066     {
1067         if (idx == 0)
1068         {
1069             return false;
1070         }
1071     }
1072     for (int idx : p.peout)
1073     {
1074         if (idx == 0)
1075         {
1076             return false;
1077         }
1078     }
1079
1080     return true;
1081 }
1082
1083 static bool compatible(const partial_port_t& added, const partial_port_t& removed)
1084 {
1085     return added.pin.size() == removed.pin.size() &&
1086            added.pout.size() == removed.pout.size() &&
1087            added.pein.size() == removed.pein.size() &&
1088            added.peout.size() == removed.peout.size();
1089 }
1090
1091 // manage partial information before a model delete
1092 void GraphicsAdapter::store_partial_links_information(Controller& controller, model::BaseObject* added, int index, const std::vector<ScicosID>& children)
1093 {
1094     model::BaseObject* removed = controller.getBaseObject(children[index]);
1095     if (removed == nullptr || removed->kind() != BLOCK)
1096     {
1097         return;
1098     }
1099     if (added == nullptr || added->kind() != BLOCK)
1100     {
1101         return;
1102     }
1103
1104     // use the cached added information by default
1105     auto added_it = partial_ports.find(added->id());
1106     partial_port_t added_interface;
1107     if (added_it == partial_ports.end())
1108     {
1109         return;
1110     }
1111     added_interface = added_it->second;
1112
1113     // resolve the removed information
1114     auto removed_it = partial_ports.find(removed->id());
1115     partial_port_t removed_interface;
1116     if (removed_it == partial_ports.end())
1117     {
1118         model::Block* block = static_cast<model::Block*>(removed);
1119
1120         resolve_ports(controller, block, INPUTS, removed_interface.pin, children);
1121         resolve_ports(controller, block, OUTPUTS, removed_interface.pout, children);
1122         resolve_ports(controller, block, EVENT_INPUTS, removed_interface.pein, children);
1123         resolve_ports(controller, block, EVENT_OUTPUTS, removed_interface.peout, children);
1124     }
1125     else
1126     {
1127         removed_interface = removed_it->second;
1128     }
1129
1130     // relink automatically
1131     if (!connected(added_interface) && compatible(added_interface, removed_interface))
1132     {
1133         added_it->second = removed_interface;
1134     }
1135 }
1136
1137 // delete all information related to the block
1138 void GraphicsAdapter::remove_partial_links_information(ScicosID uid)
1139 {
1140     partial_ports.erase(uid);
1141 }
1142
1143 } /* namespace view_scilab */
1144 } /* namespace org_scilab_modules_scicos */