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