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