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