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