Update CHANGES.md before the release
[scilab.git] / scilab / modules / scicos / src / cpp / Controller.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2014-2016 - Scilab Enterprises - Clement DAVID
4  * Copyright (C) 2017-2018 - ESI Group - Clement DAVID
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 #include <atomic>
18 #include <string>
19 #include <vector>
20 #include <map>
21 #include <utility>
22 #include <algorithm>
23 #include <iterator>
24
25 #include "utilities.hxx"
26
27 #include "Controller.hxx"
28 #include "model/BaseObject.hxx"
29
30 #include "LoggerView.hxx"
31
32 extern "C" {
33 #include "scicos.h"
34 }
35
36 namespace org_scilab_modules_scicos
37 {
38
39 /*
40  * Implement SharedData methods
41  */
42 Controller::SharedData::SharedData() :
43     onModelStructuralModification(), model(),
44     onViewsStructuralModification(), allNamedViews(), allViews()
45 {
46     unlock(&onModelStructuralModification);
47     unlock(&onViewsStructuralModification);
48 }
49
50 Controller::SharedData::~SharedData()
51 {
52     lock(&onViewsStructuralModification);
53     for (const auto& v : m_instance.allViews)
54     {
55         delete v;
56     }
57     unlock(&onViewsStructuralModification);
58 }
59
60 Controller::SharedData Controller::m_instance;
61
62 View* Controller::register_view(const std::string& name, View* v)
63 {
64     if (v != nullptr)
65     {
66         lock(&m_instance.onViewsStructuralModification);
67
68         m_instance.allNamedViews.push_back(name);
69         m_instance.allViews.push_back(v);
70
71         unlock(&m_instance.onViewsStructuralModification);
72     }
73     return v;
74 }
75
76 void Controller::unregister_view(View* v)
77 {
78     lock(&m_instance.onViewsStructuralModification);
79
80     view_set_t::iterator it = std::find(m_instance.allViews.begin(), m_instance.allViews.end(), v);
81     if (it != m_instance.allViews.end())
82     {
83         size_t d = std::distance(m_instance.allViews.begin(), it);
84         m_instance.allNamedViews.erase(m_instance.allNamedViews.begin() + d);
85         m_instance.allViews.erase(m_instance.allViews.begin() + d);
86     }
87
88     unlock(&m_instance.onViewsStructuralModification);
89 }
90
91 View* Controller::unregister_view(const std::string& name)
92 {
93     View* view = nullptr;
94
95     lock(&m_instance.onViewsStructuralModification);
96
97     view_name_set_t::iterator it = std::find(m_instance.allNamedViews.begin(), m_instance.allNamedViews.end(), name);
98     if (it != m_instance.allNamedViews.end())
99     {
100         size_t d = std::distance(m_instance.allNamedViews.begin(), it);
101         view = *(m_instance.allViews.begin() + d);
102         m_instance.allNamedViews.erase(m_instance.allNamedViews.begin() + d);
103         m_instance.allViews.erase(m_instance.allViews.begin() + d);
104     }
105     unlock(&m_instance.onViewsStructuralModification);
106
107     return view;
108 }
109
110 View* Controller::look_for_view(const std::string& name)
111 {
112     View* view = nullptr;
113
114     lock(&m_instance.onViewsStructuralModification);
115     view_name_set_t::iterator it = std::find(m_instance.allNamedViews.begin(), m_instance.allNamedViews.end(), name);
116     if (it != m_instance.allNamedViews.end())
117     {
118         size_t d = std::distance(m_instance.allNamedViews.begin(), it);
119         view = *(m_instance.allViews.begin() + d);
120     }
121     unlock(&m_instance.onViewsStructuralModification);
122
123     return view;
124 }
125
126 void Controller::end_simulation()
127 {
128     end_scicos_sim();
129 }
130
131 Controller::Controller() : _strShared(), _vecDblShared(), _vecIntShared(), _vecStrShared(), _vecIDShared()
132 {
133 }
134
135 Controller::~Controller()
136 {
137 }
138
139 model::BaseObject* Controller::createBaseObject(kind_t k)
140 {
141     lock(&m_instance.onModelStructuralModification);
142     model::BaseObject* object = m_instance.model.createObject(k);
143     unlock(&m_instance.onModelStructuralModification);
144
145     lock(&m_instance.onViewsStructuralModification);
146     for (const auto& v : m_instance.allViews)
147     {
148         v->objectCreated(object->id(), object->kind());
149     }
150     unlock(&m_instance.onViewsStructuralModification);
151
152     return object;
153 }
154
155 model::BaseObject* Controller::referenceBaseObject(model::BaseObject* o) const
156 {
157     lock(&m_instance.onModelStructuralModification);
158
159     unsigned refCount = m_instance.model.referenceObject(o);
160
161     unlock(&m_instance.onModelStructuralModification);
162     if (o == nullptr)
163     {
164         // defensive programming
165         return 0u;
166     }
167
168     // not locked on purpose, this will allow referencing on View notification
169     // lock(&m_instance.onViewsStructuralModification);
170     for (const auto& v : m_instance.allViews)
171     {
172         v->objectReferenced(o->id(), o->kind(), refCount);
173     }
174     // unlock(&m_instance.onViewsStructuralModification);
175
176     return o;
177 }
178
179 void Controller::deleteBaseObject(model::BaseObject* initial)
180 {
181     // if this object is the empty uid, ignore it : is is not stored in the model
182     if (initial == nullptr || initial->id() == ScicosID())
183     {
184         return;
185     }
186
187     lock(&m_instance.onModelStructuralModification);
188     const kind_t k = initial->kind();
189
190     // if this object has been referenced somewhere else do not delete it but decrement the reference counter
191     unsigned& refCount = m_instance.model.referenceCount(initial);
192     unlock(&m_instance.onModelStructuralModification);
193     if (refCount > 0)
194     {
195         --refCount;
196
197         // not locked on purpose, this will allow referencing on View notification
198         // lock(&m_instance.onViewsStructuralModification);
199         for (const auto& v : m_instance.allViews)
200         {
201             v->objectUnreferenced(initial->id(), initial->kind(), refCount);
202         }
203         // unlock(&m_instance.onViewsStructuralModification);
204         return;
205     }
206
207     // We need to delete this object and cleanup all the referenced model object
208
209     // disconnect / remove references of weak connected objects and decrement the reference count of all strongly connected objects.
210     if (k == ANNOTATION)
211     {
212         unlinkVector(initial, PARENT_DIAGRAM, CHILDREN);
213         unlinkVector(initial, PARENT_BLOCK, CHILDREN);
214         // RELATED_TO is not referenced back
215     }
216     else if (k == BLOCK)
217     {
218         unlinkVector(initial, PARENT_DIAGRAM, CHILDREN);
219         unlinkVector(initial, PARENT_BLOCK, CHILDREN);
220
221         deleteOwnedReference(initial, LABEL);
222
223         deleteVector(initial, INPUTS);
224         deleteVector(initial, OUTPUTS);
225         deleteVector(initial, EVENT_INPUTS);
226         deleteVector(initial, EVENT_OUTPUTS);
227
228         deleteVector(initial, CHILDREN);
229         // FIXME what about REFERENCED_PORT ?
230     }
231     else if (k == DIAGRAM)
232     {
233         unlink(initial, CHILDREN, PARENT_DIAGRAM);
234         deleteVector(initial, CHILDREN);
235     }
236     else if (k == LINK)
237     {
238         unlinkVector(initial, PARENT_DIAGRAM, CHILDREN);
239         unlinkVector(initial, PARENT_BLOCK, CHILDREN);
240
241         deleteOwnedReference(initial, LABEL);
242
243         unlinkVector(initial, SOURCE_PORT, CONNECTED_SIGNALS);
244         unlinkVector(initial, DESTINATION_PORT, CONNECTED_SIGNALS);
245     }
246     else if (k == PORT)
247     {
248         unlinkVector(initial, SOURCE_BLOCK, INPUTS);
249         unlinkVector(initial, SOURCE_BLOCK, OUTPUTS);
250         unlinkVector(initial, SOURCE_BLOCK, EVENT_INPUTS);
251         unlinkVector(initial, SOURCE_BLOCK, EVENT_OUTPUTS);
252
253         unlink(initial, CONNECTED_SIGNALS, SOURCE_PORT);
254         unlink(initial, CONNECTED_SIGNALS, DESTINATION_PORT);
255     }
256
257     // notify first
258     lock(&m_instance.onViewsStructuralModification);
259     for (const auto& v : m_instance.allViews)
260     {
261         v->objectDeleted(initial->id(), k);
262     }
263     unlock(&m_instance.onViewsStructuralModification);
264
265     // then delete the object
266     lock(&m_instance.onModelStructuralModification);
267     m_instance.model.deleteObject(initial);
268     unlock(&m_instance.onModelStructuralModification);
269 }
270
271 void Controller::unlinkVector(model::BaseObject* initial, object_properties_t uid_prop, object_properties_t ref_prop)
272 {
273     ScicosID v;
274     getObjectProperty(initial, uid_prop, v);
275     if (v != ScicosID())
276     {
277         auto o = getBaseObject(v);
278         if (o == nullptr)
279         {
280             return;
281         }
282
283         std::vector<ScicosID>& children = _vecIDShared;
284         getObjectProperty(o, ref_prop, children);
285
286         std::vector<ScicosID>::iterator it = std::find(children.begin(), children.end(), initial->id());
287         if (it != children.end())
288         {
289             children.erase(it);
290         }
291
292         setObjectProperty(o, ref_prop, children);
293     }
294 }
295
296 void Controller::unlink(model::BaseObject* initial, object_properties_t uid_prop, object_properties_t ref_prop)
297 {
298     std::vector<ScicosID> v;
299     getObjectProperty(initial, uid_prop, v);
300     for (const ScicosID id : v)
301     {
302         if (id != ScicosID())
303         {
304             auto o = getBaseObject(id);
305             if (o == nullptr)
306             {
307                 continue;
308             }
309
310             // Find which end of the link is connected to the port
311             ScicosID oppositeRef;
312             getObjectProperty(o->id(), o->kind(), ref_prop, oppositeRef);
313             if (oppositeRef == initial->id())
314             {
315                 setObjectProperty(o, ref_prop, ScicosID());
316             }
317         }
318     }
319 }
320
321 void Controller::deleteVector(model::BaseObject* initial, object_properties_t uid_prop)
322 {
323     std::vector<ScicosID> children;
324     getObjectProperty(initial, uid_prop, children);
325
326     for (ScicosID id : children)
327     {
328         deleteObject(id);
329     }
330 }
331
332 void Controller::deleteOwnedReference(model::BaseObject* o, object_properties_t uid_prop)
333 {
334     ScicosID ref;
335     getObjectProperty(o, uid_prop, ref);
336
337     deleteObject(ref);
338 }
339
340 template<typename T>
341 void Controller::cloneProperties(model::BaseObject* initial, model::BaseObject* clone)
342 {
343     for (int i = 0; i < MAX_OBJECT_PROPERTIES; ++i)
344     {
345         enum object_properties_t p = static_cast<enum object_properties_t>(i);
346
347         T value;
348         bool status = getObjectProperty(initial, p, value);
349         if (status)
350         {
351             setObjectProperty(clone, p, value);
352         }
353     }
354 }
355
356 template<typename T>
357 void Controller::cloneProperties(model::BaseObject* initial, model::BaseObject* clone, T& temporary)
358 {
359     for (int i = 0; i < MAX_OBJECT_PROPERTIES; ++i)
360     {
361         enum object_properties_t p = static_cast<enum object_properties_t>(i);
362
363         temporary.clear();
364         bool status = getObjectProperty(initial, p, temporary);
365         if (status)
366         {
367             setObjectProperty(clone, p, temporary);
368         }
369     }
370 }
371
372 model::BaseObject* Controller::cloneBaseObject(cloned_t& mapped, model::BaseObject* initial, bool cloneChildren, bool clonePorts)
373 {
374     const kind_t k = initial->kind();
375     ScicosID o = createObject(k);
376     model::BaseObject* cloned = getBaseObject(o);
377     mapped.insert(
378         std::make_pair(initial->id(), cloned_pair_t(initial, cloned)));
379
380     lock(&m_instance.onViewsStructuralModification);
381     for (const auto& v : m_instance.allViews)
382     {
383         v->objectCloned(initial->id(), o, k);
384     }
385     unlock(&m_instance.onViewsStructuralModification);
386
387     // Get then set all properties per type that do not manage ScicosID
388     cloneProperties<double>(initial, cloned);
389     cloneProperties<int>(initial, cloned);
390     cloneProperties<bool>(initial, cloned);
391     cloneProperties<std::string>(initial, cloned, _strShared);
392     cloneProperties<std::vector<double> >(initial, cloned, _vecDblShared);
393     cloneProperties<std::vector<int> >(initial, cloned, _vecIntShared);
394     cloneProperties<std::vector<std::string> >(initial, cloned, _vecStrShared);
395
396     // deep copy children, manage ScicosID and std::vector<ScicosID>
397     if (k == ANNOTATION)
398     {
399         deepClone(mapped, initial, cloned, PARENT_DIAGRAM, false);
400         deepClone(mapped, initial, cloned, PARENT_BLOCK, false);
401         deepClone(mapped, initial, cloned, RELATED_TO, true);
402     }
403     else if (k == BLOCK)
404     {
405         deepClone(mapped, initial, cloned, PARENT_DIAGRAM, false);
406         if (clonePorts)
407         {
408             // copy the block and all its ports
409             deepCloneVector(mapped, initial, cloned, INPUTS, true);
410             deepCloneVector(mapped, initial, cloned, OUTPUTS, true);
411             deepCloneVector(mapped, initial, cloned, EVENT_INPUTS, true);
412             deepCloneVector(mapped, initial, cloned, EVENT_OUTPUTS, true);
413         }
414
415         deepClone(mapped, initial, cloned, PARENT_BLOCK, false);
416         if (cloneChildren)
417         {
418             deepCloneVector(mapped, initial, cloned, CHILDREN, true);
419         }
420         // FIXME what about REFERENCED_PORT ?
421     }
422     else if (k == DIAGRAM)
423     {
424         if (cloneChildren)
425         {
426             deepCloneVector(mapped, initial, cloned, CHILDREN, true);
427         }
428     }
429     else if (k == LINK)
430     {
431         deepClone(mapped, initial, cloned, PARENT_DIAGRAM, false);
432         deepClone(mapped, initial, cloned, PARENT_BLOCK, false);
433         deepClone(mapped, initial, cloned, SOURCE_PORT, false);
434         deepClone(mapped, initial, cloned, DESTINATION_PORT, false);
435     }
436     else if (k == PORT)
437     {
438         deepClone(mapped, initial, cloned, SOURCE_BLOCK, false);
439         deepCloneVector(mapped, initial, cloned, CONNECTED_SIGNALS, false);
440     }
441     return cloned;
442 }
443
444 void Controller::deepClone(cloned_t& mapped, model::BaseObject* initial, model::BaseObject* clone, object_properties_t p, bool cloneIfNotFound)
445 {
446     ScicosID v;
447     getObjectProperty(initial, p, v);
448
449     ScicosID cloned;
450     cloned_t::iterator it = mapped.find(v);
451     if (it != mapped.end())
452     {
453         cloned = it->second.cloned->id();
454     }
455     else
456     {
457         if (cloneIfNotFound)
458         {
459             if (v != ScicosID())
460             {
461                 model::BaseObject *opposite = getBaseObject(v);
462                 cloned = cloneBaseObject(mapped, opposite, true, true)->id();
463             }
464             else
465             {
466                 cloned = ScicosID();
467             }
468         }
469         else
470         {
471             cloned = ScicosID();
472         }
473     }
474
475     setObjectProperty(clone, p, cloned);
476 }
477
478 void Controller::deepCloneVector(cloned_t &mapped, model::BaseObject *initial,
479                                  model::BaseObject *clone,
480                                  object_properties_t p, bool cloneIfNotFound)
481 {
482     std::vector<ScicosID> v;
483     getObjectProperty(initial, p, v);
484
485     std::vector<model::BaseObject *> cloned;
486     cloned.reserve(v.size());
487
488     for (const ScicosID &id : v)
489     {
490         if (id == ScicosID())
491         {
492             // Deleted Block, the cloning is done at Adapter level
493             cloned.push_back(nullptr);
494             continue;
495         }
496
497         model::BaseObject *opposite = getBaseObject(id);
498         cloned_t::iterator it = mapped.find(id);
499         if (it != mapped.end())
500         {
501             cloned.push_back(it->second.cloned);
502         }
503         else
504         {
505             if (cloneIfNotFound)
506             {
507                 if (id != ScicosID())
508                 {
509                     model::BaseObject *clone =
510                         cloneBaseObject(mapped, opposite, true, true);
511                     cloned.push_back(clone);
512                 }
513                 else
514                 {
515                     cloned.push_back(nullptr);
516                 }
517             }
518             else
519             {
520                 cloned.push_back(nullptr);
521             }
522         }
523     }
524
525     // update the ScicosID related properties after cloning all the objects
526     if (p == CHILDREN)
527     {
528         updateChildrenRelatedPropertiesAfterClone(mapped);
529     }
530
531     // set the main object vector property
532     std::vector<ScicosID> clonedUIDs(cloned.size());
533     std::transform(cloned.begin(), cloned.end(), clonedUIDs.begin(),
534                    [](model::BaseObject * o)
535     {
536         if (o == nullptr)
537         {
538             return ScicosID();
539         }
540         else
541         {
542             return o->id();
543         }
544     });
545
546     setObjectProperty(clone, p, clonedUIDs);
547 }
548
549 void Controller::updateChildrenRelatedPropertiesAfterClone(cloned_t &mapped)
550 {
551     for (auto const &it : mapped)
552     {
553         model::BaseObject *initial = it.second.initial;
554         model::BaseObject *cloned = it.second.cloned;
555
556         switch (initial->kind())
557         {
558             case PORT:
559                 deepCloneVector(mapped, initial, cloned, CONNECTED_SIGNALS, false);
560                 break;
561             case LINK:
562                 deepClone(mapped, initial, cloned, SOURCE_PORT, false);
563                 deepClone(mapped, initial, cloned, DESTINATION_PORT, false);
564                 break;
565             default:
566                 break;
567         }
568     }
569 }
570
571 ScicosID Controller::cloneObject(ScicosID uid, bool cloneChildren, bool clonePorts)
572 {
573     cloned_t mapped;
574     model::BaseObject *clone =
575         cloneBaseObject(mapped, getBaseObject(uid), cloneChildren, clonePorts);
576
577     return clone->id();
578 }
579
580 kind_t Controller::getKind(ScicosID uid) const
581 {
582     lock(&m_instance.onModelStructuralModification);
583
584     kind_t kind = m_instance.model.getKind(uid);
585
586     unlock(&m_instance.onModelStructuralModification);
587     return kind;
588 }
589
590 std::vector<ScicosID> Controller::getAll(kind_t k) const
591 {
592     lock(&m_instance.onModelStructuralModification);
593
594     std::vector<model::BaseObject*> vec = m_instance.model.getAll(k);
595     std::vector<ScicosID> ret;
596     ret.reserve(vec.size());
597     for (model::BaseObject* o : vec)
598     {
599         ret.push_back(o->id());
600     }
601
602     unlock(&m_instance.onModelStructuralModification);
603     return ret;
604 }
605
606 void Controller::sortAndFillKind(std::vector<ScicosID>& uids, std::vector<int>& kinds)
607 {
608     lock(&m_instance.onModelStructuralModification);
609
610     // create a container of pair
611     struct local_pair
612     {
613         ScicosID first;
614         int second;
615     };
616     std::vector<local_pair> container;
617     container.reserve(uids.size());
618
619     // fill it
620     for (ScicosID uid : uids)
621     {
622         // if something went wrong on the adapters, clean the invalid children
623         if (uid == ScicosID())
624         {
625             continue;
626         }
627
628         container.push_back({ uid, m_instance.model.getKind(uid) });
629     }
630
631     // sort according to the kinds
632     std::stable_sort(container.begin(), container.end(), [] (const local_pair & a, const local_pair & b)
633     {
634         return a.second < b.second;
635     });
636
637     // move things back
638     uids.clear();
639     uids.reserve(container.size());
640     kinds.reserve(container.size());
641     for (const auto & v : container)
642     {
643         uids.push_back(v.first);
644         kinds.push_back(v.second);
645     }
646
647     unlock(&m_instance.onModelStructuralModification);
648 }
649
650 template<typename T>
651 bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, T& v) const
652 {
653     return getObjectProperty(getBaseObject(uid), p, v);
654 }
655
656 bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, double& v) const
657 {
658     return getObjectProperty<>(uid, k, p, v);
659 }
660 bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, int& v) const
661 {
662     return getObjectProperty<>(uid, k, p, v);
663 }
664 bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, bool& v) const
665 {
666     return getObjectProperty<>(uid, k, p, v);
667 }
668 bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, std::string& v) const
669 {
670     return getObjectProperty<>(uid, k, p, v);
671 }
672 bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, ScicosID& v) const
673 {
674     return getObjectProperty<>(uid, k, p, v);
675 }
676 bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, std::vector<double>& v) const
677 {
678     return getObjectProperty<>(uid, k, p, v);
679 }
680 bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, std::vector<int>& v) const
681 {
682     return getObjectProperty<>(uid, k, p, v);
683 }
684 bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, std::vector<bool>& v) const
685 {
686     return getObjectProperty<>(uid, k, p, v);
687 }
688 bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, std::vector< std::string >& v) const
689 {
690     return getObjectProperty<>(uid, k, p, v);
691 }
692 bool Controller::getObjectProperty(ScicosID uid, kind_t k, object_properties_t p, std::vector<ScicosID>& v) const
693 {
694     return getObjectProperty<>(uid, k, p, v);
695 }
696
697 template<typename T>
698 update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, T v)
699 {
700     return setObjectProperty(getBaseObject(uid), p, v);
701 }
702
703 update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, double v)
704 {
705     return setObjectProperty<>(uid, k, p, v);
706 }
707 update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, int v)
708 {
709     return setObjectProperty<>(uid, k, p, v);
710 }
711 update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, bool v)
712 {
713     return setObjectProperty<>(uid, k, p, v);
714 }
715 update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, ScicosID v)
716 {
717     return setObjectProperty<>(uid, k, p, v);
718 }
719 update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, const std::string& v)
720 {
721     return setObjectProperty<>(uid, k, p, v);
722 }
723 update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, const std::vector<double>& v)
724 {
725     return setObjectProperty<>(uid, k, p, v);
726 }
727 update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, const std::vector<int>& v)
728 {
729     return setObjectProperty<>(uid, k, p, v);
730 }
731 update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, const std::vector<bool>& v)
732 {
733     return setObjectProperty<>(uid, k, p, v);
734 }
735 update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, const std::vector< std::string >& v)
736 {
737     return setObjectProperty<>(uid, k, p, v);
738 }
739 update_status_t Controller::setObjectProperty(ScicosID uid, kind_t k, object_properties_t p, const std::vector<ScicosID>& v)
740 {
741     return setObjectProperty<>(uid, k, p, v);
742 }
743
744 model::BaseObject* Controller::getBaseObject(ScicosID uid) const
745 {
746     lock(&m_instance.onModelStructuralModification);
747     model::BaseObject* o = m_instance.model.getObject(uid);
748     unlock(&m_instance.onModelStructuralModification);
749     return o;
750 }
751
752 } /* namespace org_scilab_modules_scicos */
753