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