eb3aa8f235629ec4f6d3ad33d46f7eccd74a64ee
[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 #ifdef _MSC_VER
284     std::transform(ports.begin(), ports.end(), stdext::checked_array_iterator<double*>(data, ports.size()), [](int p)
285     {
286         return p;
287     });
288 #else
289     std::transform(ports.begin(), ports.end(), data, [](int p)
290     {
291         return p;
292     });
293 #endif
294
295     return ret;
296 }
297 bool cached_ports_set(GraphicsAdapter& adaptor, const object_properties_t port_kind, Controller& controller, types::InternalType* v)
298 {
299     auto it = partial_ports.find(adaptor.getAdaptee()->id());
300     if (it == partial_ports.end())
301     {
302         return update_ports_property<GraphicsAdapter, CONNECTED_SIGNALS>(adaptor, port_kind, controller, v);
303     }
304
305     if (v->getType() != types::InternalType::ScilabDouble)
306     {
307         return false;
308     }
309     types::Double* value = v->getAs<types::Double>();
310     std::vector<int>* pPorts;
311     switch (port_kind)
312     {
313         case INPUTS:
314             pPorts = &it->second.pin;
315             break;
316         case OUTPUTS:
317             pPorts = &it->second.pout;
318             break;
319         case EVENT_INPUTS:
320             pPorts = &it->second.pein;
321             break;
322         case EVENT_OUTPUTS:
323             pPorts = &it->second.peout;
324             break;
325         default:
326             return false;
327     }
328     std::vector<int>& ports = *pPorts;
329
330     // store the updated value locally
331     {
332         ports.resize(value->getSize());
333         for (int i = 0; i < value->getSize(); ++i)
334         {
335             ports[i] = static_cast<int>(value->get(i));
336         }
337     }
338
339     // enforce the same number of port on the Model
340     {
341         std::vector<ScicosID> objects;
342         controller.getObjectProperty(adaptor.getAdaptee(), port_kind, objects);
343
344         if (ports.size() < objects.size())
345         {
346             // remove existing ports
347             for (size_t i = ports.size(); i < objects.size(); ++i)
348             {
349                 ScicosID p = objects[i];
350
351                 ScicosID signal;
352                 controller.getObjectProperty(p, PORT, CONNECTED_SIGNALS, signal);
353                 if (signal != ScicosID())
354                 {
355                     model::Link* link = controller.getBaseObject<model::Link>(signal);
356                     ScicosID opposite;
357                     controller.getObjectProperty(link, DESTINATION_PORT, opposite);
358                     if (opposite == p)
359                     {
360                         controller.setObjectProperty(link, DESTINATION_PORT, ScicosID());
361                     }
362                     controller.getObjectProperty(link, SOURCE_PORT, opposite);
363                     if (opposite == p)
364                     {
365                         controller.setObjectProperty(link, SOURCE_PORT, ScicosID());
366                     }
367                 }
368                 controller.deleteObject(p);
369             }
370             objects.resize(ports.size());
371         }
372         else
373         {
374             // add missing ports
375             for (size_t i = objects.size(); i < ports.size(); ++i)
376             {
377                 model::Port* p = controller.createBaseObject<model::Port>(PORT);
378
379                 controller.setObjectProperty(p, SOURCE_BLOCK, adaptor.getAdaptee()->id());
380                 controller.setObjectProperty(p, PORT_KIND, port_from_property(port_kind));
381
382                 objects.push_back(p->id());
383             }
384         }
385         controller.setObjectProperty(adaptor.getAdaptee(), port_kind, objects);
386     }
387     return true;
388 }
389
390 struct pin
391 {
392
393     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
394     {
395         return cached_ports_get(adaptor, INPUTS, controller);
396     }
397
398     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
399     {
400         return cached_ports_set(adaptor, INPUTS, controller, v);
401     }
402 };
403
404 struct pout
405 {
406
407     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
408     {
409         return cached_ports_get(adaptor, OUTPUTS, controller);
410     }
411
412     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
413     {
414         return cached_ports_set(adaptor, OUTPUTS, controller, v);
415     }
416 };
417
418 struct pein
419 {
420
421     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
422     {
423         return cached_ports_get(adaptor, EVENT_INPUTS, controller);
424     }
425
426     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
427     {
428         return cached_ports_set(adaptor, EVENT_INPUTS, controller, v);
429     }
430 };
431
432 struct peout
433 {
434
435     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
436     {
437         return cached_ports_get(adaptor, EVENT_OUTPUTS, controller);
438     }
439
440     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
441     {
442         return cached_ports_set(adaptor, EVENT_OUTPUTS, controller, v);
443     }
444 };
445
446 struct gr_i
447 {
448
449     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& /*controller*/)
450     {
451         return adaptor.getGrIContent();
452     }
453
454     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& /*controller*/)
455     {
456         adaptor.setGrIContent(v);
457         return true;
458     }
459 };
460
461 struct id
462 {
463
464     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
465     {
466         model::Block* adaptee = adaptor.getAdaptee();
467
468         ScicosID label;
469         std::string description;
470
471         controller.getObjectProperty(adaptee, LABEL, label);
472         if (label != ScicosID())
473         {
474             controller.getObjectProperty(label, ANNOTATION, DESCRIPTION, description);
475         }
476         else
477         {
478             controller.getObjectProperty(adaptee, DESCRIPTION, description);
479         }
480
481         types::String* o = new types::String(1, 1);
482         o->set(0, description.data());
483         return o;
484     }
485
486     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
487     {
488         if (v->getType() != types::InternalType::ScilabString)
489         {
490             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: string expected.\n"), "graphics", "id");
491             return false;
492         }
493
494         types::String* current = v->getAs<types::String>();
495         if (!current->isScalar())
496         {
497             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s.%s: %d-by-%d expected.\n"), "graphics", "id", 1, 1);
498             return false;
499         }
500
501         char* c_str = wide_string_to_UTF8(current->get(0));
502         std::string description(c_str);
503         FREE(c_str);
504
505         model::Block* adaptee = adaptor.getAdaptee();
506
507         ScicosID label;
508         controller.getObjectProperty(adaptee, LABEL, label);
509         if (label != ScicosID())
510         {
511             controller.setObjectProperty(label, ANNOTATION, DESCRIPTION, description);
512         }
513         else
514         {
515             controller.setObjectProperty(adaptee, DESCRIPTION, description);
516         }
517         return true;
518     }
519 };
520
521 struct in_implicit
522 {
523
524     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
525     {
526         return get_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, INPUTS, controller);
527     }
528
529     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
530     {
531         return set_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, INPUTS, controller, v);
532     }
533 };
534
535 struct out_implicit
536 {
537
538     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
539     {
540         return get_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, OUTPUTS, controller);
541     }
542
543     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
544     {
545         return set_ports_property<GraphicsAdapter, IMPLICIT>(adaptor, OUTPUTS, controller, v);
546     }
547 };
548
549 struct in_style
550 {
551
552     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
553     {
554         return get_ports_property<GraphicsAdapter, STYLE>(adaptor, INPUTS, controller);
555     }
556
557     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
558     {
559         return set_ports_property<GraphicsAdapter, STYLE>(adaptor, INPUTS, controller, v);
560     }
561 };
562
563 struct out_style
564 {
565
566     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
567     {
568         return get_ports_property<GraphicsAdapter, STYLE>(adaptor, OUTPUTS, controller);
569     }
570
571     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
572     {
573         return set_ports_property<GraphicsAdapter, STYLE>(adaptor, OUTPUTS, controller, v);
574     }
575 };
576
577 struct in_label
578 {
579
580     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
581     {
582         return get_ports_property<GraphicsAdapter, LABEL>(adaptor, INPUTS, controller);
583     }
584
585     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
586     {
587         return set_ports_property<GraphicsAdapter, LABEL>(adaptor, INPUTS, controller, v);
588     }
589 };
590
591 struct out_label
592 {
593
594     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
595     {
596         return get_ports_property<GraphicsAdapter, LABEL>(adaptor, OUTPUTS, controller);
597     }
598
599     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
600     {
601         return set_ports_property<GraphicsAdapter, LABEL>(adaptor, OUTPUTS, controller, v);
602     }
603 };
604
605 struct style
606 {
607
608     static types::InternalType* get(const GraphicsAdapter& adaptor, const Controller& controller)
609     {
610         model::Block* adaptee = adaptor.getAdaptee();
611
612         std::string style;
613         controller.getObjectProperty(adaptee, STYLE, style);
614
615         return new types::String(style.c_str());
616     }
617
618     static bool set(GraphicsAdapter& adaptor, types::InternalType* v, Controller& controller)
619     {
620         model::Block* adaptee = adaptor.getAdaptee();
621         if (v->getType() == types::InternalType::ScilabString)
622         {
623             types::String* current = v->getAs<types::String>();
624             if (!current->isScalar())
625             {
626                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s.%s: %d-by-%d expected.\n"), "graphics", "style", 1, 1);
627                 return false;
628             }
629
630             char* c_str = wide_string_to_UTF8(current->get(0));
631             std::string style(c_str);
632             FREE(c_str);
633
634             controller.setObjectProperty(adaptee, STYLE, style);
635             return true;
636         }
637         else if (v->getType() == types::InternalType::ScilabDouble)
638         {
639             types::Double* current = v->getAs<types::Double>();
640             if (current->getSize() != 0)
641             {
642                 get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: string expected.\n"), "graphics", "style");
643                 return false;
644             }
645
646             std::string style;
647             controller.setObjectProperty(adaptee, STYLE, style);
648             return true;
649         }
650
651         get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s.%s: string expected.\n"), "graphics", "style");
652         return false;
653     }
654 };
655
656 } /* namespace */
657
658 template<>
659 property<GraphicsAdapter>::props_t property<GraphicsAdapter>::fields = property<GraphicsAdapter>::props_t();
660 static void initialize_fields()
661 {
662     if (property<GraphicsAdapter>::properties_have_not_been_set())
663     {
664         property<GraphicsAdapter>::reserve_properties(16);
665         property<GraphicsAdapter>::add_property(L"orig", &orig::get, &orig::set);
666         property<GraphicsAdapter>::add_property(L"sz", &sz::get, &sz::set);
667         property<GraphicsAdapter>::add_property(L"exprs", &exprs::get, &exprs::set);
668         property<GraphicsAdapter>::add_property(L"pin", &pin::get, &pin::set);
669         property<GraphicsAdapter>::add_property(L"pout", &pout::get, &pout::set);
670         property<GraphicsAdapter>::add_property(L"pein", &pein::get, &pein::set);
671         property<GraphicsAdapter>::add_property(L"peout", &peout::get, &peout::set);
672         property<GraphicsAdapter>::add_property(L"gr_i", &gr_i::get, &gr_i::set);
673         property<GraphicsAdapter>::add_property(L"id", &id::get, &id::set);
674         property<GraphicsAdapter>::add_property(L"in_implicit", &in_implicit::get, &in_implicit::set);
675         property<GraphicsAdapter>::add_property(L"out_implicit", &out_implicit::get, &out_implicit::set);
676         property<GraphicsAdapter>::add_property(L"in_style", &in_style::get, &in_style::set);
677         property<GraphicsAdapter>::add_property(L"out_style", &out_style::get, &out_style::set);
678         property<GraphicsAdapter>::add_property(L"in_label", &in_label::get, &in_label::set);
679         property<GraphicsAdapter>::add_property(L"out_label", &out_label::get, &out_label::set);
680         property<GraphicsAdapter>::add_property(L"style", &style::get, &style::set);
681         property<GraphicsAdapter>::shrink_to_fit();
682     }
683 }
684
685 GraphicsAdapter::GraphicsAdapter() : BaseAdapter<GraphicsAdapter, org_scilab_modules_scicos::model::Block>(),
686     gr_i_content(reference_value(types::Double::Empty()))
687 {
688     initialize_fields();
689 }
690
691 GraphicsAdapter::GraphicsAdapter(const Controller& c, model::Block* adaptee) : BaseAdapter<GraphicsAdapter, org_scilab_modules_scicos::model::Block>(c, adaptee),
692     gr_i_content(reference_value(types::Double::Empty()))
693 {
694     initialize_fields();
695
696     auto it = partial_ports.find(adaptee->id());
697     if (it == partial_ports.end())
698     {
699         Controller controller;
700
701         // if already present, do not allocate it  !
702         partial_port_t partial;
703         cached_ports_init(partial.pin, adaptee, INPUTS, controller);
704         cached_ports_init(partial.pout, adaptee, OUTPUTS, controller);
705         cached_ports_init(partial.pein, adaptee, EVENT_INPUTS, controller);
706         cached_ports_init(partial.peout, adaptee, EVENT_OUTPUTS, controller);
707
708         partial_ports.insert(std::make_pair(adaptee->id(), partial));
709     }
710 }
711
712 GraphicsAdapter::~GraphicsAdapter()
713 {
714     gr_i_content->DecreaseRef();
715     gr_i_content->killMe();
716 }
717
718 std::wstring GraphicsAdapter::getTypeStr() const
719 {
720     return getSharedTypeStr();
721 }
722
723 std::wstring GraphicsAdapter::getShortTypeStr() const
724 {
725     return getSharedTypeStr();
726 }
727
728 types::InternalType* GraphicsAdapter::getGrIContent() const
729 {
730     return gr_i_content;
731 }
732
733 void GraphicsAdapter::setGrIContent(types::InternalType* v)
734 {
735     types::InternalType* temp = gr_i_content;
736
737     v->IncreaseRef();
738     gr_i_content = v;
739
740     temp->DecreaseRef();
741     temp->killMe();
742 }
743
744 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)
745 {
746     std::vector<ScicosID> ports;
747     controller.getObjectProperty(adaptee, p, ports);
748
749     if (cached_information.size() != ports.size())
750     {
751         // defensive programming: unable to relink as something goes wrong on the adapters
752         return;
753     }
754
755     for (size_t i = 0; i < cached_information.size(); ++i)
756     {
757         // relink
758         int index = cached_information[i];
759         if (0 < index && index <= children.size())
760         {
761             // common case: relink to a pre-connected block
762             model::BaseObject* opposite = controller.getBaseObject(children[index - 1]);
763             if (opposite == nullptr || opposite->kind() != LINK)
764             {
765                 continue;
766             }
767
768             model::Port* port = controller.getBaseObject<model::Port>(ports[i]);
769             controller.setObjectProperty(port, CONNECTED_SIGNALS, opposite->id());
770         }
771         else if (index == 0)
772         {
773             // corner case: relink to non connected block, smart-connect the links if there is enough ports.
774             // TODO: is it already done ?
775         }
776     }
777 }
778
779 // delete the current shared values if the block is fully connected
780 static void refresh_shared_values(Controller& controller, model::Block* adaptee, partials_ports_t::iterator& it)
781 {
782     /*
783     // early cleanup is commented out to pass tests where :
784     //  1. within a SuperBlock
785     //  2. a link is created
786     //  3. connected using lnk.from (which might erase the partials)
787     //  4. connected using lnk.to
788     //
789     //  The check show that as the partials are deleted on 3 (if commented out) *BUT* the
790     //  block does not appear as connected due to setLinkEnd extra checks for both start
791     //  and end. On 4, where setLinkEnd succeed for both side, we have already lost the
792     //  reference on this block.
793
794     auto are_all_connected = [&controller,
795                               adaptee](object_properties_t portKind)
796     {
797         std::vector<ScicosID> ports;
798         controller.getObjectProperty(adaptee, portKind, ports);
799
800         for (ScicosID p : ports)
801         {
802             ScicosID connectedSignal = ScicosID();
803             controller.getObjectProperty(p, PORT, CONNECTED_SIGNALS, connectedSignal);
804
805             if (connectedSignal == ScicosID())
806             {
807                 return false;
808             }
809         }
810         return true;
811     };
812
813     if (are_all_connected(INPUTS) && are_all_connected(OUTPUTS) && are_all_connected(EVENT_INPUTS) && are_all_connected(EVENT_OUTPUTS))
814     {
815
816         partial_ports.erase(it);
817     }
818     */
819 }
820
821 void GraphicsAdapter::relink(Controller& controller, model::Block* adaptee, const std::vector<ScicosID>& children)
822 {
823     auto it = partial_ports.find(adaptee->id());
824     if (it == partial_ports.end())
825     {
826         // unable to relink as there is no information to do so
827         return;
828     }
829
830
831     relink_cached(controller, adaptee, children, it->second.pin, INPUTS, it);
832     relink_cached(controller, adaptee, children, it->second.pout, OUTPUTS, it);
833     relink_cached(controller, adaptee, children, it->second.pein, EVENT_INPUTS, it);
834     relink_cached(controller, adaptee, children, it->second.peout, EVENT_OUTPUTS, it);
835
836     refresh_shared_values(controller, adaptee, it);
837 }
838
839 static bool incorrectly_connected(Controller& controller, model::Port* port,
840                                   partial_port_t::value_type& graphics_port,
841                                   const std::vector<ScicosID>& children)
842 {
843     ScicosID signal;
844     controller.getObjectProperty(port, CONNECTED_SIGNALS,
845                                  signal);
846     for (int idx : graphics_port)
847     {
848         if (0 > idx || idx >= children.size())
849         {
850             return true;
851         }
852         else if (children[idx] != signal)
853         {
854             return true;
855         }
856     }
857
858     return false;
859 }
860
861 // Remove partial information if not needed anymore
862 static void cleanup(Controller& controller, const std::vector<ScicosID>& children, model::Port* src, model::Port* dst)
863 {
864     // check if the source block is fully connected
865     ScicosID source_block = ScicosID();
866     controller.getObjectProperty(src, SOURCE_BLOCK, source_block);
867
868     auto source_it = partial_ports.find(source_block);
869     if (source_it == partial_ports.end())
870     {
871         return;
872     }
873
874     if (incorrectly_connected(controller, src, source_it->second.pin, children) ||
875             incorrectly_connected(controller, src, source_it->second.pout, children) ||
876             incorrectly_connected(controller, src, source_it->second.pein, children) ||
877             incorrectly_connected(controller, src, source_it->second.peout, children))
878     {
879         return;
880     }
881
882     // check if the destination block is fully connected
883     ScicosID destination_block = ScicosID();
884     controller.getObjectProperty(dst, SOURCE_BLOCK, destination_block);
885
886     auto destination_it = partial_ports.find(destination_block);
887     if (destination_it == partial_ports.end())
888     {
889         return;
890     }
891
892     if (incorrectly_connected(controller, dst, destination_it->second.pin, children) ||
893             incorrectly_connected(controller, dst, destination_it->second.pout, children) ||
894             incorrectly_connected(controller, dst, destination_it->second.pein, children) ||
895             incorrectly_connected(controller, dst, destination_it->second.peout, children))
896     {
897         return;
898     }
899
900
901     // erase the partial information
902     partial_ports.erase(source_it);
903     partial_ports.erase(destination_it);
904 }
905
906 void GraphicsAdapter::reverse_relink(Controller& controller, model::Link* adaptee, int index, const std::vector<ScicosID>& children)
907 {
908     if (adaptee->id() != children[index])
909     {
910         return;
911     }
912
913     ScicosID source = ScicosID();
914     ScicosID destination = ScicosID();
915     controller.getObjectProperty(adaptee, SOURCE_PORT, source);
916     controller.getObjectProperty(adaptee, DESTINATION_PORT, destination);
917
918     model::Port* src = controller.getBaseObject<model::Port>(source);
919     model::Port* dst = controller.getBaseObject<model::Port>(destination);
920
921     ScicosID source_parent = ScicosID();
922     ScicosID destination_parent = ScicosID();
923     controller.getObjectProperty(src, SOURCE_BLOCK, source_parent);
924     controller.getObjectProperty(dst, SOURCE_BLOCK, destination_parent);
925
926     int linkType = 0;
927     controller.getObjectProperty(adaptee, KIND, linkType);
928
929     auto source_it = partial_ports.find(source_parent);
930     if (source_it != partial_ports.end())
931     {
932         if (linkType == model::activation)
933         {
934             std::vector<ScicosID> ports;
935             controller.getObjectProperty(source_parent, BLOCK, EVENT_OUTPUTS, ports);
936             int port_index = (int)std::distance(ports.begin(), std::find(ports.begin(), ports.end(), source));
937             if (port_index < source_it->second.peout.size())
938             {
939                 source_it->second.peout[port_index] = index + 1;
940             }
941         }
942         else // model::regular || model::implicit
943         {
944             std::vector<ScicosID> ports;
945             controller.getObjectProperty(source_parent, BLOCK, OUTPUTS, ports);
946             int port_index = (int)std::distance(ports.begin(), std::find(ports.begin(), ports.end(), source));
947             if (port_index < source_it->second.pout.size()) // regular indexing
948             {
949                 source_it->second.pout[port_index] = index + 1;
950             }
951             else if (linkType == model::implicit &&
952                      port_index < source_it->second.pin.size()) // second try for implicit reversed link
953             {
954                 source_it->second.pin[port_index] = index + 1;
955             }
956         }
957     }
958
959     auto destination_it = partial_ports.find(destination_parent);
960     if (destination_it != partial_ports.end())
961     {
962         if (linkType == model::activation)
963         {
964             std::vector<ScicosID> ports;
965             controller.getObjectProperty(destination_parent, BLOCK, EVENT_INPUTS, ports);
966             int port_index = (int)std::distance(ports.begin(), std::find(ports.begin(), ports.end(), destination));
967             if (port_index < destination_it->second.pein.size())
968             {
969                 destination_it->second.pein[port_index] = index + 1;
970             }
971         }
972         else // model::regular || model::implicit
973         {
974             std::vector<ScicosID> ports;
975             controller.getObjectProperty(destination_parent, BLOCK, INPUTS, ports);
976             int port_index = (int)std::distance(ports.begin(), std::find(ports.begin(), ports.end(), destination));
977             if (port_index < destination_it->second.pin.size()) // regular indexing
978             {
979                 destination_it->second.pin[port_index] = index + 1;
980             }
981             else if (linkType == model::implicit &&
982                      port_index < destination_it->second.pout.size()) // second try for implicit reversed link
983             {
984                 destination_it->second.pout[port_index] = index + 1;
985             }
986         }
987     }
988
989     if (source_it != partial_ports.end() && destination_it != partial_ports.end())
990     {
991     }
992     cleanup(controller, children, src, dst);
993 }
994
995 inline std::ptrdiff_t indexof(const std::vector<int>& vec, int value)
996 {
997     return std::distance(vec.begin(), std::find(vec.begin(), vec.end(), value));
998 }
999
1000 static void resolve_ports(Controller& controller, model::Block* block, const object_properties_t port_kind, std::vector<int>& resolved, const std::vector<ScicosID>& children)
1001 {
1002     std::vector<ScicosID> ports;
1003     controller.getObjectProperty(block, port_kind, ports);
1004
1005     resolved.resize(ports.size());
1006     for (size_t i = 0; i < ports.size(); ++i)
1007     {
1008         ScicosID link;
1009         controller.getObjectProperty(ports[i], PORT, CONNECTED_SIGNALS, link);
1010         if (link == ScicosID())
1011         {
1012             resolved[i] = 0;
1013         }
1014         else
1015         {
1016             auto found = std::find(children.begin(), children.end(), link);
1017             resolved[i] = std::distance(children.begin(), found) + 1;
1018         }
1019     }
1020 }
1021
1022 void GraphicsAdapter::add_partial_links_information(Controller& controller, ScicosID original, ScicosID cloned)
1023 {
1024     auto it = partial_ports.find(original);
1025     if (it != partial_ports.end())
1026     {
1027         partial_ports.insert(std::make_pair(cloned, it->second));
1028     }
1029     else
1030     {
1031         model::Block* block = controller.getBaseObject<model::Block>(original);
1032
1033         std::vector<ScicosID> children;
1034         ScicosID parentBlock;
1035         controller.getObjectProperty(block, PARENT_BLOCK, parentBlock);
1036         if (parentBlock == ScicosID())
1037         {
1038             // Adding to a diagram
1039             ScicosID parentDiagram;
1040             controller.getObjectProperty(block, PARENT_DIAGRAM, parentDiagram);
1041
1042             controller.getObjectProperty(parentDiagram, DIAGRAM, CHILDREN, children);
1043         }
1044         else
1045         {
1046             // Adding to a superblock
1047             controller.getObjectProperty(parentBlock, BLOCK, CHILDREN, children);
1048         }
1049
1050         partial_port_t removed_interface;
1051         resolve_ports(controller, block, INPUTS, removed_interface.pin, children);
1052         resolve_ports(controller, block, OUTPUTS, removed_interface.pout, children);
1053         resolve_ports(controller, block, EVENT_INPUTS, removed_interface.pein, children);
1054         resolve_ports(controller, block, EVENT_OUTPUTS, removed_interface.peout, children);
1055
1056         partial_ports.insert(std::make_pair(cloned, removed_interface));
1057     }
1058 }
1059
1060 static bool connected(const partial_port_t& p)
1061 {
1062     for (int idx : p.pin)
1063     {
1064         if (idx == 0)
1065         {
1066             return false;
1067         }
1068     }
1069     for (int idx : p.pout)
1070     {
1071         if (idx == 0)
1072         {
1073             return false;
1074         }
1075     }
1076     for (int idx : p.pein)
1077     {
1078         if (idx == 0)
1079         {
1080             return false;
1081         }
1082     }
1083     for (int idx : p.peout)
1084     {
1085         if (idx == 0)
1086         {
1087             return false;
1088         }
1089     }
1090
1091     return true;
1092 }
1093
1094 static bool compatible(const partial_port_t& added, const partial_port_t& removed)
1095 {
1096     return added.pin.size() == removed.pin.size() &&
1097            added.pout.size() == removed.pout.size() &&
1098            added.pein.size() == removed.pein.size() &&
1099            added.peout.size() == removed.peout.size();
1100 }
1101
1102 // manage partial information before a model delete
1103 void GraphicsAdapter::store_partial_links_information(Controller& controller, model::BaseObject* added, int index, const std::vector<ScicosID>& children)
1104 {
1105     model::BaseObject* removed = controller.getBaseObject(children[index]);
1106     if (removed == nullptr || removed->kind() != BLOCK)
1107     {
1108         return;
1109     }
1110     if (added == nullptr || added->kind() != BLOCK)
1111     {
1112         return;
1113     }
1114
1115     // use the cached added information by default
1116     auto added_it = partial_ports.find(added->id());
1117     partial_port_t added_interface;
1118     if (added_it == partial_ports.end())
1119     {
1120         return;
1121     }
1122     added_interface = added_it->second;
1123
1124     // resolve the removed information
1125     auto removed_it = partial_ports.find(removed->id());
1126     partial_port_t removed_interface;
1127     if (removed_it == partial_ports.end())
1128     {
1129         model::Block* block = static_cast<model::Block*>(removed);
1130
1131         resolve_ports(controller, block, INPUTS, removed_interface.pin, children);
1132         resolve_ports(controller, block, OUTPUTS, removed_interface.pout, children);
1133         resolve_ports(controller, block, EVENT_INPUTS, removed_interface.pein, children);
1134         resolve_ports(controller, block, EVENT_OUTPUTS, removed_interface.peout, children);
1135     }
1136     else
1137     {
1138         removed_interface = removed_it->second;
1139     }
1140
1141     // relink automatically
1142     if (!connected(added_interface) && compatible(added_interface, removed_interface))
1143     {
1144         added_it->second = removed_interface;
1145     }
1146 }
1147
1148 // delete all information related to the block
1149 void GraphicsAdapter::remove_partial_links_information(ScicosID uid)
1150 {
1151     partial_ports.erase(uid);
1152 }
1153
1154 } /* namespace view_scilab */
1155 } /* namespace org_scilab_modules_scicos */