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