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