Xcos MVC: fix for implicit links
[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 != 0)
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 == 0)
330         {
331             // Added to a diagram
332             controller.getObjectProperty(adaptee, LINK, PARENT_DIAGRAM, parent);
333             parentKind = DIAGRAM;
334             if (parent == 0)
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 = 0;
435
436     if (v.block == 0 || v.port == 0)
437     {
438         // We want to set an empty link
439         if (concernedPort == 0)
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 != 0)
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 != 0)
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 == 0)
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 != 0)
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 != 0)
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 != 0)
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 != 0)
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             sourceBlockPorts = in;
593             sourceBlockPorts.insert(sourceBlockPorts.end(), out.begin(), out.end());
594
595             // Rule out the explicit ports
596             for (size_t i = 0; i < sourceBlockPorts.size(); ++i)
597             {
598                 bool isImplicit;
599                 controller.getObjectProperty(sourceBlockPorts[i], PORT, IMPLICIT, isImplicit);
600                 if (isImplicit == false)
601                 {
602                     sourceBlockPorts.erase(sourceBlockPorts.begin() + i);
603                     if (portIndex > static_cast<int>(i + 1))
604                     {
605                         portIndex--; // Keep portIndex consistent with the port indexes
606                     }
607                 }
608             }
609         }
610     }
611
612     // Disconnect the old port if it was connected. After that, concernedPort will be reused to designate the new port
613     if (concernedPort != 0)
614     {
615         controller.setObjectProperty(concernedPort, PORT, CONNECTED_SIGNALS, unconnected);
616     }
617
618     int nBlockPorts = static_cast<int>(sourceBlockPorts.size());
619     if (nBlockPorts >= portIndex)
620     {
621         concernedPort = sourceBlockPorts[portIndex - 1];
622     }
623     else
624     {
625         while (nBlockPorts < portIndex) // Create as many ports as necessary
626         {
627             concernedPort = controller.createObject(PORT);
628             controller.setObjectProperty(concernedPort, PORT, IMPLICIT, newPortIsImplicit);
629             controller.setObjectProperty(concernedPort, PORT, PORT_KIND, static_cast<int>(newPortKind));
630             controller.setObjectProperty(concernedPort, PORT, SOURCE_BLOCK, blkID);
631             controller.setObjectProperty(concernedPort, PORT, CONNECTED_SIGNALS, unconnected);
632             // Set the default dataType so it is saved in the model
633             std::vector<int> dataType;
634             controller.getObjectProperty(concernedPort, PORT, DATATYPE, dataType);
635             controller.setObjectProperty(concernedPort, PORT, DATATYPE, dataType);
636
637             std::vector<ScicosID> concernedPorts;
638             if (linkType == model::activation)
639             {
640                 if (v.kind == Start)
641                 {
642                     controller.getObjectProperty(blkID, BLOCK, EVENT_OUTPUTS, concernedPorts);
643                     concernedPorts.push_back(concernedPort);
644                     controller.setObjectProperty(blkID, BLOCK, EVENT_OUTPUTS, concernedPorts);
645                 }
646                 else
647                 {
648                     controller.getObjectProperty(blkID, BLOCK, EVENT_INPUTS, concernedPorts);
649                     concernedPorts.push_back(concernedPort);
650                     controller.setObjectProperty(blkID, BLOCK, EVENT_INPUTS, concernedPorts);
651                 }
652             }
653             else // model::regular || model::implicit
654             {
655                 if (v.kind == Start)
656                 {
657                     controller.getObjectProperty(blkID, BLOCK, OUTPUTS, concernedPorts);
658                     concernedPorts.push_back(concernedPort);
659                     controller.setObjectProperty(blkID, BLOCK, OUTPUTS, concernedPorts);
660                 }
661                 else
662                 {
663                     controller.getObjectProperty(blkID, BLOCK, INPUTS, concernedPorts);
664                     concernedPorts.push_back(concernedPort);
665                     controller.setObjectProperty(blkID, BLOCK, INPUTS, concernedPorts);
666                 }
667             }
668
669             nBlockPorts++;
670         }
671     }
672     ScicosID oldLink;
673     controller.getObjectProperty(concernedPort, PORT, CONNECTED_SIGNALS, oldLink);
674     if (oldLink != 0)
675     {
676         // Disconnect the old link
677         controller.setObjectProperty(oldLink, LINK, end, unconnected);
678         controller.setObjectProperty(concernedPort, PORT, CONNECTED_SIGNALS, unconnected);
679     }
680
681     // Connect the new source and destination ports together
682     controller.setObjectProperty(concernedPort, PORT, CONNECTED_SIGNALS, id);
683     controller.setObjectProperty(id, LINK, end, concernedPort);
684 }
685
686 // Check if the Link is valid
687 bool is_valid(types::Double* o)
688 {
689     if (o->getSize() == 0)
690     {
691         return true;
692     }
693
694     if (o->getSize() == 2 || o->getSize() == 3)
695     {
696         if (floor(o->get(0)) != o->get(0) || floor(o->get(1)) != o->get(1))
697         {
698             return false; // Block and Port numbers must be integer values
699         }
700         if (o->get(1) < 0)
701         {
702             return false; // Port number must be positive
703         }
704
705         if (o->getSize() == 3)
706         {
707             if (floor(o->get(2)) != o->get(2))
708             {
709                 return false; // Kind must be an integer value
710             }
711             if (o->get(2) < 0)
712             {
713                 return false; // Kind must be positive
714             }
715         }
716
717         return true;
718     }
719
720     return false;
721 }
722
723
724 struct from
725 {
726
727     static types::InternalType* get(const LinkAdapter& adaptor, const Controller& /*controller*/)
728     {
729         link_t from_content = adaptor.getFrom();
730
731         double* data;
732         types::Double* o = new types::Double(1, 3, &data);
733
734         data[0] = from_content.block;
735         data[1] = from_content.port;
736         data[2] = from_content.kind;
737         return o;
738     }
739
740     static bool set(LinkAdapter& adaptor, types::InternalType* v, Controller& controller)
741     {
742         if (v->getType() != types::InternalType::ScilabDouble)
743         {
744             return false;
745         }
746
747         types::Double* current = v->getAs<types::Double>();
748
749         if (!is_valid(current))
750         {
751             return false;
752         }
753
754         link_t from_content {0, 0, Start};
755         if (current->getSize() >= 2)
756         {
757             from_content.block = static_cast<int>(current->get(0));
758             from_content.port = static_cast<int>(current->get(1));
759             // By default, 'kind' designates an output (set to 0)
760
761             if (current->getSize() == 3)
762             {
763                 from_content.kind = (current->get(2) == 0.) ? Start : End;
764             }
765         }
766
767         adaptor.setFromInModel(from_content, controller);
768         return true;
769     }
770 };
771
772 struct to
773 {
774
775     static types::InternalType* get(const LinkAdapter& adaptor, const Controller& /*controller*/)
776     {
777         link_t to_content = adaptor.getTo();
778
779         double* data;
780         types::Double* o = new types::Double(1, 3, &data);
781
782         data[0] = to_content.block;
783         data[1] = to_content.port;
784         data[2] = to_content.kind;
785         return o;
786     }
787
788     static bool set(LinkAdapter& adaptor, types::InternalType* v, Controller& controller)
789     {
790         if (v->getType() != types::InternalType::ScilabDouble)
791         {
792             return false;
793         }
794
795         types::Double* current = v->getAs<types::Double>();
796
797         if (current->getSize() != 0 && current->getSize() != 2 && current->getSize() != 3)
798         {
799             return false;
800         }
801
802         if (!is_valid(current))
803         {
804             return false;
805         }
806
807         link_t to_content {0, 0, End};
808         if (current->getSize() >= 2)
809         {
810             to_content.block = static_cast<int>(current->get(0));
811             to_content.port = static_cast<int>(current->get(1));
812             // By default, 'kind' designates an input (set to 1)
813
814             if (current->getSize() == 3)
815             {
816                 to_content.kind = (current->get(2) == 0.) ? Start : End;
817             }
818         }
819
820         adaptor.setToInModel(to_content, controller);
821         return true;
822     }
823 };
824
825 } /* namespace */
826
827 template<> property<LinkAdapter>::props_t property<LinkAdapter>::fields = property<LinkAdapter>::props_t();
828
829 LinkAdapter::LinkAdapter(const Controller& c, org_scilab_modules_scicos::model::Link* adaptee) :
830     BaseAdapter<LinkAdapter, org_scilab_modules_scicos::model::Link>(c, adaptee),
831     m_from(),
832     m_to()
833 {
834     if (property<LinkAdapter>::properties_have_not_been_set())
835     {
836         property<LinkAdapter>::fields.reserve(7);
837         property<LinkAdapter>::add_property(L"xx", &xx::get, &xx::set);
838         property<LinkAdapter>::add_property(L"yy", &yy::get, &yy::set);
839         property<LinkAdapter>::add_property(L"id", &id::get, &id::set);
840         property<LinkAdapter>::add_property(L"thick", &thick::get, &thick::set);
841         property<LinkAdapter>::add_property(L"ct", &ct::get, &ct::set);
842         property<LinkAdapter>::add_property(L"from", &from::get, &from::set);
843         property<LinkAdapter>::add_property(L"to", &to::get, &to::set);
844     }
845
846     // If the Link has been added to a diagram, the following lines will dig up its information at model-level
847     Controller controller;
848     m_from = getLinkEnd(*this, controller, SOURCE_PORT);
849     m_to   = getLinkEnd(*this, controller, DESTINATION_PORT);
850 }
851
852 LinkAdapter::LinkAdapter(const LinkAdapter& adapter) :
853     BaseAdapter<LinkAdapter, org_scilab_modules_scicos::model::Link>(adapter),
854     m_from(adapter.getFrom()),
855     m_to(adapter.getTo())
856 {
857 }
858
859 LinkAdapter::~LinkAdapter()
860 {
861 }
862
863 std::wstring LinkAdapter::getTypeStr()
864 {
865     return getSharedTypeStr();
866 }
867 std::wstring LinkAdapter::getShortTypeStr()
868 {
869     return getSharedTypeStr();
870 }
871
872 link_t LinkAdapter::getFrom() const
873 {
874     return m_from;
875 }
876
877 void LinkAdapter::setFrom(const link_t& v)
878 {
879     m_from = v;
880 }
881
882 void LinkAdapter::setFromInModel(const link_t& v, Controller& controller)
883 {
884     m_from = v;
885
886     ScicosID parentDiagram;
887     controller.getObjectProperty(getAdaptee()->id(), LINK, PARENT_DIAGRAM, parentDiagram);
888     ScicosID parentBlock;
889     controller.getObjectProperty(getAdaptee()->id(), LINK, PARENT_BLOCK, parentBlock);
890
891     if (parentDiagram != 0 || parentBlock != 0)
892     {
893         // If the Link has been added to a diagram, do the linking at model-level
894         // If the provided values are wrong, the model is not updated but the info is stored in the Adapter for future attempts
895         setLinkEnd(getAdaptee()->id(), controller, SOURCE_PORT, v);
896     }
897 }
898
899 link_t LinkAdapter::getTo() const
900 {
901     return m_to;
902 }
903
904 void LinkAdapter::setTo(const link_t& v)
905 {
906     m_to = v;
907 }
908
909 void LinkAdapter::setToInModel(const link_t& v, Controller& controller)
910 {
911     m_to = v;
912
913     ScicosID parentDiagram;
914     controller.getObjectProperty(getAdaptee()->id(), LINK, PARENT_DIAGRAM, parentDiagram);
915     ScicosID parentBlock;
916     controller.getObjectProperty(getAdaptee()->id(), LINK, PARENT_BLOCK, parentBlock);
917
918     if (parentDiagram != 0 || parentBlock != 0)
919     {
920         // If the Link has been added to a diagram, do the linking at model-level
921         // If the provided values are wrong, the model is not updated but the info is stored in the Adapter for future attempts
922         setLinkEnd(getAdaptee()->id(), controller, DESTINATION_PORT, v);
923     }
924 }
925
926 } /* namespace view_scilab */
927 } /* namespace org_scilab_modules_scicos */