Xcos MVC: read-only undocumented 'modelID' field
[scilab.git] / scilab / modules / scicos / src / cpp / view_scilab / BaseAdapter.hxx
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 #ifndef BASEADAPTER_HXX_
14 #define BASEADAPTER_HXX_
15
16 #include <cstring>
17
18 #include <algorithm>
19 #include <string>
20 #include <vector>
21 #include <sstream>
22
23 #include "bool.hxx"
24 #include "double.hxx"
25 #include "user.hxx"
26 #include "internal.hxx"
27 #include "tlist.hxx"
28 #include "mlist.hxx"
29 #include "string.hxx"
30 #include "callable.hxx"
31 #include "overload.hxx"
32 #include "scilabexception.hxx"
33
34 #include "utilities.hxx"
35 #include "Controller.hxx"
36 #include "Adapters.hxx"
37 #include "model/BaseObject.hxx"
38
39 namespace org_scilab_modules_scicos
40 {
41 namespace view_scilab
42 {
43
44 /**
45  * A property used as a getter/setter for a specific name
46  */
47 template<typename Adaptor>
48 struct property
49 {
50 public:
51     typedef types::InternalType* (*getter_t)(const Adaptor& adaptor, const Controller& controller);
52     typedef bool (*setter_t)(Adaptor& adaptor, types::InternalType* v, Controller& controller);
53
54     typedef std::vector< property<Adaptor> > props_t;
55     typedef typename props_t::iterator props_t_it;
56
57
58     property(const std::wstring& prop, getter_t g, setter_t s) : original_index(fields.size()), name(prop), get(g), set(s) {};
59     ~property() {};
60
61     size_t original_index;
62     std::wstring name;
63     getter_t get;
64     setter_t set;
65
66     bool operator< (const std::wstring& v) const
67     {
68         return name < v;
69     }
70
71     static bool original_index_cmp(property<Adaptor> p1, property<Adaptor> p2)
72     {
73         return p1.original_index < p2.original_index;
74     }
75
76     /*
77      * Static properties accessors
78      */
79     static props_t fields;
80
81     /**
82      * @return true if the properties have already been setup, false otherwise.
83      */
84     static bool properties_have_not_been_set()
85     {
86         return fields.empty();
87     }
88
89     /**
90      * Add a property to an Adaptor
91      */
92     static void add_property(const std::wstring& name, getter_t g, setter_t s)
93     {
94         property<Adaptor>::props_t_it pos = std::lower_bound(fields.begin(), fields.end(), name);
95         fields.insert(pos, property(name, g, s));
96     }
97 };
98
99 /**
100  * Base definition of the adapter pattern, implement the get / set dispatch.
101  *
102  * Note that sub-classes are responsible to fill the fields accordingly to theirs interfaces.
103  */
104 template<typename Adaptor, typename Adaptee>
105 class BaseAdapter : public types::UserType
106 {
107
108 public:
109     BaseAdapter() : m_adaptee(nullptr) {};
110     BaseAdapter(const Controller& /*c*/, Adaptee* adaptee) : m_adaptee(adaptee) {}
111     BaseAdapter(const BaseAdapter& adapter) : BaseAdapter(adapter, true) {}
112     BaseAdapter(const BaseAdapter& adapter, bool cloneChildren) : m_adaptee(nullptr)
113     {
114         Controller controller;
115         ScicosID id = controller.cloneObject(adapter.getAdaptee()->id(), cloneChildren);
116         m_adaptee = controller.getObject< Adaptee >(id);
117     };
118     ~BaseAdapter()
119     {
120         if (m_adaptee != nullptr)
121         {
122             Controller controller;
123             controller.deleteObject(m_adaptee->id());
124         }
125     };
126
127     /*
128      * property accessors
129      */
130
131     bool hasProperty(const std::wstring& _sKey) const
132     {
133         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
134         return found != property<Adaptor>::fields.end() && !(_sKey < found->name);
135     }
136
137     types::InternalType* getProperty(const std::wstring& _sKey, Controller controller = Controller()) const
138     {
139         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
140         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
141         {
142             return found->get(static_cast<Adaptor*>(this), controller);
143         }
144         return 0;
145     }
146
147     bool setProperty(const std::wstring& _sKey, types::InternalType* v, Controller controller = Controller())
148     {
149         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
150         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
151         {
152             return found->set(*static_cast<Adaptor*>(this), v, controller);
153         }
154         return false;
155     }
156
157     /**
158      * property as TList accessors
159      */
160
161     types::InternalType* getAsTList(types::TList* tlist, const Controller& controller)
162     {
163         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
164         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
165
166         // create the header
167         types::String* header = new types::String(1, 1 + (int)properties.size());
168         header->set(0, Adaptor::getSharedTypeStr().c_str());
169         int index = 1;
170         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
171         {
172             header->set(index, it->name.c_str());
173         }
174         tlist->append(header);
175
176         // set the tlist field value
177         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
178         {
179             tlist->append(it->get(*static_cast<Adaptor*>(this), controller));
180         }
181
182         return tlist;
183     }
184
185     bool setAsTList(types::InternalType* v, Controller& controller)
186     {
187         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
188         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
189
190         if (v->getType() != types::InternalType::ScilabTList && v->getType() != types::InternalType::ScilabMList)
191         {
192             return false;
193         }
194         types::TList* current = v->getAs<types::TList>();
195         // The input TList can have fewer elements than the concerned adapter, but not more, and cannot be empty
196         if (current->getSize() > static_cast<int>(1 + properties.size()) || current->getSize() < 1)
197         {
198             return false;
199         }
200
201         // Check the header
202         types::String* header = current->getFieldNames();
203         if (header->getSize() > static_cast<int>(1 + properties.size()) || header->getSize() < 1)
204         {
205             return false;
206         }
207         if (header->get(0) != Adaptor::getSharedTypeStr())
208         {
209             return false;
210         }
211         typename property<Adaptor>::props_t_it it = properties.begin();
212         for (int index = 1; index < header->getSize(); ++index, ++it)
213         {
214             if (header->get(index) != it->name)
215             {
216                 return false;
217             }
218         }
219
220         // This is a valid tlist, get each tlist field value and pass it to the right property decoder
221         it = properties.begin();
222         for (int index = 1; index < header->getSize(); ++index, ++it)
223         {
224             bool status = it->set(*static_cast<Adaptor*>(this), current->get(index), controller);
225             if (!status)
226             {
227                 return false;
228             }
229         }
230
231         return true;
232     }
233
234     /**
235      * property comparison
236      */
237
238     types::Bool* equal(types::UserType*& ut)
239     {
240         const Adapters::adapters_index_t adapter_index = Adapters::instance().lookup_by_typename(ut->getShortTypeStr());
241         // Check that 'ut' is an Adapter of the same type as *this
242         if (adapter_index == Adapters::INVALID_ADAPTER)
243         {
244             return new types::Bool(false);
245         }
246         if (this->getTypeStr() != ut->getTypeStr())
247         {
248             return new types::Bool(false);
249         }
250
251         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
252         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
253
254         types::Bool* ret = new types::Bool(1, 1 + properties.size());
255         ret->set(0, true); // First field is just the Adapter's name, which has been checked by the above conditions
256
257         Controller controller = Controller();
258         int index = 1;
259         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
260         {
261             types::InternalType* ith_prop1 = it->get(*static_cast<Adaptor*>(this), controller);
262             types::InternalType* ith_prop2 = it->get(*static_cast<Adaptor*>(ut), controller);
263             ret->set(index, *ith_prop1 == *ith_prop2);
264
265             // Getting a property allocates data, so free it
266             ith_prop1->killMe();
267             ith_prop2->killMe();
268         }
269
270         return ret;
271     }
272
273     /**
274      * @return the Adaptee
275      */
276     Adaptee* getAdaptee() const
277     {
278         return m_adaptee;
279     }
280
281     /*
282      * All following methods should be implemented by each template instance
283      */
284
285     virtual std::wstring getTypeStr() = 0;
286     virtual std::wstring getShortTypeStr() = 0;
287
288 private:
289     types::InternalType* clone()
290     {
291         return new Adaptor(*static_cast<Adaptor*>(this));
292     }
293
294     /*
295      * Implement a specific types::User
296      */
297
298     bool isAssignable()
299     {
300         return true;
301     }
302
303     bool extract(const std::wstring & name, types::InternalType *& out)
304     {
305         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
306         if (found != property<Adaptor>::fields.end() && !(name < found->name))
307         {
308             Controller controller = Controller();
309             types::InternalType* value = found->get(*static_cast<Adaptor*>(this), controller);
310             if (value == 0)
311             {
312                 return false;
313             }
314
315             out = value;
316             return true;
317         }
318
319         // specific case : to ease debugging let the user retrieve the model ID
320         if (name == L"modelID")
321         {
322             out = new types::Double(m_adaptee->id());
323             return true;
324         }
325
326         return false;
327     }
328
329     types::InternalType* extract(types::typed_list* _pArgs)
330     {
331         if (_pArgs->size() == 0)
332         {
333             // call overload
334             return NULL;
335         }
336
337         if ((*_pArgs)[0]->isString())
338         {
339             types::String* pStr = (*_pArgs)[0]->getAs<types::String>();
340             types::InternalType* pOut = NULL;
341             extract(std::wstring(pStr->get(0)), pOut);
342             return pOut;
343         }
344         else
345         {
346             if ((*_pArgs)[0]->isDouble())
347             {
348                 types::Double* index = (*_pArgs)[0]->getAs<types::Double>();
349
350                 if (index->get(0) == 1)
351                 {
352                     // When _pArgs is '1', return the list of the property names of the Adaptor
353
354                     // Sort the properties before extracting them
355                     typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
356                     std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
357
358                     // Allocate the return
359                     types::String* pOut = new types::String(1, static_cast<int>(properties.size()));
360
361                     int i = 0;
362                     for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++i)
363                     {
364                         pOut->set(i, it->name.data());
365                     }
366                     return pOut;
367                 }
368             }
369             else
370             {
371                 // TO DO : management other type for arguments like a scalar or matrix of double
372             }
373         }
374
375         return NULL;
376     }
377
378     types::InternalType* insert(types::typed_list* _pArgs, types::InternalType* _pSource)
379     {
380         for (size_t i = 0; i < _pArgs->size(); i++)
381         {
382             if ((*_pArgs)[i]->isString())
383             {
384                 types::String* pStr = (*_pArgs)[i]->getAs<types::String>();
385                 std::wstring name = pStr->get(0);
386
387                 Controller controller = Controller();
388                 typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
389                 if (found != property<Adaptor>::fields.end() && !(name < found->name))
390                 {
391                     found->set(*static_cast<Adaptor*>(this), _pSource, controller);
392                 }
393
394                 return this;
395             }
396             else
397             {
398                 return NULL;
399             }
400         }
401
402         // call overload
403         return NULL;
404     }
405
406     void whoAmI(void)
407     {
408         std::cout << "scicos object";
409     }
410
411     bool hasToString()
412     {
413         // Do not allow scilab to call toString of this class
414         return false;
415     }
416
417     bool toString(std::wostringstream& ostr)
418     {
419         // Deprecated, use the overload instead
420         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
421         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
422
423         ostr << L"scicos_" <<  getTypeStr() << L" type :" << std::endl;
424         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
425         {
426             ostr << L"  " << it->name << std::endl;
427         }
428         return true;
429     }
430
431     bool isInvokable() const
432     {
433         return true;
434     }
435
436     bool invoke(types::typed_list & in, types::optional_list & /*opt*/, int /*_iRetCount*/, types::typed_list & out, ast::ConstVisitor & execFunc, const ast::Exp & /*e*/)
437     {
438         if (in.size() == 0)
439         {
440             out.push_back(this);
441             return true;
442         }
443         else if (in.size() == 1)
444         {
445             types::InternalType* _out = nullptr;
446             types::InternalType*  arg = in[0];
447             if (arg->isString())
448             {
449                 types::String* pString = arg->getAs<types::String>();
450                 for (int i = 0; i < pString->getSize(); ++i)
451                 {
452                     if (!extract(pString->get(i), _out))
453                     {
454                         return false;
455                     }
456                     out.push_back(_out);
457                 }
458             }
459
460             if (!out.empty())
461             {
462                 return true;
463             }
464         }
465
466         types::Callable::ReturnValue ret;
467         // Overload of extraction needs the BaseAdapter from where we extract
468         this->IncreaseRef();
469         in.push_back(this);
470
471         try
472         {
473             ret = Overload::call(L"%" + getShortTypeStr() + L"_e", in, 1, out, &execFunc);
474         }
475         catch (ast::ScilabError & /*se*/)
476         {
477             ret = Overload::call(L"%l_e", in, 1, out, &execFunc);
478         }
479
480         // Remove this from "in" to keep "in" unchanged.
481         this->DecreaseRef();
482         in.pop_back();
483
484         if (ret == types::Callable::Error)
485         {
486             throw ast::ScilabError();
487         }
488
489         return true;
490     }
491
492 private:
493     Adaptee* m_adaptee;
494 };
495
496
497 } /* namespace view_scilab */
498 } /* namespace org_scilab_modules_scicos */
499
500 #endif /* BASEADAPTER_HXX_ */