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