Xcos MVC: deprecate all Adapters' toString (use overload)
[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 = 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             // In a ModelAdapter, the 'rpar' property (number 13) can return '0', in which case do not set the field
175             if (index != 13)
176             {
177                 tlist->set(index, it->get(*static_cast<Adaptor*>(this), controller));
178             }
179             else
180             {
181                 types::InternalType* pVal = it->get(*static_cast<Adaptor*>(this), controller);
182                 if (pVal != 0)
183                 {
184                     tlist->set(index, pVal);
185                 }
186             }
187         }
188
189         tlist->IncreaseRef();
190         return tlist;
191     }
192
193     bool setAsTList(types::InternalType* v, Controller& controller)
194     {
195         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
196         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
197
198         if (v->getType() != types::InternalType::ScilabTList && v->getType() != types::InternalType::ScilabMList)
199         {
200             return false;
201         }
202         types::TList* current = v->getAs<types::TList>();
203         if (current->getSize() != static_cast<int>(1 + properties.size()))
204         {
205             return false;
206         }
207
208         // check the header
209         types::String* header = current->getFieldNames();
210         if (header->getSize() != static_cast<int>(1 + properties.size()))
211         {
212             return false;
213         }
214         if (header->get(0) != Adaptor::getSharedTypeStr())
215         {
216             return false;
217         }
218         int index = 1;
219         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
220         {
221             if (header->get(index) != it->name)
222             {
223                 return false;
224             }
225         }
226
227         // this is a valid tlist, get each tlist field value and pass it to the right property decoder
228         index = 1;
229         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
230         {
231             bool status = it->set(*static_cast<Adaptor*>(this), current->get(index), controller);
232             if (!status)
233             {
234                 return false;
235             }
236         }
237
238         return true;
239     }
240
241     /**
242      * @return the Adaptee
243      */
244     std::shared_ptr<Adaptee> getAdaptee() const
245     {
246         return m_adaptee;
247     }
248
249     /*
250      * All following methods should be implemented by each template instance
251      */
252
253     virtual std::wstring getTypeStr() = 0;
254     virtual std::wstring getShortTypeStr() = 0;
255
256 private:
257     types::InternalType* clone()
258     {
259         return new Adaptor(*static_cast<Adaptor*>(this));
260     }
261
262     /*
263      * Implement a specific types::User
264      */
265
266     bool isAssignable()
267     {
268         return true;
269     }
270
271     bool extract(const std::wstring & name, types::InternalType *& out)
272     {
273         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
274         if (found != property<Adaptor>::fields.end() && !(name < found->name))
275         {
276             Controller controller = Controller();
277             types::InternalType* value = found->get(*static_cast<Adaptor*>(this), controller);
278             if (value == 0)
279             {
280                 return false;
281             }
282
283             out = value;
284             return true;
285         }
286         return false;
287     }
288
289     types::InternalType* extract(types::typed_list* _pArgs)
290     {
291         if (_pArgs->size() == 0)
292         {
293             // call overload
294             return NULL;
295         }
296
297         if ((*_pArgs)[0]->isString())
298         {
299             types::String* pStr = (*_pArgs)[0]->getAs<types::String>();
300             types::InternalType* pOut = NULL;
301             extract(std::wstring(pStr->get(0)), pOut);
302             return pOut;
303         }
304         else
305         {
306             if ((*_pArgs)[0]->isDouble())
307             {
308                 types::Double* index = (*_pArgs)[0]->getAs<types::Double>();
309
310                 if (index->get(0) == 1)
311                 {
312                     // When _pArgs is '1', return the list of the property names of the Adaptor
313
314                     // Sort the properties before extracting them
315                     typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
316                     std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
317
318                     // Allocate the return
319                     types::String* pOut = new types::String(1, properties.size());
320
321                     int i = 0;
322                     for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++i)
323                     {
324                         pOut->set(i, it->name.data());
325                     }
326                     return pOut;
327                 }
328             }
329             else
330             {
331                 // TO DO : management other type for arguments like a scalar or matrix of double
332             }
333         }
334
335         return NULL;
336     }
337
338     types::InternalType* insert(types::typed_list* _pArgs, InternalType* _pSource)
339     {
340         for (size_t i = 0; i < _pArgs->size(); i++)
341         {
342             if ((*_pArgs)[i]->isString())
343             {
344                 types::String* pStr = (*_pArgs)[i]->getAs<types::String>();
345                 std::wstring name = pStr->get(0);
346
347                 Controller controller = Controller();
348                 typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
349                 if (found != property<Adaptor>::fields.end() && !(name < found->name))
350                 {
351                     found->set(*static_cast<Adaptor*>(this), _pSource, controller);
352                 }
353
354                 return this;
355             }
356             else
357             {
358                 return NULL;
359             }
360         }
361
362         // call overload
363         return NULL;
364     }
365
366     void whoAmI(void)
367     {
368         std::cout << "scicos object";
369     }
370
371     bool hasToString()
372     {
373         // Do not allow scilab to call toString of this class
374         return false;
375     }
376
377     bool toString(std::wostringstream& ostr)
378     {
379         // Deprecated, use the overload instead
380         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
381         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
382
383         ostr << L"scicos_" <<  getTypeStr() << L" type :" << std::endl;
384         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
385         {
386             ostr << L"  " << it->name << std::endl;
387         }
388         return true;
389     }
390
391 private:
392     std::shared_ptr<Adaptee> m_adaptee;
393 };
394
395
396 } /* namespace view_scilab */
397 } /* namespace org_scilab_modules_scicos */
398
399 #endif /* BASEADAPTER_HXX_ */