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