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