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