Xcos GUI: handle COSF import
[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 <cstring>
17
18 #include <algorithm>
19 #include <string>
20 #include <vector>
21 #include <sstream>
22
23 #include "bool.hxx"
24 #include "double.hxx"
25 #include "user.hxx"
26 #include "int.hxx"
27 #include "internal.hxx"
28 #include "tlist.hxx"
29 #include "mlist.hxx"
30 #include "string.hxx"
31 #include "callable.hxx"
32 #include "overload.hxx"
33 #include "configvariable.hxx"
34 #include "exp.hxx"
35
36 #include "view_scilab/Adapters.hxx"
37 #include "controller_helpers.hxx"
38 #include "utilities.hxx"
39 #include "Controller.hxx"
40 #include "model/BaseObject.hxx"
41
42 extern "C" {
43 #include "localization.h"
44 }
45
46 namespace org_scilab_modules_scicos
47 {
48 namespace view_scilab
49 {
50
51 /**
52  * A property used as a getter/setter for a specific name
53  */
54 template<typename Adaptor>
55 struct property
56 {
57 public:
58     typedef types::InternalType* (*getter_t)(const Adaptor& adaptor, const Controller& controller);
59     typedef bool (*setter_t)(Adaptor& adaptor, types::InternalType* v, Controller& controller);
60
61     typedef std::vector< property<Adaptor> > props_t;
62     typedef typename props_t::iterator props_t_it;
63
64
65     property(const std::wstring& prop, getter_t g, setter_t s) : original_index(fields.size()), name(prop), get(g), set(s) {};
66     ~property() {};
67
68     size_t original_index;
69     std::wstring name;
70     getter_t get;
71     setter_t set;
72
73     bool operator< (const std::wstring& v) const
74     {
75         return name < v;
76     }
77
78     static bool original_index_cmp(property<Adaptor> p1, property<Adaptor> p2)
79     {
80         return p1.original_index < p2.original_index;
81     }
82
83     /*
84      * Static properties accessors
85      */
86     static props_t fields;
87
88     /**
89      * @return true if the properties have already been setup, false otherwise.
90      */
91     static bool properties_have_not_been_set()
92     {
93         return fields.empty();
94     }
95
96     /**
97      * Add a property to an Adaptor
98      */
99     static void add_property(const std::wstring& name, getter_t g, setter_t s)
100     {
101         property<Adaptor>::props_t_it pos = std::lower_bound(fields.begin(), fields.end(), name);
102         fields.insert(pos, property(name, g, s));
103     }
104 };
105
106 /**
107  * Base definition of the adapter pattern, implement the get / set dispatch.
108  *
109  * Note that sub-classes are responsible to fill the fields accordingly to theirs interfaces.
110  */
111 template<typename Adaptor, typename Adaptee>
112 class BaseAdapter : public types::UserType
113 {
114
115 public:
116     BaseAdapter() : m_adaptee(nullptr) {};
117     BaseAdapter(const Controller& /*c*/, Adaptee* adaptee) : m_adaptee(adaptee) {}
118     BaseAdapter(const BaseAdapter& adapter) : BaseAdapter(adapter, true) {}
119     BaseAdapter(const BaseAdapter& adapter, bool cloneChildren) : m_adaptee(nullptr)
120     {
121         Controller controller;
122         ScicosID id = controller.cloneObject(adapter.getAdaptee()->id(), cloneChildren);
123         m_adaptee = controller.getObject< Adaptee >(id);
124     };
125     ~BaseAdapter()
126     {
127         if (m_adaptee != nullptr)
128         {
129             Controller controller;
130             controller.deleteObject(m_adaptee->id());
131         }
132     };
133
134     /*
135      * property accessors
136      */
137
138     bool hasProperty(const std::wstring& _sKey) const
139     {
140         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
141         return found != property<Adaptor>::fields.end() && !(_sKey < found->name);
142     }
143
144     types::InternalType* getProperty(const std::wstring& _sKey, Controller controller = Controller()) const
145     {
146         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
147         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
148         {
149             return found->get(static_cast<Adaptor*>(this), controller);
150         }
151         return 0;
152     }
153
154     bool setProperty(const std::wstring& _sKey, types::InternalType* v, Controller controller = Controller())
155     {
156         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
157         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
158         {
159             return found->set(*static_cast<Adaptor*>(this), v, controller);
160         }
161         return false;
162     }
163
164     /**
165      * property as TList accessors
166      */
167
168     types::InternalType* getAsTList(types::TList* tlist, const Controller& controller)
169     {
170         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
171         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
172
173         // create the header
174         types::String* header = new types::String(1, 1 + (int)properties.size());
175         header->set(0, Adaptor::getSharedTypeStr().c_str());
176         int index = 1;
177         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
178         {
179             header->set(index, it->name.c_str());
180         }
181         tlist->append(header);
182
183         // set the tlist field value
184         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
185         {
186             tlist->append(it->get(*static_cast<Adaptor*>(this), controller));
187         }
188
189         return tlist;
190     }
191
192     bool setAsTList(types::InternalType* v, Controller& controller)
193     {
194         if (v->getType() != types::InternalType::ScilabTList && v->getType() != types::InternalType::ScilabMList)
195         {
196             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s: Tlist or Mlist expected.\n"), Adaptor::getSharedTypeStr().c_str());
197             return false;
198         }
199         types::TList* current = v->getAs<types::TList>();
200         // The input TList cannot be empty
201         if (current->getSize() < 1)
202         {
203             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong length for field %s: at least %d element expected.\n"), Adaptor::getSharedTypeStr().c_str(), 1);
204             return false;
205         }
206
207         // Check the header
208         types::String* header = current->getFieldNames();
209         if (header->getSize() < 1)
210         {
211             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong length for header of field %s: at least %d element expected.\n"), Adaptor::getSharedTypeStr().c_str(), 1);
212             return false;
213         }
214         // Make sure it is the same type as the Adapter
215         if (header->get(0) != Adaptor::getSharedTypeStr())
216         {
217             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong value for header of field %s: %s expected.\n"), Adaptor::getSharedTypeStr().c_str(), Adaptor::getSharedTypeStr().c_str());
218             return false;
219         }
220
221         // Retrieve the Adapter's properties
222         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
223
224         // For each input property, if it corresponds to an Adapter's property, set it.
225         for (int index = 1; index < header->getSize(); ++index)
226         {
227             typename property<Adaptor>::props_t_it found = std::lower_bound(properties.begin(), properties.end(), header->get(index));
228             if (found != properties.end() && !(header->get(index) < found->name))
229             {
230                 bool status = found->set(*static_cast<Adaptor*>(this), current->get(index), controller);
231                 if (!status)
232                 {
233                     return false;
234                 }
235             }
236         }
237
238         return true;
239     }
240
241     /**
242      * property comparison
243      */
244
245     types::Bool* equal(types::UserType*& ut)
246     {
247         const Adapters::adapters_index_t adapter_index = Adapters::instance().lookup_by_typename(ut->getShortTypeStr());
248         // Check that 'ut' is an Adapter of the same type as *this
249         if (adapter_index == Adapters::INVALID_ADAPTER)
250         {
251             return new types::Bool(false);
252         }
253         if (this->getTypeStr() != ut->getTypeStr())
254         {
255             return new types::Bool(false);
256         }
257
258         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
259         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
260
261         types::Bool* ret = new types::Bool(1, 1 + properties.size());
262         ret->set(0, true); // First field is just the Adapter's name, which has been checked by the above conditions
263
264         Controller controller;
265         int index = 1;
266         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
267         {
268             types::InternalType* ith_prop1 = it->get(*static_cast<Adaptor*>(this), controller);
269             types::InternalType* ith_prop2 = it->get(*static_cast<Adaptor*>(ut), controller);
270             ret->set(index, *ith_prop1 == *ith_prop2);
271
272             // Getting a property allocates data, so free it
273             ith_prop1->killMe();
274             ith_prop2->killMe();
275         }
276
277         return ret;
278     }
279
280     /**
281      * @return the Adaptee
282      */
283     Adaptee* getAdaptee() const
284     {
285         return m_adaptee;
286     }
287
288     /*
289      * All following methods should be implemented by each template instance
290      */
291
292     virtual std::wstring getTypeStr() = 0;
293     virtual std::wstring getShortTypeStr() = 0;
294
295 private:
296     types::InternalType* clone()
297     {
298         return new Adaptor(*static_cast<Adaptor*>(this));
299     }
300
301     /*
302      * Implement a specific types::User
303      */
304
305     bool isAssignable()
306     {
307         return true;
308     }
309
310     bool extract(const std::wstring & name, types::InternalType *& out)
311     {
312         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
313         if (found != property<Adaptor>::fields.end() && !(name < found->name))
314         {
315             Controller controller;
316             types::InternalType* value = found->get(*static_cast<Adaptor*>(this), controller);
317             if (value == 0)
318             {
319                 return false;
320             }
321
322             out = value;
323             return true;
324         }
325
326         // specific case : to ease debugging let the user retrieve the model ID
327         if (name == L"modelID")
328         {
329             out = new types::Int64(m_adaptee->id());
330             return true;
331         }
332
333         return false;
334     }
335
336     types::InternalType* extract(types::typed_list* _pArgs)
337     {
338         if (_pArgs->size() == 0)
339         {
340             // call overload
341             return NULL;
342         }
343
344         if ((*_pArgs)[0]->isString())
345         {
346             types::String* pStr = (*_pArgs)[0]->getAs<types::String>();
347             types::InternalType* pOut = NULL;
348             extract(std::wstring(pStr->get(0)), pOut);
349             return pOut;
350         }
351         else
352         {
353             if ((*_pArgs)[0]->isDouble())
354             {
355                 types::Double* index = (*_pArgs)[0]->getAs<types::Double>();
356
357                 if (index->get(0) == 1)
358                 {
359                     // When _pArgs is '1', return the list of the property names of the Adaptor
360
361                     // Sort the properties before extracting them
362                     typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
363                     std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
364
365                     // Allocate the return
366                     types::String* pOut = new types::String(1, static_cast<int>(properties.size()));
367
368                     int i = 0;
369                     for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++i)
370                     {
371                         pOut->set(i, it->name.data());
372                     }
373                     return pOut;
374                 }
375             }
376             else
377             {
378                 // TO DO : management other type for arguments like a scalar or matrix of double
379             }
380         }
381
382         return NULL;
383     }
384
385     types::InternalType* insert(types::typed_list* _pArgs, types::InternalType* _pSource)
386     {
387         for (size_t i = 0; i < _pArgs->size(); i++)
388         {
389             if ((*_pArgs)[i]->isString())
390             {
391                 types::String* pStr = (*_pArgs)[i]->getAs<types::String>();
392                 std::wstring name = pStr->get(0);
393
394                 Controller controller;
395                 typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
396                 if (found != property<Adaptor>::fields.end() && !(name < found->name))
397                 {
398                     found->set(*static_cast<Adaptor*>(this), _pSource, controller);
399                 }
400
401                 return this;
402             }
403             else
404             {
405                 return NULL;
406             }
407         }
408
409         // call overload
410         return NULL;
411     }
412
413     void whoAmI(void)
414     {
415         std::cout << "scicos object";
416     }
417
418     bool hasToString()
419     {
420         // Do not allow scilab to call toString of this class
421         return false;
422     }
423
424     bool toString(std::wostringstream& ostr)
425     {
426         // Deprecated, use the overload instead
427         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
428         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
429
430         ostr << L"scicos_" <<  getTypeStr() << L" type :" << std::endl;
431         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
432         {
433             ostr << L"  " << it->name << std::endl;
434         }
435         return true;
436     }
437
438     bool isInvokable() const
439     {
440         return true;
441     }
442
443     bool invoke(types::typed_list & in, types::optional_list & /*opt*/, int /*_iRetCount*/, types::typed_list & out, const ast::Exp & e) override
444     {
445         if (in.size() == 0)
446         {
447             out.push_back(this);
448             return true;
449         }
450         else if (in.size() == 1)
451         {
452             types::InternalType* _out = nullptr;
453             types::InternalType*  arg = in[0];
454             if (arg->isString())
455             {
456                 types::String* pString = arg->getAs<types::String>();
457                 for (int i = 0; i < pString->getSize(); ++i)
458                 {
459                     if (!extract(pString->get(i), _out))
460                     {
461                         return false;
462                     }
463                     out.push_back(_out);
464                 }
465             }
466
467             if (!out.empty())
468             {
469                 return true;
470             }
471         }
472
473         types::Callable::ReturnValue ret;
474         // Overload of extraction needs the BaseAdapter from where we extract
475         this->IncreaseRef();
476         in.push_back(this);
477
478         try
479         {
480             ret = Overload::call(L"%" + getShortTypeStr() + L"_e", in, 1, out);
481         }
482         catch (ast::InternalError & /*se*/)
483         {
484             ret = Overload::call(L"%l_e", in, 1, out);
485         }
486
487         // Remove this from "in" to keep "in" unchanged.
488         this->DecreaseRef();
489         in.pop_back();
490
491         if (ret == types::Callable::Error)
492         {
493             throw ast::InternalError(ConfigVariable::getLastErrorMessage(), ConfigVariable::getLastErrorNumber(), e.getLocation());
494         }
495
496         return true;
497     }
498
499 private:
500     Adaptee* m_adaptee;
501 };
502
503
504 } /* namespace view_scilab */
505 } /* namespace org_scilab_modules_scicos */
506
507 #endif /* BASEADAPTER_HXX_ */