Merge 6.0 into master
[scilab.git] / scilab / modules / scicos / src / cpp / view_scilab / LinkAdapter.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 <algorithm>
18 #include <iterator>
19 #include <string>
20 #include <vector>
21
22 #include "double.hxx"
23 #include "internal.hxx"
24 #include "list.hxx"
25 #include "types.hxx"
26 #include "user.hxx"
27
28 #include "Controller.hxx"
29 #include "LinkAdapter.hxx"
30 #include "adapters_utilities.hxx"
31 #include "controller_helpers.hxx"
32 #include "model/Block.hxx"
33 #include "model/Link.hxx"
34 #include "model/Port.hxx"
35 #include "utilities.hxx"
36
37 extern "C" {
38 #include "charEncoding.h"
39 #include "localization.h"
40 #include "sci_malloc.h"
41 }
42
43 namespace org_scilab_modules_scicos
44 {
45 namespace view_scilab
46 {
47 namespace
48 {
49
50 const std::string split("split");
51 const std::string lsplit("lsplit");
52 const std::string limpsplit("limpsplit");
53
54 // shared information for relinking across adapters hierarchy
55 partials_links_t partial_links;
56
57 struct xx
58 {
59
60     static types::InternalType* get(const LinkAdapter& adaptor, const Controller& controller)
61     {
62         model::Link* adaptee = adaptor.getAdaptee();
63
64         std::vector<double> controlPoints;
65         controller.getObjectProperty(adaptee, CONTROL_POINTS, controlPoints);
66
67         double* data;
68         int size = (int)controlPoints.size() / 2;
69         types::Double* o = new types::Double(size, 1, &data);
70
71         for (int i = 0; i < size; ++i)
72         {
73             data[i] = controlPoints[2 * i];
74         }
75         return o;
76     }
77
78     static bool set(LinkAdapter& adaptor, types::InternalType* v, Controller& controller)
79     {
80         model::Link* adaptee = adaptor.getAdaptee();
81
82         if (v->getType() != types::InternalType::ScilabDouble)
83         {
84             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s: Real matrix object.\n"), "xx");
85             return false;
86         }
87
88         types::Double* current = v->getAs<types::Double>();
89
90         std::vector<double> controlPoints;
91         controller.getObjectProperty(adaptee, CONTROL_POINTS, controlPoints);
92
93         int newXSize = current->getSize();
94         int oldXSize = static_cast<int>(controlPoints.size() / 2);
95         std::vector<double> newControlPoints(controlPoints);
96
97         if (newXSize == oldXSize)
98         {
99             for (int i = 0; i < newXSize; ++i)
100             {
101                 newControlPoints[2 * i] = current->getReal()[i];
102             }
103         }
104         else
105         {
106             newControlPoints.resize(2 * current->getSize(), 0);
107
108             for (int i = 0; i < newXSize; ++i)
109             {
110                 newControlPoints[2 * i] = current->getReal()[i];
111             }
112         }
113
114         controller.setObjectProperty(adaptee, CONTROL_POINTS, newControlPoints);
115         return true;
116     }
117 };
118
119 struct yy
120 {
121
122     static types::InternalType* get(const LinkAdapter& adaptor, const Controller& controller)
123     {
124         model::Link* adaptee = adaptor.getAdaptee();
125
126         std::vector<double> controlPoints;
127         controller.getObjectProperty(adaptee, CONTROL_POINTS, controlPoints);
128
129         double* data;
130         int size = (int)controlPoints.size() / 2;
131         types::Double* o = new types::Double(size, 1, &data);
132
133         for (int i = 0; i < size; ++i)
134         {
135             data[i] = controlPoints[2 * i + 1];
136         }
137         return o;
138     }
139
140     static bool set(LinkAdapter& adaptor, types::InternalType* v, Controller& controller)
141     {
142         model::Link* adaptee = adaptor.getAdaptee();
143
144         if (v->getType() != types::InternalType::ScilabDouble)
145         {
146             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s: Real matrix object.\n"), "yy");
147             return false;
148         }
149
150         types::Double* current = v->getAs<types::Double>();
151
152         std::vector<double> controlPoints;
153         controller.getObjectProperty(adaptee, CONTROL_POINTS, controlPoints);
154
155         int newYSize = current->getSize();
156         int oldYSize = static_cast<int>(controlPoints.size() / 2);
157         std::vector<double> newControlPoints(controlPoints);
158
159         if (newYSize == oldYSize)
160         {
161             for (int i = 0; i < newYSize; ++i)
162             {
163                 newControlPoints[2 * i + 1] = current->getReal()[i];
164             }
165         }
166         else
167         {
168             newControlPoints.resize(2 * current->getSize());
169
170             for (int i = 0; i < newYSize; ++i)
171             {
172                 newControlPoints[2 * i + 1] = current->getReal()[i];
173             }
174         }
175
176         controller.setObjectProperty(adaptee, CONTROL_POINTS, newControlPoints);
177         return true;
178     }
179 };
180
181 struct id
182 {
183
184     static types::InternalType* get(const LinkAdapter& adaptor, const Controller& controller)
185     {
186         model::Link* adaptee = adaptor.getAdaptee();
187
188         std::string id;
189         controller.getObjectProperty(adaptee, DESCRIPTION, id);
190
191         types::String* o = new types::String(id.data());
192         return o;
193     }
194
195     static bool set(LinkAdapter& adaptor, types::InternalType* v, Controller& controller)
196     {
197         if (v->getType() != types::InternalType::ScilabString)
198         {
199             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s: String matrix expected.\n"), "id");
200             return false;
201         }
202
203         types::String* current = v->getAs<types::String>();
204         if (current->getSize() != 1)
205         {
206             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s: %d-by-%d expected.\n"), "id", 1, 1);
207             return false;
208         }
209
210         model::Link* adaptee = adaptor.getAdaptee();
211
212         char* c_str = wide_string_to_UTF8(current->get(0));
213         std::string description(c_str);
214         FREE(c_str);
215
216         controller.setObjectProperty(adaptee, DESCRIPTION, description);
217         return true;
218     }
219 };
220
221 struct thick
222 {
223
224     static types::InternalType* get(const LinkAdapter& adaptor, const Controller& controller)
225     {
226         model::Link* adaptee = adaptor.getAdaptee();
227
228         std::vector<double> thick;
229         controller.getObjectProperty(adaptee, THICK, thick);
230
231         double* data;
232         types::Double* o = new types::Double(1, 2, &data);
233
234         data[0] = thick[0];
235         data[1] = thick[1];
236         return o;
237     }
238
239     static bool set(LinkAdapter& adaptor, types::InternalType* v, Controller& controller)
240     {
241         model::Link* adaptee = adaptor.getAdaptee();
242
243         if (v->getType() != types::InternalType::ScilabDouble)
244         {
245             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s: Real matrix expected.\n"), "thick");
246             return false;
247         }
248
249         types::Double* current = v->getAs<types::Double>();
250         if (current->getSize() != 2)
251         {
252             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong dimension for field %s: %d-by-%d expected.\n"), "thick", 2, 1);
253             return false;
254         }
255
256         std::vector<double> thick(2);
257         thick[0] = current->get(0);
258         thick[1] = current->get(1);
259
260         controller.setObjectProperty(adaptee, THICK, thick);
261         return true;
262     }
263 };
264
265 struct ct
266 {
267
268     static types::InternalType* get(const LinkAdapter& adaptor, const Controller& controller)
269     {
270         model::Link* adaptee = adaptor.getAdaptee();
271
272         int color;
273         int kind;
274         controller.getObjectProperty(adaptee, COLOR, color);
275         controller.getObjectProperty(adaptee, KIND, kind);
276
277         double* data;
278         types::Double* o = new types::Double(1, 2, &data);
279
280         data[0] = color;
281         data[1] = kind;
282         return o;
283     }
284
285     static bool set(LinkAdapter& adaptor, types::InternalType* v, Controller& controller)
286     {
287         model::Link* adaptee = adaptor.getAdaptee();
288
289         if (v->getType() != types::InternalType::ScilabDouble)
290         {
291             return false;
292         }
293
294         types::Double* current = v->getAs<types::Double>();
295         if (current->getSize() != 2)
296         {
297             return false;
298         }
299         if (floor(current->get(0)) != current->get(0) || floor(current->get(1)) != current->get(1))
300         {
301             return false;
302         }
303
304         int color = static_cast<int>(current->get(0));
305         int kind = static_cast<int>(current->get(1));
306
307         controller.setObjectProperty(adaptee, COLOR, color);
308         controller.setObjectProperty(adaptee, KIND, kind);
309         return true;
310     }
311 };
312
313 static link_t getLinkEnd(model::Link* adaptee, const Controller& controller,
314                          const object_properties_t end)
315 {
316     link_t ret{0, 0, Start};
317     if (end == DESTINATION_PORT)
318     {
319         ret.kind = End;
320     }
321
322     ScicosID endID;
323     controller.getObjectProperty(adaptee, end, endID);
324     if (endID != ScicosID())
325     {
326         ScicosID sourceBlock;
327         controller.getObjectProperty(endID, PORT, SOURCE_BLOCK, sourceBlock);
328         model::Block* sourceBlockObject =
329             controller.getBaseObject<model::Block>(sourceBlock);
330
331         // Looking for the block number among the block IDs
332         ScicosID parent;
333         kind_t parentKind = BLOCK;
334         controller.getObjectProperty(adaptee, PARENT_BLOCK, parent);
335         std::vector<ScicosID> children;
336         // Added to a superblock
337         if (parent == ScicosID())
338         {
339             // Added to a diagram
340             controller.getObjectProperty(adaptee, PARENT_DIAGRAM, parent);
341             parentKind = DIAGRAM;
342             if (parent == ScicosID())
343             {
344                 return ret;
345             }
346         }
347         controller.getObjectProperty(parent, parentKind, CHILDREN, children);
348
349         ret.block =
350             static_cast<int>(std::distance(children.begin(),
351                                            std::find(children.begin(),
352                                                    children.end(), sourceBlock)) +
353                              1);
354
355         // To find the port index from its 'endID' ID, search through all the
356         // block's ports lists
357         std::vector<ScicosID> sourceBlockPorts;
358         controller.getObjectProperty(sourceBlockObject, INPUTS, sourceBlockPorts);
359
360         std::vector<ScicosID>::iterator found =
361             std::find(sourceBlockPorts.begin(), sourceBlockPorts.end(), endID);
362         if (found == sourceBlockPorts.end()) // Not found in the data inputs
363         {
364             sourceBlockPorts.clear();
365             controller.getObjectProperty(sourceBlockObject, OUTPUTS,
366                                          sourceBlockPorts);
367             found =
368                 std::find(sourceBlockPorts.begin(), sourceBlockPorts.end(), endID);
369             if (found == sourceBlockPorts.end()) // Not found in the data outputs
370             {
371                 sourceBlockPorts.clear();
372                 controller.getObjectProperty(sourceBlockObject, EVENT_INPUTS,
373                                              sourceBlockPorts);
374                 found =
375                     std::find(sourceBlockPorts.begin(), sourceBlockPorts.end(), endID);
376                 if (found == sourceBlockPorts.end()) // Not found in the event inputs
377                 {
378                     sourceBlockPorts.clear();
379                     controller.getObjectProperty(sourceBlockObject, EVENT_OUTPUTS,
380                                                  sourceBlockPorts);
381                     found = std::find(sourceBlockPorts.begin(), sourceBlockPorts.end(),
382                                       endID);
383                     if (found == sourceBlockPorts.end()) // Not found in the event outputs
384                     {
385                         return ret;
386                     }
387                 }
388             }
389         }
390         ret.port =
391             static_cast<int>(std::distance(sourceBlockPorts.begin(), found) + 1);
392
393         int kind;
394         controller.getObjectProperty(endID, PORT, PORT_KIND, kind);
395         if (kind == PORT_IN || kind == PORT_EIN)
396         {
397             ret.kind = End;
398         }
399         else
400         {
401             ret.kind = Start;
402         }
403     }
404     // Default case, the property was initialized at [].
405     return ret;
406 }
407
408 /*
409  * Connectivity is ensured if 'port' is of the desired type or if either of the concerned blocks is a split block,
410  * because they are connectable to anything
411  */
412 bool checkConnectivity(const int neededType, const ScicosID port, model::Block* blk1, Controller& controller)
413 {
414     int portKind;
415     controller.getObjectProperty(port, PORT, PORT_KIND, portKind);
416
417     if (portKind != neededType)
418     {
419         // Last chance if one of the connecting blocks is just a split block
420         std::string name1;
421         controller.getObjectProperty(blk1, SIM_FUNCTION_NAME, name1);
422         if (name1 != split && name1 != lsplit && name1 != limpsplit)
423         {
424             ScicosID blk2;
425             controller.getObjectProperty(port, PORT, SOURCE_BLOCK, blk2);
426             std::string name2;
427             controller.getObjectProperty(blk2, BLOCK, SIM_FUNCTION_NAME, name2);
428             if (name2 != split && name2 != lsplit && name2 != limpsplit)
429             {
430                 return false;
431             }
432         }
433     }
434     return true;
435 }
436
437 void setLinkEnd(model::Link* linkObject, Controller& controller, const object_properties_t end, const link_t& v, const std::vector<ScicosID>& children)
438 {
439     ScicosID from;
440     controller.getObjectProperty(linkObject, SOURCE_PORT, from);
441     ScicosID to;
442     controller.getObjectProperty(linkObject, DESTINATION_PORT, to);
443     ScicosID concernedPort;
444     ScicosID otherPort;
445     switch (end)
446     {
447         case SOURCE_PORT:
448             concernedPort = from;
449             otherPort = to;
450             break;
451         case DESTINATION_PORT:
452             concernedPort = to;
453             otherPort = from;
454             break;
455         default:
456             return;
457     }
458
459     if (v.block == 0 || v.port == 0)
460     {
461         // We want to set an empty link
462         if (concernedPort == ScicosID())
463         {
464             // In this case, the link was already empty, do a dummy call to display the console status.
465             controller.setObjectProperty(linkObject, end, concernedPort);
466         }
467         else
468         {
469             // Untie the old link on the concerned end and set its port as unconnected
470             controller.setObjectProperty(concernedPort, PORT, CONNECTED_SIGNALS, ScicosID());
471             controller.setObjectProperty(linkObject, end, ScicosID());
472         }
473         return;
474     }
475
476     // Connect the new one
477
478     if (v.kind != Start && v.kind != End)
479     {
480         return;
481     }
482     // kind == 0: trying to set the start of the link (output port)
483     // kind == 1: trying to set the end of the link (input port)
484
485     if (v.block < 0 || v.block > static_cast<int>(children.size()))
486     {
487         return; // Trying to link to a non-existing block
488     }
489     ScicosID blkID = children[v.block - 1];
490
491     if (blkID == ScicosID())
492     {
493         // Deleted Block
494         return;
495     }
496
497     // Check that the ID designates a BLOCK (and not an ANNOTATION)
498     model::Block* blkObject = controller.getBaseObject<model::Block>(blkID);
499     if (blkObject->kind() != BLOCK)
500     {
501         return;
502     }
503
504     // v.port may be decremented locally to square with the port indexes
505     int portIndex = v.port;
506
507     std::vector<ScicosID> sourceBlockPorts;
508     bool newPortIsImplicit = false;
509     enum portKind newPortKind = PORT_UNDEF;
510     int linkType;
511     controller.getObjectProperty(linkObject, KIND, linkType);
512     if (linkType == model::activation)
513     {
514         std::vector<ScicosID> evtin;
515         std::vector<ScicosID> evtout;
516         controller.getObjectProperty(blkObject, EVENT_INPUTS, evtin);
517         controller.getObjectProperty(blkObject, EVENT_OUTPUTS, evtout);
518
519         if (v.kind == Start)
520         {
521             if (otherPort != ScicosID())
522             {
523                 if (!checkConnectivity(PORT_EIN, otherPort, blkObject, controller))
524                 {
525                     return;
526                 }
527             }
528             newPortKind = PORT_EOUT;
529             sourceBlockPorts = evtout;
530         }
531         else
532         {
533             if (otherPort != ScicosID())
534             {
535                 if (!checkConnectivity(PORT_EOUT, otherPort, blkObject, controller))
536                 {
537                     return;
538                 }
539             }
540             newPortKind = PORT_EIN;
541             sourceBlockPorts = evtin;
542         }
543     }
544     else if (linkType == model::regular || linkType == model::implicit)
545     {
546         std::vector<ScicosID> in;
547         std::vector<ScicosID> out;
548         controller.getObjectProperty(blkObject, INPUTS, in);
549         controller.getObjectProperty(blkObject, OUTPUTS, out);
550
551         if (linkType == model::regular)
552         {
553             if (v.kind == Start)
554             {
555                 if (otherPort != ScicosID())
556                 {
557                     if (!checkConnectivity(PORT_IN, otherPort, blkObject, controller))
558                     {
559                         return;
560                     }
561                 }
562                 newPortKind = PORT_OUT;
563                 sourceBlockPorts = out;
564             }
565             else
566             {
567                 if (otherPort != ScicosID())
568                 {
569                     if (!checkConnectivity(PORT_OUT, otherPort, blkObject, controller))
570                     {
571                         return;
572                     }
573                 }
574                 newPortKind = PORT_IN;
575                 sourceBlockPorts = in;
576             }
577
578             // Rule out the implicit ports
579             for (int i = 0; i < static_cast<int>(sourceBlockPorts.size()); ++i)
580             {
581                 bool isImplicit;
582                 controller.getObjectProperty(sourceBlockPorts[i], PORT, IMPLICIT, isImplicit);
583                 if (isImplicit == true)
584                 {
585                     sourceBlockPorts.erase(sourceBlockPorts.begin() + i);
586                     if (portIndex > i + 1)
587                     {
588                         portIndex--; // Keep portIndex consistent with the port indexes
589                     }
590                 }
591             }
592         }
593         else // model::implicit
594         {
595             newPortIsImplicit = true;
596             if (v.kind == Start)
597             {
598                 sourceBlockPorts = out;
599             }
600             else // End
601             {
602                 sourceBlockPorts = in;
603             }
604
605             // Rule out the explicit ports
606             for (size_t i = 0; i < sourceBlockPorts.size(); ++i)
607             {
608                 bool isImplicit;
609                 controller.getObjectProperty(sourceBlockPorts[i], PORT, IMPLICIT, isImplicit);
610                 if (isImplicit == false)
611                 {
612                     sourceBlockPorts.erase(sourceBlockPorts.begin() + i);
613                     if (portIndex > static_cast<int>(i + 1))
614                     {
615                         portIndex--; // Keep portIndex consistent with the port indexes
616                     }
617                 }
618             }
619         }
620     }
621
622
623
624     model::Port* concernedPortObject = nullptr;
625     int nBlockPorts = static_cast<int>(sourceBlockPorts.size());
626     if (nBlockPorts >= portIndex)
627     {
628         concernedPort = sourceBlockPorts[portIndex - 1];
629         concernedPortObject = controller.getBaseObject<model::Port>(concernedPort);
630     }
631     else
632     {
633         // the interface does not match, we should not create anything else but rather alert the user that he is not matching the block interface.
634         return;
635     }
636
637     // Disconnect the old port if it was connected. After that, concernedPort will be reused to designate the new port
638     if (concernedPort != ScicosID())
639     {
640         controller.setObjectProperty(concernedPort, PORT, CONNECTED_SIGNALS, ScicosID());
641     }
642
643     ScicosID oldLink = ScicosID();
644     controller.getObjectProperty(concernedPortObject, CONNECTED_SIGNALS, oldLink);
645     if (oldLink != ScicosID())
646     {
647         // Disconnect the old link if it was indeed connected to the concerned port
648         ScicosID oldPort;
649         controller.getObjectProperty(oldLink, LINK, end, oldPort);
650         if (concernedPort == oldPort)
651         {
652             controller.setObjectProperty(oldLink, LINK, end, ScicosID());
653         }
654     }
655
656     // Connect the new source and destination ports together
657     controller.setObjectProperty(concernedPortObject, CONNECTED_SIGNALS, linkObject->id());
658     controller.setObjectProperty(linkObject, end, concernedPort);
659 }
660
661 // Check if the Link is valid
662 bool is_valid(types::Double* o)
663 {
664     if (o->getSize() == 0)
665     {
666         return true;
667     }
668
669     if (o->getSize() == 2 || o->getSize() == 3)
670     {
671         if (floor(o->get(0)) != o->get(0) || floor(o->get(1)) != o->get(1))
672         {
673             return false; // Block and Port numbers must be integer values
674         }
675         if (o->get(1) < 0)
676         {
677             return false; // Port number must be positive
678         }
679
680         if (o->getSize() == 3)
681         {
682             if (floor(o->get(2)) != o->get(2))
683             {
684                 return false; // Kind must be an integer value
685             }
686             if (o->get(2) < 0)
687             {
688                 return false; // Kind must be positive
689             }
690         }
691
692         return true;
693     }
694
695     return false;
696 }
697
698 struct from
699 {
700
701     static types::InternalType* get(const LinkAdapter& adaptor, const Controller& controller)
702     {
703         link_t from_content;
704         auto it = partial_links.find(adaptor.getAdaptee()->id());
705         if (it == partial_links.end())
706         {
707             // if not found use the connected value
708             from_content = getLinkEnd(adaptor.getAdaptee(), controller, SOURCE_PORT);
709         }
710         else
711         {
712             // if found, use the partial value
713             from_content = it->second.from;
714         }
715
716         double* data;
717         types::Double* o = new types::Double(1, 3, &data);
718
719         data[0] = from_content.block;
720         data[1] = from_content.port;
721         data[2] = from_content.kind;
722         return o;
723     }
724
725     static bool set(LinkAdapter& adaptor, types::InternalType* v, Controller& controller)
726     {
727         if (v->getType() != types::InternalType::ScilabDouble)
728         {
729             return false;
730         }
731
732         types::Double* current = v->getAs<types::Double>();
733
734         if (!is_valid(current))
735         {
736             return false;
737         }
738
739         link_t from_content{0, 0, Start};
740         if (current->getSize() >= 2)
741         {
742             from_content.block = static_cast<int>(current->get(0));
743             from_content.port = static_cast<int>(current->get(1));
744             // By default, 'kind' designates an output (set to 0)
745
746             if (current->getSize() == 3)
747             {
748                 from_content.kind = (current->get(2) == 0.) ? Start : End;
749             }
750         }
751
752         // store the new data on the adapter, the linking will be performed later on the diagram update
753         auto it = partial_links.find(adaptor.getAdaptee()->id());
754         if (it == partial_links.end())
755         {
756             partial_link_t l;
757             l.from = from_content;
758             l.to = getLinkEnd(adaptor.getAdaptee(), controller, DESTINATION_PORT);
759             partial_links.insert({adaptor.getAdaptee()->id(), l});
760         }
761         else
762         {
763             it->second.from = from_content;
764         }
765         return true;
766     }
767 };
768
769 struct to
770 {
771
772     static types::InternalType* get(const LinkAdapter& adaptor, const Controller& controller)
773     {
774         link_t to_content;
775         auto it = partial_links.find(adaptor.getAdaptee()->id());
776
777         if (it == partial_links.end())
778         {
779             // if not found use the connected value
780             to_content = getLinkEnd(adaptor.getAdaptee(), controller, DESTINATION_PORT);
781         }
782         else
783         {
784             // if found, use the partial value
785             to_content = it->second.to;
786         }
787
788         double* data;
789         types::Double* o = new types::Double(1, 3, &data);
790
791         data[0] = to_content.block;
792         data[1] = to_content.port;
793         data[2] = to_content.kind;
794         return o;
795     }
796
797     static bool set(LinkAdapter& adaptor, types::InternalType* v, Controller& controller)
798     {
799         if (v->getType() != types::InternalType::ScilabDouble)
800         {
801             return false;
802         }
803
804         types::Double* current = v->getAs<types::Double>();
805
806         if (current->getSize() != 0 && current->getSize() != 2 && current->getSize() != 3)
807         {
808             return false;
809         }
810
811         if (!is_valid(current))
812         {
813             return false;
814         }
815
816         link_t to_content{0, 0, End};
817         if (current->getSize() >= 2)
818         {
819             to_content.block = static_cast<int>(current->get(0));
820             to_content.port = static_cast<int>(current->get(1));
821             // By default, 'kind' designates an input (set to 1)
822
823             if (current->getSize() == 3)
824             {
825                 to_content.kind = (current->get(2) == 0.) ? Start : End;
826             }
827         }
828
829         // store the new data on the adapter, the linking will be performed later on the diagram update
830         auto it = partial_links.find(adaptor.getAdaptee()->id());
831         if (it == partial_links.end())
832         {
833             partial_link_t l;
834             l.from = getLinkEnd(adaptor.getAdaptee(), controller, SOURCE_PORT);
835             l.to = to_content;
836             partial_links.insert({adaptor.getAdaptee()->id(), l});
837         }
838         else
839         {
840             it->second.to = to_content;
841         }
842         return true;
843     }
844 };
845
846 } /* namespace */
847
848 #ifndef _MSC_VER
849 template<>
850 #endif
851 property<LinkAdapter>::props_t property<LinkAdapter>::fields = property<LinkAdapter>::props_t();
852
853 LinkAdapter::LinkAdapter(const Controller& c, org_scilab_modules_scicos::model::Link* adaptee) : BaseAdapter<LinkAdapter, org_scilab_modules_scicos::model::Link>(c, adaptee)
854 {
855     if (property<LinkAdapter>::properties_have_not_been_set())
856     {
857         property<LinkAdapter>::reserve_properties(7);
858         property<LinkAdapter>::add_property(L"xx", &xx::get, &xx::set);
859         property<LinkAdapter>::add_property(L"yy", &yy::get, &yy::set);
860         property<LinkAdapter>::add_property(L"id", &id::get, &id::set);
861         property<LinkAdapter>::add_property(L"thick", &thick::get, &thick::set);
862         property<LinkAdapter>::add_property(L"ct", &ct::get, &ct::set);
863         property<LinkAdapter>::add_property(L"from", &from::get, &from::set);
864         property<LinkAdapter>::add_property(L"to", &to::get, &to::set);
865         property<LinkAdapter>::shrink_to_fit();
866     }
867 }
868
869 LinkAdapter::LinkAdapter(const LinkAdapter& adapter) : BaseAdapter<LinkAdapter, org_scilab_modules_scicos::model::Link>(adapter)
870 {
871 }
872
873 LinkAdapter::~LinkAdapter()
874 {
875 }
876
877 std::wstring LinkAdapter::getTypeStr() const
878 {
879     return getSharedTypeStr();
880 }
881 std::wstring LinkAdapter::getShortTypeStr() const
882 {
883     return getSharedTypeStr();
884 }
885
886 void refresh_shared_values(Controller& controller, model::Link* adaptee, partials_links_t::iterator& it)
887 {
888     ScicosID from;
889     controller.getObjectProperty(adaptee, SOURCE_PORT, from);
890     ScicosID to;
891     controller.getObjectProperty(adaptee, DESTINATION_PORT, to);
892
893     bool isConnected = from != ScicosID() && to != ScicosID();
894     if (isConnected)
895     {
896         partial_links.erase(it);
897     }
898 }
899
900 void LinkAdapter::relink(Controller& controller, model::Link* adaptee, const std::vector<ScicosID>& children)
901 {
902     auto it = partial_links.find(adaptee->id());
903     if (it == partial_links.end())
904     {
905         // unable to relink as there is no information to do so
906         return;
907     }
908     const partial_link_t& l = it->second;
909
910     setLinkEnd(adaptee, controller, SOURCE_PORT, l.from, children);
911     setLinkEnd(adaptee, controller, DESTINATION_PORT, l.to, children);
912
913     refresh_shared_values(controller, adaptee, it);
914 }
915
916 std::vector<model::Port*> getPorts(Controller& controller, model::Block* adaptee, object_properties_t port_kind)
917 {
918     std::vector<ScicosID> ids;
919     controller.getObjectProperty(adaptee, port_kind, ids);
920
921     std::vector<model::Port*> ports;
922     ports.reserve(ids.size());
923     for (ScicosID id : ids)
924     {
925         ports.push_back(controller.getBaseObject<model::Port>(id));
926     }
927
928     return ports;
929 }
930
931 void LinkAdapter::reverse_relink(Controller& controller, model::Block* adaptee, int index, const std::vector<ScicosID>& children)
932 {
933     if (adaptee->id() != children[index])
934     {
935         return;
936     }
937
938     for (object_properties_t p :
939             {
940                 INPUTS, OUTPUTS, EVENT_INPUTS, EVENT_OUTPUTS
941             })
942     {
943         std::vector<model::Port*> ports = getPorts(controller, adaptee, p);
944
945         for (size_t i = 0; i < ports.size(); i++)
946         {
947             ScicosID signal = ScicosID();
948             controller.getObjectProperty(ports[i], CONNECTED_SIGNALS, signal);
949             model::Link* link = controller.getBaseObject<model::Link>(signal);
950
951             auto opposite = partial_links.find(signal);
952             if (opposite != partial_links.end())
953             {
954                 auto& from = opposite->second.from;
955                 auto& to = opposite->second.to;
956
957                 if (from.block == index + 1 && from.port == i)
958                 {
959                     controller.setObjectProperty(link, SOURCE_PORT, ports[i]->id());
960                     from.kind = Start;
961                 }
962                 else if (to.block == index + 1 && to.port == i)
963                 {
964                     controller.setObjectProperty(link, DESTINATION_PORT, ports[i]->id());
965                     to.kind = End;
966                 }
967
968                 refresh_shared_values(controller, link, opposite);
969             }
970         }
971     }
972 }
973
974 void LinkAdapter::add_partial_links_information(Controller& controller, ScicosID original, ScicosID cloned)
975 {
976     auto it = partial_links.find(original);
977     if (it != partial_links.end())
978     {
979         partial_links.insert({cloned, it->second});
980     }
981     else
982     {
983         model::Link* link = controller.getBaseObject<model::Link>(original);
984
985         partial_link_t l;
986         l.from = getLinkEnd(link, controller, SOURCE_PORT);
987         l.to = getLinkEnd(link, controller, DESTINATION_PORT);
988         partial_links.insert({cloned, l});
989     }
990 }
991
992 void reverse_store(Controller& controller, model::Block* removed, object_properties_t port_kind)
993 {
994     std::vector<model::Port*> ports = getPorts(controller, removed, port_kind);
995     for (model::Port* p : ports)
996     {
997         ScicosID signal = ScicosID();
998         controller.getObjectProperty(p, CONNECTED_SIGNALS, signal);
999         if (signal == ScicosID())
1000         {
1001             continue;
1002         }
1003         model::Link* link = controller.getBaseObject<model::Link>(signal);
1004
1005         auto it = partial_links.find(link->id());
1006         if (it == partial_links.end())
1007         {
1008             partial_link_t l;
1009             l.from = getLinkEnd(link, controller, SOURCE_PORT);
1010             l.to = getLinkEnd(link, controller, DESTINATION_PORT);
1011             partial_links.insert({link->id(), l});
1012         }
1013     }
1014 }
1015
1016 // manage partial information before a model delete
1017 void LinkAdapter::store_partial_links_information(Controller& controller, model::BaseObject* added, int index, const std::vector<ScicosID>& children)
1018 {
1019     model::BaseObject* removed = controller.getBaseObject(children[index]);
1020     if (removed == nullptr || added == nullptr)
1021     {
1022         return;
1023     }
1024
1025     if (removed->kind() == LINK && added->kind() == LINK)
1026     {
1027         model::Link* link = static_cast<model::Link*>(added);
1028
1029         partial_link_t l;
1030         l.from = getLinkEnd(link, controller, SOURCE_PORT);
1031         l.to = getLinkEnd(link, controller, DESTINATION_PORT);
1032         partial_links.insert({link->id(), l});
1033     }
1034     else if (removed->kind() == BLOCK && added->kind() == BLOCK)
1035     {
1036         model::Block* block = static_cast<model::Block*>(removed);
1037
1038         reverse_store(controller, block, INPUTS);
1039         reverse_store(controller, block, OUTPUTS);
1040         reverse_store(controller, block, EVENT_INPUTS);
1041         reverse_store(controller, block, EVENT_OUTPUTS);
1042     }
1043 }
1044
1045 // delete all information related to the block
1046 void LinkAdapter::remove_partial_links_information(ScicosID uid)
1047 {
1048     partial_links.erase(uid);
1049 }
1050
1051 } /* namespace view_scilab */
1052 } /* namespace org_scilab_modules_scicos */