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