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