Xcos MVC: implement diagram objs / version / contrib
[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::User<Adaptor>
99 {
100
101 public:
102     BaseAdapter(Adaptee* o) : adaptee(o) {};
103     BaseAdapter(const BaseAdapter& o) : adaptee(o.adaptee) {};
104     virtual ~BaseAdapter() {};
105
106     /*
107      * property accessors
108      */
109
110     bool hasProperty(const std::wstring& _sKey) const
111     {
112         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
113         return found != property<Adaptor>::fields.end() && !(_sKey < found->name);
114     }
115
116     types::InternalType* getProperty(const std::wstring& _sKey, Controller controller = Controller()) const
117     {
118         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
119         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
120         {
121             return found->get(static_cast<Adaptor*>(this), controller);
122         }
123         return 0;
124     }
125
126     bool setProperty(const std::wstring& _sKey, types::InternalType* v, Controller controller = Controller())
127     {
128         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
129         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
130         {
131             return found->set(*static_cast<Adaptor*>(this), v, controller);
132         }
133         return false;
134     }
135
136     /**
137      * property as TList accessors
138      */
139
140     types::InternalType* getAsTList(types::TList* tlist, const Controller& controller)
141     {
142         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
143         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
144
145         // create the header
146         types::String* header = new types::String(1 + (int)properties.size(), 1);
147         header->set(0, Adaptor::getSharedTypeStr().c_str());
148         int index = 1;
149         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
150         {
151             header->set(index, it->name.c_str());
152         }
153         tlist->set(0, header);
154
155         // set the tlist field value
156         index = 1;
157         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
158         {
159             tlist->set(index, it->get(*static_cast<Adaptor*>(this), controller));
160         }
161
162         return tlist;
163     }
164
165     bool setAsTList(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::ScilabTList && v->getType() != types::InternalType::ScilabMList)
171         {
172             return false;
173         }
174         types::TList* current = v->getAs<types::TList>();
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 tlist, get each tlist 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_ */